英文:
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: "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;
})
});
<!-- language: lang-css -->
svg{
width: 200px;
height: 200px;
}
svg text{
dominant-baseline: central;
text-anchor: middle;
}
svg rect{
cursor: pointer;
}
<!-- language: lang-html -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<body>
<svg id='focus'>
</svg>
</body>
<!-- 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('mouseover',function (){
d3.select(this).select('text').style('font-weight','bold')
})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论