Comment définir transform origin en SVG

je dois redimensionner et faire tourner certains éléments dans SVG document en utilisant javascript. Le problème est, par défaut, qu'il applique toujours la transformation autour de l'origine à (0, 0) – en haut à gauche.

Comment puis-je redéfinir ce point d'ancrage transform?

j'ai essayé d'utiliser l'attribut transform-origin , mais il n'affecte rien.

C'est comme ça que je l'ai fait:

svg.getDocumentById('someId').setAttribute('transform-origin', '75 240');

Il ne semble pas mettre le point pivot au point que j'ai spécifié bien que je puisse voir dans Firefox que l'attribut est correctement défini. J'ai essayé des choses comme center bottom et 50% 100% avec et sans parenthèses. Rien n'a fonctionné jusqu'à présent.

est-ce que quelqu'un peut aider?

75
demandé sur Hafenkranich 2011-07-15 22:29:28

5 réponses

pour tourner utilisez transform="rotate(deg, cx, cy)" , où deg est le degré que vous voulez tourner et (cx, cy) définir le centre de rotation.

pour mettre à l'échelle/redimensionner, vous devez traduire par (-cx, -cy), puis mettre à l'échelle et ensuite traduire en (CX, cy). Vous pouvez le faire avec un transformation de matrice :

transform="matrix(sx, 0, 0, sy, cx-sx*cx, cy-sy*cy)"

où sx est le facteur d'échelle dans l'axe des abscisses, sy dans l'axe des ordonnées.

124
répondu Peter Collingridge 2017-01-19 16:08:25

si vous pouvez utiliser une valeur fixe (Pas "centre" ou " 50%"), Vous pouvez utiliser CSS à la place:

-moz-transform-origin: 25px 25px;
-ms-transform-origin:  25px 25px;
-o-transform-origin: 25px 25px;
-webkit-transform-origin:  25px 25px;
transform-origin: 25px 25px;

certains navigateurs (comme Firefox) ne gèrent pas correctement les valeurs relatives.

16
répondu Hafenkranich 2016-10-18 12:00:38

si vous êtes comme moi et que vous voulez faire un panoramique et ensuite zoomer avec transform-origin, vous aurez besoin d'un peu plus.

// <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);
};

ici ça marche: http://forresto.github.io/dataflow-prototyping/react /

11
répondu forresto 2017-04-04 17:40:48

pour la mise à l'échelle sans avoir à utiliser la transformation matrix :

transform="translate(cx, cy) scale(sx sy) translate(-cx, -cy)"

Et voici dans CSS:

transform: translate(cxpx, cypx) scale(sx, sy) translate(-cxpx, -cypx)
3
répondu cmititiuc 2018-04-01 02:33:40

j'ai eu un problème similaire. Mais j'utilisais D3 pour positionner mes éléments, et je voulais que les transform et transition soient manipulés par CSS. C'était mon code d'origine, que J'ai obtenu en travaillant dans 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) ...

cela m'a permis de définir les valeurs cx , cy , et transform-origin en javascript en utilisant les mêmes données.

BUT ça n'a pas marché avec Firefox! ce que j'ai eu à faire était d'envelopper le circle dans le g étiquette et translate il en utilisant la même formule de positionnement d'en haut. J'ai ensuite ajouté le circle dans la balise g , et j'ai placé ses valeurs cx et cy à 0 . À partir de là, transform: scale(2) serait échelle du centre comme prévu. Le code final ressemblait à ça.

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,
  })

après avoir fait ce changement, j'ai changé mon CSS pour cibler le circle au lieu du .dot , ajouter le transform: scale(2) . Je n'avais même pas besoin d'utiliser transform-origin .

NOTES:

  1. j'utilise d3-selection-multi dans le deuxième exemple. Cela me permet de passer un objet à .attrs au lieu de répéter .attr pour chaque attribut.

  2. Lorsqu'on utilise un modèle de chaîne de caractères littéral, soyez conscient des sauts de ligne comme illustré dans le premier exemple. Cela inclura une nouvelle ligne dans la sortie et peut casser votre code.

0
répondu Jamie S 2018-03-21 17:51:02