Published
Edited
Oct 27, 2021
1 fork
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
{
const height = 500;
const context = DOM.context2d(width, height);
const numPoints = 50e3;
const random = d3.randomNormal(0, width * 0.12);
const points = d3
.range(numPoints)
.map(() => ({ x: random() + width * 0.7, y: random() + height * 0.6 }));
const delaunay = d3.Delaunay.from(
points,
(d) => d.x,
(d) => d.y
);
let prevIndex;
const findDot = (evt) => {
evt.preventDefault();
let x = evt.layerX;
let y = evt.layerY;
if (!x) {
const rect = evt.target.getBoundingClientRect();
x = evt?.touches?.[0]?.clientX - rect.left;
y = evt?.touches?.[0]?.clientY - rect.top;
}
const foundIndex = delaunay.find(x, y, prevIndex || 0);
prevIndex = foundIndex;
const point = points[foundIndex];
const pointElement = document.querySelector(".point");
if (point && pointElement) {
pointElement.style.visibility = `visible`;
pointElement.style.top = `${point.y}px`;
pointElement.style.left = `${point.x}px`;
}
};
context.canvas.addEventListener("mousemove", findDot, { passive: false });
context.canvas.addEventListener("touchmove", findDot);
context.clearRect(0, 0, width, height);
for (const point of points) {
context.beginPath();
context.moveTo(point.x, point.y);
context.arc(point.x, point.y, width * 0.003, 0, Math.PI * 2);
context.fillStyle = `rgba(0, 0, 0, 0.1)`;
context.fill();
}
return html`
<div>
<div class="point" style="position: absolute; left: 0; top: 0; pointer-events: none; visibility: hidden;">
<svg style="overflow: visible;">
<circle r="10" fill="red" />
</svg>
</div>
${context.canvas}
</div>`;
}
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