css 更精确的SVG文本元素边界框

c7rzv4ha  于 2024-01-09  发布在  其他
关注(0)|答案(1)|浏览(122)

我有一个"单词云",目前正在尝试在悬停在文本元素上时制作小工具提示。然而,"mouseover","mousemove"和"mouseout"事件在文本元素的"边界框"上操作。作为一个例子,在下图中,单词"merry"占据了"last"的相当大的一部分,这会导致混淆,因为工具提示将在悬停在"last"上时显示"merry"。
我不知道该怎么办。我试过了

text {
    pointer-events: painted;
}
/* and also */
svg {
    pointer-events: painted;
}

字符串
MDN,但这些不工作-相同的行为仍然存在。
这是我的工具提示代码,但我不认为它对这个问题很重要:

d3.selectAll("text")
    .on("mouseover", (e) => {
        tooltip
            .style("opacity", 1)
            .html(`<p>${e.target.textContent} used ${e.target.dataset.value} times</p>`)
            .style("left", e.pageX + "px")
            .style("top", e.pageY - 25 + "px");
    })
    .on("mousemove", (e) => {
        tooltip.style("left", e.pageX + "px").style("top", e.pageY - 25 + "px");
    })
    .on("mouseout", () => {
        tooltip.style("opacity", 0);
    });


在下面自己尝试一下。将鼠标悬停在"last"的下半部分并上下摆动鼠标。即使您的鼠标始终位于"last"上,控制台也会来回打印"merry"和"last"。

document.querySelectorAll("text").forEach((node) => {
    node.onmouseover = (e) => console.log(e.target.textContent);
})
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="900">
    <g transform="translate(450, 450)">
        <text data-value="63" text-anchor="middle" transform="translate(34, -59) rotate(0)" style="font-size: 507px; font-family: Impact; fill: #F12046">last</text>
        <text data-value="38" text-anchor="middle" transform="translate(15, 137) rotate(0)" style="font-size: 307px; font-family: Impact; fill: #009DDC">merry</text>
    </g>
</svg>

的字符串
如何让工具提示只在鼠标悬停在SVG的"已绘制"部分时显示?


的数据

olqngx59

olqngx591#

好吧...它并不完美,但我发现使用画布上下文和测量文本是相当准确的。这不是我希望的那样,但至少它是一个合理的边界框。
这是我的代码,插入近似测量文本的大小。

const ctx = document.createElement("canvas").getContext("2d")!;

document.querySelectorAll("text").forEach((text) => {
    ctx.font = `${text.style.fontSize} ${text.style.fontFamily}`;

    const metrics = ctx.measureText(text.textContent!);
    const width = metrics.actualBoundingBoxRight - metrics.actualBoundingBoxLeft;
    const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;

    const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");

    rect.dataset.word = text.textContent!;
    rect.dataset.value = text.dataset.value;

    console.log(metrics);

    rect.setAttributeNS(null, "x", (Number(text.dataset.x) - width / 2).toString());
    rect.setAttributeNS(
        null,
        "y",
        (Number(text.dataset.y) - height / 2 - (metrics as any).hangingBaseline / 2).toString()
    );
    rect.setAttributeNS(null, "width", width.toString());
    rect.setAttributeNS(null, "height", (height * 1.1).toString());
    rect.setAttributeNS(null, "fill", "rgba(0, 0, 0, 0.25)");

    text.parentNode!.insertBefore(rect, text.nextSibling);
});

字符串
然后我可以只监听rects上的事件。有时仍然会有一部分单词在边界框之外,但这比什么都不做要好得多。下面是结果(rects是灰色的):


的数据
参考文献:

相关问题