Tracer le chemin avec l'objet DOM

Je suis nouveau sur javascript et d3js. J'aimerais qu'un objet DOM trace un chemin spécifié par une courbe paramétrée (x (t), y (t)). Voici un exemple d'un tel paramétrage:

var theta = []; for(var i = 0; i <= N; i++){ theta.push(2*Math.PI*i/N); } var points = []; for(var i = 0; i <= N; i++){ points.push([Math.cos(theta[i]),Math.sin(theta[i])]); } 

Ce qui précède est le paramétrage d'une courbe – dans ce cas, aussi un cercle – et j'aimerais que mon objet DOM suive la trajectoire de cette courbe. [A part: existe-t-il un meilleur moyen de définir des points ? Il semble ridicule d'exécuter une boucle for.]

Une manière brute d'obtenir le type d'effet que je recherche est de lancer une boucle for dans la mise à jour () partie de d3. Tout d'abord, j'ajoute un cercle à la variable svg, de sorte qu'il ne faut pas l'associer à aucune donnée. Il est ensuite sélectionné et mis à jour sans entrer / sortir.

  for (var i = 0; i <= N; i++){ svg.selectAll("circle") .transition() .attr("cx",points[i][0]+w/2) // w: width .attr("cy",points[i][1]+h/2) // h: height .duration(dt) // .delay(dt*i); } 

[A part: j'ai entendu la file d'attente () être mieux, par opposition à calculer le délai total. Commentaires?] Cependant, la propriété d'assouplissement de la transition le fait fonctionner de manière agitée. J'imagine que je pourrais ne spécifier aucun assouplissement, mais je suis sûr qu'il doit y avoir une meilleure façon de réaliser ce que je veux, qui est simplement pour l'objet DOM initial (le cercle) se déplacer en douceur le long d'une trajectoire spécifique.

À la fin, je voudrais le faire pour plusieurs objets DOM qui seront éventuellement liés à des données, chacune avec une courbe spécifique à suivre. Des conseils sur la façon dont je ferais cela?

Merci d'avance pour toute aide, et je serai heureux de prendre des conseils, y compris des références.

Une approche intéressante mais pas terriblement pratique

La spécification SVG possède effectivement plusieurs options d'animation, y compris la possibilité de déplacer un objet le long d'un chemin. Le chemin d'accès est défini de la même manière que pour un élément <path> , de sorte que vous pouvez utiliser les fonctions d3.svg.arc pour créer le chemin.

Une fois que vous avez un chemin défini, il est facile d'utiliser d3 pour ajouter à l'animation:
http://fiddle.jshell.net/RnNsE/1/
Bien que vous souhaitiez lire sur les éléments et les attributs d'animation SVG .

Cependant, il existe une limitation à cette merveilleuse animation: un faible support de navigateur . Donc, si cela concerne un site Web, vous devrez faire l'animation avec d3 et Javascript.

Approche prête à la production

La clé pour obtenir d3 pour créer des animations en douce pour vous est d'utiliser une fonction "tween" personnalisée sur une transition.

Lorsque vous effectuez une transition, d3 initialise une fonction d'interpolation pour chaque changement sur chaque élément et démarre les fonctions de la minuterie pour déclencher les mises à jour. À chaque "tick" de la minuterie, d3 appelle la fonction "tween" appropriée avec les informations sur la durée de la transition. Donc, si la tache se produit 500 ms dans une transition de 2000 ms, la fonction d'interpolation donnera la valeur 0,25 (en supposant une fonction d'assouplissement linéaire, d'autres fonctions d'assouplissement compliquent la relation entre le temps écoulé et la «distance» attendue le long de la transition).

Maintenant, pour la plupart des modifications, la fonction d'interpolation est assez simple, et d3 sera automatiquement identifié pour vous. Si vous changez une valeur "cx" de 100 à 200, la fonction d'interpolation va retourner 125 lorsque la valeur de transition 25%, 150 lorsque la transition est de 50% et ainsi de suite. Si vous changez une valeur "fill" de rouge en jaune, elle calculera les valeurs numériques de ces couleurs et les convertira.

La valeur renvoyée par la fonction tween à chaque coche est ensuite utilisée pour mettre à jour l'attribut ou le style de l'élément. Comme les mises à jour se produisent plusieurs fois par seconde, elles entraînent généralement une animation en douceur. Pour l'exemple simple de modification de la valeur "cx" d'un cercle, le cercle se déplace en ligne droite du point de départ au point final.

Mais vous ne voulez pas qu'il se déplace en ligne droite. Vous voulez qu'il se déplace en cercle (ou le long de n'importe quel chemin que vous choisissez). Donc, vous devrez créer une fonction personnalisée qui indique au cercle où il devrait être 25% de la transition, et où il devrait être de 50% pendant la transition, et ainsi de suite.

Et si vous êtes inquiet, vous devez comprendre cela seul, ne craignez jamais. Comme tellement, tant avec D3, Mike Bostock a fait du travail pour vous . Mais même il n'avait pas à faire le dur travail. Son approche utilise deux fonctions JavaScript intégrées pour les chemins SVG, getTotalLength() et getPointAtLength() . Le premier vous indique la longueur totale du chemin, le second vous donne les coordonnées du point à une certaine distance du début du chemin.

Avec ces deux valeurs, il est simple de déterminer les coordonnées que vous devriez être si vous voulez être un certain pourcentage de la façon le long du chemin: à 25%, vous voulez être à path.getPointAtLength(0.25*path.getTotalLength() ) .

Voici la fonction de Mike qui fait que cela se produise:

 // Returns an attrTween for translating along the specified path element. function translateAlong(path) { var l = path.getTotalLength(); return function(d, i, a) { return function(t) { var p = path.getPointAtLength(t * l); return "translate(" + px + "," + py + ")"; }; }; } 

Un peu déroutant, non? Une fonction qui renvoie une fonction qui renvoie une fonction.

C'est parce que lorsque vous spécifiez une «interpolation» pour une transition, ce que vous devez effectivement spécifier est «tween factory» – la fonction qui renverra une fonction d'interpolation appropriée pour chaque élément de votre sélection.

Maintenant, dans son exemple, il n'a qu'un seul chemin et un objet se déplaçant le long de celui-ci, de sorte que ces couches supplémentaires ne s'habituent pas. Mais dans le cas général, votre fonction d'usine tween prendrait les arguments d (l'objet de données pour cet élément dans la sélection), i (l'indice de cet élément) et a (la valeur initiale de l'attribut ou du style que vous êtes en changeant). Avec ces valeurs, vous devez renvoyer la fonction d'interpolation personnalisée qui prend une valeur d'état de transition t (un nombre entre 0 ou 1 ou peut-être un peu plus de 1 pour certaines fonctions d'assouplissement) et calcule la valeur de l'attribut à cet état lors de la transition.

Vous remarquerez que cette fonction renvoie une instruction de traduction. Cela va généralement être un moyen plus simple de déplacer un objet autour, par rapport à l'utilisation de cx et cy , car vous pouvez spécifier le mouvement horizontal et vertical dans un appel d'attribut de transformation, donc vous avez seulement besoin de la fonction d'interpolation pour faire les deux.

Voici mon exemple ci-dessus, mis à jour pour utiliser une interpolation d3 pour déplacer les cercles le long du chemin:
http://fiddle.jshell.net/RnNsE/2/

Code clé:

 circles.transition().ease("linear") .duration(5000) .delay(function(d,i){return i*5000;}) .attrTween("transform", createPathTween); //creates a tween function to translate an element //along the path that is a sibling to the element function createPathTween(d, i, a) { var path = this.parentNode.getElementsByTagName("path")[0]; //ie, go from this <circle> -> parent <g> -> array of child <path> elements -> first (and only) element in that array var l = path.getTotalLength(); return function(t) { var p = path.getPointAtLength(t * l); return "translate(" + px + "," + py + ")"; }; } 

Ma version supprime la couche la plus externe des fonctions imbriquées de la version de Mike, mais elle ajoute un peu de Javascript pour trouver l'élément <path> correct pour chaque élément de cercle.

Notez que vous avez besoin d' un élément de chemin SVG afin d'utiliser les fonctions getTotalLength() et getPointAtLength() ; Cependant, ce chemin peut être invisible ( fill:none; stroke:none; in CSS) si vous ne voulez pas qu'il s'affiche à l'écran. Et encore, alors que mes définitions de chemin sont codées en dur, vous pouvez utiliser un des générateurs d' arc ou de ligne de D3 pour la construire pour vous.

Et juste pour le plaisir, voici mon exemple avec une fonction d'assouplissement différente:
http://fiddle.jshell.net/RnNsE/3/
Notez que je n'ai rien changé sur la fonction d'interpolation – tout ce qui a changé est la valeur t que d3 passe dans cette fonction au fur et à mesure que la transition progresse.

PS Voici une autre bonne ressource sur les fonctions d'interpolation personnalisée d3: http://blog.safaribooksonline.com/2013/07/11/reusable-d3-js-using-attrtween-transitions-and-mv/