如何获得对象在<g>内的绝对坐标。组? [英] How to get absolute coordinates of object inside a &lt;g&gt; group?

查看:228
本文介绍了如何获得对象在<g>内的绝对坐标。组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



如果我想使用d3.js获取在SVG对象中显式声明的属性,或者我明确地使用D3,我可以很容易地使用 d3.select 获得属性的值。例如,打印300:

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

如果我不明确设置属性的值,从< g> 组?或者:我如何使用代码来找出< g> 组中心在哪里?我想要某种方式确定< svg> 对象的绝对坐标系中< g> code>是。如果我知道< g> 的位置,它在空间中的定位等等,我可以知道它在哪里的点。我如何做到这一点?



BigBadaboom在对这个问题,继承的不是一对坐标,而是 transform 属性。所以我可以选择< g> 并获取transform属性的值:

 code> console.log(d3.select(#mygroup)。attr(transform)); 

打印,例如:



rotate(-125.93)translate(0,-25)



我必须解析,找出< g& c

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



还有一些其他函数可用,



SVGLocatable.getScreenCTM()给你一个 SVGMatrix 表示将视口坐标转换为元素的局部坐标所需的转换。这是伟大的,因为它将考虑应用于它被调用的元素的变换,以及应用于父元素的任何变换。不幸的是,它也考虑到元素在屏幕上的确切位置,这意味着如果你的内容在你的svg文档之前,或者甚至只是一些边缘,返回的矩阵将包括该空间作为翻译。



Element.getBoundingClientRect()将允许您计算该空间。如果你在SVG文档本身调用这个函数,你可以通过多少SVG在屏幕上偏移。



然后你需要做的是结合两个当你想在坐标系之间转换。 此处 是一些有关如何 SVGMatrix 工程。现在要知道的一件重要事情是, SVGMatrix 是一个具有六个属性的对象 a b c d e f ,它们表示如下的转换:





假设你有一个变量 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)+ .d * y)+ matrix.f - offset.top
};
};
}

这可以使用如下给定相同的 elem svgDoc 作为天真的示例:

  var bbox = elem.getBBox(),
middleX = bbox.x +(bbox.width / 2),
middleY = bbox.y +(bbox.height / 2);

//生成转换函数
var convert = makeAbsoluteContext(elem,svgDoc);

//使用它来计算元素的绝对中心
var absoluteCenter = convert(middleX,middleY);

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


This may be a FAQ, so feel free to point me to another answer. The topic is difficult to search on.

If I want to use d3.js to get an attribute that's explicitly declared in an SVG object, or that I've explicitly put there using D3, I can easily get the value of the attribute using d3.select. For example, this prints 300:

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

What if I don't explicit set the value of the attribute, but it is implicitly "set" from a <g> group? Or: How can I use code to find out where a <g> group is centered? I'd like some way of determining where in the absolute coordinate system of the <svg> object the things inside the <g> are. If I knew where the <g> was, how it's oriented in space, etc., I could figure out where points inside it are. How can I do that?

BigBadaboom remarks in a comment on an answer to this question that what is inherited is not a pair of coordinates, but a transform attribute. So I can select a <g> and get the value of the transform attribute:

console.log(d3.select("#mygroup").attr("transform"));

which prints, for example:

"rotate(-125.93)translate(0,-25)"

Do I have to parse that to find out where the <g> is situated in the absolute coordinate system?

解决方案

Others here have already mentioned SVGLocatable.getBBox() which is useful for grabbing the bounding box of an element in terms of its own local coordinate system. Unfortunately, as you noticed, this doesn't take into account any of the transformations done on the element or on its parent elements.

There are a couple other functions available that will help you out a ton when dealing with those transforms.

SVGLocatable.getScreenCTM() gives you an SVGMatrix representing the transformations needed to convert from the viewport coordinates to the local coordinates of your element. This is great because it will take into account the transforms applied to the element it is called on, and any transforms applied to parent elements. Unfortunately, it also takes into account where exactly the element is on the screen, which means if you have content before your svg document, or even just some margins around it, the returned matrix will include that space as a translation.

Element.getBoundingClientRect() will allow you to account for that space. If you call this function on the SVG document itself, you can find out by how much the SVG is offset on the screen.

Then all you have to do is combine the two when you want to convert between coordinate systems. HERE is some good info on how an SVGMatrix works. The important thing to know for now is that an SVGMatrix is an object with six properties a, b, c, d, e, and f which represent a transformation as follows:

Lets say you have a variable svgDoc which is a reference to the svg document (not a d3 selection, but the element itself). Then you can create a function that will convert to the coordinate system of an svg element elem as follows.

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
  };
}

Then, say you wanted to put a dot in the middle of elem, you could do something like this:

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);

Of course, you'd probably want to generalize the convertCoords function so you can pass in the target element, but hopefully that'll get you off in the right direction. Good luck!

A better implementation would be a factory that generates a conversion function for any given element and svg document context:

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
    };
  };
}

This could be used as follows given the same elem and svgDoc as the naive example:

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);

这篇关于如何获得对象在<g>内的绝对坐标。组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆