svg

141
AKADEMIA GÓRNICZO-HUTNICZA Wydział Elektrotechniki Automatyki Informatyki i Elektroniki Katedra Telekomunikacji PRACA MAGISTERSKA Analiza możliwości wykorzystania grafiki wektorowej SVG do projektowania aplikacji internetowych Paweł Król Promotor: dr inż. Jacek Romanowski KRAKÓW 2007

Upload: pawel-krol

Post on 08-Aug-2015

833 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: SVG

AKADEMIA GÓRNICZO-HUTNICZA

Wydział Elektrotechniki Automatyki Informatyki i Elektroniki

Katedra Telekomunikacji

PRACA MAGISTERSKA

Analiza możliwości wykorzystania grafiki

wektorowej SVG do projektowania aplikacji

internetowych

Paweł Król

Promotor: dr inż. Jacek Romanowski

KRAKÓW 2007

Page 2: SVG

Spis Treści

1. Wstęp...........................................................................................................5

2. Wprowadzenie do standardu SVG...................................................................7

2.1. Podstawowe informacje............................................................................7

2.1.1. Co to jest SVG?.................................................................................7

2.1.2. Czy potrzebujemy kolejnego nowego standardu?.................................8

2.1.3. Historia SVG jako rekomendacji W3C..................................................9

2.1.4. Aktualny stan prac standaryzacyjnych...............................................11

2.2. Rozmaitości...........................................................................................12

2.2.1. Ogólny przegląd standardu...............................................................12

2.2.2. Metody umieszczania grafiki SVG na stronach WWW..........................15

2.2.3. SVG dla urządzeń o niewielkiej mocy obliczeniowej............................16

2.3. Podsumowanie......................................................................................22

3. Szczegółowy przegląd możliwości SVG...........................................................23

3.1. Podstawowe składniki rekomendacji........................................................23

3.1.1. Przedstawienie treści pierwszych rozdziałów......................................24

3.1.2. Zagadnienia renderowania grafiki w SVG...........................................24

3.1.3. Typy danych....................................................................................25

3.1.4. Struktura dokumentu SVG................................................................25

3.1.5. Style...............................................................................................26

3.1.5. Obszar rysunku................................................................................27

3.1.6. Skalowanie w praktyce.....................................................................28

3.1.7. Jednostki wielkości...........................................................................29

3.1.8. Przedstawienie treści kolejnych rozdziałów........................................29

3.1.9. Metadane i kompatybilność wstecz....................................................29

3.1.10. Rozszerzalność języka SVG.............................................................31

3.1.11. Podsumowanie podstawowych informacji........................................31

3.2. Najważniejsze możliwości SVG................................................................32

- 2/141 -

Page 3: SVG

3.2.1. Modelowanie kształtów za pomocą ścieżek........................................32

3.2.2. Wykreślanie figur za pomocą kształtów.............................................34

3.2.3. Wprowadzanie tekstu na rysunku SVG..............................................37

3.2.4. Wypełnienia oraz kontury obiektów...................................................40

3.2.5. Wypełnianie figur za pomocą gradientów i wzorów............................41

3.2.6. Podsumowanie najważniejszych możliwości.......................................46

3.3. Zaawansowane właściwości SVG.............................................................46

3.3.1. Maski oraz ścieżki maskujące............................................................46

3.3.2. Efekty graficzne...............................................................................49

3.3.3. Interaktywność................................................................................53

3.3.4. Hiperłącza.......................................................................................54

3.3.5. Możliwości zastosowania języków skryptowych..................................54

3.3.6. Animacje.........................................................................................57

3.4. Podsumowanie.......................................................................................59

3.4.1. SVG a XML......................................................................................60

3.4.2. Kierunki rozwoju SVG: wersje 1.2 i 2.0..............................................62

4. Praktyczna realizacja przykładowych aplikacji.................................................66

4.1. Generator wykresów statystycznych........................................................66

4.1.1. Zastosowanie aplikacji......................................................................67

4.1.2. Struktura dokumentu SVG................................................................67

4.1.3. Moduł Perla do generowania wykresów.............................................69

4.1.4. Czy SVG jest koniecznością?.............................................................74

4.1.5. Wykres jako skrypt CGI....................................................................76

4.1.6. Możliwości rozbudowy......................................................................77

4.2. Generator wykresów pogodowych...........................................................78

4.2.1. Zalety wykorzystania grafiki wektorowej SVG.....................................79

4.2.2. Format przechowywania danych pogodowych....................................80

4.2.3. Proces transformacji danych arkuszem stylu XSLT..............................84

4.2.4. Przykładowe wykresy.......................................................................93

- 3/141 -

Page 4: SVG

4.2.5. Ocena wykonania aplikacji..............................................................101

4.3. Podsumowanie.....................................................................................102

5. Zakończenie...............................................................................................105

6. Dodatki: kody źródłowe..............................................................................108

6.1. Generator wykresów statystycznych......................................................108

6.1.1. Moduł (klasa) ChartSVG do generowania wykresów.........................108

6.1.2. Porównanie liczby ludności państw świata.......................................114

6.1.3. Porównanie wyników wyborów parlamentarnych..............................117

6.2. Generator wykresów pogodowych.........................................................120

6.2.1. Dane XML do wykresu temperatury.................................................121

6.2.2. Dane XML do wykresu opadów.......................................................124

6.2.3. Arkusz transformacji XSLT..............................................................129

7. Bibliografia.................................................................................................137

8. Słownik trudniejszych pojęć........................................................................138

- 4/141 -

Page 5: SVG

1. Wstęp

Tematem niniejszej pracy dyplomowej jest analiza możliwości wykorzystania grafiki

wektorowej SVG do projektowania aplikacji internetowych. Ponieważ obecnie

trudno wyobrazić sobie funkcjonowanie jakiejkolwiek aplikacji w oderwaniu od

globalnej sieci (brak współpracy z Internetem praktycznie dyskwalifikuje dany

program z powszechnego użycia), w treści swojej pracy szczególny nacisk

zdecydowałem się położyć na staranną analizę samego standardu SVG. Został on

zresztą zaprojektowany jako standard sieciowy, więc niejako sam w sobie zawiera

gotowe już mechanizmy predestynujące go do użycia w środowisku WWW.

Specjalistycznej literatury dedykowanej SVG w języku polskim brak, w związku z

czym podstawą wiedzy, na której oparłem wszystkie swoje informacje na temat

analizowanego standardu, stały się rekomendacje publikowane przez organizację

World Wide Web Consortium. Są one równocześnie najbardziej wiarygodnym

źródłem wiedzy na temat aktualnie obowiązujących w sieci Internet standardów, a

sama rekomendacja SVG została opracowana przez jedną z grup roboczych

wywodzących się z tego właśnie konsorcjum.

Wśród głównych celów, jakie postawiłem sobie podejmując ten właśnie temat

pracy dyplomowej, należy przede wszystkim wymienić dwa następujące:

Chęć gruntownego poznania jednego z najciekawszych obowiązujących

obecnie w sieci standardów grafiki wektorowej, dokładne zapoznanie się z

jego możliwościami od strony technicznej oraz analiza konsekwencji, jakie

niesie ze sobą jego zastosowanie w projektowaniu nowych aplikacji

Realizacja praktycznych przykładów wykorzystujących możliwości SVG,

adaptacja własnych pomysłów na potrzeby wykonania konkretnych zadań,

wreszcie lepsze zrozumienie istoty tworzenia grafiki wektorowej w oparciu o

- 5/141 -

Page 6: SVG

analizowany standard dzięki poznaniu jego możliwości od strony czysto

praktycznej

Aby treść mojej pracy dyplomowej mogła jak najlepiej zaprezentować

najważniejsze informacje dotyczące grafiki SVG, zdecydowałem się podzielić ją na

trzy główne części. Rozdział drugi stanowi wprowadzenie do standardu SVG,

przedstawia w skrócie historię jego powstania oraz zawiera krótkie zestawienie

jego podstawowych funkcjonalności. W rozdziale trzecim zamieszczam szczegółową

analizę większości elementów oferowanych przez standard SVG, przedstawiam

treść rekomendacji W3C oraz prezentuję swoje pomysły oraz wnioski płynące z

analizy kolejnych opisywanych funkcji. Rozdział czwarty stanowi podsumowanie

mojego osobistego wkładu w pracę dyplomową i składa się z części poświęconych

prezentacji konkretnych zastosowań SVG na podstawie zrealizowanych przeze mnie

aplikacji.

Mimo iż niniejsza praca mogłaby mieć charakter czysto teoretyczny, zdecydowałem

się na zupełnie inne podejście. Poszczególne elementy analizowanego standardu

staram się na bieżąco dokumentować samodzielnie opracowanymi praktycznymi

przykładami. Dzięki temu nawet część przeglądowa pracy, opisująca dokładnie

standard SVG, nie składa się wyłącznie z tekstu, ale zawiera również liczne

przykłady kodów źródłowych, prezentujących pewne konkretne funkcjonalności na

bardzo konkretnych przykładach.

Wierzę również, że opracowane przeze mnie aplikacje stanowić będą wraz z

załączonym do pracy ich kodem źródłowym bardzo solidną dawkę praktycznej

wiedzy na temat możliwych zastosowań grafiki wektorowej SVG oraz sposobów ich

realizacji, podkreślający jednocześnie wielkie znaczenie, jakie może ona odegrać w

sieci WWW już w najbliższym czasie.

W tym miejscu pragnąłbym serdecznie podziękować dr inż. Jackowi

Romanowskiemu za życzliwość, okazaną pomoc oraz udzielanie cennych

wskazówek w trakcie pisania tej pracy.

- 6/141 -

Page 7: SVG

2. Wprowadzenie do standardu SVG

W drugim rozdziale swojej pracy dyplomowej chciałbym przedstawić podstawowe

informacje dotyczące standardu SVG. Rozdział ten ma za zadanie stanowić krótkie i

zwięzłe wprowadzenie w świat grafiki wektorowej, dokonany nie od strony

technicznej, lecz od strony organizacyjnej. Chciałbym dokonać w nim ogólnego

przeglądu dokumentacji do standardu SVG, przedstawić pokrótce jego historię oraz

zwrócić uwagę na różnorodność istniejących w jego obszarze profili

przeznaczonych dla rozmaitych urządzeń końcowych. Rozdział został podzielony na

dwie części. W pierwszej z nich przedstawiam najbardziej podstawowe informacje

na temat SVG, w drugiej natomiast zaczynam stopniowo zagłębiać się w bardziej

konkretne tematy i zaawansowane zagadnienia, które kontynuowane i poszerzane

są w rozdziałach kolejnych.

2.1. Podstawowe informacje

Podstawowe informacje przedstawione w pierwszej części drugiego rozdziału

mojej pracy dyplomowej mają za zadanie nakreślić jej czytelnikowi elementarny

i poglądowy szkic standardu SVG. Pokrótce przedstawiam w nim podstawowe

reguły oraz pojęcia z nim związane, prezentuję historię oraz aktualny stan prac

standaryzacyjnych.

2.1.1. Co to jest SVG?

SVG stanowi skrót angielskiego określenia Scalable Vector Graphics, co

oznacza skalowalną grafikę wektorową. SVG posiada status rekomendacji

W3C – W3C (skrót od angielskiego określenia World Wide Web Consortium –

Konsorcjum WWW) jest bardzo wpływową międzynarodową organizacją,

- 7/141 -

Page 8: SVG

zrzeszającą w swoich szeregach przedstawicieli z ponad 400 [1]

najważniejszych firm informatycznych (m.in. AOL, Hewlett-Packard, IBM,

Matsushita, Microsoft, Nokia), organizacji oraz uczelni (m.in. Helsinki

University of Technology, Oxford University, Stanford University, The Hebrew

University of Jerusalem, Universidad Politécnica de Madrid) z całego świata.

W3C zajmuje się rozwijaniem standardów sieciowych od roku 1994, w którym

zostało ono założone przez Tima Bernersa-Lee [2]. Obecnie W3C jest

administrowane wspólnie przez MIT Computer Science and Artificial

Intelligence Laboratory (CSAIL) w USA, European Research Consortium for

Informatics and Mathematics (ERCIM) z siedzibą główną we Francji i Keio

University w Japonii [3].

Podstawowa definicja SVG, przedstawiana na oficjalnej stronie internetowej

organizacji W3C [4], mówi, że SVG jest językiem opisu dwuwymiarowych

obrazów oraz aplikacji graficznych w XML. Aktualnie obowiązującym

standardem jest rekomendacja SVG 1.1 (ustanowiona 14 stycznia 2003 roku).

Nieustannie trwają również prace nad ulepszoną wersją standardu SVG w

wersji 1.2.

Zostały również opracowane pewne ograniczone wersje standardu,

przeznaczone dla telefonii komórkowej trzeciej generacji oraz innych

przenośnych urządzeń, które mocą obliczeniową nie dorównują współczesnym

komputerom stacjonarnym. Cechom charakterystycznym poszczególnych

profili SVG postaram się przyjrzeć bliżej w drugiej części bieżącego rozdziału

mojej pracy.

2.1.2. Czy potrzebujemy kolejnego nowego standardu?

Przede wszystkim SVG nie jest kolejnym nowym standardem. Rekomendacja

SVG w wersji 1.0 została opublikowana 4 września 2001 roku [5], a zatem już

ponad 5 lat temu. Niemniej jednak termin SVG nie zdołał się natychmiastowo

- 8/141 -

Page 9: SVG

wpisać do zbiorowej świadomości użytkowników Internetu. Potrzeba było

czasu, aby szerokie grono twórców (i odbiorców) zainteresowało się poważnie

tym standardem (w niniejszej pracy będę się starał udowodnić, że SVG

zasługuje na znacznie większą uwagę niż obecnie).

W dalszej części rozdziału staram się pokrótce opisać, w jaki sposób

kształtował się standard SVG. Przedstawiam konkretne wydarzenia i

konkretne daty, które miały przełomowe znaczenie w tworzeniu

najważniejszych dla niego dokumentów, dyskutuję na temat aktualnego stanu

prac nad kolejnymi wersjami rekomendacji i wreszcie staram się podkreślić to,

jak ważne jest uczestnictwo wielu różnych firm oraz instytucji w

przygotowywaniu dokumentów stanowiących rekomendacje organizacji W3C.

2.1.3. Historia SVG jako rekomendacji W3C

Już wcześniej została podkreślona waga faktu, że SVG jest rekomendacją

W3C. Aktualnie obowiązującą (kwiecień 2007) wersją standardu jest SVG 1.1

oraz jego uszczuplone profile mobilne (ang. Mobile SVG Profiles): SVG Tiny

oraz SVG Basic [6].

Pierwszą istotną datą w rozwoju nowego standardu grafiki wektorowej jest 11

lutego 1999 roku. W tym dniu został opublikowany pierwszy ogólnodostępny

draft SVG. Prace nad ulepszeniem dokumentu były bardzo intensywne (w

międzyczasie ukazało się jeszcze osiem kolejnych draftów) i trwały do dnia 2

sierpnia 2000 roku, gdy SVG stał się oficjalnym kandydatem do rekomendacji

W3C. W przedstawionym wówczas dokumencie dokonano jeszcze kilku

poprawek i w dniu 5 września 2001 roku SVG 1.0 zostało uznane za oficjalną

rekomendację W3C. W tym samym dniu opublikowano również inny standard:

Animacje SMIL (ang. SMIL Animation), którego głównym celem jest

przygotowanie szkieletu projektowego (ang. framework) pod integrację

animacji z dowolnym dokumentem stworzonym w oparciu o język XML. SVG

- 9/141 -

Page 10: SVG

wykorzystuje Animacje SMIL do tworzenia animowanych efektów na swoich

własnych elementach.

Jak widać prace nad standardem trwały dość długo, bo od pierwszej

propozycji draftu do publikacji oficjalnej rekomendacji minęło ponad 30

miesięcy, a w dokumencie nieustannie dokonywano licznych poprawek.

Świadczy to o tym, iż standard SVG został opracowany bardzo starannie i

rzetelnie przez grono ekspertów, któremu zależało na przygotowaniu

solidnego i bardzo praktycznego dokumentu.

Na miesiąc przed publikacją rekomendacji SVG 1.0, pojawiły się pierwsze

dokumenty, zawierające zestawienie podstawowych wymagań w odniesieniu

do jej następców: SVG w wersji 1.1 oraz 2.0. W tym samym czasie ukazał się

pierwszy draft dokumentu dotyczącego podstawowych wymagań stawianych

profilowi SVG Mobile. 30 października 2001 roku grupa robocza W3C (ang.

W3C Working Group) pracująca nad SVG ogłosiła pierwszą propozycję

specyfikacji 1.1, jak również dwóch dodatkowych profili SVG Tiny i SVG Basic.

14 stycznia 2003 roku dokument, którego opracowanie nadzorowali Jon

Ferraiolo (Adobe Systems), Jun Fujisawa (Canon Inc.) i Dean Jackson (W3C),

stał się oficjalną rekomendacją SVG 1.1, pod którą podpisało się World Wide

Web Consortium.

Przedstawiona historia standardu SVG [9] sięga już kilka lat wstecz. Mimo to

dopiero teraz przeciętni użytkownicy Internetu zaczynają kojarzyć ten

trzyliterowy skrót (SVG) z jego rzeczywistym przeznaczeniem. W prace nad

coraz lepszym dostosowaniem standardu do rosnących wymagań twórców i

użytkowników sieci WWW zaangażowanych jest wielu przedstawicieli

najważniejszych firm informatycznych, uczelni oraz innych instytucji z całego

świata.

- 10/141 -

Page 11: SVG

2.1.4. Aktualny stan prac standaryzacyjnych

Nieustannie trwają prace nad standardem SVG w wersji 1.2. SVG 1.2 jest

aktualnie dostępne w formie draftu [7], zaproponowanego przez Deana

Jacksona z W3C oraz Craiga Northwaya z Canon Inc. Obecnie pracami grupy

przygotowującej nową wersję standardu kieruje Chris Lilley, a w skład

zespołu SVG Working Group wchodzą przedstawiciele takich firm i instytucji

jak Adobe Systems Inc., ERICSSON, France Telecom, Nokia czy Sun

Microsystems Inc. [8].

W związku z przeciągającymi się pracami nad SVG 1.2, szczególny nacisk

położono na szybkie dokończenie i rychłą publikację jego profilu SVG Tiny

1.2. W dniu 10 sierpnia 2006 roku opublikowano oficjalnie dokument SVG

Tiny 1.2 jako kandydata na rekomendację W3C [10]. Uznanie tego standardu

za oficjalną specyfikację sygnowaną przez W3C to kwestia najbliższej

przyszłości. Kolejny draft SVG 1.2 Full ma się ukazać niebawem jako

rozszerzenie SVG Tiny 1.2 o dodatkowe funkcjonalności.

Szczegółowy przegląd oraz porównanie możliwości poszczególnych profili oraz

wersji standardu SVG można znaleźć w drugiej części tego rozdziału. W tym

miejscu chciałbym jeszcze zwrócić uwagę na fakt, że nad przygotowaniem

dokumentu SVG Tiny 1.2 pracowali przedstawiciele tak ważnych firm jak

Adobe Systems (które wycofało się z pracy nad projektem w maju 2006

roku), czy Apple, Canon, Corel Corporation, Hewlett-Packard, IBM, Ikivo,

Macromedia, Microsoft, Motorola, Nokia, Opera Software, Sun Microsystems,

Xerox i wielu innych. Świadczy to o tym, iż standard SVG został uznany za

bardzo istotny element sieci Internet przez wszystkie światowe potęgi

informatyczne. Jednocześnie podkreśla to wagę rekomendacji

opracowywanych przez organizację W3C i konieczność uczestniczenia w

pracach nad nimi przez gigantów branży IT. Zdają oni sobie sprawę z tego jak

ważne jest wywieranie przez nich wpływu na kształt tych rekomendacji.

- 11/141 -

Page 12: SVG

2.2. Rozmaitości

W drugiej części bieżącego rozdziału staram się przedstawić podstawowe

koncepcje, które składają się na będący przedmiotem niniejszej pracy standard.

Oprócz tego poddaję analizie samą nazwę standardu oraz jej implikacje,

wyjaśniam podstawowe pojęcia, z jakimi spotykamy się czytając treść

rekomendacji, by w końcu wskazać kilka sposobów wykorzystania grafiki SVG na

stronach WWW [12]. Na zakończenie rozdziału zwracam uwagę na pewien

podzbiór funkcjonalności SVG, definiowany jako profil przeznaczony dla

urządzeń o niewielkiej mocy obliczeniowej.

2.2.1. Ogólny przegląd standardu

Akronim SVG oznacza Skalowalną Grafikę Wektorową (ang. Scalable Vector

Graphics).

„Skalowalność” polega na możliwości jednolitego zmniejszania oraz

zwiększania rozmiaru. W grafice komputerowej odpowiada to sytuacji, w

której definicja obrazu nie jest ograniczona do pojedynczych pikseli o dobrze

określonej wielkości. Z pojęciem skalowalności spotykamy się również w

sieciach telekomunikacyjnych, gdzie przymiotnik „skalowalny” określa te

techniki, które pozwalają na łatwe przystosowanie usługi zarówno do

niewielkiej, jak i bardzo dużej liczby użytkowników, plików czy aplikacji.

Standard uznaje skalowalność SVG w obu powyższych znaczeniach. Dzięki

temu wyświetlany obraz nie traci na jakości bez względu na to, czy zostanie

on wyświetlony na ekranie niewielkiego urządzenia przenośnego, czy też

wykorzystany do wykonania wydruku na drukarce w najwyższej

rozdzielczości. Obraz może być dowolnie powiększany oraz pomniejszany w

zależności od tego, w jakich okolicznościach jest on przedstawiany. Jeszcze

inną cechą skalowalności SVG jest to, że obrazy SVG mogą stanowić

samodzielne rysunki, jak i być włączane do innych obrazów SVG jako ich

- 12/141 -

Page 13: SVG

części składowe. Dzięki temu skomplikowane ilustracje mogą być budowane z

oddzielnych części nawet przez wiele niezależnie pracujących od siebie osób.

Rys.2.1. Przykładowy wykres pogody na stronie WWW Prognoza Pogody ICM.

Doskonałym przykładem wykorzystania SVG w sieci Internet, który nasuwa mi

się w tym miejscu, może być tworzenie ilustracji, przedstawiającej prognozę

pogody dla wybranego obszaru. Kilka niezależnych zespołów programistów

oraz grafików może mieć przypisane oddzielne zadania. Każdy z nich może

pracować nad ilustracją odpowiadającą innym zbieranym danym: ciśnieniu,

opadom, temperaturze, zachmurzeniu, itp. Następnie wszystkie te fragmenty

łączone są w jeden większy obraz, prezentowany na monitorze użytkownika.

Na stronie internetowej prognozy pogody ICM [11] możemy zobaczyć, jak

- 13/141 -

Page 14: SVG

wygląda taka „modułowa” budowa grafiki (podgląd strony przedstawiłem

również na rysunku 2.1). W tym jednak przypadku nie skorzystano z

możliwości oferowanych przez standard SVG – obrazy przedstawiane są

użytkownikowi w postaci statycznych rysunków w formacie GIF, a co za tym

idzie nie ma możliwości ich bezstratnego powiększania. W tym miejscu

chciałbym zaznaczyć, że jednym z pierwszych celów, jakie postawiłem sobie

do realizacji praktycznej w ramach niniejszej pracy dyplomowej, było

opracowanie aplikacji, umożliwiającej proste generowanie podobnych

wykresów pogodowych, tyle że w formacie SVG.

Kolejną ważną właściwością grafiki SVG jest określenie jej jako „wektorowej”.

Grafika wektorowa zawiera informację o obiektach geometrycznych takich jak

linie proste lub krzywe. Powoduje to, że jest ona zdecydowanie bardziej

elastyczna niż grafika rastrowa (reprezentowana przez obrazy w takich

formatach jak JPG czy PNG), która opiera się na przechowywaniu danych dla

każdego pojedynczego piksela grafiki. Dodatkowo grafika wektorowa posiada

zdolność włączania grafiki rastrowej i jej łączenia z treścią wektorową, np. do

tworzenia ścieżek maskujących (ang. clipping path).

Do pozostałych ważnych cech standardu SVG możemy zaliczyć: fakt, że jest

on aplikacją XML (XML jako rekomendacja W3C jest powszechnie uznanym i

szeroko stosowanym standardem wymiany informacji), za czym idzie

możliwość integracji komponentów SVG w ramach wielu przestrzeni nazw w

większych aplikacjach XML (przykładowo włączając obrazy SVG do

dokumentów napisanych w języku XHTML czy MathML) oraz możliwość

zastosowania arkuszy stylu do kontrolowania wartości atrybutów

poszczególnych elementów dokumentu SVG.

W SVG grafika modelowana jest na poziomie obiektów, a nie pojedynczych

punktów. Podstawowym elementem jest ścieżka (ang. path), która pozwala

na tworzenie rozmaitych obiektów graficznych. Możliwe jest również

- 14/141 -

Page 15: SVG

skorzystanie z kilku podstawowych figur (ang. basic shapes) takich jest

prostokąty czy elipsy.

Standard SVG pozwala użytkownikom na tworzenie nowych, redefiniowanie

istniejących oraz współdzielenie swoich własnych symboli bez konieczności

gromadzenia informacji o nich w scentralizowanych rejestrach. Dzięki temu

różne społeczności użytkowników (np. elektronicy, kartografowie) mogą

tworzyć swoje własne elementy SVG, bez konieczności wprowadzania

dodatkowych modyfikacji do samego standardu.

Bardzo ciekawą propozycją organizacji W3C było wyszczególnienie osobnej

linii rozwojowej standardu SVG, przeznaczonej dla urządzeń mobilnych: profil

SVG Tiny dedykowany telefonom komórkowym oraz profil SVG Basic dla

palmtopów (ang. PDA – Personal Digital Assistant). Specyfikacja SVG Tiny 1.2

posiada status kandydata do rekomendacji (ang. W3C Candidate

Recommendation), a bieżąca wersja draftu została opublikowana w dniu 10

sierpnia 2006 roku. Temat tych uproszczonych wersji standardu SVG

kontynuuję w rozdziale 2.2.3. W związku z faktem, że ani SVG 1.2 Full, ani

SVG 1.2 Tiny nie są jeszcze oficjalnymi rekomendacjami, skupiam się w nim

na krótkiej analizie porównawczej specyfikacji SVG Tiny oraz SVG Basic z SVG

Full, rekomendacjach opublikowanych w dniu 14 stycznia 2003 roku [13].

2.2.2. Metody umieszczania grafiki SVG na stronach WWW

Twórcy grafiki mają do dyspozycji kilka metod, pozwalających na

umieszczanie ich obrazów na stronach internetowych. Wśród możliwych opcji

można wymienić m.in.:

samodzielna (ang. standalone) grafika SVG: w tej sytuacji całkowitą

zawartość strony WWW stanowi dokument SVG, ładowany

bezpośrednio do przeglądarki i tak prezentowany użytkownikowi

osadzanie poprzez odwołanie (ang. embedding by reference): w tym

- 15/141 -

Page 16: SVG

przypadku nadrzędny dokument (strona WWW) odwołuje się do

przechowywanej w oddzielnym pliku grafiki SVG. Takie osadzenie

można wykonać za pomocą jednego z trzech elementów

HTML/XHTML: <img>, <object> lub <applet>

osadzanie wewnętrzne (ang. embedding inline): treść dokumentu SVG

zawarta jest bezpośrednio wewnątrz dokumentu nadrzędnego (np.

strony WWW)

łącze zewnętrzne: wykorzystanie elementu <a> języka HTML

umożliwia przeglądanie grafiki w dowolnym programie akceptującym

format SVG

2.2.3. SVG dla urządzeń o niewielkiej mocy obliczeniowej

SVG Working Group zdecydowało się na opracowanie oddzielnych

rekomendacji dla urządzeń mobilnych przede wszystkim dlatego, że

urządzenia te bardzo znacząco różnią się od siebie w wielu aspektach, między

innymi szybkością procesora (ang. CPU speed), rozmiarem dostępnej pamięci

oraz liczbą wyświetlanych kolorów. Aby skutecznie zaimplementować obsługę

standardu SVG w tak różnorodnych urządzeniach, zdecydowano się na

przygotowanie dla nich oddzielnych profili: SVG Tiny przeznaczone dla

przyrządów o bardzo ograniczonych możliwościach (np. telefonów

komórkowych) oraz SVG Basic dla urządzeń dysponujących nieco większymi

zasobami (np. palmtopy). Podstawowym założeniem obydwu profili jest

umożliwienie renderowania grafiki SVG na ekranach urządzeń przenośnych,

dysponujących ograniczonymi zasobami pamięci czy szybkości procesora.

Na profil SVG Tiny składają się następujące moduły (w obrębie poniższej listy

elementów oraz atrybutów sygnalizuję tylko obecność pewnych

funkcjonalności, szczegółowy opis właściwości wybranych elementów

standardu jest przedmiotem następnego rozdziału):

- 16/141 -

Page 17: SVG

Moduł podstawowych atrybutów (ang. Core Attribute Module),

definiujący zbiór atrybutów (ang. attribute set) Core.attrib, które mogą

wystąpić w dowolnym elemencie. Są to cztery atrybuty: id,

xml:base, xml:lang, xml:space

Moduł podstawowej struktury dokumentu SVG (ang. Basic Structure

Module), w ramach którego zawierają się następujące elementy: defs,

desc, g, metadata, svg, title, use

Moduł podstawowych atrybutów rysowania (ang. Basic Paint Attribute

Module), który definiuje zbiór atrybutów nazwany Paint.attrib, w

którym znajdują się atrybuty takie jak color, fill, stroke,

stroke-width i kilka innych, określających styl rysowania elementów

Moduł podstawowych atrybutów grafiki (ang. Basic Graphics Attribute

Module) to moduł, który definiuje dwa atrybuty: display,

visibility

Moduł hiperłącza (ang. Hyperlinking Module) określa listę dozwolonych

atrybutów elementu a (m.in. Style.attrib, transform, target),

służącego do tworzenia hiperłączy w dokumencie SVG

Moduł atrybutów XLink (ang. XLink Attribute Module) definiuje zbiory

atrybutów: XLink.attrib, XLinkRequired.attrib, XLinkEmbed.attrib i

XLinkReplace.attrib, zawierające atrybuty związane z właściwościami

hiperłączy

Moduł przetwarzania warunkowego (ang. Conditional Processing

Module) zawiera jeden element switch oraz listę dozwolonych dla

niego atrybutów

Moduł figur geometrycznych (ang. Shape Module) opisuje podstawowe

elementy, za pomocą których możemy definiować proste kształty na

- 17/141 -

Page 18: SVG

rysunku SVG. Są to: okrąg (element circle), elipsa (ellipse),

odcinek (line), ścieżka (path), wielokąt (polygon), linia łamana

(polyline) i prostokąt (rect). Każdy z tych elementów posiada listę

dozwolonych atrybutów, które pozwalają określić np. położenie obiektu

w układzie współrzędnych, długości boków lub promień oraz kilka

zestawów atrybutów opisanych w pozostałych podpunktach tego

zestawienia, np. Paint.attrib czy Graphics.attrib

Moduł obrazu (ang. Image Module) opisuje listę dozwolonych

właściwości elementu image, m.in. atrybuty transform, x, y,

width, height oraz kilka innych zestawów atrybutów

Moduł tekstowy (ang. Basic Text Module) zawiera listę dozwolonych

zestawów atrybutów dla elementu text, dozwolone wartości tego

elementu oraz atrybuty wchodzące w skład kolekcji Font.attrib (są to

właściwości opisujące krój, rozmiar oraz styl stosowanej czcionki:

font-family, font-size, font-style, font-weight) oraz

TextContent.attrib (zawierający atrybut text-anchor, określający

wyrównanie tekstu, np. wycentrowanie w poziomie)

Moduł czcionki (ang. Basic Font Module) definiuje listę dozwolonych

atrybutów dla elementów: font, font-face, font-face-name,

font-face-src, glyph, hkern, missing-glyph, służących do

definiowania czcionek

Moduł animacji (ang. Animation Module), definiujący zbiór

podstawowych elementów pozwalających na tworzenie animowanych

efektów w SVG: animate, animateColor, animateMotion,

animateTransform, mpath, set oraz listę skojarzonych z nimi

atrybutów

Moduł rozszerzalności (ang. Extensibility Module) opisuje tylko jeden

- 18/141 -

Page 19: SVG

element foreignObject i jego atrybuty. Zawartością tego elementu

jest zawsze sekcja #PCDATA. Głównym przeznaczeniem tego modułu

jest umożliwienie włączania elementów z innych przestrzeni nazw w

dowolnym miejscu dokumentu SVG.

Powyższe zestawienie modułów daje nam obraz możliwości, jakie powinna

posiadać zgodna ze specyfikacją W3C implementacja profilu SVG Tiny.

Zdecydowałem się na tak dokładne wymienienie wszystkich modułów,

ponieważ stanowią one rdzeń nie tylko dla SVG Tiny, ale również wszystkich

pozostałych profili SVG.

Już teraz SVG Tiny zostało zaimplementowane w ponad 100 modelach

telefonów komórkowych, produkowanych przez takie koncerny jak LG,

Motorola, NEC, Nokia, Panasonic, Samsung, Sharp, Siemens, Sony Ericsson

czy Toshiba [14].

Profil SVG Basic posiada wszystkie cechy SVG Tiny, został on jednak

poszerzony o kilka dodatkowych modułów, dających mu znacznie większe

możliwości. Aby nie wymieniać wszystkich z nich po kolei tak, jak to zrobiłem

dla SVG Tiny, pozwolę sobie przedstawić pokrótce te, które uważam za

najistotniejsze i które decydują o tym, że profil SVG Basic jest znacznie

bardziej skomplikowany. Co za tym idzie, jest on implementowany w

urządzeniach mobilnych typu palmtopy, które posiadają większe możliwości

przetwarzania danych niż zwykłe aparaty telefoniczne.

Pierwszym modułem, na który chcę zwrócić uwagę, jest moduł stylów (ang.

Style Module), który pozwala na zastosowanie arkuszy stylu CSS lub XSL do

dokumentu SVG. Dzięki temu w samym dokumencie SVG możemy

zdefiniować tylko i wyłącznie „treść” rysunku (np. dane wykresu), natomiast

jego wygląd (np. kolory poszczególnych słupków na wykresie) możemy

kontrolować z poziomu zewnętrznego arkusza stylu.

Inną cenną własnością profilu SVG Basic jest implementacja modułu

- 19/141 -

Page 20: SVG

atrybutów przezroczystości (ang. Opacity Attribute Module). Moduł ten

pozwala na definiowanie właściwości określających przezroczystość do

wszystkich elementów, które w wykazie swoich atrybutów posiadają zbiór

Opacity.attrib.

Jedną z najbardziej wyróżniających się różnic pomiędzy profilami SVG Basic i

SVG Tiny jest implementacja modułu gradientowego (ang. Gradient Module),

który pozwala na definiowanie gradientów liniowych oraz radialnych w SVG

Basic. W związku z faktem, że rysowanie gradientów wymaga znacznych

nakładów obliczeniowych, moduł ten nie mógłby być zaimplementowany w

SVG Tiny.

Moduł wzorów (ang. Pattern Module) pozwala na wykorzystanie

predefiniowanych obiektów złożonych z podstawowych elementów SVG jako

wypełnienia innych elementów rysunku. Pozwala to użytkownikowi na

definiowanie dowolnie skomplikowanych wzorów, a następnie ich

zastosowanie na przykład jako wypełnienia podstawowych figur.

W SVG Basic wprowadzone zostają dodatkowe moduły, odpowiedzialne za

interaktywność rysunku. Pierwszym z nich jest moduł atrybutów zdarzeń

dokumentu (ang. Document Events Attribute Module), który pozwala m.in.

określać, jak ma zachować się przeglądarka w przypadku nie załadowania

któregoś z elementów, niekompletnego załadowania elementu, skalowania

obrazu, przewijania obrazu w poziomie lub w pionie oraz jego powiększania

lub pomniejszania. Drugim interaktywnym modułem jest moduł atrybutów

zdarzeń elementów graficznych (ang. Graphical Element Events Attribute

Module), definiujący atrybuty dedykowane elementom graficznym obrazu

SVG, które pozwalają określić sposób reakcji przeglądarki na zdarzenia takie

jak naciśnięcie lub zwolnienie przycisku myszy nad wybranym elementem,

przemieszczanie wskaźnika myszy nad elementem, itp. Trzeci zbiór atrybutów

interaktywnych zdefiniowany jest w module atrybutów zdarzeń animacji (ang.

- 20/141 -

Page 21: SVG

Animation Events Attribute Module). Moduł ten pozwala zdefiniować reakcje

na zdarzenia takie jak rozpoczęcie animacji, jej zakończenie oraz powtórzenie.

Bardzo ważnym modułem jest moduł skryptów (ang. Scripting Module).

Definiuje on tylko jeden element script, który posiada jednak potężne

możliwości. Przeznaczenie tego elementu jest dokładnie takie samo jak w

przypadku dokumentów HTML, tzn. pozwala on na zamieszczanie skryptów

wewnątrz dokumentów SVG (z tego też powodu zawartość tego elementu

może stanowić wyłącznie sekcja #PCDATA). Zastosowanie skryptów jest

szczególnie przydatne wówczas, gdy chcemy manipulować obrazem SVG w

wyniku zaistniałych zdarzeń. Banalny przykład: korzystając z obiektowego

modelu dokumentu SVG, możemy wywołać prosty skrypt, który w wyniku

kliknięcia myszą na elemencie, spowoduje zmianę jego rozmiarów. Możliwości

zastosowania skryptów są ogromne, ponieważ SVG umożliwia niezależne

kojarzenie zdarzeń z dowolnym elementem graficznym rysunku.

Ostatnim modułem, na który chciałbym zwrócić uwagę w tym skróconym

opisie, jest moduł podstawowych filtrów (ang. Basic Filter Module). Filtry są

doskonałym narzędziem do tworzenia efektów graficznych, urozmaicają

rysunek, sprawiają, że zawartość grafiki staje się o wiele bogatsza w stosunku

do prymitywnego oryginału. Filtrowanie poszczególnych części rysunku

pozwala na uzyskanie takich efektów graficznych jak rozmycie, przesunięcie,

rozświetlenie, łączenie różnych warstw, morfing, turbulencja i inne.

Oprócz wymienionych wyżej modułów, które decydują o tym, że SVG Basic

jest zdecydowanie bardziej skomplikowane niż SVG Tiny (chociaż ciągle nie

tak trudne w implementacji jak SVG Full), dostępnych jest jeszcze kilka innych

modułów, o których nie wspomniałem, by nie zagłębiać się w niezbyt ciekawe

szczegóły teorii.

Mimo iż są ograniczone w stosunku do SVG Full, to jednak zarówno SVG Tiny

jak i SVG Basic posiadają potężne możliwości tworzenia oraz manipulowania

- 21/141 -

Page 22: SVG

obrazami. Co istotne, obie wersje mobilnego standardu SVG są obecnie

skutecznie implementowane w coraz większej liczbie urządzeń przenośnych

[14], na co już wcześniej zwróciłem uwagę.

2.3. Podsumowanie

W drugim rozdziale swojej pracy dyplomowej dokonałem krótkiego

wprowadzenia do standardu SVG, przedstawiłem podstawowe koncepcje oraz

pojęcia z nim związane, opisałem historię jego powstania oraz przebieg prac

standaryzacyjnych. Zwróciłem również uwagę na kilka zagadnień praktycznych,

takich jak umieszczanie grafiki SVG na stronach WWW. Na jego zakończenie

przybliżyłem elementy składowe okrojonych profili dyskutowanego standardu,

które przeznaczone są do implementacji w urządzeniach mobilnych ustępujących

mocą obliczeniową współczesnym komputerom stacjonarnym.

W rozdziale trzecim zamierzam przedstawić szczegółowo składniki rekomendacji

SVG w ostatniej opublikowanej wersji 1.1, dokonać precyzyjnej analizy

najważniejszych możliwości grafiki SVG oraz zaprezentować kilka konkretnych

przykładów jej wykorzystania. Z kolei rozdział czwarty poświęcam

charakterystyce aplikacji przygotowanych przeze mnie na potrzeby pracy oraz

demonstracji praktycznych ich możliwości.

- 22/141 -

Page 23: SVG

3. Szczegółowy przegląd możliwości SVG

Trzeci rozdział pracy dyplomowej chciałbym poświęcić szczegółowemu przeglądowi

możliwości grafiki SVG. Poprzedni rozdział w sposób bardzo ogólny opisywał

podstawowe jej cechy. Sucha teoria, nie poparta konkretnymi przykładami, może

dać zaledwie przybliżony obraz potencjalnych możliwości dyskutowanej techniki.

Dlatego też ten rozdział będzie o wiele bardziej konkretny, zawierać będzie kilka

praktycznych przykładów i wartościowych, z praktycznego punktu widzenia,

informacji. Zdaję sobie sprawę z tego, że nie sposób ogarnąć wszystkich istotnych

właściwości skalowalnej grafiki wektorowej (nie mówiąc już o ogarnięciu standardu

SVG jako całości) w jednym krótkim rozdziale (potrzeba by na to

kilkusetstronicowej książki, a i ona zapewne nie wyczerpałaby do końca tematu,

nad którym pracuje od wielu lat szerokie grono ekspertów). Postaram się zatem

zwrócić uwagę tylko na te zagadnienia, które z punktu widzenia osoby chcącej

poznać od podstaw grafikę SVG mogłyby się wydać najciekawsze, a których

znajomość będzie jednocześnie doskonałym punktem wyjścia do dalszego

poszerzania wiedzy.

3.1. Podstawowe składniki rekomendacji

Wszystkie właściwości grafiki SVG można odnaleźć w rekomendacji W3C [15].

Kolejne rozdziały specyfikacji dotyczą różnorodnych aspektów tego standardu.

Celem przejrzystego zestawienia jego podstawowych cech pozwolę sobie

dokonać w niniejszym rozdziale krótkiej charakterystyki zagadnień, opisywanych

w kilku różnych rozdziałach specyfikacji, a dotyczących najbardziej

podstawowych obszarów wykorzystania grafiki SVG (rozdział trzeci mojej pracy

- 23/141 -

Page 24: SVG

w całości został oparty na informacjach zawartych w rekomendacji W3C).

3.1.1. Przedstawienie treści pierwszych rozdziałów

Pierwszy rozdział rekomendacji wprowadza nas w świat SVG, wyjaśniając

podstawowe pojęcia i terminy stosowane w tekście specyfikacji, jak również

przedstawiając kilka kluczowych zagadnień z zakresu jej praktycznego

wykorzystania (przyjęte rozszerzenia plików SVG, typ MIME, przestrzeń nazw

SVG, deklarację DTD dokumentu).

W drugim rozdziale opisane zostają kluczowe koncepcje standardu:

wyjaśniona zostaje geneza nazwy SVG, jej najważniejsze idee, jak również

możliwości wykorzystania grafiki SVG w sieci WWW (o zagadnieniach tych

pisałem już wcześniej w rozdziałach 2.3.1 oraz 2.3.2).

3.1.2. Zagadnienia renderowania grafiki w SVG

Rozdział trzeci dotyczy szczegółów technicznych związanych z renderowaniem

grafiki SVG. Jest to krótki, ale bardzo ważny rozdział, ponieważ procedura

generowania rysunku determinuje to, w jaki sposób widzieć go będzie na

ekranie swojego monitora użytkownik końcowy. Kolejność nakładania

następujących po sobie elementów na prezentowany obraz ma bardzo istotne

znaczenie. Na przykład nie jest do końca oczywiste, czy elementy potomne

powinny być rysowane na pierwszym czy na drugim planie w stosunku do

swoich elementów nadrzędnych. Rekomendacja reguluje wszelkie tego typu

niejasności.

W rozdziale szczegółowo opisano, jak powinny być renderowane grupy

elementów, jak pojedyncze elementy, w jaki sposób nakładane mają być filtry

na wykreślone już wcześniej regiony, czy też jak realizować maskowanie oraz

nakładanie się różnych elementów. Informacje te są szczególnie istotne dla

osób i firm, zajmujących się implementacją standardu SVG w swoich

- 24/141 -

Page 25: SVG

własnych aplikacjach, zwłaszcza w przeglądarkach internetowych oraz

edytorach graficznych.

3.1.3. Typy danych

W rozdziale czwartym rekomendacji przedstawione zostały bardzo

szczegółowe informacje na temat podstawowych typów danych oraz

interfejsów DOM stosowanych w SVG. Można dowiedzieć się stąd między

innymi o tym, że właściwości oraz atrybuty elementów SVG mogą mieć

przypisane wartości m.in. następujących typów: liczby całkowite oznaczane

jako <integer>, liczby rzeczywiste <number>, długości <length>

(dozwolone jednostki opisane zostały w rozdziale 7.10 specyfikacji),

współrzędne <coordinate>, listy wartości <list of xxx>, kąty

<angle>, kolory <color>, procenty <percentage>, częstotliwości

<frequency>, czas <time> oraz kilka innych.

Bardzo wartościową, zwłaszcza dla osób tworzących grafikę SVG w sposób

niebezpośredni (tzn. nie w specjalizowanych do tego edytorach graficznych,

ale na przykład za pośrednictwem innych języków programowania lub za

pomocą zwykłego edytora tekstu), jest sekcja zawierająca zestawienie

rozpoznawalnych jako kluczowe nazw kolorów. Przeglądając kod źródłowy

dokumentu SVG o wiele łatwiej można sobie wyobrazić wygląd rysunku, jeżeli

kolory opisane są przez wyrazy gold i brown zamiast rgb(255,215,0) i

rgb(165,42,42). Kolorów, które posiadają w SVG swoje nazwy, jest 147 –

jest to ilość zadowalająca nawet bardziej wymagających twórców grafiki.

3.1.4. Struktura dokumentu SVG

Rozdział piąty dotyczy struktury dokumentu SVG. Opisano w nim, w jaki

sposób poprawnie zdefiniować dokument SVG za pomocą elementu <svg>

oraz odpowiedniego zapisu przestrzeni nazw w elemencie nadrzędnym.

- 25/141 -

Page 26: SVG

Zawarte zostały tam również informacje na temat dozwolonych atrybutów

elementu <svg>. W dalszej części rozdziału scharakteryzowane zostało

zagadnienie grupowania większej liczby elementów w jeden za pomocą

elementu <g>.

Kolejne zagadnienia dotyczą odwołań do innych zasobów za pomocą

identyfikatorów URI (ang. Uniform Resource Identifiers), zastosowania

elementów opisowych, przetwarzania warunkowego oraz innych kwestii

związanych z poprawną konstrukcją dokumentów SVG. Na zakończenie

rozdziału zestawione zostały wszystkie moduły SVG, które dotyczą

wspomnianych zagadnień, m.in. moduł atrybutów dozwolonych dla

wszystkich elementów, moduł struktury zawierający listę elementów

związanych ze strukturą dokumentu, moduł przetwarzania warunkowego

(ang. Conditional Processing Module) czy moduł obrazów (ang. Image

Module).

3.1.5. Style

O możliwościach zastosowania stylów w SVG można przeczytać w rozdziale

szóstym rekomendacji W3C. Style pozwalają na opisanie wielu różnorodnych

właściwości dokumentu SVG, przede wszystkim na zdefiniowanie sposobu, w

jaki renderowane będą elementy rysunku. Pozwalają na określanie takich

parametrów jak wypełnienia, kontury, grubości linii. W przypadku tekstu

pozwalają na przykład na określenie rozmiaru oraz rodzaju czcionki.

Modyfikują parametry, które wpływają na sposób generowania rysunku, takie

jak ścieżki maskujące, znaczniki czy filtry.

Właściwości wszystkich elementów rysunku SVG mogą zostać określone bez

definiowania stylów (czasami takie rozwiązanie jest konieczne, na przykład

gdy ten sam plik SVG przetwarzany jest za pomocą różnych programów, z

których nie każdy obsługuje zewnętrzne style), ale najczęściej stosuje się w

- 26/141 -

Page 27: SVG

tym celu jeden z dwóch standardów: XSLT oraz CSS. Podejścia do

zagadnienia są tu jednak różne.

W przypadku zastosowania XSLT jesteśmy w stanie dokonać skomplikowanej

transformacji dowolnego dokumentu z danymi w formacie XML (a zatem

także rysunku SVG) do dowolnego innego formatu, na przykład SVG

(przykładem takiego zastosowania jest jedna ze zrealizowanych przeze mnie

aplikacji praktycznych, opisana w rozdziale zatytułowanym „Generator

wykresów pogodowych”).

Technika CSS pozwala nam na zastosowanie stylów do już istniejących

dokumentów SVG, dokładnie w taki sam sposób, jak stosuje się ją do

dokumentów HTML. Skojarzony z dokumentem SVG arkusz stylu CSS pozwala

na modyfikację atrybutów wszystkich elementów tego dokumentu.

Rekomendacja wskazuje szczegółowo, w jaki sposób można z poziomu

dokumentu SVG odwoływać się do zewnętrznego arkuszu stylu oraz jakie

reguły rządzą przetwarzaniem dokumentu SVG za pomocą techniki XSLT.

3.1.5. Obszar rysunku

Rozdział siódmy został poświęcony systemowi współrzędnych rysunku,

transformacjom oraz stosowanym jednostkom. Bardzo ważnym pojęciem, na

które zwraca uwagę rekomendacja, jest tutaj obszar obrazu (ang. canvas).

Obszar obrazu definiowany jest przez specyfikację jako „przestrzeń, na której

renderowana jest treść rysunku”. Oprócz tego definiowany jest również

widoczny obszar obrazu (ang. viewport), który określany jest jako „widoczna

dla użytkownika część obrazu”. W odniesieniu do tych terminów

definiowanych jest mnóstwo innych, określających rozmiary obrazu,

współrzędne rysunku, matryce transformacji, itd.

Przyjmuje się, że punkt w lewym górnym rogu rysunku ma współrzędne

(0,0). Przesuwając się w prawo wzdłuż osi X wartości rosną, podobnie

- 27/141 -

Page 28: SVG

przesuwając się w dół wzdłuż osi Y wartości również rosną. Oczywiście za

pomocą odpowiednich transformacji możliwe jest przemieszczanie, obracanie,

przekrzywianie oraz skalowanie pierwotnego systemu współrzędnych i co za

tym idzie modyfikowanie prezentowanego użytkownikowi obrazu.

3.1.6. Skalowanie w praktyce

Bardzo ciekawym parametrem elementu <svg>, odnoszącym się do

skalowania, jest atrybut viewBox. Umożliwia on dopasowanie rozmiarów

rysunku do potrzeb użytkownika. W ten sposób, jeśli posiadamy rysunek o

oryginalnych rozmiarach 2000x2000 pikseli i chcemy, aby został on „ściśnięty”

na naszej stronie WWW do obszaru o wymiarach 150x200 pikseli (bo akurat

taki rozmiar jest wymagany przez układ graficzny naszej strony), wystarczy

zastosować atrybut viewBox, który spowoduje, że oryginalny obraz zostanie

przeskalowany i w całości wypełni obszar przeznaczony dla rysunku SVG:

<svg width="150px" height="200px" version="1.1"viewBox="0 0 2000 2000" preserveAspectRatio="none"xmlns="http://www.w3.org/2000/svg">

Analogicznie do poprzedniego przykładu, jeżeli ten sam rysunek na innej już

stronie potrzeba by umieścić w obszarze o wymiarach 250x100 pikseli,

zapisalibyśmy:

<svg width="250px" height="100px" version="1.1"viewBox="0 0 2000 2000" preserveAspectRatio="none"xmlns="http://www.w3.org/2000/svg">

W powyższym przykładzie w elemencie <svg> zdefiniowano jeszcze jeden

dodatkowy atrybut: preserveAspectRatio. Służy on do określenia, czy

rysunek ma zachować oryginalne proporcje, czy też może on całkowicie

wypełnić przeznaczony mu obszar. Lista dostępnych wartości tego parametru

jest długa i pozwala na bardzo precyzyjny dobór warunków skalowania

- 28/141 -

Page 29: SVG

rysunku.

3.1.7. Jednostki wielkości

Innym interesującym zagadnieniem, poruszanym w siódmym rozdziale

rekomendacji, jest wspomniana wcześniej kwestia jednostek. W SVG wszelkie

współrzędne oraz rozmiary mogą być definiowane zarówno z jak i bez

identyfikatora jednostek. Jeżeli liczby podawane są bez jednostki, przyjmuje

się, że wartość podana jest w jednostkach użytkownika. Możliwe jest również

wskazanie którejś z jednostek absolutnych zdefiniowanych przez standard

CSS (tj. em, ex, px, pt, pc, cm, mm, in). Oprócz tego dozwolone jest także

określanie rozmiarów w procentach.

3.1.8. Przedstawienie treści kolejnych rozdziałów

Kilka kolejnych rozdziałów standardu dotyczy zagadnień, którym szczegółowo

przyjrzę się w rozdziale 3.2 pracy zatytułowanym „Najważniejsze możliwości

SVG”, ponieważ dotyczą one bezpośrednio tworzenia konkretnych elementów

SVG, takich jak ścieżki (rozdział 8 rekomendacji), podstawowe kształty

(rozdział 9), tekst (rozdział 10), wypełnienia i kontury (rozdział 11), gradienty

i wzory (rozdział 13) oraz czcionki (rozdział 20).

Bardziej skomplikowane właściwości SVG, takie jak przycinanie, maskowanie,

komponowanie (rozdział 14), filtry (rozdział 15), interaktywność (rozdział 16),

hiperłącza (rozdział 17), skrypty (rozdział 18) oraz animacje (rozdział 19)

będą przedmiotem rozdziału 3.3 niniejszej pracy zatytułowanego

„Zaawansowane właściwości SVG”. W tym miejscu pozostały mi do omówienia

jeszcze trzy ostatnie rozdziały specyfikacji.

3.1.9. Metadane i kompatybilność wstecz

Rozdział dwudziesty pierwszy dotyczy metadanych w SVG. Standard XML

- 29/141 -

Page 30: SVG

pozwala na opisywanie danych przez inne dane nazywane dla rozróżnienia

metadanymi i zawieranie tych informacji wewnątrz samego dokumentu. W

związku z tym SVG posiada również taką możliwość, która realizowana jest za

pomocą elementu <metadata>.

W rozdziale dwudziestym drugim opisano dwa scenariusze, pozwalające na

zachowanie kompatybilności wstecz dokumentom SVG. Oczywistym jest, że

użytkownik końcowy może korzystać z takiej wersji przeglądarki internetowej

lub innego programu (ang. user agent), która nie została wyposażona w

obsługę standardu SVG (taka obsługa została/zostanie dopiero

zaimplementowana w jego kolejnej wersji lub w ogóle). W związku z tym

założenie, że rysunek SVG zostanie poprawnie wyświetlony na każdym

urządzeniu końcowym, jest błędne. Rekomendacja W3C proponuje

przeciwdziałać niekompatybilności starszych programów z nowym standardem

na dwa sposoby.

W przypadku dokumentów zgodnych ze standardem XML, które pozwalają na

osadzanie treści SVG, można użyć elementu <switch> w następujący

sposób, aby zapewnić alternatywny rysunek do wyświetlenia na wypadek,

gdyby program nie obsługiwał formatu SVG:

<switch> <!-- Wyświetl rysunek SVG, jeżeli jest to możliwe. --> <ref type="image/svg+xml" src="rysunek.svg"/> <!-- W przeciwnym razie wyświetl alternatywny rys. --> <img src="alternatywny_rysunek.jpg"/></switch>

W przypadku HTML 4, rysunki SVG mogą być osadzane w dokumencie za

pomocą elementu <object> w następujący sposób:

<object type="image/svg+xml" data="rysunek.svg"> <!-- Jeżeli przeglądarka internetowa nie jest w stanie wyświetlić rysunku SVG, wówczas przetwarzana będzie

- 30/141 -

Page 31: SVG

poniższa zawartość: --> <img src="alternatywny_rysunek.jpg" alt="opis"></object>

3.1.10. Rozszerzalność języka SVG

Ostatni rozdział rekomendacji opisuje zagadnienia związane z rozszerzalnością

(ang. extensibility) języka SVG. Możemy się z niego dowiedzieć, że SVG

pozwala na włączanie elementów z obcych przestrzeni nazw w dowolnym

miejscu dokumentu. SVG dostarcza również mechanizmów pozwalających

innym językom XML na wstawianie swojej zawartości na obszar rysunku (np.

wstawianie wyrażenia matematycznego przygotowanego w języku MathML na

wybrany fragment rysunku). Służy do tego celu element <foreignObject>,

który przyjmuje cztery atrybuty określające położenie obcego elementu na

rysunku SVG (współrzędne x i y oraz rozmiary width i height).

W SVG możliwe jest również dodawanie własnych elementów oraz atrybutów

do składni DTD. W ten sposób użytkownik może zbudować w oparciu o

standard SVG swój własny rozszerzony język SVG, który najlepiej będzie

spełniał jego osobiste potrzeby.

3.1.11. Podsumowanie podstawowych informacji

Rekomendacja opisuje bardzo szczegółowo wymienione w tym rozdziale

mojej pracy zagadnienia. Moim celem nie było powielanie tych informacji, lecz

solidne ich streszczenie oraz dokonanie ogólnego przeglądu możliwości grafiki

SVG. Chciałem zasygnalizować potężne możliwości tego języka, jak również

przedstawić dokładniej kilka zagadnień, które wydały mi się najciekawsze. W

rozdziale 3.2 zaprezentuję na konkretnych przykładach w postaci kodu

źródłowego oraz wygenerowanych w przeglądarce internetowej rysunków, w

jaki sposób korzystać z podstawowych elementów graficznych oferowanych

przez standard oraz jak wygląda tworzenie grafiki w oparciu o te elementy.

- 31/141 -

Page 32: SVG

3.2. Najważniejsze możliwości SVG

Przedmiotem niniejszego rozdziału jest przedstawienie najistotniejszych z punktu

widzenia twórcy grafiki możliwości, oferowanych przez standard SVG. W celu

realizacji tego zadania omówię oraz przedstawię kilka praktycznych przykładów

wykorzystania podstawowych elementów, będących składnikami języka SVG.

Mam nadzieję, że rozdział ten da znacznie szerszy obraz możliwości

dyskutowanego standardu niż omawiane do tej pory zagadnienia teoretyczne.

3.2.1. Modelowanie kształtów za pomocą ścieżek

Pierwszym elementem, na który chciałbym zwrócić uwagę w tym paragrafie,

jest ścieżka (ang. path). Rozdział ósmy rekomendacji W3C definiuje ścieżkę

jako kontur (ang. outline) figury, który może zostać wykorzystany na jeden z

trzech sposobów (lub jako ich kombinację): wypełnienie, obramowanie,

ścieżka maskująca. Ścieżka opisywana jest za pomocą koncepcji bieżącego

punktu (ang. current point) – co jest przez to rozumiane, łatwo sobie

wyobrazić stosując anologię z rysowaniem na papierze. Bieżący punkt jest

odpowiednikiem aktualnego położenia ołówka na kartce, po której rysujemy.

Jego pozycja może ulec zmianie w dowolnym momencie, kontur może być

zamknięty lub otwarty i wykreślany za pomocą linii krzywych lub prostych.

Ścieżka reprezentuje kontur obiektu, zdefiniowany za pomocą takich instrukcji

jak moveto (określenie nowej pozycji dla bieżącego punktu), lineto

(wykreślenie linii prostej do wskazanego punktu), curveto (wykreślenie linii

krzywej do wskazanego punktu przy wykorzystaniu miary Beziera), arc

(poprowadzenie łuku eliptycznego lub kołowego) oraz closepath

(zamknięcie kształtu poprzez przedłużenie ścieżki do ostatniego z elementów

moveto).

Ścieżki w SVG definiowane są za pomocą elementu <path>. Dozwolone są tu

następujące dwa atrybuty: d zawierający definicję konturu oraz pathLength

- 32/141 -

Page 33: SVG

określający całkowitą długość ścieżki, służący do jej skalowania przez

aplikację. Kluczowym składnikiem jest tu atrybut d elementu <path>,

definiujący kształt ścieżki. Jego wartością jest wyrażenie, składające się z

instrukcji sformułowanych za pomocą pojedynczych liter, np. litera M

odpowiada instrukcji moveto, a litera L odpowiada instrukcji lineto. Po

instrukcji następują liczby, stanowiące parametry instrukcji (ich liczba zależy

od typu instrukcji), a po nich kolejne instrukcje. Całość wyrażenia jest

definicją ścieżki.

Na rysunku 3.2 przedstawiono przykładowy obraz SVG, utworzony wyłącznie

z elementów <path>, natomiast na rysunku 3.1 można przejrzeć kod

źródłowy SVG, który posłużył do jego wygenerowania. Jak widzimy do ścieżek

można stosować wszystkie podstawowe atrybuty, pozwalające na określanie

takich właściwości utworzonych figur jak chociażby kolor wypełnienia czy

grubość obramowania. Czyni to ścieżki jednymi z najefektywniejszych

narzędzi do edycji grafiki wektorowej.

<path d="M 10 280 L 180 10 L 140 260 Z" fill="yellowgreen" stroke="darkgreen" stroke-width="5" stroke-linejoin="round"/><path d="M 300 100 h -80 a 80 80 0 1 0 80 -80 Z" fill="khaki" stroke="peru" stroke-width="5"stroke-linejoin="square"/><path d="M 10 10 l 50 50 a 25 25 30 0 1 50 25 l 75 25 a 25 50 30 0 1 50 50 l 25 50 a 25 100 40 0 1 50 50 l 50 25" fill="none" stroke="sienna" stroke-width="6" stroke-linejoin="square"/><path d="M 10 230 Q 60 10 180 180 T 390 250" fill="none"stroke="dodgerblue" stroke-width="6" stroke-linecap="round"/>

Rys.3.1. Kod źródłowy obrazu SVG, przedstawionego na rysunku 3.2(pominięto nagłówek XML, deklarację DTD oraz element główny <svg>).

Starałem się na jednym obrazie zamieścić różne kształty wygenerowane za

pomocą tego samego elemetu SVG, tj. ścieżki <path>, aby pokazać jak

- 33/141 -

Page 34: SVG

różnorodne i wszechstronne zastosowanie może mieć ten jeden tylko element

standardu.

Rys.3.2. Rysunek SVG utworzony wyłącznie z elementów <path>.

3.2.2. Wykreślanie figur za pomocą kształtów

Rozdział 9 rekomendacji W3C poświęcony został opisowi podstawowych

kształtów (ang. basic shapes), oferowanych użytkownikowi przez standard

SVG. Poza ścieżkami są one chyba najważniejszymi z podstawowych

elementów grafiki SVG. Odróżnia ich od ścieżek to, że są dużo łatwiejsze do

zastosowania dla początkujących użytkowników.

Specyfikacja oferuje następujące słowa kluczowe służące do definiowania

podstawowych kształtów: <rect> (prostokąt), <circle> (koło),

- 34/141 -

Page 35: SVG

<ellipse> (elipsa), <line> (linia), <polyline> (linia łamana) i

<polygon> (wielokąt). Mimo iż każdy z tych kształtów, dla których

stworzono oddzielne słowa kluczowe, można uzyskać przez odpowiednie

zdefiniowanie ścieżki <path>, o wiele wygodniejsze wydaje się przecież

wykreślanie prostokąta za pomocą elementu <rect> niż poprzez

wykorzystanie ścieżki <path>. Rzut oka na kod źródłowy pozwala

zorientować się, w którym miejscu znajduje się definicja prostokąta, w

przypadku zastosowania nie opatrzonego żadnym komentarzem elementu

<path> nie jest to w żadnym wypadku oczywiste.

Każdy z wymienionych wyżej kształtów może posiadać kontur, zdefiniowany

za pomocą odpowiednich atrybutów (stroke, stroke-width, itp.). Może

również zostać wypełniony (atrybut fill). Wiąże się to z faktem, że każdy z

atrybutów dostępnych dla elementu <path> można zastosować również do

każdego z podstawowych kształtów.

Na rysunku 3.3 zamieszczono przykładowy obraz, na którym wykreślono po

jednym obiekcie dla każdego z elementów zawierających się w zbiorze

podstawowych kształtów. Warto zauważyć, że atrybuty poszczególnych

elementów są bardzo intuicyjne i możliwe do zrozumienia nawet bez

dogłębnej lektury specyfikacji. Atrybuty x i y zwykle oznaczają współrzędne

obiektu na płaszczyźnie – nie inaczej jest w tym przypadku. Atrubuty width

oraz height odpowiadają odpowiednio szerokości oraz wysokości obiektu, r

to oczywiście promień koła, natomiast rx i ry to dwa promienie elipsy. W

przypadku linii musimy określić współrzędne jej początku oraz końca, a zatem

zastosujemy zmienne z indeksem: x1 i y1 oraz x2 i y2. Jedynym wyjątkiem

są tu elementy <polyline> oraz <polygon>. Zbiór kolejnych punktów

figury stanowi wartość atrybutu points (współrzędne punktów podawane są

w układzie współrzędnych użytkownika). Każdy z wymienionych elementów

- 35/141 -

Page 36: SVG

można ujrzeć w kodzie źródłowym obrazu zamieszczonym na rysunku 3.4.

Rys.3.3. Rysunek SVG utworzony za pomocą podstawowych kształtów.

<rect x="20" y="180" width="180" stroke-width="5" height="100" fill="paleturquoise" stroke="darkcyan"/><circle cx="330" cy="100" r="50" fill="darkseagreen" stroke="darkgreen" stroke-width="5"/><ellipse cx="135" cy="50" rx="120" ry="30" fill="palegoldenrod" stroke="brown" stroke-width="5"/><line x1="220" y1="285" x2="280" y2="15" stroke="olivedrab" stroke-width="5"/><polyline fill="none" stroke="steelblue" stroke-width="5" points="20,110 30,155 125,155 135,110 225,110 235,155"/><polygon fill="orange" stroke="firebrick" stroke-width="5" stroke-linejoin="round" points="316,175 332,218 380,218 342,245 357,288 316,262 275,288 290,245 250,218 300,218"/>

- 36/141 -

Page 37: SVG

Rys.3.4. Kod źródłowy obrazu SVG, przedstawionego na rysunku 3.3.

3.2.3. Wprowadzanie tekstu na rysunku SVG

W rekomendacji SVG duży nacisk położony został nie tylko na elementy

związane bezpośrednio z wstawianiem elementów graficznych na rysunkach.

Bardzo rozbudowane zostały również rozdziały poświęcone wykreślaniu

tekstu. Rozdział dziesiąty poświęcony został w całości metodom wstawiania

tekstu na rysunek, natomiast rozdział dwudziesty traktuje o możliwościach

zastosowania różnych czcionek oraz stylów do wykreślanego tekstu.

Do umieszczania tekstu na rysunkach SVG służy element <text>. Tekst,

który ma zostać wyświetlony na ekranie, powinien się znaleźć pomiędzy

znacznikiem otwierającym oraz zamykającym element <text>.

Element tekstowy traktowany jest w dokładnie identyczny sposób jak

wszystkie pozostałe elementy SVG. Konsekwencją tego faktu jest to, że

wszelkie transformacje współrzędnych (będzie o nich mowa w rozdziale 3.3),

nakładanie, maskowanie czy wypełnianie kolorami ma dokładnie takie samo

zastosowanie w odniesieniu do tekstu jak do podstawowych kształtów oraz

ścieżek.

Aby wstawić nowy obiekt tekstowy na rysunek należy w elemencie <text>

określić jego położenie za pomocą atrybutów x oraz y oznaczających jego

bezwzględne współrzędne. Atrybut fill definiuje kolor znaków. Wyboru

czcionki dokonuje się za pomocą atrybutu font-family, jej rozmiaru

natomiast poprzez wartość atrybutu font-size. Istnieje możliwość

dostosowywania właściwości czcionki (kolor, wyróżnienie, indeksowanie, itp.)

oraz tekstu (zawijanie wierszy, zaawansowane formatowanie, itp.) w obrębie

jednego ciągu znaków poprzez zastosowanie kilku elementów <tspan>,

przyjmujących identyczne argumenty, zawartych wewnątrz pojedynczego

- 37/141 -

Page 38: SVG

elementu <text>. Za pomocą atrybutu text-anchor można określić

wyrównanie tekstu w odniesieniu do jego współrzędnych (wyrównanie do

lewej, do prawej strony lub wyśrodkowanie osiąga się odpowiednio

wartościami start, end oraz middle).

Do ustalenia właściwości czcionki służą między innymi atrybuty: font-style

pozwalający na wybór pomiędzy pismem normalnym, ukośnym oraz kursywą,

font-weight służący do określenia poziomu pogrubienia liter, font-

stretch umożliwiający wskazanie pożądanego ściśnięcia bądź rozrzedzenia

przestrzeni pomiędzy znakami.

Rys.3.5. Wykreślanie tekstu w grafice SVG. Na rysunku widoczny jestfragment zaznaczony poprzez przeciągnięcie nad nim wskaźnika myszy.

- 38/141 -

Page 39: SVG

Oprócz wspomnianych właściwości w stosunku do elementów <text> oraz

<tspan> można zastosować wiele różnorodnych efektów: rotację znaków,

zróżnicowane odstępy pomiędzy literami oraz słowami, podkreślanie oraz

przekreślanie tekstu, zmianę jego orientacji (co jest przydatne zwłaszcza w

przypadku stosowania niektórych języków azjatyckich), czy na przykład

umieszczanie tekstu na ścieżce, dzięki czemu można tworzyć fantazyjnie

wyglądające napisy.

Bardzo ważną cechą elementów tekstowych w SVG jest to, że z punktu

widzenia użytkownika, przeglądającego rysunek, są one traktowane nie jako

obiekty graficzne, lecz jako tekst. Oznacza to, że użytkownik musi mieć

możliwość zarówno zaznaczenia wybranego fragmentu tekstu, jak i jego

skopiowania do schowka systemowego (ang. clipboard).

Na rysunku 3.6 zaprezentowano kilka sposobów wstawiania tekstu oraz jego

formatowania na rysunku SVG. Efekt zastosowania przedstawionego na nim

kodu źródłowego można zobaczyć na rysunku 3.5. Warto zwrócić uwagę na

fragment tekstu wyróżniony za pomocą wskaźnika myszy – widzimy, że

przeglądarka „Opera” ma możliwość zaznaczania oraz kopiowania tekstu z

rysunku SVG, zalecaną w rekomendacji W3C.

<text x="5" y="30" font-family="Verdana" font-size="22" fill="dodgerblue">As far as the laws of <tspan font-weight="bold" fill="magenta">mathematics</tspan></text><text x="200" y="80" font-family="Verdana" font-size="48" fill="navy" font-style="italic" text-anchor="middle">refer to reality</text><text x="390" y="120" font-family="Verdana" font-size="32" fill="maroon" text-decoration="underline" text-anchor="end">they are not</text><text font-family="Verdana" font-size="64" fill="purple"><tspan x="10 40 80 130 190 270 350" y="185">certain</tspan></text><defs><path id="MyPath" d="M 30 290 S 50 200 120 200 S 180 280 250 280 S 390 240 390 240"/></defs><text font-family="Verdana" font-size="16"

- 39/141 -

Page 40: SVG

fill="darkslategrey"><textPath xlink:href="#MyPath"> As far as they are certain, they do not refer to reality...</textPath></text>

Rys.3.6. Kod źródłowy obrazu SVG, przedstawionego na rysunku 3.5.

3.2.4. Wypełnienia oraz kontury obiektów

Rozdział jedenasty specyfikacji SVG został poświęcony rysowaniu wypełnień

(ang. fill) oraz konturów (ang. stroke). Każdy element ścieżki, tekstu oraz

podstawowych kształtów, omówiony oddzielnie w trzech poprzednich

rozdziałach może być wypełniony (wypełnienie rozumiane jest tutaj jako

zamalowanie wnętrza obiektu) oraz obrysowany (co oznacza wykreślenie

konturu wokół obiektu). Obie te operacje, tzn. wypełnianie oraz

obrysowywanie, razem określane są ogólniejszym terminem rysowania (ang.

painting). W grafice SVG możemy rysować (tzn. wypełniać obszary oraz je

obrysowywać) za pomocą:

pojedynczego koloru

pojedynczego koloru z określoną przezroczystością

gradientu (liniowego lub kołowego)

wzoru (wektorowego lub innego rysunku, również sąsiadująco (ang.

tiled))

innych obiektów zdefiniowanych poprzez rozszerzenia SVG

Atrybuty fill oraz stroke przyjmują ten sam typ wartości, którym może

być: słowo kluczowe none (które oznacza, że operacja rysowania nie jest

wykonywana), nazwa koloru (jedna z niemal 150 dozwolonych nazw,

zebranych w czwartym rozdziale rekomendacji, np. gold lub brown), wartość

koloru (zapisana w formacie #RRGGBB, np. #FFD700 lub #A52A2A) lub

odnośnik URI (ten sposób stosowany jest dla gradientów, wzorów oraz

- 40/141 -

Page 41: SVG

obiektów rozszerzonych, np. jeśli w obrębie tego samego dokumentu

zdefiniowano gradient i oznaczono go identyfikatorem myGradient,

wówczas odwołujemy się do niego pisząc url(#myGradient)).

Dostępne są jeszcze dwie dodatkowe opcje definiowania sposobu wypełniania

elementów. Atrybut fill-rule decyduje o tym, które fragmenty obszaru

rysowania należy uznać za znajdujące się wewnątrz obiektu, a więc dla której

części elementu ma zostać narysowane wypełnienie (dla większości

standardowych obiektów nie ma on jednak większego znaczenia). O wiele

bardziej atrakcyjny z punktu widzenia użytkownika wydaje się być atrybut

fill-opacity. Określa on poziom przezroczystości wypełnienia z zakresu

od 0 (całkowita przezroczystość) do 1 (wypełnienie nieprzezroczyste).

W przypadku rysowania konturów dostępnych jest o wiele więcej opcji.

Wspomniany już atrybut stroke definiuje kolor rysowania. Atrubut stroke-

width pozwala na dobór grubości linii, którą wykonywany jest obrys. Mamy

możliwość dokonania wyboru, czy zakończenie linii ma być kwadratowe czy

może zaokrąglone, dobierając odpowiednio wartość atrubytu stroke-

linecap. Podobnie rzecz ma się z połączeniami linii, stanowiących krawędzi

figur lub ścieżek – można je łączyć ze sobą na trzy sposoby: ostry (ang.

miter), skośny (ang. bevel) oraz zaokrąglony (ang. round), przypisując

pożądany typ połączenia atrybutowi stroke-linejoin. Mamy również

możliwość wykreślania linii kreskowanych, kropkowanych oraz dowolnych ich

kombinacji poprzez ustawienie wartości atrybutu stroke-dasharray.

Podobnie jak w przypadku wypełnienia, tak również do konturu można

zaaplikować dowolny stopień przezroczystości. Do tego celu służy atrybut

stroke-opacity (domyślnie zarówno kontur jak i wypełnienie są całkowicie

nieprzezroczyste).

Specyfikacja dostarcza również możliwości zakańczania ścieżek oraz linii

- 41/141 -

Page 42: SVG

symbolami strzałek. Aby z niej skorzystać należy użyć elementu <marker>.

3.2.5. Wypełnianie figur za pomocą gradientów i wzorów

Jedne z najefektowniejszych, a jednocześnie wymagających niewielkich

nakładów pracy ze strony twórcy, rezultatów zastosowania grafiki SVG można

osiągnąć, korzystając z gradientów oraz wzorów, opisanych szczegółowo w

trzynastym rozdziale specyfikacji. Już wcześniej wspominałem, że SVG

pozwala na wypełnianie kształtów jak i obrysowywanie ich konturów nie tylko

za pomocą pojedynczego koloru, ale również za pomocą gradientów i

wzorów. Przyjrzymy się teraz szerzej tym możliwościom.

Czym w ogóle jest gradient? W grafice SVG przez gradient rozumiane jest

płynne przejście pomiędzy dwoma kolorami. Standard definiuje dwa rodzaje

gradientów: liniowy (ang. linear gradient) oraz kołowy (ang. radial gradient),

określane odpowiednio za pomocą elementów <linearGradient> oraz

<radialGradient>. Po zdefiniowaniu gradientu w dokumencie, można się

do niego odwoływać poprzez atrybuty fill i stroke wybranego elementu,

aby wskazać chęć jego wypełnienia bądź narysowania konturu za pomocą

określonego gradientu.

Wśród najważniejszych atrybutów służących do definiowania gradientów

liniowych możemy wyróżnić: współrzędne x1, y1 oraz x2, y2 (współrzędne

te określają punkt początkowy oraz punkt końcowy gradientu, najczęściej

określane są w procentach, domyślnie przypisane są im następujące wartości:

x1="0%", y1="0%", x2="100%", y2="0%"), identyfikator id (unikalny

identyfikator, który można przypisać każdemu elementowi dokumentu SVG, a

zatem również gradientowi, umożliwiający późniejsze odwoływanie się do

niego poprzez ten identyfikator) i spreadMethod (pozwalający określić

zachowanie gradientu, kończącego się wewnątrz). Kolory, pomiędzy którymi

dokonywane jest przejście gradientowe, definiuje się wewnątrz elementu

- 42/141 -

Page 43: SVG

<linearGradient> za pomocą co najmniej dwóch elementów podrzędnych

<stop>, w których określone zostają wartości dwóch kluczowych atrybutów:

stop-color odpowiadający pożądanemu kolorowi oraz offset (wyrażany

głównie w procentach) służący do określenia położenia tego koloru w

gradiencie.

W przypadku gradientu kołowego dostępne atrybuty różnią się nieznacznie,

ponieważ jego charakter jest trochę inny niż gradientu liniowego. Zamiast

współrzędnych definiujących punkt początkowy oraz punkt końcowy mamy

tutaj możliwość zdefiniowania współrzędnych największego możliwego okręgu

(cx, cy, r), który będzie wchodził w skład gradientu (gradient zostanie

wykreślony w ten sposób, że jego kolor określony dla atrybutu

offset="100%" w elemencie <stop> będzie odpowiadał właśnie temu

największemu okręgowi). Z kolei punkt środkowy, od którego gradient

„promieniuje” definiuje się za pomocą atrybutów fx i fy, które określają

środek okręgu (punkt ten odpowiada kolorowi określonemu w elemencie

<stop> dla atrybutu offset="0%").

W grafice SVG efektownie rysować można nie tylko za pomocą gradientów,

ale również za pomocą samodzielnie zdefiniowanych wzorów (ang. patterns).

Poprzez wzór możemy rozumieć niezależny rysunek SVG, który można później

dowolnie wykorzystać. Przygotowanie wymyślnego wzoru, a następnie

wypełnienie nim wnętrza jakiegoś elementu może nieraz dać zadziwiający

efekt.

Do definiowania wzorów służy element <pattern>. Odwoływać się można

do niego w atrybutach fill i stroke dokładnie w taki sam sposób jak do

gradientów (patrz przykład na rysunku 3.8). Podstawowymi atrybutami

elementu <pattern> są: współrzędne x i y, szerokość width oraz

wysokość height (parametry te decydują, w jaki sposób zostaną

- 43/141 -

Page 44: SVG

rozmieszczone poszczególne kafelki (ang. tiles) wzoru), a także

patternUnits (definiujący system współrzędnych dla wymienionych

atrybutów) i patternContentUnits (definiujący system współrzędnych dla

wszystkich elementów składających się na wzór). Wewnątrz elementu

<pattern> możemy zdefiniować nasz wzór dokładnie w taki sam sposób,

jakbyśmy definiowali niezależny rysunek SVG. Wzór może się składać ze

ścieżek, prostokątów, okręgów oraz wszelkich innych elementów SVG.

Jedynym ograniczeniem jest tu tylko inwencja twórcy.

Na rysunku 3.7 został przedstawiony obraz, na którym zamieszczono kilka

podstawowych elementów SVG, do których wypełnienia oraz obrysowania

zastosowano różnorodne techniki i właściwości opisane powyżej, włączając w

to gradienty, wzory, przezroczystości, zdefiniowane przez użytkownika

kreskowanie linii i inne. Kod źródłowy, który posłużył do wygenerowania tej

grafiki, został przedstawiony na rysunku 3.8.

- 44/141 -

Page 45: SVG

Rys.3.7. Rysunek SVG prezentujący zastosowanie różnych technikwypełniania oraz obrysowywania kształtów, między innymi za pomocą

gradientów i wzorów.

- 45/141 -

Page 46: SVG

<defs> <linearGradient id="MyGradient1" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stop-color="#00FF00"/><stop offset="100%" stop-color="#0000FF"/></linearGradient> <radialGradient id="MyGradient2" gradientUnits="userSpaceOnUse" cx="190" cy="120" r="80" fx="190" fy="120"><stop offset="0%" stop-color="yellow"/><stop offset="100%" stop-color="red"/></radialGradient> <linearGradient id="MyGradient3" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stop-color="dodgerblue"/><stop offset="100%" stop-color="purple"/></linearGradient> <pattern id="MyPattern1" patternUnits="userSpaceOnUse" x="0" y="0" width="10" height="10" viewBox="0 0 10 10"><path d="M 0 4 L 10 0 L 6 10 z" fill="red" stroke="black"/><path d="M 0 4 L 6 10 L 0 10 z" fill="yellow" stroke="black"/><path d="M 10 0 L 6 10 L 10 10 z" fill="lightgreen" stroke="black"/></pattern> </defs><path d="M -50 230 Q 100 10 200 170 T 480 30" fill="none" stroke="gold" stroke-width="120" stroke-linecap="square" stroke-opacity="0.3"/><text x="50" y="275" font-family="Verdana" font-size="112" font-weight="bold" fill="url(#MyGradient1)" stroke-dasharray="9,4" stroke="black" stroke-width="2">SVG</text><path d="M 20 270 Q 40 120 150 50 T 320 190 T 380 30" fill="none" stroke="url(#MyGradient3)" stroke-width="15"stroke-linecap="square"/><ellipse cx="45" cy="65" rx="30" ry="50" fill="url(#MyPattern1)" stroke="brown" stroke-width="5" fill-opacity="0.2" stroke-dasharray="2,1" stroke-opacity="0.2"/><ellipse cx="330" cy="65" rx="30" ry="50" fill="url(#MyPattern1)" stroke="brown" stroke-width="5" fill-opacity="0.8" stroke-dasharray="2,1"/><circle cx="190" cy="100" r="40" stroke-width="5" fill="url(#MyGradient2)" stroke="darkgreen"/><circle cx="155" cy="135" r="40" stroke-width="5" fill="url(#MyGradient2)" stroke="darkred"/><circle cx="215" cy="135" r="40" stroke-width="5" fill="url(#MyGradient2)" stroke="darkblue"/>

Rys.3.8. Kod źródłowy obrazu SVG, przedstawionego na rysunku 3.7.

- 46/141 -

Page 47: SVG

3.2.6. Podsumowanie najważniejszych możliwości

W rozdziale tym starałem się przedstawić najważniejsze z możliwości

oferowanych przez standard SVG. Znalazło się wśród nich wykreślanie

podstawowych kształtów, wyświetlanie tekstu na rysunku, wypełnianie oraz

ograniczanie obszarów, zarządzanie kolorami oraz stosowanie gradientów i

wzorów. Każde z zagadnień zostało poparte praktycznym przykładem, który

składał się z kodu źródłowego oraz podglądu wygenerowanego za

pośrednictwem przeglądarki internetowej obrazu. W następnym rozdziale

swojej pracy przyjrzę się bliżej bardziej zaawansowanym technikom SVG, nie

pomijając wyjaśnienia tak istotnych zagadnień jak filtry, interaktywność

elementów, hiperłącza, skrypty oraz animacje.

3.3. Zaawansowane właściwości SVG

Wśród zaawansowanych właściwości SVG, które są przedmiotem szczegółowej

analizy w niniejszym rozdziale, można odnaleźć kwestie związane z

maskowaniem, nakładaniem czy przycinaniem fragmentów rysunku,

zastosowaniem różnorodnych efektów filtrujących, opcjami interaktywności

poszczególnych elementów, możliwościami zastosowania hiperłączy w

odniesieniu do konkretnych składników grafiki, elementami umożliwiającymi

realizowanie animowanych sekwencji na rysunkach, a także sposobami

wykorzystania języków skryptowych do realizacji zadań związanych z obsługą

zdarzeń.

3.3.1. Maski oraz ścieżki maskujące

Zagadnienia maskowania są przedmiotem czternastego rozdziału

rekomendacji W3C. SVG oferuje użytkownikowi dwa podstawowe elementy

maskujące: ścieżki maskujące (ang. clipping paths) oraz maski (ang. masks).

Ścieżki maskujące składają się z dowolnej kombinacji podstawowych

- 47/141 -

Page 48: SVG

elementów SVG (ścieżek, kształtów, tekstu), które pełnią rolę ramki (ang.

outline) dla maski w ten sposób, że wszystko co znajduje się wewnątrz ramki

zostaje pokazane, natomiast reszta (wszystko co znajduje się na zewnątrz

ramki) nie. Z kolei maski są obiektami mogącymi zawierać dowolne elementy

graficzne, które zostają użyte jako półprzezroczysta maska, umożliwiająca

przede wszystkim komponowanie obiektów pierwszoplanowych do aktualnego

tła. Najważniejsze rozróżnienie pomiędzy ścieżkami maskującymi oraz

maskami polega na tym, że te pierwsze mogą znajdować się tylko w jednym z

dwóch stanów: albo całkowitej przezroczystości, albo całkowitej

nieprzezroczystości. Maski natomiast zawierają obraz, w którym każdy

pojedynczy piksel może być determinowany przez inny stopień

przezroczystości.

Ścieżkę maskującą definiuje się za pomocą elementu <clipPath>. Jego

elementami potomnymi mogą być tylko następujące obiekty: ścieżki <path>,

napisy <text>, podstawowe kształty (np. <rect>), a także elementy

<use>, które mogą odwoływać się jedynie do tych trzech rodzajów

wymienionych obiektów. Każdy element graficzny SVG może odwoływać się

do ścieżki maskującej poprzez atrybut clip-path. Wartością tego atrybutu

może być none (brak maskowania) lub odwołanie URI do obiektu w ramach

tego samego dokumentu SVG, który będzie pełnił rolę ścieżki maskującej.

Każdy obiekt graficzny w SVG może zostać użyty jako maska do

wkomponowania innego obiektu w tło rysunku. Do definiowania maski służy

element <mask>. Odwołujemy się do niej za pomocą tak samo nazwanego

atrybutu mask. Przykłady zastosowania obu metod maskowania można

zobaczyć na rysunku 3.9. Przedstawiono na nim między innymi napis

maskowany za pomocą gradientu. Na rysunku jako pierwszy rysowany jest

jasnozielony prostokąt. Następnie nanoszony jest na niego napis SVG,

zawierający odwołanie do wcześniej zdefiniowanej maski. Tekst zostaje

- 48/141 -

Page 49: SVG

wypisany w kolorze ciemnozielonym (widać to dobrze w kodzie źródłowym po

wartości atrybutu wypełnienia: fill="darkgreen"), ale zostaje do niego

zaaplikowana maska zawierająca definicję gradientu przezroczystości (atrybut

odwołania do maski w kodzie źródłowym: mask="url(#Mask1)").

Rys.3.9. Rysunek SVG prezentujący zastosowanie różnych technikmaskowania (dla ułatwienia rozpoznania ścieżki maskującej, narysowane

zostały zarówno kontury tej ścieżki, jak i wypełniony został oryginalny kształtnie zamaskowanego obiektu) oraz dwóch przykładowych filtrów feTurbulence

i feComponentTransfer.

Dzięki temu lewa strona napisu jest prawie niewidoczna (całkowicie zlewa się

z kolorem tła, ponieważ maska jest w tym miejscu nieprzezroczysta),

natomiast prawa strona posiada dokładnie taki kolor jak zdefiniowano w

elemencie <text> (jest dobrze widoczna, ponieważ w tym miejscu maska

- 49/141 -

Page 50: SVG

jest całkowicie przezroczysta). Kod źródłowy tego dokumentu SVG został

zamieszczony na rysunku 3.10.

<defs> <clipPath id="MyClip1"><path d="M 20 20 L 250 50 L 180 160 Z" clip-rule="evenodd"/></clipPath> <linearGradient id="Gradient1"><stop offset="10%" stop-color="white" stop-opacity="0"/><stop offset="90%" stop-color="white" stop-opacity="1"/></linearGradient> <mask id="Mask1"><rect x="160" y="180" width="220" height="100" fill="url(#Gradient1)"/></mask> <filter id="Turbulence1"><feTurbulence type="turbulence" baseFrequency="0.05" numOctaves="5"/></filter> <filter id="ComponentTransfer1"><feComponentTransfer><feFuncR type="linear" slope=".25" intercept=".25"/><feFuncG type="linear" slope=".50" intercept=".25"/><feFuncB type="linear" slope=".75" intercept=".50"/></feComponentTransfer></filter></defs><rect clip-path="url(#MyClip1)" x="20" y="30" width="220" height="100" fill="goldenrod"/><rect x="160" y="180" width="220" height="100" fill="lightgreen"/><text x="270" y="265" font-family="Verdana" font-weight="bold" font-size="96" text-anchor="middle" fill="darkgreen" mask="url(#Mask1)">SVG</text><rect x="30" y="161" width="100" height="108" filter="url(#Turbulence1)"/><ellipse cx="325" cy="90" rx="55" ry="70" fill="url(#Gradient1)" filter="url(#ComponentTransfer1)"/>

Rys.3.10. Kod źródłowy obrazu SVG, przedstawionego na rysunku 3.9.

3.3.2. Efekty graficzne

Kolejną bardzo cenną właściwością grafiki SVG jest możliwość zastosowania

różnorodnych filtrów, pozwalających na generowanie niezwykle wyszukanych

efektów. Filtry oferowane przez SVG są zwykle dostępne w zaawansowanych

programach graficznych, co czyni je jednymi z najpotężniejszych narzędzi

- 50/141 -

Page 51: SVG

wchodzących w skład tego standardu. Rozdział piętnasty specyfikacji,

poświęcony właśnie filtrom, jest bardzo rozbudowany i szczegółowo omawia

zastosowanie każdego z dostępnych efektów, zawiera również kody źródłowe

prezentujące przykładowe ich wykorzystanie.

Standardowo działanie filtru polega na wykonaniu określonych operacji na

źródle danych i wytworzeniu na ich podstawie nowych danych wyjściowych,

które stanowią ich modyfikację. Dokładnie tak samo funkcjonują filtry w SVG,

przy czym danymi źródłowymi są tu dane grafiki (od pojedynczego elementu

aż po grupy obiektów), natomiast wyjściem filtru jest obraz, jaki otrzymuje na

ekranie swojego monitora użytkownik końcowy.

Filtry definiowane są za pomocą elementu <filter>. Aby dany efekt został

zastosowany do wybranego obiektu, należy ustawić wartość jego atrybutu

filter tak, aby wskazywała na identyfikator zdefiniowanego wcześniej

filtru.

Każdy filtr zawiera zbiór prymitywów (ang. filter primitives), z których każdy

może być jednym z jego elementów podrzędnych. Każdy prymityw wykonuje

na danych wejściowych jedną fundamentalną operację graficzną, np.

rozmycie (ang. blur) lub efekt oświetlenia (ang. lighting effect), w wyniku

której uzyskuje się wyjściowe dane graficzne.

Dwa przykłady zastosowania filtrów zostały przedstawione na rysunku 3.9,

natomiast kod źródłowy prezentujący sposób ich definiowania został

zamieszczony na rysunku 3.10.

Szczegółowa analiza wszystkich prymitywów wykracza poza ramy tej pracy.

Niemniej jednak chciałbym pokrótce wymienić ich kompletną listę wraz z

krótka charakterystyką uzyskiwanych w ich rezultacie efektów, aby odnieść

się do postawionej wcześniej tezy, że filtry są jednymi z najpotężniejszych

narzędzi oferowanych przez standard SVG. Oto pełna lista opisanych w

rekomendacji prymitywów filtrów:

- 51/141 -

Page 52: SVG

feBlend: prymityw nakłada dwa obiekty na siebie, używając jednego z

popularnych trybów mieszania obrazów (ang. image blending mode)

feColorMatrix: prymityw aplikuje matrycę transformacji do każdego

piksela wejściowej grafiki, w rezultacie której otrzymujemy nowy zbiór

kolorów w zapisie RGBA

feComponentTransfer: prymityw wykonuje odwzorowanie danych

składowych koloru dla każdego piksela, umożliwiając operacje takie jak

korekta jasności, regulacja kontrastu, balans kolorów czy progowanie

(ang. thresholding)

feComposite: prymityw dokonuje połączenia dwóch obrazów na

poziomie pojedynczych pikseli

feConvolveMatrix: prymityw zastosowania matrycy splotu łączy ze

sobą sąsiednie piksele, aby wytworzyć obraz wynikowy; poprzez splot

można uzyskać wiele interesujących efektów graficznych takich jak

rozmycie, detekcja krawędzi (ang. edge detection), wyostrzanie (ang.

sharpening), gofrowanie (ang. embossing) czy ukosowanie (ang.

beveling)

feDiffuseLighting: prymityw oświetla rysunek wykorzystując kanał

przezroczystości (ang. alpha channel) do mapowania wypukłości (ang.

bump map); obliczenia są zgodne ze standardem odbicia światła w

modelu oświetlenia Phonga; w rezultacie działania filtru uzyskiwany jest

obraz nieprzezroczysty

feDisplacementMap: prymityw wykorzystuje wartości pikseli z

rysunku podanego jako wartość atrybutu in2 do przestrzennego

przesunięcia (ang. spatial displacement) obrazu z in

feFlood: prymityw tworzy prostokąt wypełniony kolorem podanym w

- 52/141 -

Page 53: SVG

atrybucie flood-color oraz przezroczystością podaną w atrybucie

flood-opacity

feGaussianBlur: prymityw realizuje rozmycie gaussowskie (ang.

Gaussian blur)

feImage: prymityw odwołuje się do zewnętrznej grafiki (którą może być

obraz rastrowy lub rysunek SVG)

feMerge: prymityw nakłada na siebie kolejne warstwy rysunków

(„jedna nad drugą”) podanych jako jego argumenty wejściowe

feMergeNode: prymityw nakładający nową warstwę rysunku

feMorphology: prymityw wykonuje „pogrubianie” (ang. fattening) lub

„odchudzanie” (ang. thinning) rysunku; jest przydatny w szczególności w

odniesieniu do kanału przezroczystości

feOffset: prymityw przesuwa (ang. offset) wejściowy rysunek

względem jego bieżącej pozycji w przestrzeni obrazu (ang. image space)

o określony wektor; jest on szczególnie przydatny do generowania

efektów takich jak rzucanie cienia (ang. drop shadow)

feSpecularLighting: prymityw oświetla rysunek wykorzystując kanał

przezroczystości do mapowania wypukłości; obliczenia są zgodne ze

standardem odbicia światła w modelu oświetlenia Phonga; w rezultacie

działania filtru uzyskiwany jest obraz przezroczysty

feTile: prymityw wypełnia wskazany prostokąt powtarzalnym wzorem,

którym jest rysunek, podany jako parametr wejściowy filtru

feTurbulence: prymityw tworzy rysunek na podstawie funkcji

turbulencji Perlina, umożliwiającej generowanie sztucznych tekstur

przypominających wyglądem chmury, marmur, itp.

feDistantLight: prymityw definiujący kierunkowe źródło światła

- 53/141 -

Page 54: SVG

fePointLight: prymityw definiujący punktowe źródło światła

feSpotLight: prymityw definiujący reflektorowe źródło światła

feFuncR: funkcja przenoszenia (ang. transfer function) dla czerwonego

komponentu wejściowej grafiki

feFuncG: funkcja przenoszenia dla zielonego komponentu wejściowej

grafiki

feFuncB: funkcja przenoszenia dla niebieskiego komponentu wejściowej

grafiki

feFuncA: funkcja przenoszenia dla komponentu przezroczystości (ang.

alpha component) wejściowej grafiki

Na podstawie powyższej listy jesteśmy w stanie śmiało stwierdzić, że

rzeczywiście za pomocą filtrów możemy definiować niezwykle wyrafinowane

efekty graficzne, dzięki którym nasze obrazy nie muszą w niczym ustępować

wymyślnym rysunkom stworzonym w zaawansowanych edytorach

graficznych.

3.3.3. Interaktywność

Elementy SVG mogą być interaktywne, tzn. mogą reagować na zdarzenia

inicjowane przez użytkownika, dzięki następującym właściwościom:

inicjowane przez użytkownika akcje, takie jak na przykład wciśnięcie

lewego przycisku myszy, mogą spowodować rozpoczęcie wykonywania

animacji lub skryptów

użytkownik ma możliwość inicjować hiperłącza do innych stron

internetowych poprzez takie działania jak kliknięcie lewego przycisku

myszy nad konkretnym elementem grafiki

w wielu przypadkach (zależy to od możliwości przeglądarki internetowej

- 54/141 -

Page 55: SVG

jak i od ustawień atrybutu zoomAndPan w elemencie głównym <svg>)

użytkownik jest w stanie powiększać oraz przesuwać obraz SVG

ruchy myszą mogą powodować zmianę wyglądu wskaźnika (ang.

pointing device)

Rozdział szesnasty rekomendacji W3C szczegółowo opisuje informacje na

temat dostępnych zdarzeń (łącznie z warunkami definiowanymi za pomocą

atrybutu pointer-events, które muszą być spełnione, aby dane zdarzenie

mogło zostać wywołane), sposobu sprawdzenia czy dany dokument może być

powiększany oraz przesuwany (ang. panned), jak również sposobu wyboru

bieżącego wskaźnika myszy (wraz z listą dostępnych wartości

przekazywanych poprzez atrybut cursor).

3.3.4. Hiperłącza

Do definiowania każdego rodzaju łącz SVG korzysta ze standardu XLink. W

rozdziale siedemnastym specyfikacji zostały omówione łącza zewnętrzne,

które tworzy się za pomocą podobnego jak w języku HTML elementu <a>.

Służy on do wskazywania innych elementów, które będą stanowić hiperłącze.

Przykładowy kod łącza do zewnętrznego zasobu sieciowego przedstawiono na

rysunku 3.11. W tym przykładzie wykreślony zostaje prostokąt. Po kliknięciu

na nim użytkownik przechodzi na internetową stronę wyszukiwarki Google.

Hiperłącze może jednak wskazywać na dowolny inny zasób sieciowy, np.

rysunek, film, program, inny dokument SVG, stronę HTML i inne.

<a xlink:href="http://www.google.pl"> <rect x="0" y="0" width="10" height="10" fill="green"/></a>

Rys.3.11. Kod źródłowy łącza do zewnętrznego zasobu sieciowego.

- 55/141 -

Page 56: SVG

3.3.5. Możliwości zastosowania języków skryptowych

W rozdziale osiemnastym rekomendacji opisano reguły pisania skryptów oraz

zestawiono atrybuty dostępnych zdarzeń. Domyślnym językiem skryptowym

dla dokumentów SVG jest ECMAScript. Zmiany języka można dokonać

redefiniując atrybut contentScriptType w elemencie głównym <svg>

(domyślną wartością tego atrybutu jest text/ecmascript). Oczywiście

można również określić język skryptowy indywidualnie dla każdego elementu

<script>, ustawiając jego atrybutu type.

     

Rys.3.12. Rysunek SVG prezentujący wykorzystanie skryptu ECMAScript dotworzenia interaktywnych obrazów (po lewej stronie przedstawiono

oryginalny rysunek, natomiast po prawej obraz zmodyfikowany po kliknięciuprzyciskiem myszy na prostokącie).

Element <script> w SVG odpowiada takiemu samemu elementowi z języka

- 56/141 -

Page 57: SVG

HTML. Każda funkcja zdefiniowana wewnątrz tego elementu ma zasięg

globalny w odniesieniu do całego dokumentu SVG. Przykład wykorzystania

skryptu ECMAScript zamieszczono na rysunku 3.12. Przedstawia on prostokąt,

na który należy kliknąć przyciskiem myszy, aby zmienić jego rozmiar oraz

kolor. Na rysunku zaprezentowano obie fazy działania skryptu: przed oraz po

kliknięciu. Kod źródłowy można zobaczyć na rysunku 3.13. W skrypcie

zdefiniowano funkcję onRectClick, która zostaje wywołana przez zdarzenie

onclick, skojarzone z elementem <rect>. To właśnie w niej dokonują się

modyfikacje atrybutów prostokąta. Dodatkowo przy przesuwaniu myszy nad

prostokątem, wskaźnik zmienia wygląd ze strzałki na dłoń z wysuniętym

palcem wskazującym (ustawienie atrybutu cursor="pointer"), co

sugeruje użytkownikowi możliwość wywołania jakiejś akcji po kliknięciu na

obiekt.

<script type="text/ecmascript"><![CDATA[ function onRectClick( evt ) { var myRect = evt.target; if( myRect.getAttribute("x") == 70 ) { myRect.setAttribute( "x", 30 ); myRect.setAttribute( "width", 340 ); myRect.setAttribute( "y", 150 ); myRect.setAttribute( "height", 250 ); myRect.setAttribute( "fill", "purple" ); } else { myRect.setAttribute( "x", 70 ); myRect.setAttribute( "width", 260 ); myRect.setAttribute( "y", 50 ); myRect.setAttribute( "height", 450 ); myRect.setAttribute( "fill", "green" ); } }]]></script><rect x="70" y="50" width="260" height="450" fill="darkgreen" onclick="onRectClick(evt)" cursor="pointer"/>

Rys.3.13. Kod źródłowy obrazu SVG, przedstawionego na rysunku 3.12.

- 57/141 -

Page 58: SVG

3.3.6. Animacje

Na zakończenie szczegółowej analizy możliwości grafiki SVG przedstawię

najistotniejsze informacje dotyczące animacji, której poświęcony został w

całości dziewiętnasty rozdział rekomendacji W3C. Specyfikacja definiuje

animację w SVG jako dynamiczną zmianę grafiki wektorowej w czasie.

Animację można zrealizować na jeden z trzech poniższych sposobów:

korzystając z przeznaczonych do tego elementów animacji, np.

<animate>

Używając umiejętnie elementów animacji można tworzyć ruchome

ścieżki (ang. motion paths), efekty rozjaśniające i zaciemniające obraz

oraz obiekty, które rosną, kurczą się, obracają lub zmieniają kolor.

korzystając z obiektowego modelu dokumentu SVG DOM, np. w

skryptach

Każdy atrybut oraz każdy styl dokumentu SVG jest dostępny w

skryptach. SVG posiada dodatkowe interfejsy DOM, umożliwiające

efektywne tworzenie animacji za pomocą skryptów. Dzięki nim można

uzyskać praktycznie każdy możliwy rodzaj animacji.

SVG został zaprojektowany w taki sposób, aby umożliwić przyszłym

wersjom języka SMIL (Synchronized Multimedia Integration Language

– język opisu prezentacji multimedialnych korzystający z techniki XML)

wykorzystanie obrazów SVG jako komponentów multimedialnych.

SVG oferuje użytkownikowi cztery elementy animacji opisane w

specyfikacji SMIL: <animate> (modyfikuje wartości atrybutów oraz

właściwości w określonym czasie), <set> (synonim elementu

<animate>, wygodny w sytuacjach, gdy opisujemy animację poprzez

zmianę wartości atrybutów nienumerycznych), <animateMotion>

(przesuwa element wzdłuż ruchomej ścieżki), <animateColor>

- 58/141 -

Page 59: SVG

(modyfikuje kolor wybranego atrybutu w określonym czasie).

Dodatkowo w standardzie zdefiniowano kilka innych elementów,

stanowiących rozszerzenie w stosunku do animacji SMIL.

Na rysunku 3.14 przedstawiono prostą animację. W czasie kilku sekund żółte

koło przesuwane jest od lewej do prawej części ekranu. Ten sam efekt

animacji można uzyskać na kilka sposobów. Na rysunku 3.15 przedstawiono

kod źródłowy zbudowany w oparciu o obiektowy model dokumentu oraz

wykorzystanie języka skryptowego ECMAScript. Identyczny efekt daje

zastosowanie standardowych elementów animacji języka SVG (w tym

przypadku elementu <animate>), którego kod źródłowy można zobaczyć na

rysunku 3.16. W pierwszym przypadku kod jest dużo bardziej rozbudowany,

jednak z drugiej strony daje nam lepszą kontrolę i większą swobodę

manipulacji dokumentem SVG. Decyzja o wyborze metody animacji zależy od

konkretnego przypadku. Wydaje się jednak, że do wykonania prostych

animacji wystarczy zastosowanie podstawowych elementów (łatwiej wtedy

zrozumieć całość dokumentu), z kolei przy bardziej rozbudowanych

projektach skrypty dają większe możliwości napisania uporządkowanego i

przejrzystego kodu.

     

Rys.3.14. Rysunek przedstawiający prostą animację zrealizowaną za pomocągrafiki SVG.

- 59/141 -

Page 60: SVG

<svg onload="animate(evt)" xmlns="http://www.w3.org/2000/svg" version="1.1"> <script type="text/ecmascript"><![CDATA[ var circle; var min_x = 0; var max_x = 500; var x = min_x; var speed = .1; function animate( evt ) { if( window.svgDocument == null ) svgDocument = evt.target.ownerDocument; circle = svgDocument.getElementById( "myCircle" ); setTimeout( "advance()", speed ); } function advance() { ++x; if( ++x > max_x ) x = min_x; circle.setAttributeNS( null, "cx", x - 50 ); setTimeout( "advance()", speed ); } ]]></script> <circle id="myCircle" cx="-100" cy="120" r="50" stroke="black" stroke-width="5" fill="yellow"/></svg>

Rys.3.15. Kod źródłowy animacji SVG, przedstawionej na rysunku 3.14,zrealizowany w oparciu o obiektowy model dokumentu DOM oraz skrypt

ECMAScript.

<circle id="myCircle" cx="-100" cy="120" r="50" stroke="black" stroke-width="5" fill="yellow"> <animate attributeName="cx" from="-50" to="450" dur="6s" repeatCount="indefinite"/></circle>

Rys.3.16. Kod źródłowy animacji SVG, przedstawionej na rysunku 3.14,zrealizowany w oparciu o standardowy element animacji <animate>.

3.4. Podsumowanie

Trzeci rozdział pracy dyplomowej w całości zdecydowałem się poświęcić

starannej analizie grafiki SVG. Wierzę, że skutecznie przedstawiłem w nim

- 60/141 -

Page 61: SVG

wszystkie najważniejsze informacje, pozwalające czytelnikowi niniejszego

opracowania na wystarczająco dogłębne przyjrzenie się możliwościom

dyskutowanego standardu.

W treści pracy zawarte zostały zarówno podstawowe informacje na temat grafiki

SVG, jak i zagadnienia bardziej szczegółowe. Większość omawianych

właściwości starałem się poprzeć praktycznymi przykładami, prezentując

zarówno gotowy rysunek tak jak wygląda on w oknie przeglądarki internetowej,

jak i kompletny kod źródłowy, który posłużył do jego wygenerowania.

Wiedzę teoretyczną pozyskaną z lektury rekomendacji W3C uzupełniłem w tym

rozdziale umiejętnościami jej praktycznego wykorzystania oraz własną

pomysłowością, pozwalającą na stworzenie czytelnych i przejrzystych

przykładów, które mam nadzieję dały klarowny obraz najważniejszych

możliwości oferowanych twórcom grafiki przez standard SVG.

Na zakończenie niniejszego rozdziału chciałbym pokrótce nawiązać do faktu, iż

SVG jest aplikacją XML i zasygnalizować wiążące się z tym konsekwencje, by

wreszcie w kilku krótkich zdaniach przedstawić widoki rozwoju standardu w

przyszłości, kierunki proponowanych zmian oraz dyskutowane na bieżąco przez

SVG Working Group pomysły na implementację nowych funkcjonalności.

3.4.1. SVG a XML

Bardzo ważnym elementem, na który chciałbym zwrócić uwagę na

zakończenie tego rozdziału jest wyraźne podkreślenie faktu, że SVG jest

aplikacją XML. Ma to swoje bardzo pozytywne konsekwencje. Umożliwia nam

między innymi zagnieżdżanie dokumentów SVG w obrębie innych przestrzeni

nazw XML i vice versa: plik SVG również może zawierać w sobie dokumenty

przygotowane w innych językach XML.

Dokumenty SVG są zwykłymi plikami tekstowymi, a co za tym idzie mogą być

edytowane bezpośrednio w najprostszym edytorze tekstu. Oczywiście nic nie

- 61/141 -

Page 62: SVG

stoi na przeszkodzie, aby tworzyć skomplikowane dokumenty SVG właśnie w

ten sposób. Na szczęście istnieją znacznie wygodniejsze sposoby ich

generowania, między innymi specjalizowane edytory graficzne dedykowane

grafice wektorowej i standardowi SVG.

Pomimo możliwości wykorzystania zaawansowanych aplikacji graficznych do

edycji grafiki SVG, bardzo często może okazać się, iż w przypadku prostych

zadań ich zastosowanie będzie wytaczaniem armat na muchy. Standard XML

daje nam tę fantastyczną możliwość niezwykle szybkiego i efektywnego

tworzenia dokumentów, iż grzechem byłoby z niej nie skorzystać, gdy wydaje

się nam to najodpowiedniejszym rozwiązaniem. Większość zadań

praktycznych, opisanych w niniejszej pracy, wykonałem bez wykorzystania

żadnego specjalistycznego oprogramowania, najczęściej natomiast przy

użyciu prostego edytora tekstu, którego największym atutem było

kolorowanie składni XML. To mocny dowód na to, że edycja dokumentów SVG

jest niezwykle prosta, bardzo często intuicyjna i najczęściej nie wymagająca

dużych nakładów pracy (oczywiście w przypadku zaawansowanych projektów

poziom skomplikowania struktury dokumentu SVG wzrasta, jednak nawet

wtedy edycja pliku w zwykłym edytorze tekstu jest nadal możliwa, głównie

dzięki jasnej i przejrzystej składni samego języka).

Z mojego punktu widzenia jako programisty niezwykle cenną i chyba

najważniejszą konsekwencją faktu, że pliki SVG są zwykłymi plikami

tekstowymi, jest to, że ich przetwarzanie jest niezwykle szybkie i wygodne.

Dostęp do danych składowanych w pliku tekstowym nie wymaga

zastosowania żadnych wyspecjalizowanych interfejsów i jest tak samo łatwy

do zrealizowania w dowolnym języku programowania.

Biorąc pod uwagę ogromną popularność oraz rozpowszechnienie standardu

XML (nie tylko w sieci Internet), istnieje możliwość wykorzystania jednego z

wielu narzędzi wspomagających przetwarzanie dokumentów opracowanych

- 62/141 -

Page 63: SVG

zgodnie z regułami tworzenia języków XML, a więc również SVG.

Bezcenny dla programistów jest również bezpośredni dostęp do kodu

źródłowego każdego stworzonego dokumentu SVG – analiza gotowych

przykładów zawsze stanowić będzie najlepsze źródło pozyskiwania wiedzy w

czasie nauki programowania. Tutaj jest ona na wyciągnięcie ręki (chociaż

może się to zmienić od wersji 2.0 standardu: SVG Working Group analizuje

możliwości ukrywania kodu źródłowego SVG przed przeglądaniem). W

przypadku języków kompilowanych takiej możliwości w zasadzie nie mamy.

3.4.2. Kierunki rozwoju SVG: wersje 1.2 i 2.0

Chociaż standard SVG w wersji 1.1 zdążył już na dobre zadomowić się w

zbiorowej świadomości użytkowników sieci Internet, zarówno członkowie SVG

Working Group jak i indywidualni użytkownicy wciąż dostrzegają pewne jego

niedociągnięcia. Eliminację tych niedostatków ma zapewnić wersja 1.2

standardu, nad którą prace trwają już od kilku lat i która ma obecnie status

wydania roboczego (ang. working draft).

Standard SVG w wersji 2.0 nie posiada jeszcze statusu gotowego dokumentu,

niemniej jednak nieustannie gromadzone są dla niego nowe wymagania [16],

ponieważ ciągle istnieje zapotrzebowanie na nowe funkcjonalności, których

implementacja nie została zaplanowana dla wcześniejszych wersji.

Pomijając tak oczywiste kwestie jak zachowanie kompatybilności wstecz

kolejnych wersji standardu, chciałbym wymienić poniżej kilka z ciekawszych,

spośród wielu proponowanych w kolejnych wersjach, udoskonaleń. Niektóre z

nich opatrzyłem przymiotnikiem „możliwe”, co oznacza, że ich wprowadzenie

nie jest na obecnym etapie projektowania standardu wymagane, jakkolwiek

bardzo poważnie rozważane. Wprowadzenie pozostałych wymienionych

funkcjonalności jest pożądane i konieczne.

Jeżeli chodzi o cechy (ang. feature) typowo graficzne proponowane są między

- 63/141 -

Page 64: SVG

innymi następujące ulepszenia (w nawiasie podaję wersję standardu, w której

proponowane udoskonalenia miałyby się znaleźć):

Możliwe rozszerzenie zbioru predefiniowanych podstawowych kształtów

(o np. łuk, spiralę, gwiazdę, wielokąty foremne) oraz dodanie nowych

atrybutów do już istniejących kształtów (np. kąt obrotu elipsy) (SVG 2.0)

Możliwe definiowanie punktów, a następnie odwoływanie się do nich w

trakcie definiowania figur za pomocą kształtów lub ścieżek (SVG 2.0)

Możliwe utworzenie zbioru predefiniowanych pól kontrolnych interfejsu

użytkownika (ang. user interface controls), które mogą być użyte

podczas interakcji ze stroną WWW, takich jak przyciski (ang. buttons)

czy pola tekstowe (ang. text fields) (SVG 1.2)

Możliwe wyjustowanie tekstu (ang. text justification) w ramach

określonego kształtu (SVG 2.0)

Dostarczenie parametru pozwalającego na określenie sposobu obsługi

białych znaków (ang. whitespaces) (SVG 2.0)

Utworzenie nowego elementu definiującego kolor, do którego można

odwoływać się dokładnie w taki sam sposób, w jaki obecnie odwołuje

się do gradientów oraz wzorów (SVG 1.2)

Możliwe utworzenie nowych typów gradientów, np. stożkowy (ang.

conical), prostokątny (ang. rectangular), cieniowanie Gourauda (ang.

Gouraud shading) i inne (SVG 2.0)

Możliwe utworzenie mechanizmu umożliwiającego określanie kolejności

renderowania elementów, np. przez zastosowanie atrybutu z-index

(SVG 2.0)

Możliwe wprowadzenie koncepcji warstw (ang. layers), ułatwiające

grupowanie elementów (SVG 2.0)

- 64/141 -

Page 65: SVG

Wśród pozostałych cech standardu możemy odnaleźć propozycje między

innymi następujących udoskonaleń:

Zaznaczanie oraz wybieranie nie tylko elementów tekstowych, ale

również elementów graficznych (SVG 2.0)

Opracowanie mechanizmów umożliwiających przesyłanie strumieniowe

(ang. streaming) animacji (SVG 2.0)

Wyzwalanie dynamicznej zawartości na podstawie poziomu

powiększenia (ang. zoom level) oraz pozycji podglądu (ang. location of

the viewport) (SVG 2.0)

Możliwe zaimplementowanie mechanizmów umożliwiających obsługę

dokumentów zawierających dodatkową informację o poziomie

szczegółowości (ang. level of detail), takich jak np. mapy (SVG 2.0)

Możliwe zaimplementowanie mechanizmów zapewniających ochronę

kodu źródłowego, uniemożliwiających dostęp do treści dokumentu (SVG

2.0)

Ważny wniosek, jaki płynie z analizy tego częściowego przeglądu

proponowanych przez SVG Working Group zmian dla kolejnych wersji, jest

taki, że standard SVG nie wymaga obecnie żadnych dramatycznych zmian.

Jego koncepcja została bardzo starannie przemyślana i trudno znaleźć w jego

specyfikacji znaczące uchybienia. Poza pewnymi dodatkami, które ułatwią

tworzenie grafiki, nie jest potrzebna żadna zasadnicza ingerencja w obecny

kształt standardu.

Koncepcyjnie standard SVG praktycznie już teraz osiągnął status języka

kompletnego, chciałoby się rzec gotowego. Opracowano go bardzo starannie i

chociaż, jak każdy projekt, nie jest on pozbawiony pewnych wad i

niedociągnięć, to jest on na pewno standardem bardzo dobrym. Z kolei o

tym, że nie jest to standard martwy, świadczą ciągłe propozycje jego

- 65/141 -

Page 66: SVG

udoskonalania.

Kolejne wersje standardu SVG znajdują się obecnie w fazie projektowej. Minie

zapewne jeszcze kilka lat (a na pewno co najmniej kilka miesięcy) zanim ujrzą

one światło dzienne. Spowodowane jest to przede wszystkim faktem, iż

proponowane poprawki nie wnoszą do całości projektu rewolucyjnych zmian,

a zatem nie ma istotnych nacisków na ich niezwłoczną publikację.

Jestem przekonany, że SVG funkcjonować będzie w obecnym kształcie jeszcze

przez wiele lat. Jednocześnie żywię nadzieję, iż zyska on z czasem coraz

większą popularność, na którą z całą pewnością zasługuje.

- 66/141 -

Page 67: SVG

4. Praktyczna realizacja przykładowych aplikacji

W czwartym rozdziale pracy dyplomowej chciałbym przedstawić kilka praktycznych

przykładów wykorzystania grafiki SVG. W poprzedzających rozdziałach zestawiłem

podstawową wiedzę teoretyczną niezbędną do zrozumienia istoty funkcjonowania

grafiki SVG. Poszerzyłem ją o swoje własne wnioski oraz analizy dotyczące

możliwości jej wykorzystania. W tym miejscu chciałbym zaprezentować płaszczyznę

stanowiącą pomost pomiędzy teorią oraz praktyką. W dalszej części rozdziału

zamierzam przedstawić kilka konkretnych realizacji aplikacji, które stanowią

praktyczną część mojej pracy i mają za zadanie prezentację wybranych

funkcjonalności analizowanego standardu poprzez konkretne przykłady ich

zastosowania.

Opisywane aplikacje zostały zrealizowane przy pomocy różnych technik, tak aby

nie ograniczać się tylko i wyłącznie do wybranych i ulubionych metod

programowania. Ma to na celu pokazanie, że z grafiką SVG można wygodnie

pracować na wielu platformach – część języków programowania oferuje

bezpośrednie wsparcie dla grafiki wektorowej, inne doskonale radzą sobie z

przetwarzaniem danych tekstowych. Twórca ma tutaj ogromną swobodę w

wyborze sposobu dostępu do danych graficznych. Korzystając z możliwości grafiki

SVG, sam może wybrać metodę tworzenia rysunków lub np. zdecydować, czy ich

zawartość powinna być statyczna czy też generowana dynamicznie.

4.1. Generator wykresów statystycznych

W kolejnych sekcjach pracy dyplomowej prezentuję szczegółowo najistotniejsze

elementy oraz przykładowe zastosowania swojej pierwszej praktycznej realizacji

aplikacji, wykorzystującej możliwości grafiki SVG, którą jest prosty generator

- 67/141 -

Page 68: SVG

wykresów statystycznych przygotowany w języku Perl. Najpierw staram się

dokonać krótkiej analizy przydatności wykresów w środowisku WWW, następnie

odnaleźć miejsce dla obrazów SVG w tej dziedzinie, by w końcu omówić

najistotniejsze korzyści, jakie płyną z ich zastosowania. W dalszej części

dokonuję technicznej analizy zrealizowanej aplikacji oraz prezentuję przykłady

jej wykorzystania.

4.1.1. Zastosowanie aplikacji

Wykresy statystyczne spotykamy w Internecie niemal na każdym kroku. Za

ich pomocą prezentowane są wyniki przeróżnych głosowań internetowych,

zestawień porównawczych i wielu innych. Aplikacje generujące wykresy mogą

znaleźć zastosowanie wszędzie tam, gdzie zachodzi potrzeba wizualizacji

porównania ze sobą kilku wielkości, która pozwoli na graficzne urozmaicenie

„suchego” opisu wyników.

Obecnie wykresy na stronach WWW nie są zamieszczane w formatach

wektorowych, najczęściej wykorzystywane są formaty rastrowe, takie jak JPG

czy PNG. Dyskusję o tym, która z tych metod jest lepsza, podejmuję w

kolejnych rozdziałach.

Do generacji wykresów w formacie SVG zdecydowałem się wykorzystać język

Perl, który świetnie nadaje się do przetwarzania tekstów. Pamiętamy, że SVG

jest aplikacją XML, co oznacza, że dokumenty w tym języku mogą być

tworzone za pomocą dowolnego edytora tekstu. Nic nie stoi na przeszkodzie,

aby ułatwić sobie zadanie i skorzystać z możliwości, jakie oferuje skryptowy

język programowania Perl.

4.1.2. Struktura dokumentu SVG

Przed przygotowaniem kodu źródłowego generatora wykresów, musiałem

- 68/141 -

Page 69: SVG

opracować strukturę dokumentu SVG, który miał posłużyć jako szablon

każdego tworzonego rysunku. W tym celu należało się zastanowić, w jaki

sposób najlepiej będzie odzwierciedlić dane rysunku w tekstowej strukturze

dokumentu XML-owego (przykładowe kody źródłowe już wygenerowanych

gotowych rysunków można przeglądać w rozdziałach 6.1.2 oraz 6.1.3,

bezpośrednie spojrzenie na ich budowę ułatwi zrozumienie opisu, który

kontynuuję w kilku kolejnych paragrafach).

W pierwszej kolejności określiłem wartości atrybutów, jakie powinien posiadać

korzeń dokumentu, tj. element <svg>. Najważniejszy atrybut to viewBox,

który pozwala na dynamiczne skalowanie obrazu po stronie klienta, w

zależności od rozmiarów okna jego przeglądarki WWW. Zdecydowałem się na

wykorzystanie tego atrybutu, ponieważ chciałem, aby rysunek wykresu mógł

być każdorazowo dynamicznie przeskalowany i w całości wypełnić okno

przeglądarki.

Następnie za pomocą dwóch elementów <path> definiowana jest ramka

wokół obrazu oraz kolor tła (atrybut fill). Warto zauważyć, że współrzędne

punktów końcowych ścieżki odpowiadają wymiarom rysunku zdefiniowanym

w elemencie <svg>. Te dane pozostają niezmienne dla każdego

generowanego rysunku. Pierwszym elementem, który je różni, jest tytuł

wykresu. Określam go w kolejnym elemencie SVG <text>.

W kolejnym kroku definiowane są dwa gradienty liniowe, które posłużą jako

wypełnienie poszczególnych elementów wykresu. Kolejnym fragmentem

danych jest definicja poziomej i pionowej osi wykresu oraz punktów

wyznaczających na niej kolejne wartości.

Ostatnią najważniejszą część grafiki stanowią kolejne elementy przedstawiane

na wykresie. Każdy element składa się z napisu obróconego o kąt 50 stopni

(transformacja <g transform="rotate(-50)">), oznaczającego nazwę

tego elementu, tekstu prezentującego osiąganą wartość oraz w końcu sam

- 69/141 -

Page 70: SVG

słupek wykresu. Efektowny wygląd słupka uzyskuje się dzięki wykorzystaniu

zdefiniowanego wcześniej w dokumencie kolorowego gradientu i

zastosowaniu go jako wypełnienie prostokąta ograniczającego słupek.

Powyższy krótki opis obejmuje projekt struktury dokumentu SVG. Bardzo

ważne jest, aby stanowił on kompletny model tego, co chcemy ostatecznie

uzyskać za pomocą generatora, ponieważ może okazać się, że ten dokument

będzie później przetwarzany przez inną aplikację (np. arkusz stylu XSLT).

W momencie gdy określono już, jaką strukturę powinien posiadać rysunek

SVG, można zastanowić się nad sposobami jego wygenerowania.

4.1.3. Moduł Perla do generowania wykresów

Za bardzo dobry sposób zbudowania podstaw swojej aplikacji uznałem

opracowanie niezależnego modułu w języku Perl, który spełniać będzie

wszystkie funkcje niezbędne do prostego oraz szybkiego generowania

wykresów. W tym miejscu muszę zaznaczyć dość istotny szczegół.

Mianowicie, zadaniem stworzonej aplikacji jest generacja grafiki na podstawie

wprowadzonych danych, nie jest natomiast żadną jej funkcją weryfikacja

poprawności tych danych. Logika generatora wykresów obejmuje wszystkie

funkcje związane z przetworzeniem wejściowych danych statystycznych w

obraz SVG, to co znajdzie się na tym obrazie już jej nie „interesuje”.

W związku z powyższym, jeśli użytkownik potrzebuje przykładowo

wygenerować wykres udziału procentowego głosów, jakie uzyskały partie

polityczne w wyborach powszechnych, to podając jako dane wejściowe dla

skryptu kolejne wyniki dające w sumie wartość większą niż 100%, nie

spowoduje on błędu działania skryptu. Moduł generatora wykresów wykona

takie przeskalowanie osi, aby odpowiadało ono wprowadzonym danym.

Weryfikacja poprawności tych danych musi odbywać się na wcześniejszym

etapie, ponieważ do obowiązków generatora nie należy analiza treści rysunku,

- 70/141 -

Page 71: SVG

lecz jego bezbłędna generacja. Użytkownik sam musi zapewnić załadowanie

prawidłowych danych do programu.

Moduł w Perlu pełni podobną funkcję, jaką pełni klasa w obiektowym języku

programowania, takim jak na przykład C++. Również tutaj mamy do

czynienia z enkapsulacją. Oznacza to, że użytkownik nie ingeruje

bezpośrednio w kod modułu, lecz korzysta z dostarczonych w nim i dobrze

udokumentowanych funkcji (w C++ metod). Swój moduł nazwałem

„ChartSVG”, aby jego nazwa jak najwierniej odzwierciedlała to, do czego służy

(generowanie wykresów w formacie SVG).

Do dyspozycji użytkownika zdecydowałem się udostępnić następujące

funkcje:

new – konstruktor nowego obiektu typu ChartSVG

set_y_desc – określenie nazwy oraz jednostki osi Y

add – dodanie nowego elementu wykresu

set_title – określenie tytułu całego wykresu

entries – sprawdzenie, ile elementów zostało wstawionych do

wykresu

show_all – wypisanie (na konsolę) listy elementów wstawionych do

wykresu

make_image – wygenerowanie dokumentu SVG na podstawie danych

przekazanych do egzemplarza obiektu

Pełny kod źródłowy modułu można odnaleźć w załączonym na końcu pracy

rozdziale 6.1.1. Na szczególną uwagę zasługuje tutaj funkcja make_image

(pozostałe funkcje nie wymagają wyczerpującego komentarza, gdyż nie

wykonują żadnych skomplikowanych operacji), która wykonuje całą pracę

generacji wykresu na podstawie danych, wstawionych do egzemplarza

- 71/141 -

Page 72: SVG

obiektu modułu ChartSVG. Warto zauważyć, że definicja tej funkcji

pozostawia „furtkę” do generowania zupełnie nowych typów wykresów,

chociaż w prezentowanej tu wersji zaimplementowano tylko jeden (wykres

słupkowy). Wywołanie funkcji make_image powoduje zapisanie na dysku

twardym komputera dokumentu w formacie SVG, zawierającego treść

rysunku, zgodną z danymi dostarczonymi do egzemplarza obiektu modułu.

W module ChartSVG określono dość znaczącą liczbę stałych, dzięki czemu

możliwe są jego szybkie modyfikacje dla własnych potrzeb. Sam moduł

korzysta również z kilku zmiennych, z których największe znaczenie ma

zmienna MAX_ENTRIES_ON_DIAGRAM, która określa maksymalną liczbę

słupków, które zostaną narysowane na wykresie. Jeżeli przykładowo

ustawimy tą zmienną na wartość 5, a funkcję add wywołamy trzykrotnie,

wówczas na wykresie otrzymamy trzy słupki. Ale jeśli funkcja add zostanie

wywołana 10 razy, a MAX_ENTRIES_ON_DIAGRAM jest równe 5, to

narysowane zostanie tylko pięć słupków. Zmienna ta pozwala ograniczyć

maksymalną dozwoloną liczbę słupków prezentowanych na wykresie.

Sam moduł zawiera około 250 linii kodu, czym udowadnia, że generowanie

grafiki SVG z poziomu Perla jest nie tylko bardzo proste, ale i bardzo szybkie.

Efekty działania modułu można oglądać na rysunkach 4.1 oraz 4.3.

W tym miejscu chciałbym zaprezentować dwa konkretne przykłady

wykorzystania przygotowanego wcześniej modułu. Jako pierwszy

przedstawiam kompletny kod, służący do wygenerowania wykresu

przedstawiającego porównanie liczby ludności w najludniejszych państwach

świata. Pełny kod źródłowy można przeglądać w dołączonym na końcu pracy

rozdziale 6.1.2, a jego skróconą wersję zamieściłem na rysunku 4.2. Z kolei

efekt działania tego kodu można zobaczyć na rysunku 4.1. Jak widać na tym

przykładzie, większą część kodu źródłowego stanowi wprowadzanie danych

do egzemplarza obiektu modułu ChartSVG. Dzięki temu, że przygotowany

- 72/141 -

Page 73: SVG

został przeze mnie ten właśnie moduł, generacja gotowego wykresu w

formacie SVG wymaga napisania zaledwie kilku linijek kodu w języku Perl.

Rys.4.1. Rysunek SVG zawierający wykres prezentujący liczbę ludności wnajludniejszych krajach świata, wygenerowany za pomocą modułu ChartSVG

(podgląd wykonany w przeglądarce „Opera”).

Warto zauważyć, że kolejność wprowadzanych danych nie ma większego

znaczenia, ponieważ w trakcie generowania wykresu zostają one

posortowane w kolejności malejącej (służy do tego wewnętrzna funkcja

modułu ChartSVG: sort_all), dzięki czemu użytkownik nie musi się

martwić, jeśli wprowadzane przez niego dane są nieuporządkowane.

W sposób analogiczny do poprzedniego przykładu generowany jest wykres

przedstawiający fikcyjne wyniki wyborów parlamentarnych w 2006 roku. Kod

źródłowy skryptu generującego plik SVG różni się tylko wartościami

przekazywanymi do kolejnych funkcji modułu ChartSVG. Pełny kod źródłowy

można przeglądać w dołączonym na końcu pracy rozdziale 6.1.3, a jego

- 73/141 -

Page 74: SVG

skróconą wersję zamieściłem na rysunku 4.4. Wynik działania tego skryptu

został przedstawiony na rysunku 4.3.

#!/usr/bin/perl

use ChartSVG;

$myChart = ChartSVG->new();$myChart->set_title( "LUDNOŚĆ PAŃSTW ŚWIATA" );$myChart->set_y_desc( "mln" );$myChart->add( "Chiny", 1306.3 );...$myChart->add( "Japonia", 127.4 );

$myChart->make_image( "kraje.svg", "BAR" );

Rys.4.2. Skrócony kod źródłowy programu służącego do wygenerowaniawykresu przedstawiającego porównanie liczby ludności w najludniejszychpaństwach świata w oparciu o moduł Perla „ChartSVG” (pominięto kilka

podobnych wierszy, wstawiających do egzemplarza obiektu klasy ChartSVGdane o kolejnych państwach; pełny kod źródłowy skryptu w rozdziale 6.1.2).

Rys.4.3. Rysunek SVG zawierający wykres prezentujący fikcyjne wynikiwyborów parlamentarnych, wygenerowany za pomocą modułu ChartSVG.

- 74/141 -

Page 75: SVG

#!/usr/bin/perl

use ChartSVG;

$myChart = ChartSVG->new();$myChart->set_title( "WYBORY PARLAMENTARNE 2006" );$myChart->set_y_desc( "%" );$myChart->add( "SLD", "7.86" );...$myChart->add( "PD", 2.35 );

$myChart->make_image( "wybory.svg", "BAR" );

Rys.4.4. Skrócony kod źródłowy programu służącego do wygenerowaniawykresu przedstawiającego fikcyjne wyniki wyborów parlamentarnych woparciu o moduł Perla „ChartSVG” (pominięto kilka podobnych wierszy,

wstawiających do egzemplarza obiektu klasy ChartSVG dane o kolejnychpartiach politycznych; pełny kod źródłowy skryptu w rozdziale 6.1.3).

Jak widać opracowanie specjalnego modułu, służącego do generowania

wykresów w formacie SVG, pozwoliło dramatycznie uprościć proces generacji

wykresów. Jestem przekonany, że nawet laik nie mający pojęcia o

programowaniu w języku Perl (chociaż oczywiście mający ogólne pojęcie o

programowaniu), potrafiłby w pełni skutecznie skorzystać z możliwości

oferowanych przez przygotowany przeze mnie moduł.

4.1.4. Czy SVG jest koniecznością?

Dlaczego upierać się przy stosowaniu grafiki SVG do generowania wykresów,

zamiast pozostać przy zupełnie poprawnie funkcjonujących formatach JPG czy

PNG, zwłaszcza, że wygenerowanie grafiki SVG po stronie klienta zużywa

znacznie więcej zasobów niż odtworzenie danych z pliku w formacie JPG?

Chodzi tu przede wszystkim o rozmiar przesyłanych przez sieć informacji.

Pamiętajmy, że to nie zasoby sprzętowe stanowią obecnie problem.

Problemem w sieci jest wciąż tak zwane „wąskie gardło”, którym jest

przyłącze klienta końcowego do sieci Internet. Duża szybkość renderowania

obrazów rastrowych po stronie klienta niekoniecznie musi rekompensować ich

- 75/141 -

Page 76: SVG

powolny transfer z sieci. W trakcie korzystania z Internetu wielokrotnie

doświadczam sytuacji, w której obserwuję jak obraz w formacie JPG bardzo

powoli wyświetla się na ekranie mojego monitora. Dane przesyłane są powoli,

ponieważ jest ich bardzo dużo – w zależności od stopnia kompresji oraz

rozmiaru obrazu może to być od kilkudziesięciu kilobajtów do nawet kilku

megabajtów informacji! Tymczasem grafika SVG pozwala wielokrotnie

zmniejszyć wielkość pliku przechowującego analogiczne informacje.

Przy obecnych możliwościach zwykłych komputerów osobistych, renderowanie

obrazu SVG zajmuje ułamek sekundy. Ponieważ dane takiego dokumentu

stanowią wyłącznie tekst, dlatego dają się świetnie skompresować, a co za

tym idzie przesyłać przez sieć znacznie szybciej niż pliki z grafiką rastrową.

Jest to silny argument za tym, aby pewne specyficzne obrazy (takie jak

wykresy) były publikowane na stronach WWW w formacie SVG. Myślę, że

bardzo przekonujące jest to, że czas pobierania strony WWW zawierającej

grafikę SVG będzie znacznie krótszy niż tej, która zawiera identyczne obrazy

w formacie JPG.

Odpowiadając na pytanie postawione w tytule niniejszego podrozdziału

muszę powiedzieć, że oczywiście nie jest żadną koniecznością publikowanie

wykresów na stronach WWW w formacie SVG. Natomiast niewątpliwie będzie

to stanowić wielką ulgę dla wszystkich tych użytkowników końcowych, którzy

nie posiadają bardzo szybkiego łącza dostępowego do sieci Internet.

Zadowolenie użytkownika z szybkiego załadowania strony WWW może się z

całą pewnością opłacić jej twórcy, zwłaszcza, że punktu widzenia tego

użytkownika mniej istotne jest to, jakie techniki zostały użyte do

przygotowania witryny, a bardziej to, jak długo musi on oczekiwać na jej

załadowanie do swojej przeglądarki internetowej.

W tabeli 4.1 zestawiłem porównanie rozmiarów pliku, zawierających dane

graficzne wykresu wygenerowanego za pomocą opracowanego przeze mnie

- 76/141 -

Page 77: SVG

modułu ChartSVG, w różnych formatach graficznych (skorzystałem z

rysunków 4.1 oraz 4.3 o rozmiarze 1024x768 pikseli).

Tabela 4.1. Porównanie rozmiarów plików graficznych popularnych formatów,zawierających dane identyczne z rysunkami SVG, wygenerowanymi za

pomocą stworzonego przeze mnie generatora wykresów – skorzystano zrysunków 4.1 oraz 4.3 o rozmiarach 1024x768 pikseli (rozmiary w bajtach).

nazwa pliku SVGZ SVG JPG PNG GIF BMP

wybory.svg 1 145 6 042 64 328 89 192 192 627 2 359 350

kraje.svg 1 205 6 457 72 390 118 390 114 174 2 359 350

Tabela 4.1 daje nam zdumiewający przykład na to, jak niewielki rozmiar mogą

mieć rysunki SVG! Warto w tym miejscu przypomnieć, że rozmiary plików w

pozostałych formatach będą zmieniać się wraz ze skalowaniem obrazu

(równocześnie pogarszać się będzie ich jakość), podczas gdy rysunek SVG

zawsze będzie miał ten sam rozmiar (najwyższa jakość grafiki pozostanie bez

zmian).

4.1.5. Wykres jako skrypt CGI

Skrypty CGI są używane do dynamicznego generowania zawartości stron

WWW. Tworzone są one w różnych językach programowania, niemniej jednak

jednym z najpopularniejszych sposobów ich tworzenia, jest pisanie skryptów

w języku Perl (utarło się wśród programistów przekonanie, że jeśli mówimy o

skryptach CGI, to niemal na pewno mówimy równocześnie o języku Perl).

Bardzo łatwo można przebudować zaprezentowany przeze mnie w

poprzedniej sekcji kod generujący wykres w taki sposób, aby mógł być on

uruchamiany jako skrypt CGI. Dzięki temu w zależności od tego, jakie dane

zostałyby dostarczone do skryptu, każdorazowo moglibyśmy dynamicznie

generować zupełnie nowy wykres z zupełnie nowymi danymi. Kod w Perlu,

- 77/141 -

Page 78: SVG

który miałby funkcjonować jako skrypt CGI, wymagałby minimalnych

modyfikacji, które przedstawiłem na rysunku 4.5.

#!/usr/bin/perl

use CGI;

# $data - do tej zmiennej należy w tym miejscu zapisać# treść dokumentu SVG

print "Content-Type: image/svg+xml\n";print "Content-Length: ", length($data), "\n\n$data";

1;

Rys.4.5. Fragment kodu źródłowego zawierającego modyfikacje, o jakienależałoby rozbudować kod generujący wykresy w oparciu o moduł

ChartSVG, tak aby mógł on funkcjonować jako skrypt CGI.

Jedyne modyfikacje, które należałoby wykonać, to wskazanie przeglądarce, z

jakim typem dokumentu ma ona do czynienia oraz jaki jest jego rozmiar.

Potęga skryptów CGI pisanych w Perlu polega właśnie na tym, że dane, które

program zapisuje bezpośrednio do standardowego wyjścia, po stronie klienta

widziane są jako treść pobieranego pliku.

Tylko od użytkownika skryptu zależałoby, w jaki sposób wykorzystać jego

możliwości. Można by przykładowo stworzyć formularz na stronie WWW, który

przekazuje do skryptu informacje wpisane przez gości strony jako jego dane

wejściowe. To, czy skrypt miałby generować od razu dokument SVG, czy też

wstawiać grafikę SVG w określonym miejscu na stronie WWW, zależałoby już

tylko od preferencji użytkownika lub autora strony.

4.1.6. Możliwości rozbudowy

Zaprezentowany w tym rozdziale napisany przeze mnie moduł Perla, służący

do generacji wykresów, ma stosunkowo ubogie możliwości. Jego

funkcjonalność można by jeszcze rozszerzyć o wiele różnorodnych opcji. Moim

celem nie było jednak przygotowanie rozbudowanej aplikacji generującej

- 78/141 -

Page 79: SVG

wykresy, tylko zasygnalizowanie korzyści, jakie płyną z zastosowaniu grafiki

SVG do tego celu. Utworzenie modułu Perla do tego celu było powodowane

chęcią stworzenia eleganckiej metody prezentującej wszystkie pozytywne

cechy, jakie niesie ze sobą integracja SVG (i w ogóle wszystkich aplikacji XML)

z możliwościami języka Perl.

Co można by jeszcze dodać w module ChartSVG? Na pewno można by

pokusić się o przygotowanie generatorów innych typów wykresów: wykresów

kołowych, liniowych, punktowych czy też ich trójwymiarowych reprezentacji.

Można by pozwolić na wyróżnianie wskazanych elementów. Można by

opracować algorytm pozwalający na wykreślanie linii trendu na wykresie,

prezentację wybranego wycinka wykresu w powiększeniu, a nawet animację

wybranych elementów, pokazujących przykładowo zmiany zachodzące we

wskazanym obszarze w czasie. Te wszystkie pomysły są możliwe do

zrealizowania za pomocą wielu różnorodnych aplikacji, jednak format SVG

pozwala na zaskakującą prostotę zapisu i przede wszystkim doskonałą

kompresję rozmiaru tych danych.

4.2. Generator wykresów pogodowych

Kolejną praktyczną aplikacją, zrealizowaną w ramach mojej pracy dyplomowej,

jest arkusz XSLT do transformacji danych pogodowych, przechowywanych w

zaprojektowanym przeze mnie formacie dokumentu XML, do formatu grafiki

SVG. W kilku kolejnych podrozdziałach staram się przedstawić koncepcję

realizacji tego projektu, uzasadniam decyzję o wyborze technik

programistycznych, przedstawiam bardziej zawiłe elementy tworzenia wykresów

i wreszcie prezentuję kilka przykładowych rysunków wraz z krótką

charakterystyką danych, które posłużyły do ich wygenerowania.

- 79/141 -

Page 80: SVG

4.2.1. Zalety wykorzystania grafiki wektorowej SVG

Najistotniejszą pozytywną cechą, jaką niesie dla omawianej aplikacji grafika

SVG, jest jej skalowalność. Pozwala ona w bardzo elastyczny sposób

rozmieszczać różnorodne wykresy na pojedynczej stronie internetowej,

personalizować jej wygląd pod kątem preferencji poszczególnych

użytkowników, czy też dowolnie zmieniać rozmiary prezentowanych wykresów

w celu analizy wybranych charakterystyk.

Już w drugim rozdziale wspominałem, że realizacja aplikacji wykorzystującej

możliwości grafiki SVG do tworzenia wykresów pogodowych na stronach

WWW była jednym z pierwszych zadań, jakie postawiłem sobie do realizacji w

ramach niniejszej pracy dyplomowej. Ponieważ celem mojej pracy nie jest

realizacja żadnego dużego projektu informatycznego wykorzystującego

standard SVG, lecz analiza różnych obszarów Internetu, w których ten

standard można śmiało wykorzystać, również opisywana tutaj aplikacja nie

jest kompletnym rozwiązaniem systemu do zbierania, przechowywania oraz

prezentowania danych pogodowych. Swój projekt ograniczyłem do tych

elementów, które bezpośrednio dotyczą grafiki, tj. do wizualizacji danych

pogodowych w postaci wykresów w formacie SVG.

Jest oczywistym, że aby móc wykonać graficzną reprezentację pewnych

danych, należy te dane posiadać. Do tego celu musiałem zaprojektować swój

własny model danych XML i zrobić to w taki sposób, aby jak najlepiej

odzwierciadlał rzeczywiste dane, które mogłyby posłużyć jako źródło

informacji do dalszego przetwarzania. Aby przekształcić liczbowe dane do

grafiki w formacie SVG zdecydowałem się tym razem na skorzystanie z

możliwości innego XML-owego narzędzia, mianowicie XSLT (ang. eXtensible

Stylesheet Language Transformations), umożliwiającego przekształcanie

różnych dokumentów zgodnych ze standardem XML do innych formatów. W

tym przypadku potrzebowałem dokonać transformacji z mojej własnej

- 80/141 -

Page 81: SVG

aplikacji XML do grafiki SVG. Efektem mojej pracy było opracowanie arkusza

stylu XSLT, który to zadanie realizował. W następnych podrozdziałach

przedstawiam szczegółowo charakterystykę obu omawianych składników

aplikacji, jak również prezentuję kilka gotowych przykładów, będących

efektem ich wykorzystania.

4.2.2. Format przechowywania danych pogodowych

Do przechowywania danych o pogodzie został zaprojektowany dokument

XML. Ponieważ format SVG sam jest aplikacją XML, uznałem za stosowne

wykorzystanie takiej techniki, która pozwoli zaprezentować wszystkie

najlepszy cechy, jakie niesie ze sobą modelowanie danych za pomocą

metajęzyka XML.

Pierwszym krokiem projektu było opracowanie definicji DTD (ang. Document

Type Definition – definicja typu dokumentu), na której zostałyby oparte

wszelkie możliwe rodzaje danych pogodowych. Zdecydowałem się

zaprojektować tylko jedną definicję DTD, aby później móc korzystać z

jednego tylko arkusza stylu XSLT, który posłużyłby do transformacji danych z

dokumentu XML do formatu SVG. Z jednej strony może się wydawać, że takie

podejście może powodować niepotrzebną komplikację struktury danych, ale w

praktyce rozbudowie ulega w zasadzie tylko arkusz stylu XSLT, który musi

„obsłużyć” większą liczbę możliwych kombinacji danych.

Wiadomo, że inny charakter mają dane takie jak temperatura, a inny opady.

Niemniej jednak będę chciał pokazać, że zaproponowany przeze mnie model

danych pozwala nie tylko na wygodne przechowywanie tych danych w tym

samym typie dokumentu XML. Co więcej, dwa różne rodzaje danych można

swobodnie zaprezentować na jednym wspólnym wykresie, co przedstawię

później na bardzo konkretnym przykładzie.

Należy w tym miejscu zaznaczyć, że definicja DTD nie została przeze mnie

- 81/141 -

Page 82: SVG

zaprojektowana w ciągu jednej chwili i nie ulegała później żadnym zmianom.

Wprost przeciwnie, w trakcie pisania arkusza stylu XSLT byłem zmuszony

wielokrotnie dokonywać zmian w swoim pierwotnym projekcie dokumentu

XML, aby poprawnie odzwierciedlić wszystkie dodatkowe cechy rysunków, na

których realizację decydowałem się w czasie realizowania projektu.

Początkowo wykresy miały zawierać następujące informacje: tytuł, godziny

oraz daty wybranych punktów, ich wartości oraz właściwy diagram (wykres

liniowy) reprezentujący określoną wielkość pogodową. W związku z tym tylko

te elementy znalazły się w pierwotnym projekcie dokumentu XML. Dopiero

później wprowadzałem kolejne składniki, mające na celu zbudowanie bardziej

atrakcyjnych wykresów, tzn. rozróżnienie na typy wykresów, zróżnicowanie

metod prezentowania danych (linie, słupki, itd.), możliwość zastosowania

nietypowych skali na osi rzędnych oraz zamieszczanie różnych typów

wykresów na tym samym diagramie.

Ostatecznie powstał projekt DTD, który stanowił podstawę dla

przechowywania danych pogodowych, które z kolei miały posłużyć do

tworzenia obrazów SVG za pomocą przekształcenia XSLT. Na rysunku 4.6

przedstawiłem kod źródłowy, który należałoby dołączać do każdego

dokumentu XML, zawierającego dane pogodowe, aby pozostał on w zgodzie z

moim projektem.

Jak widzimy korzeń całego dokumentu stanowi element weather i posiada

on kilka obowiązkowych sekcji. Pierwszą sekcją jest description, która

określa tytuł wykresu oraz decyduje o tym, co zostanie wyświetlone w górnej

części obrazu SVG. Sekcja dates zawiera listę godzin oraz dat, które zostaną

przypisane poszczególnym punktom na osi odciętych. Warto w tym miejscu

zwrócić uwagę na to, że już na etapie projektu definicji DTD założyłem sobie,

że liczba dozwolonych punktów nie będzie w żaden sposób normalizowana –

bez względu na liczbę takich pomocniczych pionowych linii, jaką życzyłby

- 82/141 -

Page 83: SVG

sobie zobaczyć na wykresie użytkownik korzystający z tej aplikacji, należy się

postarać, aby na wykresie rzeczywiście została przedstawiona taka ich liczba,

jakiej zażąda użytkownik.

<!DOCTYPE weather [ <!ELEMENT weather (description,dates,values,diagram+)> <!ELEMENT description (title,additional_title?)> <!ELEMENT title (#PCDATA)> <!ELEMENT additional_title (#PCDATA)> <!ELEMENT dates (date+)> <!ELEMENT date EMPTY> <!ELEMENT values (value+)> <!ELEMENT value EMPTY> <!ELEMENT diagram (point+)> <!ELEMENT point EMPTY> <!ATTLIST weather diagram_bckg_color CDATA #REQUIRED> <!ATTLIST title outline_color CDATA #REQUIRED> <!ATTLIST additional_title outline_color CDATA #REQUIRED> <!ATTLIST date day CDATA #REQUIRED> <!ATTLIST date hour CDATA #REQUIRED> <!ATTLIST values left_color_shadow CDATA #IMPLIED> <!ATTLIST values right_color_shadow CDATA #IMPLIED> <!ATTLIST value left CDATA #IMPLIED> <!ATTLIST value right CDATA #IMPLIED> <!ATTLIST diagram type CDATA #REQUIRED> <!ATTLIST diagram name CDATA #REQUIRED> <!ATTLIST diagram style CDATA #REQUIRED> <!ATTLIST diagram color CDATA #REQUIRED> <!ATTLIST diagram values (left|right) #REQUIRED> <!ATTLIST point value CDATA #REQUIRED> <!ATTLIST point min_value CDATA #IMPLIED> <!ATTLIST point max_value CDATA #IMPLIED>]>

Rys.4.6. Projekt definicji DTD, na której zostały oparte wszystkie generowanerodzaje danych pogodowych. W plikach XML bazujących na tej definicji

przechowywane są dane pogodowe, które można później przekształcić doformatu grafiki SVG za pomocą odpowiedniego arkusza stylu XSLT.

Kolejna sekcja values ma za zadanie przypisać wartości kolejnych punktów

na osi rzędnych. Wartości definiowane są jako atrybuty elementu value:

left oraz right. Zdecydowałem się na wprowadzenie takiego zabiegu,

- 83/141 -

Page 84: SVG

ponieważ chciałem, aby na jednym diagramie możliwe było zamieszczenie

dwóch zupełnie różnych wykresów. Przykładowo jeden wykres (dla którego

wartości kolejnych punktów zapisane byłyby po lewej stronie diagramu)

dotyczyłby danych temperaturowych, natomiast drugi (wartości po prawej

stronie) stanowiłby reprezentację wilgotności powietrza w kolejnych

godzinach. Co jest tutaj kolejną wartą odnotowania cechą mojej aplikacji to

to, że oba wykresy niekoniecznie musiałyby posiadać tą samą dokładność.

Przykładowo temperatura mogłaby być mierzona w odstępach 3 godzin,

natomiast wilgotność co godzinę. Arkusz stylu XSLT uwzględnia te

właściwości i za każdym razem odpowiednio skaluje obie osie, tak aby te dwa

zupełnie różne wykresy zostały prawidłowo wykreślone.

Ostatnia obowiązkowa sekcja dokumentu XML to diagram, przy czym musi

ona wystąpić co najmniej jeden raz (ale może też więcej). To tutaj właśnie

powinny zostać zawarte wartości poszczególnych punktów wykresów. Dzięki

temu, że moje DTD pozwala na wprowadzenie kilku takich sekcji, dane

pogodowe dotyczące różnych dziedzin, mogą znaleźć się w tym samym

dokumencie XML, a co za tym idzie, narysowane również na tym samym

wykresie SVG. Takie rozwiązanie pozwala na dużą elastyczność w

podejmowaniu decyzji o tym, co chcemy przedstawić na rysunku. Wybór, czy

rozbić dane na cztery oddzielne, ale bardzo przejrzyste wykresy, czy też

zaprezentować je tylko na jednym rysunku, oszczędzając przy tym cenne

miejsce na swojej stronie internetowej, należy już tylko do projektanta

serwisu.

Moja aplikacja pogodowa pozwala na wybór nie tylko jednego z

wymienionych rozwiązań, ale każde możliwe rozwiązanie, które wyda się

użytkownikowi najkorzystniejsze, włącznie z personalizowaniem ustawień dla

różnych gości jego witryny. Jedynym ograniczeniem, które jest narzucone, to

konieczność zastosowania jednego z istniejących mechanizmów rysowania

- 84/141 -

Page 85: SVG

wykresów (dla różnych typów wykresów, zaprojektowałem różne metody ich

prezentacji, szczegóły zostały przedstawione w dalszej części tekstu),

jakkolwiek nic nie stoi na przeszkodzie, aby rozbudować arkusz stylu XSLT o

zupełnie nowe rodzaje wykresów (jak łatwe jest to zadanie będzie się można

również przekonać w trakcie dalszej lektury pracy).

Projekt dokumentu XML z danymi pogodowymi starałem się ograniczyć do

niezbędnego minimum, aby był on tak przejrzysty jak to tylko możliwe (jeżeli

ktoś chciałby odczytać z niego pogodę, powinien móc tego dokonać w tak

samo wygodny sposób jak analizując rysunek z wykresem). Niemniej jednak

istnieje jeden element, który może szczególnie razić w moim projekcie. Jest

to fakt zawarcia danych dotyczących sposobu prezentacji danych graficznych,

na przykład określania kolorów poszczególnych wykresów, w miejscu, w

którym powinny znaleźć się tylko i wyłącznie dane pogodowe (przecież o to

właśnie chodzi w XML-u: o oddzielenie treści od prezentacji). Zdecydowałem

się na taki krok świadomie. Chodziło mi o to, aby pokazać szybki i skuteczny

sposób na zmianę niektórych preferencji obrazu, bez konieczności

bezpośredniej ingerencji w arkusz stylu XSLT.

Informacji o danych graficznych SVG jest w moim dokumencie XML

stosunkowo dużo i gdyby je usunąć, to definicja DTD skurczyłaby się o około

20%. Jest rzeczą oczywistą, że projektując poważną aplikację, należałoby tak

właśnie postąpić. Ponieważ jednak nie chciałem zaciemniać jeszcze bardziej

arkusza stylu XSLT, który i tak w trakcie realizowania aplikacji rozrósł się do

ponad 200 linii kodu i co za tym idzie nieznacznie skomplikował,

zdecydowałem się na tak drastyczny krok. Ułatwiło mi to późniejsze

wykonanie przykładowych wykresów, które mogły różnić się kolorystyką,

dopasowywaną do swojego charakteru, tylko dzięki edycji danych XML.

- 85/141 -

Page 86: SVG

4.2.3. Proces transformacji danych arkuszem stylu XSLT

Aby przekształcić jeden dokument XML w inny, należy opracować odpowiedni

arkusz stylu XSLT. Celem wykazania, że transformacja z dokumentu opartego

na własnej definicji DTD do formatu grafiki SVG jest możliwa, a co więcej

bardzo łatwa, całą funkcjonalność swojej aplikacji do prezentowania

wykresów pogodowych zdecydowałem się oprzeć właśnie na przekształceniu

XSLT.

W każdym dokumencie XML, zgodnym z definicją DTD przedstawioną w

podrozdziale 4.2.2, można umieścić następującą informację:

<?xml-stylesheet type="text/xsl" href="weather.xsl"?>

Oznacza ona, że z tym dokumentem XML skojarzony został arkusz stylu XSLT,

za pomocą którego dokonane zostanie przekształcenie danych do formatu

SVG.

Plik weather.xsl oczywiście musi być zgodny z XML-em, ponieważ XSLT

jest aplikacją XML. Pomijając komentarze, które zostały zamieszczone

wewnątrz pliku źródłowego, mój dokument XSLT zajmuje mniej niż 200 linii

kodu. Ta uwaga warta jest odnotowania, ponieważ efekt, jaki uzyskujemy po

jego zastosowaniu, to poprawnie skomponowany rysunek zawierający

przejrzyste wykresy pogodowe.

Plik XSLT ma rozmiar 15 kilobajtów. Żaden rysunek rastrowy,

odzwierciedlający z podobną dokładnością tak dużą liczbę szczegółów, nie

byłby w stanie zmieścić się w tak niewielkiej przestrzeni dyskowej, nawet jeśli

do arkusza XSLT doliczymy plik zawierający 8 kilobajtów danych o pogodzie

(plik XML). Po skompresowaniu obu plików do formatu .tgz zajmują one

ledwie 4 kilobajty przestrzeni dyskowej! Tak niewielkie rozmiary plików

otrzymujemy po pierwsze dzięki przeniesieniu całej logiki związanej z

- 86/141 -

Page 87: SVG

renderowaniem grafiki do komputera użytkownika końcowego, a po drugie

dzięki temu, że pliki XML mają format tekstowy, który znakomicie się

kompresuje.

Chciałbym teraz pokrótce omówić sposób, w jaki odbywa się tworzenie

rysunku SVG w oparciu o omówiony w poprzednim podrozdziale dokument

XML. Podczas lektury dalszego tekstu warto spoglądać od czasu do czasu na

kod źródłowy, do którego się w nim odwołuję. Pełny kod źródłowy arkusza

stylu XSLT zamieściłem w rozdziale 6.2.3 na końcu pracy dyplomowej.

Pierwsza linia kodu to standardowa deklaracja dokumentu XML, natomiast to,

co jest kluczowym elementem dla poprawnego przenikania się elementów z

kilku różnych przestrzeni nazw w jednym dokumencie (a tutaj przecież

przenikać się mają elementy XSLT oraz SVG), to ich nazwanie w elemencie

nadrzędnym całego dokumentu. Elementem nadrzędnym dla pliku w formacie

XSLT jest <xsl:stylesheet>. I właśnie w nim zadeklarowałem informację

o tym, że w dokumencie korzystam z dwóch zupełnie różnych przestrzeni

nazw:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg">

Do definiowania przestrzeni nazw służy atrybut xmlns. W powyższym

przykładzie widać, że korzystam z dwóch przestrzeni nazw: przedrostkiem

xsl: zdecydowałem się poprzedzać wszystkie elementy standardu XSLT,

natomiast przedrostkiem svg: te, które są elementami SVG.

Możliwość korzystania z wielu różnych przestrzeni nazw w jednym

dokumencie XML jest jedną z najpotężniejszych możliwości, jakie daje nam

ten standard. Dzięki niej bezproblemowo przenikają się i wzajemnie

zagnieżdżają elementy XSLT oraz elementy SVG, a przeglądarka

interpretująca dokument XML za każdym razem wie, z elementem której

- 87/141 -

Page 88: SVG

przestrzeni nazw ma w danej chwili do czynienia.

Kolejnym bardzo istotnym składnikiem projektowanej przeze mnie

transformacji było poprawne określenie typu dokumentu wyjściowego. Miał to

być oczywiście plik w formacie SVG, ale nie mogłem sobie przecież pozwolić

na wstawienie takiej deklaracji DTD:

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

Byłoby to niezgodne z prawdą, bo przecież w poprzedniej linii kodu

zadeklarowałem fakt korzystania z dwóch różnych przestrzeni nazw. Zamiast

tego należało skorzystać z jednego z elementów standardu XSLT, mianowicie

<xsl:output>, który służy właśnie do definiowania formatu dokumentu

wyjściowego transformacji:

<xsl:output method="xml" indent="yes" doctype-public="-//W3C//DTD SVG 1.1//EN" doctype-system="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"/>

Kluczowe dla skutecznego przekształcenia są dwa atrybuty: doctype-

public oraz doctype-system. Pierwszy z nich ustawia wartość atrybutu

PUBLIC wyjściowej deklaracji DOCTYPE, natomiast drugi ustawia jej atrybut

SYSTEM. Taki zapis jest całkowicie tożsamy z zapisaną wprost w dokumencie

SVG deklaracją DOCTYPE, natomiast w dokumencie XSLT chroni on przed

niewłaściwym zinterpretowaniem formatu wyjściowego przez procesor

przekształcający dokument z jednego formatu XML w inny.

Gdy wiadomo już elementy których przestrzeni nazw mogą się pojawić w

kodzie źródłowym przekształcenia oraz poprawnie określony został format

dokumentu wyjściowego transformacji, można przystąpić do analizy samego

arkusza stylu XSLT. Można dowiedzieć się z niego, jakie operacje wykonywane

są w trakcie generowania rysunku zawierającego wykres oparty na danych ze

- 88/141 -

Page 89: SVG

źródłowego dokumentu XML.

Aby podkreślić skalowalność wygenerowanego rysunku, zdecydowałem się

wprowadzić na początku kodu transformacji kilka zmiennych globalnych.

Definiują one całkowity rozmiar rysunku (ponieważ obraz jest skalowalny,

więc lepiej w tym miejscu mówić o jego proporcjach – w praktyce manipuluję

tylko stosunkiem wysokości do szerokości, gdyż rysunek i tak wypełni

maksymalnie dostępny obszar w oknie przeglądarki) oraz położenie i rozmiary

samego wykresu. Dzięki tym zmiennym bardzo łatwo i szybko jesteśmy w

stanie dostosowywać wielkość rysunku do naszych własnych potrzeb. W

kodzie źródłowym przekształcenia ten fragment jest opatrzony komentarzem

„XSLT STYLESHEET VARIABLES”. Jako przykład manipulowania tymi danymi

podam wykorzystanie zmiennej pictureWidth. Zmienna ta definiuje

szerokość samego wykresu. Jeżeli w dokumencie źródłowym XML

zdefiniowano dwa różne rodzaje danych pogodowych z zamiarem

przedstawienia ich na jednym wykresie, wówczas wskazane jest

przedstawienie dwóch różnie opisanych osi wartości (po lewej stronie

wykresu dla jednej i po prawej stronie dla drugiej). Jeżeli później okaże się,

że zależy nam na usunięciu jednej z tych wartości z wykresu, wówczas wolne

miejsce z prawej strony rysunku, które zajmowane było wcześniej przez

wartości liczbowe, pozwala na poszerzenie wykresu za pomocą modyfikacji

wartości zmiennej pictureWidth, a co za tym idzie na zwiększenie jego

czytelności oraz ekonomiczniejszego rozdysponowania pustej przestrzeni

rysunku.

Kolejna sekcja dokumentu XSLT, opatrzona komentarzem „DOCUMENT

MATCHING ROOT ELEMENT”, służy do wygenerowania na wyjściu

transformacji głównego elementu <svg>, a także do wykreślenia obramowań

całego rysunku, jak i samego wykresu oraz do pokolorowania tła na wskazany

w źródłowym dokumencie XML kolor. Wartości atrybutów definiujących

- 89/141 -

Page 90: SVG

rozmiary wykreślanych prostokątów (do tworzenia obramowań

wykorzystywane są elementy <rect> ze zbioru dostępnych elementów SVG)

pobierane są ze zdefiniowanych w poprzedniej sekcji dokumentu zmiennych

globalnych, np. zapis width="{$pictureWidth}" oznacza, że w

momencie przetwarzania dokumentu jako wartość atrybutu width

wykorzystana zostanie wartość przechowywana aktualnie w zmiennej

pictureWidth. Taka konstrukcja arkusza stylu XSLT zwalnia użytkownika z

konieczności szczegółowej analizy kodu źródłowego – chcąc dokonać

znaczących modyfikacji w wyglądzie swojego wykresu, musi on jedynie

dokonać zmian albo w danych (dokument XML), albo kilku globalnych

zmiennych (dokument XSLT). Oczywiście nic nie stoi na przeszkodzie, aby na

przykład te kilka zmiennych globalnych przenieść do źródłowego dokumentu

XML i tam dokonywać ich modyfikacji (jedynym kłopotem mogłaby być

wówczas konieczność modyfikacji przygotowanej wcześniej definicji DTD –

chociaż w praktyce procesor XSLT nie zwraca uwagi na obecność definicji

DTD w dokumencie XML, dobrze jest zachować ją w zgodzie z treścią

dokumentu, ponieważ pozwala to uniknąć niejednoznaczności podczas jego

stosowania w przyszłości).

Sekcja opisana jako „DOCUMENT MATCHING DESCRIPTION ELEMENT” służy

do wyświetlenia tytułu wykresu w postaci tekstu (zastosowany zostaje tu

element <text> ze zbioru elementów SVG). Do tego celu wykorzystywane są

standardowe atrybuty, określające położenie, rozmiar oraz styl napisu. Tekst,

który ma zostać wyświetlony, wstawiony zostaje ze źródłowego dokumentu

XML. Jeżeli zdefiniowany został dodatkowy nagłówek (jest to istotne w

przypadku, gdy na jednym diagramie chcemy przedstawić dwa różne rodzaje

wykresów), to zostanie on wyświetlony na rysunku poniżej głównego tytułu

(zastępując daty, które widoczne są tylko na rysunkach bez dodatkowego

nagłówka).

- 90/141 -

Page 91: SVG

Pierwszą sekcją, która jest szczególnie godna uwagi, jest część kodu

źródłowego arkusza stylu XSLT opatrzona komentarzem „DOCUMENT

MATCHING DATES ELEMENT”. W podrozdziale 4.2.2 zaznaczyłem, że

wewnątrz znacznika <dates> przechowywane są informacje dotyczące

kolejnych punktów na osi X oraz odpowiadające im daty i godziny.

Przetwarzaniu tych informacji poświęcony został stosunkowo rozbudowany

kod źródłowy, który musi wykonać kilka różnych operacji: wyświetlić godzinę

oraz pionową linię odpowiadającą danemu punktowi wykresu, jak również

daty odpowiadające kolejnym dniom przedstawionym na diagramie. O ile w

pierwszym przypadku przedstawienie danych polega na prostej iteracji przez

wszystkie dostępne wartości, o tyle w drugim sytuacja się komplikuje. Widać

to na przykładach zaprezentowanych w rozdziale 4.2.4.

Obliczenie centralnej pozycji (w poziomie) napisu daty odpowiadającej

danemu dniu zależy od tego, ile godzin z tego dnia jest przedstawianych na

wykresie. Ponieważ nie chciałem stosować w swoim kodzie skomplikowanych

wywołań rekurencyjnych, które owszem spełniają swoją rolę, to jednak

sprawiają czasami kłopoty przeglądarkom (pamiętam, że w trakcie tworzenia

dokumentu XSLT bardzo długo nie mogłem znaleźć przyczyny występowania

zupełnie niezrozumiałego błędu – okazało się, że rysunek mógł być

generowany poprawnie dopiero po wyeliminowaniu rekurencji z kodu

źródłowego!), dlatego posłużyłem się pewną sztuczką, która pozwoliła mi

obejść konieczność rekurencyjnego wywoływania funkcji do obliczenia

centralnego położenia napisu. Mianowicie za każdym razem, gdy wykonywana

jest iteracja przez wszystkie punkty osi X (pętla <xsl:for-each>),

sprawdzana jest również informacja, czy jest to koniec poprzedniego dnia (i

jednocześnie rozpoczęcie nowego) – jeżeli tak, to wykonywana jest

procedura, która zlicza ilość punktów, które weszły w skład tego dnia, dzieli ją

przez dwa i wyznacza pozycję napisu na rysunku na podstawie numeru

bieżącej iteracji.

- 91/141 -

Page 92: SVG

Do wyświetlania napisów (godziny oraz daty) wykorzystywany jest element

SVG <text>, natomiast linie pionowe, które mają na celu ułatwienie

odczytywania danych z wykresu, rysowane są za pomocą elementu SVG

<line>. Dla większej przejrzystości wykresu linie oznaczające rozpoczęcie

nowego dnia (godzina 24) rysowane są innym stylem niż pozostałe.

Dodatkowo w źródłowym dokumencie XML istnieje możliwość takiego

zagęszczenia wartości kolejnych punktów wykresu, aby nie wykreślano

pionowej linii dla każdego jednego punktu wykresu (aby to zrobić wystarczy

tylko zdefiniować więcej źródłowych elementów <point> niż istnieje

zdefiniowanych elementów <date>).

Sekcja opatrzona komentarzem „DOCUMENT MATCHING VALUES ELEMENT”

służy do wyświetlania liczb wzdłuż obu osi Y diagramu (lewej i prawej),

odpowiadających kolejnym pozycjom wartości wykresu, jak również

znajdujących się na tej samej wysokości poziomych linii, których funkcją jest

ułatwienie odczytywania wartości poszczególnych punktów wykresu. Metoda

generowania danych SVG jest dokładnie analogiczna jak dla osi X. Jedyną

różnicą jest fakt, że dodatkowe wartości są wykreślane nie tylko po lewej, ale

również po prawej stronie wykresu (o ile tylko zdefiniowano je w źródłowym

dokumencie XML).

Ostatnią sekcją arkusza stylu XSLT, kluczową dla całej aplikacji, jest

najdłuższy fragment kodu źródłowego, opisany jako „DOCUMENT MATCHING

DIAGRAM ELEMENT”. To tutaj przetwarzane są dane prowadzące do

wygenerowania właściwego wykresu, który jest najbardziej interesującą

częścią całej aplikacji. Kod źródłowy przeznaczony do zaaplikowania sekcji

<diagram> ze źródłowego dokumentu XML, zostaje zastosowany tyle razy,

ile razy pojawia się w nim element <diagram>. W związku z tym istotna jest

kolejność, w jakiej zapisywane są dane źródłowe, ponieważ w dokładnie

takiej kolejności będą one nanoszone na docelowy rysunek. Jeżeli chcemy,

- 92/141 -

Page 93: SVG

aby na przykład wykres temperatury został wykreślony na pierwszym planie,

a wykres opadów na drugim, wówczas musimy przenieść dane pogody

przeznaczone dla wykresu temperatury (atrybut type="temperature") na

koniec danych w pliku XML.

Przetwarzanie danych źródłowych odbywa się kolejno dla każdej wartości

punktu w pętli <xsl:for-each>. Przed jej wywołaniem, ustawianych jest

kilka pomocniczych zmiennych lokalnych, które skracają skomplikowane

obliczenia w trakcie działania pętli. Są to zmienne przechowujące informacje

typowo obliczeniowe o tym, któremu wykresowi odpowiadają dane

(pamiętajmy, że na jednym diagramie istnieje możliwość wykreślenia dwóch

wykresów, dysponujących zupełnie różnymi zakresami osiąganych wartości),

jaki jest rozrzut możliwych wartości, jaka jest odległość między dwoma

sąsiednimi wartościami, tzn. wartościami różniącymi się o jedność, na rysunku

(w pikselach), jaka jest odległość pomiędzy dwoma kolejnymi argumentami

na rysunku (w pikselach), jak również informacje pobrane ze źródłowego

dokumentu XML o tym, jaki ma być typ, styl oraz kolor rysowanego wykresu.

Procedura przetwarzania danych jest identyczna dla każdego z punktów, przy

czym różni się ona w zależności od typu wykresu. W przypadku wykresu typu

temperaturowego w pierwszej kolejności wyznaczane są pozycje dwóch

sąsiednich punktów (x1,y1) i (x2,y2). Ustalane są one na podstawie

położenia wykresu na obrazie, obliczonych wcześniej pomocniczych stałych

oraz wartości punktów pobranych ze źródłowego dokumentu XML. Następnie

za pomocą elementu SVG <line> wykreślana jest linia łącząca oba te

punkty. Dodatkowo jeżeli w źródłowym dokumencie zdefiniowano

dopuszczalny błąd pomiaru poprzez podanie minimalnej oraz maksymalnej

wartości temperatury, obliczana jest dodatkowa linia pionowa na rysunku

(obliczane są tylko wartości, gdyż argument odpowiada wyznaczonej

wcześniej pozycji punktu x1), a następnie wykreślana przez element <line>

- 93/141 -

Page 94: SVG

z identycznymi argumentami jak poprzednia z tym wyjątkiem, że atrybut

stroke-width (definiujący grubość linii) ma czterokrotnie mniejszą

wartość.

W przypadku wykresów opadów oraz wilgotności (typ wykresu to

precipitation lub humidity) obliczenia są nieco bardziej

skomplikowane, co wiąże się z faktem, że:

różne rodzaje wykresów mogą być przedstawiane na jednym diagramie

(patrz przykład w następnym podrozdziale: wykresy opadów oraz

wilgotności zamieszczone na tym samym rysunku), a zatem potrzebne

są do rozważenia dwa oddzielne przypadki – jeden, w którym wartości

punktów odnoszą się do lewej osi Y, drugi – do prawej osi Y

skala na osi Y może być z pewnych względów nieproporcjonalna (patrz

przykład w następnym podrozdziale: skala na wykresie wilgotności), a

zatem obliczenie właściwej pozycji punktu na wykresie wymaga

uwzględnienia odpowiedniego przedziału wartości, w którym znajduje

się aktualnie dany punkt, a następnie wyznaczeniu współrzędnych tego

przedziału na rysunku

Po obliczeniu położenia poszczególnych punktów na diagramie, tworzone są

odpowiadające wskazanemu stylowi wykresy. W przypadku wykresu

wilgotności jest to linia identyczna jak dla wykresu temperatury. Dla opadów

przelotnych są to pionowe linie (wykreślane podobnie jak różnica pomiędzy

minimalną a maksymalną temperaturą, z tym wyjątkiem, że biorą one swój

początek w wartości zerowej). Opady ciągłe oraz śnieg reprezentowane są w

postaci słupków, które tworzone są za pomocą elementu SVG <rect>, który

służy do wykreślania prostokątów.

- 94/141 -

Page 95: SVG

4.2.4. Przykładowe wykresy

Mając już za sobą prezentację solidnej dawki teorii, która wprowadza w

zagadnienie generowania wykresów pogodowych od jej strony technicznej,

chciałbym poświęcić niniejszy fragment tekstu przedstawieniu dwóch

praktycznych przykładów wykorzystania omawianych wcześniej mechanizmów

oraz wygenerowaniu rysunków SVG, zawierających wykresy pogodowe,

stworzone w oparciu o dostarczone za pomocą źródłowych dokumentów XML

dane.

Jako pierwszy przykład chciałbym zaprezentować generację wykresu

temperatury. Przedstawię również wszystkie kroki prowadzące do

przygotowania dokumentu XML z danymi pogodowymi: opierając się na

regułach omówionych w podrozdziale 4.2.2 zamierzam pokazać, w jaki

sposób przygotować źródłowy dokument XML, zawierający dane, które

chcemy przedstawić na wykresie.

Rozpoczynamy od standardowej deklaracji XML w pierwszej linii dokumentu

oraz powiązania go z przygotowanym wcześniej arkuszem stylu XSLT w

następnej. Następnie należy utworzyć element nadrzędny (ang. root element

– korzeń) dokumentu. Zgodnie z definicją DTD jest to element <weather>.

Pamiętamy, że jeden z atrybutów tego elementu pozwala na określenie koloru

tła wykresu, korzystamy z tej właściwości i przypisujemy mu wybrany kolor.

W tym momencie mamy już przygotowany szkielet dokumentu XML, któremu

trzeba teraz dostarczyć odpowiednich danych:

<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="weather.xsl"?><weather diagram_bckg_color="ghostwhite">...</weather>

Pierwszą sekcją dokumentu, którą dodamy, będzie tytuł wykresu. Jak

- 95/141 -

Page 96: SVG

pamiętamy do tego celu należy wykorzystać element <description>.

Wewnątrz tego elementu wstawiamy element podrzędny <title>, którego

wartość stanowi sekcja CDATA. Dodatkowo powinniśmy określić kolor

obwódki dla tekstu na rysunku, korzystając z atrybutu outline_color. W

ten oto sposób mamy już zdefiniowaną pierwszą sekcję danych (sekcję

tytułową) dokumentu XML:

<description> <title outline_color="darkgreen"> <![CDATA[temperatura - temperature - Temperatur (°C)]]> </title></description>

Przystępujemy następnie do ustalenia, jaki okres czasu ma obejmować

wykres oraz jaką gęstość pomocniczych linii pionowych dla niego

przewidujemy. Przykładowo ustalmy, że kolejne linie pionowe wraz z

oznaczeniami godzin pojawiać się będą na rysunku co trzy godziny i

obejmować okres czasu od północy dnia 12 X do południa dnia 14 X. Sekcja

<dates> dokumentu XML będzie miała wówczas następującą postać:

<dates> <date day="12 X" hour="0"/> <date day="12 X" hour="3"/> <date day="12 X" hour="6"/> ... <date day="14 X" hour="12"/></dates>

W miejsce wielokropka wstawiamy kolejne godziny oraz dni, tak aby na

wykresie znalazło się ostatecznie 21 pionowych linii, ułatwiających

odczytywanie oraz umiejscawianie w czasie wybranych danych o

temperaturze.

Kolejna sekcja danych pozwala określić kilka elementów związanych z

- 96/141 -

Page 97: SVG

wartościami, jakie mogą być przypisywane atrybutom wykresu. Są to:

maksymalna oraz minimalna wartość przedstawiana na wykresie, odstęp

pomiędzy kolejnymi wartościami oraz liczba poziomych linii pomocniczych,

ułatwiających odczyt wartości użytkownikowi. Dodatkowo atrybuty elementu

<values> pozwalają określić kolory obwódki tekstu wypisującego kolejne

wartości wzdłuż obu osi Y (lewej i prawej niezależnie).

W naszym przykładzie decydujemy się na zakres temperatur od 0°C do 30°C

wraz z dwoma poziomymi liniami pomocniczymi:

<values left_color_shadow="darkgray" right_color_shadow="darkgray"> <value left="0" right="0"/> <value left="10" right="10"/> <value left="20" right="20"/> <value left="30" right="30"/></values>

Pozostało nam jeszcze dostarczenie danych dla samego wykresu temperatury.

Aby zademonstrować wykreślanie dwóch wykresów (jednego typu) na tym

samym rysunku, przygotujmy dane dla temperatury uśrednionej oraz dla

temperatury odczuwanej. W przypadku temperatury uśrednionej dodamy

pomocnicze słupki określające dozwolony błąd prognozy, natomiast w

przypadku temperatury odczuwanej wykonamy zwykły wykres w postaci linii

ciągłej.

Jeżeli chcemy dostarczyć do dokumentu dane, zawierające prognozę pogody

w odstępach jednej godziny pomiędzy kolejnymi danymi, musimy wprowadzić

trzykrotnie więcej danych niż zrobiliśmy to w sekcji <dates>, ponieważ tam

odstępy pomiędzy kolejnymi punktami wykresu wynosiły trzy godziny. Chcąc

umieścić wykres uśredniony na pierwszym planie, musimy dane temperatury

odczuwanej wstawić do dokumentu wcześniej niż dane temperatury

uśrednionej.

- 97/141 -

Page 98: SVG

Pozostało nam już tylko uzupełnić dane dla kolejnych punktów obu wykresów

oraz określić ich atrybuty (typ, styl, kolor, nazwa). W tym momencie proces

przygotowywania źródłowego dokumentu XML z pożądanymi danymi

pogodowymi został zakończony. Podgląd na dane obu wykresów temperatury

(uśrednionej oraz odczuwanej) można zobaczyć na rysunku 4.7, natomiast

pełny kod źródłowy tak przygotowanego dokumentu XML można przeglądać

w rozdziale 6.2.1. Efekt wygenerowanego za pomocą przygotowanego

wcześniej arkusza stylu XSLT wykresu możemy podziwiać na rysunku 4.8.

<diagram type="temperature" style="percepted" name="temperatura odczuwana" color="darkcyan" values="left"> <point value="8.0"/> <point value="7.8"/> ... <point value="20.5"/></diagram><diagram type="temperature" style="average" name="temperatura uśredniona" color="firebrick" values="right"> <point value="9.8" min_value="5.4" max_value="10.4"/> <point value="9.5" min_value="5.0" max_value="10.3"/> ... <point value="20.5" min_value="17.7" max_value="21.9"/></diagram>

Rys.4.7. Fragment kodu źródłowego (pominięto dane wewnętrznych punktówwykresu) dokumentu XML zawierającego dane, na podstawie których

generowany jest wykres temperatury (pełny kod źródłowy można znaleźć wrozdziale 6.2.1).

- 98/141 -

Page 99: SVG

Rys.4.8. Wykres temperatury jako rysunek SVG wygenerowany na podstawieźródłowego dokumentu XML za pośrednictwem przygotowanego arkusza

stylu XSLT (podgląd wygenerowany w przeglądarce internetowej „Opera”).

W drugim przykładzie chciałbym przedstawić dwa zupełnie różne wykresy na

jednym diagramie. Uzyskanie takiego efektu jest możliwe dzięki opisanym

wcześniej mechanizmom, zaimplementowanym w dokumencie z danymi oraz

w arkuszu transformacji.

Wartości odnoszące się do danych opisanych wzdłuż lewej osi Y dotyczą

intensywności opadów (tutaj również wyróżnione zostaną różne style

wykresów: opady ciągłe deszczu, opady przelotne deszczu oraz opady

śniegu), natomiast prawa oś Y odnosi się do danych wilgotności powietrza.

Ponieważ budowa dokumentu XML dla każdego typu wykresu jest analogiczna

jak dla wykresu temperatury, skupię się wyłącznie do wskazaniu różnic

pomiędzy tymi dwoma dokumentami.

W elemencie nadrzędnym XML można określić kolor tła diagramu.

Skorzystajmy zatem z tej funkcjonalności i przypiszmy mu inny kolor, tym

razem jasnoniebieski:

<weather diagram_bckg_color="lightskyblue">...</weather>

- 99/141 -

Page 100: SVG

Sekcja <description> również musi ulec zmianom, ponieważ powinna

uwzględniać nowy tytuł wykresu. Dodatkowo musi ona uwzględniać fakt, że

dwa zupełnie różne typy wykresów będą przedstawione na tym samym

rysunku. Konieczne jest zatem wstawienie dodatkowe elementu podrzędnego

<additional_title>:

<description> <title outline_color="steelblue"> <![CDATA[opady - precipitation - Niederschlag (mm/h : kg/m³h)]]> </title> <additional_title outline_color="darkgreen"> <![CDATA[wilgotność - humidity - Feuchtigkeit (%)]]> </additional_title></description>

Sekcja <dates> dokumentu XML pozostanie bez zmian, ponieważ chcemy,

aby opady oraz wilgotność dotyczyły dokładnie tego samego okresu, którego

dotyczył wykres temperaturowy. Natomiast w przypadku sekcji <values>

konieczne są zmiany, ponieważ możliwe do osiągnięcia wartości opadów oraz

wilgotności różnią się znacząco od temperatury. W związku z tym atrybutom

left elementów <value> przypiszemy zakres opadów od 0 do 8 mm3,

natomiast atrybutom right zakres wilgotności od 20 do 100%:

<values left_color_shadow="gray" right_color_shadow="steelblue"> <value left="0" right="20"/> <value left="0.2" right="40"/> <value left="0.5" right="60"/> <value left="1" right="80"/> <value left="2" right="90"/> <value left="4" right="95"/> <value left="6" right="98"/> <value left="8" right="100"/></values>

W ten oto sposób zdefiniowaliśmy „szkielet” diagramu dla wykresów opadów

- 100/141 -

Page 101: SVG

oraz wilgotności. Pozostaje teraz tylko nanieść na niego odpowiednie

wartości, a arkusz stylu XSLT dokona właściwej transformacji i wygeneruje

dla nas gotowy rysunek SVG.

Chcemy przedstawić cztery różne wykresy. Sposób ich wykreślania na rysunku

determinowany jest przez wartości dwóch atrybutów (type oraz style)

elementu <diagram>. Dla wykresów opadowych

(type="precipitation") zastosujemy następujące style:

style="rainfall" dla ciągłego opadu deszczu, style="rainfall" dla

opadu śniegu (ten sam styl, ponieważ oba wykresy są wykreślane w ten sam

sposób; to, co je odróżnia, to kolor – dla deszczu wykres rysowany będzie w

kolorze niebieskim, dla śniegu w kolorze białym) oraz

style="occasional" dla przelotnego opadu deszczu. Dla wykresu

wilgotności (type="humidity") zastosowany zostanie styl liniowy:

style="line". Ostatecznie, po przypisaniu wartości kolejnym punktom

wykresu, w źródłowym dokumencie XML znaleźć będzie można dane, których

fragment przedstawiony został na rysunku 4.9, natomiast pełny kod źródłowy

tak przygotowanego dokumentu XML można przeglądać w rozdziale 6.2.2.

<diagram type="precipitation" style="rainfall" name="deszcz ciągły" color="cadetblue" values="left"> <point value="1.13"/> ... <point value="3.95"/></diagram><diagram type="precipitation" style="rainfall" name="śnieg" color="ghostwhite" values="left"> <point value="0.17"/> ... <point value="0.12"/></diagram><diagram type="precipitation" style="occasional" name="deszcz przelotny" color="darkcyan" values="left"> <point value="0.21"/> ... <point value="0.30"/>

- 101/141 -

Page 102: SVG

</diagram><diagram type="humidity" style="line" name="wilgotność" color="darkgreen" values="right"> <point value="94.5"/> ... <point value="27.6"/></diagram>

Rys.4.9. Fragment kodu źródłowego (pominięto dane wewnętrznych punktówwykresu) dokumentu XML zawierającego dane, na podstawie których na

jednym rysunku generowane są wykresy opadów oraz wilgotności (pełny kodźródłowy można znaleźć w rozdziale 6.2.2).

Dysponując gotowymi danymi pogody, możemy przystąpić do zastosowania w

ich kontekście arkusza transformacji XSLT, w rezultacie którego otrzymamy

gotowy rysunek, który w przeglądarce internetowej będzie wyglądał mniej

więcej tak, jak przedstawiono to na rysunku 4.10.

Rys.4.10. Wykres opadów oraz wilgotności powietrza jako rysunek SVGwygenerowany na podstawie źródłowego dokumentu XML za pomocą arkusza

stylu XSLT (podgląd wygenerowany w przeglądarce internetowej „Opera”).

4.2.5. Ocena wykonania aplikacji

W rozdziale 4.2 starałem się szczegółowo i dokładnie opisać jedną z

przygotowanych na potrzeby mojej pracy dyplomowej praktycznych realizacji

- 102/141 -

Page 103: SVG

zastosowania grafiki SVG w ramach potencjalnej aplikacji internetowej,

dostarczającej wizualizacji danych pogodowych w postaci wykresów.

Przedstawione pod koniec rozdziału przykłady udowadniają, że grafika SVG

świetnie spełnia swoją rolę w tym zadaniu i doskonale nadaje się do

prezentacji złożonych wykresów, charakteryzujących różnorodne dane

pogodowe, a odpowiednio dobrane komponenty obrazów dają w efekcie

przejrzyste i czytelne rysunki.

Sposób przygotowania arkusza transformacji XSLT oraz źródłowego

dokumentu XML pozwala na umieszczanie dwóch różnych typów wykresów na

jednym rysunku oraz dowolną liczbę różnych stylów wykresów

zdefiniowanych w obrębie tych typów. Od użytkownika aplikacji zależy tylko,

czy chce on różne rodzaje danych rozbijać na kilka oddzielnych wykresów, czy

też upakować wszystkie z nich na jednym tylko rysunku.

Już wcześniej zwróciłem uwagę na fakt, że dane grafiki zgromadzone w

formacie plików XML oraz XSLT, służących do wygenerowania rysunku SVG,

zajmują o wiele mniej przestrzeni dyskowej niż jakikolwiek rysunek rastrowy,

umożliwiający przedstawienie obrazów o porównywalnej jakości. W

konsekwencji dane przesyłane przez sieć Internet docierają do użytkownika

końcowego znacznie szybciej niż zwykłe obrazy typu JPG czy PNG, co ma

niebagatelny wpływ na jego zadowolenie z korzystania z wybranego serwisu

internetowego. Przypominam tę niezwykle ważną korzyść płynącą z

zastosowania grafiki SVG raz jeszcze, ponieważ uważam ją za jeden z

kluczowych argumentów, przemawiających za korzystaniem właśnie z grafiki

wektorowej zamiast używaniem popularnych i powszechnie stosowanych

obecnie standardów grafiki rastrowej.

4.3. Podsumowanie

Czwarty rozdział pracy dyplomowej zdecydowałem się w całości poświęcić

- 103/141 -

Page 104: SVG

analizie praktycznego wykorzystania grafiki SVG. Odbyło się to poprzez

zrealizowanie kilku aplikacji, które mogłyby znaleźć swoje zastosowanie w

środowisku WWW. Wierzę, że przedstawione przeze mnie przykłady mogły w

sposób kompletny ugruntować pogląd na przydatność oraz niepodważalne zalety

zastosowania grafiki wektorowej SVG w Internecie.

W trakcie edycji kolejnych paragrafów swojej pracy, wielokrotnie wplatałem w

tekst różnorodne wnioski, płynące z analizy konkretnych funkcjonalności, a także

podkreślałem swoje własne poglądy na tematy dotyczące wykorzystania

dyskutowanego standardu w aplikacjach internetowych. Na pierwszy rzut oka

mogłoby się wydawać, że mój ogromny entuzjazm dla jego natychmiastowego

wykorzystania na wszystkich możliwych polach zastosowań, jest nieco

przesadzony. Jednak staranne rozpatrzenie wszystkich korzyści płynących z

wykorzystania każdego jednego małego elementu składowego standardu,

uświadamia nam potęgę możliwości, jaka drzemie w grafice SVG.

SVG może być już teraz bez trudu wykorzystane do budowania nowych lepszych

stron WWW. Obsługa standardu w wersji 1.1 jest bardzo dobra. W przypadku

przeglądarki „Opera” nie zauważyłem praktycznie żadnych wad, które

dyskwalifikowałyby ją z tego zastosowania. Również obsługa SVG w

przeglądarce „Mozilla Firefox” poprawia się wraz z publikacją każdej kolejnej jej

wersji. Czarną owcą w gronie najpopularniejszych przeglądarek internetowych

pozostaje „Internet Explorer” (nic dziwnego, skoro Microsoft forsuje w nim swój

własny standard grafiki wektorowej VML), na szczęście wciąż można

zainstalować w nim odpowiednią wtyczkę, umożliwiającą obsługę grafiki SVG.

Życzyłbym sobie, aby przedstawione przeze mnie w tym rozdziale praktyczne

przykłady realizacji aplikacji internetowych, korzystających z możliwości SVG,

stanowiły zachętę dla innych do dokładniejszego zapoznania się z tym

standardem oraz do śmielszego sięgnięcia po jego wykorzystanie we własnych

projektach. Zadowolenie autora witryny internetowej z dobrze wykonanej pracy

- 104/141 -

Page 105: SVG

może iść śmiało w parze z zadowoleniem odwiedzających ją gości. Jeśli zsumuje

się wszystkie zalety, jakie płyną z wykorzystania będącego przedmiotem mojej

pracy dyplomowej standardu, nie musi to być pusty i nic nie znaczący slogan.

Pracując nad wykonaniem prezentowanych tutaj aplikacji, zdobyłem praktyczne

doświadczenie, umożliwiające mi swobodne operowanie najważniejszymi

możliwościami standardu SVG. Na tej podstawie mogę bez przymusu stwierdzić,

że tworzenie grafiki w oparciu o niego jest bardzo wygodne, nieskomplikowane,

żeby nie powiedzieć banalne. Oczywiście korzystanie z bardziej zaawansowanych

funkcji SVG wymaga większej wprawy, doświadczenia oraz pomysłowości.

Niemniej jednak do realizacji podstawowych celów ich znajomość nie jest

przecież konieczna.

Zastosowanie SVG we własnych aplikacjach mógłbym streścić w kilku słowach:

prostota i elegancja, zarówno podczas projektowania, jak i późniejszego ich

wykonania. Mam nadzieję, że solidnym dowodem na poparcie tych słów są

przykłady moich prac, przedstawionych oraz szczegółowo przeanalizowanych w

tym rozdziale.

- 105/141 -

Page 106: SVG

5. Zakończenie

Przystępując do napisania niniejszej pracy dyplomowej, dwa główne cele, jakie

sobie postawiłem, stanowiły dokładne rozpoznanie grafiki wektorowej SVG oraz

praktyczną realizację kilku aplikacji, korzystających z jej możliwości. Mam nadzieję,

że wiedza teoretyczna poparta licznymi przykładami, którą starałem się jak

najlepiej przedstawić w części przeglądowej pracy, daje solidny obraz tego, co

można uzyskać, posługując się grafiką wektorową. Trzeci rozdział mojej pracy

może stanowić doskonały punkt wyjścia do zgłębiania tajników SVG dla każdej

osoby rozpoczynającej swoją przygodę z wykorzystaniem grafiki wektorowej.

Jestem przekonany, że zebrane we wspomnianym rozdziale informacje mogą

stanowić wartościowe źródło wiedzy na opisywany temat.

Być może aplikacje zrealizowane na potrzeby części praktycznej tej pracy nie są

szczególnie imponujące, biorąc pod uwagę fantastyczne możliwości, jakie daje

- 106/141 -

Page 107: SVG

doświadczonemu artyście standard SVG. Chciałbym jednak zwrócić uwagę na fakt,

iż wykonałem je całkowicie samodzielnie. Nie wzorowałem się w trakcie ich

opracowywania na żadnych innych gotowych aplikacjach, mogących realizować

podobne funkcje. Kod źródłowy poszczególnych aplikacji został przygotowany

wyłącznie na potrzeby tej pracy. Od samego początku zamierzałem stworzyć

produkt oryginalny i ten cel z całą pewnością osiągnąłem, z czego mogę być

bardzo zadowolony.

Z całą pewnością pole do popisu w dziedzinie grafiki wektorowej jest ogromne.

Wielokrotnie starałem się wykazać, jak potężne możliwości tkwią w SVG. Tworzenie

grafiki w tym formacie jest limitowane praktycznie tylko i wyłącznie talentem i

wyobraźnią twórcy. Liczba możliwych do zrealizowania aplikacji, korzystających z

SVG, jest praktycznie niczym nieograniczona. Wszędzie, gdzie tylko istnieje

potrzeba wizualizacji jakiejkolwiek informacji, można tego dokonać za pomocą

grafiki SVG. Jej zastosowanie da w efekcie oszczędność czasu (dzięki prostocie i

szybkości generowania rysunków), zasobów dyskowych (niewielkie rozmiary

plików) oraz nerwów (dzięki małym rozmiarom rysunki SVG przesyłane są przez

sieć w o wiele krótszym czasie niż ich rastrowe odpowiedniki), a jednocześnie

pozwoli na generowanie obrazów o najwyższej jakości (dzięki wektorowej

reprezentacji danych), bezstratnie dających się pomniejszać lub powiększać (dzięki

ich skalowalności). Dokładne zapoznanie się ze standardem SVG pozwala mi na tak

wielki entuzjazm w ocenie możliwych jego zastosowań.

Niniejsza praca dyplomowa w żadnym wypadku nie zamyka tematu analizy

obszarów możliwego wykorzystania grafiki SVG. Dalsze kierunki badań powinny

dotyczyć między innymi szczegółowego przeglądu wszystkich detali, opisywanych

w rekomendacji W3C. W swojej pracy skupiłem się na przeglądzie standardu jako

całości, ale z całą pewnością równie obszerna mogłaby być szczegółowa analiza

wybranych tylko zagadnień funkcjonalnych SVG, np. filtrów lub problemów

związanych z wyświetlaniem tekstu na rysunkach. Niemal każdy rozdział

rekomendacji obejmuje na tyle szerokie spektrum zagadnień, że wart jest

- 107/141 -

Page 108: SVG

starannej i szczegółowej analizy.

Oprócz zagadnień ściśle teoretycznych bardzo wiele można zrealizować jeszcze na

polu praktycznym. Naturalnie oczywisty wydaje się być rozwój zupełnie nowych

aplikacji, korzystających z grafiki wektorowej SVG. Duże pole do popisu istnieje

jednak również w zakresie rozbudowy przygotowanych przeze mnie w ramach tej

pracy aplikacji. Możliwa jest ich rozbudowa o nowe funkcjonalności, które

sygnalizowałem już w treści czwartego rozdziału pracy. Warto byłoby z całą

pewnością opracować dedykowane ich obsłudze interfejsy administracyjne na

poziomie WWW, które mogłyby służyć do zautomatyzowanego generowania

różnorodnych wykresów. Innym cennym pomysłem mogłoby być opracowanie

stron WWW korzystających z generowanych przez moje aplikacje wykresów

statystycznych lub pogodowych, wstawiających rysunki SVG do swojej zawartości.

Bliższe poznanie standardu SVG wzbudziło mój wielki entuzjazm. Chciałbym, aby

ten entuzjazm udzielił się również czytelnikom niniejszej pracy dyplomowej. Jestem

przekonany, że w przyszłości skorzystam nieraz z możliwości oferowanych przez

grafikę SVG w trakcie projektowania swoich własnych witryn WWW oraz innych

aplikacji internetowych.

- 108/141 -

Page 109: SVG

6. Dodatki: kody źródłowe

W dodatkowym rozdziale mojej pracy dyplomowej postanowiłem zamieścić kody

źródłowe wszystkich zrealizowanych przeze mnie (w ramach części praktycznej)

aplikacji, które w sposób szczegółowy zostały omówione w rozdziale czwartym.

6.1. Generator wykresów statystycznych

W tej sekcji zawarte zostały wszystkie kody źródłowe przygotowane w trakcie

opracowywania generatora wykresów statystycznych.

6.1.1. Moduł (klasa) ChartSVG do generowania wykresów

Kod źródłowy modułu „ChartSVG” opracowałem w języku skryptowym Perl:

package ChartSVG;

- 109/141 -

Page 110: SVG

use Carp;

# Lewy gorny rog polozenia calego rysunku oraz jego calkowita wysokosc:use constant _ALL_LEFT => 3;use constant _ALL_TOP => 3;use constant _ALL_HEIGHT => 300;# Szerokosc pikselowa, poswiecana na jeden slupek diagramu oraz szerokosc wlasciwa slupka:use constant _FOR_BAR_WIDTH => 45;use constant _BAR_WIDTH => 40;use constant _FREE_SPACE_BARS => _FOR_BAR_WIDTH - _BAR_WIDTH;# Minimalna szerokosc wykresu, jezeli nie wprowadzono zadnych danych:use constant _DIAGRAM_MIN_WIDTH => 50;# Odleglosc poziomu poczatku slupkow (i dolnej osi opisu) od dolnej krawedzi ramki:use constant _SPACE_AT_BOTTOM => 80;# Odleglosc najwyzszego poziomu slupkow (i miejsca na tytul wykresu)od gornej krawedzi ramki:use constant _SPACE_AT_TOP => 30;# Dodatkowe miejsce na wpisanie wartosci powyzej najwyzszego slupka:use constant _SPACE_AT_BAR_TOP => 10;

sub new { my $proto = shift; my $class = ref( $proto ) || $proto; my $self = {}; $self->{HOWMANY} = 0; $self->{SIZE} = 1; $self->{PERCENTAGE} = 0; $self->{MAX_ENTRIES_ON_DIAGRAM} = 10; $self->{ENTRIES} = []; $self->{TITLE} = "You Haven't Set The Diagram Title"; $self->{AXIS_Y_DESC} = ""; bless( $self, $class ); return $self;}

sub set_y_desc { my $self = shift; $self->{AXIS_Y_DESC} = shift;}

sub add { my $self = shift; my( $name, $number ) = @_; # Test if $number really contains a number: if( !( $number =~ m/^\d*?\.?\d*?$/ ) ) { carp "FATAL ERROR: entry not added ($number is not a number!)"; return; } # Create a new hash containing the information on newly added entry: my %new_entry; $new_entry{"NAME"} = $name;

- 110/141 -

Page 111: SVG

$new_entry{"NUMBER"} = $number; # Add this hash to the ENTRIES table through reference: $self->{ENTRIES}[$self->{HOWMANY}] = \%new_entry; ++$self->{HOWMANY};}

sub set_title { my $self = shift; $self->{TITLE} = shift;}

sub entries { my $self = shift; return $self->{HOWMANY};}

sub show_all { my $self = shift; for( my $i=0; $i<$self->{HOWMANY}; $i++ ) { printf "name: %-20s number: %-5.2f\n", $self->{ENTRIES}[$i]{"NAME"}, $self->{ENTRIES}[$i]{"NUMBER"}; }}

sub sort_all { my $self = shift; for( my $i=($self->{HOWMANY}-1); $i>=0; $i-- ) { for( my $j=0; $j<$i; $j++ ) { if( $self->{ENTRIES}[$j]{"NUMBER"} < $self->{ENTRIES}[$j+1]{"NUMBER"} ) { ( $self->{ENTRIES}[$j], $self->{ENTRIES}[$j+1] ) = ( $self->{ENTRIES}[$j+1], $self->{ENTRIES}[$j] ); } } }}

sub max { my $a = shift; my $b = shift; return $a > $b ? $a : $b; }sub MAX { my( $max ) = pop( @_ ); foreach my $foo ( @_ ) { $max = $foo if $max < $foo; } return $max; }sub min { my $a = shift; my $b = shift; return $a < $b ? $a : $b; }sub MIN { my( $min ) = pop( @_ ); foreach my $foo ( @_ ) { $min = $foo if $min > $foo; } return $min; }

sub calc_y_val { my $self = shift; my $max_val = shift; my @values; # Dziele wartosc maksymalna przez 10 tak dlugo, az uda mi sie uzyskac wartosc mniejsza niz 10: my $new_max = $max_val; my $przez_ile_dzielone = 1; while( $new_max > 10 ) { $przez_ile_dzielone *= 10; $new_max /= 10; }

- 111/141 -

Page 112: SVG

# Jesli uzyskana wartosc jest mniejsza niz pewna okreslona wartosc,to mnoze ja celem powiekszenia ilosci kreseczek na osi Y: if( $new_max <= 2 ) { $przez_ile_dzielone /= 5; $new_max *= 5; } elsif( $new_max <= 5 ) { $przez_ile_dzielone /= 2; $new_max *= 2; } # Bierzemy tylko calkowite czesci z wszystkich liczb <= $new_max: my $i; $przez_ile_dzielone = int( $przez_ile_dzielone ); for( $i=0; $i<=$new_max; $i++ ) { $values[$i] = $i * $przez_ile_dzielone; } # $values[$i] = $max_val; return @values;}

sub make_image { my $self = shift; # $img_type: WHEEL -> kolowy, BAR -> slupkowy my( $filename, $img_type ) = @_; # Prepare miscellaneous image variables: my $size = $self->{SIZE}; my $value_type; if( $self->{PERCENTAGE} == 0 ) { $value_type = 'NUMBER'; } else { $value_type = 'PERCENT'; } # Sort all entries ascending: $self->sort_all(); # Open the target file for writing: open( SVG, ">$filename" ); # Prepare the SVG headers: my $svg = "<?xml version=\"1.0\" encoding=\"windows-1250\" standalone=\"no\" ?>\n"; $svg .= "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"; # Okresl szerokosc wlasciwego diagramu: my $szerokosc = min( $self->{HOWMANY}, $self->{MAX_ENTRIES_ON_DIAGRAM} ) * _FOR_BAR_WIDTH + _DIAGRAM_MIN_WIDTH; my $viewBoxCx = $szerokosc + _ALL_LEFT * 2; my $viewBoxCy = _ALL_HEIGHT + _ALL_TOP * 2; $svg .= "<svg width=\"100%\" height=\"100%\" viewBox=\"0 0 $viewBoxCx $viewBoxCy\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n"; # Narysuj podstawowe tlo pod calym obszarem rysunku: my( $all_left, $all_top, $all_right, $all_bottom ) = ( 0, 0, $viewBoxCx, $viewBoxCy ); $svg .= " <path stroke=\"#117711\" fill=\"#AADDAA\" d=\"M $all_left$all_top L $all_right $all_top L $all_right $all_bottom L $all_left $all_bottom Z\" />\n"; # Okresl wielkosc diagramu: my( $ins_left, $ins_top, $ins_right, $ins_bottom ) = ( _ALL_LEFT, _ALL_TOP, $szerokosc + _ALL_LEFT, _ALL_HEIGHT + _ALL_TOP ); # Wyrysuj obramowanie diagramu: # $svg .= " <rect x=\"$left\" y=\"$top\" width=\"$width\" height=\"$height\" stroke=\"#228822\" fill=\"#EEFFEE\" />\n"; $svg .= " <path stroke=\"#228822\" fill=\"#EEFFEE\" d=\"M $ins_left$ins_top L $ins_right $ins_top L $ins_right $ins_bottom L $ins_left $ins_bottom Z\" />"; # Wypisz na gorze tytul wykresu: my( $txt_head_y, $txt_head_x ) = ( _ALL_TOP + _SPACE_AT_TOP - 7,

- 112/141 -

Page 113: SVG

$ins_left + ( $ins_right - $ins_left ) / 2 - 2 ); $svg .= " <text x=\"$txt_head_x\" y=\"$txt_head_y\" font-family=\"Verdana\" text-anchor=\"middle\" font-size=\"21\" fill=\"#006600\">"; $svg .= $self->{TITLE}; $svg .= "</text>\n"; # Check out the diagram type: if( $img_type eq "WHEEL" ) { # Generate wheeled SVG chart: print "Generating wheeled SVG chart...\n"; # Current diagram: $svg .= " <circle cx=\"200\" cy=\"200\" r=\"180\" stroke=\"red\" stroke-width=\"20\" fill=\"black\" />\n"; print "OK!\n"; } elsif( $img_type eq "BAR" ) { # Generate bar SVG chart: print "Generating bar SVG chart..."; # Define the vertical linear gradient for diagrams: $svg .= " <defs>\n"; $svg .= " <linearGradient id=\"gradient_01\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n"; $svg .= " <stop offset=\"0%\" style=\"stop-color:rgb(32,32,255);stop-opacity:1\" />\n"; $svg .= " <stop offset=\"100%\" style=\"stop-color:rgb(0,0,128);stop-opacity:1\" />\n"; $svg .= " </linearGradient>\n"; $svg .= " </defs>\n"; $svg .= " <defs>\n"; $svg .= " <linearGradient id=\"gradient_02\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n"; $svg .= " <stop offset=\"0%\" style=\"stop-color:rgb(64,64,255);stop-opacity:1\" />\n"; $svg .= " <stop offset=\"100%\" style=\"stop-color:rgb(16,16,255); stop-opacity:1\" />\n"; $svg .= " </linearGradient>\n"; $svg .= " </defs>\n"; # Znajdz najwieksza wartosc sposrod wszystkich elementow: my @temp; for( my $i=0; $i<$self->{HOWMANY}; $i++ ) { $temp[$i] = $self->{ENTRIES}[$i]{"NUMBER"}; } my $max_wartosc = MAX( @temp ); # Okresl obramowanie wykresu: my( $dia_left, $dia_top, $dia_right, $dia_bottom ) = ( $ins_left +_DIAGRAM_MIN_WIDTH - _FREE_SPACE_BARS, $ins_top + _SPACE_AT_TOP - 1,$ins_right - _FREE_SPACE_BARS, $ins_bottom - _SPACE_AT_BOTTOM ); # Linia pionowa na wartosci i linia pozioma na kolejne elementy: $svg .= "<polyline fill=\"none\" stroke=\"#222222\" stroke-width=\"2\" points=\"$dia_left,$dia_top $dia_left,$dia_bottom $dia_right,$dia_bottom\" />"; # Oblicz wartosci, ktore beda wyswietlane na osi Y: my @values = $self->calc_y_val( $max_wartosc ); my $jednostka_wysokosci = ( $dia_bottom - $dia_top - _SPACE_AT_BAR_TOP ) / $max_wartosc; my( $left_kreseczka, $right_kreseczka ) = ( $dia_left - 2, $dia_left + 2 ); for( my $i=0; $i<@values; $i++ ) { # Wypisz kreseczke pozioma na osi Y, symbolizujacac poziom

- 113/141 -

Page 114: SVG

wartosci na wykresie: my $poz_y = $dia_bottom - int( $jednostka_wysokosci * $values[$i]); $svg .= " <path stroke=\"#222222\" fill=\"none\" d=\"M $left_kreseczka $poz_y L $right_kreseczka $poz_y\" />\n"; # Wypisz liczbe okreslajaca wartosc na tym poziomie: my( $value_number_x, $value_number_y ) = ( $right_kreseczka - 6, $poz_y + 4 ); $svg .= " <text x=\"$value_number_x\" y=\"$value_number_y\" font-family=\"Tahoma\" font-weight=\"bold\" text-anchor=\"end\" font-size=\"10\" fill=\"#117711\">"; $svg .= $values[$i]; if( $self->{PERCENTAGE} == 1 ) { $svg .= "%"; } $svg .= "</text>\n"; } # Wypisz na gorze osi Y nazwe wyswietlanych jednostek: if( $self->{AXIS_Y_DESC} ) { my( $pos_x_desc, $pos_y_desc ) = ( $right_kreseczka - 4, $dia_top+ 4 ); $svg .= " <text x=\"$pos_x_desc\" y=\"$pos_y_desc\" font-family=\"Tahoma\" font-weight=\"bold\" text-anchor=\"end\" font-size=\"8\" fill=\"#117711\">["; $svg .= $self->{AXIS_Y_DESC}; $svg .= "]</text>\n"; } # Znajdz wielkosci zmiennych potrzebne do wyrysowywania kolejnych slupkow: my $max_wysokosc = $ins_bottom - $ins_top - _SPACE_AT_TOP - _SPACE_AT_BAR_TOP - _SPACE_AT_BOTTOM; my $jednostka_wysokosci = $max_wysokosc / $max_wartosc; # Wyrysuj slupek dla kazdego elementu: for( my $i=0; $i<$self->{HOWMANY}; $i++ ) { last if( $i == $self->{MAX_ENTRIES_ON_DIAGRAM} ); # Zbuduj slupek dla wybranego elementu: my $slupek_left = $ins_left + _DIAGRAM_MIN_WIDTH + $i * _FOR_BAR_WIDTH; my $slupek_width = _BAR_WIDTH; my $slupek_height = int( $jednostka_wysokosci * $self->{ENTRIES}[$i]{"NUMBER"} ); my $slupek_top = $ins_bottom - _SPACE_AT_BOTTOM - $slupek_height - 1; my $gradient; if( $i % 2 ) { $gradient = "gradient_01"; } else { $gradient = "gradient_02"; } $svg .= " <rect x=\"$slupek_left\" y=\"$slupek_top\" width=\"$slupek_width\" height=\"$slupek_height\" style=\"fill:url(#$gradient)\" />\n"; # Wypisz tekst opisujacy kazdy ze slupkow u jego dolu: my( $txt_pos_x, $txt_pos_y ) = ( $slupek_left + _BAR_WIDTH / 2, $ins_bottom - _SPACE_AT_BOTTOM + 12 ); $svg .= " <g transform=\"translate($txt_pos_x $txt_pos_y)\">\n"; $svg .= " <g transform=\"rotate(-50)\">\n"; $svg .= " <text x=\"0\" y=\"0\" font-family=\"Tahoma\" text-anchor=\"end\" font-size=\"14\" fill=\"#117711\">"; $svg .= $self->{ENTRIES}[$i]{"NAME"}; $svg .= "</text>\n"; $svg .= " </g>\n";

- 114/141 -

Page 115: SVG

$svg .= " </g>\n"; # Wpisz wartosc dla kazdego ze slupkow ponad nim: my( $number_x, $number_y ) = ( $slupek_left + int( $slupek_width / 2 ) + 1, $slupek_top - 2 ); $svg .= " <text x=\"$number_x\" y=\"$number_y\" font-family=\"Tahoma\" font-weight=\"bold\" text-anchor=\"middle\" font-size=\"10\" fill=\"#117711\">"; $svg .= sprintf( "%.2f", $self->{ENTRIES}[$i]{"NUMBER"} ); # Dopisujemy za liczba znak procenta, jezeli jest to wykres procentowy: if( $self->{PERCENTAGE} == 1 ) { $svg .= "%"; } $svg .= "</text>\n"; } print "OK!\n"; } $svg .= "</svg>"; print SVG $svg; close( SVG );}

1;

6.1.2. Porównanie liczby ludności państw świata

Kod źródłowy generujący rysunek SVG przedstawiający porównanie liczby

ludności w najludniejszych państwach świata opracowałem w języku

skryptowym Perl w oparciu o moduł „ChartSVG”:

#!/usr/bin/perl

use strict;use ChartSVG;

my $myChart = ChartSVG->new();$myChart->set_title( "LUDNOŚĆ PAŃSTW ŚWIATA" );$myChart->set_y_desc( "mln" );$myChart->add( "Chiny", 1306.3 );$myChart->add( "Indie", 1080.3 );$myChart->add( "USA", 295.7 );$myChart->add( "Indonezja", 242.0 );$myChart->add( "Brazylia", 186.1 );$myChart->add( "Pakistan", 162.4 );$myChart->add( "Bangladesz", 144.3 );$myChart->add( "Rosja", 143.4 );$myChart->add( "Nigeria", 128.8 );$myChart->add( "Japonia", 127.4 );

$myChart->make_image( "kraje.svg", "BAR" );

Kod źródłowy wygenerowanego za pomocą powyższego skryptu rysunku

- 115/141 -

Page 116: SVG

SVG:

<?xml version="1.0" encoding="windows-1250" standalone="no" ?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 506 306" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path stroke="#117711" fill="#AADDAA" d="M 0 0 L 506 0 L 506 306 L 0 306 Z" /> <path stroke="#228822" fill="#EEFFEE" d="M 3 3 L 503 3 L 503 303 L 3 303 Z" /> <text x="251" y="26" font-family="Verdana" text-anchor="middle" font-size="21" fill="#006600">LUDNOŚĆ PAŃSTW ŚWIATA</text> <defs> <linearGradient id="gradient_01" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" style="stop-color:rgb(32,32,255); stop-opacity:1" /> <stop offset="100%" style="stop-color:rgb(0,0,128); stop-opacity:1" /> </linearGradient> </defs> <defs> <linearGradient id="gradient_02" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" style="stop-color:rgb(64,64,255); stop-opacity:1" /> <stop offset="100%" style="stop-color:rgb(16,16,255); stop-opacity:1" /> </linearGradient> </defs><polyline fill="none" stroke="#222222" stroke-width="2" points="48,32 48,223 498,223" /> <path stroke="#222222" fill="none" d="M 46 223 L 50 223" /> <text x="44" y="227" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">0</text> <path stroke="#222222" fill="none" d="M 46 196 L 50 196" /> <text x="44" y="200" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">200</text> <path stroke="#222222" fill="none" d="M 46 168 L 50 168" /> <text x="44" y="172" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">400</text> <path stroke="#222222" fill="none" d="M 46 140 L 50 140" /> <text x="44" y="144" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">600</text> <path stroke="#222222" fill="none" d="M 46 113 L 50 113" /> <text x="44" y="117" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">800</text> <path stroke="#222222" fill="none" d="M 46 85 L 50 85" /> <text x="44" y="89" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">1000</text> <path stroke="#222222" fill="none" d="M 46 57 L 50 57" /> <text x="44" y="61" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">1200</text> <text x="46" y="36" font-family="Tahoma" font-weight="bold" text-

- 116/141 -

Page 117: SVG

anchor="end" font-size="8" fill="#117711">[mln]</text> <rect x="53" y="42" width="40" height="180" style="fill:url(#gradient_02)" /> <g transform="translate(73 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">Chiny</text> </g> </g> <text x="74" y="40" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">1306.30</text> <rect x="98" y="74" width="40" height="148" style="fill:url(#gradient_01)" /> <g transform="translate(118 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">Indie</text> </g> </g> <text x="119" y="72" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">1080.30</text> <rect x="143" y="182" width="40" height="40" style="fill:url(#gradient_02)" /> <g transform="translate(163 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">USA</text> </g> </g> <text x="164" y="180" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">295.70</text> <rect x="188" y="189" width="40" height="33" style="fill:url(#gradient_01)" /> <g transform="translate(208 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">Indonezja</text> </g> </g> <text x="209" y="187" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">242.00</text> <rect x="233" y="197" width="40" height="25" style="fill:url(#gradient_02)" /> <g transform="translate(253 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">Brazylia</text> </g> </g> <text x="254" y="195" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">186.10</text> <rect x="278" y="200" width="40" height="22" style="fill:url(#gradient_01)" /> <g transform="translate(298 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-

- 117/141 -

Page 118: SVG

size="14" fill="#117711">Pakistan</text> </g> </g> <text x="299" y="198" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">162.40</text> <rect x="323" y="203" width="40" height="19" style="fill:url(#gradient_02)" /> <g transform="translate(343 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">Bangladesz</text> </g> </g> <text x="344" y="201" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">144.30</text> <rect x="368" y="203" width="40" height="19" style="fill:url(#gradient_01)" /> <g transform="translate(388 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">Rosja</text> </g> </g> <text x="389" y="201" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">143.40</text> <rect x="413" y="205" width="40" height="17" style="fill:url(#gradient_02)" /> <g transform="translate(433 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">Nigeria</text> </g> </g> <text x="434" y="203" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">128.80</text> <rect x="458" y="205" width="40" height="17" style="fill:url(#gradient_01)" /> <g transform="translate(478 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">Japonia</text> </g> </g> <text x="479" y="203" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">127.40</text></svg>

6.1.3. Porównanie wyników wyborów parlamentarnych

Kod źródłowy generujący rysunek SVG przedstawiający fikcyjne wyniki

wyborów parlamentarnych w 2006 roku opracowałem w języku skryptowym

- 118/141 -

Page 119: SVG

Perl w oparciu o moduł „ChartSVG”:

#!/usr/bin/perl

use strict;use ChartSVG;

my $myChart = ChartSVG->new();$myChart->set_title( "WYBORY PARLAMENTARNE 2006" );$myChart->set_y_desc( "%" );$myChart->add( "SLD", "7.86" );$myChart->add( "UPR", 5.76 );$myChart->add( "PO", 22.19 );$myChart->add( "PiS", 21.22 );$myChart->add( "SdPL", 2.83 );$myChart->add( "LPR", 4.87 );$myChart->add( "Samoobrona", 6.01 );$myChart->add( "PSL", 4.14 );$myChart->add( "KPEiR", 0.24 );$myChart->add( "PD", 2.35 );

$myChart->make_image( "wybory.svg", "BAR" );

Kod źródłowy wygenerowanego za pomocą powyższego skryptu rysunku

SVG:

<?xml version="1.0" encoding="windows-1250" standalone="no" ?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 506 306" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path stroke="#117711" fill="#AADDAA" d="M 0 0 L 506 0 L 506 306 L 0 306 Z" /> <path stroke="#228822" fill="#EEFFEE" d="M 3 3 L 503 3 L 503 303 L 3 303 Z" /> <text x="251" y="26" font-family="Verdana" text-anchor="middle" font-size="21" fill="#006600">WYBORY PARLAMENTARNE 2006</text> <defs> <linearGradient id="gradient_01" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" style="stop-color:rgb(32,32,255); stop-opacity:1" /> <stop offset="100%" style="stop-color:rgb(0,0,128); stop-opacity:1" /> </linearGradient> </defs> <defs> <linearGradient id="gradient_02" x1="0%" y1="0%" x2="0%" y2="100%"> <stop offset="0%" style="stop-color:rgb(64,64,255); stop-opacity:1" /> <stop offset="100%" style="stop-color:rgb(16,16,255); stop-opacity:1" />

- 119/141 -

Page 120: SVG

</linearGradient> </defs><polyline fill="none" stroke="#222222" stroke-width="2" points="48,32 48,223 498,223" /> <path stroke="#222222" fill="none" d="M 46 223 L 50 223" /> <text x="44" y="227" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">0</text> <path stroke="#222222" fill="none" d="M 46 183 L 50 183" /> <text x="44" y="187" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">5</text> <path stroke="#222222" fill="none" d="M 46 142 L 50 142" /> <text x="44" y="146" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">10</text> <path stroke="#222222" fill="none" d="M 46 101 L 50 101" /> <text x="44" y="105" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">15</text> <path stroke="#222222" fill="none" d="M 46 60 L 50 60" /> <text x="44" y="64" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="10" fill="#117711">20</text> <text x="46" y="36" font-family="Tahoma" font-weight="bold" text-anchor="end" font-size="8" fill="#117711">[%]</text> <rect x="53" y="42" width="40" height="180" style="fill:url(#gradient_02)" /> <g transform="translate(73 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">PO</text> </g> </g> <text x="74" y="40" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">22.19</text> <rect x="98" y="50" width="40" height="172" style="fill:url(#gradient_01)" /> <g transform="translate(118 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">PiS</text> </g> </g> <text x="119" y="48" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">21.22</text> <rect x="143" y="159" width="40" height="63" style="fill:url(#gradient_02)" /> <g transform="translate(163 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">SLD</text> </g> </g> <text x="164" y="157" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">7.86</text> <rect x="188" y="174" width="40" height="48" style="fill:url(#gradient_01)" /> <g transform="translate(208 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-

- 120/141 -

Page 121: SVG

size="14" fill="#117711">Samoobrona</text> </g> </g> <text x="209" y="172" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">6.01</text> <rect x="233" y="176" width="40" height="46" style="fill:url(#gradient_02)" /> <g transform="translate(253 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">UPR</text> </g> </g> <text x="254" y="174" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">5.76</text> <rect x="278" y="183" width="40" height="39" style="fill:url(#gradient_01)" /> <g transform="translate(298 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">LPR</text> </g> </g> <text x="299" y="181" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">4.87</text> <rect x="323" y="189" width="40" height="33" style="fill:url(#gradient_02)" /> <g transform="translate(343 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">PSL</text> </g> </g> <text x="344" y="187" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">4.14</text> <rect x="368" y="200" width="40" height="22" style="fill:url(#gradient_01)" /> <g transform="translate(388 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">SdPL</text> </g> </g> <text x="389" y="198" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">2.83</text> <rect x="413" y="203" width="40" height="19" style="fill:url(#gradient_02)" /> <g transform="translate(433 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">PD</text> </g> </g> <text x="434" y="201" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">2.35</text> <rect x="458" y="221" width="40" height="1"

- 121/141 -

Page 122: SVG

style="fill:url(#gradient_01)" /> <g transform="translate(478 235)"> <g transform="rotate(-50)"> <text x="0" y="0" font-family="Tahoma" text-anchor="end" font-size="14" fill="#117711">KPEiR</text> </g> </g> <text x="479" y="219" font-family="Tahoma" font-weight="bold" text-anchor="middle" font-size="10" fill="#117711">0.24</text></svg>

6.2. Generator wykresów pogodowych

W tej sekcji zawarte zostały wszystkie kody źródłowe przygotowane w trakcie

opracowywania generatora wykresów pogodowych.

6.2.1. Dane XML do wykresu temperatury

Dane temperatury zebrane do pliku w formacie XML:

<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="weather.xsl"?><weather diagram_bckg_color="ghostwhite"> <description> <title outline_color="darkgreen"><![CDATA[temperatura - temperature - Temperatur (°C)]]></title> </description> <dates> <date day="12 X" hour="0"/> <date day="12 X" hour="3"/> <date day="12 X" hour="6"/> <date day="12 X" hour="9"/> <date day="12 X" hour="12"/> <date day="12 X" hour="15"/> <date day="12 X" hour="18"/> <date day="12 X" hour="21"/> <date day="13 X" hour="0"/> <date day="13 X" hour="3"/> <date day="13 X" hour="6"/> <date day="13 X" hour="9"/> <date day="13 X" hour="12"/> <date day="13 X" hour="15"/> <date day="13 X" hour="18"/> <date day="13 X" hour="21"/> <date day="14 X" hour="0"/> <date day="14 X" hour="3"/> <date day="14 X" hour="6"/> <date day="14 X" hour="9"/> <date day="14 X" hour="12"/>

- 122/141 -

Page 123: SVG

</dates> <values left_color_shadow="darkgray" right_color_shadow="darkgray"> <value left="0" right="0"/> <value left="10" right="10"/> <value left="20" right="20"/> <value left="30" right="30"/> </values> <diagram type="temperature" style="percepted" name="temperatura odczuwana" color="darkcyan" values="left"> <point value="8.0"/> <point value="7.8"/> <point value="7.7"/> <point value="7.9"/> <point value="8.6"/> <point value="9.3"/> <point value="10.4"/> <point value="12.2"/> <point value="14.7"/> <point value="17.2"/> <point value="19.0"/> <point value="20.0"/> <point value="20.5"/> <point value="20.9"/> <point value="21.1"/> <point value="21.0"/> <point value="20.4"/> <point value="18.7"/> <point value="16.5"/> <point value="14.9"/> <point value="14.0"/> <point value="13.4"/> <point value="12.4"/> <point value="10.7"/> <point value="8.7"/> <point value="7.8"/> <point value="7.7"/> <point value="7.9"/> <point value="8.6"/> <point value="9.3"/> <point value="10.4"/> <point value="12.2"/> <point value="14.7"/> <point value="17.2"/> <point value="19.0"/> <point value="20.0"/> <point value="20.5"/> <point value="20.9"/> <point value="21.1"/> <point value="21.0"/> <point value="20.4"/> <point value="18.7"/> <point value="16.5"/> <point value="14.9"/> <point value="14.0"/> <point value="13.4"/> <point value="12.4"/>

- 123/141 -

Page 124: SVG

<point value="10.7"/> <point value="8.7"/> <point value="7.8"/> <point value="7.7"/> <point value="7.9"/> <point value="8.6"/> <point value="9.3"/> <point value="10.4"/> <point value="12.2"/> <point value="14.7"/> <point value="17.2"/> <point value="19.0"/> <point value="20.0"/> <point value="20.5"/> </diagram> <diagram type="temperature" style="average" name="temperatura uśredniona" color="firebrick" values="right"> <point value="9.8" min_value="5.4" max_value="10.4"/> <point value="9.5" min_value="5.0" max_value="10.3"/> <point value="8.9" min_value="4.6" max_value="10.2"/> <point value="8.9" min_value="4.1" max_value="10.1"/> <point value="9.6" min_value="5.9" max_value="11.3"/> <point value="10.3" min_value="7.1" max_value="12.6"/> <point value="11.4" min_value="8.6" max_value="13.7"/> <point value="13.2" min_value="10.3" max_value="16.6"/> <point value="15.7" min_value="12.2" max_value="17.9"/> <point value="18.2" min_value="16.3" max_value="19.6"/> <point value="19.7" min_value="16.7" max_value="20.1"/> <point value="20.3" min_value="17.2" max_value="20.9"/> <point value="20.5" min_value="17.7" max_value="21.9"/> <point value="21.1" min_value="18.0" max_value="22.4"/> <point value="21.6" min_value="18.1" max_value="22.8"/> <point value="22.1" min_value="18.3" max_value="23.4"/> <point value="21.5" min_value="16.6" max_value="22.8"/> <point value="19.7" min_value="14.6" max_value="20.8"/> <point value="17.2" min_value="12.6" max_value="18.8"/> <point value="15.9" min_value="11.0" max_value="17.1"/> <point value="15.0" min_value="10.2" max_value="15.8"/> <point value="14.4" min_value="9.0" max_value="15.1"/> <point value="13.6" min_value="8.4" max_value="14.7"/> <point value="12.0" min_value="6.4" max_value="13.9"/> <point value="9.8" min_value="5.4" max_value="10.4"/> <point value="9.5" min_value="5.0" max_value="10.3"/> <point value="8.9" min_value="4.6" max_value="10.2"/> <point value="8.9" min_value="4.1" max_value="10.1"/> <point value="9.6" min_value="5.9" max_value="11.3"/> <point value="10.3" min_value="7.1" max_value="12.6"/> <point value="11.4" min_value="8.6" max_value="13.7"/> <point value="13.2" min_value="10.3" max_value="16.6"/> <point value="15.7" min_value="12.2" max_value="17.9"/> <point value="18.2" min_value="16.3" max_value="19.6"/> <point value="19.7" min_value="16.7" max_value="20.1"/> <point value="20.3" min_value="17.2" max_value="20.9"/> <point value="20.5" min_value="17.7" max_value="21.9"/> <point value="21.1" min_value="18.0" max_value="22.4"/> <point value="21.6" min_value="18.1" max_value="22.8"/>

- 124/141 -

Page 125: SVG

<point value="22.1" min_value="18.3" max_value="23.4"/> <point value="21.5" min_value="16.6" max_value="22.8"/> <point value="19.7" min_value="14.6" max_value="20.8"/> <point value="17.2" min_value="12.6" max_value="18.8"/> <point value="15.9" min_value="11.0" max_value="17.1"/> <point value="15.0" min_value="10.2" max_value="15.8"/> <point value="14.4" min_value="9.0" max_value="15.1"/> <point value="13.6" min_value="8.4" max_value="14.7"/> <point value="12.0" min_value="6.4" max_value="13.9"/> <point value="9.8" min_value="5.4" max_value="10.4"/> <point value="9.5" min_value="5.0" max_value="10.3"/> <point value="8.9" min_value="4.6" max_value="10.2"/> <point value="8.9" min_value="4.1" max_value="10.1"/> <point value="9.6" min_value="5.9" max_value="11.3"/> <point value="10.3" min_value="7.1" max_value="12.6"/> <point value="11.4" min_value="8.6" max_value="13.7"/> <point value="13.2" min_value="10.3" max_value="16.6"/> <point value="15.7" min_value="12.2" max_value="17.9"/> <point value="18.2" min_value="16.3" max_value="19.6"/> <point value="19.7" min_value="16.7" max_value="20.1"/> <point value="20.3" min_value="17.2" max_value="20.9"/> <point value="20.5" min_value="17.7" max_value="21.9"/> </diagram></weather>

6.2.2. Dane XML do wykresu opadów

Dane opadów zebrane do pliku w formacie XML:

<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="weather.xsl"?><weather diagram_bckg_color="lightskyblue"> <description> <title outline_color="steelblue"><![CDATA[opady - precipitation - Niederschlag (mm/h : kg/m³h)]]></title> <additional_title outline_color="darkgreen"><![CDATA[wilgotność - humidity - Feuchtigkeit (%)]]></additional_title> </description> <dates> <date day="12 X" hour="0"/> <date day="12 X" hour="3"/> <date day="12 X" hour="6"/> <date day="12 X" hour="9"/> <date day="12 X" hour="12"/> <date day="12 X" hour="15"/> <date day="12 X" hour="18"/> <date day="12 X" hour="21"/> <date day="13 X" hour="0"/> <date day="13 X" hour="3"/> <date day="13 X" hour="6"/> <date day="13 X" hour="9"/> <date day="13 X" hour="12"/> <date day="13 X" hour="15"/>

- 125/141 -

Page 126: SVG

<date day="13 X" hour="18"/> <date day="13 X" hour="21"/> <date day="14 X" hour="0"/> <date day="14 X" hour="3"/> <date day="14 X" hour="6"/> <date day="14 X" hour="9"/> <date day="14 X" hour="12"/> </dates> <values left_color_shadow="gray" right_color_shadow="steelblue"> <value left="0" right="20"/> <value left="0.2" right="40"/> <value left="0.5" right="60"/> <value left="1" right="80"/> <value left="2" right="90"/> <value left="4" right="95"/> <value left="6" right="98"/> <value left="8" right="100"/> </values> <diagram type="precipitation" style="rainfall" name="deszcz ciągły"color="cadetblue" values="left"> <point value="1.1"/> <point value="2.5"/> <point value="4.9"/> <point value="5.8"/> <point value="3.6"/> <point value="1.9"/> <point value="1.6"/> <point value="0.7"/> <point value="0.3"/> <point value="0.1"/> <point value="0.02"/> <point value="0.04"/> <point value="0.10"/> <point value="0.18"/> <point value="0.09"/> <point value="0.03"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/>

- 126/141 -

Page 127: SVG

<point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0.05"/> <point value="0.2"/> <point value="0.8"/> <point value="3.1"/> <point value="5.0"/> <point value="6.2"/> <point value="5.5"/> <point value="2.3"/> <point value="0.7"/> <point value="0.2"/> <point value="0.1"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> </diagram> <diagram type="precipitation" style="rainfall" name="śnieg" color="ghostwhite" values="left"> <point value="0.17"/> <point value="0.44"/> <point value="1.1"/> <point value="1.2"/> <point value="0.76"/> <point value="0.41"/> <point value="0.19"/> <point value="0.09"/> <point value="0.03"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/>

- 127/141 -

Page 128: SVG

<point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> </diagram> <diagram type="precipitation" style="occasional" name="deszcz przelotny" color="darkcyan" values="left"> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/>

- 128/141 -

Page 129: SVG

<point value="0"/> <point value="0.04"/> <point value="0.2"/> <point value="0.6"/> <point value="1.2"/> <point value="1"/> <point value="0.97"/> <point value="1.5"/> <point value="2.7"/> <point value="3.1"/> <point value="2.1"/> <point value="1.2"/> <point value="0.66"/> <point value="0.47"/> <point value="0.3"/> <point value="0.21"/> <point value="0.15"/> <point value="0.11"/> <point value="0.06"/> <point value="0.02"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> <point value="0"/> </diagram> <diagram type="humidity" style="line" name="wilgotność" color="darkgreen" values="right"> <point value="94.5"/> <point value="94.7"/> <point value="95.0"/> <point value="95.1"/> <point value="94.9"/> <point value="93.1"/> <point value="85.7"/> <point value="77.0"/> <point value="66.5"/> <point value="59.5"/> <point value="52.0"/> <point value="45.0"/>

- 129/141 -

Page 130: SVG

<point value="40.3"/> <point value="38.7"/> <point value="37.8"/> <point value="39.9"/> <point value="47.0"/> <point value="57.0"/> <point value="66.6"/> <point value="73.0"/> <point value="78.0"/> <point value="80.8"/> <point value="82.2"/> <point value="83.3"/> <point value="84.5"/> <point value="85.5"/> <point value="86.5"/> <point value="87.0"/> <point value="86.0"/> <point value="83.5"/> <point value="78.3"/> <point value="68.0"/> <point value="55.0"/> <point value="45.5"/> <point value="38.0"/> <point value="31.0"/> <point value="27.2"/> <point value="27.0"/> <point value="28.0"/> <point value="31.8"/> <point value="42.0"/> <point value="60.0"/> <point value="67.9"/> <point value="71.7"/> <point value="74.0"/> <point value="75.5"/> <point value="77.0"/> <point value="78.0"/> <point value="79.2"/> <point value="79.5"/> <point value="79.9"/> <point value="80.1"/> <point value="79.8"/> <point value="78.9"/> <point value="78.3"/> <point value="64.0"/> <point value="52.9"/> <point value="44.9"/> <point value="38.0"/> <point value="32.0"/> <point value="27.6"/> </diagram></weather>

- 130/141 -

Page 131: SVG

6.2.3. Arkusz transformacji XSLT

Kod źródłowy arkusza XSLT przeznaczonego do transformacji danych

pogodowych z formatu XML do grafiki SVG:

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg"> <xsl:output method="xml" indent="yes" doctype-public="-//W3C//DTD SVG 1.1//EN" doctype-system="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"/> <!-- XSLT STYLESHEET VARIABLES --> <xsl:variable name="viewBoxWidth" select="500"/> <xsl:variable name="viewBoxHeight" select="200"/> <xsl:variable name="picturePositionX" select="20"/> <xsl:variable name="picturePositionY" select="50"/> <xsl:variable name="pictureWidth" select="460"/> <xsl:variable name="pictureHeight" select="140"/> <!-- DOCUMENT MATCHING "WEATHER" (ROOT) ELEMENT --> <xsl:template match="/"> <svg:svg width="100%" height="100%" viewBox="0 0 {$viewBoxWidth} {$viewBoxHeight}" version="1.1"> <svg:rect x="0" y="0" width="{$viewBoxWidth}" height="{$viewBoxHeight}" style="fill:gainsboro" stroke="grey" stroke-width="1"/> <xsl:variable name="diagram_background_color" select="/weather/@diagram_bckg_color"/> <svg:rect x="{$picturePositionX}" y="{$picturePositionY}" height="{$pictureHeight}" width="{$pictureWidth}" style="fill:{$diagram_background_color}" stroke="black" stroke-width="1"/> <xsl:apply-templates/> </svg:svg> </xsl:template> <!-- DOCUMENT MATCHING "DESCRIPTION" ELEMENT --> <xsl:template match="description"> <xsl:variable name="outlineColor" select="title/@outline_color"/> <svg:text x="50%" y="8%" stroke-width="0.2" stroke="{$outlineColor}" fill="black" font-size="15" font-family="Verdana" text-anchor="middle"> <xsl:value-of select="title"/> </svg:text> <!-- TEST IF THERE'S AN ADDITIONAL HEADER TEXT --> <xsl:if test="count( /weather/description/additional_title ) &gt; 0"> <xsl:variable name="additionalOutlineColor" select="additional_title/@outline_color"/>

- 131/141 -

Page 132: SVG

<svg:text x="70%" y="15.5%" stroke-width="0.3" stroke="{$additionalOutlineColor}" fill="black" font-size="12" font-family="Verdana" text-anchor="middle"> <xsl:value-of select="additional_title"/> </svg:text> </xsl:if> </xsl:template> <!-- DOCUMENT MATCHING "DATES" ELEMENT --> <xsl:template match="dates"> <xsl:variable name="valuesCount" select="count(date) - 1"/> <xsl:variable name="diagramValueStep" select="$pictureWidth div $valuesCount"/> <xsl:for-each select="date"> <xsl:variable name="iCount" select="position() - 1"/> <xsl:variable name="valueLinePositionX" select="$picturePositionX+ $iCount * $diagramValueStep"/> <!-- DISPALY THE VALUE OF THIS POINT AT THE X AXIS --> <xsl:if test="$iCount != 0 and $iCount != last() - 1"> <svg:text x="{$valueLinePositionX}" y="{$picturePositionY - 3}" stroke-width="0.2" stroke="darkgray" fill="black" font-size="10" font-family="Verdana" text-anchor="middle"> <xsl:value-of select="@hour"/> </svg:text> </xsl:if> <!-- DISPLAY A VERTICAL LINE AT THIS VALUE'S POSITION --> <xsl:if test="$iCount &gt; 0 and $iCount &lt; $valuesCount"> <xsl:variable name="hour" select="@hour"/> <xsl:choose> <xsl:when test="$hour = 0"> <svg:line x1="{$valueLinePositionX}" y1="{$picturePositionY}" x2="{$valueLinePositionX}" y2="{$picturePositionY + $pictureHeight}"stroke="black" stroke-width="1" stroke-dasharray="4,3"/> </xsl:when> <xsl:otherwise> <svg:line x1="{$valueLinePositionX}" y1="{$picturePositionY}" x2="{$valueLinePositionX}" y2="{$picturePositionY + $pictureHeight}"stroke="black" stroke-width="1" stroke-dasharray="1,2"/> </xsl:otherwise> </xsl:choose> </xsl:if> <!-- IF THERE'S AN ADDITIONAL HEADER TEXT, THEN THERE'S NO NEED TO DISPLAY DAY DATES ON A DIAGRAM --> <xsl:if test="count( /weather/description/additional_title ) = 0"> <!-- DISPLAY DAY DATES AT THE TOP OF THE DIAGRAM --> <xsl:variable name="jCount1" select="position() - 1"/> <xsl:variable name="jCount2" select="position()"/> <xsl:variable name="leftDate" select="/weather/dates/date[$jCount1]/@day"/> <xsl:variable name="rightDate" select="/weather/dates/date[$jCount2]/@day"/> <xsl:if test="$leftDate != $rightDate or position() = 1 or position() = last()"> <xsl:variable name="endCount" select="position()"/>

- 132/141 -

Page 133: SVG

<xsl:if test="$jCount1 != 0"> <!-- FIND INDEX OF THE VERY FIRST ELEMENT CONTAINING "/weather/dates/date[???]/@day" ATTRIBUTE'S VALUE EQUAL TO "$leftDate" --> <xsl:for-each select="/weather/dates/date"> <xsl:variable name="previousElementIndex" select="position() - 1"/> <xsl:variable name="previousElementValue" select="/weather/dates/date[$previousElementIndex]/@day"/> <xsl:if test="@day = $leftDate and ( $previousElementValue !=$leftDate or $previousElementIndex = 0)"> <!-- THIS SECTION SHOULD DISPLAY INTERVALS LIKE: 1-8, 8-16, 16-20, ETC. --> <!-- <xsl:value-of select="position()"/>-<xsl:value-of select="$endCount"/> --> <!-- CALCULATE LOCATION OF THE DATE ON THE PICTURE --> <xsl:variable name="dayDatePositionX" select="$picturePositionX + $diagramValueStep * ( ( $endCount - position() ) div 2 + position() - 1 )"/> <!-- DISPLAY DAY DATE IN THE COUNTED POSITION --> <svg:text x="{$dayDatePositionX}" y="{$picturePositionY - 18}" stroke-width="0.1" stroke="yellowgreen" fill="black" font-size="12" font-family="Verdana" text-anchor="middle"> - <xsl:value-of select="$leftDate"/> - </svg:text> </xsl:if> </xsl:for-each> </xsl:if> </xsl:if> </xsl:if> </xsl:for-each> </xsl:template> <!-- DOCUMENT MATCHING "VALUES" ELEMENT --> <xsl:template match="values"> <xsl:variable name="valuesCount" select="count(value) - 1"/> <xsl:variable name="diagramValueStep" select="$pictureHeight div $valuesCount"/> <xsl:variable name="leftColorShadow" select="@left_color_shadow"/> <xsl:variable name="rightColorShadow" select="@right_color_shadow"/> <xsl:for-each select="value"> <xsl:variable name="iCount" select="position() - 1"/> <xsl:variable name="valueLinePositionY" select="$pictureHeight + $picturePositionY - $iCount * $diagramValueStep"/> <!-- DISPALY THE VALUE OF THIS POINT AT THE Y AXIS ON THE LEFT SIDE OF A DIAGRAM--> <svg:text x="{$picturePositionX - 2}" y="{$valueLinePositionY}" stroke-width="0.2" stroke="{$leftColorShadow}" fill="black" font-size="10" font-family="Verdana" text-anchor="end"> <xsl:value-of select="@left"/> </svg:text> <!-- DISPALY THE VALUE OF THIS POINT AT THE Y AXIS ON THE RIGHT SIDE OF A DIAGRAM--> <svg:text x="{$picturePositionX + $pictureWidth + 2}"

- 133/141 -

Page 134: SVG

y="{$valueLinePositionY}" stroke-width="0.2" stroke="{$rightColorShadow}" fill="black" font-size="10" font-family="Verdana" text-anchor="start"> <xsl:value-of select="@right"/> </svg:text> <!-- DISPLAY A HORIZONTAL LINE AT THIS VALUE'S POSITION --> <xsl:if test="$iCount &gt; 0 and $iCount &lt; $valuesCount"> <svg:line x1="{$picturePositionX}" y1="{$valueLinePositionY}" x2="{$picturePositionX + $pictureWidth}" y2="{$valueLinePositionY}" stroke="black" stroke-width="1" stroke-dasharray="1,2"/> </xsl:if> </xsl:for-each> </xsl:template> <!-- DOCUMENT MATCHING "DIAGRAM" ELEMENT --> <xsl:template match="diagram"> <xsl:variable name="valuesDataSide" select="@values"/> <xsl:variable name="valuesRange" select="/weather/values/value[ count(/weather/values/value) ]/@left - /weather/values/value[1]/@left"/> <xsl:variable name="valueStep" select="$pictureHeight div $valuesRange"/> <xsl:variable name="argumentStep" select="$pictureWidth div ( count(point) - 1 )"/> <xsl:variable name="diagramType" select="@type"/> <xsl:variable name="diagramStyle" select="@style"/> <xsl:variable name="diagramColor" select="@color"/> <xsl:for-each select="point"> <xsl:variable name="x1" select="$picturePositionX + ( position() - 1 ) * $argumentStep"/> <xsl:if test="position() != last()"> <xsl:variable name="x2" select="$picturePositionX + ( position()) * $argumentStep"/> <xsl:variable name="y1" select="$picturePositionY + $pictureHeight - @value * $valueStep"/> <xsl:variable name="nextValue" select="position() + 1"/> <xsl:variable name="y2" select="$picturePositionY + $pictureHeight - ( ../point[ $nextValue ]/@value ) * $valueStep"/> <!-- *********************************** --> <!-- DRAWING DIAGRAM OF TEMPERATURE TYPE --> <!-- *********************************** --> <xsl:if test="$diagramType = 'temperature'"> <!-- DIAGRAM CONNECTING PERCEPTED AND AVERAGE TEMPERATURE POINTS --> <svg:line x1="{$x1}" y1="{$y1}" x2="{$x2}" y2="{$y2}" stroke="{$diagramColor}" stroke-width="2" stroke-dasharray="1,0" stroke-linecap="round"/> <xsl:if test="$diagramStyle = 'average'"> <!-- DIAGRAM CONNECTING TEMPERATURE'S MIN AND MAX VALUES --> <xsl:if test="position() != 1"> <xsl:variable name="y3" select="$picturePositionY + $pictureHeight - @min_value * $valueStep"/> <xsl:variable name="y4" select="$picturePositionY + $pictureHeight - @max_value * $valueStep"/> <svg:line x1="{$x1}" y1="{$y3}" x2="{$x1}" y2="{$y4}"

- 134/141 -

Page 135: SVG

stroke="{$diagramColor}" stroke-width="0.5" stroke-dasharray="1,0" stroke-linecap="square"/> </xsl:if> </xsl:if> </xsl:if> <!-- ******************************** --> <!-- DRAWING DIAGRAM OF HUMIDITY TYPE --> <!-- ******************************** --> <xsl:variable name="thisPointValue" select="@value"/> <xsl:variable name="nextValuePosition" select="position() + 1"/> <xsl:variable name="nextPointValue" select="../point[$nextValuePosition]/@value"/> <xsl:if test="$diagramType = 'humidity' or $diagramType = 'precipitation'"> <!-- 1. CALCULATE NEW Y VALUE ON THE PICTURE --> <!-- a) GET PIXEL RANGE BETWEEN TWO HORIZONTAL LINES --> <xsl:variable name="pixelRange" select="$pictureHeight div ( count(/weather/values/value) - 1 )"/> <!-- b) GO THROUGH ALL THE POSSIBLE VALUE RANGES AND SELECT THEONE TO WHICH THE CURRENT VALUE APPLIES --> <xsl:variable name="valuesSide" select="../@values"/> <xsl:for-each select="/weather/values/value"> <xsl:variable name="leftBottomRange" select="@left"/> <xsl:variable name="rightBottomRange" select="@right"/> <xsl:variable name="nextPosition" select="position() + 1"/> <xsl:variable name="leftTopRange" select="../value[$nextPosition]/@left"/> <xsl:variable name="rightTopRange" select="../value[$nextPosition]/@right"/> <!-- c) CALCULATE DIAGRAM Y VALUE FOR BOTH CASES: LEFT AND RIGHT Y AXIS --> <xsl:if test="$valuesSide = 'right' and $rightBottomRange &lt;= $thisPointValue and $rightTopRange &gt;= $thisPointValue"> <!-- d) CALCULATING VALUES FROM THE RIGHT'S AXIS RANGE --> <xsl:variable name="singleValueStep" select="$pixelRange div ( $rightTopRange - $rightBottomRange )"/> <xsl:variable name="additionalValueSubtrahend" select="$thisPointValue - $rightBottomRange"/> <xsl:variable name="diagramThisPositionYRight" select="$pictureHeight + $picturePositionY - ( ( position() - 1 ) * $pixelRange ) - $additionalValueSubtrahend * $singleValueStep"/> <!-- NOW WHEN WE'VE GOT THE DIAGRAM'S Y POSITION OF OUR VALUE, WE HAVE TO CALCULATE THE POSITION OF THE NEXT POINT TO CONNECT IT TO --> <xsl:for-each select="/weather/values/value"> <xsl:variable name="nextBottomRange" select="@right"/> <xsl:variable name="nextNextPosition" select="position() + 1"/> <xsl:variable name="nextTopRange" select="../value[$nextNextPosition]/@right"/> <xsl:if test="$nextBottomRange &lt;= $nextPointValue and $nextTopRange &gt;= $nextPointValue"> <xsl:variable name="nextSingleValueStep" select="$pixelRange div ( $nextTopRange - $nextBottomRange )"/> <xsl:variable name="nextAdditionalValueSubtrahend" select="$nextPointValue - $nextBottomRange"/>

- 135/141 -

Page 136: SVG

<xsl:variable name="diagramNextPositionYRight" select="$pictureHeight + $picturePositionY - ( ( position() - 1 ) * $pixelRange ) - $nextAdditionalValueSubtrahend * $nextSingleValueStep"/> <!-- DIAGRAM STYLE: RAINFALL --> <xsl:if test="$diagramStyle = 'rainfall'"> <svg:rect x="{$x1 + 1}" y="{$diagramThisPositionYRight}" width="{$x2 - $x1}" height="{$pictureHeight + $picturePositionY - $diagramThisPositionYRight - 1}" fill="{$diagramColor}" stroke="{$diagramColor}" stroke-width="1"/> </xsl:if> <!-- DIAGRAM STYLE: LINE --> <xsl:if test="$diagramStyle = 'line'"> <svg:line x1="{$x1}" y1="{$diagramThisPositionYRight}" x2="{$x2}" y2="{$diagramNextPositionYRight}" stroke="{$diagramColor}" stroke-width="2" stroke-dasharray="1,0" stroke-linecap="round"/> </xsl:if> </xsl:if> </xsl:for-each> </xsl:if> <xsl:if test="$valuesSide = 'left' and $leftBottomRange &lt;= $thisPointValue and $leftTopRange &gt;= $thisPointValue"> <!-- e) CALCULATING VALUES FROM THE LEFT'S AXIS RANGE --> <xsl:variable name="singleValueStep" select="$pixelRange div ( $leftTopRange - $leftBottomRange )"/> <xsl:variable name="additionalValueSubtrahend" select="$thisPointValue - $leftBottomRange"/> <xsl:variable name="diagramThisPositionYLeft" select="$pictureHeight + $picturePositionY - ( ( position() - 1 ) * $pixelRange ) - $additionalValueSubtrahend * $singleValueStep"/> <!-- NOW WHEN WE'VE GOT THE DIAGRAM'S Y POSITION OF OUR VALUE, WE HAVE TO CALCULATE THE POSITION OF THE NEXT POINT TO CONNECT IT TO --> <xsl:for-each select="/weather/values/value"> <xsl:variable name="nextBottomRange" select="@left"/> <xsl:variable name="nextNextPosition" select="position() + 1"/> <xsl:variable name="nextTopRange" select="../value[$nextNextPosition]/@left"/> <xsl:if test="$nextBottomRange &lt;= $nextPointValue and $nextTopRange &gt;= $nextPointValue"> <xsl:variable name="nextSingleValueStep" select="$pixelRange div ( $nextTopRange - $nextBottomRange )"/> <xsl:variable name="nextAdditionalValueSubtrahend" select="$nextPointValue - $nextBottomRange"/> <xsl:variable name="diagramNextPositionYLeft" select="$pictureHeight + $picturePositionY - ( ( position() - 1 ) * $pixelRange ) - $nextAdditionalValueSubtrahend * $nextSingleValueStep"/> <!-- DIAGRAM STYLE: RAINFALL --> <xsl:if test="$diagramStyle = 'rainfall'"> <svg:rect x="{$x1 + 1}" y="{$diagramThisPositionYLeft}" width="{$x2 - $x1}" height="{$pictureHeight + $picturePositionY - $diagramThisPositionYLeft - 1}" fill="{$diagramColor}" stroke="{$diagramColor}" stroke-width="1"/>

- 136/141 -

Page 137: SVG

</xsl:if> <!-- DIAGRAM STYLE: LINE --> <xsl:if test="$diagramStyle = 'line'"> <svg:line x1="{$x1}" y1="{$diagramThisPositionYLeft}" x2="{$x2}" y2="{$diagramNextPositionYLeft}" stroke="{$diagramColor}"stroke-width="2" stroke-dasharray="1,0" stroke-linecap="round"/> </xsl:if> <!-- DIAGRAM STYLE: OCCASIONAL --> <xsl:if test="$diagramStyle = 'occasional' and $thisPointValue != 0"> <svg:line x1="{$x1 + ($x2 - $x1) div 2}" y1="{$diagramThisPositionYLeft}" x2="{$x1 + ($x2 - $x1) div 2}" y2="{$picturePositionY + $pictureHeight - 0.5}" stroke="{$diagramColor}" stroke-width="1" stroke-dasharray="1,0" stroke-linecap="butt"/> </xsl:if> </xsl:if> </xsl:for-each> </xsl:if> </xsl:for-each> </xsl:if> </xsl:if> </xsl:for-each> </xsl:template></xsl:stylesheet>

- 137/141 -

Page 138: SVG

7. Bibliografia

[1] World Wide Web Consortium (W3C) MembersStrona Internetowa: http://www.w3.org/Consortium/Member/List/

[2] Tim Berners-Lee – BiografiaStrona Internetowa: http://www.w3.org/People/Berners-Lee/

[3] About the World Wide Web Consortium (W3C)Strona Internetowa: http://www.w3.org/Consortium/

[4] Scalable Vector Graphics (SVG): XML Graphics for the WebStrona Internetowa: http://www.w3.org/Graphics/SVG/

[5] Scalable Vector Graphics (SVG) 1.0 Specification (W3C Recommendation)Strona Internetowa: http://www.w3.org/TR/SVG10/

[6] About SVG: 2D Graphics in XMLStrona Internetowa: http://www.w3.org/Graphics/SVG/About.html

[7] Scalable Vector Graphics (SVG) Full 1.2 Specification: W3C Working DraftStrona Internetowa: http://www.w3.org/TR/SVG12/

[8] Scalable Vector Graphics (SVG): Group MembersStrona Internetowa: http://www.w3.org/Graphics/SVG/Membership

- 138/141 -

Page 139: SVG

[9] W3C Scalable Vector Graphics (SVG) – HistoryStrona Internetowa: http://www.w3.org/Graphics/SVG/History

[10] Scalable Vector Graphics Tiny 1.2 Specification: W3C CandidateStrona Internetowa: http://www.w3.org/TR/SVGMobile12/

[11] Prognoza Pogody ICMStrona Internetowa: http://meteo.icm.edu.pl/

[12] Scalable Vector Graphics (SVG) 1.1 Specification: ConceptsStrona Internetowa: http://www.w3.org/TR/SVG11/concepts.html

[13] Mobile SVG Profiles: SVG Tiny and SVG Basic: W3C RecommendationStrona Internetowa: http://www.w3.org/TR/SVGMobile/

[14] SVG.org: Shipping and Announced SVG PhonesStrona Internetowa: http://svg.org/special/svg_phones/

[15] Scalable Vector Graphics (SVG) 1.1 Specification: W3C RecommendationStrona Internetowa: http://www.w3.org/TR/SVG11/

[16] SVG 1.1/1.2/2.0 Requirements: W3C Working DraftStrona Internetowa: http://www.w3.org/TR/SVG2Reqs/

8. Słownik trudniejszych pojęć

cieniowanie Gourauda (ang. Gouraud shading) – jedna z metod symulowania

zmiany jasności obiektów w grafice komputerowej poprzez odpowiednie

cieniowanie kolorów na ich powierzchni, opracowana przez francuskiego

matematyka Henri Gourauda

draft (ang. szkic, projekt) – propozycja nowej wersji standardu

enkapsulacja (ang. encapsulation) – w programowaniu obiektowym ukrywanie

danych składowych klasy, tak aby były one niedostępne dla użytkownika

funkcja turbulencji Perlina (ang. Perlin Noise) – pseudolosowa funkcja szeroko

stosowana w grafice komputerowej, używana do zwiększenia realizmu różnych

obiektów (np. chmur), opracowana przez Kena Perlina, profesora New York

University

- 139/141 -

Page 140: SVG

hiperłącze (ang. hyperlink) – odnośnik do innego dokumentu lub do innego

miejsca w bieżącym dokumencie elektronicznym

kanał przezroczystości (ang. alpha channel) – dodatkowa informacja jaką może

nieść ze sobą każdy piksel, używana do generowania przezroczystości obiektów

przez ich wkomponowanie w tło rysunku

kierunkowe źródło światła (ang. distant light) – jedna ze składowych

modelujących oświetlenie w grafice komputerowej, w której zakłada się

równoległość promieni świetlnych, używana do modelowania odległych obiektów

(np. światła słonecznego)

model oświetlenia Phonga – jeden z modeli służących do symulowania zmiany

odbicia światła od różnych obiektów w grafice komputerowej, opracowany przez

Phong Bui-Tuonga

morfing (ang. morphing) – płynne przekształcanie jednego obrazu w inny

progowanie (ang. thresholding) – efekt graficzny polegający podzieleniu obrazu

na wiele regionów, z których część składa się z pikseli mających jasność większą

niż określona wartość progowa, a część z pikseli o jasności mniejszej, które

nazywane są pikselami tła (ang. background pixels)

przestrzenie nazw XML (ang. XML Namespaces) – mechanizm opracowany

przez W3C umożliwiający stosowanie w jednym dokumencie znaczników z różnych

języków XML

punktowe źródło światła (ang. point light) – jedna ze składowych modelujących

oświetlenie w grafice komputerowej, w której zakłada się pochodzenie promieni

świetlnych z pojedynczego punktu, używana do modelowania bliskich obiektów

(np. światła żarówki)

renderowanie (ang. rendering) – w grafice komputerowej oznacza proces

generowania gotowego obrazu w oparciu o dostarczone dane

rozmycie gaussowskie (ang. Gaussian blur) – szeroko stosowany efekt

- 140/141 -

Page 141: SVG

graficzny, służący do zmniejszenia liczby szczegółów na rysunku poprzez jego

rozmycie

- 141/141 -