{
const width = 400;
const height = 400;
const count = 500;
const values = Array.from({length: count}, (_, i) => ({ x: Math.random() * width, y: Math.random() * height, i: i }));
const container = d3.create("div");
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.style("stroke", "black")
.style("fill", "none")
.style("stroke-width", 1);
const dots = svg
.append("g")
.style("fill", "steelblue")
.selectAll("dot")
.data(values)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", 5)
.style("opacity", 0.75);
const tooltip = container.append("div")
.style("display", "none")
.style("background", "rgba(69,77,93,.9)")
.style("border-radius", ".2rem")
.style("color", "#fff")
.style("padding", ".6rem")
.style("position", "absolute")
.style("text-overflow", "ellipsis")
.style("white-space", "pre")
.style("line-height", "1em")
.style("z-index", "300");
dots
.on("pointerenter pointermove", (e) => {
const xpos = d3.pointer(e, svg.node())[0];
const ypos = d3.pointer(e, svg.node())[1];
const d = d3.select(e.target).datum();
tooltip
.style("display", null)
.html(`index: ${d.i}<br>x: ${d.x}<br>y: ${d.y}`);
const { width: textw, height: texth } = tooltip.node().getBoundingClientRect();
tooltip
.style("left", (xpos - textw / 2) + "px")
.style("top", (ypos - texth - 5) + "px");
})
.on("pointerleave", (e) => {
tooltip.style("display", "none");
});
container.append(() => svg.node());
return container.node()
}