hover_with_rect = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("overflow", "display");
const circles = svg
.selectAll("circle")
.data(state_data)
.join("circle")
.attr("r", 5)
.attr("cx", d => x(d.x))
.attr("cy", d => y(d.y))
.attr("opacity", .3);
const tip = svg
.append("g")
.style("pointer-events", "none")
.style("text-anchor", "middle");
circles.on("mouseenter", event => {
const value = event.target.__data__;
const pointer = d3.pointer(event, this);
const text = [value.name, "City: " + value.city];
const side_padding = 3;
tip
.style("text-anchor", "middle")
.attr("transform", `translate(${pointer[0]}, ${pointer[1]})`)
.selectAll("text")
.data(text)
.join('text')
.style("dominant-baseline", "ideographic")
.text(d => d)
.attr("y", (d, i) => (i - (text.length - 1)) * 15)
.style("font-weight", (d, i) => (i === 0 ? "bold" : "normal"));
const bbox = tip.node().getBBox();
tip
.append("rect")
.attr("y", bbox.y)
.attr("x", bbox.x - side_padding)
.attr("width", bbox.width + side_padding * 2)
.attr("height", bbox.height)
.style("fill", "white")
.style("stroke", "#d3d3d3")
.lower();
if (pointer[0] + bbox.x < margin.left) {
tip.attr(
"transform",
`translate(${margin.left + bbox.width / 2}, ${pointer[1]})`
);
}
if (pointer[0] - bbox.x > width - margin.right) {
tip.attr(
"transform",
`translate(${width - margin.right - bbox.width / 2}, ${pointer[1]})`
);
}
});
circles.on("mouseout", event => {
tip.selectAll("*").remove();
});
svg.append("g").call(xAxis);
svg.append("g").call(yAxis);
return svg.node();
}