D3.js Odd Rotation Behavior

Je suis dans les premiers stades d'un projet JS. Tout va bien jusqu'à présent, sauf pour le positionnement d'une seule forme. La forme en question est un diamant de sarcelle (carré tourné à 45 degrés). Je peux obtenir le carré sur l'écran pas de problème, mais quand j'ajoute:

.attr("transform", "rotate(45)") 

Le carré tourne correctement, mais se déplace vers la partie gauche de l'écran, comme ceci:

Entrez la description de l'image ici

Je ne suis pas sûr de ce qui se produit. Si cela vous aide, voici une partie du code qui a produit ce résultat:

 var svg = d3.select("body") .append("svg") .attr("width", w) .attr("height", h); svg .append("rect") .attr("transform", "rotate(45)") .attr("x", 250) .attr("height", w / 10) .attr("width", w / 10) .attr("fill", "teal") 

Remarque: Si je place l'attribut "y", le carré disparaît complètement.

Qu'est-ce qui cause cela? Ai-je fait quelque chose de mal que je ne peux pas voir?

Lorsque vous faites pivoter le rect, vous faites pivoter son système de coordonnées. Donc, lorsque vous le déplacez plus tard 250 le long de l'axe des x, vous le déplacez réellement 250 unités le long d'un axe de 45 degrés – le résultat de la rotation.

En règle générale, lorsque vous introduisez un attribut de transform comme vous l'avez fait pour la rotate , vous devez effectuer toute votre transformation via cet attribut. Donc, vous devez utiliser la translate au lieu d'utiliser l'attribut "x" . Ensuite, il ressemblerait à ceci:

 svg .append("rect") .attr("transform", "translate(250, 0) rotate(45)") // remove this: .attr("x", 250) .attr("height", w / 10) ... 

Cela vous donne les résultats que je pense que vous recherchez. Notez maintenant que l'ordre des transformations est important ici: si votre transformation était "rotate(45) translate(250, 0)" (c.-à-d., Tourner d'abord puis traduire), vous obtiendrez les mêmes résultats erronés. C'est parce que lorsque vous tournez d'abord, votre traduction se produit, comme précédemment, le long d'un axe de rotation de x.

Dans SVG, vous devez définir l'origine de la transformation pour la faire tourner du centre, par exemple …

 .attr("transform", "rotate(45, 250, 100)"); 

250, 100 est la position x et y de votre rect moins son rayon. Tout en rassemblant, il ressemblerait à …

 var svg = d3.select("body") .append("svg") .attr("width", 400) .attr("height", 300); svg .append("rect") .attr("transform", "rotate(30,"+ (diamond.x+diamond.width/2) + ","+ (diamond.y+diamond.width/2) +")") .attr("x", diamond.x) .attr("y", diamond.y) .attr("height", diamond.width) .attr("width", diamond.width) .attr("fill", "teal")​ 

Vous pouvez afficher une démonstration ici:

http://jsfiddle.net/uwM8u/

Voici une approche légèrement différente de la réponse donnée par Duopixel. Ici, vous ne répétez pas les calculs pour X et Y. Dans l'exemple de Duopixel, c'est une amélioration triviale puisqu'il fait simplement référence à une structure. C'est souvent le cas que X et Y sont des fonctions et je ne voudrais pas maintenir cette connexion en deux endroits. Cette approche vous permet de définir X et Y un noeud, puis de tourner au centre dudit noeud.

Vous pouvez constater qu'après la rotation, vous souhaitez toujours modifier la position finale, ce qui pourrait être fait avec une autre transformation, ou dans le cas de TEXT, vous pouvez utiliser dx, dy.

  svgNode.attr("transform", function (d) { var w = +d3.select(this).attr("x") + (this.getBBox().width / 2) ; var h = +d3.select(this).attr("y") + (this.getBBox().height / 2); return "rotate(90," + w + "," + h + ")"; })