I have a SVG based app that makes heavy use of transformation such as translates, rotates and scales. While I have no issue in Firefox, in Chrome, the transform-origin
property is not taken in account. It seems to apply the user-agent default value 0px 0px 0
.
Here is an example (JSFiddle):
<svg width="400" height="400">
<defs>
<rect id="shape" width="200" height="200"/>
</defs>
<g transform="translate(100,100)">
<use xlink:href="#shape" style="stroke: lightgray; fill: transparent;"/>
<ellipse cx="100" cy="100" rx="3" ry="3" style="fill: black;"/>
<g transform="translate(0,0) scale(0.5) rotate(45)" style="transform-origin: 100px 100px;">
<use xlink:href="#shape" style="stroke: black; fill: transparent;"/>
</g>
</g>
</svg>
As you can see Chrome applies all transformation from top left corner of the shape regardless of the defined origin while Firefox respects the defined origin.
Am I missing something about how transform-origin
works with SVG?
Does anyone actually found a way to fix this without compensating with translates?
I am answering to my own question in order to clarify entirely what is going on with transform-origin
properties on the SVG 1.1 transform functions and how to overcome this issue in Chrome 48.
First of all, transform-origin
is a pure CSS 3 property, it is not related to SVG 1.1 at all. Despite the fact that transform
sounds a lot like transform-origin
, they apply to different systems. transform
exists in both CSS 3 and SVG 1.1 but have separate implementations. transform-origin
only exists in CSS 3 and therefore it is not supposed to influence SVG 1.1. The fact that transform-origin
has no influence on SVG in Chrome 48 is expected.
So why transform-origin
does apply to SVG in Firefox 44? Well the reason is not exactly clear, but it seems that it is part of the ongoing effort from Mozilla to slowly bring support for SVG 2 in Firefox. Indeed with SVG 2, everything will become a CSS 3 transform (no separate implementation) and SVG will therefore get support for transform-origin
. I found out about this in the excellent article about the SVG coordinate systems from Sara Soueidan.
Now how can that be overcome in Chrome 48. It is fairly simple but if you want to apply translate()
, scale()
and rotate()
all the same time, you will still need to calculate the offset induced by the scaling and compensate it in your translation.
As Bobby Orndorff mentioned in his answer, it is actually possible to provide the center of rotation to the rotate()
function by providing extra x and y parameters. This is already a great improvement. But unfortunately the scale()
function does not support such a thing and will always scale from the top left corner of its parent. Therefore you will still have to correct your translation in order to simulate a scale around a center.
Here is the final solution that works on Chrome 48 and Firefox 44:
<svg width="400" height="400">
<defs>
<rect id="shape" width="200" height="200"/>
</defs>
<g transform="translate(100,100)">
<use xlink:href="#shape" style="stroke: lightgray; fill: transparent;"/>
<ellipse cx="100" cy="100" rx="3" ry="3" style="fill: black;"/>
<g transform="translate(50,50) scale(0.5) rotate(45, 100, 100)">
<use xlink:href="#shape" style="stroke: black; fill: transparent;"/>
</g>
</g>
</svg>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With