Public
Edited
Jun 3, 2024
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
image = {
// For brevity we create the elements through htl instead of d3.
// We'll wrap them in d3.select(element) whenever we require a d3 selection.
const svg = htl.svg`<svg width=600 height=500 style="border:1px solid #aaa">`;
// This group will be the transform target to which we add our data points.
const points = htl.svg`<g>`;
// This rect will become the area in which the most recent point needs to be visible.
const frame = htl.svg`<rect x=150 y=150 width=300 height=200 stroke="#0008" fill="#0001" />`;
svg.append(frame, points);

// A helper to get the [left, top, right, bottom] bxtent for an SVG element.
// Optionally we can pass sx() and sy() to scale the offsets.
function extent(element, sx = d => d, sy = d => d) {
const {x, y, width, height} = element.getBBox();
return [sx(x), sy(y), sx(x + width), sy(y + height)];
}
svg.addEventListener("click", e => {
const [x, y] = d3.pointer(e, points);
const element = htl.svg`<circle cx=${x} cy=${y} r=5 fill=black />`;
points.append(element);
// Fade out points and remove them after a while.
d3.select(element).transition().duration(10000).attr("fill", "#0000").remove();

const t = d3.zoomTransform(svg);
const [ax0, ay0, ax1, ay1] = extent(frame, x => t.invertX(x), y => t.invertY(y));
const [bx0, by0, bx1, by1] = extent(element);

const dx = bx0 < ax0 ? ax0 - bx0 : bx1 > ax1 ? ax1 - bx1 : 0;
const dy = by0 < ay0 ? ay0 - by0 : by1 > ay1 ? ay1 - by1 : 0;
if(dx || dy) {
// We pass a transition so that d3-zoom will automatically animate the change.
const transition = d3.select(svg).transition().delay(150).duration(250).ease(d3.easeCubicOut);
zoom.translateBy(transition, dx, dy);
}
});

const zoom = d3.zoom().on("zoom", ({transform}) => {
d3.select(points).attr("transform", transform);
});
d3.select(svg).call(zoom);
svg.zoom = zoom;
return svg;
}
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more