Reputation: 14139
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
Reputation: 5670
You can use the getBoundingClientRect()
method to get the position of the node.
Here's a snippet showing two rect
s 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
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:
Upvotes: 3