2016-04-19 18 views
2

Hallo allerseits das ist Code, mit dem ich schon gearbeitet habe. Es bewegt ein Objekt von A nach B. Ich versuche mehrere Punkte zu haben, auf die es sich bewegen würde. Also von der Startposition A -> B, dann von B -> C und so weiter. Vielleicht haben Sie eine Variable, die Sätze von Koordinaten enthalten würde, die in einige animierte Funktionen als Parameter eingegeben würden. Aber alles, was ich versuchte, resultierte nur in der Ausführung des letzten Befehls, also würde es sich direkt von A -> C bewegen und B ignorieren. Jeder Rat/jede Demo wird geschätzt.Fabric.js animieren Objekt/Bild

Javascript

var canvas = new fabric.Canvas('scene', { backgroundColor: 'green'}); 

var triangle = new fabric.Triangle({ 
    width: 30 
    , height: 30 
    , fill: 'red' 
    , left: 30 
    , top: 0 
}); 

canvas.add(triangle); 

function animateTop() { 
    triangle.animate('top', '+=55', { 
    duration: 1000, 
    onChange: canvas.renderAll.bind(canvas) 
    }); 
} 

function animateLeft() { 
    triangle.animate('left', '+=100', { 
    duration: 1000, 
    onChange: canvas.renderAll.bind(canvas) 
    }); 
} 

function fireAnimation() { 
    animateTop(); 
    animateLeft(); 
} 

document.onreadystatechange = function() { 
    if (document.readyState == "complete") { 
    fireAnimation(); 
    } 
} 

HTML

<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8"> 
    <title>JS Bin</title> 
    <script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script> 
</head> 
<body> 
    <canvas id="scene" width="400" height="400" /> 
</body> 
</html> 

Antwort

1

Das Problem ist, Sie konfrontiert, dass die Animationsfunktionen blockieren einander nicht, so dass, wenn Ihre fireAnimation() Funktion ausgeführt wird, beginnt es beide Animationen Sensorbildschirm Gleichzeitig wird jeder Animationswechsel auf jeden Frame angewendet, was bedeutet, dass beide Animationen gleichzeitig auftreten.

Eine Möglichkeit, dies zu lösen, wäre, die Animationsaufrufe mit der Animation .onComplete zu ketten. Doing this könnte sperren Sie in ein bisschen eine höllische Situation, wenn Sie die Reihenfolge Ihrer Animationen aktualisieren müssen.

Vorausgesetzt, Sie haben vielleicht eine Liste von Animationen vorgeschlagen, die nacheinander angewendet werden, können Sie besser eine generische Funktion erstellen, die Animationen basierend auf einer Eingabeliste von Animationsparametern wie folgt anwendet (Erklärung in Kommentaren im Code):

function startAnimationQueue(animationQueue){ 
    // queues up the animations for the shape 

    var runningDuration = 0; // variable that adds up the animationQueue durations 
    for (var i=0; i<animationQueue.length; i++){ 
     var animationDefinition = animationQueue[i]; 

     // Create a closure around the animationDefiniton so that each setTimeout gets sequential animationDefinition inputs 
     var fn = (function(animationDefinition){ 
      return function(){ 
       triangle.animate('left', animationDefinition.left, {duration: animationDefinition.duration, onChange:canvas.renderAll.bind(canvas)}) 
       triangle.animate('top', animationDefinition.top, {duration: animationDefinition.duration, onChange:canvas.renderAll.bind(canvas)}) 
       // Note: you can animate additional attributes here if you want, just add additional attributes to the objects in 
       // the animationQueue list. You could also have one of those inputs be the object to be animated in case you want 
       // to animate multiple objects using the same queue. 
       }; 
      }) 

     // Create the timeout that will apply the transformations sequentially 
     // If you want you could set the window.setTimeout to a variable that you could destroy if you need 
     // to interrupt the animation queue after you create it (but before it finishes) 
     window.setTimeout(fn(animationDefinition), runningDuration); 

     // set the next setTimeout duration to be .duration later than the previous one 
     // this makes the second animation fire after the first one completes 
     runningDuration += animationDefinition.duration; 
    } 
} 

document.onreadystatechange = function() { 
    if (document.readyState == "complete") { 

    // I put the canvas init stuff in here because of (I think) a failed race condition or something that caused 
    // your original method to fail in Chrome 
    window.canvas = new fabric.Canvas('scene'); 

    window.triangle = new fabric.Triangle({ 
     width: 30 
     , height: 30 
     , fill: 'red' 
     , left: 30 
     , top: 0 
    }); 

    window.canvas.add(window.triangle); 
    window.canvas.renderAll(); 

    // Create a list of animations to apply 
    var animationQueue = [ 
     {"left": "+=0", "top": "+=100", "duration": 1000}, 
     {"left": "+=55", "top": "+=0", "duration": 2000} 

    ] 

    // Apply the animations in sequence using window.setTimeout 
    startAnimationQueue(animationQueue); 
    } 
} 
+1

+1 für die Liste. @ Yondaru, ich empfehle Ihnen, in State-Maschinen zu schauen, sie sind der beste Ansatz für die Handhabung von Animationssequenzen. –

+0

@nickvans, Vielen Dank, funktioniert wie Charme. Und könntest du mir vielleicht sagen, was du tun würdest, wenn du einen Bild-Uploader für diese Leinwand hättest und du würdest jedem der hochgeladenen Bilder eine Liste von Befehlen zuweisen? – Yondaru

+0

Zuerst fügen Sie jedem animationQueue-Objekt ein zusätzliches Attribut hinzu, das das Fabric-Objekt für das Bild speichert, sobald Sie es erstellt haben. '{" fabricShape ": newlyAddedShape," left ":" + = 0 ", ...' Ändere die Closure-Funktion so, dass 'animationDefinition.newlyAddedShape' anstelle von' triangle' verwendet wird. Im abgeschlossenen Event für deinen Uploader (das Event wird ausgelöst wenn Der Upload ist erfolgreich. Erstellen Sie einfach eine neue animationQue-Liste für dieses Objekt und übergeben Sie sie an die startAnimationQueue-Funktion. – nickvans