问题
I need to resize and rotate certain elements in SVG document using javascript. The problem is, by default, it always applies the transform around the origin at (0, 0)
– top left.
How can I re-define this transform anchor point?
I tried using the transform-origin
attribute, but it does not affect anything.
This is how I did it:
svg.getDocumentById('someId').setAttribute('transform-origin', '75 240');
It does not seem to set the pivotal point to the point I specified although I can see in Firefox that the attribute is correctly set. I tried things like center bottom
and 50% 100%
with and without parenthesis. Nothing worked so far.
Can anyone help?
回答1:
To rotate use transform="rotate(deg, cx, cy)"
, where deg is the degree you want to rotate and (cx, cy) define the centre of rotation.
For scaling/resizing, you have to translate by (-cx, -cy), then scale and then translate back to (cx, cy). You can do this with a matrix transform:
transform="matrix(sx, 0, 0, sy, cx-sx*cx, cy-sy*cy)"
Where sx is the scaling factor in the x-axis, sy in the y-axis.
回答2:
If you can use a fixed value (not "center" or "50%"), you can use CSS instead:
-moz-transform-origin: 25px 25px;
-ms-transform-origin: 25px 25px;
-o-transform-origin: 25px 25px;
-webkit-transform-origin: 25px 25px;
transform-origin: 25px 25px;
Some browsers (like Firefox) won't handle relative values correctly.
回答3:
If you're like me and want to pan and then zoom with transform-origin, you'll need a little more.
// <g id="view"></g>
var view = document.getElementById("view");
var state = {
x: 0,
y: 0,
scale: 1
};
// Origin of transform, set to mouse position or pinch center
var oX = window.innerWidth/2;
var oY = window.innerHeight/2;
var changeScale = function (scale) {
// Limit the scale here if you want
// Zoom and pan transform-origin equivalent
var scaleD = scale / state.scale;
var currentX = state.x;
var currentY = state.y;
// The magic
var x = scaleD * (currentX - oX) + oX;
var y = scaleD * (currentY - oY) + oY;
state.scale = scale;
state.x = x;
state.y = y;
var transform = "matrix("+scale+",0,0,"+scale+","+x+","+y+")";
//var transform = "translate("+x+","+y+") scale("+scale+")"; //same
view.setAttributeNS(null, "transform", transform);
};
Here it is working: http://forresto.github.io/dataflow-prototyping/react/
回答4:
For scaling without having to use the matrix
transformation:
transform="translate(cx, cy) scale(sx sy) translate(-cx, -cy)"
And here it is in CSS:
transform: translate(cxpx, cypx) scale(sx, sy) translate(-cxpx, -cypx)
回答5:
I had a similar issue. But I was using D3 to position my elements, and wanted the transform and transition to be handled by CSS. This was my original code, which I got working in Chrome 65:
//...
this.layerGroups.selectAll('.dot')
.data(data)
.enter()
.append('circle')
.attr('transform-origin', (d,i)=> `${valueScale(d.value) * Math.sin( sliceSize * i)}
${valueScale(d.value) * Math.cos( sliceSize * i + Math.PI)}`)
//... etc (set the cx, cy and r below) ...
This allowed me to set the cx
,cy
, and transform-origin
values in javascript using the same data.
BUT this didn't work in Firefox! What I had to do was wrap the circle
in the g
tag and translate
it using the same positioning formula from above. I then appended the circle
in the g
tag, and set its cx
and cy
values to 0
. From there, transform: scale(2)
would scale from the center as expected. The final code looked like this.
this.layerGroups.selectAll('.dot')
.data(data)
.enter()
.append('g')
.attrs({
class: d => `dot ${d.metric}`,
transform: (d,i) => `translate(${valueScale(d.value) * Math.sin( sliceSize * i)} ${valueScale(d.value) * Math.cos( sliceSize * i + Math.PI)})`
})
.append('circle')
.attrs({
r: this.opts.dotRadius,
cx: 0,
cy: 0,
})
After making this change, I changed my CSS to target the circle
instead of the .dot
, to add the transform: scale(2)
. I didn't even need use transform-origin
.
NOTES:
I am using
d3-selection-multi
in the second example. This allows me to pass an object to.attrs
instead of repeating.attr
for every attribute.When using a string template literal, be aware of line-breaks as illustrated in the first example. This will include a newline in the output and may break your code.
来源:https://stackoverflow.com/questions/6711610/how-to-set-transform-origin-in-svg