svg - 如何获取 <g> 组内对象的绝对坐标?

标签 svg d3.js

这可能是一个常见问题解答,所以请随时向我指出另一个答案。该主题很难搜索。

如果我想使用 d3.js 获取在 SVG 对象中显式声明的属性,或者我使用 D3 显式放置的属性,我可以使用 d3.select 轻松获取属性的值.例如,打印 300:

...
<circle id="mycircle" r="10" cx="100" cy="200">
...
d3.select("#mycircle").attr("cx", 300);
console.log(d3.select("#mycircle").attr("cx"));

如果我没有显式设置属性的值,但它是从 <g> 中隐式“设置”的怎么办?团体?或者:如何使用代码找出 <g> 的位置组居中?我想要一些方法来确定 <svg> 的绝对坐标系中的位置反对<g>里面的东西是。如果我知道<g> 在哪里是,它在空间中的方向等等,我可以弄清楚它里面的点在哪里。我怎样才能做到这一点?

BigBadaboom 在对 this question 答案的评论中发表评论继承的不是一对坐标,而是一个transform属性。所以我可以选择 <g>并获取变换属性的值:
console.log(d3.select("#mygroup").attr("transform"));

打印,例如:

“旋转(-125.93)翻译(0,-25)”

我是否必须解析它才能找出 <g> 的位置?是否位于绝对坐标系中?

最佳答案

这里的其他人已经提到了SVGLocatable.getBBox()这对于根据元素自身的局部坐标系抓取元素的边界框很有用。不幸的是,正如您所注意到的,这没有考虑对元素或其父元素进行的任何转换。

在处理这些转换时,还有一些其他功能可以帮助您解决问题。
SVGLocatable.getScreenCTM()给你一个SVGMatrix表示从视口(viewport)坐标转换为元素的本地坐标所需的转换。这很棒,因为它将考虑应用于调用它的元素的变换,以及应用于父元素的任何变换。不幸的是,它还考虑了元素在屏幕上的确切位置,这意味着如果您在 svg 文档之前有内容,或者甚至只是围绕它的一些边距,则返回的矩阵将包含该空间作为翻译。
Element.getBoundingClientRect()将允许您考虑该空间。如果您在 SVG 文档本身上调用此函数,您可以找出 SVG 在屏幕上的偏移量。

然后,当您想在坐标系之间转换时,您所要做的就是将两者结合起来。 HERE是一些关于如何使用 SVGMatrix 的好信息作品。现在要知道的重要一点是 SVGMatrix是一个有六个属性的对象 a , b , c , d , e , 和 f它表示如下变换:

svg matrix equations

假设您有一个变量 svgDoc这是对 svg 文档的引用(不是 d3 选择,而是元素本身)。然后您可以创建一个函数,将其转换为 svg 元素的坐标系 elem如下。

function convertCoords(x,y) {

  var offset = svgDoc.getBoundingClientRect();

  var matrix = elem.getScreenCTM();

  return {
    x: (matrix.a * x) + (matrix.c * y) + matrix.e - offset.left,
    y: (matrix.b * x) + (matrix.d * y) + matrix.f - offset.top
  };
}

然后,假设您想在 elem 的中间添加一个点。 ,你可以这样做:
var bbox = elem.getBBox(),
    middleX = bbox.x + (bbox.width / 2),
    middleY = bbox.y + (bbox.height / 2);

var absoluteCoords = convertCoords(middleX, middleY);

var dot = svg.append('circle')
  .attr('cx', absoluteCoords.x)
  .attr('cy', absoluteCoords.y)
  .attr('r', 5);

当然,您可能想要概括 convertCoords函数,因此您可以传入目标元素,但希望这会让您朝着正确的方向前进。祝你好运!

更好的实现是为任何给定元素和 svg 文档上下文生成转换函数的工厂:
function makeAbsoluteContext(element, svgDocument) {
  return function(x,y) {
    var offset = svgDocument.getBoundingClientRect();
    var matrix = element.getScreenCTM();
    return {
      x: (matrix.a * x) + (matrix.c * y) + matrix.e - offset.left,
      y: (matrix.b * x) + (matrix.d * y) + matrix.f - offset.top
    };
  };
}

给定相同的elem,这可以按如下方式使用和 svgDoc作为一个天真的例子:
var bbox = elem.getBBox(),
    middleX = bbox.x + (bbox.width / 2),
    middleY = bbox.y + (bbox.height / 2);

// generate a conversion function
var convert = makeAbsoluteContext(elem, svgDoc);

// use it to calculate the absolute center of the element
var absoluteCenter = convert(middleX, middleY);

var dot = svg.append('circle')
  .attr('cx', absoluteCenter.x)
  .attr('cy', absoluteCenter.y)
  .attr('r', 5);

关于svg - 如何获取 <g> 组内对象的绝对坐标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26049488/

相关文章:

javascript - 使用 underscorejs 和 d3 数据进行过滤

html - svg 图像标签大小

javascript - 如何将比例应用于 d3 v4.0 `brush` ?

javascript - svg - 获取重叠形状区域的路径坐标

Javascript无限循环(Greensock)

javascript - d3 : how to interpolate a string (with numbers in it) so that the numbers don't get interpolated

javascript - D3 不在折线图上绘制数据

JavaScript 变量赋值/返回

javascript - d3.js 在追加时不返回动态构造的 html 元素

javascript - Svg 图像在设置变换旋转后更改大小