Autor Zpráva
mark
Profil
zdravim, chcem naprogramovat plynuly pohyb obrazku a neviem, prečo mi nefunguje tento skript:
for (i=1; i<=10; i++)
{setTimeout("document.getElementById('div').style.top = i + 'px'", i*100);}

... pričom <div id="div"></div> mám, prejaví sa to tým, že obrázok za 100 milisekund skočí o 10px dole, a jeho pohyb nieje plynulý, ako by som chcel a netrvá 1 sekundu (100x10 milisekúnd). Neviete v čom je chyba? poraďte prosím, ďakujem....
Nox
Profil
Místo této zběsilosti použij setInterval...a plynulé to není samozřejmě když máš tak dlouhý interval 100ms a a tak velký posun 10px
mark
Profil
Posun som nastavil na 1 px, skúsil som seInterval, windows.setInterval a nefunguje to, zaujívamé je ale to, že keď to nahrubo všetko vypíšem:
setTimeout("document.getElementById('div').style.top = 1 + 'px'", 1*100);
setTimeout("document.getElementById('div').style.top = 2 + 'px'", 2*100);
setTimeout("document.getElementById('div').style.top = 3 + 'px'", 3*100);
...

a namiesto premennej "i" dosadím hodnoty, ako som uviedol v príklade, tak mi to funguje, s cyklom for nie....
DIV som vypísal nasledovne:
document.write("<div id='div' style='position: absolute; z-index: 1; top: 0px; left: 0px; width: 44px; height: 44px; background: url(img.PNG)'></div>");
mark
Profil
*window.setInterval a *setInterval
Nox
Profil
function Pohni(div,kolik,limit){ 
div.style.top=parseInt(div.style.top)-(-kolik)+"px";
if((kolik>0 && parseInt(div.style.top)>=limit) || (kolik<0 && parseInt(div.style.top)<=limit)){ clearInterval(move); }
}

move=setInterval("Pohni(document.getElementById('div'),1,100)",8);
mark
Profil
waaaaaw, ono to funguje:)) veeľmi pekne ďakujem.......:)
Nox
Profil
to jsem rád:) nemáš zač
ah01
Profil
Nox
Funguje to, ale moc pěkné to není.

1) Ono je paradoxně výhodnější použít onTimeout (viz http://ejohn.org/blog/how-javascript-timers-work/)

2) Zadávat do setInterval nebo kamkoli jinam volání funkce jako řetězec, je dost velká prasárna (omlouvám se za to slovo, neber si to osobně, je to tu vidět dost často, tak na to chci zase jednou upozornit)

3) Používat globální proměnou (move) je dost nevýhodné, můžeš hýbat jen jedním objektem v jeden čas.

Nebudu zde uvádět fungující řešení, ale jen napíšu kostru, jak je vhodné podobné úkoly řešit. Můžeš si zkusit přepsat své řešení tímto způsobem. Můžeš to brát třeba jako zdokonalování svých JS dovedností ;-)

function animace(div, speed, ... další potřebné parametry )
{
  function step()
  {
  
    jeden krok animace // např. posuň div o jeden krok
    
    if(! už je konec ? )
    {
      setTimeout(step, speed); // pokud ne, jdi za chvíli na další krok
    }
  }

  step(); // spuštění animace
}


Možná se to nezdá, ale takovýto krátký kód ukazuje mnoho důležitých vlastností JS – funkcionální programování, closure, scope.

Pro inspiraci se můžeš podívat na http://jslab.net/pub/jpw/closure.html
Nox
Profil
ah01
1) Díky, mrknu (a dalším to taky pomůže)
2) Možná máš pravdu, ikdyž bych se rád dozvěděl proč to tedy podle tebe je prasárna
3) Prostě se použije globální pole a je po problému, stejně si engine určitě vytváří nějaký identifikátor timeoutu, aby s ním mohl pracovat (navazuju v dalším odstavci)

Nestudoval jsem, ale tipoval bych že budou enginy lépe optimalizované pro jedno spuštění intervalu a pak jeho provádění,
než neustálé rušení a spouštění timeoutů, ale nečetl sem o tom, je to jen má domněnka

Já zase nejsem moc fanda rekurzivních funkcí:)

Každopádně děkuju za tvůj příspěvek

Edit:
Tak ten první článek moc nechápu, hlavně mi přijde že ten graf říká něco úplně jiného než ten článek, ale zkusím o tom ještě někdy něco pohledat

V tom druhém, je to podobné co si tu psal, ale pořád si nejsem jistý proč to dělat tímto způsobem (definovat funkci ve funkci a pak ji ještě rekurzivně opakovat) (ale neznal jsem tu syntaxi onload = ...zase něco nového)
mark
Profil
asi hodinu som študoval kód od Noxa, kým som mu celkom pochopil a upravil som si ho na mieru, aby sa mi to pohybovalo všetkými možnými smermi, s ľubovoľnými intervalmi, stanovil som si 2 limity - top a left a 2 intervaly_posunov, tiež top a left a taktiež som upravil na to aj podmienku;)
document.write("<div id='div' style='position: absolute; z-index: 1; top: 200px; left: 150px; width: 44px; height: 44px; background: url(img.PNG)'></div>");

function pohyb(div,interval_top,interval_left,limit_top,limit_left){

div.style.top=parseInt(div.style.top)+interval_top+"px";
div.style.left=parseInt(div.style.left)+interval_left+"px";
if((interval_top>0 && parseInt(div.style.top)>=limit_top) || (interval_top<0 && parseInt(div.style.top)<=limit_top) || (interval_left>0 && parseInt(div.style.left)>=limit_left) || (interval_left<0 && parseInt(div.style.left)<=limit_left)){ clearInterval(move); }
}
move=setInterval("pohyb(document.getElementById('div'),2,1,400,250)",10)

a teraz ked čítam príspevok od ah01, dostávam sa do neistoty, nechápem s Noxom, prečo by to mala byť velká prasárna? Ako kód od Noxa, tak aj ten môj upravený, mi fungujú bez problémov a posúva sa to plynule .....:)
Nox
Profil
mark
Ono funkční neznamená vždy korektní nebo nejlepší - ah01 chtěl říct (když si drze dovolím mluvit za něj:) ), že to moje funguje, ale dalo by se to udělat rozhodně lépe,
nejspíš bude mít pravdu (ikdyž důvody proč tomu tak je by mě zajímaly taky, ale to už sem psal v předchozím příspěvku)
los
Profil *
Je to nevhodné hlavne kvôli tomu, že vôbec nie je potrebné dynamicky vyhodnocovať reťazec, kvôli zavolaniu funkcie - je to zložitejšie (objekty sa musia prenášať pomocou globálnych premenných), pomalšie (pri každom zavolaní sa to musí rozparsovať), neprehľadnejšie (pri dlhších funkciách). Dá sa to prirovnať zavolaniu funkcie eval v takej situácií, kde to nie je vôbec nutné - funguje to, ale neexistuje žiaden rozumný dôvod, prečo to tak robiť.
mark
Profil
keď mňa lepší kód nenapadne, dokonca ma nenapadol ani ten, čo mi poradil Nox. :o)
Okrem toho som sa ešte chcel spýtať na jednu drobnosť. Keď mám kód:
document.write("<div style='position: relative; top: (premenna)px;'>");

, neviete, ako dosadiť do top: premennú? problém je v tom, že zápis je ohraničený ako "uvodzovkami", tak aj 'apostrofmi'. Poraďte prosím, ďakujem....
ah01
Profil
Nox
Pokusím se to více rozvést.

volba setInterval vs. setTimeout

Pokud vznikne nějaká událost (kliknutí myší, stisk klávesy nebo doběhnutí časovače), vloží se do fronty událostí, odkud si je postupně interpret JS odebírá a zpracovává je. K jejich zpracování zpravidla dojde ihned, ale může pochopitelně dojít k prodlení v případě, že ve frontě ještě budou starší nezpracované událost.

setInterval pravidelně vytváří události o uběhnutí zadaného časového intervalu. Z toho plyne, že zadaný interval určuje, jak často dochází ke vzniku události, nevypovídá ale nic o tom, kdy tyto události budou zpracovány. V krajním případě může nastat situace, že se ve frontě nahromadí třeba 3 události od setInterval, které se pak zpracují ihned za sebou, což není to, co bychom od setInterval požadovali. Šance že k tomu dojde je samozřejmě vyšší u krátkých intervalů, což je právě případ různých animací a efektů.

Při použití setTimeout k tomu dojít nemůže.

používání eval (zadávání kódu v podobě řetězce)

Používání eval, a jeho ekvivalentů, tedy new Function, setInterval a setTimeout je velké zlo (z anglického eval is evil). Psát jakýkoliv kód jako řetězec a pak ho spouštět vyhodnocením je velmi nebezpečné. Můžou tím snadno vzniknout chyby, které se velmi těžko hledají. V 99% případů to ukazuje na špatný návrh aplikace a je to zbytečné.
Místo toho řetězce můžu předat funkci, která bude zavolaná po uběhnutí času.
move = setInterval(function(){
  pohyb(document.getElementById('div'), 2, 1, 400, 250);
}, 10);

Navíc můžu takto předat i reference na jiné objekty, což by jinak nebylo možné (zmiňuje to los).
onload = function(){
  var div = document.getElementById('div');
  move = setInterval(function(){
    pohyb(div, 2, 1, 400, 250);
  }, 10);
}

Prostě se použije globální pole a je po problému
Používat globální pole není v tomto případě třeba. Je to zbytečná komplikace.

Já zase nejsem moc fanda rekurzivních funkcí
Toto v principu není rekurzivní funkce. K opětovnému zavolání step dojde až po uplynutí setTimeout.

Uvedený způsob má několik výhod:
• používá setTimeout, takže se vyhneš problémům se setInterval,
• nepotřebuješ žádnou globální proměnou, vše potřebné umístíš do fce. animace a díky closure to máš dostupné i v rámci fce step,
• díky předchozímu bodu můžeš tuto funkci volat kolikrát chceš, bez jakékoliv možnosti kolize.
ah01
Profil
mark
document.write("<div style='position: relative; top: " + premenna+ "px;'>");
los
Profil *
> V krajním případě může nastat situace, že se ve frontě nahromadí třeba 3 události od setInterval, které se pak zpracují ihned za sebou
Obsluha jedného časovača nastaveného pomocou setInterval sa nehromadí vo fronte. V prípade, že sa obsluha nestihne vykonať v danom intervale, preskočí sa.
mark
Profil
ďakujem...:)

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0