Jump to content
php.lv forumi

Plūstošas animācijas


Lynx

Recommended Posts

Pašlaik esmu sastapies ar nelielu problēmu, ka dažādas animācijas pēc ilgākas browsera stāvēšanas vaļā sāk lagot(notiek animācija plūstoši pussekundi, talāk neliela pauze un tad atkal aiziet plūstoši, līdz nopauzē atkal).

Un te es sāku domāt variantus kā varētu šo lietu atrisināt pašreizējais variants izmanto šādu setTimeut metodi.

var Interface { 
unrollEle : function(id, max) {

if(!max)
return;
var ele = document.getElementById(id); 
var eleH = parseInt(ele.style.height); 

if(eleH < max) {
ele.style.height = eleH + 1 + 'px'; setTimeout("Interface.unrollEle('"+id+"',"+max+");",10);
}
}

Pirmā ideja optimizācijai bija nemeklēt visu laiku to objektu(nomainīju attiecīgas rindiņas uz šādu variantu):

var ele  typeof id == 'object' ? id : document.getElementById(id); 
setTimeout("Interface.unrollEle("+ele+","+max+");",10);

Tas viss beidzās ar firebug izmestu erroru:

missing ] after element list

[break on this error] Interface.unrollEle([object HTMLDivElement]);

 

Meklēju googlē un vienīgais atrisinājums, kas tika dots bija izmantot manu pirmo variantu :D Vai tomēr ir kāds triks, kā padot elementu caur setTimeout?

 

Tālāk paskatījos, kā citi risina šīs problēmas. script.aculo.us izskatās, ka izmanto time based loopu. Man parasts loops iziet tik ātri ka nav iespējams pat īsti saskatīt animāciju. Tad rodas jautājums kā viņi ir īsti panākuši, ka piemēram tieši vienā sekundē izpildās visa animācija? Parasts loops ar ifu, kas salīdzina mikrosekundes? Izklausās pārāk vienkārši, jo te izskatās, ka tiek apreiķinātas visas animācijas:

 loop: function() {
var timePos = new Date().getTime();
for(var i=0, len=this.effects.length;i<len;i++) 
  this.effects[i] && this.effects[i].loop(timePos);
 }

Un šeit izpildītas:

 loop: function(timePos) {
if (timePos >= this.startOn) {
  if (timePos >= this.finishOn) {
	this.render(1.0);
	this.cancel();
	this.event('beforeFinish');
	if (this.finish) this.finish(); 
	this.event('afterFinish');
	return;  
  }
  var pos   = (timePos - this.startOn) / this.totalTime,
	  frame = (pos * this.totalFrames).round();
  if (frame > this.currentFrame) {
	this.render(pos);
	this.currentFrame = frame;
  }
}
 }

 

Citi varianti šadu te paužu novēršanai?

Link to comment
Share on other sites

Nu time based loopā koordināes nav jāmaina par noteiktu skaitli, bet gan atkarībā no tā cik laiks ir pagājis kopš iepriekšējās reizes.

Vienkāršakajā gadījumā - Eilera integrēšanas metode: s = s0 + v*t.

s0 - patreizējā koordināte

v - vēlamais ātrums pikseļos/sekundē

t - pagājušais laiks kopš iepriekšējā izsaukuma sekundēs

s - jaunā pozīcija.

 

Krutākā gadījumā (lielāka precizitāte) var izmantot augstākas kārtas integrēšanu - Runge-Kutta metodi, piemēram. Bet diez vai tas vienkāršām kustībām būs nepieciešams.

 

Par to firebug izmesto kļūdu - vai tik problēma nav tā ka tu saskaiti stringu ar objektu: setTimeout("Interface.unrollEle('"+id+"', "...);

id tur tak ir objekts. Kāds ir rezultāts, kad tu saskati objektu ar strinu? Parasti šāds te: "[object HTMLDivElement]".

Un tagad tu šim ele stringam mēģini ņemt style atribūtu.

Tā, ka debugot tev vajag iemācīties kārtīgāk :) Debugo pa soļiem, pārbaudi lokālo mainīgo vērtības, ja izsaucās kļūda, utt...

 

Tev tur pareizāk būtu taisīt clousuri: setTimeout(function() { Interface.unrollEle(id, max); }, 10);

Un lai nelīkotu atmiņu IE6, tad netaisi katru reizi šo closuri, bet tikai pirmo reizi izsaucot setTimeout. Tad pieglabā šo funkciju kautkur (Interface objektā?) un nākamreiz izmanto atkal.

Link to comment
Share on other sites

O, paldies, palaidu tagad setTimeout, ka var padot objektu,

bet kā jau minēju 2ajā koda blokā - es arī teorētiski veicu tās nepieciešamās izmaiņas, lai nenotiktu objekta saskaitīšana ar stringu:

 

Izsaucam šādi(ele tiek padots bez pēdiņām, kam teorētiski vajadzētu nozīmēt, ka viņs nemeiģina typecastot): setTimeout("Interface.unrollEle("+ele+","+max+");",10);

Un pēc tam saņemot parbaudam vai ir objekts vai strings un tad arī attiecīgi rīkojamies: var ele typeof id == 'object' ? id : document.getElementById(id);

Bet kaut kas tāpat nepatika. Izmantojot tavu variantu un padodot vienkārši funkciju viss normāli.

 

Bet lagošanas problēmu tas neatrisināja. Izskatās, ka vienkārši pats setTimeout sāk bremzēt pēc ilgām sessijām.

Būs jāpameiģina Eilera integrēšanas metode loopā.

Link to comment
Share on other sites

bet kā jau minēju 2ajā koda blokā - es arī teorētiski veicu tās nepieciešamās izmaiņas, lai nenotiktu objekta saskaitīšana ar stringu:

Nē, tas gan nav tiesa. Tu pilnīgi neko nedari, lai nenotiktu objekta saskaitīšana ar stringu.

 

Izsaucam šādi(ele tiek padots bez pēdiņām, kam teorētiski vajadzētu nozīmēt, ka viņs nemeiģina typecastot): setTimeout("Interface.unrollEle("+ele+","+max+");",10);

Un pēc tam saņemot parbaudam vai ir objekts vai strings un tad arī attiecīgi rīkojamies: var ele typeof id == 'object' ? id : document.getElementById(id);

Rindiņa setTimeout("Interface.unrollEle("+ele+","+max+");",10); vienmēr pārvērtīs ele un max elementus uz stringiem. Vienmēr! Nav svarīgi kādas rindiņas ir pirms tam.

Tāpēc, ka "asdasdfg" + x izteiksmes rezultāta tips ir strings - neatkarīgi no x tipa.

 

Ja netici tas pamēģini alertu. Uzliec unrollEle funkcijas sākumā: alert(ele); alert(typeof(ele)). Redzēsi, ka tiks vispirms parādīts kautkas "[object HTMLDivElement]" un pēc tam "string" (nevis object vai kautkas tml, ja tas būtu DOM elements).

Link to comment
Share on other sites

Ah skaidrs, liels paldies, ka izskaidroji.

 

Saskāros ar interesantu problēmu tā algoritma realizācijā. Pats algoritms teorētiski strādā un ar pašreizējo ātrumu aptuveni sekundes laikā izvada vērtības ar 1px intervālu. Bet pats browseris(testēju gan tikai uz FF2) nerenderē konteinera izstiepšanu pa soļiem(bet parāda pēc loopa jau uzreiz pēdējo konteinera height):

var max = 112; 
var ele = document.getElementById(id); 
var s = parseInt(ele.style.height); 
var timeStart = new Date().getTime();
var timePos = 0; 
var s = 0; 

while(s < max) {
timePos = new Date().getTime();
s = Math.round(s + 0.1*(timePos-timeStart));
timeStart = new Date().getTime();
if(ele.style.height != s+'px') {
ele.style.height = s + 'px';
//	ele.style.display = 'none'; 
//	ele.style.display = 'block'; 
//   var n = document.createTextNode(' ');
//	ele.appendChild(n);
//	ele.removeChild(n);
//	this.draw(ele, s); 
//alert(s); 
}
}

Atkomentētie bija meiģinājumi panākt, lai FF2 tomēr pamaina arī pa soļiem izmēru. Uzraku googlē piemērums, velti pieminēt, ka nepalīdz.

Link to comment
Share on other sites

×
×
  • Create New...