127 votes

Comment définir l'origine de la transformation dans SVG

J'ai besoin de redimensionner et de faire pivoter certains éléments dans un document SVG en utilisant le javascript. Le problème est que, par défaut, il applique toujours la transformation autour de l'origine à (0, 0) - en haut à gauche.

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

J'ai essayé d'utiliser le transform-origin mais cela n'a aucune incidence.

C'est comme ça que j'ai fait :

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

Il ne semble pas définir 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.

Quelqu'un peut-il m'aider ?

0 votes

Pour information, le problème est censé être résolu depuis la version bêta 3 de Firefox 19, mais j'ai encore des problèmes avec Firefox 22. Liste de bugzilla de Mozilla : bugzilla.mozilla.org/show_bug.cgi?id=828286

0 votes

@CTheDark, pourriez-vous reconsidérer la réponse acceptée pour ceci s'il vous plaît ? Nous avons maintenant une solution plus moderne : stackoverflow.com/a/62720107/4375751

171voto

Peter Collingridge Points 4037

Pour effectuer une rotation, utilisez transform="rotate(deg, cx, cy)" où deg est le degré que vous souhaitez faire pivoter et (cx, cy) définit le centre de rotation.

Pour la mise à l'échelle/le redimensionnement, vous devez effectuer une translation de (-cx, -cy), puis une mise à l'échelle et enfin une translation de retour à (cx, cy). Vous pouvez le faire avec un transformation matricielle :

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

Où sx est le facteur d'échelle dans l'axe des x, sy dans l'axe des y.

0 votes

Merci beaucoup. La rotation fonctionne parfaitement je pense, mais la mise à l'échelle et le redimensionnement finissent toujours par être décalés d'une quantité aléatoire. J'ai essayé d'utiliser la matrice et de les faire séparément comme "translate(cx) sx, cy sy) scale(sx, sy)". Le même résultat.

6 votes

Ne serait-ce pas transform="matrix(sx, 0, 0, sy, cx-sx cx, cy-sy cy) " ? Parce que vous voulez traduire uniquement par la différence. Je pense que cette logique est correcte, mais cela me donne toujours des positions erronées...

0 votes

Maintenant ça marche ! J'utilisais juste les mauvaises valeurs de cx et cy ! Merci beaucoup !

109voto

George Points 374
svg * { 
  transform-box: fill-box;
}

en appliquant transform-box: fill-box fera en sorte qu'un élément dans un SVG se comporte comme un élément HTML normal. Vous pouvez alors appliquer transform-origin: center (ou autre) comme vous le feriez normalement

c'est vrai, transform-box: fill-box . De nos jours, il n'y a pas besoin d'une matrice compliquée.

22voto

Hafenkranich Points 1142

Si vous pouvez utiliser une valeur fixe (pas "center" 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.

15voto

cmititiuc Points 383

Pour une mise à l'échelle sans avoir à utiliser le matrix transformation :

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

Et le voici en CSS :

transform: translate(cxpx, cypx) scale(sx, sy) translate(-cxpx, -cypx)

14voto

forresto Points 1783

Si vous êtes comme moi et que vous voulez faire un panoramique puis un zoom 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);
};

Le voici qui fonctionne : http://forresto.github.io/dataflow-prototyping/react/

0 votes

Votre lien github 404s

0 votes

Bonjour @NuclearPeon, c'est génial, mais je n'arrive pas à l'implémenter dans mon code. L'élément SVG auquel j'aimerais que cela s'applique est déjà une variable appelée "mainGrid". J'ai essayé de remplacer l'instance de "view" par "mainGrid", sans résultat. Que me manque-t-il ? Merci !

0 votes

@sakeferret les choses les plus évidentes à vérifier sont que la id les correspondances dans la getElementById et les documents id="..." attribut. Il est difficile d'en être sûr sans voir le code. Si vous ne voulez pas le poster en tant que question SO, vous pouvez essayer de créer l'exemple le plus simple en utilisant vos noms d'attributs jusqu'à ce qu'il fonctionne/que vous trouviez le problème, puis rajouter le reste.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X