svg - origin - transform css
Cómo configurar el origen de la transformación en SVG (5)
Para escalar sin tener que usar la transformación de matrix
:
transform="translate(cx, cy) scale(sx sy) translate(-cx, -cy)"
Y aquí está en CSS:
transform: translate(cxpx, cypx) scale(sx, sy) translate(-cxpx, -cypx)
Necesito cambiar el tamaño y rotar ciertos elementos en el documento SVG usando javascript. El problema es que, por defecto, siempre aplica la transformación alrededor del origen en (0, 0)
- arriba a la izquierda.
¿Cómo puedo redefinir este punto de ancla de transformación?
Intenté usar el atributo de transform-origin
, pero no afecta nada.
Así es como lo hice:
svg.getDocumentById(''someId'').setAttribute(''transform-origin'', ''75 240'');
No parece establecer el punto fundamental al punto que especifiqué, aunque puedo ver en Firefox que el atributo está configurado correctamente. Probé cosas como center bottom
y 50% 100%
con y sin paréntesis. Nada funcionó hasta ahora.
¿Alguien puede ayudar?
Para rotar use transform="rotate(deg, cx, cy)"
, donde deg es el grado que desea rotar y (cx, cy) define el centro de rotación.
Para escalar / redimensionar, debe traducir por (-cx, -cy), luego escalar y luego traducir de nuevo a (cx, cy). Puedes hacer esto con una transformación matricial :
transform="matrix(sx, 0, 0, sy, cx-sx*cx, cy-sy*cy)"
Donde sx es el factor de escala en el eje x, sy en el eje y.
Si eres como yo y quieres hacer panorámicas y luego hacer zoom con origen de transformación, necesitarás un poco más.
// <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);
};
Aquí está funcionando: http://forresto.github.io/dataflow-prototyping/react/
Si puede usar un valor fijo (no "centro" o "50%"), puede usar CSS en su lugar:
-moz-transform-origin: 25px 25px;
-ms-transform-origin: 25px 25px;
-o-transform-origin: 25px 25px;
-webkit-transform-origin: 25px 25px;
transform-origin: 25px 25px;
Algunos navegadores (como Firefox) no manejarán los valores relativos correctamente.
Tuve un problema similar. Pero estaba usando D3 para posicionar mis elementos, y quería que la transformación y la transición fueran manejadas por CSS. Este era mi código original, que obtuve trabajando en 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) ...
Esto me permitió establecer los valores de cx
, cy
y transform-origin
en javascript utilizando los mismos datos.
PERO esto no funcionó en Firefox! Lo que tenía que hacer era envolver el circle
en la etiqueta g
y translate
usando la misma fórmula de posicionamiento de arriba. A continuación, agregué el circle
en la etiqueta g
, y establecí sus valores de cx
y cy
en 0
. A partir de ahí, transform: scale(2)
se escalaría desde el centro como se esperaba. El código final se veía así.
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,
})
Después de hacer este cambio, cambié mi CSS para enfocar el circle
lugar del .dot
, para agregar la transform: scale(2)
. Ni siquiera necesito utilizar transform-origin
.
NOTAS:
Estoy usando
d3-selection-multi
en el segundo ejemplo. Esto me permite pasar un objeto a.attrs
lugar de repetir.attr
para cada atributo.Al usar un literal de plantilla de cadena, tenga en cuenta los saltos de línea como se ilustra en el primer ejemplo. Esto incluirá una nueva línea en la salida y puede romper su código.