2013-02-03 7 views
6

È possibile modificare l'animazione duration di un'animazione jQuery attualmente in esecuzione tra due valori diversi?Modifica la durata dell'animazione di jQuery durante l'animazione

Ho provato a cambiare il duration tramite assegnazione diretta, ma senza successo:

var timing = { duration: 4000 }; 
$(document).click(function (e) { 
    timing.duration = 1000; 
}); 

$('#foo').animate({top:200, left:200}, timing); 

... e anche, cambiando il fx.options.duration in step -Metodo non influenza l'animazione in esecuzione:

var state = false, 
$(document).click(function (e) { 
    state = true; 
}); 

$('#foo').animate({top:200, left:200}, { 
    duration: 4000, 
    step: function(now, fx){ 
    if(state) fx.options.duration = 1000; 
    console.log(fx.options.duration); // 1000 
    } 
}); 

Ecco uno fiddle per giocare. Qualche idea su come si può fare?

+0

Se si passa da jQuery 2.0 a jQuery> = 1.7.2 esso (in qualche modo) funziona. Immagino che abbia a che fare con le recenti modifiche apportate dal team jQuery alle funzioni relative alle animazioni. – Mahn

+0

@ Mahn Sì, grazie! Ho notato che ... sono al centro ora, prova a capire come farlo! – yckart

risposta

9

La durata viene passata per valore, non per riferimento. Quindi animate non memorizza un riferimento a duration. Anche se si aggiorna l'oggetto options (che viene passato per riferimento) jQuery utilizza internamente options.duration, il che significa che verrà passato per valore.

Come soluzione rapida, è possibile interrompere l'animazione e riavviarla con la nuova durata, regolando la parte dell'animazione già terminata.

Dovresti considerare come vuoi che si comporti, ad esempio quando acceleri un'animazione di 4 secondi in un'animazione di 2 secondi dopo 3 secondi. Nel codice qui sotto l'animazione sarà immediata. Pensandoci, probabilmente non è quello che vuoi dato che probabilmente ti interessa davvero la velocità, non la durata.

Il codice seguente è uno schizzo approssimativo, non sono sicuro se è accurato, se funziona quando si riducono i valori di animazione o come gestisce più valori di animazione. Puoi anche modificare la durata solo una volta.

var state = false, 
    duration = 8000; 

$(document).click(function (e) { 
    state = true; 
    duration = 1000; 
}); 
var animationCss = {top:200, left:200}; 
$('#foo').animate(animationCss, { 
    duration: duration, 
    step: function(now, fx){ 
     if(state) { 
      $("#foo").stop(); 
      var percentageDone = (fx.now - fx.start)/(fx.end - fx.start) 
      var durationDone = fx.options.duration * percentageDone; 
      var newDuration = duration - durationDone; 
      if (newDuration < 0) 
      { 
       newDuration = 0; 
      } 
      $("#foo").animate(animationCss, { duration: newDuration}) 

     } 
    } 
}); 

http://fiddle.jshell.net/5cdwc/3/

+0

Sì, grazie per i vostri pensieri e spiegazioni! L'idea è grandiosa, comunque penso, che ci sia sicuramente una soluzione più dolce da qualche parte in natura! – yckart

+0

@yckart C'è l'opzione 'easing', ma non sono sicuro di come funzioni e se è necessario conoscere la velocità dell'animazione prima di avviare l'animazione. –

+0

Questo può effettivamente funzionare bene, purché l'animazioneCss porti valori assoluti (ad esempio no + = 50) e in base a come si desidera che si comporti come @Matt menziona nella sua risposta. Puoi farlo sembrare piuttosto avvolgente in un plugin, che dovrebbe essere relativamente facile da fare. – Mahn

0

io sono probabilmente un po 'tardi per op, ma da quando ho finito qui durante il tentativo di fare la stessa cosa, qualcun altro troppo maggio.

Con il callback start() jQuery passa l'oggetto di animazione come argomento, quindi è sufficiente mantenere il riferimento da qualche parte e quindi è possibile modificarlo nel callback step().

Qualcosa di simile:

var animEnd = false; //this will be updated somewhere else 
var animObj; 
$().animate({ 
     width: '100%' 
    }, 
    { 
     start: function(animation){ 
      animObj = animation; 
     }, 
     step: function(now, tween){ 
      if(!animEnd) 
       //jquery set an interval of 13 but let's be safe 
       animObj.duration += 30; 

      //you can change the value of tween.pos aswell 
     } 
    } 
); 

Ora la parte difficile è che jQuery decidono di fermarsi o continuare l'animazione prima di chiamare il step() callback. Quindi la durata è impostata per il segno di spunta successivo e se non è stata impostata abbastanza grande, l'animazione potrebbe essere interrotta.
jQuery usa setInterval() con un intervallo di 13 quindi teoricamente step() deve essere chiamato ogni 13 ms ma poiché non è garantito nulla, penso che la durata dovrebbe essere aumentata di 30 ms come minimo.
Personalmente ci andrei almeno per almeno 100. Meglio avere un'animazione che gira un po 'troppo a lungo (100 ms è quasi impercettibile) piuttosto che doverla fermare troppo presto.