Black Friday = Pricewatch Bekijk onze selectie van de beste Black Friday-deals en voorkom een miskoop.

[js] slide effect dmv setTimeout te traag

Pagina: 1
Acties:

  • marty
  • Registratie: Augustus 2002
  • Laatst online: 27-03-2023
Ik heb een menu gemaakt wat standaard helemaal uitgeklapt is en wat na een trigger in de body-onload inklapt doordat de hoogte van iedere LI zo wordt aangepast dat alleen het root element zichtbaar is. Vervolgens kun je door op een plusje te klikken het menu weer uitklappen waarbij je het menu er uit ziet schuiven. Dit laatste effect doe ik met deze functie:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function slideOut(li, orgHeight, curHeight, maxHeight)
{
    var speed = 10;
    if (parseInt(curHeight) < parseInt(maxHeight))
    {
        curHeight += 2;
        li.style.height = curHeight+'px';
        setTimeout(function() { slideOut(li, orgHeight, curHeight, maxHeight); }, speed);
    }
    else
    {
        li.style.height = 'auto';
    }
}

li = het LI element, en maxHeight de hoogte die hij moet hebben als hij uitgeklapt is. (die andere 2 variabelen wilde ik gebruiken om speed mee aan te passen zodat het niet lineair gebeurt, maar dat doet nu niet ter zake). Wat het in feite dus doet is de hoogte van het li element weer zo aanpassen dat alle subelement zichtbaar zijn.

Opzich werkt dit goed, behalve dat het veel te traag gaat. Zelfs als ik de timeout op 0 zet, dan gaat het nog te traag. het zetten van de timeout kost kennelijk veel meer tijd dan de timeout zelf.
Als ik ipv die IF een WHILE loop maak met dezelfde conditie en die setTimeout er uit gooi, dan zie je weer niets van het effect en klapt ie voor het oog in 1x uit (ipv 'sliden'). Ik heb verder nog geprobeerd om in die while loop een vertraging in te bouwen:
- dmv wederom een setTimeout
- dmv een loopje die na een bepaald aantal miliseconde weer afbreekt
maar beide oplossingen zorgen ervoor dat er heel even niets gebeurd en het menu dan ineens in 1x uitklapt; de browser hertekent het beeld dus niet tijdens die pauzes.

Iemand bekend met dit probleem? En een idee voor een andere aanpak?

  • BtM909
  • Registratie: Juni 2000
  • Niet online

BtM909

Watch out Guys...

setTimeout heeft volgens mij een minimum waarde van 25ms - 50ms (ergens daartussen), dus al zet je hem op 1ms dan gaat het niet sneller :)

Ik dacht dat er workarounds beschikbaar waren met bijv. setInterval (sowieso handiger voor wat je aan 't doen bent ;)

Ace of Base vs Charli XCX - All That She Boom Claps (RMT) | Clean Bandit vs Galantis - I'd Rather Be You (RMT)
You've moved up on my notch-list. You have 1 notch
I have a black belt in Kung Flu.


  • marty
  • Registratie: Augustus 2002
  • Laatst online: 27-03-2023
ik zal het eens met setInterval proberen.
(sowieso handiger voor wat je aan 't doen bent ;)
ik heb setInterval niet genomen omdat het telkens maar 1x uitgevoerd moet worden. ik wil de speed namelijk ook nog wijzigen adhv hoever hij is met sliden, als het geheel eenmaal goed werkt.

  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Wat ik gemerkt heb, bijvoorbeeld ook met "fade" effecten d.m.v. opacity, is dat JavaScript zelf niet zozeer de vertraging veroorzaakt, maar de grafische capaciteiten van je videokaart/browser op een gegeven moment de beperkende factor zijn. Je merkt dan bijvoorbeeld ook dat Safari heel snel is met het verwerken van grafische effecten, dat Firefox daar dicht in de buurt zit en dat (verrassing!) Internet Explorer vaak vervelend traag is.

Je hebt dan, zoals ook al in jouw code naar voren komt, eigenlijk twee elementen die de snelheid van je effect bepalen, namelijk de vertraging tussen twee stappen (in jouw code "speed") en het totaal aantal stappen dat je gebruikt om van "uit" naar "aan" te gaan.

Stel bijvoorbeeld dat je je menu van 0 pixels hoogte naar 100 pixels hoogte wil veranderen. Als je dan 100 stappen zet, dan verander je dus per stap steeds 1 pixel. Als je daarentegen 10 stappen gebruikt, dan verander je dus per stap 10 pixels.

Theoretisch zou het dus niet moeten uitmaken of je 100 stappen zet met een vertraging van 5 milliseconde, of dat je 10 stappen zet met een vertraging van 50 milliseconde. In beide gevallen duurt de volledige transitie van 0 naar 100 immers 500 milliseconde.

Maar dan komt de grafische capaciteit van je client om de hoek kijken. Die heeft voor het grafisch weergeven van één stap (of het nou een stap van 1px of een stap van 10px is) altijd een minimale tijd nodig.

Conclusie: ga eens spelen met je speed en met de hoeveelheid pixels die je per stap verandert (nu 2px. geloof ik). Wellicht dat je een ergens een balans vindt die je menu "optisch" vloeiend uitklapt.

Is het niet zo dat een tekenfilm traditioneel 24 frames per seconde afspeelt? Je hersenen zien dat als een vloeiende beweging. 1000 milliseconde / 24 frames = ca. 40 ms. per frame. Lager zou dus niet hoeven voor een (optisch) vloeiende beweging. En waarschijnlijk kun je nog wel iets hoger terwijl beweging redelijk vloeiend blijft.

[ Voor 12% gewijzigd door gvanh op 20-08-2008 13:19 . Reden: aanvulling ]


  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 11-11 10:24

Bosmonster

*zucht*

De basis van je animatie ligt nu in de hoeveelheid pixels die je verschuift, terwijl je eigenlijk 'frames-per-seconde' als basis wil hebben. Bijvoorbeeld 20 fps is een behoorlijk vloeiende animatie, dat is een verversing van iedere 50ms. Hoeveel pixels moet je verplaatsen om die fps aan te houden?

2 pixels is dan waarschijnlijk veel te weinig.

edit: wat gvanh ook zegt dus :) Had mn scherm een beetje te lang open denk ik :P

[ Voor 10% gewijzigd door Bosmonster op 20-08-2008 13:26 ]


  • marty
  • Registratie: Augustus 2002
  • Laatst online: 27-03-2023
ik weet dat het niet aan de grafische capaciteiten ligt omdat ik het ook met een while heb gedaan (zonder timeout) en dan gaat het zo snel dat het lijkt alsof er niet eens een 'slide' effect is. de vertragende factor zit dus echt in het gebruik van die setTimeout.
zet ik een pauze in de while, dan duurt het wel langer, maar krijg ik het helaas niet voor elkaar om de browser het scherm ook te laten hertekenen en klapt ie alsnog in 1x uit.

kan setInterval pas later op de dag proberen, maar zal nog laten weten wat daar uitkomt.

  • WeeJeWel
  • Registratie: April 2007
  • Laatst online: 14-11 11:07
Ik raad je een JavaScript-framework zoals jQuery, MooTools of scriptaculous. Die hebben ongetwijfeld iets slimmere code dan een hobbyist kan maken :)

Homey — Critics are those without skills to create.


  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 11-11 10:24

Bosmonster

*zucht*

marty schreef op woensdag 20 augustus 2008 @ 15:39:
ik weet dat het niet aan de grafische capaciteiten ligt omdat ik het ook met een while heb gedaan (zonder timeout) en dan gaat het zo snel dat het lijkt alsof er niet eens een 'slide' effect is. de vertragende factor zit dus echt in het gebruik van die setTimeout.
zet ik een pauze in de while, dan duurt het wel langer, maar krijg ik het helaas niet voor elkaar om de browser het scherm ook te laten hertekenen en klapt ie alsnog in 1x uit.

kan setInterval pas later op de dag proberen, maar zal nog laten weten wat daar uitkomt.
En de suggesties die gegeven zijn heb je ook al geprobeerd? Gewoon meer pixels verplaatsen ipv proberen het sneller te doen met minder pixels?

Anders kun je net zo goed alles in 100sten van pixels gaan doen en dan een interval verwachten van 0.0001 ms ofzo...

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 15:02

crisp

Devver

Pixelated

marty schreef op woensdag 20 augustus 2008 @ 15:39:
ik weet dat het niet aan de grafische capaciteiten ligt omdat ik het ook met een while heb gedaan (zonder timeout) en dan gaat het zo snel dat het lijkt alsof er niet eens een 'slide' effect is. de vertragende factor zit dus echt in het gebruik van die setTimeout.
Er is dan ook geen slide effect; zolang de browser nog in JS executie context zit zal hij het renderen van DOM wijzigingen zoveel mogelijk uitstellen totdat de executie klaar is ;)

Intentionally left blank


  • marty
  • Registratie: Augustus 2002
  • Laatst online: 27-03-2023
Bosmonster schreef op woensdag 20 augustus 2008 @ 17:02:
[...]


En de suggesties die gegeven zijn heb je ook al geprobeerd? Gewoon meer pixels verplaatsen ipv proberen het sneller te doen met minder pixels?
Jep, heb ik geprobeerd, alleen loopt ie dan veel minder vloeiend (wat te verwachten was).
Wat ik ook geprobeerd heb is om het in een while-loop te doen met tienden of hondersten van een pixel, maar dat levert hetzelfde probleem op als met een while en een pauze: de browser wacht dan met tekenen tot hij helemaal klaar is.

Hier is een copy-paste scriptje (code is niet heel generiek :)) ter voorbeeld met wat pogingen er in:

HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
 <title>Test-Slide</title>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15">
 <script type="text/javascript">
 function slideOut(div, curHeight, maxHeight, px)
 {
    var speed = 0;
    if (parseInt(curHeight) < parseInt(maxHeight))
    {
        curHeight += px;
        div.style.height = curHeight+'px';
        setTimeout(function() { slideOut(div, curHeight, maxHeight, px); }, speed);
    }
    else
    {
        div.style.height = 'auto';
    }
 }
 function slideOutWhile(div, curHeight, maxHeight)
 {
    while (parseInt(curHeight) < parseInt(maxHeight))
    {
        curHeight += 2;
        div.style.height = curHeight+'px';
    }
    div.style.height = 'auto';
 }
 function slideOutWhilePause(div, curHeight, maxHeight)
 {
    var speed = 0;
    while (parseInt(curHeight) < parseInt(maxHeight))
    {
        curHeight += 2;
        div.style.height = curHeight+'px';
        var curDate = new Date
        var tgtTime = curDate.getTime() + 5;
        while (curDate.getTime() < tgtTime) {
            curDate = new Date;
        }
    }
    div.style.height = 'auto';
 }
 function slideIn(div, curHeight, minHeight, px)
 {
    var speed = 0;
    if (parseInt(curHeight) > parseInt(minHeight))
    {
        curHeight -= px;
        div.style.height = curHeight+'px';
        setTimeout(function() { slideIn(div, curHeight, minHeight, px); }, speed);
    }
    else
    {
        div.style.height = '20px';
    }
 }
 function slideInWhile(div, curHeight, minHeight, px)
 {
    while (parseFloat(curHeight) > parseFloat(minHeight))
    {
        curHeight -= px;
        div.style.height = curHeight+'px';
    }
    div.style.height = '20px';
 }
 </script>
</head>

<body onLoad="">


<a href="#" onclick="slideOut(document.getElementById('divje'), 20, 240, 2);">slideOut timeout 2px</a> - <a href="#" onclick="slideIn(document.getElementById('divje'), 240, 20, 2);">slideIn timeout 2px</a><br>
<a href="#" onclick="slideOut(document.getElementById('divje'), 20, 240, 10);">slideOut timeout 10px</a> - <a href="#" onclick="slideIn(document.getElementById('divje'), 240, 20, 10);">slideIn timeout 10px</a><br>
<a href="#" onclick="slideOutWhile(document.getElementById('divje'), 20, 240);">slideOut while</a> - <a href="#" onclick="slideInWhile(document.getElementById('divje'), 240, 20, 2);">slideIn while 2px</a><br>
<a href="#" onclick="slideOutWhilePause(document.getElementById('divje'), 20, 240);">slideOut while + pause</a> - <a href="#" onclick="slideInWhile(document.getElementById('divje'), 240, 20, 0.01);">slideIn while 0.01px</a><br>

<div style="height: 20px; width: 40px; border: 1px solid black; background-color: #EEE; overflow: hidden;" id="divje">
    1<br>
    2<br>
    3<br>
    4<br>
    5<br>
    6<br>
    7<br>
    8<br>
    9<br>
    10<br>
    11<br>
    12<br>
</div>

<div id="debug"></div>


</body>
</html>


Bestaan er geen andere manieren van pauzeren die wel nauwkeurig zijn en waarbij de browser wel het scherm hertekend?

Ik heb overigens ook gekeken naar hoe andere sliders dit probleem hebben opgelost, maar die werken allemaal net even anders waardoor de oplossing dus ook niet van toepassing is helaas

  • Joolee
  • Registratie: Juni 2005
  • Niet online
Ik gebruikte daar zelf altijd een motion tween class voor (http://jstween.blogspot.com/)
Deze class houd er rekening mee dat bijv. je animatie niet langer dan 2 sec mag duren en maakt dan zelf uit welke waarden daar verder voor nodig zijn.

Het is ook een erg compacte class met zeer goed aanpasbare code.

  • Blaise
  • Registratie: Juni 2001
  • Niet online
Ik zou ook voor een library gaan als het kan. Scheelt een hoop werk, en vaak zijn libraries in hoge mate geoptimaliseerd.

Meerdere timers maken een animatie ook sneller, maar pixel voor pixel verplaatsen blijft traag.

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 11-11 10:24

Bosmonster

*zucht*

Bosmonster schreef op woensdag 20 augustus 2008 @ 17:02:
[...]

Anders kun je net zo goed alles in 100sten van pixels gaan doen en dan een interval verwachten van 0.0001 ms ofzo...
marty schreef op donderdag 21 augustus 2008 @ 06:41:
[...]

Wat ik ook geprobeerd heb is om het in een while-loop te doen met tienden of hondersten van een pixel, maar dat levert hetzelfde probleem op als met een while en een pauze: de browser wacht dan met tekenen tot hij helemaal klaar is.
Dat was sarcastisch bedoeld hoor :+

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 15:02

crisp

Devver

Pixelated

De minimale timeout die browsers hanteren is 10ms, bij een verplaatsing van 220 pixels met stappen van 2 pixels duurt dat gewoon 110 x 10 = 1100 milliseconden, hetgeen ook wel ongeveer klopt: als ik een timertje laat meelopen komt die op 1180 milliseconden, dus slechts 80 milliseconden 'overhead'.

Intentionally left blank


  • gvanh
  • Registratie: April 2003
  • Laatst online: 02-12-2023

gvanh

Webdeveloper

Kun je het qua stijlen ook zo regelen dat je i.p.v. de "height" de positie ("top") van het uit te klappen menu verandert? Ik ben wel benieuwd of dat wellicht soepeler gaat.

  • --MeAngry--
  • Registratie: September 2002
  • Laatst online: 11:41

--MeAngry--

aka Qonstrukt

Ik ben hier zelf ooit ook al eens lang mee aan het prutsen geweest, en ben uiteindelijk ook op het gebruik van een FPS met setInterval uitgekomen, zoals hier ook wordt gesuggereerd.

Je kunt binnen je setInterval functie prima gebruik maken van globale variabelen waarmee je bepaalt hoe ver je bent in je uitvoer, en dan op basis daarvan bepalen wat je moet tekenen.
Ik gebruik een FPS van 50, wat voor 1 seconde dus de 20ms per frame geeft, en dat werkt cross-browser het beste is mijn bevinding. De berekeningen doe ik vervolgens op basis van tijd.

Stel je neemt een animatie, dan ga ik dus elke (1000 / 50 =) 20ms opnieuw door m'n setInterval functie heen. Echter vertrouw ik de browser standaard niet zo, en kijk ik hoeveel tijd er verstreken is tussen het moment dat ik de animatie start, en welke tijd het nu is. En op basis daarvan bepaal ik hoe ver de animatie moet zijn.
Wat ik dus eigenlijk aangeef, is dat de "maximum" FPS 50 kan zijn. Voor mij is gebleken dat dit ervoor zorgt dat de animatie in vrijwel elke browser (IE 6, Firefox, Safari, Opera...) soepel gaat.

Enkel IE 7 doet erg moeilijk bij mij. Om een of andere reden is deze grafisch erg traag.

[ Voor 4% gewijzigd door --MeAngry-- op 21-08-2008 10:19 . Reden: Ik ben nog niet wakker :P ]

Tesla Model Y RWD (2024)


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 15:02

crisp

Devver

Pixelated

de interval/timeout is ook een minimale waarde; er is dus altijd een afwijking naar boven.

Soepelere animaties bereik je eigenlijk alleen maar met meerdere intervals/timeouts, tot het punt dat je de CPU-limit bereikt :P

Intentionally left blank


  • --MeAngry--
  • Registratie: September 2002
  • Laatst online: 11:41

--MeAngry--

aka Qonstrukt

Klopt, maar dat is niet iets wat je altijd wil :P
Zo zet ik altijd een mooie slideshow in elkaar met m'n effecten klasse, maar ik denk niet dat bezoekers blij worden als deze om de 3 sec. 100% CPU trekt :+

Tis stiekem ook best verradelijk om op een snelle PC zoiets te ontwikkelen. Pak er vervolgens een oude Celeron bij en de hele site wordt onbruikbaar. Dat is niet echt gewenst. Vandaar dat ik het ook bij 1 interval houd. En animaties meestal nooit overdadig toepassen. Dan kom je vrijwel nooit in de problemen. (Hoogstens met scrollen tijdens de animatie.)

Tesla Model Y RWD (2024)


  • marty
  • Registratie: Augustus 2002
  • Laatst online: 27-03-2023
Ik snap dat het sarcastisch bedoelt was mbt de setinterval :)
Maar het bracht me wel op het idee om het met hondersten van een pixel te proberen in combinatie met een while-loop (zoals in het copy-paste dingetje te zien is). Met 2px tegelijk staat het namelijk in een fractie uitgeklapt en ik hoopte dat de while + pauze niet hertekende omdat hij het te druk met de pauze had en dat ie misschien wel zou hertekenen als ik de while alleen beperkte tot het aanpassen van de hoogte en het dan op de juiste snelheid zou krijgen door gewoon hele kleine pixels te nemen :-) Maar dat werkte dus ook niet.

Met betrekking tot de adviezen van deze strekking:
gebruik een framework
Dat kan natuurlijk wel, maar het idee leek me vrij simpel: klap een menuutje helemaal uit (werkt ie ook zonder javascript) en maak vervolgens een mooie slider door de hoogte te manipuleren. Opzich niet echt iets waar ik m'n hand voor omdraai. En als dat dan niet lukt vanwege het hiergenoemde probleem vind ik het leuker dat uit te pluizen dan gelijk maar op te geven en op een framework over te stappen. Maar, evengoed bedankt voor de suggesties.
gvanh schreef op donderdag 21 augustus 2008 @ 10:00:
Kun je het qua stijlen ook zo regelen dat je i.p.v. de "height" de positie ("top") van het uit te klappen menu verandert? Ik ben wel benieuwd of dat wellicht soepeler gaat.
hmm...ik snap niet zo goed hoe dat moet gaan werken?
Pagina: 1