Vyuºití JavaScriptových knihoven - ExtBrain

Transkript

Vyuºití JavaScriptových knihoven - ExtBrain
České vysoké učení technické v Praze
Fakulta elektrotechnická
Katedra počítačů
Bakalářská práce
Využití JavaScriptových knihoven
Lukáš Kukačka
Vedoucí práce: Ing. Tomáš Novotný
Studijní program: Softwarové technologie a management, Bakalářský
Obor: Softwarové inženýrství
26. května 2010
iv
v
Poděkování
Zde můžete napsat své poděkování, pokud chcete a máte komu děkovat.
vi
vii
Prohlášení
Prohlašuji, že jsem práci vypracoval samostatně a použil jsem pouze podklady uvedené
v přiloženém seznamu.
Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000
Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některých
zákonů (autorský zákon).
V Dobříši dne 15. 5. 2008
.............................................................
viii
Abstract
Translation of Czech abstract into English.
Abstrakt
Abstrakt práce by měl velmi stručně vystihovat její podstatu. Tedy čím se práce zabývá a
co je jejím výsledkem/přínosem.
Očekávají se cca 1 – 2 odstavce, maximálně půl stránky.
ix
x
Obsah
1 Úvod
2 Zhodnocení knihoven
2.1 jQuery . . . . . . .
2.2 Dojo . . . . . . . .
2.3 Ext . . . . . . . . .
2.4 MochiKit . . . . .
2.5 MooTools . . . . .
2.6 YUI . . . . . . . .
1
pro JavaScript
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3 Vektorová grafika v JavaScriptu
3.1 Vektorové formáty pro web . . . . . . . . . . .
3.1.1 SVG . . . . . . . . . . . . . . . . . . . .
3.1.2 VML . . . . . . . . . . . . . . . . . . . .
3.1.3 Silverlight . . . . . . . . . . . . . . . . .
3.2 Implementace v různých prohlížečích . . . . . .
3.3 Knihovny pro cross-browser vektorovou grafiku
3.3.1 dojox.gfx . . . . . . . . . . . . . . . . .
3.3.2 Raphaël . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
. 3
. 7
. 9
. 11
. 12
. 13
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
15
15
15
17
17
18
18
18
20
4 Popis problému a specifikace cíle ukázkové aplikace
4.1 Popis řešeného problému . . . . . . . . . . . . . . . .
4.2 Existující implementace . . . . . . . . . . . . . . . .
4.2.1 Raphaël Graffle . . . . . . . . . . . . . . . . .
4.2.2 Litha–Paint . . . . . . . . . . . . . . . . . . .
4.2.3 RichDraw . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
21
21
22
22
22
22
5 Analýza a návrh řešení ukázkové aplikace
5.1 Analýza implementovatelnosti a volba knihoven
5.2 Funkční prototypy . . . . . . . . . . . . . . . .
5.3 Návrh . . . . . . . . . . . . . . . . . . . . . . .
5.3.1 Struktura kódu aplikace . . . . . . . . .
5.3.2 Node . . . . . . . . . . . . . . . . . . . .
5.3.3 Skupina . . . . . . . . . . . . . . . . . .
5.3.4 Spojení mezi nody . . . . . . . . . . . .
5.3.5 Pohyb nodů a překreslování cest . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
23
23
24
25
25
27
28
29
31
xi
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
xii
6 Realizace ukázkové aplikace
6.1 Inicializace aplikace . . . . . . . . . . . . . .
6.2 Rozhraní zpráv . . . . . . . . . . . . . . . .
6.2.1 Zpráva uživateli . . . . . . . . . . . .
6.2.2 Debugovací informace . . . . . . . .
6.3 Inicializace uživatelského rozhraní . . . . . .
6.4 Vlastní selektory . . . . . . . . . . . . . . .
6.5 Ovládací prvky . . . . . . . . . . . . . . . .
6.5.1 Funkce pro práci s ovládacími prvky
6.6 Vybírání elementů . . . . . . . . . . . . . .
6.6.1 Metoda topGroups . . . . . . . . . .
6.6.2 Metoda mmSelectable . . . . . . . .
6.7 Vkládání nodů . . . . . . . . . . . . . . . .
6.8 Pohyblivost nodů a skupin . . . . . . . . . .
6.8.1 Metoda mmDraggable . . . . . . . .
6.9 Odstranění nodů . . . . . . . . . . . . . . .
6.10 Vytvoření skupiny . . . . . . . . . . . . . .
6.11 Zrušení skupiny . . . . . . . . . . . . . . . .
6.12 Cesty . . . . . . . . . . . . . . . . . . . . .
6.12.1 Vytvoření cesty . . . . . . . . . . . .
6.12.2 Spojení více nodů . . . . . . . . . . .
6.12.3 Hledání vnitřních a vnějších cest . .
6.12.4 Přepočet cest . . . . . . . . . . . . .
6.13 Problémy funkčnosti . . . . . . . . . . . . .
OBSAH
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
33
33
35
35
36
36
37
37
37
38
38
38
39
40
40
42
42
43
44
44
44
45
46
47
7 Závěr
49
Literatura
51
A Editace základního vzhledu
53
B Specifické vlastnosti kódu
55
B.1 jQuery length vs. size() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
C Seznam použitých zkratek
57
D Obsah přiloženého CD
59
Seznam obrázků
2.1
2.2
2.3
2.4
Dojo namespacy v DOM (screenshot z nástroje FireBug) . . . . . . . . . . . . 7
Ukázkový příklad aplikace v ExtJS. V prohlížeči napodobuje plochu a chování
oken jako v desktopovém operačním systému . . . . . . . . . . . . . . . . . . 9
Strom vytvořený ukázkovým příkladem. . . . . . . . . . . . . . . . . . . . . . 10
Ukázkový příklad rozhraní aplikace v YUI . . . . . . . . . . . . . . . . . . . . 13
3.1
3.2
Obraz vzniklý z ukázkového SVG dokumentu . . . . . . . . . . . . . . . . . . 16
Obraz vzniklý z ukázkového VML dokumentu . . . . . . . . . . . . . . . . . . 17
5.1
Ilustrace hledání vnitřních spojení ve skupině . . . . . . . . . . . . . . . . . . 29
6.1
6.2
6.3
Screenshot aplikace s diagramem . . . . . . . . . . . . . . . . . . . . . . . . . 34
Screenshot zpráv uživateli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Ukázka znaménka příslušnosti skupině . . . . . . . . . . . . . . . . . . . . . . 43
D.1 Seznam přiloženého CD — příklad . . . . . . . . . . . . . . . . . . . . . . . . 59
xiii
xiv
SEZNAM OBRÁZKŮ
Seznam tabulek
6.1
6.2
Přehled vlastních jQuery selektorů . . . . . . . . . . . . . . . . . . . . . . . . 37
Přehled funkcí pro aktualizaci cesty . . . . . . . . . . . . . . . . . . . . . . . . 47
A.1 Přehled CSS stylů editoru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
xv
xvi
SEZNAM TABULEK
Kapitola 1
Úvod
Tohle je includovanej uvod +ěšččřřžžýýáí Úvod charakterizující kontext zadání, případně
motivace.
Výsledná struktura vaší práce a názvy a rozsahy jednotlivých kapitol se samozřejmě
budou lišit podle typu práce a podle konkrétní povahy zpracovávaného tématu. Níže uvedená
struktura práce odpovídá práci implementační, viz [?] respektive [?].
1
2
KAPITOLA 1. ÚVOD
Kapitola 2
Zhodnocení knihoven pro JavaScript
JavaScriptových knihoven je velké množství a liší se jak ve způsobu vývoje, tak ve svém
původním účelu. V této kapitole představím některé z nejrozšířenějších knihoven. Každá
knihovna je stručně představena a uvádím její základní či specifické prvky.
2.1
jQuery
jQuery je dnes zřejmě všeobecně nejznámější JavaScriptová knihovna. Původní autor John
Resig ji poprvé představil v polovině roku 2006 a v současné době se o její správu stará
jQuery Project. jQuery je využíváno například společnostmi Google, DELL a mozilla.org
nebo oblíbenými a rozšířenými CMS (content management systémy) Wordpress a Drupal.
Tato skutečnost jQuery poskytuje široké fanouškovské a vývojářské zázemí.
jQuery zjednodušuje procházení HTML dokumentu, zacházení s eventy (uživatelskými
akcemi), animacemi a práci s AJAXem. jQuery odděluje chování a od HTML dokumentu.
To znamená, že objekty v DOMu nemusí obsahovat akce "on-click"apod., ale pomocí jQuery
najdeme objekt a tomu přiřadíme akce.
Selektorový engine Sizzle
Jedním ze základních prvků jQuery je další počin autora jQuery a sice CSS selektorový
engine Sizzle. Ten byl plně integrován do jádra jQuery od verze 1.3, tedy od ledna 2009.
Sizzle je napsaný v čistém JavaScriptu (tudíž není závislý na žádné specifické knihovně) a
díky tomu umožňuje snadnou integraci do knihoven. Nabízí možnost vyhledávat elementy v
DOM ne pouze na základě atributů id, class apod., ale i složitějších požadavků jako určení
pořadí výskytu, porovnání atributů, procházení ve stromové struktuře DOM, druhu objektu
a dalších.
3
4
KAPITOLA 2. ZHODNOCENÍ KNIHOVEN PRO JAVASCRIPT
Základní prvky
Jednou z prvních vlastností, se kterou se vývojář setká hned po nainstalování jQuery, je
nahrazení window.onload... vlastní metodou $(document).ready(function().... jQuery
metoda .ready() (jednoduše vysvětlená zde [2]) obsluhuje událost domready. Podle jQuery
dokumentace [14] bude metoda spuštěna, když je DOM plně načten. To znamená, že je sestaven DOM, nicméně nemusí být nutně načteny všechny obrázky. Event má několik možných
způsobů zápisu, vždy je ale ekvivalentní se zápisem
$(document).ready(handler)
tedy "jakmile je plně připraven DOM dokumentu, zavolej handler". V praxi se jako handler
nejčastěji používá anonymní funkce
$(document).ready(function(){
kód, který má být vykonán
});
jQuery objekt je vytvořen jednoduchým způsobem. Kód vypadá následovně:
$("selektor").metoda("parametr");
Kde $ označuje jQuery objekt a selektor je výraz kompatibilní se selektorovým enginem
Sizzle. Ten určuje, s jakým elementem se bude pracovat. Je vytvořena kolekce objektů,
nad kterou jsou volány jQuery metody. Většina jQuery metoda vrací jQuery objekt, což
umožňuje zřetězení metod (výjimkou je např. metoda size() vracející integer počet elementů
v kolekci). Zřetězení je volání metod za sebou v rámci jednoho příkazu, jak je ukázáno na
následujícím příkladě:
$("#nejakyDiv")
.children("a")
.addClass("vybranyOdkaz");
Uvedený kód najde element s atributem id odpovídajícím řetězci nejakyDiv a vytvoří objekt.
Funkce .children("a") najde potomky, které jsou hypertextové odkazy a všem přidá HTML
třídu vybranyOdkaz
V jádře jQuery jsou zakomponovány funkce pro správu událostí (event handling). Pokud
je daná událost na elementu vyvolána, je spuštěna akce, která se k dané události váže.
Základem připojování událostí k elementům je metoda .bind(). Základní využití vypadá
takto:
$(’selektor’).bind(’akce’, function() {
// zde bude kód, který je vykonán
});
2.1. JQUERY
5
Na vybrané elementy bude připojena událost akce. Pokud zvolená událost nastane, bude
vykonána tzv. callback funkce. Mezi použitelné události patří všechny akce myši (od stisku
tlačítka, přes kliknutí až po pohyb) a klávesnice (stisknutá klávesa) a akce specifické pro
druh elementu, jako například focus pro textové pole nebo submit pro odeslání formuláře.
Pro zjednodušení je možné všechny události nastavit zkráceným voláním
$(’selektor’).click(function() {
// zde bude kód, který je vykonán
});
kde click je název události.
Za zmínku jistě stojí metoda jQuery.noConflict() umožňující kompatibilitu s některými jinými knihovnami. jQuery jako svůj klíčový znak užívá $, nicméně ten je používán
například knihovnou Prototype. Volání
var jq = jQuery.noConflict();
umožní používat vlastní značení jq namísto $.
Zdrojový kód
jQuery kód se skládá z několika hlavních částí:
• Definice objektu jQuery
• Definice zahrnutého selektorového enginu Sizzle (od verze 1.3)
• Pomocné metody
Definice jQuery objektu sama o sobě obsahuje několik základních metod jádra vytvořených
pomocí jQuery.prototype, převážně pro práci s poli a kolekcemi jQuery objektů. Na tyto
metody lze přistoupit i zkráceným zápisem jQuery.fn. Jednou z nejzajímavějších je metoda
jQuery.extend (přesněji jQuery.fn.extend). Ta umožňuje rozšiřování objektu jQuery o
téměř jakoukoli část. Umožňuje nejen vkládat nové metody:
jQuery.fn.extend({
novaMetoda1
novaMetoda2
});
: function() { ... },
: function() { ... }
ale například i rozšiřovat si sadu předdefinovaných selektorů o své vlastní například takto:
$.extend($.expr[’:’],{
block: function(a) {
return $(a).css(’display’) === ’block’;
}
});
6
KAPITOLA 2. ZHODNOCENÍ KNIHOVEN PRO JAVASCRIPT
Zápis objektu pomocí výrazu $(’:block’) poté vybere všechny elementy, jejichž CSS hodnota display je block. Podobně jde filtrovat podrobněji např. $(’div:block’) vybere
všechny elementy div, které mají CSS hodnotu display rovnu block. Vlastní selektor se
dá použít pro složitější hledání a může kombinovat více podmínek. Můžeme pomocí něho
vybrat například jen ty elementy, které mají šířku menší než 100px a zároveň mají nějakou
specifickou třídu class.
jQuery UI
Součástí projektu jQuery je knihovna jQuery UI [15] nabízející snadné použití vizuálních
efektů, widgetů pro uživatelské rozhraní a skinovací framework. jQuery UI využívá knihovnu
jQuery a je na ní přímo závislý. Stránka pro stažení nabízí možnost vybrat si komponenty,
které chceme mít v knihovně zahrnuty. Ve standardní distribuci jsou všechny komponenty
zahrnuty. Skinů je na výběr poměrně velké množství a pro možnost přizpůsobení vzhledu je
na stránkách projektu webová aplikace ThemeRoller umožňující sestavit si vlastní téma.
jQuery UI se skládá z těchto částí:
• JavaScriptový kód rozšiřující možnosti standardního jQuery objektu o efekty a widgety
• CSS styl upravující vzhled widgetů
• Grafika (obrázky na pozadí a ikonky)
jQuery UI si stejně jako jQuery zakládá na jednoduchosti použití. Díky integraci metod
efektů do jQuery objektu je lze snadnou použít a zřetězovat, jak je ukázáno výše v kapitole
Základní prvky. Widget je použit stejně.
Vizuální manipulace s daty
Jak jsem již uvedl, pro vizuální manipulaci s daty slouží převážně jQuery UI, konkrétně jeho
widgety a část pro interakci. Ta řeší například řazení HTML seznamu metodou Sortable.
Základní použití interakční části kódu jakož i widgetů je velice snadné a vypadá následovně:
$("#sortable").sortable({
placeholder: ’ui-state-highlight’
});
Vytvořím jQuery objekt pomocí selektoru a zavolám na něj metodu (v ukázkovém příkladě Sortable) a té případně vložím objekt jako parametry. Všechny fungují s výchozím
nastavením i bez parametrů.
2.2. DOJO
2.2
7
Dojo
Dojo Toolkit je open source JavaScriptová knihovna. Toolkit v názvu přesněji říká "sada
nástrojů". Je navržena pro zjednodušení rychlého vývoje cross-browser aplikací založených
na JavaScriptu a AJAXu. Dle [8] její vývoj započali v roce 2004 Alex Russell, Dylan Schiemann, David Schontzler a další pod duální licencí BSD a AFL. O správu knihovny se stará
nezisková organizace Dojo Foundation. Stejně jako ostatní nejčastěji používané knihovny, i
Dojo používají některé světově známé firmy jako AOL či Cisco.
Dojo podporuje CSS3 selektory a funguje ve všech nejpoužívanějších prohlížečích (IE6+,
Firefox, Safari, Opera, Chrome)
Pěkný seriál o Dojo v češtině je na webu zdroják.cz [3].
Základní prvky
Základní funkce Dojo jsou obsaženy v jádře nazvaném Base Dojo v souboru dojo.js (dokumentace [7]. Další funkcionalita je nahrávána z modulů určených namespacem (jmenným
prostorem) [3]. Dojo striktně dodržuje zápis pomocí namespaců, aby nezaplňoval hlavní
namespace velkým množstvím funkcí. Pro ukázku:
Obrázek 2.1: Dojo namespacy v DOM (screenshot z nástroje FireBug)
Vyznačené objekty vytvořilo Dojo jako svůj namespace. Metody v namespacu Dojo nezasahují mezi ostatní funkce a nemohou proto být v konfliktu například s jinými knihovnami.
Zápis namespaců je oddělen . (tečkou) takto:
dojo.fx
Pokud je potřeba další funkcionalita mimo jádro (což je velice často), je nahrán namespace
obsahující danou funcionalitu následovně:
dojo.require("dojo.fx.easing");
Metoda dojo.require() nahrává další pluginy, v tomto případě easing (styl průběhu animace
- lineární, "elastický"apod).
8
KAPITOLA 2. ZHODNOCENÍ KNIHOVEN PRO JAVASCRIPT
Dojo definuje vlastní metodu, která je spuštěna, když je připraven DOM. Je to metoda
dojo.addOnLoad(). Používá se podobně jako u jQuery v kombinaci s anonymní funkcí takto:
dojo.addOnLoad(function() {
kód pro vykonání
});
Dojo má vlastní selektorový engine podporující CSS3. Hledání elementu pomocí CSS
zápisu provádí metoda
dojo.query("selektor")
Základní zacházení s událostmi provádí metoda dojo.connect(). Jak je zvykem, na
jakýkoli element umí připojit události DOM (click, mousedown apod.). Dojo connect ovšem
umí propojit akci na jakýkoli objekt. Umožňuje tedy například připojit funkci na další funkci.
var handle = dojo.connect(dojo, "require", function(arg) {
console.log("Bylo voláno require() s argumenty: ", arg)
dojo.disconnect(handle);
});
dojo.require("dojo.io.iframe");
Ukázkový kód z [3] připojí akci na metodu dojo.require(). Jakmile je tedy zavolána, je
zavolána i připojená funkce.
V jádře Dojo jsou i metody pro AJAX. Velké množství další funkcionality je možné načíst
pomocí pluginů.
K projektu Dojo patří Dijit a DojoX.
• Dijit - skinovatelná knihovna uživatelského rozhraní pro Dojo, obsahuje velké množství
widgetů a ovládacích prvků, které běžně HTML nepodporuje (slider, paletu barev a
další)
• DojoX (Dojo eXtensions) - rozšíření a podprojekty (např. dojox.Drawing pro vektorovou grafiku)
2.3. EXT
2.3
9
Ext
Ext je JavaScriptová knihovna vhodná především pro vytváření interaktivních webových
aplikací. Ext se skládá hlavně z prvků uživatelského rozhraní (různé panely, editory, pole pro
tabulkové a stromové strukury atd).) a proto si zakládá na vyladěném a jednotném vzhledu
svých komponent. Nejlépe jsou možnosti vidět na ukázkových příkladech [11]
Obrázek 2.2: Ukázkový příklad aplikace v ExtJS. V prohlížeči napodobuje plochu a chování
oken jako v desktopovém operačním systému
V době psaní práce je nejnovější verzí Ext 3.2. Na knihovně Ext je zajímavé licencování.
Zatímco ostatní knihovny jsou většinou open source a zdarma a placená je případně až
podpora, Ext má jiný přístup. Je zdarma pro osobní, výukové a nekomerční využití, pro
komerční využití je potřeba licence v ceně řádově stovek amerických dolarů.
Dle [10] v roce 2006 začal Jack Slocum vyvíjet množinu rozšíření pro knihovnu YUI
2.6. Ta byla rychle zorganizována do nezávislé knihovny pod názvem "yui-ext". Knihovna
získávala rychle popularitu a následně byla přejmenována na Ext. Oficiální verze 1.0 byla
uvedena 1.4.2007.
10
KAPITOLA 2. ZHODNOCENÍ KNIHOVEN PRO JAVASCRIPT
Základní prvky
Objekty Ext jsou vytvářeny v nějakém HTML elementu. Vytváření objektu demonstruji na
ukázkovém příkladu, který jsem vytvořil pro řazení stromové struktury.
Ext.onReady(function(){
var json = [
{"text" : "pes", "id" : 100, "leaf" : false, "cls" : "folder", "children" :[
{"text" : "maly;", "id" : "100000", "leaf" : true, "cls" : "file"}, ...
]}];
var Tree = Ext.tree;
var tree = new Tree.TreePanel({
useArrows: true,
autoScroll: true,
animate: true,
enableDD: true,
containerScroll: true,
root: {
text: ’strom’,
draggable: false,
id: ’src’,
children: json
}
});
tree.render(’tree-div’);
tree.getRootNode().expand();
});
Do proměnné json jsou vložena data, která se zobrazí ve stromové struktuře. V ukázce kódu
jsou data nekompletní. Do proměnné Tree se vytvoří nový objekt Ext.tree, tedy stromová
struktura. V proměnné tree je vytvořen ze stromové struktury panel s určitými vlastnostmi. tree.render(’tree-div’) vykreslí stromovou strukturu do elementu s id tree-div.
Poslední řádek rozbalí kořen stromu. Výsledek vypadá takto:
Obrázek 2.3: Strom vytvořený ukázkovým příkladem.
2.4. MOCHIKIT
2.4
11
MochiKit
MochiKit je malá JavaScriptová knihovna, kterou vyvíjí a udržuje Bob Ippolito. Kód je inspirovaný jazykem Python. Motem MochiKit je "makes JavaScript suck a bit less". MochiKit
je rozdělen do několika souborů, každý z nich je balíčkem funkcionality. Jednotlivá funkcionalita je nahrávána načtením daného souboru.
Výhodou MochiKitu je přehledná dokumentace [18], kde je pro každou funkcionalitu
ukázkový kód, a její jednoduché využítí. Nevýhodou je, že na internetu existuje velice málo
tutoriálů.
Základní prvky
V hlavičce HTML souboru je nutno načíst soubory s potřebnou funkcionalitou. Hledání
elementů podle CSS selektoru je podporováno v balíčku MochiKit.Selector. Metody jsou
vždy volány s celým jmenným prostorem podobně jako u Dojo.
12
2.5
KAPITOLA 2. ZHODNOCENÍ KNIHOVEN PRO JAVASCRIPT
MooTools
MooTools začal vyvíjet Valerio Proietti a v září 2006 vydal první verzi. Knihovna je inspirována knihovnou Prototype a vychází z pluginu Proietti pro Prototype. Knihovna je
založená na možnosti rozšiřování existujících objektů, tedy přidávání k existujícím objektům
vlastní metody. MooTools se drží objektově orientovaného přístupu k JavaScriptu. Dokumentace MooTools [19] je přehledná a obsahuje velké množství ukázek kódu.
Základní prvky
MooTools poskytuje několik balíků, z nichž každý rozšiřuje jinou část základního JavaScriptu.
Základem je balík Core , který přidává metody pro základní práci s JavaSciptem (kontrola
existence proměnné, zjištění typu objektu, spojení objektů, iterace objekty a další).
MooTools obsahuje vlastní systém vytváření tříd a dědičnosti. Příklad (převzatý z dokumentace):
var Animal = new Class({
initialize: function(age){
this.age = age;
}
});
var Cat = new Class({
Extends: Animal,
initialize: function(name, age){
this.parent(age); //will call initalize of Animal
this.name = name;
}
});
var myCat = new Cat(’Micia’, 20);
alert(myCat.name); //Alerts ’Micia’.
alert(myCat.age); //Alerts 20.
Jako Animal je vytvořena třída. Metoda initialize je konstruktor třídy, její argumenty
jsou argumenty při vytváření třídy. Třída Cat rozšiřuje třídu Animal a nastavuje vlastní
konstruktor, který akceptuje 2 argumenty. Do proměnné myCat je vytvořen nový objekt Cat.
Balíky Native rozšiřují funkcionalitu základních objektů Array, Function, Number, String,
Hash a Event.
Hledání elementů pomocí CSS selektorů umožňuje balík Utilities/Selectors. Hledat
lze relativně k elementu
$(’#el’).getElements(’div’);
nebo absolutně ve stránce
$$(’#el div’);
Kód nalezne všechny elementy div uvnitř elementu s id el.
2.6. YUI
2.6
13
YUI
YUI je zkratka z Yahoo! User Interface Library. YUI je knihovna vyvíjená společností Yahoo
představená v únoru 2006. V době psaní práce je nejnovější verze YUI 3.1.1 uvedená v
5.5.2010. Jak je uvedeno uvedeno v 2.3, knihovna Ext vychází z YUI. Obě knihovny jsou
si proto velice podobné. V komentářích na [22] je řešeno srovnání ExtJS, YUI a jQuery.
Uživatel karf (komentář č. 5) vystihuje rozdíly: YUI a ExtJS simulují objektový přístup,
jQuery je spíše funkcionální.
Obrázek 2.4: Ukázkový příklad rozhraní aplikace v YUI
Knihovna YUI je stejně jako ExtJS vhodná pro tvorbu aplikací založených na JavaScriptu.
Má vlastní vzhled uživatelského rozhraní a poskytuje velké množství ovládacích prvků a
widgetů, které HTML neposkytuje (např. slider). Pro svojí rozsáhlost není příliš vhodná na
jednoduché manipulace ve stránce.
YUI má kvalitní dokumentaci [21]. Je přehledná a každá vlastnost je rozsáhle zdokumentována i s příklady kódu.
14
KAPITOLA 2. ZHODNOCENÍ KNIHOVEN PRO JAVASCRIPT
Základní prvky
YUI má funkcionalitu rozdělenu do modulů. Pro načtení modulů lze použít načtení souboru
v hlavičce dokumentu nebo metodu use()
YUI().use(’node’, function(Y) {
var node = Y.one(’#demo’);
Y.log(’Found node.. Setting style’);
node.setStyle(’backgroundColor’, ’#D00050’);
node.set(’innerHTML’, ’<strong>Changed!</strong>’);
});
Ukázka kódu je z dokumentace. Metoda use načítá modul pro práci s nodem a function(Y) je
nepovinná callback funkce, která bude vykonána. Y.one() najde element podle CSS selektoru
a vloží ho do proměnné node. Nad tímto elementem jsou pak provedeny další změny.
YUI má vlastní systém vytváření tříd a dědění. Příklad kódu z dokumentace:
Bird = function (name) {
this.name = name;
};
Bird.prototype.flighted
= true;
Bird.prototype.isFlighted = function () { return this.flighted };
Bird.prototype.getName
= function () { return this.name };
Chicken = function (name) {
Chicken.superclass.constructor.call(this, name);
};
Y.extend(Chicken, Bird);
Chicken.prototype.flighted = false;
Je vytvořena třída Bird a její prototype rozšířen o metody a proměnné. Dále je vytvořena
třída Chicken. Ta je voláním Y.extend(Chicken, Bird) nastavena jako podtřída třídy Bird.
Kapitola 3
Vektorová grafika v JavaScriptu
Vektorová grafika je způsob reprezentace obrazových dat pomocí geometrických tvarů určených
vzorci. Oproti rastrové grafice má tu výhodu, že změna rozměrů se neprojevuje negativně
na její kvalitě.
3.1
3.1.1
Vektorové formáty pro web
SVG
Scalable Vector Graphic [4] je formát pro popis dvojrozměrné vektorové grafiky. SVG byl
navržen a vytvořen konsorciem W3C tak, aby splňoval požadavky vektorové grafiky pro
web. Má dvě části:
• formát souboru založený na XML
• API pro grafické aplikace
SVG formát umožňuje vytvářet tvary, text a vloženou rastrovou grafiku. Vše je popsáno
XML formátem. Pro příklad dokumentu:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="400" height="300" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" rx="20" width="300" height="200"
style="fill:red;stroke:black;stroke-width:5"/>
<circle cx="250" cy="200" r="120"
style="fill:blue;stroke:black;stroke-width:3;opacity:0.7"/>
</svg>
15
16
KAPITOLA 3. VEKTOROVÁ GRAFIKA V JAVASCRIPTU
Ukázkový dokument vytvoří SVG plochu o velikosti 400x300px. V něm na souřadnicích
[10,10] vykreslí obdélník ("x="10" y="10") o velikosti 300x200 (width="300" height="200").
Bude mít kulaté rohy s poloměrem s rohů 20 (rx="20") a styl daný kódem style="...".
Podobně druhý objekt bude kruh na pozici [250,200] s poloměrem 120 (r="120"). Ten navíc
bude částečně průhledný.
Ukázkový dokument popisuje následující obrázek. Kruh je oříznutý, protože přesahuje z
dokumentu.
Obrázek 3.1: Obraz vzniklý z ukázkového SVG dokumentu
3.1. VEKTOROVÉ FORMÁTY PRO WEB
3.1.2
17
VML
Vector Markup Language [5] je formát pro popis vektorové grafiky psaný syntaxí XML stejně
jako HTML. VML používá CSS stejným způsobem jako HTML pro určení vzhledu prvků.
Formát VML je vyvinut a prosazován firmou Microsoft. Podpora v produktech Microsoftu
je od IE5 a od Office 2000.
Následující VML kód vykreslí podobný obrázek jako u příkladu k SVG
<html xmlns:v>
<style>v\:*{behavior:url(#default#VML);position:absolute}</style>
<body>
<v:roundrect
style="left:10px;top:10px;width:400px;height:300px"
arcsize="0.1"
fillcolor="red"
strokecolor="black"
strokeweight="5px"
/>
<v:oval
style="left:250px;top:200px;width:240;height:240;"
fill="true"
fillcolor="blue"
strokecolor="black"
strokeweight="3px"
/>
</body>
</html>
Výsledkem bude následující obrázek
Obrázek 3.2: Obraz vzniklý z ukázkového VML dokumentu
3.1.3
TODO
Silverlight
18
KAPITOLA 3. VEKTOROVÁ GRAFIKA V JAVASCRIPTU
3.2
Implementace v různých prohlížečích
Problémem implementace vektorové grafiky na webu je podpora prohlížečů. Microsoft ve
všech dosavadních verzích prohlížeče podporuje VML a nikoli SVG, které je navrženo přímo
pro web. Podle [13] má Internet Exploreru verze 9 už SVG podporovat.
Všechny ostatní nejčastěji rozšířené prohlížeče (Mozilla Firefox, Safari, Google Chrome,
Opera) podporují SVG.
3.3
Knihovny pro cross-browser vektorovou grafiku
Cross-browser implementace knihovny musí řešit rozdílnou podporu prohlížečů. To znamená,
že pro práci s grafikou knihovna poskytuje jednotné rozhraní, ale vnitřně pracuje podle
druhu prohlížeče. Pokud je grafika vykreslována v IE, vykresluje ji pomocí VML, v ostatních
prohlížečích pomocí SVG. V obou prohlížečích musí ovšem grafika vypadat stejně.
3.3.1
dojox.gfx
dojox.gfx [9] je rozšíření knihovny Dojo pro vytváření cross-browser vektorové grafiky. Vybírá
nejvhodnější engine (SVG, VML, Silverlight, Canvas) v daném prohlížeči a za pomocí toho
vykresluje grafiku.
Každý obraz vykreslený pomocí dojox.gfx je vykreslován na Surface (povrch). Surface
je obdélníkový kontejner pro grafiku. Stránka může obsahovat více Surfaců, každý má vlastní
poziční systém od souřadnic [0,0].
Na Surface jsou vytvářeny objekty Shape (tvar). dojox.gfx podporuje následující tvary:
• Rectangle - obdélník (možno se zakulacenými okraji)
• Circle - kruh
• Ellipse - elipsa
• Line - čára
• Polyline / polygon - lomená čára / mnohoúhelník
• Path - cesta/křivka (nejpřizpůsobivější tvar)
• Image - obrázek
• Text
• TextPath - křivka, jejíž tvar bude kopírovat text
Každý tvar má vlastnosti geometrické (popis tvaru) a vizuální (vytažení tvaru, vyplnění
tvaru). Detaily v dokumentaci [9]. V dokumentaci jsou rovněž informace o odlišném chování
v různých prohlížečích a jaké volby nejsou podporovány v jednotlivých technologiích.
3.3. KNIHOVNY PRO CROSS-BROWSER VEKTOROVOU GRAFIKU
19
V dojox.gfx jsem vytvořil příklad, který vytvoří obrázek jako ukázkové SVG 3.1.1 a VML
3.1.2 dokumenty. JavaScriptový kód vypadá následovně:
dojo.require("dojox.gfx");
dojo.require("dojo.colors");
dojo.addOnLoad(function(){
var surface = dojox.gfx.createSurface("canvas", 400, 300);
var rect = surface.createRect({
x: 10,
y: 10,
width: 300,
height: 200,
r: 20
}).setFill("red").setStroke({
color: "black",
width: 5
});
var transparentBlue = new dojo.Color([0, 0, 255, 0.7]);
var circ = surface.createCircle({
cx: 250,
cy: 200,
r: 120
}).setFill(transparentBlue).setStroke({
color: "black",
width: 3
});
});
Metody dojo.require() načtou balíčky pro práci s dojox.gfx a barvami. V metodě addOnLoad
je vytvořen Surface (povrch na vykreslování) v elementu s id canvas. Metody surface.createRect()
a surface.createCircle() vytvoří tvary v Surfacu a dalšími metodami jim jsou nastaveny
atributy. Zajímavé je volání new dojo.Color([0, 0, 255, 0.7]), to vytváří objekt barvy
s průhledností. Předpis je tvaru (R, G, B, opacity). Průhlednost nelze nastavit běžným
voláním metody.
20
KAPITOLA 3. VEKTOROVÁ GRAFIKA V JAVASCRIPTU
3.3.2
Raphaël
Raphaël je JavaScriptová knihovna zjednodušující práci s vektorovou grafikou na webu.
Knihovnu vyvíjí Dmitry Baranovskiy. Autor ji představuje na [1]. Raphaël používá SVG
a VML pro vykreslení grafiky v prohlížeči.
Raphaël umožňuje vytvářet stejné základní tvary jako dojo.gfx (kromě TextPath) a
každému nastavovat vlastnosti.
Raphaël vytváří v elementu obdélníkový Canvas s danými rozměry. V canvasu jsou
vykreslovány všechny tvary vytvářené Raphaëlem.
V Raphaëlu jsem vytvořil stejný příklad jako v dojox.gfx, aby bylo možné srovnat zdrojový kód pro stejný obrázek.
window.onload = function(){
var paper = Raphael("canvas", 400, 300);
var rect = paper.rect(10, 10, 300, 200, 20).attr({
fill: "red",
stroke: "black",
"stroke-width": 5
});
var circ = paper.circle(250, 200, 120).attr({
fill: "blue",
"fill-opacity": 0.7,
stroke: "black",
"stroke-width": 3
});
};
Do proměnné paper je vytvořen Raphaël Paper objekt, ve kterém jsou vykreslovány tvary.
Metody paper.rect a paper.circle vytvoří obdélník a kruh o dané velikosti. Veškerý vzhled
(atributy) je nastaven jediným volání metody attr(). Metoda attr umožňuje přímo nastavit
průhlednost.
Kapitola 4
Popis problému a specifikace cíle
ukázkové aplikace
Vzorová aplikace má za cíl demonstrovat využití některé z popisovaných JavaScriptových
knihoven v kombinaci s vektorovou grafikou pro JavaScript.
4.1
Popis řešeného problému
Při konzultacích s vedoucím práce jsme usoudili, že vhodnou úlohou pro demonstraci výše
zmíněného bude implementovat základní funkcionalitu editoru diagramů. Jednotlivé objekty
je možné vkládat, odstraňovat, vybírat, propojovat a přesouvat.
21
22KAPITOLA 4. POPIS PROBLÉMU A SPECIFIKACE CÍLE UKÁZKOVÉ APLIKACE
4.2
4.2.1
Existující implementace
Raphaël Graffle
Graffle [12] je ukázkovým příkladem knihovny RaphaëlJS. Umožňuje přesouvat vektorové
tvary a při přesouvání jsou přepočítávány cesty mezi tvary. Je tedy svým chováním blízko
aplikaci z této práce. Graffle nevyužívá žádnou další JavaScriptovou knihovnou, pracuje
pouze pomocí knihovny RaphaëlJS a eventů prohlížeče.
4.2.2
Litha–Paint
Litha–Paint [17] je v současné době ve stádiu beta verze. Litha–Paint je plnohodnotný
online vektorový editor, takže má jiný účel než aplikace popisovaná v této práci. Nicméně je
zajímavé ji zhodnotit technologicky.
Přestože tvůrci na úvodní stránce uvádějí tučným písmem "free HTML+Javascript vector graphic editor", čili "HTML+Javascript editor vektorové grafiky zdarma", editor není
čistě HTML+JavaScript editorem. Po analýze nástrojem FireBug je vidět, že na HTML je
založeno uživatelské rozhraní a editační prvky grafiky a na JavaScriptu odezva uživateli,
nicméně po provedení akce je provedena komunikace se serverem a obraz v prohlížeči je
vytvořen vyskládáním obrázků 200x200px přes celý editační prostor a tedy nevyužívá VML/SVG
grafiku v prohlížeči.
4.2.3
RichDraw
RichDraw [20] a je oproti předchozímu jednoduchý editor založený na JavaScriptu a VML/SVG,
ovšem je také pouze vektorovým editorem a tedy není relevantní ho srovnávat s prací.
Nicméně je při jeho analýze FireBugem dobře vidět kombinace HTML a SVG.
Kapitola 5
Analýza a návrh řešení ukázkové
aplikace
V této kapitole je popsán návrh aplikace a specifika realizace.
Je třeba vysvětlit základní pojmy, které využívám:
• node - objekt (uzel) v diagramu, je možné ho spojovat spojeními
• spojení, cesta - vizuální spojení nodů
• drag, draggování - pohyb nodem tažením myši
• id - pokud mluvím o id, je téměř vždy myšlena hodnota HTML atributu id nebo
identifikační řetězec cesty
5.1
Analýza implementovatelnosti a volba knihoven
Pro splnění požadavků jsem potřeboval následující funkcionalitu:
• vkládání a odstraňování elementů - základní funkce, splní každá knihovna
• pohyblivost elementů ("drag & drop"chování) - podporují jQuery UI, Dojo/dnd,
YUI
• vybírání elementů - hotové řešení nabízí jQuery UI pomocí Selectable
• spojení elementů - zajistí knihovny pro vektorou grafiku, RaphaëlJS nebo Dojox.gfx
Rozhodl jsem se použít jQuery. Poskytuje "drag & drop", mám s ním předchozí zkušenosti
a pracuje se mi s ním nejsnáze.
Dále jsem se seznámil s cross-browser implementacemi vektorové grafiky pro JavaScript.
Existují dvě vhodná řešení. V obou jsem si zkusil vykreslit několik objektů a zvolil jsem
RaphaëlJS. Lépe se mi s ním pracuje.
Zajímavým řešením by mohlo být spojení knihovny Dojo Toolkit a DojoX.gfx. To by
poskytlo jednotné rozhraní používání knihoven.
23
24
5.2
KAPITOLA 5. ANALÝZA A NÁVRH ŘEŠENÍ UKÁZKOVÉ APLIKACE
Funkční prototypy
Po zvolení knihoven pro implementaci jsem začal vytvářet technologický prototyp, na kterém
jsem vyzkoušel propojení jQuery s RaphaëlJS.
1. prototyp
Prototyp uměl vkládal nody. Pohyblivost nodů byla řešena metodou Selectable z jQuery
UI. Vybírání jsem řešil vlastním způsobem na základě stavových proměnných. Po kliknutí
na node byla volána funkce, která zkontrolovala, jaká akce je vykonávána. Pokud při kliknutí
byla stisknuta klávesa CTRL, byl node přidán do výběru, jinak byl vybrán samostatně.
Výběr pomocí přetažení obdélníku myši neuměl.
Propojování nodů fungovalo na základě stavových proměnných. Po stisknutí tlačítka byla
nastavena proměnná. Při kliknutí byla zkontrolována proměnná spojování a pokud byla
nastavena, bylo vykresleno spojení mezi nody. Překreslování nodů probíhalo pomalu. Při
každém pohybu nodem byly překresleny všechny cesty spojené s nodem. To bylo neefektivní,
protože rychlost překreslování byla přímo závislá na počtu spojení.
Zdrojový kód jsem psal třídně. Node a cesta měli vlastní třídu. Kód měl následující
strukturu:
function Node (nodeId) {
this.id = nodeId;
this.jqObj = $(’#’ + this.id);
var text = ’prvni text’;
this.create = function() {...};
}
Metody a proměnné začínající this. jsou veřejné, ostatní privátní. To umožňuje zapouzdření.
V prototypu jsem si ověřil, že danou funkcionalitu je možno pomocí jQuery a RaphaëlJS
implementovat. Seznámil jsem se s metodou Draggable, kterou jsem poté využil i ve finální
aplikaci.
2. prototyp
Aplikace podporovala vkládání nodů. Pohyblivost zajišťovalo jQuery Draggable, vybírání
nodů jQuery Selectable.
Během vývoje byla přidávána funkcionalita jako editace uvnitř skupiny. Experimentoval jsem se stylem zobrazení skupiny. Řešil jsem, zda ji zobrazit jako obdélník okolo všech
vnitřních elementů nebo ji skrýt. Po dohodě s cvičícím jsem se rozhodl, že nejlepším řešení
bude element skupiny úplně skrýt nastavením velikosti na 0x0px.
Postupné zásahy do aplikace zanesly do kódu nepřehlednost a aplikace se začala stávat
neudržovatelnou. Proto jsem se rozhodl na základě chyb vytvořit nový prototyp od začátku.
3. prototyp
Třetí prototyp zůstal aplikací popisovanou v této práci.
5.3. NÁVRH
5.3
25
Návrh
Na základě zkušeností z prototypů jsem vypracoval návrh chování a struktury aplikace
5.3.1
Struktura kódu aplikace
Po dohodě s cvičícím jsem se rozhodl formátovat zdrojový kód podobně, jako to dělá třeba
jQuery.
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {...},
jquery: "1.4.2",
length: 0,
size: function() {
return this.length;
}
}
Zdrojový kód je strukturovaný podobně jako JSON do stromové struktury. Každý klíč je buď
proměnná (v příkladě jquery a length), metoda (size) nebo další objekt ({} za jQuery.fn).
Tento formát se dá používat tak, že si kód rozdělím do modulů podle účelu. Pro tento formát
kódu je používán název "jmenný prostor ". V aplikaci používám následující strukturu
mm = {
settings: {...},
canvas: null,
paper: null,
vars: {},
init: function() {...},
ctrl: {
node: {...},
group: {...},
con: {...},
deselect: function() {...}
},
dom: {...},
gui: {...},
fn: {...},
msg: {...}
};
$.fn.mmSelectable = function(){...};
Array.prototype.unique = function(){...};
(pozn. struktura je zjednodušena a zkrácena, slouží pro ilustraci)
26
KAPITOLA 5. ANALÝZA A NÁVRH ŘEŠENÍ UKÁZKOVÉ APLIKACE
Celý kód má vlastní namespace mm. V každém modulu jsou metody a proměnné, které se
vztahují ke stejné oblasti funkcionality. Například settings obsahuje nastavení aplikace, fn
pomocné funkce, msg funkce pro zobrazení zpráv atd.
Proměnné a metody jsou volány pomocí tečkové notace. Každá úroveň ve struktuře kódu
značí jednu tečku v zápisu názvu funkce. Pro ilustraci tedy funkce deselect() v modulu
ctrl bude volána zápisem
mm.ctrl.deselect();
Zdrojový kód je komentován pomocí JSDoc [16] v angličtině. JSDoc je formát dokumentování JavaScriptového kódu přímo inspirovaný formátem JavaDoc. Pro příklad, komentář
funkce vypadá následovně:
/**
* function returns center coordinations of given element
* in format like
*
{
*
hor: Integer,
*
ver: Integer
*
}
* hor and ver means "horizontal" (x) and "vertical" (y)
*
* @param {Object} el jQuery object
* @return {Object} center coordinations of element
*/
getCenter: function(el){...
Hodnoty bez @ jsou popis metody, @param značí typ a popis parametru, @return typ a popis
návratové hodnoty.
Kód je formátován automatickým formátováním vývojového prostředí Aptana Studio 2
[6].
5.3. NÁVRH
5.3.2
27
Node
HTML nodu má následující formát
<div id="UUIDElementu" class="nodeDiv">
<div class="nodeText">obsah nodu</div>
<div class="groupSigns"></div>
</div>
• UUIDElementu - vygenerované globálně unikátní id podle RFC 4122. Při vývoji jsem
používal id ve tvaru nodeX, kde X bylo číslo nodu podle pořadí, ve které byl vložen.
To mi umožňovalo snadněji se vyznat v dokumentu a hledat chyby.
• nodeDiv - třída značící, že div element je node
Do prvního elementu div uvnitř nodu je vkládán textový obsah nodu. Ve 2. prototypu
jsem pro textový obsah nodu neměl vlastní element, což dělalo problémy při editaci. Element
s textem a ve skupině vypadal následovně:
<div id="node1" class="nodeDiv">
<p>zkusebni text</p>
<p>dalsi text<br></p>
<div class="nodeGrMembDiv">
<div class="membsign-group1">
</div>
</div>
</div>
Editor, který pracuje nad elementem nodu nodeDiv, se bude snažit pracovat se všemi potomky. Tedy i s elemtem pro značení skupin, což je problematické.
Pro každý element jsou ukládána pole paths a parents
• paths - id všech spojení, které začínají nebo končí v nodu. Tyto je potřeba překreslit
při pohybu nodem
• parents - id všech skupin, ve kterých se node nachází. Po vložení nodu do skupiny
je na konec pole přidáno id skupiny. Nižší index prvku tedy znamená bližšího rodiče.
Slouží pro rychlé hledání specificky vzdálených rodičů (skupiny, která je pohybována
při pohybu nodem).
28
KAPITOLA 5. ANALÝZA A NÁVRH ŘEŠENÍ UKÁZKOVÉ APLIKACE
Pro ilustraci, při struktuře
<div id="group2">
<div id="group1">
<div id="node1" />
</div>
</div>
bude pole parents elementu node1 vypadat: ["group1", "group2"].
5.3.3
Skupina
HTML kód skupiny má následující strukturu
<div id="UUIDSkupiny" class="groupDiv">
2 až n nodů nebo skupin
</div>
• UUIDSkupiny - je řešeno stejně jako u nodu
• groupDiv - třída značící, že div element je skupina
Pro každou skupinu jsou ukládána pole innerPaths, childrens a objekt pathSet
• innerPaths - id všech spojení, které jsou uvnitř skupiny (spojení, která začínají a
končí v nodech uvnitř skupiny)
• childrens - id všech přímých potomků skupiny
• pathSet - Raphaël objekt set (množina objektů), obsahuje všechny vnitřní cesty s id
podle pole innerPaths
Množina pathSet je uchovávána pro možnosti posouvání. Vnitřní cesty nemusí být jednotlivě přepočítávány, když je skupina posouvána. Místo toho je posunuta celá množina
spojení jako celek. Dokumentace Raphaël nicméně varuje, že při vytváření množiny pro
ní není vytvořený žádný samostatný element. To znamená, že při posouvání Raphaël sám
posouvá všechny jednotlivé prvky v množině pomocí vypočtených souřadnic. Pokud by byl
pro množinu vytvořen element, výpočty by zařídílo na jádro prohlížeče, což by bylo rychlejší.
5.3. NÁVRH
29
Obrázek 5.1: Ilustrace hledání vnitřních spojení ve skupině
Pokud na obrázku jsou node1 a node2 ve stejné skupině (ohraničení jen pro názornost),
v poli innerPaths bude pouze id jejich spojení, nikoli ostatních cest.
5.3.4
Spojení mezi nody
Spojení mezi nody, jinak také cesta (objekt čáry se v Raphaëlu jmenuje path) je Raphaël
objekt path. S cestou není pracováno v DOM. Změny jsou prováděny pouze nad objektem
path, případně množinou set cest path. Objekty path tedy musím uchovávat v proměnných.
Struktura uchovávající spojení je následující:
mm.vars.path = {
map: {
"nodeA-nodeB": "pathUUID",
"nodeB-nodeA": "pathUUID"
},
obj: {
"pathUUID": {
from: "nodeAId",
to: "nodeBId",
path: RaphaelObjektPath
}
}
}
30
KAPITOLA 5. ANALÝZA A NÁVRH ŘEŠENÍ UKÁZKOVÉ APLIKACE
Klíč mm.vars.path uchovává informace o spojeních. Pod klíčem obj jsou uchovávány
informace o cestě. Klíč jednotlivých objektů cest je UUID cesty.
• from - id elementu, ve kterém spojení začíná
• to - id elementu, ve kterém spojení končí
• path - Raphaël objekt path reprezentující cestu
Informace o počátečním a koncovém nodu spojení je až uvnitř objektu. Při hledání spojení mezi dvěma specifickými nody by bylo nutné projít všechny objekty pod klíčem obj
a následně porovnat jejich hodnoty from a to. Proto jsou pod klíčem map uloženy ještě
mapovací klíče.
nodeA-nodeB jsou id obou elementů oddělená pomlčkou. Mapování z počátečního nodu
do koncového i naopak ukazují na stejné UUID, protože nelze zaručit, v jakém pořadí budou
nody, jejichž spojení hledám.
Například id koncového elementu cesty zjistím zápisem:
mm.vars.path.obj["nejakeUUIDcesty"].to
Pro ilustraci hledání spojení mezi dvěma nody:
1. zjistím id prvního elementu, např. node4
2. zjistím id druhého elementu, např. node2
3. vytvořím řetězec z jejich id oddělený pomlčkou, tedy node4-node2
4. voláním mm.vars.path.map["node4-node2"] zjistím UUID cesty
5. voláním mm.vars.path.obj["UUIDcesty"].to přistoupím na objekt cesty a zjistím id
koncového elementu
5.3. NÁVRH
5.3.5
31
Pohyb nodů a překreslování cest
Pohyblivý (draggable) je každý node. Při začátku pohybu nodem je potřeba nastavit collection,
pathSet a alonePaths.
• collection - jQuery kolekce objektů, které budou přemístěny podle pohybu myši. Může
obsahovat nody i skupiny
• pathSet - množina spojení, která bude posouvána podle pohybu myši
• alonePaths - pole id spojení, která budou přepočítávána
Všechny proměnné závisí na stavu aktuálního výběru a druhu dragovaného elementu.
• není vybrán žádný element
– posouván samostatný node
∗ collection - samotný node
∗ pathSet - prázdný
∗ alonePaths - všechny cesty, které začínají nebo končí v dragovaném nodu
– posouván node ve skupině
∗ collection - nejvyšší rodičovská skupina
∗ pathSet - pathSet rodičovské skupiny (obsahuje cesty, které začínají a končí
v některém z nodů ve skupině)
∗ alonePaths - všechny cesty, které začínají nebo končí v některém z nodů
ve skupině
• vybrán alespoň 1 element
– collection - mm-selected elementy (vysvětleno dále zde 6.6)
– pathSet - všechny vnitřní cesty mezi mm-selected elementy (obsahuje cesty,
které začínají a končí některém z nodů ve výběru)
– alonePaths - všechny cesty, které začínají nebo končí v nodu ve výběru
Při dragování elementu jsou elementy v collection a množina pathSet posunuty o
pohyb myši. Akce drag, ve které je volán posun collection a pathSet, může být aktivována
až několikrát za vteřinu. Počet volání funkce závisí na rychlosti pohybu myši. Množství
posunů (resp. přepočtů souřadnic) je tedy lineárně závislé na rychlosti pohybu myši.
Přepočet všech cest alonePaths nemůže být volán při každém pohybu. Rychlost odezvy
pro uživatele by potom byla silně závislá na počtu cest v alonePaths. Pro kompenzaci byla
navržena metoda překreslování popsaná v sekci 6.12.4
Zkoušel jsem i možnost, kdy byl dragovatelný samostatný node a celá skupina. Problém
nastal, když byla dragována skupina, ale ve výběru bylo jen několik nodů z ní. Protože byly
pohybovány nody v kolekci a zároveň skupina, chycený node se pohyboval 2x rychleji než
ostatní.
32
KAPITOLA 5. ANALÝZA A NÁVRH ŘEŠENÍ UKÁZKOVÉ APLIKACE
Kapitola 6
Realizace ukázkové aplikace
Kapitola popisuje realizaci ukázkové aplikace. V popisu se zaměřuji na nestandardní části
řešení a popis implementace základní funkcionality.
6.1
Inicializace aplikace
Po načtení stránky stránky je třeba zavolat inicializační funkci mm.init v jQuery eventu
.ready().
$(document).ready(function(){
mm.init();
});
mm.init = function(){
// init canvas and paper
mm.canvas = mm.vars.currentContext = $(’#canvas’);
mm.paper = Raphael(’canvas’, mm.canvas.width(), mm.canvas.height());
$(mm.canvas).mmSelectable();
// init GUI
mm.gui.init();
};
Inicializační funkce provádí inicializaci a přiřazení základních proměnných
• mm.canvas ukazuje na element s id canvas, který je rodičovským elementem celého
editoru. Jsou v něm prováděny všechny změny DOMu při editaci
• mm.paper ukazuje na objekt RaphaëlJS Paper, ve kterém je vykreslována vektorová
grafika
mm.paper je vytvořen voláním metody Raphael(). Ta vytvoří Raphaël paper v elementu
s id canvas o rozměrech tohoto elementu.
33
34
KAPITOLA 6. REALIZACE UKÁZKOVÉ APLIKACE
Další částí inicializační funkce je vytvoření selectable (možnosti vybírání elementů) pomocí volání
$(mm.canvas).mmSelectable();
v elementu mm.canvas. Popis metody se nachází dále v textu 6.6.2.
Při inicializaci aplikace je třeba inicializovat uživatelské rozhraní voláním 6.3
mm.gui.init();
Obrázek 6.1: Screenshot aplikace s diagramem
6.2. ROZHRANÍ ZPRÁV
6.2
35
Rozhraní zpráv
Vytvořil jsem si vlastní rozhraní pro vytváření zpráv v objektu mm.msg. To umožňuje jednodušší
a přehlednější spravování cíle a účelu zprávy.
6.2.1
Zpráva uživateli
Tato funkce vytvoří informační okno se zprávou ve stylu MAC OS X, jak je vidět na obrázku
níže
Obrázek 6.2: Screenshot zpráv uživateli
Zpráva je vytvořena voláním funkce
mm.msg.notice(str);
kde str je obsah sdělení, který může obsahovat HTML formátování.
Zdrojový kód funkce vypadá následovně
notice: function(str){
$("<div/>", {
"class": ’noticeMsg’,
"html": str,
"css": { opacity: 0.7 }
}).hide().appendTo(’#noticePanel’)
.fadeIn(2000).delay(5000)
.fadeOut(2000, function(){
$(this).css({
display: ’block’,
visibility: ’hidden’
}).addClass(’noticeHidden’);
if ($(’#noticePanel>div:not(.noticeHidden)’).length == 0) {
$(’#noticePanel>div’).remove();
};
});
}
36
KAPITOLA 6. REALIZACE UKÁZKOVÉ APLIKACE
Pro každou zprávu je vytvořen element div s třídou noticeMsg a HTML obsahem str.
Element je ještě před připojením do DOM skryt voláním metody .hide(), aby se element
hned neobjevil, ale bylo ho možno animovat. Následně je element připojen do rodičovského
elementu. Element bude postupně zobrazen během 2s (2000ms), zůstane 5s vidět a následně
bude během 2s skryt. Metoda fadeOut() má vloženu callback funkci, která opravuje standarní chování metody. Po doběhnutí animace by byla elementu nastavena CSS vlastnost
display: ’none’. To by způsobilo nežádoucí "poskočení"elementu úplně nahoru v rodiči,
které nevypádá dobře pro uživatele. Callback funkce nastaví elementu zpět display:’block’
a skrytí zprávy provede vlastností visibility: ’hidden’, takže element zůstane na místě,
jen nebude vidět. Následně elementu nastaví třídu noticeHidden. Ta je dále využita pro
kontrolu, zda je ještě nějaká zpráva zobrazena a pokud ne, odstraní všechny zprávy z DOM.
6.2.2
Debugovací informace
Tato zpráva při vývoji vypisovala debugovací informace. Debugovací zprávy jsou vkládány
do elementu s id debug jako nové řádky. Funkce je volána takto:
mm.msg.debug(str);
Debugovací informace jsou v ukázkové aplikaci skryty.
6.3
Inicializace uživatelského rozhraní
Funkce mm.gui.init() inicializuje uživatelské rozhraní. Provede zakázání tlačítek a nastaví
tlačítkům a panelu nastavení vzhled jQuery UI.
Canvas div element a Raphael Paper objekt jsou vytvořeny s pevnými rozměry. Proto
při inicializaci aplikaci jsou zjištěny rozměry okna a nastaveny canvasu i paperu.
Problém by nastal, pokud by byla změněna velikost okna. Canvas i paper by měli pořád
stejný rozměr. Proto je oknu prohlížeče nastaven event při změně velikosti resize, který
oběma nastaví nové rozměry.
$(window).resize(function(){
var w = $(window).width();
var h = $(window).height();
$(mm.canvas).width(w).height(h - $(’#controls’).height());
mm.paper.setSize(w, h);
});
6.4. VLASTNÍ SELEKTORY
6.4
37
Vlastní selektory
Pro zjednodušení vybírání a filtrování elementů pomocí jQuery jsem si vytvořil některé
vlastní selektory. Jejich přehled a popis je v následující tabulce
selektor
:nodes
:groups
popis selektoru
vybere pouze elementy, které jsou nodem
vybere pouze elementy, které jsou skupinou
Tabulka 6.1: Přehled vlastních jQuery selektorů
6.5
Ovládací prvky
Ovládací prvky se nachází v horní části editoru ve vlastním panelu.
6.5.1
Funkce pro práci s ovládacími prvky
Specifické akce editoru lze provést pouze za určitého stavu (například skupina jde vytvořit
pouze pokud je vybráno 2 a více nodů nebo skupin). Proto nemohou být všechna tlačítka
aktivní neustále. Pro povolení, zakázání a aktualizaci zobrazení tlačítek jsem vytvořil funkce.
Zakázání tlačítek
Tlačítko je výchozím stavu povoleno. Jeho zakázání je provedeno voláním
mm.gui.btn.disable(el);
kde el je jQuery objekt tlačítka. Uvnitř funkce je voláno
$(el).button(’disable’);
pro zakázání tlačítka vytvořeného pomocí jQuery UI.
Povolení tlačítek
Tlačítko je povoleno funkcí mm.gui.btn.enable(el) stejně jako u zakázání. Povolení je
provedeno podobně jako zakázání nastavením
$(el).button(’enable’);
Aktualizace tlačítek
Funkce mm.gui.btn.refreshAll() provádí aktualizaci stavů jednotlivých tlačítek v závislosti na stavu editoru. Aktualizace probíhá po změně výběru. Jednotlivé stavy a jim náležící
povolená tlačítka jsou komentovány ve zdrojovém kódu funkce.
38
KAPITOLA 6. REALIZACE UKÁZKOVÉ APLIKACE
6.6
Vybírání elementů
Aplikace umožňuje vybírání elementů tažením obdélníku myší tak, jak je uživatel zvyklý z
desktopových operačních systémů. Tuto funkcionalitu nabízí jQuery Selectable.
jQuery Selectable je jednou z interakčních metod jQuery UI. Jak bylo zmíněno v sekci
6.1, aktivaci Selectable provádí metoda mmSelectable.
V souvislosti s vybíráním existují třídy ui-selected a mm-selected
• ui-selected - nody vybrané myší pomocí jQuery Selectable. Nody s touto třídou jsou
zvýrazněny v uživatelském rozhraní jinou barvou.
• mm-selected - node vybraný vzhledem k editoru. Může to být node nebo skupina. Dle
této třídy jsou vybírány elementy, se kterými se bude pracovat, a určují aktivní ovládací
prvky. Pokud je mm-selected skupina, všechny nody uvnitř ní jsou ui-selected, tedy
zvýrazněny v uživatelském rozhraní.
6.6.1
Metoda topGroups
Metoda topGroups(index) je vlastní jQuery metoda, která hledá nejvyšší rodiče elementů
pro účely vybírání.
Pokud je vybrán node a má s ním být vybrána celá skupina, metoda je zavolána na
element nodu a ta vrátí element celé skupiny. Pokud node nemá žádného rodiče, je vrácen
samotný node.
6.6.2
Metoda mmSelectable
Metoda mmSelectable je mým vlastním rozšířením funkcionality jQuery. Vlastní metodu
jsem vytvořil pro zpřehlednění inicializační funkce.
Metoda je volána nad elementem, uvnitř kterého bude možnost vybírat. Vytváří běžný
jQuery Selectable s mými požadovanými vlastnostmi a callback funkcemi. Následně vrací
objekt, nad kterým je volána, v souladu s konvencemi psaní vlastních jQuery metod. Použití
metody je již ukázáno v sekci 6.1.
filter
Parametr filter určuje, které elementy bude možné vybrat. Jeho hodnota je vlastní selektor
:nodes. To znamená, že bude možno vybrat pouze nody.
stop
K eventu stop lze připojit callback funkci. Ta je provedena, když je skončeno vybírání,
přesněji když je uvolněno tlačítko myši. V callback funkci tohoto eventu je provedeno několik
důležitých akcí.
Předně, pokud není nic vybráno (počet elementů s třídou ui-selected je roven 0),
jsou pouze odstraněna označení mm-selected, aktualizována tlačítka a příkazem return je
ukončen běh funkce.
6.7. VKLÁDÁNÍ NODŮ
39
Do proměnné aloneNodes jsou vybrány samostatné nody, které jsou přímými samostatnými potomky canvasu.
Při výběru je zkontrolován checkbox, zda mají vybrány celé skupiny
• nezaškrtnutý - jako mm-selected jsou označeny nody, které jsou vybrány uživatelem
(nody ui-selected pomocí Selectable)
• zaškrtnutý - metodou topGroups jsou nalezeny nejvyšší elementy, ve kterých se node
nachází (skupina nebo sám node), a jsou označeny jako mm-selected.
Když je checkbox zaškrtnutý, jsou elementy nalezené metodou topGroups uloženy do
proměnné topGroups. Pokud se v kolekci nalezených elementů vyskytuje skupina
if (topGroups.not(’:nodes’).length != 0 &&
$(’#selectionMethod’).is(’:checked’)) ...
je jim přidána třída mm-selected, všechny vnitřní nody jsou označeny jako ui-selected a je
vypsáno oznámení uživateli, že byly vybrány celé skupiny. Dále jsou aktualizována tlačítka.
Pokud je nastavena kolekce mm.vars.connectingTo, probíhá akce "connect to", tedy
propojení více nodů najednou. Nodům, které jsou v této kolekci, je odstraněna třída mm-selected
a je volána funkce mm.ctrl.con.connectToStop(). Třída mm-selected je odstraněna, aby
se funkce nemusela pokoušet propojit node sám se sebou.
6.7
Vkládání nodů
Základní uživatelskou akcí je vložení nodu. Po kliknutí na příslušné tlačítko je vložen node
do editoru, tedy do mm.canvas. Všechny nové nody jsou vkládány na stejnou pozici podle
nastavení v CSS dokumentu.
Zdrojový kód funkce pro vkládání nodu do DOM
create: function(nodeId){
$("<div/>", {
"id": nodeId,
"class": mm.settings.nodeDivClassName,
"html": ’<div class="nodeText">’ + mm.settings.defaultValues.node.html +
’<br/>’ + nodeId + ’</div>’ + ’<div class="groupSigns"></div>’
}).data({
’paths’: [], // array with IDs of all path connecting node
’parents’: [] // array of parent IDs
}).appendTo(mm.canvas).mmDraggable();
}
Je vytvořen element ve tvaru uvedeném v sekci 5.3.2, který je následně připojen do
canvasu. Dále je nad nodem zavolána metoda, která umožní jeho pohyblivost.
40
6.8
KAPITOLA 6. REALIZACE UKÁZKOVÉ APLIKACE
Pohyblivost nodů a skupin
Pro pohyblivost (dragování) nodů jsem si vytvořil vlastní metodu mmDraggable.
6.8.1
Metoda mmDraggable
Metoda mmDraggable je stejně jako mmSelectable mým vlastním rozšířením funkcionality
jQuery. Metoda vytváří nad objektem, nad kterým je volána, běžný jQuery Draggable se
zadanými vlastnostmi a callback funkcemi dle mé potřeby. Metoda vrací objekt, nad kterým
je zavolána, aby splnila konvence vlastních metod jQuery. Použití metody je uvedeno v sekci
6.7.
Zdrojový kód metody je velice rozsáhlý, proto není v práci uveden. K nalezení je ve
zdrojových kódech aplikace
cursor
Parametr cursor je nastaven na move. Toto je z čistě estetického hlediska, kdy se uživateli při
začátku dragu změní kurzor myši na kříž pohybu, jak je zvykem v desktopových prostředích.
grid
Parametr grid nastavuje elementu mřížku na přichytávání. Hodnota je pole ve tvaru [x,y].
Lze nastavit jednoduše v mm.settings.canvas.grid.
helper
Parametr helper umožňuje nahradit pohybovaný node vlastním kódem. Funkce vrací prázdný
div element. Toto nastavení zakáže pohyb dragovaného elementu. Ten je pak posunut stejně
jako ostatní s kolekcí mm.vars.drag.collection.
start
Parametr start určuje callback funkci vykonanou při začátku dragování. V této funkci jsou
nastaveny v klíči mm.vars.drag proměnné pathSet, alonePaths a collection podle návrhu
v sekci 5.3.5. Když je splněna podmínka
if ($(’div.ui-selected’).length == 0) { ...
výběr je prázdný a proměnné jsou nastaveny podle nodu, který spustil akci.
if ($(this).data(’parents’).length != 0)
Když element nemá prázdné pole parents, má rodiče (je ve skupině). Potom jsou kódem
6.8. POHYBLIVOST NODŮ A SKUPIN
41
var parents = $(this).data(’parents’);
var parent = $(’#’ + parents[parents.length - 1]);
mm.vars.drag.pathSet = parent.data(’pathSet’);
var nodes = parent.find(’:nodes’);
var alonePaths = mm.dom.con.getOuterConnectionIds(nodes);
if (alonePaths.length != 0)
mm.vars.drag.alonePaths = alonePaths;
nastaveny proměnné
• mm.vars.drag.pathSet je pathSet nalezené rodičovské skupiny
• mm.vars.drag.alonePaths jsou vnější spojení všech nodů ve skupině
• mm.vars.drag.collection je rodičovská skupina
Pokud dragovaný node nemá rodiče, všechny proměnné jsou nastaveny podlě něho
mm.vars.drag.pathSet = false;
mm.vars.drag.alonePaths = $(this).data(’paths’);
mm.vars.drag.collection = $(this);
• mm.vars.drag.pathSet je false, protože žádné cesty nebudou pouze přesouvány
• mm.vars.drag.alonePaths jsou všechny cesty, které má node v poli paths
• mm.vars.drag.collection je sám node
Pokud výběr není prázdný, všechny proměnné jsou nastaveny podle vybraných elementů, tedy mm-selected.
• mm.vars.drag.collection jsou všechny mm-selected elementy
• mm.vars.drag.pathSet je vytvořen z vnitřních spojení spojení všech nodů ve výběru
• mm.vars.drag.alonePaths jsou vnější spojení všech nodů ve výběru
Všechny nody, které se budou přepočítávat, jsou zesvětleny. Následně je spustěna metoda
mm.dom.con.refreshCycle() 6.12.4 zajišťující překreslování cest.
drag
Metoda vypočte změnu pozice od předchozího volání metody drag. Pokud je nastaven
mm.vars.drag.pathSet, je posunut o tuto změnu. Pokud je nastavena kolekce, pro všechny
její členy jsou vypočteny a nastaveny nové souřadnice.
mm.vars.initPos = {
x: x,
y: y
};
nastaví proměnné, které udržují pozici, na které byl naposledy proveden posun elementů.
42
KAPITOLA 6. REALIZACE UKÁZKOVÉ APLIKACE
stop
Metoda je volána, když skončí dragování (myš na dragovaném elementu je uvolněna). Pokud
pole alonePaths není prázdné, jsou všechny cesty přepočteny a je jim nastaven výchozí styl.
Všechny nastavené proměnné vzhledem k dragovaní (initPos, collection, dragging,
pathSet a alonePaths) jsou nastaveny na false.
6.9
Odstranění nodů
Vybrané nody lze odstranit, pokud ve výběru není skupina. Funkce dostane jako parametr
kolekci nodů mm-selected. Pro všechny nody v kolekci jsou odstraněny cesty z paths (začínající nebo končící v nodu). Id cest je odstraněno i z nodů, které nejsou odstraňovány, ale
cesta v nich začíná nebo končí.
Pro každou jednotlivou cestu jsou odstraněny položky v mapovacích proměnných a objekt
cesty. Dále jsou odstraněny elementy v kolekci.
6.10
Vytvoření skupiny
Ve funkci mm.ctrl.group.create() je vygenerováno id nové skupiny a vygenerována barva
značení skupiny. Barvy skupin jsou uloženy v proměnné
mm.vars.group[groupId] = {
color: barvaSkupiny
};
Poté je zavolána funkce
mm.dom.group.create(groupId, parent, childrens);
• groupId - id nově vytvářené skupiny
• parent - rodičovský prvek, ve kterém bude vytvořena skupina
• childrens - potomci nové skupiny
Funkce mm.dom.group.create(groupId, parent, childrens) vytvoří element skupiny
podle návrhu 5.3.3.
6.11. ZRUŠENÍ SKUPINY
43
Kód
var groupSign = $("<div/>", {
"class": ’groupMembSign grMembSign-’ + groupId,
"css": {
"background-color": mm.vars.group[groupId].color
}
});
vytvoří čtverec značící příslušnost skupině. Ten má dříve vygenerovanou barvu.
Obrázek 6.3: Ukázka znaménka příslušnosti skupině
Následně je vytvořeno pole childrensArr s id potomků. Všem nodům ve skupině je na
konec pole parents vloženo id nové skupiny.
Funkce mm.dom.con.refreshGroup(objektCesty) aktualizuje pole innerPaths a pathSet
skupiny.
6.11
Zrušení skupiny
Funkce odstraní znaménka příslušnosti ke skupině všem vnitřním nodům. Dále odstraní id
skupiny z pole parents všech nodů.
Všichni přímí potomci skupiny mají přepočteny pozice (pozice elementu + pozice skupiny).
Dále jsou přepojeny do rodiče a element skupiny odstraněn.
44
KAPITOLA 6. REALIZACE UKÁZKOVÉ APLIKACE
6.12
6.12.1
Cesty
Vytvoření cesty
Cesta může být vytvořena mezi dvěma nody. Jedno spojení vytvoří funkce
mm.dom.con.connect(nodes)
Funkce vytvoří obě možné kombinace pro mapování. Pokud už existuje spojení cest, funkce
končí. Pokud ne, jsou nastaveny mapovací proměnné a vytvořen objekt cesty
mm.vars.path.map[nameA] = pathUUID;
mm.vars.path.map[nameB] = pathUUID;
mm.vars.path.obj[pathUUID] = {
from: nodeA.attr(’id’),
to: nodeB.attr(’id’)
};
Do pole paths obou nodů je přidáno UUID cesty. Následně jsou zjištěny počáteční a koncové
souřadnice cesty a mezi těmito body vytvořena cesta Raphaël path.
mm.vars.path.obj[pathUUID].path = mm.paper.path(...)
Pokud je některý z nodů ve skupině, je aktualizován obsah proměnných cesty.
6.12.2
Spojení více nodů
Tlačítko connect to uživatelského rozhraní umožňuje propojit více nodů najednou. Při stisku
tlačítka je volána funkce mm.ctrl.con.connectToStart().
Do proměnné mm.vars.connectingTo jsou vloženy elementy mm-selected a je zrušen
výběr. Callback funkce mmSelectable stop zjistí, že probíhá spojení více nodů a volá funkci
mm.ctrl.con.connectToStop() (více v 6.6.2).
Funkce mm.dom.con.connectTo()
Funkce mm.dom.con.connectTo() vytváří samotné vícenásobné spojení.
connectTo: function(where){
var from = mm.vars.connectingTo;
var to = $(where);
for (i = 0; i < from.length; i++) {
var fromId = $(from).eq(i).attr(’id’);
for (j = 0; j < to.length; j++) {
var toId = $(to).eq(j).attr(’id’);
var toConnect = $(’#’ + fromId + ’, #’ + toId);
mm.dom.con.connect(toConnect);
}
};
}
6.12. CESTY
45
Funkce dostává jako parametr cílové elementy v atributu where. Dva for cykly v sobě
projdou kombinaci všech nodů, které byly vybrány jako první (from, zdroje spojení), a nodů
které byly výbrány jako druhé (to, cíle spojení). Na každou kombinaci nodů poté volá funkci
pro běžné spojení dvou nodů.
6.12.3
Hledání vnitřních a vnějších cest
Pro hledání vnitřních a vnějších cest daných nodů jsem si vytvořil dvě funkce.
• vnitřní cesty nodů - cesty, které začínají a končí v některém z daných nodů
• vnější cesty nodů - cesty, které začínají nebo končí v některém z daných nodů
Hledání vnitřních cest
getInnerConnectionIds: function(elements){
var paths = [];
$(elements).each(function(key, value){
var elId = $(this).attr(’id’);
for (i = 1; i < $(elements).length; i++) {
var thisId = $(elements).eq(i).attr(’id’);
if (elId == thisId || i <= key)
continue;
var mapName = elId + ’-’ + thisId;
if (mm.dom.con.exists(mapName))
paths.push(mm.dom.con.getId(mapName));
}
});
return paths;
}
Funkce hledá všechny možné kombinace vnitřních cest. Konkrétně vytváří všechny možné
kombinace id a pomocí mapování hledá, zda cesta existuje. Pokud ano, do pole paths přidá
její id. Pole id je nakonec vráceno.
46
KAPITOLA 6. REALIZACE UKÁZKOVÉ APLIKACE
Hledání vnějších cest
getOuterConnectionIds: function(elements){
var innerConnections = mm.dom.con.getInnerConnectionIds(elements);
var allConnections = [];
var outerConnections = [];
var pathsArr = [];
$(elements).each(function(key, value){
pathsArr = $(this).data(’paths’);
allConnections = allConnections.concat(pathsArr);
});
outerConnections = allConnections.unique().diff(innerConnections);
return outerConnections;
}
Funkce dostává jako parametr elementy, jejichž vnitřní spojení má vrátit. Funkce nejprve do
pole allConnections najde všechna spojení všech nodů. Do pole outerConnections najde
rozdíl polí všech a vnitřních spojení. To jsou vnější cesty a ty jsou vráceny.
6.12.4
Přepočet cest
Přepočet cesty je její překreslení. To probíhá na základě aktuálních souřadnic počátečního
a koncového nodu cesty. Základní funkcí je přepočet jedné cesty určené podle UUID cesty
mm.dom.con.refreshSingle(UUID).
Přepočet jedné cesty
Funkce mm.dom.con.refreshSingle(UUID) najde počáteční a koncové elementy cesty a do
proměnných start a end najde jejich středy. Pokud je některý z nodů ve skupině, jsou
přičteny souřadnice skupiny.
newPath = {
path: "M" + start.hor + " " + start.ver + "L" + end.hor + " " + end.ver
};
pathObj.attr(newPath);
newPath obsahuje klíč path. To je řetězec určující souřadnice cesty. Tento tvar má, protože
Raphaël metoda attr vyžaduje objekt s jednotlivými atributy. Metoda attr() nastavuje
nové hodnoty atributů jednotlivému Raphaël objektu nebo množině.
Překreslování cest při draggování
Funkce mm.dom.con.refreshCycle(index) provádí "lazy"("líné") překreslování. To znamená, že nepřekresluje cesty při dragu, ale na pozadí nezávisle na pohybu myši. Když je
spuštěna, najde si cesty z mm.vars.drag.alonePaths, které mají být přepočteny a podle
indexu přepočte jednu z nich. Jakmile je přepočtena cesta určená indexem, funkce volá sebe
samu s indexem o jedna větším. To znamená, že přepočte další cestu.
6.13. PROBLÉMY FUNKČNOSTI
47
Další přepočty cest
Další metody přepočtu v klíči mm.dom.con využívají přepočet jednotlivé cesty. Liší se typem
parametru, který určuje, jaké cesty přepočítat.
funkce
refresh(node)
refreshByArray(paths)
popis
překreslí cesty podle pole paths daného nodu
překreslí cesty dané polem paths v parametru
Tabulka 6.2: Přehled funkcí pro aktualizaci cesty
6.13
Problémy funkčnosti
Nefunkčnost v IE
V průběhu vývoje přestala aplikace správně pracovat v prohlížeči Internet Explorer. Problém
nastane, když se uživatel snaží pohybovat nodem. V debugeru IE je hlášena chyba "Neplatný
argument"v souboru jquery-1.4.2.min.js s knihovnou jQuery.
Problém se projevil po spojení jQuery Draggable a Selectable. Při dragu nodu nebyl
správně zachycen event a zároveň začala akce select, která při dragu nodu nemá být
spuštěna.
Spojení nodu vektorově vykreslenou cestou funguje v pořádku.
Pokud by aplikace měla přejít do produkční verze, toto by byl první problém, který by
bylo potřeba vyřešit.
Výběr pomocí klávesy CTRL
jQuery Selectable podporuje výběr pomocí klikání s klávesou CTRL, jak je zvykem z desktopových prostředí. Po kombinaci Draggable a Selectable tato možnost přestala fungovat.
48
KAPITOLA 6. REALIZACE UKÁZKOVÉ APLIKACE
Kapitola 7
Závěr
• Zhodnocení splnění cílů DP/BP a vlastního přínosu práce (při formulaci je třeba vzít
v potaz zadání práce).
• Diskuse dalšího možného pokračování práce.
49
50
KAPITOLA 7. ZÁVĚR
Literatura
[1] Dmitry Baranovskiy. Raphaël: a JavaScript API for SVG.
http://dev.opera.com/articles/view/raphael-a-javascript-api-for-svg/, stav
z 22.5.2010.
[2] R. Šerý. JavaScript s jQuery - lehký úvod.
http://interval.cz/clanky/javascript-s-jquery-lehky-uvod/, stav z 8.5.2010.
[3] M. Hassman. Seriál Seznamte se s Dojo Toolkitem.
http://zdrojak.root.cz/serialy/seznamte-se-s-dojo-toolkit/, stav z 18.5.2010.
[4] W3C. Scalable Vector Graphics (SVG).
http://www.w3.org/Graphics/SVG/, stav z 21.5.2010.
[5] W3C. Vector Markup Language (VML).
http://www.w3.org/TR/NOTE-VML, stav z 21.5.2010.
[6] Aptana Studio 2 - oficiální stránky.
http://www.aptana.org/, stav z 23.5.2010.
[7] Dojo dokumentace - dojocampus.
http://www.dojotoolkit.org/documentation/, stav z 19.5.2010.
[8] Book of Dojo.
http://o.dojotoolkit.org/book/dojo-book-0-9/introduction/history,
18.5.2010.
stav
z
[9] dojox/gfx - DojoCampus - Docs.
http://docs.dojocampus.org/dojox/gfx/, stav z 22.5.2010.
[10] Ext JS learn overview.
http://www.extjs.com/learn/Overview, stav z 19.5.2010.
[11] Ext JS 3.2 Samples.
http://www.extjs.com/deploy/dev/examples/, stav z 19.5.2010.
[12] Graffle - příklad knihovny Raphaël.
http://raphaeljs.com/graffle.html, stav z 2.5.2010.
[13] IEBlog: SVG in IE9 Roadmap.
http://blogs.msdn.com/ie/archive/2010/03/18/svg-in-ie9-roadmap.aspx, stav z
21.5.2010.
51
52
LITERATURA
[14] jQuery dokumentace.
http://docs.jquery.com/, stav z 25.5.2010.
[15] jQuery UI domácí stránka.
http://jqueryui.com/, stav z 8.5.2010.
[16] JSDoc - JavaScript Documentation Tool.
http://jsdoc.sourceforge.net/, stav z 23.5.2010.
[17] Litha–Paint - web drawing service.
http://www.litha-paint.com/, stav z 25.5.2010.
[18] Mochikit documentation.
http://www.mochikit.com/doc/html/MochiKit/index.html, stav z 19.5.2010.
[19] Mootools dokumentace.
http://mootools.net/docs/, stav z 19.5.2010.
[20] RichDraw Demo.
http://starkravingfinkle.org/projects/richdraw/richdraw_demo.htm,
25.5.2010.
stav
z
[21] YUI 3 dokumentace.
http://developer.yahoo.com/yui/3/, stav z 20.5.2010.
[22] Komentáře článku Naučte se YUI - Dan Wellman.
http://www.misantrop.info/679958-naucte-se-yui-dan-wellman.php,
20.5.2010.
stav
z
Příloha A
Editace základního vzhledu
Veškeré nastavení vzhledu je prováděno pomocí CSS stylů v souboru mm-style.css. V následující tabulce je uveden seznam používaných specifických CSS stylů s jejich popisem
selektor
#canvas
#controls
#noticePanel
#noticePanel .noticeMsg
.nodeDiv
.groupDiv
.ui-selecting,
.ui-selecting .nodeDiv
.ui-selected,
.ui-selected .nodeDiv
.groupSigns
.groupMembSign
popis stylu
styly pro element canvas
umístění a styl panelu s kontrolními prvky
element pro umísťování zpráv uživateli
styl jednotlivých zpráv pro uživatele
inspirován hlášeními MAC OS X
třída specifikující styl vloženého nodu
třída specifikující styl skupiny
styl vybraných elementů během vybírání
styl vybraných elementů po skončení vybírání
styl elementu, do kterého jsou vkládány znaménka
příslušnosti ke skupinám
styl znaménka příslušnosti ke skupině
Tabulka A.1: Přehled CSS stylů editoru
53
54
PŘÍLOHA A. EDITACE ZÁKLADNÍHO VZHLEDU
Příloha B
Specifické vlastnosti kódu
Ve zdrojovém kódu se vyskytují specifické zápisy, které bych rád vysvětlil
B.1
jQuery length vs. size()
jQuery metoda size() vrací délku kolekce (počet elementů v kolekci). Metoda však pouze
vrací hodnotu proměnné length. Proto nepoužívám metodu size(), ale na počet elementů se
dotazuji přímo v proměnné length. Tím je ušetřeno jedno zbytečné volání funkce. Zjišťování
délky kolekce díky tomu vypadá stejně jako například zjištění délky pole.
55
56
PŘÍLOHA B. SPECIFICKÉ VLASTNOSTI KÓDU
Příloha C
Seznam použitých zkratek
AJAX Asynchronous JavaScript and XML
API Application Programming Interface
CSS Cascading Style Sheets
DOM Document Object Model
IE Internet Explorer
JS JavaScript
JSON JavaScript Object Notation
HTML HyperText Markup Language
SVG Scalable Vector Graphics
UUID Universally Unique Identifier
VML Vector Markup Language
XML Extensible Markup Language
YUI Yahoo! User Interface
57
58
PŘÍLOHA C. SEZNAM POUŽITÝCH ZKRATEK
Příloha D
Obsah přiloženého CD
Tato příloha je povinná pro každou práci. Každá práce musí totiž obsahovat
přiložené CD. Viz dále.
Může vypadat například takto. Váš seznam samozřejmě bude odpovídat typu vaší práce.
(viz [?]):
Obrázek D.1: Seznam přiloženého CD — příklad
Na GNU/Linuxu si strukturu přiloženého CD můžete snadno vyrobit příkazem:
$ tree . >tree.txt
Ve vzniklém souboru pak stačí pouze doplnit komentáře.
59
60
PŘÍLOHA D. OBSAH PŘILOŽENÉHO CD
Z README.TXT (případne index.html apod.) musí být rovněž zřejmé, jak programy
instalovat, spouštět a jaké požadavky mají tyto programy na hardware.
Adresář text musí obsahovat soubor s vlastním textem práce v PDF nebo PS formátu,
který bude později použit pro prezentaci diplomové práce na WWW.

Podobné dokumenty

Obsah - CPress

Obsah - CPress Technické triky Trik 12.01: Upravte si sluchátka, aby fungovala s původním iPhonem Trik 12.02: Přinuťte kolébku původního iPhonu fungovat i s iPhonem 3G Trik 12.03: Vyrobte si pro iPhone headset z ...

Více

Přednáška v PDF.

Přednáška v PDF. – Konvence má přednost před konfigurací = Nastavujeme pouze to, co se liší od výchozí konfigurace – http://blog.karmi.cz/2007/6/16/co-je-ruby-on-rails-cast-2

Více

prezentace

prezentace Srovnání JS frameworků Jiří Kunčar & Jiří Martišek Technologie vývoje webových aplikací

Více

Konspekt-Speciální technické prostředky

Konspekt-Speciální technické prostředky nástroje a pracovních tlaků, které se pohybují od 35 do 72 MPa! Střižná síla je největší u čepu hydraulických nůžek viz obr. Stříhání pružinových a kalených ocelí je nepřípustné. Nůžky existují s r...

Více

Co je Dojo?

Co je Dojo? Dojo je javascriptový toolkit určený k usnadnění tvorby webových aplikací. Nabízí nástroje pro manipulaci s DOM, animaci, AJAX a internacionalizaci webových projektů. Dojo Core, který obsahuje nejz...

Více

Operační systéme II

Operační systéme II Návod : Vytvořte kopii shellu bash a nastavte mu všechna práva a s-bit uživatele. Potom zkuste předat jeho vlastnictví superuživateli. Vytvořili jste kopii shellu s nastaveným s-bitem ve vlastnictv...

Více

Dokumentace

Dokumentace že se jedná o velmi kvalitní kreslící a prezentační nástroj, ve kterém lze dokonce tvořit aplikace a hry, je uživatelsky přívětivý, intuitivní a velmi dobře se v něm pracuje. ActionScript samotný j...

Více

zablokování olivkou

zablokování olivkou • Signál Memory Read (MR), zabezpečuje časování čtení z pamětí či jiných bloků do mikroprocesoru nebo počítače, • Signál Memory Write (MW), zabezpečuje časování zápisu do pamětí či jiných bloků z m...

Více