简体   繁体   English

通过.getBoundingClientRect()在可变宽度div中定位SVG元素

[英]Positioning SVG elements via .getBoundingClientRect() in variable-width div

I have a bit of an annoying problem. 我有一个烦人的问题。

I'm trying to position a bunch of SVG circle elements according to an existing bunch of SVG text elements that share similar properties. 我正在尝试根据一堆共享相似属性的SVG文本元素来定位一堆SVG圆形元素。

The circle elements are created in a very separate process than the text elements, so positioning the new elements just using the same transforms etc. as the old one isn't a viable option. circle元素的创建过程与文本元素的创建过程非常不同,因此,仅使用与旧元素相同的变换等方式来放置新元素不是可行的选择。

I'm trying to use .getBoundingClientRect() to get the positions since the text elements are transformed into position (so .getBBox() isn't an option) rather than positioned by x and y attributes. 我正在尝试使用.getBoundingClientRect()来获取位置,因为文本元素已转换为位置(因此.getBBox()不是一个选择),而不是通过x和y属性进行定位。

With .getBoundingClientRect(), I can get the correct size/arrangement of the new elements, but since the width of the svg-containing div is variable, there's always a bit of a weird offset that I can't quite account for. 使用.getBoundingClientRect(),我可以获取新元素的正确大小/排列,但是由于包含svg的div的宽度是可变的,因此总有些奇怪的偏移量,我无法完全解决。

I created a simplified example of my issue here . 我在这里创建了我的问题的简化示例。 Resize and refresh the page to see the issue in action. 调整页面大小并刷新,以查看实际存在的问题。

The code I use to position the circle elements is replicated below. 我用来放置圆形元素的代码复制如下。

var circs = theSvg.selectAll("circle")
    .data(theCircles)
    .enter()
    .append("circle")
    .attr("r", 15)
    .attr("fill", "#f00")
    .style("opacity", 0.3)
    .attr("transform", function(d){

      var sizeDif = 800/(d3.select(".svgTestHolder")[0][0].getBoundingClientRect()["width"]);

      var theNum = parseInt(d.split("&")[1]);
      var thePosition = theSvg.selectAll("text").filter(function(e){
      return e == theNum;})[0];
      var theCoords = thePosition[0].getBoundingClientRect();

      var leftOffset = d3.select(".svgTestHolder")[0][0].getBoundingClientRect()["left"];
      var leftOffset2 = d3.select(".svgTest")[0][0].getBoundingClientRect()["left"];
      var bottomOffset = d3.select(".svgTestHolder")[0][0].getBoundingClientRect()["top"];
      var bottomOffset2 = d3.select(".svgTest")[0][0].getBoundingClientRect()["top"];

      return
      "translate(" + ((theCoords["left"] - leftOffset - leftOffset2)  
       * sizeDif) + "," + ((theCoords["top"] - bottomOffset - bottomOffset2) 
       * sizeDif) + ")";
 })

EDIT: 编辑:

This is a very delayed update just to note that while I was unable to answer my question as stated, I was able to make a workable solution based on Paul LeBeau's suggestion to extract the transforms from the target element. 这是一个非常延迟的更新,只是要注意,尽管我无法回答我所说的问题,但我能够根据Paul LeBeau的建议从目标元素中提取转换,从而提出了可行的解决方案。

In my case, I had to use a series of consecutive transforms rather than a combination of transforming and changing the x/y position (due to certain realities of the project not represented in the linked example). 就我而言,我不得不使用一系列连续的转换,而不是转换和更改x / y位置的组合(由于链接示例中未显示的项目的某些实际情况)。 But I'm happy to have found an answer! 但我很高兴找到答案!

Your example works fine for me on Chrome. 您的示例在Chrome上对我来说效果很好。 But really that's only because the SVG is the only thing on the page. 但这确实是因为SVG是页面上唯一的内容。 If I add some text above the SVG everything goes wrong. 如果我在SVG上方添加一些文本,一切都会出错。

https://jsfiddle.net/rrpfmm6d/1/ https://jsfiddle.net/rrpfmm6d/1/

Is this the problem you are talking about? 这是您正在谈论的问题吗?

If so, the reason is because you are making the wrong choice in using getBoundingClientRect() . 如果是这样,原因是因为您在使用getBoundingClientRect()选择错误。 It provides coordinates in screen space. 它在屏幕空间中提供坐标。 It's origin is the top left of the window (or iframe in the case of jsfiddle). 它的原点是窗口的左上角(如果是jsfiddle,则为iframe)。

You should be using getBBox() . 您应该使用getBBox() The values it returns are in the same coordinate space as the SVG elements. 它返回的值与SVG元素在同一坐标空间中。 It's origin is (normally) at the top left of the SVG. 它的起源(通常)在SVG的左上方。

In summary, use the coordinates returned by calling getBBox() on your <text> element to calculate the position for your circle. 总之,请使用在<text>元素上调用getBBox()返回的坐标来计算圆的位置。 If the circles are inserted into the same SVG as the text, there will be no need to do any adjusting with the div or svg offsets. 如果将圆插入到与文本相同的SVG中,则无需对div或svg偏移进行任何调整。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM