image = {
const svg = htl.svg`<svg width=600 height=500 style="border:1px solid #aaa">`;
const points = htl.svg`<g>`;
const frame = htl.svg`<rect x=150 y=150 width=300 height=200 stroke="#0008" fill="#0001" />`;
svg.append(frame, points);
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);
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) {
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;
}