J'ai besoin de redimensionner et de faire pivoter certains éléments d'un document SVG à l'aide de 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 l'attribut transform-Origin
, mais cela n'affecte rien.
Voici comment je l'ai fait:
svg.getDocumentById('someId').setAttribute('transform-Origin', '75 240');
Il ne semble pas que le point pivot soit celui que j’ai spécifié bien que je puisse voir dans Firefox que cet attribut est correctement défini. J'ai essayé des choses comme 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 est le degré de rotation souhaité et (cx, cy) définissez le centre de rotation.
Pour la mise à l'échelle/le redimensionnement, vous devez traduire par (-cx, -cy), puis redimensionner et ensuite traduire en (cx, cy). Vous pouvez le faire avec une transformation matrix :
transform="matrix(sx, 0, 0, sy, cx-sx*cx, cy-sy*cy)"
Où sx est le facteur d'é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 les valeurs relatives correctement.
Si vous êtes comme moi et que vous souhaitez effectuer 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);
};
Ici cela fonctionne: http://forresto.github.io/dataflow-prototyping/react/
Pour une mise à l'échelle sans avoir à utiliser la transformation matrix
:
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)
J'ai eu un problème similaire. Mais j’utilisais D3 pour positionner mes éléments et je voulais que transform et transition soient gérés par CSS. C’était mon code original, que j’ai obtenu sous 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, c’est d’envelopper circle
dans la balise g
et translate
avec la même formule de positionnement que ci-dessus. J'ai ensuite ajouté la variable circle
à la balise g
et ai défini ses valeurs cx
et cy
sur 0
. À partir de là, transform: scale(2)
évoluerait à partir du centre comme prévu. Le code final ressemblait à ceci.
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 apporté cette modification, j'ai modifié mon CSS pour cibler la circle
au lieu du .dot
, afin d'ajouter la transform: scale(2)
. Je n'ai même pas eu besoin d'utiliser transform-Origin
.
REMARQUES:
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.
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.