|
generate(); |
|
|
|
function generate(){ |
|
var height = window.innerHeight; |
|
var width = window.innerWidth; |
|
var svg = d3.select("#chartArea").append("svg") |
|
.attr("width", width) |
|
.attr("height", height) |
|
|
|
coords = [] |
|
for(var i = 0; i < 50; i++){ |
|
var cy = Math.random()*(height-100) + 50 |
|
var cx = Math.random()*(width-100) + 50 |
|
|
|
coords.push([cx, cy]) |
|
} |
|
|
|
//Hull |
|
var hull = svg.append("path") |
|
.attr("class", "hull"); |
|
hull.data([d3.geom.hull(coords)]) |
|
.attr("d", function(d) { return "M" + d.join("L") + "Z"; }) |
|
.attr("opacity", .3) |
|
|
|
console.log('area', d3.geom.polygon(d3.geom.hull(coords)).area()) |
|
|
|
|
|
//Voronoi -> how to make a weighted version of this depending on the node in the center? |
|
var voronoi = d3.geom.voronoi() |
|
.clipExtent([[0, 0], [width, height]]); |
|
|
|
//voronoi.triangles seems very similar to the outside of a hull? |
|
var path = svg.append("g").selectAll("path"); |
|
path = path.data(voronoi.triangles(coords), polygon); |
|
path.enter().append("path") |
|
.attr("class", function(d, i) { return "q" + (i % 9) + "-9" + " voronoiTriangles"; }) |
|
.attr("fill", 'none') |
|
.attr("stroke", "maroon") |
|
.attr("d", polygon) |
|
.on('mouseover', function() { |
|
d3.selectAll('.voronoiTriangles').style('stroke-width', 3) |
|
}) |
|
.on('mouseout', function() { |
|
d3.selectAll('.voronoiTriangles').style('stroke-width', 1) |
|
}) |
|
function polygon(d) { |
|
return "M" + d.join("L") + "Z"; |
|
} |
|
|
|
//Voronoi |
|
path = path.data(voronoi(coords), polygon); |
|
path.enter().append("path") |
|
.attr("class", function(d, i) { return "q" + (i % 9) + "-9" + " voronoi"; }) |
|
.attr("fill", 'none') |
|
.attr("stroke", "#3CA1A5") |
|
.attr("d", polygon) |
|
.on('mouseover', function() { |
|
d3.selectAll('.voronoi').style('stroke-width', 3) |
|
}) |
|
.on('mouseout', function() { |
|
d3.selectAll('.voronoi').style('stroke-width', 1) |
|
}) |
|
|
|
//QuadTrees |
|
var quadtree = d3.geom.quadtree() |
|
.extent([[0, 0], [width, height]]); |
|
var rect = svg.selectAll(".node") |
|
.data(nodes(quadtree(coords))) |
|
.enter().append("rect") |
|
.attr("class", "node quadTrees") |
|
.attr("fill", 'none') |
|
.attr("stroke", "#7D9B47") |
|
.attr("x", function(d) { return d.x1; }) |
|
.attr("y", function(d) { return d.y1; }) |
|
.attr("width", function(d) { return d.x2 - d.x1; }) |
|
.attr("height", function(d) { return d.y2 - d.y1; }) |
|
.on('mouseover', function() { |
|
d3.selectAll('.quadTrees').style('stroke-width', 3) |
|
}) |
|
.on('mouseout', function() { |
|
d3.selectAll('.quadTrees').style('stroke-width', 1) |
|
}) |
|
function nodes(quadtree) { |
|
var nodes = []; |
|
quadtree.depth = 0; // root |
|
quadtree.visit(function(node, x1, y1, x2, y2) { |
|
node.x1 = x1; |
|
node.y1 = y1; |
|
node.x2 = x2; |
|
node.y2 = y2; |
|
nodes.push(node); |
|
for (var i=0; i<4; i++) { |
|
if (node.nodes[i]) node.nodes[i].depth = node.depth+1; |
|
} |
|
}); |
|
return nodes; |
|
} |
|
|
|
//Circles |
|
svg.selectAll('circle') |
|
.data(coords).enter().append('circle') |
|
.classed('circle', true) |
|
.attr('cx', function(d) { return d[0]; }) |
|
.attr('cy', function(d) { return d[1]; }) |
|
.attr('r', 5) |
|
} |