mgr inż. Wacław Libront * Bobowa 2017-2019

ZSO Bobowa, ul. Długoszowskich 1, 38-350 Bobowa, tel: 0183514009, fax: 0183530221, email: sekretariat@zsobobowa.eu, www: zsobobowa.eu

Lekcja 18

Animacja SVG w JS

  1. tarcza
  2. wskazówki
  3. animacja
  4. płynnie

Animowany zegar w SVG

Tarcza
Zegar przygotowany w grafice wektorowej SVG będzie wyświetlał aktualny czas. Pierwszy rysunek przedstawia obiekt trzy, składający się z trzech kwadracików. Grupa trzy zostanie obrócona jeszcze trzy razy. Zwróć uwagę, że kwadraciki rysowane są w tym samym miejscu, a drugi i trzeci mają zdefiniowany dodatkowy obrót. Kołowa tarcza zegara powinna być rysowana wcześniej, aby nie zasłaniała punktów godzinowych.

<svg width="300px" height="300px">
  <!-- tarcza zegara - koło -->
  <circle cx="150" cy="150" r="135" stroke-width="12" stroke="black" fill="white"/>
  <!-- 3 punkty godzin: 0 - większy, 5 i 10 - mniejsze -->
  <g id="trzy">
    <rect x="145" y="15" width="10" height="25" />
    <rect x="145" y="15" width="10" height="15" transform="rotate(30,150,150)" />
    <rect x="145" y="15" width="10" height="15" transform="rotate(60,150,150)" />
  </g>
  <!-- 12 punktów na tarczy -->
  <use xlink:href="#trzy" />
  <use xlink:href="#trzy" transform="rotate(90,150,150)" />
  <use xlink:href="#trzy" transform="rotate(180,150,150)" />
  <use xlink:href="#trzy" transform="rotate(270,150,150)" />
  <!-- kropka na środku -->
  <circle cx="150" cy="150" r="7" stroke-width="2" stroke="black" fill="white" />
  <circle cx="150" cy="150" r="6" stroke-width="2" stroke="white" fill="black"/>
</svg>

Wskazówki
Wskazówka sekundowa jest prostokątem i przechodzi przez środek tarczy (150,150). Ma szerokość 4, więc powinna być przesunięta o 2 punkty w lewo, do punktu (148). Do każdej wskazówki dorysujemy małe kółeczko, które będzie przesuwało się wraz z nią na brzegu tarczy. Wskazówki grupujemy i nadajemy im identyfikatory: WSKsek, WSKmin, WSKgod. Wskazówki obejmujemy znacznikami: , aby nie były rysowane podczas definiowania.

 

Definicje wskazówek mogą być w dowolnym miejscu kodu, natomiast rysowane powinny być na tarczy, ale przed kropkami na środku. Wskazówki powinny być też rysowane w odpowiedniej kolejności – na samym wierzchu sekundnik. Każda wskazówka „wyposażona” została w Identyfikator, który posłuży do późniejszej obsługi animacji.

<defs>
  <g id="WSKsek">
    <rect x="148" y="30" height="145" width="4" fill="red" />
    <circle cx="150" cy="15" r="3"  fill="red" />
  </g>
  <g id="WSKmin">
    <rect x="146" y="35" height="140" width="8" fill="black" />
    <circle cx="150" cy="15" r="5" stroke-width="2" stroke="black" fill="white" />
  </g>
  <g id="WSKgod">
    <rect x="145" y="65" height="110" width="10" fill="black" />
    <circle cx="150" cy="15" r="8" stroke-width="2" stroke="black" fill="white" />
  </g>
</defs>

Animacja
Aby zegar pokazywał aktualną godzinę wykorzystamy język JavaScript. Najprostsza procedura animacyjna wykorzystuje rekurencję – w naszym przypadku wystarczy wywoływać procedurę co 1000 milisekund, czyli co 1 sekundę.

var czas;
var skok=1000;
function ANIMACJA() {

  clearTimeout(czas);
  czas=setInterval(animacja,skok);
}
animacja();

Będziemy modyfikować położenie wskazówek, dlatego potrzebne będzie utworzenie trzech zmiennych do obiektów SVG, które opisaliśmy odpowiednimi identyfikatorami. Standardowo czynimy to instrukcją dokument.getElementById, ale równie dobrze można to zrobić w prostszy sposób: var Wsek=SEK;

Następnie musimy nakazać obrót poszczególnych wskazówek o określony kąt – modyfikujemy obiekty SVG za pomocą polecenia setAttribute podając w postaci łańcuchów znakowych odpowiednie parametry.

<script>
  //zmienne do obiektów wskazówek
  var Wsek=SEK;
  var Wmin=MIN;
  var Wgod=GOD;
  //zmienne sterujące animacją
  var skok = 1000;
  var czas;
function animacja() {
  //zmienne przechowujące czas
  var date = new Date();
  var Dsek = date.getSeconds();
  var Dmin = date.getMinutes();
  var Dgod = date.getHours() % 12;
  //obracanie obiektów wskazówek
  Wsek.setAttribute('transform','rotate('+(Dsek * 6)+',150,150)');
  Wmin.setAttribute('transform','rotate('+(Dmin * 6)+',150,150)');
  Wgod.setAttribute('transform','rotate('+(Dgod * 30)+',150,150)');
  //rekurencyjne wywołanie kolejnych animacji  
  clearTimeout(czas);
  czas = setTimeout(animacja, skok); 
}
animacja();
</script>

Płynne przesuwanie wskazówek
Wskazówka przesuwa się skokowo – jeśli chcemy płynnej zmiany musimy wywoływać animację częściej, na przykład co 1 milisekundę. Konieczne będzie

var skok=10;
//... w funkcji animacja
var Dmil = date.getMilliseconds();
//sekundowa zmienia się co 10 milisekund
Wsek.setAttribute('transform','rotate('+(Dsek * 6 + Dmil * 6/1000)+',150,150)');
//minutowa zmienia się co 1 sekundę
Wmin.setAttribute('transform','rotate('+(Dmin * 6 + Dsek * 6/60)+',150,150)');
//godzinowa zmienia się co 1 minutę
Wgod.setAttribute('transform','rotate('+(Dgod * 30 + Dmin * 6/12)+',150,150)');