|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
.links { |
|
stroke: #000; |
|
stroke-opacity: 0.2; |
|
} |
|
|
|
.polygons { |
|
fill: none; |
|
stroke: #000; |
|
} |
|
|
|
.polygons.found { |
|
fill: #f00; |
|
} |
|
|
|
.sites { |
|
fill: #000; |
|
stroke: #fff; |
|
} |
|
|
|
|
|
|
|
</style> |
|
<svg width="960" height="500"></svg> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script> |
|
|
|
var svg = d3.select("svg").on("touchmove mousemove", moved), |
|
width = +svg.attr("width"), |
|
height = +svg.attr("height"); |
|
|
|
var sites = d3.range(1000) |
|
.map(function(d) { return [Math.random() * (width - 80) + 40, Math.random() * (height-80) + 40]; }); |
|
|
|
var voronoi = d3.voronoi() |
|
.extent([[30, 30], [width - 30, height - 30]]); |
|
|
|
var polygon = svg.append("g") |
|
.attr("class", "polygons") |
|
.selectAll("path") |
|
.data(voronoi.polygons(sites)) |
|
.enter().append("path") |
|
.call(redrawPolygon); |
|
|
|
var diagram = voronoi(sites); |
|
|
|
// voronoi.find is included in [d3 v4.3.0](https://github.com/d3/d3/releases/v4.3.0) |
|
// the following lines just add coloring |
|
diagram.find = function(x, y, radius) { |
|
var i, next = diagram.find.found || Math.floor(Math.random() * diagram.cells.length); |
|
var cell = diagram.cells[next] || diagram.cells[next=0]; |
|
var dx = x - cell.site[0], |
|
dy = y - cell.site[1], |
|
dist = dx*dx + dy*dy; |
|
|
|
|
|
do { |
|
cell = diagram.cells[i=next]; |
|
next = null; |
|
polygon._groups[0][i].setAttribute('fill', '#f5a61d'); |
|
cell.halfedges.forEach(function(e) { |
|
var edge = diagram.edges[e]; |
|
var ea = edge.left; |
|
if (ea === cell.site || !ea) { |
|
ea = edge.right; |
|
} |
|
if (ea){ |
|
if (polygon._groups[0][ea.index].getAttribute('fill') != '#f5a61d') |
|
polygon._groups[0][ea.index].setAttribute('fill', '#fbe8ab'); |
|
var dx = x - ea[0], |
|
dy = y - ea[1], |
|
ndist = dx*dx + dy*dy; |
|
if (ndist < dist){ |
|
dist = ndist; |
|
next = ea.index; |
|
return; |
|
} |
|
} |
|
}); |
|
|
|
} while (next !== null); |
|
|
|
diagram.find.found = i; |
|
if (!radius || dist < radius * radius) return cell.site; |
|
} |
|
|
|
|
|
findcell([width/2, height/2]); |
|
|
|
function moved() { |
|
findcell(d3.mouse(this)); |
|
} |
|
|
|
function findcell(m) { |
|
polygon.attr('fill', ''); |
|
var found = diagram.find(m[0],m[1], 50); |
|
if (found) |
|
polygon._groups[0][found.index].setAttribute('fill', 'red'); |
|
} |
|
|
|
function redraw() { |
|
polygon = polygon.data(diagram.polygons()).call(redrawPolygon); |
|
} |
|
|
|
function redrawPolygon(polygon) { |
|
polygon |
|
.attr("d", function(d) { return d ? "M" + d.join("L") + "Z" : null; }); |
|
} |
|
|
|
|
|
</script> |