15 votes

Comment animer un dessin progressif d'un chemin svg ?

Je veux animer un dessin progressif d'une ligne en utilisant seulement css avec svg/canvas et js maximum. Une idée de la ligne que je veux dessiner peut être trouvée aquí

<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">
 <!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
 <g>
  <title>Layer 1</title>
  <path d="m33,104c1,0 2.1306,-0.8037 23,3c9.07012,1.65314 10,2 24,2c7,0 29,0 33,0c8,0 9,0 11,0c2,0 8,0 11,0c9,0 17,0 18,0c10,0 12,0 20,0c1,0 6,0 7,0c2,0 3.07613,0.38268 4,0c2.61313,-1.08239 2,-3 2,-6c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0.30745,-3.186 -1,-5c-0.8269,-1.14727 -0.09789,-2.82443 -2,-4c-0.85065,-0.52573 -2.82443,-0.09789 -4,-2c-0.52573,-0.85065 -2.58578,-0.58578 -4,-2c-0.70711,-0.70711 -1.81265,-1.20681 -4,-3c-2.78833,-2.28588 -3.64749,-2.97251 -8,-4c-2.91975,-0.68926 -4.82375,-2.48626 -7,-3c-2.91975,-0.68926 -5.15224,-0.23463 -7,-1c-1.30656,-0.5412 -4.38687,-1.91761 -7,-3c-1.84776,-0.76537 -5.03609,0.37821 -7,0c-5.28799,-1.01837 -8,-3 -9,-3c-2,0 -5.0535,-0.54049 -7,-1c-2.17625,-0.51374 -4.15224,-0.23463 -6,-1c-1.30656,-0.54119 -3,-1 -4,-1c-2,0 -5,-1 -6,-1c-1,0 -3,-2 -6,-2c-2,0 -5,-2 -6,-2c-2,0 -2.02583,-0.67963 -4,-1c-3.12144,-0.50654 -4.15224,-0.23463 -6,-1c-1.30656,-0.54119 -2,-1 -3,-1c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-1,0 -2,0 -3,0c-1,0 -2,0 -3,0c-2,0 -3.85273,0.1731 -5,1c-1.81399,1.30745 -5.18601,1.69255 -7,3c-1.14727,0.8269 -1.82375,2.48626 -4,3c-0.97325,0.22975 -1.69344,1.45881 -3,2c-0.92388,0.38268 -1.45951,1.0535 -1,3c0.51374,2.17625 3.07844,2.78985 6,4c2.06586,0.85571 3.38688,1.91761 6,3c1.84776,0.76537 5.2987,-1.05146 7,0c1.90211,1.17557 3.82375,2.48626 6,3c0.97325,0.22975 3.29289,0.29289 4,1c0.70711,0.70711 4,2 9,4c5,2 8,4 11,4c2,0 5,0 7,0c3,0 5,0 7,0c2,0 4,0 7,0c2,0 4,0 8,0c3,0 7,0 10,0c4,0 7,0 12,0c3,0 5,0 6,0c2,0 3,0 5,0c1,0 1.09789,-0.82443 3,-2c0.85065,-0.52573 3.07613,0.38268 4,0c1.30656,-0.5412 0.71022,-2.04291 1,-3c1.04483,-3.45084 2.84723,-5.04132 4,-9c0.88414,-3.03616 1.85194,-5.22836 3,-8c0.5412,-1.30656 1.5405,-2.0535 2,-4c0.51375,-2.17625 2.71413,-4.21167 5,-7c2.68979,-3.28101 4,-6 5,-7c1,-1 2,-2 2,-4c0,-1 0.70711,-2.29289 0,-3c-0.70711,-0.70711 -2.07613,0.38268 -3,0c-1.30656,-0.54119 -2,-1 -4,-1c-3,0 -6.87856,-2.49346 -10,-3c-2.96126,-0.48055 -6.71201,-0.98162 -12,-2c-2.94586,-0.56732 -5,-1 -9,-1c-3,0 -6,-1 -8,-1c-2,0 -5,-3 -7,-3c-2,0 -5.38687,-0.91761 -8,-2c-0.92388,-0.38268 -3.0535,-0.54049 -5,-1c-2.17625,-0.51374 -4.58578,0.41421 -6,-1c-0.70711,-0.70711 -1,-1 -2,-1c-1,0 -2,0 -3,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,0c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-1,0 -3,0 -4,0c-3,0 -5,0 -7,0c-2,0 -4,0 -6,0c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-2,0 -4,0 -5,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,1l-1,0" id="svg_1" stroke-width="5" stroke="#000000" fill="none"/>
 </g>
</svg>

44voto

Phrogz Points 112337

Il y a trois techniques énumérées dans cette réponse :


Il existe une solution tout-SVG qui consiste à modifier progressivement les stroke-dasharray pour que la forme dessine un "tiret" de plus en plus long suivi d'un énorme vide.

Démonstration : http://phrogz.net/svg/progressively-drawing-svg-path-via-dasharray.html

Code pertinent :

var distancePerPoint = 1;
var drawFPS          = 60;

var orig = document.querySelector('path'), length, timer;
orig.addEventListener('mouseover',startDrawingPath,false);
orig.addEventListener('mouseout', stopDrawingPath, false);

function startDrawingPath(){
  length = 0;
  orig.style.stroke = '#f60';
  timer = setInterval(increaseLength,1000/drawFPS);
}

function increaseLength(){
  var pathLength = orig.getTotalLength();
  length += distancePerPoint;
  orig.style.strokeDasharray = [length,pathLength].join(' ');
  if (length >= pathLength) clearInterval(timer);
}

function stopDrawingPath(){
  clearInterval(timer);
  orig.style.stroke = '';
  orig.style.strokeDasharray = '';
}

Sinon, vous pouvez toujours utiliser tout le SVG et choisir de construire le chemin SVG une commande à la fois :

Démonstration : http://phrogz.net/svg/progressively-cloning-svg-path.html

Code pertinent :

// Assumes 'orig' and dup' are SVG paths
function addNextPathSegment(){
  var nextIndex   = dup.pathSegList.numberOfItems;
  if (nextIndex<orig.pathSegList.numberOfItems){
    var nextSegment = orig.pathSegList.getItem(nextIndex);
    var segmentDup  = cloneSVGPathSeg( dup, nextSegment );
    dup.pathSegList.appendItem( segmentDup );
  }
}

function cloneSVGPathSeg( path, seg ){
  switch(seg.pathSegTypeAsLetter){
    case 'M': return path.createSVGPathSegMovetoAbs(seg.x,seg.y);                                                     break;
    case 'm': return path.createSVGPathSegMovetoRel(seg.x,seg.y);                                                     break;
    case 'L': return path.createSVGPathSegLinetoAbs(seg.x,seg.y);                                                     break;
    case 'l': return path.createSVGPathSegLinetoRel(seg.x,seg.y);                                                     break;
    case 'H': return path.createSVGPathSegLinetoHorizontalAbs(seg.x);                                                 break;
    case 'h': return path.createSVGPathSegLinetoHorizontalRel(seg.x);                                                 break;
    case 'V': return path.createSVGPathSegLinetoVerticalAbs(seg.y);                                                   break;
    case 'v': return path.createSVGPathSegLinetoVerticalRel(seg.y);                                                   break;
    case 'C': return path.createSVGPathSegCurvetoCubicAbs(seg.x,seg.y,seg.x1,seg.y1,seg.x2,seg.y2);                   break;
    case 'c': return path.createSVGPathSegCurvetoCubicRel(seg.x,seg.y,seg.x1,seg.y1,seg.x2,seg.y2);                   break;
    case 'S': return path.createSVGPathSegCurvetoCubicSmoothAbs(seg.x,seg.y,seg.x2,seg.y2);                           break;
    case 's': return path.createSVGPathSegCurvetoCubicSmoothRel(seg.x,seg.y,seg.x2,seg.y2);                           break;
    case 'Q': return path.createSVGPathSegCurvetoQuadraticAbs(seg.x,seg.y,seg.x1,seg.y1);                             break;
    case 'q': return path.createSVGPathSegCurvetoQuadraticRel(seg.x,seg.y,seg.x1,seg.y1);                             break;
    case 'T': return path.createSVGPathSegCurvetoQuadraticSmoothAbs(seg.x,seg.y);                                     break;
    case 't': return path.createSVGPathSegCurvetoQuadraticSmoothRel(seg.x,seg.y);                                     break;
    case 'A': return path.createSVGPathSegArcAbs(seg.x,seg.y,seg.r1,seg.r2,seg.angle,seg.largeArcFlag,seg.sweepFlag); break;
    case 'a': return path.createSVGPathSegArcRel(seg.x,seg.y,seg.r1,seg.r2,seg.angle,seg.largeArcFlag,seg.sweepFlag); break;
    case 'z':
    case 'Z': return path.createSVGPathSegClosePath();                                                                break;
  }
}

Enfin, vous pouvez choisir de dessiner votre chemin sur un canevas HTML5 en échantillonnant périodiquement le chemin SVG et en le dessinant sur le canevas. (Notez que le chemin SVG n'a pas besoin d'être affiché pour que cela se produise ; vous pouvez construire un élément de chemin SVG entièrement en JavaScript et l'échantillonner) :

Démonstration : http://phrogz.net/svg/progressively-drawing-svg-path.html

Code pertinent :

function startDrawingPath(){
  points = [];
  timer = setInterval(buildPath,1000/drawFPS);
}

// Assumes that 'orig' is an SVG path
function buildPath(){
  var nextPoint = points.length * distancePerPoint;
  var pathLength = orig.getTotalLength();
  if (nextPoint <= pathLength){
    points.push(orig.getPointAtLength(nextPoint));
    redrawCanvas();
  } else stopDrawingPath();
}

function redrawCanvas(){
  clearCanvas();
  ctx.beginPath();
  ctx.moveTo(points[0].x,points[0].y);
  for (var i=1;i<points.length;i++) ctx.lineTo(points[i].x,points[i].y);
  ctx.stroke();
}

6voto

Joonas Points 4679

Il y a donc cette question similaire avec cette réponse .


J'ai pris votre chemin et l'ai mis dans le code dans cette réponse.

Démonstration de jsfiddle

Html :

<html>
<style>
    #canvas
    {
    border-style:solid;
    border-width:1px;
    }
</style>
<div id="canvas"> 
    <p>Hover over me</p>        
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

Javascript ( Notez que Jquery 1.8.3 et Raphael 1.5.2 ont été utilisés dans l'exemple ) :

$(function() {

animateLine = function(canvas, hoverDivName, colorNumber, pathString) {
    $('#' + hoverDivName).hover(

    function() {
        var line = canvas.path(pathString).attr({
            stroke: colorNumber
        });
        var length = line.getTotalLength();

        $('path[fill*="none"]').animate({
            'to': 1
        }, {
            duration: 5000,
            step: function(pos, fx) {
                var offset = length * fx.pos;
                var subpath = line.getSubpath(0, offset);
                canvas.clear();
                canvas.path(subpath).attr({
                    'stroke-width': 5,
                    stroke: colorNumber
                });

            },
        });
    }, function() {
        $('path[fill*="none"]').stop(true, false).fadeOut();
    });
};

var canvas = Raphael('canvas', 200, 200);
var pathString = "m33,104c1,0 2.1306,-0.8037 23,3c9.07012,1.65314 10,2 24,2c7,0 29,0 33,0c8,0 9,0 11,0c2,0 8,0 11,0c9,0 17,0 18,0c10,0 12,0 20,0c1,0 6,0 7,0c2,0 3.07613,0.38268 4,0c2.61313,-1.08239 2,-3 2,-6c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0.30745,-3.186 -1,-5c-0.8269,-1.14727 -0.09789,-2.82443 -2,-4c-0.85065,-0.52573 -2.82443,-0.09789 -4,-2c-0.52573,-0.85065 -2.58578,-0.58578 -4,-2c-0.70711,-0.70711 -1.81265,-1.20681 -4,-3c-2.78833,-2.28588 -3.64749,-2.97251 -8,-4c-2.91975,-0.68926 -4.82375,-2.48626 -7,-3c-2.91975,-0.68926 -5.15224,-0.23463 -7,-1c-1.30656,-0.5412 -4.38687,-1.91761 -7,-3c-1.84776,-0.76537 -5.03609,0.37821 -7,0c-5.28799,-1.01837 -8,-3 -9,-3c-2,0 -5.0535,-0.54049 -7,-1c-2.17625,-0.51374 -4.15224,-0.23463 -6,-1c-1.30656,-0.54119 -3,-1 -4,-1c-2,0 -5,-1 -6,-1c-1,0 -3,-2 -6,-2c-2,0 -5,-2 -6,-2c-2,0 -2.02583,-0.67963 -4,-1c-3.12144,-0.50654 -4.15224,-0.23463 -6,-1c-1.30656,-0.54119 -2,-1 -3,-1c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-1,0 -2,0 -3,0c-1,0 -2,0 -3,0c-2,0 -3.85273,0.1731 -5,1c-1.81399,1.30745 -5.18601,1.69255 -7,3c-1.14727,0.8269 -1.82375,2.48626 -4,3c-0.97325,0.22975 -1.69344,1.45881 -3,2c-0.92388,0.38268 -1.45951,1.0535 -1,3c0.51374,2.17625 3.07844,2.78985 6,4c2.06586,0.85571 3.38688,1.91761 6,3c1.84776,0.76537 5.2987,-1.05146 7,0c1.90211,1.17557 3.82375,2.48626 6,3c0.97325,0.22975 3.29289,0.29289 4,1c0.70711,0.70711 4,2 9,4c5,2 8,4 11,4c2,0 5,0 7,0c3,0 5,0 7,0c2,0 4,0 7,0c2,0 4,0 8,0c3,0 7,0 10,0c4,0 7,0 12,0c3,0 5,0 6,0c2,0 3,0 5,0c1,0 1.09789,-0.82443 3,-2c0.85065,-0.52573 3.07613,0.38268 4,0c1.30656,-0.5412 0.71022,-2.04291 1,-3c1.04483,-3.45084 2.84723,-5.04132 4,-9c0.88414,-3.03616 1.85194,-5.22836 3,-8c0.5412,-1.30656 1.5405,-2.0535 2,-4c0.51375,-2.17625 2.71413,-4.21167 5,-7c2.68979,-3.28101 4,-6 5,-7c1,-1 2,-2 2,-4c0,-1 0.70711,-2.29289 0,-3c-0.70711,-0.70711 -2.07613,0.38268 -3,0c-1.30656,-0.54119 -2,-1 -4,-1c-3,0 -6.87856,-2.49346 -10,-3c-2.96126,-0.48055 -6.71201,-0.98162 -12,-2c-2.94586,-0.56732 -5,-1 -9,-1c-3,0 -6,-1 -8,-1c-2,0 -5,-3 -7,-3c-2,0 -5.38687,-0.91761 -8,-2c-0.92388,-0.38268 -3.0535,-0.54049 -5,-1c-2.17625,-0.51374 -4.58578,0.41421 -6,-1c-0.70711,-0.70711 -1,-1 -2,-1c-1,0 -2,0 -3,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,0c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-1,0 -3,0 -4,0c-3,0 -5,0 -7,0c-2,0 -4,0 -6,0c-2,0 -3,0 -5,0c-1,0 -2,0 -3,0c-2,0 -4,0 -5,0c-1,0 -2,0 -4,0c-1,0 -2,0 -3,1l-1,0";

animateLine(canvas, "canvas", "#000", pathString);

});
  • J'ai pris votre chemin à partir du [ d et le placer à l'intérieur de l'attribut pathString variable.
  • J'ai également ajouté une ligne pour définir le [ stroke-width ]

Je n'ai joué qu'une seule fois avec raphael de manière assez brève, mais en vérifiant les exemples et en regardant comment le code est construit ( from page source ) permet d'aller assez loin (je n'arrivais pas à me rappeler où et comment placer le bouton stroke-width J'ai donc vérifié la méthode à partir de la source de la page en question. exemple . ).


Vous pouvez trouver raphael et plus d'informations ici.


Juste pour le plaisir, J'ai fait mon propre chemin...

4voto

carl Points 41

En utilisant l'excellente technique de Phrogz, j'ai créé une animation GreenSock très basique en utilisant TweenLite pour interpeller la valeur de la longueur à la valeur de getTotalLength().

Comme vous pouvez le voir dans la démo, le fait de l'intégrer à un moteur d'interpolation vous permet d'avoir un contrôle total, et ce, avec très peu de code.

var orig = document.querySelector('path'), length, timer;

var obj = {length:0,
           pathLength:orig.getTotalLength()};

orig.style.stroke = '#f60';

var t = TweenMax.to(obj, 10, {length:obj.pathLength, onUpdate:drawLine, ease:Linear.easeNone})

function drawLine() {
  orig.style.strokeDasharray = [obj.length,obj.pathLength].join(' ');
  updateSlider();
}

Un grand respect à Phrogz pour cette idée et ce code géniaux.

http://codepen.io/GreenSock/pen/zLiux

2voto

Ashley Sheridan Points 526

J'ai fait quelque chose de similaire l'année dernière pour animer un dessin dans canvas. Les chemins sont tous des chemins de type SVG avec des courbes et des lignes, vous pouvez donc les extraire directement de votre fichier SVG et les placer dans le tableau Javascript.

http://www.ashleysheridan.co.uk/coding/javascript/Animated+Glowing+Line+Drawing+in+Canvas

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