Egyszerű JavaScript animation queue
Egyik kedves ismerősömnek segédkezem egy egyszerű honlap elkészítésénél. Adott volt egy logó, melyet maga tervezett. Megálmondtott egy egyszerű animációt a logóval kapcsolatban. Mondta, hogy miért ne legyen Flash-ben megoldva, én meg mondtam, hogy miért ne legyen megoldva Flash nélkül?
Így hát nekifogtam a dolognak. Megkaptam az animáció egyes fázisairól a forrásképeket. Ezeket összeillesztettem Photoshopban, mivel az eredeti grafika Corelben készült. Kigondoltam, hogy miként valósítanám meg az animációt HTML, CSS és JavaScript segítségével, majd ez alapján létrehoztam egyetlen GIF fájlt (CSS sprite).
A gondok ezután kezdődtek. Az egyes grafikai objektumokat reprezentáló HTML elemek létrehozása, majd alap „konfigurációs” CSS kódok megírása után pofáncsapott megint az a jelenség, hogy a JavaScriptben nincsen megoldás az egymást követő műveletek „lineáris” végrehajtására.
Hiába vannak egymás után kiadva a parancsok, azok azonos időpillanatban kezdenek futni. A jQuery-nek bár van animation queue megoldása, de ez csak akkor működik, ha az egymás után végrehajtandó animációkat ugyanazon HTML elemen akarjuk futtatni.
Van egy kiegészítés a jQuery-hez, ami kiterjeszti az alap animation queue-t oly módon, hogy meg lehet adni az animate()
parancsnak paraméterben, hogy a kérdéses animáció melyik (nevesített) queue-hoz tartozzon.
Szépen működik is, de a csomagban 1.4-es jQuery van, a legújabb 1.7.1-es verzióval nem működik. Mivel nem értek a jQuery-hez, és egyébként sem szívem csücske a JavaScript, egy egyszerű megoldást kerestem a problémára.
Fórumokban keresgélve vagy a callback alapú megoldást ajánlották, vagy pedig a klasszikus setTimeout()
-ot. A callbackes történet (amikor egyik animáció callbackje a következő animáció, és így tovább) addig jó, amíg az animation()
metódussal operálunk. Nekem viszont kellett a css()
is, így ezt a megoldást elvetettem.
Marad nekünk a setTimeout()
, ami alap esetben eléggé megnehezíti a dolgunkat. Teszi ezt azért, mert nekünk kellene kézileg kiszámolgatni, hogy az egyes animáció lépések a kezdeti időpillanattól milyen távolságra vannak. Éppen ezen probléma kiküszöbölésére készítettem egy nagyon egyszerű, ám annál hasznosabb animation queue megoldást.
Lássuk a kódot:
var queue = {
delay: 0,
callbacks: [],
add: function (callback, duration) {
this.callbacks.push({
duration: duration,
callback: callback
});
},
start: function () {
var length = this.callbacks.length;
for (var i = 0; i < length; i++) {
setTimeout("eval(" + this.callbacks[i].callback + ");", this.delay);
this.delay += this.callbacks[i].duration;
}
}
}
Semmi különöset nem csinál, csupán annyit, hogy helyettünk végzi a setTimeout()
-nak megadandó ezredmásodperc értékek kiszámítását. Ezt úgy tudja megtenni, hogy minden egyes animáció lépéshez megadjuk, hogy mennyi ideig fog tartani.
Valószínűleg nem a legszebb JavaScript kód, de amire szükség volt a feladat során, arra éppen megfelelőnek bizonyult.
■
Animált gif?
GIF
-et használsz, miért nem használtál animáltGIF
-et? Annak is pontosan be lehet állítani, mennyi milliszekundumig legyen az aktuális kép megjelenítve, majd továbblép a következőre, és ha az animáció végére ért, akkor indulhat az egész előről. Ha mondjuk jobb átlátszóság kezelés kellett volna, ésPNG
-t használsz, akkor jobban megértettem volna, miért is használsz JavaScript-et az animációra. Vagy ha az animáció képkockái között nem lineáris a váltás, hanem mondjuk ugrálni kell az animációban, akkor is megérteném. De az animált GIF kisebb lenne, mint egy sprite, ráadásul JavaScript nélkül is működik, valamint a böngésző natívan kezeli.Re
Az egész egyébként azért JavaScript alapokon nyugszik, mert a koncepció egy vizuálisan dinamikusan változó betéteket tartalmazó honlap, de lehetőség szerint Flash nélkül.
Mit értesz az alatt, hogy: „Vagy ha az animáció képkockái között nem lineáris a váltás, hanem mondjuk ugrálni kell az animációban, akkor is megérteném.”?
A logo animálása csak egy felhasználási példa, ami ihlette az animation queue-t. Mivel a jQuery és úgy egyébként a JavaScript nincsen felkészítve ilyen jellegű használatra, azt hiszem, hogy jó szolgálatot tehát másnak is a cucc.
Javascript animációval már
A problémák ott kezdődnek, ha egy folytonos mozgást akarok, pl képernyő bal oldaláról egy piros pötty mozgatása a jobb oldalra. A pöttyöt képtelenség folyamatosnak ható mozgásra bírni, időnként ugrál (javascript garbage collection esetén többnyire)
setTimeout, setInterval, vagy az újabb RequestAnimationFrame, mindnél megvan ez a probléma.
Hiába próbáltam a két frame közötti eltelt időt vizsgálni és azzal arányossan növelni egy frame alatt megtett távot, a javascript által visszaadott idő nem pontos.
Direkt játék készítésre készült frameworkökkel csinált demókat is néztem, mindegyiknél észre lehet venni a kis beakadásokat, ha folyamatos mozgás van.
Próbáltátok már ilyesmire használni az animációt? Tudtok valami megoldást esetleg, ami elkerülte a figyelmemet? Hmm, lehet fórum témát kellene csinálnom belőle.
Én ezt néztem tegnap, elég
Amúgy HTML5-nek nem pont erre kellett volna megoldást kínálnia?
Re
Jelen esetben a lényeg a flash kiváltása volt. Ahhoz nem értek, ehhez pedig annyira igen, hogy a feladatot meg tudjam oldani. Valamint lesz több olyan anim az oldalon, amihez feleslegesnek éreztem a Flash használatát, ha már egyszer úgyis csak minimális, ám annál látványosabb megoldások lesznek használva.
a flash sem sokkal jobb
flash
1, akik flash alkalmazásokat
2, a flash fejlesztői környezet rendkívül erőforrásigényes, gyors gépet igényel, ha nem akarod a fél életedet várakozással tölteni, emiatt a fejlesztők nem szoktak törődni az optimalizálással (náluk jól megy minden)
Ebben a formában nem igaz
A videó lejátszása Flash alatt viszont más tészta, mivel az nem a Flash képkocka metódusa alapján történik normálesetben (bár a kettő szinkronizációja megoldható, csak akkor lehet még darabosabb lesz a videó lejátszása).
Emlékszem, mikor a 700Mhz-es Pentium 3-ason 3D-t szimuláltam háromszögek torzításával és gradiens színezéssel, a gép majd meghalt, de nem tudta lejátszani a mozit 25 képkockánál gyorsabban, hiába állítottam be 50fps-t. Ugyanez a mozi egy akkor viszonylag korszerű 400Mhz-es iMac-en 15fps-sel futott :).
Tanulság: ha valaki intenzívebb kódot akar futtatni Flash-ben (vagy JS-ben), mint amire a gép képes, akkor előfordulhat beszaggatás.
eval minek?
szerintem az eval teljesen fölösleges:
setTimeout(this.callbacks[i].callback, this.delay);
Re
Nem annyira felesleges, mint
Ez így nem igazán "queue",
A másik probléma, hogy a this javascriptben meglehetősen törékeny:
Ez mi ez a Deferred? Azt
Kíváncsi vagyok, igazam van-e
Szerintem egy olyan késleltető mechanizmus, ami pl. alkalmas rá, hogy több függvényt indítson szorosan egymás után. (gyakorlatilag egy egyetlen job futtatására alkalmas queue – VMS-ből tudnék erre jó példát :) )
Ez a deferred ránézésre sima
Lehet. Én csak a nevéből és
kötekedés
meg nem is animation queue, hanem callback queue. :/
Re
Ha semmi mást nem értem el a publikálással csak annyit, hogy a téma kicsit felszínre került -- mármint a JavaScript queue (jellegű) megoldások --, akkor már megérte...
nem is ezzel van a gond
(nemtom lehet-e szerkeszteni kikerülés előtt)
na mindegy, fel ne vegyétek, kötekedős napom van :D :D
Re
Tehetjük magasabbra a
Vagy megjelentethetjük a szerző szándéka szerint, és a közösségre hagyjuk, hogy rámutasson az esetleges hibákra.
Hidd el, láttam az evalt.
timeline.js