Widget:KTN Research Mapping

From EngageWiki
Revision as of 20:58, 3 December 2021 by WikiVisor (talk | contribs)
<style>
div#canvas{
  min-width: 800px;
  margin: auto;
}
div.info {
   max-width: 340px;
   min-height: 30px;
   padding: 5px;
   font: 14px sans-serif;
   background: lightsteelblue;
   border: 0px;
   display: none;
   overflow-y: auto;
}
div#current{
  position: absolute;
  min-width: 280px !important;
  pointer-events: none;
  z-index: 2000;
}
div#selected{
  position: fixed; 
  right: 0;
  top: 0;
  min-width: 300px;
  padding: 15px;
  opacity: 1;
  z-index: 1090;
  height: 100%;
}
#selected {
   -ms-overflow-style: none;  /* Internet Explorer 10+ */
   scrollbar-width: none;  /* Firefox */
   overflow: -moz-scrollbars-none;
}
#selected::-webkit-scrollbar { 
   display: none;  /* Safari and Chrome */
}
div#search-box{
   display: inline-block !important;
   padding: .5rem;
   background: #e2e2e2;
   border-radius: 4px;
}
.btn, .btn-xs {
  margin: .5rem 0;
  padding: .4rem;
  font-size: .875rem;
  line-height: .5;
  border-radius: .2rem;
}
div.info div {
  margin-bottom: 5px;
}
div.info ul {
  padding-left: 20px;
  font-size: 95%;
}
div.info ul li {
  margin-bottom: 3px;
}

h1.firstHeading {
  border-bottom: none !important;
  text-align: center;
}
.unselectable {
   -moz-user-select: -moz-none;
   -khtml-user-select: none;
   -webkit-user-select: none;
   -o-user-select: none;
   user-select: none;
}
</style>
       Filter by call: 
       <a onclick="update_call('wp-e')" href="#">WP-E</a>,
       <a onclick="update_call('ir')" href="#">IR</a>,
       <a onclick="update_call('ir-demo')" href="#">IR-Demo</a>,
       <a onclick="update_call('ir-aire iii')" href="#">IR-AIRE III</a>,
       <a onclick="update_call('ir-lsd')" href="#">IR-LSD</a>,
       <a onclick="update_call('ir-rpas')" href="#">IR-RPAS</a>,
       <a onclick="update_call('ir wave 1')" href="#">IR WAVE 1</a>,
       <a onclick="update_call('er1')" href="#">ER1</a>,
       <a onclick="update_call('er2')" href="#">ER2</a>,
       <a onclick="update_call('er3')" href="#">ER3</a>,
       <a onclick="update_call('er4')" href="#">ER4</a>,

<button id="selected-close" type="button" class="close"> × </button>

 <script src="https://d3js.org/d3.v5.min.js"></script>
 <script>
   var data;
   var width = d3.select("#canvas").node().getBoundingClientRect().width;
   var height = 900;
   var div_current = d3.select("#current")
   var div_selected = d3.select("#selected")
   var div_selected_content = d3.select("#selected-content")


   d3.json("/extensions/ComplexWorld/visuals/assets/tree_cluster.json").then(function (d) {
     data = d;
     visualize(data);
   });
   d3.select("#search").on("click", function () {
     update_filter();
   })
   d3.select("#search_term").on("keypress", function () {
     if (d3.event.keyCode == 13) {
       update_filter();
     }
   })
   function update_filter() {
     var term = d3.select("#search_term").node().value.toLowerCase();
     d3.select("svg").remove();
     var data_f = JSON.parse(JSON.stringify(data));
     filterData(data_f.children, term);
     visualize(data_f);
   }
   d3.select("#reset").on("click", function () {
     d3.select("#search_term").node().value = null;
     d3.select("svg").remove();
     visualize(data);
   })


   function filterData(data, term) {
     var r = data.filter(function (o) {
       if (o.children) {
         o.children = filterData(o.children, term);
       } else {
         var words = term.split(" ");
         var match = true;
         words.forEach((w, i) => {
           match = match && (o.keywords.includes(w) || o.title.toLowerCase().includes(w) || o.partners.toLowerCase().includes(w))
         });
         return match
       }
     })
     return r;
   }


   // d3.select("#filter-er1").on("click", function () {
   //   update_call("er3");
   // })
   function update_call(call) {
     d3.select("svg").remove();
     var data_f = JSON.parse(JSON.stringify(data));
     filterCall(data_f.children, call);
     visualize(data_f);
   }
   function filterCall(data, call) {
     var r = data.filter(function (o) {
       if (o.children) {
         o.children = filterCall(o.children, call);
       } else {
         match = (o.call.toLowerCase() == call.toLowerCase())
         return match
       }
     })
     return r;
   }
   function visualize(data) {
     var root = d3.hierarchy(data);
     var links = root.links();
     var nodes = root.descendants();
     var simulation = d3.forceSimulation(nodes)
       .force("link", d3.forceLink(links).id(d => d.id).distance(40).strength(0.5))
       .force("charge", d3.forceManyBody().strength(-110))
       .force("x", d3.forceX())
       .force("y", d3.forceY())
       ;
     var svg = d3.select("#canvas")
       .append("svg")
       .attr("width", width)
       .attr("height", height)
       .attr("viewBox", [-width / 2, -height / 2, width, height]);
     var link = svg.append("g")
       // .attr("stroke", "#555")
       // .attr("stroke-opacity", 0.6)
       .selectAll("line")
       .data(links)
       .join("line")
       .attr("stroke", "#555")
       .attr("stroke", d => d.target.children ? "#555" : "#999")
       .attr("stroke-opacity", d => d.target.children ? 0.6 : 0.4)
       ;
     var node = svg.append("g")
       .selectAll(".node")
       .data(nodes)
       .join("g")
       .call(drag(simulation));


     node.append("circle")
       .attr("class", "circle")
       .style("cursor", "pointer")
       .raise()
       .on("mouseover", mouseover)
       .on("mouseout", mouseout)
       .on("click", click);
     reset_all_nodes();
     // node.append("text")
     //   .text(d => d.data.wbs ? d.data.wbs : null)
     //   .style('fill', '#000')
     //   .style('font-size', '12px')
     //   .style("text-anchor", "middle");
     //   // .attr('x', 6)
     //   // .attr('y', 3);


     // // unselect
     // d3.select("body").on("click", function () {
     //   var outside_circle = d3.selectAll('.circle').filter(function () { return this == d3.event.target }).empty();
     //   var outside_box = d3.select('#selected').filter(function () { return this == d3.event.target }).empty();
     //   if (outside_circle && outside_box) {
     //     div_selected.style("display", "none");
     //     selected = false;
     //   }
     // });
     // close selected div
     d3.select("#selected-close").on("click", function () {
       div_selected.style("display", "none");
       reset_all_nodes();
     });
     simulation.on("tick", () => {
       link
         .attr("x1", d => d.source.x)
         .attr("y1", d => d.source.y)
         .attr("x2", d => d.target.x)
         .attr("y2", d => d.target.y);
       node
         .attr("transform", d => `translate(${d.x}, ${d.y})`);
     });
   }
   function mouseover(d) {
     var c = d3.color(d3.interpolateSpectral(d.data.cluster / 20 + 0.1));
     div_current.transition().duration(0).style("display", "block");
     div_current.html(
       d.data.name

+ (d.data.wbs ? "


WBS:" + d.data.wbs : "")

     ).style("background-color", c)
       .style("left", (d3.event.pageX + 15) + "px")
       .style("top", (d3.event.pageY - 15) + "px");
   }
   function mouseout(d) {
     div_current.transition().duration(0).style("display", "none");
   }


   function reset_all_nodes() {
     d3.selectAll(".circle").attr("fill", d => d.data.nodetype == 'project' ? d3.interpolateSpectral(d.data.cluster / 20 + 0.1) : "#eee")
       .attr("stroke", d => d.data.nodetype == 'project' ? d3.interpolateSpectral(d.data.cluster / 20 + 0.1) : "#000")
       .attr("r", d => d.data.nodetype == 'project' ? 8 : 6)
       .attr("stroke-width", 1)
       .raise();
   }
   function click(d) {
     if (d3.event.defaultPrevented) return; // dragged
     var html_content;
     if (d.data.nodetype == "cluster") {

html_content = "

" + d.data.name + "

"; html_content += "Keywords: " + d.data.keywords + "


"; html_content += "Projects

    "; d.data.children.forEach(function (project) { html_content += "
  • " + project.title + "
  • "; }) html_content += "

";


     } else {

var links = "

";
       if (d.data.url) {
         links += " <a class='btn btn-xs btn-primary' href='" + d.data.url + "' target='_blank'>Website</a> ";
       } else {
         links += " <a class='btn btn-xs btn-primary disabled' href='#' target='_blank'>Website</a> ";
       }
       links += " <a class='btn btn-xs btn-primary disabled' href='#' target='_blank'>Reports</a> ";
       links += " <a class='btn btn-xs btn-secondary' href='https://google.com/search?q=\"SESAR\" "
         + d.data.title.replace(/[^a-zA-Z0-9]/g, " ") + "' target='_blank'>Web search</a>";
links += "

"; var info = "

"; info += "
Call: " + d.data.call + "
"; info += "
Call ID: " + d.data.callid + "
"; info += "
Partners: " + (d.data.partners ? d.data.partners : "n/a") + "
"; info += "
Theme: " + (d.data.theme ? d.data.theme : "n/a") + "
"; info += "
Budget: " + (d.data.budget ? d.data.budget : "n/a") + "
"; info += "
Duration: " + d.data.start + " - " + d.data.close + "
"; info += "
Public deliverables:
    ";


           d.data.docs.forEach(function (doc) {
             console.log(doc.FILENAME_ANON)
             var file_url;
             if (doc.FILE_URL !== "") {
               file_url = doc.FILE_URL;
    
    info += "
  • <a target='_blank' href='" + file_url + "'>" + doc.DEL_NAME + "</a>
  • "; } else if (doc.FILENAME_ANON !== "") { file_url = "wiki_public_repository/" + doc.FILENAME_ANON; info += "
  • <a target='_blank' href='" + file_url + "'>" + doc.DEL_NAME + "</a>
  • "; } else { } }) info += "
"; info += "

";

       html_content = d.data.title + links

+ "


"

         + info

+ "


"

         + " Keywords 
"

+ "

" + d.data.keywords + "

";

     }
     div_selected_content.html(html_content);
     div_selected
       .style("background-color", "#dddddd")
       .style("display", "block");
     reset_all_nodes();
     d3.select(this).attr("stroke-width", 5)
       .attr("stroke", "black");
   }


   function drag(simulation) {
     function dragstarted(d) {
       if (!d3.event.active) simulation.alphaTarget(0.1).restart();
       d.fx = d.x;
       d.fy = d.y;
     }
     function dragged(d) {
       d.fx = d3.event.x;
       d.fy = d3.event.y;
     }
     function dragended(d) {
       if (!d3.event.active) simulation.alphaTarget(0);
       d.fx = null;
       d.fy = null;
     }
     return d3.drag()
       .on("start", dragstarted)
       .on("drag", dragged)
       .on("end", dragended);
   }


 </script>

This project has received funding from the SESAR Joint Undertaking under the European Union’s Horizon 2020 research and innovation programme under grant agreement No 783287.