Home > HTML5, IE > [PL] Create a #SVG analog clock in your browser #IE #HTML5

[PL] Create a #SVG analog clock in your browser #IE #HTML5

[EN] This post describes in Polish my sample project presented on HTML5 Day at Gdańsk University. To translate into English please use Google translator or Microsoft translator.

[PL] Jednym z tematów poruszanych na mojej prezentacji podczas HTML5 Day na Uniwersytecie Gdańskim był SVG, a raczej jego obsługa od strony programisty. Jako przykład utworzyłem prosty zegarek tarczowy, który wyświetlał aktualną godzinę w przeglądarce. Przykład ten funkcjonuje obecnie we wszystkich nowszych przeglądarkach internetowych (mam tu na myśli  wszystkie przeglądaki od IE9 włącznie).

Różnego rodzaju gadżety w przeglądarkach wykorzystują w chwili obecnej głównie Flash/Silverlight/ czy też w sporadycznych przypadkach Javę. Od czasu wprowadzenia przez IE obsługi SVG, można powiedzieć, że i SVG stał się kolejną metodą dodawania multimedialnych gadżetów na stronę. SVG nie jest nowością, na rynku istnieje już od kilku lat, nie będę tutaj rozpisywał się czym jest SVG i jakich narzędzi używać do jego edycji – parę linków można znaleźć na wikipedii, a także kilka ciekawych przykładów na IE Test Drive. Rozpoczniemy zabawę krok, po kroku z SVG tworząc od podstaw zegarek tarczowy. Już na wstępie napiszę, że nie będzie to piękny przykład (od strony wizualnej) – celem jest jedynie pokazanie samego kodu i sposobu tworzenia.

Zaczniemy od utworzenia zwykłego pliku HTML, w którym to zamieścimy poniższą zawartość:

<!DOCTYPE html/>
<html>
  <head>
    <title>Clock Example</title>
  </head>
<body onload="addLife()">
  <svg id="clock">
    <!-- SVG CLOCK CONTENT -->
  </svg>

  <script type="text/javascript">

    function addLife() {
      // AddLife function
    }

    function updateHands() {
      // Update hands function
    }

  </script>    
</body>
</html>

Jak widać plik składa się z jednego taga SVG oraz dwóch funkcji javascriptowych umieszczonych na dole. Teraz przystąpimy do omówienia tych trzech elementów. W tagu SVG utworzymy elementy wizualne, funkcja addLife odpowiedzialna będzie za odpalenie funkcji updateHands, która to z kolei będzie uaktualniała wskazówki zegara.

Zabawę rozpoczniemy od utworzenia tarczy zegara wraz z punktem z którego wychodzą wskazówki. Będzie to jeden duży okrąg zawierający obramowanie i jedem mały wewnątrz dużego. W tym celu zamieniamy komentarz SVG CLOCK CONTENT  poniższym kodem:

<!-- DEFS -->
<circle cx="200" cy="200" r="200" 
   fill="yellow" 
   id="myCircle" 
   stroke-width="15"
   stroke="red" />
<circle cx="200" cy="200" r="5" fill="green" />
<!-- BODY -->

W rezultacie otrzymujemy poniższy wynik

Brakuje nam jeszcze wskazówek oraz znaczników godzin. Łącznie mamy 12 znaczników w zwykłym 12 godzinnym zegarze, a także przeważnie znaczniki godziny 12,3,6, i 9 są większe od pozostałych. Z punktu widzenia obiektów wykorzystywać będziemy dwa różne znaczniki. Jeden większy i jeden mniejszy (ktoś by mógł się uprzeć, że użyjemy tylko jednego obiektu – mniejszego i większego, ale już nie utrudniajmy sobie życia). Wobec tego zdefiniujemy sobie te elementy i dodamy do zegara większe znaczniki. Zamienimy więc komentarz DEFS poniższym kodem

<defs>
 <rect width="10" height="25" id="longTick" x="195" y="30" />
 <rect width="10" height="10" id="shortTick" x="195" y="30" />
 <!-- HANDS -->
</defs>

Znacznik DEFS w SVG jest odpowiednikiem konetera obiektów, w którym definiujemy sobie wewnątrz SVG pewne obiekty, które renderowane są jedynie gdy do nich się odwołamy wewnątrz SVG. Jak widać utworzyłem dwa elementy o id longTick i shortTick będące odpowiednikiem dużego i małego znacznika. Elementy te definiujemy w górnej części zegara (parametry x i y). Teraz odwołamy się do tych elementów wewnątrz SVG. W tym celu zamieniamy komentarz BODY tymi elementami:

<use xlink:href="#longTick" />
<use xlink:href="#longTick" transform="rotate(90,200,200)" />
<use xlink:href="#longTick" transform="rotate(180,200,200)" />
<use xlink:href="#longTick" transform="rotate(270,200,200)" />
<!-- BODY -->

Jak widać odwołujemy się do naszego elementu wykorzystując znacznik use i podając nazwę elementu zdefiniowanego wewnątrz znacznika defs (xlink:href i ID elementu).  Jako, że znacznik powinien zostać wyświetlony przy godzinach 3,6 i 9 wyświetlamy nasz element wykorzystując transformację wg określonego stopnia (kolejno 90,180,270) względem środka tarczy. W rezultacie otrzymamy już tarczę z naszymi dużymi znacznikami:

Pozostało nam jeszcze wyświetlenie pozostałych znaczników i wskazówek. W tym celu w miejsce komentarza HANDS wstawiamy definicję naszych wskazówek:

<rect width="10" height="150" id="minute" x="195" y="50" />
<rect width="10" height="100" id="hour" x="195" y="100"/>
<rect width="4" height="150" id="second" x="198" y="50" fill="red"/>

Definiujemy je tak samo jak znaczniki godzin, z tą różnicą, że podajemy różnego rodzaju wielkości, szerokości i kolor wypełnienia. Następnie w miejsce komentarza BODY dodajemy parę linii wyświetlających pozostałe znaczniki godzin i nasze wskazówki.

<use xlink:href="#shortTick" transform="rotate(30,200,200)" />
<use xlink:href="#shortTick" transform="rotate(60,200,200)" />
<use xlink:href="#shortTick" transform="rotate(120,200,200)" />
<use xlink:href="#shortTick" transform="rotate(150,200,200)" />

<use xlink:href="#shortTick" transform="rotate(-30,200,200)" />
<use xlink:href="#shortTick" transform="rotate(-60,200,200)" />
<use xlink:href="#shortTick" transform="rotate(-120,200,200)" />
<use xlink:href="#shortTick" transform="rotate(-150,200,200)" />

<use xlink:href="#minute" id="minuteHand" transform="rotate(0,200,200)"  />
<use xlink:href="#hour" id="hourHand" transform="rotate(0,200,200)" />
<use xlink:href="#second" id="secondHand" transform="rotate(0,200,200)" />

W rezultacie otrzymujemy już gotową, ale jeszcze nieruchomą tarczę zegara.

Do szczęścia pozostało nam zaprogramowanie funkcji Java Scriptowych. Zaczynamy od zdefiniowania ciała funkcji addLife, które wygląda następująco.

var minuteHand;
var secondHand;
var hourHand;
function addLife() {
  var domClock = document.getElementById('clock');
  minuteHand = document.getElementById('minuteHand');
  hourHand = document.getElementById('hourHand');
  secondHand = document.getElementById('secondHand');
  setInterval('updateHands()', 1000);
}

Funkcja ta, po załadowaniu strony pobiera uchwyty do wskazówek i zapamiętuje je w zmiennej globalnej, a następnie wywołuje funkcję setInterval odpowiedzialną za cykliczne uruchamianie wskazanej funkcji. W naszym przypadku co sekundę odpalać będziemy funkcję updateHands, której zawartość wygląda następująco:

var date = new Date();
var hour = (date.getHours()) % 12;
var minute = date.getMinutes();
var second = date.getSeconds();

secondHand.transform.baseVal.getItem(0).setRotate((second / 60 * 360),200,200);
hourHand.setAttribute('transform','rotate('+(hour / 12 * 360)+',200,200)');
minuteHand.setAttribute('transform','rotate('+(minute / 60 * 360)+',200,200)');

Jak widać, funkcja ta pobiera aktualną datę, następnie zmienia kąt obrotu każdej wskazówki. Warta uwagi jest różnica pomiędzy ustawieniem wskazówki sekundy, a ustawieniem wsazówki godzinowej i minutowej. Wskazówkę sekundową ustawiamy wykorzystując do tego celu nawigację SVG DOM, a pozostałe zwykłej nawigacji DOM. Z poziomu funkcjonalnego obie metody robią to samo, jednak z poziomu kodu preferowana jest manipulacja SVG przy pomocy SVG DOM, ponieważ nie wykorzystuje ona serializacji, a jedynie ustawia parametry funkcji.

W rezultacie naszego działania otrzymujemy już w pełni działający zegar tarczowy, który wykorzystywać możemy na naszej stronie.

Nic nie stoi na przeszkodzie, aby cały kod (przy drobnych modyfikacjach) przenieść do oddzielnego pliku z rozszerzeniem SVG (wraz z obsługą JavaScriptu). Dzięki temu możemy ładować wewnątrz strony plik SVG. Co więcej dzięki możliwości skalowania możemy wyświetlać nasz zegarek w dowolnym rozmiarze, a dodając do tego style CSS możemy także w łatwy sposób upiększyć nasz zegarek.

Przykład: http://cid-e2eed297c7a63060.office.live.com/self.aspx/Publiczny/Samples/svg%20clock.zip

  1. Krzysztof Wilczek
    July 17, 2011 at 01:33

    Lepiej dużo prościej:

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: