d3 Node Tree
by Sam Fereday
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<canvas width="960" height="500"></canvas>
JavaScript
var canvas = d3.select("canvas"),
context = canvas.node().getContext("2d"),
width = canvas.property("width"),
height = canvas.property("height"),
radius = 2.5,
transform = d3.zoomIdentity;
var points = d3.range(200).map(phyllotaxis(10));
canvas
.call(d3.drag().subject(dragsubject).on("drag", dragged))
.call(d3.zoom().scaleExtent([1 / 2, 8]).on("zoom", zoomed))
.call(render);
function zoomed() {
transform = d3.event.transform;
render();
}
function dragsubject() {
var i,
x = transform.invertX(d3.event.x),
y = transform.invertY(d3.event.y),
dx,
dy;
for (i = points.length - 1; i >= 0; --i) {
point = points[i];
dx = x - point[0];
dy = y - point[1];
if (dx * dx + dy * dy < radius * radius) {
point.x = transform.applyX(point[0]);
point.y = transform.applyY(point[1]);
return point;
}
}
}
function dragged() {
d3.event.subject[0] = transform.invertX(d3.event.x);
d3.event.subject[1] = transform.invertY(d3.event.y);
render();
}
function render() {
context.save();
context.clearRect(0, 0, width, height);
context.beginPath();
context.translate(transform.x, transform.y);
context.scale(transform.k, transform.k);
points.forEach(drawPoint);
context.fill();
context.restore();
}
function drawPoint(point) {
//context.moveTo(point[0] + radius, point[1]);
//context.arc(point[0], point[1], radius, 0, 2 * Math.PI);
context.rect(point[0],point[1],10,10);
context.stroke();
}
function phyllotaxis(radius) {
var theta = Math.PI * (3 - Math.sqrt(5));
return function(i) {
var r = radius * Math.sqrt(i),
a = theta * i;
return [
width / 2 + r * Math.cos(a),
height / 2 + r * Math.sin(a)
];
};
}