我有一个带有SVG的网页。在某些形状上,我需要显示工具提示。但是,我无法将工具提示显示在它应该的位置,只是距离形状本身一些像素。
它出现在屏幕的右侧,可能距离大约300px。 我用来获取坐标的代码如下:
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");});
我在this SO post之后得到了这段代码。
我更改了$(ev.target).attr(cx),因为它没有在我的机器上返回值; d3.event.target.cx是,尽管它似乎并没有影响最终结果。
我做错了什么?有人可以帮帮我吗?非常感谢你的时间。
答案 0 :(得分:30)
如果您的工具提示是HTML元素,那么您希望将其相对于页面整体定位,而不是内部SVG坐标,因此访问cx / cy值只会使事情变得复杂。我不能在不查看您的代码的情况下肯定地说,但如果您对<svg>
或<g>
元素进行了任何转换,那么这可能会让您失望。
然而,有一个更容易的解决方案。只需访问鼠标事件的默认.pageX
和.pageY
属性,这些属性提供鼠标相对于HTML正文的位置,并使用这些坐标来定位工具提示div。
此处示例:http://fiddle.jshell.net/tPv46/1/
密码:
.on("mousemove", function () {
//console.log(d3.event);
return tooltip
.style("top", (d3.event.pageY + 16) + "px")
.style("left", (d3.event.pageX + 16) + "px");
})
即使在SVG圆圈上进行旋转变换,鼠标也会知道它在页面上的位置,并且相应地定位了工具提示。
还有其他方法可以做到这一点,包括让工具提示显示在相对于圆圈的固定位置而不是跟随鼠标,但我只是检查了我正在处理的示例并意识到它们不是交叉-browser兼容,所以我必须将它们标准化并回复你。与此同时,我希望这能让您重回项目。
为了进行比较,以下是使用HTML工具提示(<div>
元素)和SVG工具提示(<g>
元素)实现的相同示例。
http://fiddle.jshell.net/tPv46/4/
默认鼠标事件坐标可能非常适合定位<body>
的直接子元素的HTML元素,但它们对于定位SVG元素不太有用。在应用了所有变换之后,d3.mouse()
函数计算当前事件相对于指定SVG元素坐标系的鼠标坐标。因此,它可用于以我们定位SVG工具提示所需的形式获取鼠标坐标。
密码:
.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");
})
请注意,即使我使用viewBox
属性缩放SVG并将工具提示放在带有转换属性的<g>
内,它也能正常工作。
在Chrome,Firefox和Opera(合理的最新版本)中经过测试和工作 - 虽然SVG工具提示中的文字可能会超出其矩形,具体取决于您的字体设置。使用HTML工具提示的一个原因!另一个原因是它不会被SVG的边缘切断。
如果您在Safari或IE9 / 10/11中有任何错误,请发表评论。 (IE8及以下版本不幸,因为他们不做SVG)。
那么您最初的想法是什么,将工具提示放在圆圈本身上?能够准确定位笔尖有一定的好处:更好的布局控制,文本不会随着鼠标摆动。最重要的是,你可以在mouseover事件中定位一次,而不是对每个mousemove事件作出反应。
但要做到这一点,你不能再只使用鼠标位置来确定放置工具提示的位置 - 你需要弄清楚元素的位置,这意味着你必须处理转换。 SVG规范为locating SVG elements relative to other parts of the DOM引入了一组接口。
要在两个SVG转换系统之间进行转换,请使用SVGElement.getTransformToElement(SVGElement)
;要在SVG坐标系和屏幕之间进行转换,请使用SVGElement.getScreenCTM()
。结果是transformation matrices,您可以从中获得
提取净水平和垂直平移。
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) + ")");
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");
实例:http://fiddle.jshell.net/tPv46/89/
同样,我很感激任何可以在Safari或IE或任何移动浏览器中测试此内容的人的确认评论。我很确定我已经为所有内容使用了标准API,但仅仅因为API是标准的并不意味着它是普遍实现的!