如何链接两个SVG元素,使得在一个上面鼠标悬停也可以引用另一个元素?

huangapple go评论72阅读模式
英文:

How to link two SVG elements so that mouseover on one can reference also the other?

问题

在我的代码中,我创建了一个文本标签和一个透明的矩形,以便用户可以轻松选择它。由于鼠标悬停事件被定义在矩形上,所以我无法对文本做任何操作(显然)。我应该如何最好地将文本与矩形“链接”起来?我需要每个矩形与相应的文本关联起来,但我找不到这样做的方法:

// 对于每个数据点,创建一个标签和一个矩形
settings.g.selectAll(".labels")
    .data(data)
    .join(
        enter => {
            let g = enter.append("g");
            let text = g.append("text");
            let rect = g.append("rect");

            text
                .text(d => d.name);
            rect
                .attr("width", d => d.bbox.width)
                .attr("height", d => d.bbox.height)
                .attr("fill", "transparent")
                .on('mouseover', function (d) {
                    // TODO: 使相应的文本加粗
                });
        }
    );

我知道我可以使用 selectAll("text") 并找到正确的文本,但这并不高效,因为有许多 "texts" 元素。

英文:

In my code, I create a text label and a transparent rect behind it so that user can easily select it. As the mouseover is defined on the rect, I cannot do anything with the text (obviously). How should I best "link" the text to the rectangle? I would need every rect to be linked to a respective text, but I could not find a way of doing in this way:

//for every data point, one label and one rect are created
settings.g.selectAll(".labels")
            .data(data)
            .join(
                enter => {
                    let g = enter.append("g");
                    let text = g.append("text")
                    let rect = g.append("rect");

                    text
                        .text(d => d.name)
                    rect
            
                        .attr("width", (d) => d.bbox.width)
                        .attr("height", (d) => d.bbox.height)
                        .attr("fill", "transparent")
                        .on('mouseover', function (d) {
                           //TODO: make the respective text BOLD
                        })

I know I could selectAll("text") and find the right one but that would not be efficient as there are many "texts".

答案1

得分: 1

以下是您要翻译的内容:

"不确定这是否是“最佳”方式,但这里有一个演示。
这起作用是因为 rect.nodes()[0] 匹配 text.nodes()[0] 等等,并且 e.target 是相关的 SVGRectElement。"

let data = [
    { name: "A", bbox: { x: 20, y: 20, width: 20, height: 40 } },
    { name: "B", bbox: { x: 60, y: 20, width: 20, height: 40 } },
    { name: "C", bbox: { x: 100, y: 20, width: 20, height: 40 } },
    { name: "D", bbox: { x: 140, y: 20, width: 20, height: 40 } },
]
document.addEventListener("DOMContentLoaded", () => {

    d3.select('#focus').selectAll(null).enter()
        .data(data)
        .join(enter => {

            let g = enter.append("g");
            let text = g.append("text")
            let rect = g.append("rect");

            text.text(d => d.name).attr('x', d => d.bbox.x + d.bbox.width / 2).attr('y', d => d.bbox.y + d.bbox.height / 2)
            rect.attr("width", (d) => d.bbox.width)
                .attr("height", (d) => d.bbox.height)
                .attr('x', d => d.bbox.x).attr('y', d => d.bbox.y)
                .attr("fill", "transparent")
                .on('mouseover', function (e, d) {
                  let idx = rect.nodes().indexOf(e.target);
                  let textElement = text.nodes()[idx]
                  d3.select(textElement).attr('font-weight', 'bold');
                }).on('mouseout', function (e, d) {
                  let idx = rect.nodes().indexOf(e.target);
                  let textElement = text.nodes()[idx]
                  d3.select(textElement).attr('font-weight', null);
                })

            return g;
        })

});
svg{
  width: 200px;
  height: 200px;
}

svg text{
  dominant-baseline: central;
  text-anchor: middle;
}

svg rect{
  cursor: pointer;
}
<script src="https://d3js.org/d3.v7.min.js"></script>

<body>
<svg id='focus'>

</svg>

</body>
英文:

Not sure if this is the "best" way, but here is a demo.<br>
This works because rect.nodes()[0] matches text.nodes()[0] and so on, and e.target is the relevant SVGRectElement.

<!-- begin snippet: js hide: false console: false babel: false -->

<!-- language: lang-js -->

let data = [
{ name: &quot;A&quot;, bbox: { x: 20, y: 20, width: 20, height: 40 } },
{ name: &quot;B&quot;, bbox: { x: 60, y: 20, width: 20, height: 40 } },
{ name: &quot;C&quot;, bbox: { x: 100, y: 20, width: 20, height: 40 } },
{ name: &quot;D&quot;, bbox: { x: 140, y: 20, width: 20, height: 40 } },
]
document.addEventListener(&quot;DOMContentLoaded&quot;, () =&gt; {
d3.select(&#39;#focus&#39;).selectAll(null).enter()
.data(data)
.join(enter =&gt; {
let g = enter.append(&quot;g&quot;);
let text = g.append(&quot;text&quot;)
let rect = g.append(&quot;rect&quot;);
text.text(d =&gt; d.name).attr(&#39;x&#39;, d =&gt; d.bbox.x + d.bbox.width / 2).attr(&#39;y&#39;, d =&gt; d.bbox.y + d.bbox.height / 2)
rect.attr(&quot;width&quot;, (d) =&gt; d.bbox.width)
.attr(&quot;height&quot;, (d) =&gt; d.bbox.height)
.attr(&#39;x&#39;, d =&gt; d.bbox.x).attr(&#39;y&#39;, d =&gt; d.bbox.y)
.attr(&quot;fill&quot;, &quot;transparent&quot;)
.on(&#39;mouseover&#39;, function (e, d) {
let idx = rect.nodes().indexOf(e.target);
let textElement = text.nodes()[idx]
d3.select(textElement).attr(&#39;font-weight&#39;, &#39;bold&#39;);
}).on(&#39;mouseout&#39;, function (e, d) {
let idx = rect.nodes().indexOf(e.target);
let textElement = text.nodes()[idx]
d3.select(textElement).attr(&#39;font-weight&#39;, null);
})
return g;
})
});

<!-- language: lang-css -->

svg{
width: 200px;
height: 200px;
}
svg text{
dominant-baseline: central;
text-anchor: middle;
}
svg rect{
cursor: pointer;
}

<!-- language: lang-html -->

&lt;script src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;
&lt;body&gt;
&lt;svg id=&#39;focus&#39;&gt;
&lt;/svg&gt;
&lt;/body&gt;

<!-- end snippet -->

答案2

得分: 0

你可以将鼠标悬停在包含 "rect" 和 "text" 的 g 元素上。
事件在悬停在 rect 或 text 上触发。然后,你可以获取文本元素并进行任何你想要的操作。

g.on('mouseover',function (){
    d3.select(this).select('text').style('font-weight','bold')
})
英文:

You can put the mouseover on the g element containing "rect" and "text".
Event is triggered on either rect or text hovering. You can then retrieve the text element and do whatever you want.

g.on(&#39;mouseover&#39;,function (){
d3.select(this).select(&#39;text&#39;).style(&#39;font-weight&#39;,&#39;bold&#39;)
})

huangapple
  • 本文由 发表于 2023年6月29日 14:29:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76578531.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定