Skip to content

Instantly share code, notes, and snippets.

@ddramone
Last active August 25, 2017 09:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ddramone/5db5cf87f906beb9a01e924dabffecf7 to your computer and use it in GitHub Desktop.
Save ddramone/5db5cf87f906beb9a01e924dabffecf7 to your computer and use it in GitHub Desktop.
voronoi knn
license: mit
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.links {
stroke: #000;
stroke-opacity: 0.2;
}
.polygons {
fill: none;
stroke: #000;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
console.clear();
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
/** DUMB DATA **/
var sites = d3.range(200)
.map(function(d) {
var x = Math.random() * (width - 80) + 40;
var y = Math.random() * (height-80) + 40;
return {
x: x,
y: y,
id: 'luminiare'+Math.random()
};
}).filter((point)=>{
var x = point.x;
var y = point.y;
xInRange = x>200 && x<600;
yInRange = y<400;
return !(xInRange && yInRange);
});
var voronoi = d3.voronoi()
.x((d)=>d.x)
.y((d)=>d.y)
.extent([[0, 0], [width, height]]);
var diagram = voronoi(sites);
var links = diagram.links();
var averageDistance = getAverageDistance();
var radius = svg.append("g")
.attr("class", "spread");
var polygon = svg.append("g")
.attr("class", "polygons")
.selectAll("path")
.data(voronoi.polygons(sites))
.enter().append("path")
.attr('stroke','cyan')
.call(redrawPolygon);
var circles = svg.append("g")
.attr("class", "circles")
.selectAll('circle')
.data(sites)
.enter().append('circle')
.attr('r', 10)
.attr('fill',function(d){
return 'red';
})
.attr("cy", (d)=> d.y)
.attr("cx", (d)=> d.x)
.on("click", findNeighbours)
.on("mouseenter", showRadius)
function showRadius(){
var cell = findCell(d3.mouse(this));
radius.selectAll('circle').remove();
radius
.append('circle')
.attr('r', averageDistance)
.attr("cy", cell.data.y)
.attr("cx", cell.data.x)
.attr('stroke','blue')
.attr('fill','#fffbea');
}
var highlighted = [];
function findCell(m) {
return diagram.find(m[0],m[1])
}
function findNeighbours() {
var cell = findCell(d3.mouse(this));
var cellData = diagram.cells[cell.index];
cell.data.status = 'localized';
for(var edgeIndex of cellData.halfedges)
{
var edge = diagram.edges[edgeIndex];
var neighbour = edge.left == cell ? edge.right : edge.left;
if(!neighbour) continue;
if(neighbour.data.status == 'localized') continue;
var tP = neighbour.data; // target Point
var sP = cell.data; // source Point
var distance = Math.sqrt(
(Math.pow(tP.x-sP.x,2))+
(Math.pow(tP.y-sP.y,2)))
if(distance < averageDistance){
neighbour.data.status = 'highlighted';
}
// break;
}
redraw();
}
function redraw() {
circles.data(sites)
.attr('fill',function(d){
return {
localized: 'blue',
highlighted: 'green'
}[d.status] || 'red'
})
}
function redrawPolygon(polygon) {
polygon
.attr("d", function(d) { return d ? "M" + d.join("L") + "Z" : null; });
}
function getAverageDistance() {
var distances = links.map(function(d) {
return Math.sqrt(
Math.pow(d.target.x - d.source.x,2) +
Math.pow(d.target.y - d.source.y,2)
);
});
var max = d3.max(distances);
var min = d3.min(distances);
var mean = d3.mean(distances);
return max-(max-mean)/2;
return (max+mean)/2;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment