This is an attempt to integrate VisDock into Christopher Manning's Voronoi Diagram with Force Directed Nodes and Delaunay Links. A few modifications and addition of lines allow users to query Voronoi path elements. For more about VisDock, click here.
Last active
August 29, 2015 13:56
-
-
Save VisDockHub/9119115 to your computer and use it in GitHub Desktop.
VisDock in Force Directed Voronoi Diagram
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Voronoi Diagram with Force Directed Nodes and Delaunay Links</title> | |
| <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <style type="text/css"> | |
| circle { | |
| stroke: #EFEDF5; | |
| fill: #EFEDF5; | |
| pointer-events: none; | |
| } | |
| line { | |
| pointer-events: none; | |
| stroke: #EFEDF5; | |
| stroke-width: 2px; | |
| opacity: .05; | |
| } | |
| path{ | |
| stroke: #EFEDF5; | |
| stroke-width: 4px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="chart"> | |
| </div> | |
| <link href="http://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.css" rel="stylesheet" type="text/css"/> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <script src="http://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.js"></script> | |
| <script src="http://rawgithub.com/VisDockHub/NewVisDock/master/master/2D.js"></script> | |
| <script src="http://rawgithub.com/VisDockHub/NewVisDock/master/master/IntersectionUtilities.js"></script> | |
| <script src="http://rawgithub.com/VisDockHub/NewVisDock/master/master/visdock.utils.js"></script> | |
| <script type="text/javascript"> | |
| var w = 960; | |
| h = 500; | |
| radius = 5.25, | |
| links = [], | |
| simulate = true, | |
| zoomToAdd = true, | |
| // https://github.com/mbostock/d3/blob/master/lib/colorbrewer/colorbrewer.js#L105 | |
| color = d3.scale.quantize().domain([10000, 7250]).range(["#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"]) | |
| var numVertices = (w*h) / 3000; | |
| var vertices = d3.range(numVertices).map(function(i) { | |
| angle = radius * (i+10); | |
| return {x: angle*Math.cos(angle)+(w/2), y: angle*Math.sin(angle)+(h/2)}; | |
| }); | |
| var d3_geom_voronoi = d3.geom.voronoi().x(function(d) { return d.x; }).y(function(d) { return d.y; }) | |
| var prevEventScale = 1; | |
| var zoom = d3.behavior.zoom().on("zoom", function(d,i) { | |
| if (zoomToAdd){ | |
| if (d3.event.scale > prevEventScale) { | |
| angle = radius * vertices.length; | |
| vertices.push({x: angle*Math.cos(angle)+(w/2), y: angle*Math.sin(angle)+(h/2)}) | |
| } else if (vertices.length > 2 && d3.event.scale != prevEventScale) { | |
| vertices.pop(); | |
| } | |
| force.nodes(vertices).start() | |
| } else { | |
| if (d3.event.scale > prevEventScale) { | |
| radius+= .01 | |
| } else { | |
| radius -= .01 | |
| } | |
| vertices.forEach(function(d, i) { | |
| angle = radius * (i+10); | |
| vertices[i] = {x: angle*Math.cos(angle)+(w/2), y: angle*Math.sin(angle)+(h/2)}; | |
| }); | |
| force.nodes(vertices).start() | |
| } | |
| prevEventScale = d3.event.scale; | |
| }); | |
| d3.select(window) | |
| .on("keydown", function() { | |
| // shift | |
| if(d3.event.keyCode == 16) { | |
| zoomToAdd = false | |
| } | |
| // s | |
| if(d3.event.keyCode == 83) { | |
| simulate = !simulate | |
| if(simulate) { | |
| force.start() | |
| } else { | |
| force.stop() | |
| } | |
| } | |
| }) | |
| .on("keyup", function() { | |
| zoomToAdd = true | |
| }) | |
| VisDock.init("#chart", {width: w+200, height: h+200});//width + leftMargin + rightMargin +200, height + topMargin + bottomMargin) | |
| VisDock.opacity = 0.5; | |
| var viewport = VisDock.getViewport(); | |
| var svg = viewport | |
| .call(zoom) | |
| var force = d3.layout.force() | |
| .charge(-300) | |
| .size([w, h]) | |
| .on("tick", update); | |
| force.nodes(vertices).start(); | |
| var circle = svg.selectAll("circle"); | |
| var path = svg.selectAll("path"); | |
| var link = svg.selectAll("line"); | |
| function update(e) { | |
| VisDock.startChrome(); | |
| path = path.data(d3_geom_voronoi(vertices)) | |
| var id = 0; | |
| path.enter().append("path").attr("class", "voronoi") | |
| .attr("id", function(){ | |
| return "v" + id++; | |
| }) | |
| // drag node by dragging cell | |
| .call(d3.behavior.drag() | |
| .on("drag", function(d, i) { | |
| vertices[i] = {x: vertices[i].x + d3.event.dx, y: vertices[i].y + d3.event.dy} | |
| }) | |
| ) | |
| .style("fill", function(d, i) { return color(0) }) | |
| path.attr("d", function(d) { return "M" + d.join("L") + "Z"; }) | |
| .transition().duration(150).style("fill", function(d, i) { return color(d3.geom.polygon(d).area()) }) | |
| path.exit().remove(); | |
| circle = circle.data(vertices) | |
| circle.enter().append("circle") | |
| .attr("r", 0) | |
| .transition().duration(1000).attr("r", 5); | |
| circle.attr("cx", function(d) { return d.x; }) | |
| .attr("cy", function(d) { return d.y; }); | |
| circle.exit().transition().attr("r", 0).remove(); | |
| link = link.data(d3_geom_voronoi.links(vertices)) | |
| link.enter().append("line") | |
| link.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; }) | |
| link.exit().remove() | |
| if(!simulate) force.stop() | |
| for (var i = 0; i < d3.selectAll(".voronoi")[0].length; i++){ | |
| var id = d3.selectAll(".voronoi")[0][i].getAttributeNS(null, "id") | |
| d3.selectAll("#_" + id).attr("d", d3.selectAll("#" + id).attr("d")) | |
| } | |
| VisDock.finishChrome(); | |
| } | |
| /*d3.timer(function(){ | |
| VisDock.startChrome(); | |
| for (var i = 0; i < d3.selectAll(".voronoi")[0].length; i++){ | |
| var id = d3.selectAll(".voronoi")[0][i].getAttributeNS(null, "id") | |
| d3.selectAll("#_" + id).attr("d", d3.selectAll("#" + id).attr("d")) | |
| } | |
| VisDock.finishChrome(); | |
| })*/ | |
| VisDock.eventHandler = { | |
| getHitsPolygon : function(points, inclusive) { | |
| var shapebound = new createPolygon(points); | |
| return shapebound.intersectPath(d3.selectAll(".voronoi")[0], inclusive) | |
| }, | |
| getHitsEllipse : function(points, inclusive) { | |
| var shapebound = new createEllipse(points); | |
| return shapebound.intersectPath(d3.selectAll(".voronoi")[0], inclusive) | |
| }, | |
| getHitsLine : function(points, inclusive) { | |
| var shapebound = new createLine(points); | |
| return shapebound.intersectPath(d3.selectAll(".voronoi")[0], inclusive) | |
| }, | |
| setColor : function(hits) { | |
| var circleObjects = d3.selectAll("circle")[0]; | |
| QueryManager.layers[num - 1] = []; | |
| for (var i = 0; i < hits.length; i++) { | |
| var d = hits[i].getAttributeNS(null, "d") | |
| QueryManager.layers[num - 1][i] = d3.select(hits[i].parentNode).append("path") | |
| .attr("d", d) | |
| .attr("style", "fill: " + VisDock.color[num - 1] + "; opacity: 0.5; pointer-events: none") | |
| .attr("id", "_" + hits[i].getAttributeNS(null, "id")) | |
| } | |
| }, | |
| changeColor : function(color, query, index) { | |
| for (var i = 0; i < query.length; i++) { | |
| var visibility = query[i].attr("style").split("opacity: ")[1].split(";")[0] | |
| query[i].attr("style", "opacity: " + visibility + "; fill: " + color) | |
| } | |
| }, | |
| changeVisibility : function(vis, query, index) { | |
| var color = VisDock.utils.getQueryColor(index); | |
| for (var i = 0; i < query.length; i++) { | |
| var color = query[i].attr("style").split("fill: ")[1].split(";")[0] | |
| query[i].attr("style", "opacity: " + vis + "; fill: " + color) | |
| } | |
| }, | |
| removeColor : function(hits, index) { | |
| for (var i = 0; i < hits.length; i++) { | |
| hits[i].remove(); | |
| } | |
| }, | |
| } | |
| BirdView.init(viewport, 1160, 700) | |
| d3.select(self.frameElement).style("width", "1160px") | |
| d3.select(self.frameElement).style("height", "700px") | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment