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

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

Comment redéfinir ce point d’ancrage de la transformation?

J’ai essayé d’utiliser l’atsortingbut transform-origin , mais cela n’affecte en rien.

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

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

Il ne semble pas définir le point crucial sur le point que j’ai spécifié, bien que je puisse voir dans Firefox que l’atsortingbut est correctement défini. J’ai essayé des choses comme le center bottom et 50% 100% avec et sans parenthèse. Rien n’a fonctionné jusqu’à présent.

Quelqu’un peut-il aider?

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

Pour le redimensionnement / redimensionnement, vous devez traduire par (-cx, -cy), puis mettre à l’échelle, puis revenir à (cx, cy). Vous pouvez le faire avec une transformation de masortingce :

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

Où sx est le facteur de mise à l’échelle sur l’axe des x, sy sur l’axe des y.

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.

Si vous êtes comme moi et que vous souhaitez effectuer un panoramique puis zoomer avec l’origine de la transformation, vous aurez besoin d’un peu plus.

 //  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 = "masortingx("+scale+",0,0,"+scale+","+x+","+y+")"; //var transform = "translate("+x+","+y+") scale("+scale+")"; //same view.setAtsortingbuteNS(null, "transform", transform); }; 

Ici, il fonctionne: http://forresto.github.io/dataflow-prototyping/react/

Pour la mise à l’échelle sans avoir à utiliser la transformation de masortingx :

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

Et la voici en CSS:

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

J’ai eu un problème similaire. Mais j’utilisais D3 pour positionner mes éléments et souhaitais que la transformation et la transition soient gérées par CSS. C’était mon code original, que j’ai utilisé 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.

MAIS cela n’a pas fonctionné dans Firefox! Ce que je devais faire était d’envelopper le circle dans la balise g et de le translate en utilisant la même formule de positionnement que ci-dessus. J’ai ensuite ajouté le circle dans la balise g et mis ses valeurs cx et cy à 0 . À partir de là, transform: scale(2) sera redimensionné du centre comme prévu. Le code final ressemblait à ceci.

 this.layerGroups.selectAll('.dot') .data(data) .enter() .append('g') .attrs({ class: d => `dot ${d.mesortingc}`, 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 , pour append la transform: scale(2) . Je n’ai même pas eu besoin d’utiliser l’ transform-origin .

REMARQUES:

  1. J’utilise d3-selection-multi dans le deuxième exemple. Cela me permet de passer un object à .attrs au lieu de répéter .attr pour chaque atsortingbut.

  2. Lorsque vous utilisez un littéral de modèle de chaîne, tenez compte des sauts de ligne, comme illustré dans le premier exemple. Cela inclura une nouvelle ligne dans la sortie et pourrait casser votre code.