Bluefire
Bluefire

Reputation: 14139

How can I find the translated co-ordinates of an SVG element?

I have a SVG element with x and y set, but I'm also translating it by a certain vector using transform="translate(a, b)", which changes the co-ordinates it's rendered to but obviously doesn't update its x and y attributes. Is there a way to get the actual co-ordinates, which in this case would be x + a and y + b, without having to directly parse the values out of the transform attribute?

Not that this is a D3-specific question, but my code looks like this:

svg.selectAll(selector)
    .attr("x", x)
    .attr("y", y)
    .attr("width", width)
    .attr("height", height)
    .attr("transform", `translate(${a}, ${b})`);

Upvotes: 5

Views: 1412

Answers (2)

Shashank
Shashank

Reputation: 5670

You can use the getBoundingClientRect() method to get the position of the node.

Here's a snippet showing two rects with one of them translated:

var svgXY = d3.select('svg').node().getBoundingClientRect();

var rect1 = d3.select('rect#test1').node().getBoundingClientRect();
console.log('Rect 1: { top: ' + (rect1.top-svgXY.top) + ', left: ' + (rect1.left-svgXY.left) + '}');

var rect2 = d3.select('rect#test2').node().getBoundingClientRect();
console.log('Rect 2: { top: ' + (rect2.top-svgXY.top) + ', left: ' + (rect2.left-svgXY.left) + '}');
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<script src="https://code.jquery.com/jquery-3.2.1.js"></script>


<svg width="300" height="200">

  <rect x="20" y="40" fill="red" width="100" height="40" id="test1"></rect>
  <rect x="20" y="40" fill="green" width="100" height="40" transform="translate(40, 30)" id="test2"></rect>
</svg>

Or if you're using jQuery, you can get the position by using $('rect#test1').position().

Hope this helps.

Edit: body had a margin of 8px by default and hence x was equal to 28. I've added the CSS and check out the snippet now.

Upvotes: 1

Sergey Rudenko
Sergey Rudenko

Reputation: 9235

OK, this is not really D3 related, but pure SVG/javascript:

I use this function here that I call "flatten", basically you want to reset matrix to non-transformed one (matrix(1 0 0 1 0 0)) and update path points with their sort of flattened values:

flattenShape(item, matrix) {
    let points = item.pathPoints;
    let l = points.length;
    for (let i = 0; i<l; i++) {
        let cache = this.mainSVG.createSVGPoint();
        cache.x = points[i].x;
        cache.y = points[i].y;
        cache = cache.matrixTransform(matrix);
        points[i].x = cache.x;
        points[i].y = cache.y;
    }
    item.d = this.constructPath(points);
    item.transform = "matrix(1 0 0 1 0 0)";
};

item - your SVG element, matrix - you need to get the actual SVGMatrix of the element in question. I get it using:

let matrix = YOUR_SVG_ELEMENT.transform.baseVal.consolidate().matrix;

So my approach is maybe too specific but generally speaking:

  • consolidate matrix of the SVG element that you are transforming.
  • use SVGPoint to perform: matrixTransform(matrix) for each coordinate in question.
  • reset transform attribute to initial state e.g. matrixTransform(matrix)

Upvotes: 3

Related Questions