D3 -在SVG元素上的定位工具提示不起作用。

时间:2022-11-20 14:35:15

I have a webpage with an SVG. On some of its shapes I need to display a tooltip. However, I can't get the tooltip to appear where it should, just some pixels away from the shape itself.

我有一个带有SVG的网页。在它的一些形状上,我需要显示一个工具提示。但是,我不能让工具提示出现在它应该出现的地方,只是一些像素远离了形状本身。

It appears way on the right hand side of the screen, maybe some 300px away. The code I am using to get the coordinates is as follows:

它出现在屏幕的右边,大约300像素。我使用的获取坐标的代码如下:

d3.select("body")
  .select("svg")
  .select("g")
  .selectAll("circle")
  .on("mouseover", function(){return tooltip.style("visibility", "visible");})
  .on("mousemove", function(){

var svgPos = $('svg').offset(),

/*** Tooltip ***/

//This should be the correct one, but is displaying at all working at all.
/*x = svgPos.left + d3.event.target.cx.animVal.value,
y = svgPos.top + d3.event.target.cy.animVal.value;*/


//This displays a tool tip but way much to the left of the screen.
x = svgPos.left + d3.event.target.cx.animVal.value,
y = svgPos.top + d3.event.target.cy.animVal.value;

Tooltip
window.alert("svgPos: "+svgPos+"        top: "+y+"px          left: "+x+"px     "+d3.event.target.cx.animVal.value);


return tooltip.style("top", x+"px").style("left",y+"px");
})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");});

I got to this code following this SO post.

在这之后,我得到了这个代码。

I have changed $(ev.target).attr(cx) as it is not returning a value on my machine; d3.event.target.cx is, even though it seems it is not affecting the end result anyway.

我已经更改了$(ev.target).attr(cx),因为它没有返回我的机器上的值;d3.event.target。cx是,尽管它似乎并没有影响到最终结果。

What am I doing wrong? Could somebody help me please? Thank you very much in advance for your time.

我做错了什么?有人能帮我吗?非常感谢您的时间。

1 个解决方案

#1


29  

If your tooltip is an HTML element, then you want to position it relative to the page as a whole, not the internal SVG coordinates, so accessing the cx/cy value is just complicating things. I can't say for sure without looking at your code, but if you have any transforms on your <svg> or <g> elements, then that could be what's throwing you off.

如果您的工具提示是一个HTML元素,那么您希望将它与整个页面相关联,而不是内部SVG坐标,因此访问cx/cy值只会使事情复杂化。我不能肯定地说,没有看你的代码,但是如果你的 元素上有任何转换,那么这可能就是让你崩溃的原因。

However, there is a much easier solution. Just access the mouse event's default .pageX and .pageY properties, which give the position of the mouse relative to the HTML body, and use these coordinates to position your tooltip div.

然而,有一个更简单的解决方案。只需要访问鼠标事件的默认值. pagex和. pagey属性,就会给出鼠标相对于HTML主体的位置,并使用这些坐标来定位你的工具提示div。

Example here: http://fiddle.jshell.net/tPv46/1/

例子:http://fiddle.jshell.net/tPv46/1/

Key code:

关键代码:

.on("mousemove", function () {
    //console.log(d3.event);
    return tooltip
        .style("top", (d3.event.pageY + 16) + "px")
        .style("left", (d3.event.pageX + 16) + "px");
})

Even with rotational transforms on the SVG circles, the mouse knows where it is on the page and the tooltip is positioned accordingly.

即使在SVG圈上进行旋转转换,鼠标也知道它在页面上的位置,工具提示也相应地定位。

There are other ways to do this, including getting a tooltip to show up in a fixed location relative to the circle instead of following the mouse around, but I just checked the examples I was working on and realized they aren't cross-browser compatible, so I'll have to standardize them and get back to you. In the meantime, I hope this gets you back on track with your project.

还有其他的方法可以做到这一点,包括获取工具提示显示在一个固定的位置相对于后的圆,而不是老鼠,我只是检查我工作的例子,发现他们不是跨浏览器兼容的,所以我必须规范和送还给你。同时,我希望这能让你回到项目的轨道上来。

Edit 1

For comparison, here is the same example implemented with both an HTML tooltip (a <div> element) and an SVG tooltip (a <g> element).

为了进行比较,这里有一个相同的示例,它同时实现了一个HTML工具提示(一个

元素)和一个SVG工具提示(一个 元素)。

http://fiddle.jshell.net/tPv46/4/

http://fiddle.jshell.net/tPv46/4/

The default mouse event coordinates may be great for positioning HTML elements that are direct children of <body>, but they are less useful for positioning SVG elements. The d3.mouse() function calculates the mouse coordinates of the current event relative to a specified SVG element's coordinate system, after all transformations have been applied. It can therefore be used to get the mouse coordinates in the form we need to position an SVG tooltip.

默认的鼠标事件坐标可能非常适合定位HTML元素,这些元素是的直接子元素,但是它们对定位SVG元素没有多大用处。在应用了所有转换之后,d3.mouse()函数计算当前事件相对于指定的SVG元素的坐标系统的鼠标坐标。因此,可以使用它来获取表单中需要放置SVG工具提示的鼠标坐标。

Key code:

关键代码:

.on("mousemove", function () {


    var mouseCoords = d3.mouse(
        SVGtooltip[0][0].parentNode);
    //the d3.mouse() function calculates the mouse
    //position relative to an SVG Element, in that 
    //element's coordinate system 
    //(after transform or viewBox attributes).

    //Because we're using the coordinates to position
    //the SVG tooltip, we want the coordinates to be
    //with respect to that element's parent.
    //SVGtooltip[0][0] accesses the (first and only)
    //selected element from the saved d3 selection object.

    SVGtooltip
        .attr("transform", "translate(" + (mouseCoords[0]-30)
                  + "," + (mouseCoords[1]-30) + ")");

    HTMLtooltip
        .style("top", (d3.event.pageY + 16) + "px")
        .style("left", (d3.event.pageX + 16) + "px");
})

Note that it works even though I've scaled the SVG with a viewBox attribute and put the tooltip inside a <g> with a transform attribute.

请注意,即使我使用viewBox属性缩放SVG,并将工具提示放在 中,并使用转换属性,它仍然有效。

Tested and works in Chrome, Firefox, and Opera (reasonably recent versions) -- although the text in the SVG tooltip might extend past its rectangle depending on your font settings. One reason to use an HTML tooltip! Another reason is that it doesn't get cut off by the edge of the SVG.

测试和工作在Chrome, Firefox和Opera(合理的最新版本)——尽管SVG工具提示中的文本可能会根据您的字体设置扩展到它的矩形。使用HTML工具提示的一个原因!另一个原因是它不会被SVG的边缘切断。

Leave a comment if you have any bugs in Safari or IE9/10/11. (IE8 and under are out of luck, since they don't do SVG).

如果在Safari或IE9/10/11中有任何bug,请留下评论。(IE8和under是不吉利的,因为它们不做SVG)。

Edit 2

So what about your original idea, to position the tooltip on the circle itself? There are definite benefits to being able to position the tip exactly: better layout control, and the text doesn't wiggle around with the mouse. And most importantly, you can just position it once, on the mouseover event, instead of reacting to every mousemove event.

那么你的原始想法是什么呢,把工具提示放在圆上?能够精确定位提示有一定的好处:更好的布局控制,而文本不会和鼠标一起摆动。最重要的是,你可以在mouseover事件上只定位一次,而不是对每个mousemove事件做出反应。

But to do this, you can no longer just use the mouse position to figure out where to put the tooltip -- you need to figure out the position of the element, which means you have to deal with transformations. The SVG spec introduces a set of interfaces for locating SVG elements relative to other parts of the DOM.

但是要做到这一点,您不能再仅仅使用鼠标位置来计算工具提示的位置——您需要确定元素的位置,这意味着您必须处理转换。SVG规范引入了一组接口,用于定位相对于DOM其他部分的SVG元素。

For converting between two SVG transformation systems you use SVGElement.getTransformToElement(SVGElement); for converting between an SVG coordinate system and the screen, you use SVGElement.getScreenCTM(). The result are transformation matrices from which you can extract the net horizontal and vertical translation.

为了在两个SVG转换系统之间转换,可以使用SVGElement.getTransformToElement(SVGElement);要在SVG坐标系和屏幕之间进行转换,可以使用SVGElement.getScreenCTM()。结果是变换矩阵,你可以从中提取净水平和垂直的平移。

The key code for the SVG tooltip is

SVG工具提示的关键代码是。

    var tooltipParent = SVGtooltip[0][0].parentNode;
    var matrix = 
            this.getTransformToElement(tooltipParent)
                .translate(+this.getAttribute("cx"),
                     +this.getAttribute("cy"));
    SVGtooltip
        .attr("transform", "translate(" + (matrix.e)
                  + "," + (matrix.f - 30) + ")");

The key code for the HTML tooltip is

HTML工具提示的关键代码是。

    var matrix = this.getScreenCTM()
            .translate(+this.getAttribute("cx"),
                     +this.getAttribute("cy"));

    absoluteHTMLtooltip
        .style("left", 
               (window.pageXOffset + matrix.e) + "px")
        .style("top",
               (window.pageYOffset + matrix.f + 30) + "px");

Live example: http://fiddle.jshell.net/tPv46/89/

生活例子:http://fiddle.jshell.net/tPv46/89/

Again, I'd appreciate a confirmation comment from anyone who can test this in Safari or IE -- or any mobile browser. I'm pretty sure I've used standard API for everything, but just because the API is standard doesn't mean it's universally implemented!

再一次,我希望任何人能在Safari或IE或任何移动浏览器上测试它。我很确定我已经使用了标准的API,但是仅仅因为API是标准的并不意味着它得到了普遍的实现!

#1


29  

If your tooltip is an HTML element, then you want to position it relative to the page as a whole, not the internal SVG coordinates, so accessing the cx/cy value is just complicating things. I can't say for sure without looking at your code, but if you have any transforms on your <svg> or <g> elements, then that could be what's throwing you off.

如果您的工具提示是一个HTML元素,那么您希望将它与整个页面相关联,而不是内部SVG坐标,因此访问cx/cy值只会使事情复杂化。我不能肯定地说,没有看你的代码,但是如果你的 元素上有任何转换,那么这可能就是让你崩溃的原因。

However, there is a much easier solution. Just access the mouse event's default .pageX and .pageY properties, which give the position of the mouse relative to the HTML body, and use these coordinates to position your tooltip div.

然而,有一个更简单的解决方案。只需要访问鼠标事件的默认值. pagex和. pagey属性,就会给出鼠标相对于HTML主体的位置,并使用这些坐标来定位你的工具提示div。

Example here: http://fiddle.jshell.net/tPv46/1/

例子:http://fiddle.jshell.net/tPv46/1/

Key code:

关键代码:

.on("mousemove", function () {
    //console.log(d3.event);
    return tooltip
        .style("top", (d3.event.pageY + 16) + "px")
        .style("left", (d3.event.pageX + 16) + "px");
})

Even with rotational transforms on the SVG circles, the mouse knows where it is on the page and the tooltip is positioned accordingly.

即使在SVG圈上进行旋转转换,鼠标也知道它在页面上的位置,工具提示也相应地定位。

There are other ways to do this, including getting a tooltip to show up in a fixed location relative to the circle instead of following the mouse around, but I just checked the examples I was working on and realized they aren't cross-browser compatible, so I'll have to standardize them and get back to you. In the meantime, I hope this gets you back on track with your project.

还有其他的方法可以做到这一点,包括获取工具提示显示在一个固定的位置相对于后的圆,而不是老鼠,我只是检查我工作的例子,发现他们不是跨浏览器兼容的,所以我必须规范和送还给你。同时,我希望这能让你回到项目的轨道上来。

Edit 1

For comparison, here is the same example implemented with both an HTML tooltip (a <div> element) and an SVG tooltip (a <g> element).

为了进行比较,这里有一个相同的示例,它同时实现了一个HTML工具提示(一个

元素)和一个SVG工具提示(一个 元素)。

http://fiddle.jshell.net/tPv46/4/

http://fiddle.jshell.net/tPv46/4/

The default mouse event coordinates may be great for positioning HTML elements that are direct children of <body>, but they are less useful for positioning SVG elements. The d3.mouse() function calculates the mouse coordinates of the current event relative to a specified SVG element's coordinate system, after all transformations have been applied. It can therefore be used to get the mouse coordinates in the form we need to position an SVG tooltip.

默认的鼠标事件坐标可能非常适合定位HTML元素,这些元素是的直接子元素,但是它们对定位SVG元素没有多大用处。在应用了所有转换之后,d3.mouse()函数计算当前事件相对于指定的SVG元素的坐标系统的鼠标坐标。因此,可以使用它来获取表单中需要放置SVG工具提示的鼠标坐标。

Key code:

关键代码:

.on("mousemove", function () {


    var mouseCoords = d3.mouse(
        SVGtooltip[0][0].parentNode);
    //the d3.mouse() function calculates the mouse
    //position relative to an SVG Element, in that 
    //element's coordinate system 
    //(after transform or viewBox attributes).

    //Because we're using the coordinates to position
    //the SVG tooltip, we want the coordinates to be
    //with respect to that element's parent.
    //SVGtooltip[0][0] accesses the (first and only)
    //selected element from the saved d3 selection object.

    SVGtooltip
        .attr("transform", "translate(" + (mouseCoords[0]-30)
                  + "," + (mouseCoords[1]-30) + ")");

    HTMLtooltip
        .style("top", (d3.event.pageY + 16) + "px")
        .style("left", (d3.event.pageX + 16) + "px");
})

Note that it works even though I've scaled the SVG with a viewBox attribute and put the tooltip inside a <g> with a transform attribute.

请注意,即使我使用viewBox属性缩放SVG,并将工具提示放在 中,并使用转换属性,它仍然有效。

Tested and works in Chrome, Firefox, and Opera (reasonably recent versions) -- although the text in the SVG tooltip might extend past its rectangle depending on your font settings. One reason to use an HTML tooltip! Another reason is that it doesn't get cut off by the edge of the SVG.

测试和工作在Chrome, Firefox和Opera(合理的最新版本)——尽管SVG工具提示中的文本可能会根据您的字体设置扩展到它的矩形。使用HTML工具提示的一个原因!另一个原因是它不会被SVG的边缘切断。

Leave a comment if you have any bugs in Safari or IE9/10/11. (IE8 and under are out of luck, since they don't do SVG).

如果在Safari或IE9/10/11中有任何bug,请留下评论。(IE8和under是不吉利的,因为它们不做SVG)。

Edit 2

So what about your original idea, to position the tooltip on the circle itself? There are definite benefits to being able to position the tip exactly: better layout control, and the text doesn't wiggle around with the mouse. And most importantly, you can just position it once, on the mouseover event, instead of reacting to every mousemove event.

那么你的原始想法是什么呢,把工具提示放在圆上?能够精确定位提示有一定的好处:更好的布局控制,而文本不会和鼠标一起摆动。最重要的是,你可以在mouseover事件上只定位一次,而不是对每个mousemove事件做出反应。

But to do this, you can no longer just use the mouse position to figure out where to put the tooltip -- you need to figure out the position of the element, which means you have to deal with transformations. The SVG spec introduces a set of interfaces for locating SVG elements relative to other parts of the DOM.

但是要做到这一点,您不能再仅仅使用鼠标位置来计算工具提示的位置——您需要确定元素的位置,这意味着您必须处理转换。SVG规范引入了一组接口,用于定位相对于DOM其他部分的SVG元素。

For converting between two SVG transformation systems you use SVGElement.getTransformToElement(SVGElement); for converting between an SVG coordinate system and the screen, you use SVGElement.getScreenCTM(). The result are transformation matrices from which you can extract the net horizontal and vertical translation.

为了在两个SVG转换系统之间转换,可以使用SVGElement.getTransformToElement(SVGElement);要在SVG坐标系和屏幕之间进行转换,可以使用SVGElement.getScreenCTM()。结果是变换矩阵,你可以从中提取净水平和垂直的平移。

The key code for the SVG tooltip is

SVG工具提示的关键代码是。

    var tooltipParent = SVGtooltip[0][0].parentNode;
    var matrix = 
            this.getTransformToElement(tooltipParent)
                .translate(+this.getAttribute("cx"),
                     +this.getAttribute("cy"));
    SVGtooltip
        .attr("transform", "translate(" + (matrix.e)
                  + "," + (matrix.f - 30) + ")");

The key code for the HTML tooltip is

HTML工具提示的关键代码是。

    var matrix = this.getScreenCTM()
            .translate(+this.getAttribute("cx"),
                     +this.getAttribute("cy"));

    absoluteHTMLtooltip
        .style("left", 
               (window.pageXOffset + matrix.e) + "px")
        .style("top",
               (window.pageYOffset + matrix.f + 30) + "px");

Live example: http://fiddle.jshell.net/tPv46/89/

生活例子:http://fiddle.jshell.net/tPv46/89/

Again, I'd appreciate a confirmation comment from anyone who can test this in Safari or IE -- or any mobile browser. I'm pretty sure I've used standard API for everything, but just because the API is standard doesn't mean it's universally implemented!

再一次,我希望任何人能在Safari或IE或任何移动浏览器上测试它。我很确定我已经使用了标准的API,但是仅仅因为API是标准的并不意味着它得到了普遍的实现!