How can I use an SVG element’s transformation matrix to calculate destination coordinates?
You can use simple trigonometric transformation:
const rotatePoint = (point, center, rotateAngle) => {
const dx = point.x - center.x;
const dy = point.y - center.y;
const distance = Math.hypot(dx, dy);
const currentAngle = Math.atan(dy / dx);
const nextAngle = currentAngle - rotateAngle;
const nextDX = distance * Math.cos(nextAngle);
const nextDY = distance * Math.sin(nextAngle);
return {x: center.x + nextDX, y: center.y + nextDY};
};
The snippet displays rotation of a blue point around the red one (30 / 90 / 123 degrees counter-clockwise)
const rotatePoint = (point, center, angle) => {
const dx = point.x - center.x;
const dy = point.y - center.y;
const distance = Math.hypot(dx, dy);
const current = Math.atan(dy / dx);
const next = current - angle;
const nextDX = distance * Math.cos(next);
const nextDY = distance * Math.sin(next);
return {x: center.x + nextDX, y: center.y + nextDY};
};
const center = {x: 150, y: 150};
const start = {x: 200, y: 30};
const svg = d3.select('svg');
svg.append('circle')
.attr('cx', center.x)
.attr('cy', center.y)
.attr('r', 5)
.style('fill', 'red');
svg.append('circle')
.attr('cx', start.x)
.attr('cy', start.y)
.attr('r', 5)
.style('fill', 'blue');
// Rotate 30 deg
const p30 = rotatePoint(start, center, Math.PI * 30 / 180);
svg.append('circle')
.attr('cx', p30.x)
.attr('cy', p30.y)
.attr('r', 5)
.style('fill', 'green');
// Rotate 90 deg
const p90 = rotatePoint(start, center, Math.PI * 90 / 180);
svg.append('circle')
.attr('cx', p90.x)
.attr('cy', p90.y)
.attr('r', 5)
.style('fill', 'orange');
// Rotate 123 deg
const p123 = rotatePoint(start, center, Math.PI * 123 / 180);
svg.append('circle')
.attr('cx', p123.x)
.attr('cy', p123.y)
.attr('r', 5)
.style('fill', 'yellow');
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="250" height="200"></svg>
How to compute new coordinates after rotation?
I looked up some math.
It's a matrix-vector-multiplication. For SVG that means:
matrix(a b c d e f)
corresponds to
x(new) = a*x + c*y + e
y(new) = b*x + d*y + f
How to calculate SVG transform matrix from rotate/translate/scale values?
Translate(tx, ty) can be written as the matrix:
1 0 tx
0 1 ty
0 0 1
Scale(sx, sy) can be written as the matrix:
sx 0 0
0 sy 0
0 0 1
Rotate(a) can be written as a matrix:
cos(a) -sin(a) 0
sin(a) cos(a) 0
0 0 1
Rotate(a, cx, cy) is the combination of a translation by (-cx, cy), a rotation of a degrees and a translation back to (cx, cy), which gives:
cos(a) -sin(a) -cx × cos(a) + cy × sin(a) + cx
sin(a) cos(a) -cx × sin(a) - cy × cos(a) + cy
0 0 1
If you just multiply this with the translation matrix you get:
cos(a) -sin(a) -cx × cos(a) + cy × sin(a) + cx + tx
sin(a) cos(a) -cx × sin(a) - cy × cos(a) + cy + ty
0 0 1
Which corresponds to the SVG transform matrix:
(cos(a), sin(a), -sin(a), cos(a), -cx × cos(a) + cy × sin(a) + cx + tx, -cx × sin(a) - cy × cos(a) + cy + ty)
.
In your case that is: matrix(0.866, -0.5 0.5 0.866 8.84 58.35)
.
If you include the scale (sx, sy) transform, the matrix is:
(sx × cos(a), sy × sin(a), -sx × sin(a), sy × cos(a), (-cx × cos(a) + cy × sin(a) + cx) × sx + tx, (-cx × sin(a) - cy × cos(a) + cy) × sy + ty)
Note that this assumes you are doing the transformations in the order you wrote them.
How to convert svg element coordinates to screen coordinates?
I was playing around with this snippet below when I wanted to do the same (learn which screen coordinates correspond to the SVG coordinates). I think in short this is what you need:
Learn current transformation matrix of the SVG element (which coordinates you are interested in), roughly: matrix = element.getCTM();
Then get screen position by doing, roughly: position = point.matrixTransform(matrix), where "point" is a SVGPoint.
See the snippet below. I was playing with this by changing browser window size and was altering svg coordinates to match those of the div element
// main SVG:var rootSVG = document.getElementById("rootSVG");// SVG element (group with rectangle inside):var rect = document.getElementById("rect");// SVGPoint that we create to use transformation methods:var point = rootSVG.createSVGPoint();// declare vars we will use below:var matrix, position;// this method is called by rootSVG after load:function init() { // first we learn current transform matrix (CTM) of the element' whose screen (not SVG) coordinates we want to learn: matrix = rect.getCTM(); // then we "load" SVG coordinates in question into SVGPoint here: point.x = 100; // replace this with the x co-ordinate of the path segment point.y = 300; // replace this with the y co-ordinate of the path segment // now position var will contain screen coordinates: position = point.matrixTransform(matrix); console.log(position) // to validate that the coordinates are correct - take these x,y screen coordinates and apply to CSS #htmlRect to change left, top pixel position. You will see that the HTML div element will get placed into the top left corner of the current svg element position.}
html, body { margin: 0; padding: 0; border: 0; overflow:hidden; background-color: #fff; }svg { position: fixed; top:0%; left:0%; width:100%; height:100%; background:#fff; }#htmlRect { width: 10px; height: 10px; background: green; position: fixed; left: 44px; top: 132px;}
<body> <svg id="rootSVG" width="100%" height="100%" viewbox="0 0 480 800" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init()">
<g id="rect"> <rect id="rectangle" x="100" y="300" width="400" height="150"/> </g>
</svg> <div id="htmlRect"></div></body>
How to get the actual x/y position of an element in SVG with transformations and matrices
As well as i understood your problem, you need to know the x and y co-ordinates of an element, after it is transformed.
Mathematically, all transformations can be represented as 3x3 transformation matrices of the following form:
a b e
c d f
0 0 1
Since only six values are used in the above 3x3 matrix, a transformation matrix is also expressed as a vector: [a b c d e f]
.
a and d responsible for scaling in x and y respectively, whereas e and f gives you the translated axis in the x and y respectively.
So In your code which is
<text transform="matrix(1,0,0,-1,236.532,417.253)" id="text6560">
<tspan x="0 4.448" y="0" id="tspan6562">10</tspan>
</text>
Element text is translated 236.532 in the x-axis 417.253 in the y-axis.
So tspan x point becomes 236.. + 4.4.. and y point 417.. + 0.
Related Topics
How to Prevent the Scrollbar Overlaying Content in Ie10
How to Make Type="Number" to Positive Numbers Only
Html5Shiv VS Dean Edwards IE7-Js VS Modernizr - Which to Choose
Is HTML Considered a Programming Language
Node.Js - How to Send Data from HTML to Express
Hide HTML Horizontal But Not Vertical Scrollbar
Jquery Click Function Doesn't Work After Ajax Call
What's Default HTML/CSS Link Color
How to Show Disable HTML Select Option in by Default
How to Disable CSS in Browser for Testing Purposes
How to Export HTML Table Data as .CSV File
Using Thymeleaf When the Value Is Null
Sending HTML Mail Using a Shell Script
How to Link HTML Pages in Same or Different Folders
Change the Color of a Bullet in a HTML List
How to Keep :Active CSS Style After Click a Button
Correct Way to Use Modernizr to Detect Ie
Which Is More Correct: <H1><A>...</A></H1> or <A><H1>...</H1></A>