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

Jes*_*ess 1 javascript svg d3.js

我有一个烦人的问题。

我正在尝试根据一堆共享相似属性的SVG文本元素来定位一堆SVG圆形元素。

circle元素的创建过程与文本元素的创建过程非常不同,因此,仅使用与旧元素相同的变换等方式来放置新元素不是可行的选择。

我正在尝试使用.getBoundingClientRect()来获取位置,因为文本元素已转换为位置(因此.getBBox()不是一个选择),而不是通过x和y属性进行定位。

使用.getBoundingClientRect(),我可以获取新元素的正确大小/排列,但是由于包含svg的div的宽度是可变的,因此总有些奇怪的偏移量,我无法完全解决。

我在这里创建了我的问题的简化示例。调整页面大小并刷新,以查看实际存在的问题。

我用来放置圆形元素的代码复制如下。

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) + ")";
 })
Run Code Online (Sandbox Code Playgroud)

编辑:

这是一个非常延迟的更新,只是要注意,尽管我无法回答我所说的问题,但我能够根据Paul LeBeau的建议从目标元素中提取转换,从而提出了可行的解决方案。

就我而言,我不得不使用一系列连续的转换,而不是转换和更改x / y位置的组合(由于链接示例中未显示的项目的某些实际情况)。但我很高兴找到答案!

Pau*_*eau 5

您的示例在Chrome上对我来说效果很好。但这确实是因为SVG是页面上唯一的内容。如果我在SVG上方添加一些文本,一切都会出错。

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

这是您正在谈论的问题吗?

如果是这样,原因是因为您使用时选择错误getBoundingClientRect()。它在屏幕空间中提供坐标。它的原点是窗口的左上角(如果是jsfiddle,则为iframe)。

您应该使用getBBox()。它返回的值与SVG元素在同一坐标空间中。它的起源(通常)在SVG的左上方。

总之,使用通过调用返回的坐标,getBBox()您的<text>元素来计算你的圈子位置。如果将圆插入到与文本相同的SVG中,则无需对div或svg偏移进行任何调整。

  • 我意识到从理论上说getBBox()可以解决我的问题,但是由于我在需要位置的项目上使用了转换,因此getBBox()并不是解决方案。这就是为什么我一直试图根据getBoundingClientRect()进行偏移并根据需要添加/减去父元素的偏移的原因(请参阅[更新的小提琴](https://jsfiddle.net/rrpfmm6d/3/))。我一直在寻找用于转换元素的getBBox()的替代方法,包括将SVG转换矩阵应用于文本元素的x和y(根据[此人的](http://stackoverflow.com/a/18561829/3899852 )解决方案。 (2认同)
  • 您说不能使用相同的转换,但是为什么不能仅从文本元素复制它们呢?像这样:https://jsfiddle.net/rrpfmm6d/5/ (2认同)