Skip to content

Instantly share code, notes, and snippets.

@Fil
Last active November 17, 2016 15:29
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 Fil/56c02237d9951c4bb12ed41cf64d6e4c to your computer and use it in GitHub Desktop.
Save Fil/56c02237d9951c4bb12ed41cf64d6e4c to your computer and use it in GitHub Desktop.
Urquhart Force Mesh
license: gpl-3.0
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v4.js"></script>
<script>
var width = 960,
height = 500,
τ = 2 * Math.PI,
maxLength = 10000,
maxLength2 = maxLength * maxLength;
var nodes = d3.range(200).map(function() {
return {
x: Math.random() * width,
y: Math.random() * height
};
});
var force = d3.forceSimulation()
.nodes(nodes.slice())
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody().strength(function(d,i){
return i ? -25 : -1000
}))
.force("x", d3.forceX())
.force("y", d3.forceY())
.force("center", d3.forceCenter(width / 2, height / 2))
.on("tick", ticked);
var voronoi = d3.voronoi()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
var canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height)
.on("ontouchstart" in document ? "touchmove" : "mousemove", moved);
var context = canvas.node().getContext("2d");
function moved() {
var p1 = d3.mouse(this);
nodes[0].fx = p1[0];
nodes[0].fy = p1[1];
force.alpha(0.1).restart();
}
function urquhart(diagram){
var urquhart = d3.map();
diagram.links()
.forEach(function(link) {
var v = d3.extent([link.source.index, link.target.index]);
urquhart.set(v, link);
});
urquhart._remove = [];
diagram.triangles()
.forEach(function(t) {
var l = 0, length = 0, i="bleh", v;
for (var j=0; j<3; j++) {
var a = t[j], b = t[(j+1)%3];
v = d3.extent([a.index, b.index]);
length = (a.x-b.x) * (a.x-b.x) + (a.y-b.y) * (a.y-b.y);
if (length > l) {
l = length;
i = v;
}
}
urquhart._remove.push(i);
});
//console.log(JSON.stringify(urquhart._remove))
urquhart._remove.forEach(function(i) {
if (urquhart.has(i)) urquhart.remove(i);
});
return urquhart.values();
}
function ticked() {
var diagram = voronoi(nodes);
//var links = diagram.links();
var links = urquhart(diagram);
context.clearRect(0, 0, width, height);
context.beginPath();
for (var i = 0, n = links.length; i < n; ++i) {
var link = links[i],
dx = link.source.x - link.target.x,
dy = link.source.y - link.target.y;
if (dx * dx + dy * dy < maxLength2) {
context.moveTo(link.source.x, link.source.y);
context.lineTo(link.target.x, link.target.y);
}
}
context.lineWidth = 1;
context.strokeStyle = "#bbb";
context.stroke();
context.beginPath();
for (var i = 0, n = nodes.length; i < n; ++i) {
var node = nodes[i];
context.moveTo(node.x, node.y);
context.arc(node.x, node.y, 2, 0, τ);
}
context.lineWidth = 3;
context.strokeStyle = "#fff";
context.stroke();
context.fillStyle = "#000";
context.fill();
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment