Pregunta Cómo configurar el origen de la transformación en SVG


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 transform-origin atributo, 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. Intenté cosas como center bottom y 50% 100% con y sin paréntesis. Nada funcionó hasta ahora.

¿Alguien puede ayudar?


74
2017-07-15 18:29


origen


Respuestas:


Para girar el uso transform="rotate(deg, cx, cy)", donde grados 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 un transformada de matriz:

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.


118
2017-07-15 23:16



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.


14
2017-09-01 17:53



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/


10
2018-01-08 12:47



Para escalar sin tener que usar el matrix transformación:

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)

2
2018-04-01 02:09



Tuve un problema similar. Pero estaba usando D3 para posicionar mis elementos, y quería el transformar y transición para ser manejado 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 el cx,cyy transform-origin valores en javascript usando los mismos datos.

PERO esto no funcionó en Firefox! Lo que tenía que hacer era envolver el circle en el g etiqueta y translate usando la misma fórmula de posicionamiento de arriba. Luego agregué el circle en el g etiqueta, y establecer su cx y cy valores a 0. Desde allí, transform: scale(2) 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 apuntar al circle en vez de .dot, para agregar el transform: scale(2). Ni siquiera necesito usar transform-origin.

NOTAS: 

  1. estoy usando d3-selection-multi en el segundo ejemplo. Esto me permite pasar un objeto a .attrs en lugar de repetir .attr por cada atributo.

  2. 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.


0
2018-03-21 17:51