Created by Christopher Manning
Nodes are linked to nodes in neighboring cells. The cell's color is a function of its area.
- Drag the nodes to interact with the diagram.
- Use the mousewheel to add/remove nodes.
Created by Christopher Manning
Nodes are linked to nodes in neighboring cells. The cell's color is a function of its area.
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> | |
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.min.js"></script> | |
<link rel="stylesheet" href="http://mbostock.github.com/d3/ex/colorbrewer.css"> | |
<style type="text/css"> | |
circle { | |
stroke: #EFEDF5; | |
fill: #EFEDF5; | |
} | |
line { | |
stroke: #EFEDF5; | |
pointer-events: none | |
} | |
path{ | |
stroke: black | |
} | |
</style> | |
</head> | |
<body> | |
<div id="chart"> | |
</div> | |
<script type="text/javascript"> | |
var w = 1200, | |
h = 400, | |
links = [], | |
voronoiVertices = [], | |
color = d3.scale.quantize().domain([7000, 10000]).range(d3.range(2, 9)); | |
var numVertices = 100; | |
var vertices = d3.range(numVertices).map(function(d) { return {x: d.x, y: d.y}; }) | |
var prevEventScale = 1; | |
var zoom = d3.behavior.zoom().on("zoom", function(d,i) { | |
if (d3.event.scale > prevEventScale) { | |
vertices.push(function(d) { return {x: d.x, y: d.y}; }) | |
} else if (vertices.length > 2) { | |
vertices.pop(); | |
} | |
force.nodes(vertices).start() | |
prevEventScale = d3.event.scale; | |
}); | |
var svg = d3.select("#chart") | |
.append("svg") | |
.attr("width", w) | |
.attr("height", h) | |
.attr("class", "Purples") | |
.call(zoom) | |
var force = self.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) { | |
voronoiVertices = vertices.map(function(o){return [o.x, o.y, o]}) | |
path = path.data(d3.geom.voronoi(voronoiVertices)) | |
path.enter().insert("path", "path") //group all the path elements first so they have the lowest z-order | |
.attr("class", function(d, i) { return "q"+color(d3.geom.polygon(d).area())+"-9"; }) | |
.attr("d", function(d) { return "M" + d.join("L") + "Z"; }); | |
path.attr("class", function(d, i) { return "q"+color(d3.geom.polygon(d).area())+"-9"; }) | |
.attr("d", function(d) { return "M" + d.join("L") + "Z"; }); | |
path.exit().remove(); | |
circle = circle.data(vertices) | |
circle.enter().append("circle") | |
.call(force.drag) | |
.attr("r", 0) | |
.attr("cx", function(d) { return d.x; }) | |
.attr("cy", function(d) { return d.y; }) | |
.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(); | |
links = [] | |
d3.geom.delaunay(voronoiVertices).forEach(function(d) { | |
links.push(edge(d[0], d[1])); | |
links.push(edge(d[1], d[2])); | |
links.push(edge(d[2], d[0])); | |
}); | |
link = link.data(links) | |
link.enter().append("line") | |
link.attr("x1", function(d) { return d.source[2].x; }) | |
.attr("y1", function(d) { return d.source[2].y; }) | |
.attr("x2", function(d) { return d.target[2].x; }) | |
.attr("y2", function(d) { return d.target[2].y; }) | |
link.exit().remove() | |
} | |
function edge(a, b) { | |
return { | |
source: a, | |
target: b | |
}; | |
} | |
</script> | |
</body> | |
</html> |