forked from riyoyukai's block: BugsWIP03
forked from anonymous's block: BugsWIP03
| license: mit |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>D3 Test</title> | |
| <style> | |
| .active { | |
| stroke: #000; | |
| stroke-width: 2px; | |
| } | |
| .links line { | |
| stroke: #999; | |
| stroke-opacity: 0.6; | |
| } | |
| .nodes circle { | |
| stroke: #fff; | |
| stroke-width: 1.5px; | |
| } | |
| text { | |
| font-family: verdana; | |
| pointer-events: none; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="container"> | |
| <div id="graph"> | |
| </div> | |
| </div> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <script> | |
| var bugs_data = [ | |
| { | |
| "name": "Redhot", | |
| "attributes": [ | |
| {"attribute":"Legs", | |
| "name":"100"}, | |
| {"attribute":"Teeth", | |
| "name":"0"}, | |
| {"attribute":"Color", | |
| "name":"Red"}, | |
| {"attribute":"Habitat", | |
| "name":"Desert"}, | |
| {"attribute":"Diet", | |
| "name":"Insects"} | |
| ] | |
| }, | |
| { | |
| "name": "Dwarf Mantid", | |
| "attributes": [ | |
| {"attribute":"Legs", | |
| "name":"4"}, | |
| {"attribute":"Teeth", | |
| "name":"4"}, | |
| {"attribute":"Color", | |
| "name":"Purple"}, | |
| {"attribute":"Habitat", | |
| "name":"Grasslands"}, | |
| {"attribute":"Diet", | |
| "name":"Insects"} | |
| ] | |
| }, | |
| { | |
| "name": "Click Flipper", | |
| "attributes": [ | |
| {"attribute":"Legs", | |
| "name":"6"}, | |
| {"attribute":"Teeth", | |
| "name":"4"}, | |
| {"attribute":"Color", | |
| "name":"Black"}, | |
| {"attribute":"Feature", | |
| "name":"Red Stripe"}, | |
| {"attribute":"Habitat", | |
| "name":"Desert"}, | |
| {"attribute":"Diet", | |
| "name":"Sap"} | |
| ] | |
| } | |
| ]; | |
| var width = 960; | |
| var height = 500; | |
| var radius = 50; | |
| var small_radius = radius * (2/3); | |
| var node_color = "#BBDD44"; | |
| var link_distance = radius * 1.68; | |
| var allNodes = []; | |
| var bugNodes = []; | |
| var attributeNodes = []; | |
| var links_data = []; | |
| var graph = d3.select('#graph'); | |
| var svg = graph.append('svg') | |
| .attr('width', width) | |
| .attr('height', height); | |
| bugs_data.map(function(entry){ | |
| var b = {}; | |
| b.name = entry.name; | |
| b.label = entry.name; | |
| b.type = "bug"; | |
| b.attributes = entry.attributes; | |
| bugNodes.push(b); | |
| }); | |
| bugNodes.forEach(function(bugNode){ | |
| bugNode.attributes.map(function(entry){ | |
| var atrb = {}; | |
| atrb.name = bugNode.name + entry.attribute + entry.name; | |
| atrb.label = entry.name; | |
| atrb.type = "attribute"; | |
| atrb.attribute = entry.attribute; | |
| attributeNodes.push(atrb); | |
| var link = {}; | |
| link.source = bugNode.name; | |
| link.target = atrb.name; | |
| links_data.push(link); | |
| }); | |
| }); | |
| allNodes = bugNodes.concat(attributeNodes); | |
| var linkSelection = svg.append("g") | |
| .attr("class", "links") | |
| .selectAll("line") | |
| .data(links_data) | |
| .enter() | |
| .append("line") | |
| .attr("stroke-width", 2); | |
| var nodeSelection = svg.append("g") | |
| .attr("class", "nodes") | |
| .selectAll("circle") | |
| .data(allNodes) | |
| .enter() | |
| .append("circle") | |
| .attr("r", function(d) { | |
| if(d.type == 'attribute') | |
| return small_radius; | |
| else | |
| return radius; | |
| }) | |
| .attr("fill", node_color) | |
| .call(d3.drag() | |
| .on("start", dragstarted) | |
| .on("drag", dragged) | |
| .on("end", dragended)) | |
| .attr("cx", width/2) | |
| .attr("cx", height/2); | |
| var labelSelection = svg.append("g") | |
| .attr("class", "labels") | |
| .selectAll("text") | |
| .data(allNodes) | |
| .enter() | |
| .append("text") | |
| .text(function(d){ return d.label }) | |
| .style("text-anchor", "middle"); | |
| var link_force = d3.forceLink(links_data) | |
| .id(function(d) { return d.name; }) | |
| .distance(link_distance); | |
| var simulation = d3.forceSimulation() | |
| .nodes(allNodes); | |
| simulation | |
| .force("charge_force", d3.forceManyBody()); | |
| // .force("center_force", d3.forceCenter(width/2, height/2)); | |
| simulation.force("nodes", link_force); | |
| function dragstarted(d) { | |
| d3.select(this).raise().classed("active", true); | |
| if (!d3.event.active){ | |
| simulation.alphaTarget(0.3).restart(); | |
| } | |
| } | |
| function dragged(d) { | |
| d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y); | |
| } | |
| function dragended(d) { | |
| d3.select(this).classed("active", false); | |
| } | |
| function tick(){ | |
| nodeSelection | |
| .attr("cx", function(d) { return d.x = Math.max(radius, Math.min(width - radius, d.x)); }) | |
| .attr("cy", function(d) { return d.y = Math.max(radius, Math.min(height - radius, d.y)); }); | |
| labelSelection | |
| .attr("x", function(d) { return d.x; }) | |
| .attr("y", function(d) { return d.y; }); | |
| linkSelection | |
| .attr("x1", function(d) { return d.source.x; }) | |
| .attr("y1", function(d) { return d.source.y; }) | |
| .attr("x2", function(d) { return d.target.x; }) | |
| .attr("y2", function(d) { return d.target.y; }); | |
| } | |
| simulation.on("tick", tick); | |
| </script> | |
| </body> | |
| </html> |