requestAnimationFrame

Bonusmaterial: requestAnimationFrame

Das Glücksrad dreht sich, und wenn es angehalten wird, gibt das Skript den Treffer aus.

<div class="flex stopper">
   <img id="rad" src="rad.svg" width="200" height="200" />
   <img id="eck" src="eck.svg" width="40" height="40" />
</div>

<div id="lucky"></div>

<div class="flex">
   <button id="drehen">DREHEN!</button> 
   <button id="stopp" disabled="disabled">STOPP</button>
</div>

Hier sind alle Variablen unter einem Dach als einfaches JavaScript-Objekt. Das führt zu etwas mehr Schreibarbeit, dafür kollidieren die Variablen nicht mit anderen Skripten derselben Seite.

const obj = {
   on: document.querySelector("#drehen"),
   off: document.querySelector("#stopp"),
   rad: document.querySelector("#rad"),
   lucky: document.querySelector("#lucky"),
   deg: 0,
   repeater: null
}

// DREHEN
obj.on.addEventListener("click", function() {
   obj.off.removeAttribute("disabled");
   obj.on.setAttribute("disabled", "true");
   obj.repeater = requestAnimationFrame(turn);
});

// STOPP
obj.off.addEventListener("click", function() {
   cancelAnimationFrame(obj.repeater);
   obj.on.removeAttribute("disabled");
}); 

Der Klick auf DREHEN! ruft requestAnimationFrame(turn) ein erstes Mal auf, der Klick auf STOPP cancelAnimationFrame(obj.repeater). Die Buttons werden wieder im Wechsel aktiviert und deaktiviert. Die Funktion turn ist kurz und übersichtlich:

function turn() {
   obj.deg++;
   if (obj.deg > 359) obj.deg = 0;
   obj.rad.style.transform = "rotate(" + obj.deg + "deg)";
   obj.repeater = requestAnimationFrame(turn);
}

Die Funktion zählt die Variable deg um 1 hoch – die Drehung des Rads – und setzt deg zurück auf 0, wenn deg größer als 359 ist. Die CSS-Eigenschaft transform: rotate() dreht das Rad also um jeweils 1 Grad. Am Ende ruft turn requestAnimationFrame() für das nächste Grad auf.

Fehlt noch die Ausgabe der Zahl unter dem Dreieck. Das ist eine einfache case-Anweisung beim STOPP, die den aktuellen Wert von deg prüft.

Die switch-Anweisung sitzt unter dem Aufruf von cancelAnimationFrame().

switch (true) {
   case (obj.deg % 45 === 0):
      obj.lucky.textContent = "dazwischen";break;
   case (obj.deg < 45):
      obj.lucky.textContent = "5";break;
   case (obj.deg < 90):
      obj.lucky.textContent = "4";break;
   case (obj.deg < 135):
      obj.lucky.textContent = "3";break;
    case (obj.deg < 180):
      obj.lucky.textContent = "2";break;
   case (obj.deg < 225):
      obj.lucky.textContent = "1";break;
   case (obj.deg < 270):
      obj.lucky.textContent = "8";break;
   case (obj.deg < 315):
      obj.lucky.textContent = "7";break;
   case (obj.deg < 359):
      obj.lucky.textContent = "6";break;
   default: 
      console.log ("ups")
}

Statt einen Timeout mit einer Verzögerung in einer Schleife immer wieder aufzurufen, feuern die Browser ein Event, sobald das System wieder einen Frame rendern kann. Wenn die Animation in einem Hintergrund-Tab läuft, pausiert der Browser die Animation, um den Energieverbrauch zu senken.