31 votes

Comment dessiner un chemin vectoriel de manière progressive ? (Raphael.js)

Comment animer un chemin vectoriel comme s'il était en train d'être dessiné, progressivement ? En d'autres termes, montrer lentement le chemin pixel par pixel.

J'utilise Raphaël.js , mais si votre réponse n'est pas spécifique à une bibliothèque - comme s'il existait un modèle de programmation général pour faire ce genre de choses (je suis assez novice en matière d'animation vectorielle) - elle est la bienvenue !


C'est facile à faire avec des chemins droits, aussi simple qu'un exemple sur cette page : :

path("M114 253").animate({path: "M114 253 L 234 253"});

Mais essayez de changer le code sur cette page, disons, de cette façon : :

path("M114 26").animate({path: "M114 26 C 24 23 234 253 234 253"});

Et vous verrez ce que je veux dire. Le chemin est certes animé depuis son état initial (point "M114 26") jusqu'à son état final (courbe "C 24 23 234 253 234 253" partant du point "M114 26"), mais pas d'une manière spécifiée dans la question, pas comme s'il était dessiné.

Je ne vois pas comment animateAlong peut le faire. Il peut animer un objet le long d'un chemin, mais comment faire pour que ce chemin s'affiche progressivement pendant que l'objet est animé le long de celui-ci ?


La solution ?

(Via La réponse de peteorpeter .)

Il semble qu'actuellement, la meilleure façon de le faire est d'utiliser de "faux" tirets en utilisant le SVG brut. Pour l'explication, voir cette démo o ce document page 4.

Comment produire un dessin progressif ?

Nous devons utiliser stroke-dasharray y stroke-dashoffset et connaître la longueur de la courbe à dessiner. Ce code ne dessine rien à l'écran pour un cercle, une ellipse, une polyligne, un polygone ou un chemin :

<[element] style="stroke-dasharray:[curve_length],[curve_length]; stroke-dashoffset:[curve_length]"/>

Si dans l'élément animate stroke-dashoffset on diminue à 0, on obtient un dessin progressif de la courbe.

<circle cx="200" cy="200" r="115"
    style="fill:none; stroke:blue; stroke-dasharray:723,723; stroke-dashoffset:723">
    <animate begin="0" attributeName="stroke-dashoffset"
        from="723" to="0" dur="5s" fill="freeze"/>
</circle>

Si vous connaissez une meilleure méthode, veuillez laisser une réponse.


Mise à jour (26 avr. 2012) : J'ai trouvé un exemple qui illustre bien l'idée, voir Courbes de Bézier animées .

26voto

davidenke Points 349

Peut-être que quelqu'un cherche une réponse, comme moi depuis deux jours maintenant :

// Draw a path and hide it:
var root = paper.path('M0 50L30 50Q100 100 50 50').hide();
var length = root.getTotalLength();

// Setup your animation (in my case jQuery):
element.animate({ 'to': 1 }, {
    duration: 500,
    step: function(pos, fx) {
        var offset = length * fx.pos;
        var subpath = root.getSubpath(0, offset);
        paper.clear();
        paper.path(subpath);
    }
});

Cela a fonctionné pour moi, mais en utilisant les méthodes de RaphaelJS.

Voici un exemple de jsFiddle comme demandé dans les commentaires, http://jsfiddle.net/eA8bj/

17voto

peteorpeter Points 2322

Eurêka ! (Peut-être - en supposant que vous soyez à l'aise pour sortir du domaine amical de Raphael et entrer dans le monde pur des SVG...)

Vous pouvez utiliser SVG heures clés y keySplines .

Voici un exemple concret :

http://www.carto.net/svg/samples/animated_bustrack.shtml

...et voici une explication potentiellement utile :

http://msdn.microsoft.com/en-us/library/ms533119(v=vs.85).aspx

11voto

Kevin Nielsen Points 3546

J'aimerais proposer une solution alternative, uniquement basée sur Raphael+JS, que j'ai largement utilisée dans mon propre travail. Elle présente plusieurs avantages par rapport à la solution de davidenke :

  1. Le papier n'est pas effacé à chaque cycle, ce qui permet à la trajectoire animée de coexister harmonieusement avec d'autres éléments ;
  2. Réutilise un chemin unique avec l'animation progressive propre à Raphael, ce qui permet des animations plus fluides ;
  3. Les ressources sont nettement moins importantes.

Voici la méthode (qui pourrait très facilement être transformée en extension) :

function drawpath( canvas, pathstr, duration, attr, callback )
{
    var guide_path = canvas.path( pathstr ).attr( { stroke: "none", fill: "none" } );
    var path = canvas.path( guide_path.getSubpath( 0, 1 ) ).attr( attr );
    var total_length = guide_path.getTotalLength( guide_path );
    var last_point = guide_path.getPointAtLength( 0 );
    var start_time = new Date().getTime();
    var interval_length = 50;
    var result = path;        

    var interval_id = setInterval( function()
    {
        var elapsed_time = new Date().getTime() - start_time;
        var this_length = elapsed_time / duration * total_length;
        var subpathstr = guide_path.getSubpath( 0, this_length );            
        attr.path = subpathstr;

        path.animate( attr, interval_length );
        if ( elapsed_time >= duration )
        {
            clearInterval( interval_id );
            if ( callback != undefined ) callback();
                guide_path.remove();
        }                                       
    }, interval_length );  
    return result;
}

Et voici deux exemples de son utilisation sur mon site : l'un pour Transformation de la voie et l'autre pour Lettrage progressif .

6voto

Brazhnyk Yuriy Points 61

Utilisation " pathLength "Nous pouvons définir une longueur virtuelle pour le chemin. A partir de là, nous pouvons utiliser cette longueur virtuelle dans "stroke-dasharray". Ainsi, si nous définissons "pathLength" à 100 unités, nous pouvons alors définir "stroke-dasharray" à "50,50", ce qui correspondrait exactement à 50%, 50% du chemin !

Il y a un problème avec cette approche : le seul navigateur qui prend en charge cet attribut est Opera 11.

Ici Voici un exemple d'animation de dessin en courbe douce sans javascript ou longueur codée en dur. (Ne fonctionne correctement que sur Opera 11).

3voto

Ben Points 1219

La solution d'Anton et Peteorpeter tombe malheureusement en panne dans Chrome lorsque les chemins se compliquent. Elle est parfaite pour le plan de bus dans la démo en lien. Jetez un coup d'œil à ce jsfiddle animé "pétales de fleurs" que j'ai créé, qui s'affiche correctement dans FF10 et Safari5, mais qui clignote de manière incontrôlable dans Chrome :

http://jsfiddle.net/VjMvz/

(Tout ceci est du HTML et du SVG en ligne, pas de javascript).

Je suis toujours à la recherche d'une solution non-Flash pour cela. AnimateAlong n'est évidemment pas adapté à ce que je fais. Raphael.js pourrait fonctionner, mais il risque de se transformer très vite en spaghetti de callbacks.

Davidenke, pouvez-vous poster un jsfiddle fonctionnel avec votre solution ? Je n'arrive pas à la faire fonctionner. J'obtiens une erreur dans Chrome 18 : les nœuds qui sont définis sur "display : none" avec votre ".hide" n'ont pas de méthode "getTotalLength".

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