Visit Mozilla.org

Przewodnik po canvas:Proste animacje

z Mozilla Developer Center, polskiego centrum programistów Mozilli.

Spis treści

UWAGA: Tłumaczenie tej strony nie zostało zakończone.
Może być ona niekompletna lub wymagać korekty.
Chcesz pomóc? | Dokończ tłumaczenie | Sprawdź ortografię | Więcej takich stron...

Odkąd używamy skryptów do kontroli elementów canvas, to w bardzo prosty sposób możemy utworzyć (interaktywne) animacje. Niestety element canvas nie był nigdy zaprojektowany w celu takiego użycia (w przeciwieństwie do technologi Flash), więc mamy nałożone pewne ograniczenia.

Prawdopodobnie największym ograniczeniem tego sposobu jest to, iż raz narysowany kształt pozostaje na elemencie canvas. Jeżeli będziemy chcieli go przemieścić to będziemy musieli przerysować zarówno ten kształt jak i wszystko co było narysowane przed nim. Dużo czasu zabierze ponowne narysowanie złożonych ramek i wydajność ściśle zależy od prędkości komputera na którym skrypt jest uruchomiony.

[edytuj] Prosta animacja - krok po kroku

Rysując ramki należy podjąć parę niezbędnych kroków.

  1. Wyczyść canvas
    Jeżeli rysowany kształt nie wypełnia w całości canvas (np. umieszczenie obrazka w tle) należy przede wszystkim wyczyścić canvas i usunąć kształty uprzednio narysowane. Najprościej robi się to za pomocą metody clearRect.
  2. Zapamiętaj stan canvas
    Jeśli zmienia się jakieś ustawienia (style, transformacje, itd.), które zmieniają stan canvas, należy zapamiętać jego stan aby zapewnić użycie oryginalnego stanu przy kolejnych próbach rysowania ramki.
  3. Narysuj animowane kształty
    Krok, w którym dokonujemy zasadniczej modyfikacji ramki.
  4. Przywróć stan canvas
    Jeśli zapamiętano stan, to przed narysowaniem aktualnej ramki należy ten stan przywrócić.

[edytuj] Kontrolowanie animacji

Kształty są rysowane w elemencie canvas przez użycie metod canvas lub wywołanie funkcji użytkownika. W normalnych warunkach zobaczymy tylko rezultaty widniejące w elemencie canvas po zakończeniu wykonywania skryptu. Przykładowo nie jest możliwa animacja z obrębu pętli for.

Potrzebujemy sposobu do wykonania naszych funkcji rysujących przez pewien okres czasu. Mamy dwa podobne sposoby na kontrolę animacji. Pierwszym są funkcje setInterval i setTimeout, które mogą być użyte do wywoływania określonej funkcji przez pewien ustalony okres czau.

setInterval('animateShape()',500);
setTimeout('animateShape()',500);

Jeżeli nie potrzebujemy żadnej interakcji z użytkownikiem najlepiej użyć funkcji setInterval, która wciąż na nowo wykonuje dostarczony kod. W przykładzie powyżej funkcja animateShape jest wykonywana co 500 milisekund (pół sekundy). Funkcja setTimeout wykonywana jest tylko raz po ustawionej ilości czasu.

Drugą metodą, którą możemy użyć do kontroli animacji są dane wejściowe użytkownika. Jeżeli chcielibyśmy stworzyć grę moglibyśmy użyć zdarzeń klawiatury lub myszki do kontrolowania animacji. Przez ustawienie eventListeners wychwytujemy jakąś interakcję użytkownika i wykonujemy funkcje naszej animacji.

W przykładzie poniżej użyliśmy pierwszej metody do kontroli animacji. Na dole tej strony jest trochę odnośników do przykładów używających drugiego sposobu.

[edytuj] Przykład animacji 1

W tym przykładzie tworzymy animację mini symulacji naszego układu słonecznego.
var sun = new Image();
var moon = new Image();
var earth = new Image();
function init(){
  sun.src = 'images/sun.png';
  moon.src = 'images/moon.png';
  earth.src = 'images/earth.png';
  setInterval('draw()',100);
}

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');

  ctx.globalCompositeOperation = 'destination-over';
  ctx.clearRect(0,0,300,300); // czyści canvas

  ctx.fillStyle = 'rgba(0,0,0,0.4)';
  ctx.strokeStyle = 'rgba(0,153,255,0.4)';
  ctx.save();
  ctx.translate(150,150);

  // Ziemia
  var time = new Date();
  ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
  ctx.translate(105,0);
  ctx.fillRect(0,-12,50,24); // Cień
  ctx.drawImage(earth,-12,-12);

  // Księżyc
  ctx.save();
  ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );
  ctx.translate(0,28.5);
  ctx.drawImage(moon,-3.5,-3.5);
  ctx.restore();

  ctx.restore();
  
  ctx.beginPath();
  ctx.arc(150,150,105,0,Math.PI*2,false); // orbita Ziemi
  ctx.stroke();
 
  ctx.drawImage(sun,0,0,300,300);
}

[edytuj] Przykład animacji 2

function init(){
  clock();
  setInterval('clock()',1000);
}
function clock(){
  var now = new Date();
  var ctx = document.getElementById('canvas').getContext('2d');
  ctx.save();
  ctx.clearRect(0,0,150,150);
  ctx.translate(75,75);
  ctx.scale(0.4,0.4);
  ctx.rotate(-Math.PI/2);
  ctx.strokeStyle = "black";
  ctx.fillStyle = "white";
  ctx.lineWidth = 8;
  ctx.lineCap = "round";

  // oznaczenie godziny 
  ctx.save();
  ctx.beginPath();
  for (i=0;i<12;i++){
    ctx.rotate(Math.PI/6);
    ctx.moveTo(100,0);
    ctx.lineTo(120,0);
  }
  ctx.stroke();
  ctx.restore();

  // oznaczenie minut 
  ctx.save();
  ctx.lineWidth = 5;
  ctx.beginPath();
  for (i=0;i<60;i++){
    if (i%5!=0) {
      ctx.moveTo(117,0);
      ctx.lineTo(120,0);
    }
    ctx.rotate(Math.PI/30);
  }
  ctx.stroke();
  ctx.restore();
  
  var sec = now.getSeconds();
  var min = now.getMinutes();
  var hr  = now.getHours();
  hr = hr>=12 ? hr-12 : hr;

  ctx.fillStyle = "black";

  // wypisuje godzinę 
  ctx.save();
  ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec )
  ctx.lineWidth = 14;
  ctx.beginPath();
  ctx.moveTo(-20,0);
  ctx.lineTo(80,0);
  ctx.stroke();
  ctx.restore();

  // wypisuje minuty 
  ctx.save();
  ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec )
  ctx.lineWidth = 10;
  ctx.beginPath();
  ctx.moveTo(-28,0);
  ctx.lineTo(112,0);
  ctx.stroke();
  ctx.restore();
  
  // wypisuje sekundy 
  ctx.save();
  ctx.rotate(sec * Math.PI/30);
  ctx.strokeStyle = "#D40000";
  ctx.fillStyle = "#D40000";
  ctx.lineWidth = 6;
  ctx.beginPath();
  ctx.moveTo(-30,0);
  ctx.lineTo(83,0);
  ctx.stroke();
  ctx.beginPath();
  ctx.arc(0,0,10,0,Math.PI*2,true);
  ctx.fill();
  ctx.beginPath();
  ctx.arc(95,0,10,0,Math.PI*2,true);
  ctx.stroke();
  ctx.fillStyle = "#555";
  ctx.arc(0,0,3,0,Math.PI*2,true);
  ctx.fill();
  ctx.restore();

  ctx.beginPath();
  ctx.lineWidth = 14;
  ctx.strokeStyle = '#325FA2';
  ctx.arc(0,0,142,0,Math.PI*2,true);
  ctx.stroke();

  ctx.restore();
}

[edytuj] Inne przykłady

  • Canvascape
    Gra przygodowa 3D (kto pierwszy strzeli).
  • Prosty RayCaster
    Dobry przykład jak robić animację używającą klawiszy do jej kontrolowania.
  • canvas adventure
    Także miły przykład, w którym używamy klawiszy klawiatury do kontrolowania.