Progressbar setInterval Exaktheit der Zeitmessung


Jofre

Erfahrenes Mitglied
#1
Güß Euch miteinander,


ich möchte eine Progressbar haben, die eine verbleibende Zeit anzeigt.

Ich habe eine kleine Funktion, die das im Prinzip macht. Sie ist aber ungenau mit der Zeit.
Code:
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" width="500" height="600"></canvas>

<script>

var canv = document.getElementById("canvas");
var ctx = canv.getContext("2d");

  function progMinus(x,y,w,h,zeit,iz){
    //x, y , w, h Eingangsgrößen für das Rechteck Progressbar
    // zeit gibt an wieviel Sekunden die Progressbar aktiv ist
   // iz Aufruf setInterval

    var ist =w;
    zeit=zeit*1000;
    var progInterval = setInterval (function() {
    
    ist=ist-(w/zeit)*iz;   
    ctx.fillStyle = "black";
    ctx.clearRect(x,y,w,h);   
    ctx.strokeRect(x,y,w,h);   
    ctx.fillRect(x,y,ist,h);

    if( ist<=0 ) clearInterval(progInterval);
    }, iz);
    
  }
 
 progMinus(50,50,200,10,4,10);

</script>

</body>
</html>

Ich möchte, dass in möglichst vielen Schritten (iz=10 gesetzt,Fließeffekt) in diesem Beispiel das ausgefüllte Rechteck von 200 px Länge in 4 Sekunden auf 0 zurückgesetzt wird.

Das Ergebnis ist ungenau. Liegt es an meinem Ansatz oder habe ich bei der Berechnung des Rest Rechtecks einen Fehler

GzG

Joachim
 

Sempervivum

Erfahrenes Mitglied
#2
Wie hast Du denn heraus gefunden, dass es ungenau ist? Bei 4 sec kann man mit einer Stoppuhr doch kaum etwas messen. Es sei denn, die Abweichung ist so drastisch, dass sie ins Auge springt.
 
#3
Bei mir gibt es zwar keinen Fehler für
var ist =w;
aber ansonsten läuft es doch so, wie ich es erwarten würde.
Was meinst du mit "Das Ergebnis ist ungenau. " ?

edit: Huch, das mit "var ist =w;" ist ja gar kein Kommentar. Also alles gut; sah nur seltsam aus.
 
#5
Beim ersten Aufruf von deinem Script, @basti1012, hatte ich 4402 Millisekunden.
Beim zweiten 4241 Millisekunden.
Beim dritten 4271 Millisekunden.
Beim vierten 4181 Millisekunden.

Es sollte aber wohl GENAU 4000 sein; das ist wohl mit ungenau gemeint (?).
 

Jofre

Erfahrenes Mitglied
#6
Ich habe mit der Stopuhr meines Handy's gemessen. Ich habe jetzt gerade mit zeit = 20 getestet. Das Handy meldete 30 Sekunden statt 20. Zeit = 40 brauchte lt. Hany 61 Sekunden.
 

basti1012

Erfahrenes Mitglied
#7
Mit der Stopuhr des Handys wirst du das nie genau hinbekommen, gerade bei 4 Sekunden.Du weißt ja nie genau wenn du start drücken mußt und nie genau wann stop.Bei einen Start Button des Scriptes kommst du da vieleicht schon etwas genauer dran.
So startet das Script ja erst wenn es geladen ist und das kannst du mit dein Handy nicht genau erfassen.

Hier mal mit Startbutton, da kannst du sehen das es nah an die 4000 dran kommt
https://codepen.io/basti1012/pen/ExYZGZq?editors=1000
 
Zuletzt bearbeitet:

Sempervivum

Erfahrenes Mitglied
#9
Mit der letzten Version von Bastis Skript passt es bei mir bis auf wenige Millisekunden. Vermutlich ist dein Rechner nicht der schnellste. Ein 10-Millisekunden-Intervall ist aber auch sehr kurz und eine Herausforderung für den Rechner. 40 würden eine Framerate von 25 fps ergeben und auch ausreichen. Oder am besten auf requestAnimationFrame umstellen.
 

Sempervivum

Erfahrenes Mitglied
#11
Mit requestAnimationFrame könnte es so aussehen:
Code:
<!DOCTYPE html>
<html>

<body>
    <input type="button" id="start" value="start">
    <div id="clock"></div>
    <canvas id="canvas" width="500" height="600"></canvas>
    <script>
        var x = 50, y = 50, w = 200, h = 10;
        var total = 4000;
        var vstart;
        var canv = document.getElementById("canvas");
        var ctx = canv.getContext("2d");
        function doIt() {
            // die vergangene Zeit;
            var gone = Date.now() - vstart;
            document.getElementById('clock').innerHTML = gone + ' Millisekunden';
            // die verbleibende Zeit
            var remaining = total - gone;
            // die Breite des Balkens
            var ist = remaining / total * w;
            // Progressbar zeichnen
            ctx.fillStyle = "lightblue";
            ctx.strokeStyle = "black";
            ctx.strokeWidth = 2;
            ctx.clearRect(x, y, w, h);
            ctx.strokeRect(x, y, w, h);
            ctx.fillRect(x, y, ist, h);
            // wenn die verbleibende Zeit groesser als 0 ist,
            // erneuten Aufruf der Funktion doIt veranlassen
            if (remaining > 0) requestAnimationFrame(doIt);
        }
        lo = document.getElementById('start');
        lo.addEventListener('click', function () {
            vstart = Date.now();
            doIt();
        }); 
    </script>
</body>

</html>
 

basti1012

Erfahrenes Mitglied
#12
Ja(y) Mit requestAnimationFrame läuft es bei mir auch besser, die Ergebnisse sind Konstanter und es werden auch wenniger recourcen gebraucht. Das merkr ich vor allem bei meinen Laptop de ist ca 10 Jahre alt und nicht mehr der schnellste..

Ich weiß gar nicht mehr genau wie das wahr , aber wahr ein fps von 60 oder mehr gar nicht mehr möglich oder wie wahr das ?
60fps sind ca 17 Millisekunden ?
Also währe ein setInterval von 10ms ja sowieso kaum möglich ,was die großen unterschiede erklären die oben noch rausgekommen sind.

Weiß das einer von euch noch wie das genau wahr ? Konnte bis jetzt noch nix genaues finden obwoh ich das mal irgend wo im Netz gefunden hatte
 
#13
Also ich hatte bei meiner letzten Anfrage ein github-Projekt (es war eines von diesen; welches weiss ich leider nicht mehr) zugrunde, das auch requestAnimationFrame einsetzt und auch die Framerate ausgeben konnte. Da waren es immer ca. 75,03 fps. Und das bei bis zu 1.500 bewegten Objekten (weiter hatte ich noch nicht getestet).

edit: Irrtum. Das Original hatte setTimeout. Das requestAnmationFrame hatte ich über die Suche nach setInterval gefunden und eingebaut.

Bei den Werten habe ich mich dann allerdings gefragt, ob das überhaupt noch stimmen kann, weil dieser Rechner nun wirklich betagt ist (CPU-Z sagt dazu:

cpuz-klein-20190824.png .

Allerdings war mit meiner Skepsis an der angezeigten Framerate auch das weitere Interesse verflogen, weil es ja letztlich auf "läuft" oder "läuft nicht" hinausläuft :)
 
Zuletzt bearbeitet:

Jofre

Erfahrenes Mitglied
#14
Sehr schön.

ich möchte diese Progressbar in diversen Anwendungen nutzen.
Bei meinem Ansatz hatte ich alle Variablen in der Parameterleiste. So kann ich die Funktion zentral speichern und rufe sie in den einzelnen Anwendungen lediglich mit dem Funktionsaufruf auf ( Siehe oben bei meinem Ansatz.)

Soweit ich das mit meinen eingeschränkten Wissen sehe ist das bei dem Ansatz von Sempervivum nicht möglich. Hier muss ich dann jedesmal die einzelnen Variablen neu definieren . Ich kann keine "umhüllende" Funktion dafür nutzen. Ich habes es jedenfalls nicht geschafft.
 

Sempervivum

Erfahrenes Mitglied
#15
Doch, das ist kein Problem:
Code:
        function startTimer(x, y, w, h, total) {
            var vstart = Date.now();
            var ctx = document.getElementById("canvas").getContext("2d");
            function doIt() {
                // die vergangene Zeit;
                var gone = Date.now() - vstart;
                document.getElementById('clock').innerHTML = gone + ' Millisekunden';
                // die verbleibende Zeit
                var remaining = total - gone;
                // die Breite des Balkens
                var ist = remaining / total * w;
                // Progressbar zeichnen
                ctx.fillStyle = "lightblue";
                ctx.strokeStyle = "black";
                ctx.strokeWidth = 2;
                ctx.clearRect(x, y, w, h);
                ctx.fillRect(x, y, ist, h);
                ctx.strokeRect(x, y, w, h);
                // wenn die verbleibende Zeit groesser als 0 ist:
                // erneuten Aufruf der Funktion doIt veranlassen
                if (remaining > 0) requestAnimationFrame(doIt);
            }
            doIt();
        }
        lo = document.getElementById('start');
        lo.addEventListener('click', function () {
            startTimer(50, 50, 200, 20, 4000);
        });