当鼠标悬停时更改SVG <g/>坐标

3

我有一个由x和y坐标组成的数组:

var coordinateX = [10,20,30,40,50,....];
var coordinateY = [10,20,30,40,50,....]:

这些坐标是圆心,当鼠标悬停在圆上时我希望显示工具提示。

for (var i = 0; i < circles.length; i++) {
    circles[i].addEventListener('mousemove', show);
    circles[i].addEventListener('mouseout', hide);
}

工具提示是以矩形和文本为内容的 g 元素表示

<g id="poligon" visibility="hidden" class="element">
  <rect width="80" height="20" fill="white"/>
  <text class="tooltip" x="4" y="15" dominant-baseline="centered">Tooltip</text>
</g>

var poligon = svgDoc.getElementById("poligon")

function show(evt) {
  poligon.setAttributeNS(null, "transform","translate(" + coordinateX[i] + ", " + coordinatey[i] + ")");
  poligon.setAttributeNS(null, "visibility", "visible");
  textTooltipVrijednost.data = evt.target.getAttributeNS(null, "class");    
}

function hide(){
  poligon.setAttributeNS(null, "visibility", "hidden");
}

我尝试使用setAttribute和更改转换属性的x、y值来翻译g元素,但我只得到了最后一个位置值。如何为每个位置动态地执行此操作?

最后位置值是什么意思? - Scott Anderson
例如,coordinateX数组中的最后一个值为50,coordinateY数组中的最后一个值也是50...因此,使用我的代码,当我悬停在任何圆圈上时,我的工具提示将显示在50,50位置。 - Hyacinth
好的,问题和我想的有点不同,但是来吧:在 show(evt) {..coordinateX[i] + "," + coordinateY[i] 中,索引 i 是从哪里来的?如果您想让它按您最初创建事件监听器的索引移动,它将无法正常工作,因为索引 i 未与事件监听器一起存储。 我也遇到了这个问题,并通过在相关数据与实际 DOM 节点之间使用 Map 结构来解决了它。 - Scott Anderson
我的想法是循环遍历坐标数组,这样我就可以将每个坐标对(coordinateX[i]和coordinateY[i])传递给g元素的translate属性。然后在悬停所属圆圈时使用事件监听器调用show(evt)函数。您能否详细解释一下,使用Map结构将相关数据与所涉及的物理DOM节点之间建立联系是什么意思? - Hyacinth
一个更好的想法是使用外部 div 作为工具提示。 - enxaneta
@Zmaj,说实话,我认为你应该听从enxaneta的答案,因为他们似乎比我更了解你的问题 - 我在你的JavaScript代码中看到一个问题,在那里你试图用i(你用来索引circles的变量不再存在)索引你的坐标数组,但是这会创建一个引用错误而不是你所描述的问题。我认为我错了,你应该听取其他人的意见。尽管如此,JS中的Map允许你将任何东西直接关联成对: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map - Scott Anderson
2个回答

1

如我所评论的,更好的想法是使用HTML元素作为工具提示。这样,当SVG元素在小尺寸下时,文本可能变得太小而无法阅读时,就不会出现问题。

主要思路是检测鼠标在SVG元素上的位置。如果鼠标进入圆圈,则工具提示变为可见,并占据鼠标的位置。此外,在这种情况下,还显示了圆圈的坐标。当鼠标离开圆圈时,工具提示的显示返回到none

希望能对您有所帮助。

const SVG_NS = 'http://www.w3.org/2000/svg';
let coordinates = [{cx:10,cy:7,r:5},{cx:10,cy:30,r:5},{cx:50,cy:10,r:5},{cx:33,cy:25,r:5}]

let circles = []

coordinates.forEach(c=>{
  circles.push(drawCircle(c, svg))
})

circles.forEach((c,i)=>{
  c.addEventListener("mouseenter",(e)=>{
    let m = oMousePos(svg, e);
    let cx = coordinates[i].cx;
    let cy = coordinates[i].cy;
    tooltip.style.display = "block"
    tooltip.style.left = m.x+"px";
    tooltip.style.top = m.y+"px";
    tooltip.innerHTML = `${cx}, ${cy}`
  })
  c.addEventListener("mouseleave",(e)=>{
    tooltip.style.display = "none"
  })
})




function drawCircle(o, parent) {

  var circle = document.createElementNS(SVG_NS, 'circle');
  for (var name in o) {
    if (o.hasOwnProperty(name)) {
      circle.setAttributeNS(null, name, o[name]);
    }
  }
  parent.appendChild(circle);
  return circle;
}



function oMousePos(svg, evt) {
      var ClientRect = svg.getBoundingClientRect();
                return { //objeto
                x: Math.round(evt.clientX - ClientRect.left),
                y: Math.round(evt.clientY - ClientRect.top)
      }
}
svg {
  border: 1px solid;
  width:100vh;
}
#wrap {
  position: relative;
}
#tooltip {
  position: absolute;
  width: 80px;
  height: 30px;
  background: white;
  border: 1px solid;
  text-align: center;
  line-height: 30px;
  top: 0;
  left: 0;
  display: none;
  pointer-events: none;
}
<div id="wrap">
<svg id="svg" viewBox="0 0 60 40"></svg>

<div id="tooltip">0,0</div>
  
</div>


有用的,有趣的答案 - Alexandr_TT

0
一个解决方案是将 i 直接传递给你的 show() 函数。
for (let i = 0; i < circles.length; i++) {  // <-- change "var" to "let"
    circles[i].addEventListener('mousemove', function() { show(i) });
    circles[i].addEventListener('mouseout', hide);
}

function show(i) {
  poligon.setAttributeNS(null, "transform","translate(" + coordinateX[i] + ", " + coordinatey[i] + ")");
  poligon.setAttributeNS(null, "visibility", "visible");
  textTooltipVrijednost.data = evt.target.getAttributeNS(null, "class");    
}

var coordinateX = [10,20,30,40,50];
var coordinateY = [10,20,30,40,50];

var svgDoc = document.querySelector("svg");
var poligon = svgDoc.getElementById("poligon")

for (let i = 0; i < coordinateX.length; i++) {
  var circle = document.createElementNS(svgDoc.namespaceURI, "circle");
  circle.setAttribute("cx", coordinateX[i]);
  circle.setAttribute("cy", coordinateY[i]);
  circle.setAttribute("r", "5");
  svgDoc.appendChild(circle);

  circle.addEventListener('mousemove', function() { show(i); } );
  circle.addEventListener('mouseout', hide);
}



function show(i) {
  poligon.setAttribute("transform","translate(" + coordinateX[i] + ", " + coordinateY[i] + ")");
  poligon.setAttribute("visibility", "visible");
}

function hide(){
  poligon.setAttributeNS(null, "visibility", "hidden");
}
<svg width="400" height="400" viewBox="0 0 200 200">

  <g id="poligon" visibility="hidden" class="element">
    <rect width="80" height="20" fill="white"/>
    <text class="tooltip" x="4" y="15" dominant-baseline="centered">Tooltip</text>
  </g>

</svg>


谢谢你们俩,我已经为这个问题挣扎了一段时间。 - Hyacinth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接