Published
Edited
Aug 27, 2020
8 forks
Importers
22 stars
Insert cell
Insert cell
circles
Insert cell
viewof circles = {
const context = DOM.context2d(width, height);
const canvas = context.canvas;

// An assortment of randomly-positioned colorful circles.
const circles = canvas.value = d3.range(20).map(i => ({
x: Math.random() * (width - radius * 2) + radius,
y: Math.random() * (height - radius * 2) + radius,
color: d3.schemeCategory10[i % 10]
}));

// Whenever the circles move, redraw the canvas.
function render() {
context.clearRect(0, 0, width, height);
for (const {x, y, color, active} of circles) {
context.beginPath();
context.moveTo(x + radius, y);
context.arc(x, y, radius, 0, 2 * Math.PI);
context.fillStyle = color;
context.fill();
if (active) {
context.lineWidth = 2;
context.stroke();
}
}
canvas.dispatchEvent(new CustomEvent("input"));
}

// Bind the drag behavior for interaction.
d3.select(context.canvas).call(drag(circles)
.on("start.render drag.render end.render", render));

// Render the initial canvas.
render();

return canvas;
}
Insert cell
drag = circles => {

// Choose the circle that is closest to the pointer for dragging.
function dragsubject(event) {
let subject = null;
let distance = maxDistance;
for (const c of circles) {
let d = Math.hypot(event.x - c.x, event.y - c.y);
if (d < distance) {
distance = d;
subject = c;
}
}
return subject;
}

// When starting a drag gesture, move the subject to the top and mark it as active.
function dragstarted(event) {
circles.splice(circles.indexOf(event.subject), 1);
circles.push(event.subject);
event.subject.active = true;
}

// When dragging, update the subject’s position.
function dragged(event) {
event.subject.x = Math.max(0, Math.min(width, event.x));
event.subject.y = Math.max(0, Math.min(height, event.y));
}

// When ending a drag gesture, mark the subject as inactive again.
function dragended(event) {
event.subject.active = false;
}

return d3.drag()
.subject(dragsubject)
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
Insert cell
maxDistance = Infinity // Limit the search distance, if desired.
Insert cell
height = 600
Insert cell
radius = 32
Insert cell
d3 = require("d3@6")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more