Univerza v Ljubljani
Fakulteta za raˇ cunalniˇ stvo in informatiko
Klemen Jug
Prenova spletne aplikacije VPT z uporabo tehnologije spletnih
komponent
DIPLOMSKO DELO
UNIVERZITETNI ˇSTUDIJSKI PROGRAM PRVE STOPNJE
RA ˇCUNALNIˇSTVO IN INFORMATIKA
Mentor : izr. prof. dr. Matija Marolt Somentor : as. mag. ˇ Ziga Lesar
Ljubljana, 2022
To delo je ponujeno pod licenco Creative Commons Priznanje avtorstva-Deljenje pod enakimi pogoji 2.5 Slovenija (ali novejˇso razliˇcico). To pomeni, da se tako besedilo, slike, grafi in druge sestavine dela kot tudi rezultati diplomskega dela lahko prosto distribuirajo, reproducirajo, uporabljajo, priobˇcujejo javnosti in pre- delujejo, pod pogojem, da se jasno in vidno navede avtorja in naslov tega dela in da se v primeru spremembe, preoblikovanja ali uporabe tega dela v svojem delu, lahko distribuira predelava le pod licenco, ki je enaka tej. Podrobnosti licence so dostopne na spletni strani creativecommons.si ali na Inˇstitutu za intelektualno lastnino, Streliˇska 1, 1000 Ljubljana.
Izvorna koda diplomskega dela, njeni rezultati in v ta namen razvita program- ska oprema je ponujena pod licenco GNU General Public License, razliˇcica 3 (ali novejˇsa). To pomeni, da se lahko prosto distribuira in/ali predeluje pod njenimi pogoji. Podrobnosti licence so dostopne na spletni strani http://www.gnu.org/
licenses/.
Besedilo je oblikovano z urejevalnikom besedil LATEX.
Kandidat: Klemen Jug
Naslov: Prenova spletne aplikacije VPT z uporabo tehnologije spletnih kom- ponent
Vrsta naloge: Diplomska naloga na univerzitetnem programu prve stopnje Raˇcunalniˇstvo in informatika
Mentor: izr. prof. dr. Matija Marolt Somentor: as. mag. ˇZiga Lesar Opis:
V diplomski nalogi razvijte sistem za serializacijo podatkov spletne aplikacije.
Sistem mora biti odporen na spremembe formata serializiranih podatkov in na spremembe aplikacije. S tehnologijo spletnih komponent postavite ogrodje za razvoj aplikacijskih gradnikov. Komponente morajo podpirati enostavno konfiguracijo lastnosti, ki jih je moˇc serializirati, ter samodejno preverjanje veljavnosti vhodnih podatkov pri branju glede na podano konfiguracijo. Sis- tem preizkusite na primeru spletne aplikacije za volumetriˇcno upodabljanje.
Title: Adapting the VPT web application with Web Components Description:
In this thesis, you shall develop a system for web application data serializa- tion. The system must be resistant to changes of the serialized data format and to application changes. Using Web Components technology, assemble a framework for the development of new application widgets. Components must support easy configuration of serializable properties and automatic va- lidation of input data according to the provided configuration. You shall test your system on the example volumetric path tracing application.
Na tem mestu bi se rad iskreno zahvalil somentorju as. mag. ˇZigi Lesarju in mentorju izr. prof. dr. Matiji Maroltu za pomoˇc pri pisanju diplome. Rad bi se zahvalil ˇse druˇzini, predvsem starˇsema in ˇzal ˇze pokojni babici, za vso podporo med ˇstudijem, ter prijateljem za druˇzbo in pomoˇc pri ˇstudiju.
Kazalo
Povzetek Abstract
1 Uvod 1
2 Pregled podroˇcja 3
2.1 Spletne komponente . . . 3 2.2 Serializacija . . . 4
3 Opis tehnologij 7
3.1 Spletne komponente . . . 7 3.2 Ogrodje za vizualizacijo volumetriˇcnih podatkov . . . 9 4 Izboljˇsava in poenostavitev gradnikov 17 4.1 Pretvorba prvotnih komponent in dialogov v spletne komponente 17 4.2 Registracija lastnosti in izdelava dialogov . . . 22 5 Serializacija in deserializacija podatkov 27 5.1 Shranjevanje stanja aplikacije . . . 27 5.2 Obnovitev stanja aplikacije in preverjanje veljavnosti vhodnih
podatkov . . . 31 5.3 Funkcije za preverjanje veljavnosti vhodnih podatkov . . . 33
6 Rezultati 35
7 Zakljuˇcek 39
Literatura 41
Seznam uporabljenih kratic
kratica angleˇsko slovensko
VPT volumetric path tracing volumetriˇcno sledenje poti HTML hypertext markup language oznaˇcevalni jezik za oblikova-
nje veˇcpredstavnostnih doku- mentov
CSS cascading style sheet prekrivni slogi
JSON JavaScript object notation format zapisa objektov v je- ziku JavaScript
DOM document object model objektni model dokumenta
Povzetek
Naslov: Prenova spletne aplikacije VPT z uporabo tehnologije spletnih kom- ponent
Avtor: Klemen Jug
V diplomski nalogi smo s pomoˇcjo tehnologije Web Components razvili nove komponente spletne aplikacije za volumetriˇcno upodabljanje (VPT). Kompo- nente podpirajo enostavno konfiguracijo lastnosti aplikacije. Poleg tega smo v okviru naloge razvili tudi sistem za serializacijo in deserializacijo podat- kov spletne aplikacije. Sistem je robusten – odporen na spremembe formata serializiranih podatkov in na spremembe aplikacije – in omogoˇca samodejno preverjanje veljavnosti vhodnih podatkov pri branju glede na podano konfi- guracijo. S temi spremembami je bistveno poenostavljeno programiranje in izdelovanje vizualnih komponent aplikacije, kar olajˇsa in pohitri dodajanje novih funkcionalnosti.
Kljuˇcne besede: serializacija, spletne aplikacije, Web Components, Java- Script, HTML, CSS, JSON, DOM, prilagodljivi elementi, skriti DOM.
Abstract
Title: Adapting the VPT web application with Web Components Author: Klemen Jug
In this thesis, we have developed new components for the volumetric path tracing (VPT) web application using Web Components technology. The components support simple configuration of application properties. Addi- tionally, we have developed a system for serialization and deserialization of web application data. The system is robust – resistant to changes in the format of the serialized data and to changes of the application itself – and supports automatic input data validation according to the provided configu- ration. With these changes, we have noticeably simplified the programming and creation of new visual elements for the application, which makes addition of new functionality easier and faster.
Keywords: serialization, web applications, Web Components, JavaScript, HTML, CSS, JSON, DOM, custom elements, shadow DOM.
Poglavje 1 Uvod
Razvoj spletnih aplikacij je kompleksen proces, pri katerem stremimo k ˇcim veˇcji uˇcinkovitosti. Dobra praksa pri tem procesu je ponovna uporaba kode, kot je na primer vkljuˇcitev ˇze razvitih komponent drugih razvijalcev v naˇso aplikacijo. Toda s tem imamo pogosto teˇzave. Ce v svojo spletno apli-ˇ kacijo vkljuˇcimo ˇze razvite komponente, v objektnem modelu dokumenta (DOM) nastanejo konflikti – identifikatorji in razredi HTML so skupni za celotno aplikacijo (globalno dosegljivi), zato lahko vkljuˇcene komponente ne- hote prevzamejo CSS sloge aplikacije ali huje, povzroˇcijo nepravilno delova- nje aplikacije, zato bi v takem primeru morali naˇso celotno kodo prilagoditi glede na vsako vkljuˇceno komponento ali obratno. Omenjene probleme lahko elegantno reˇsimo s spletnimi komponentami (angl. Web Components) [15].
Spletne komponente so sklop treh tehnologij (prilagodljivi elementi (angl. cu- stom elements), skriti DOM (angl. shadow DOM) in predloge HTML (angl.
HTML templates)), ki skupaj omogoˇcajo izdelavo prilagodljivih elementov za veˇckratno uporabo v spletnih aplikacijah in razvoj spletnih komponent, ki so loˇcene od preostale kode naˇse aplikacije – njihova vsebina je skrita v tako imenovanem skritem DOM, zato ne more priti do konfliktov med slogi CSS in identifikatorji ali razredi HTML. Tehnologijo spletnih komponent smo uporabili za izboljˇsavo in poenostavitev obstojeˇcih elementov aplikacije za volumetriˇcno sledenje poti (angl. Volumetric Path Tracing, VPT) [6].
1
2 Klemen Jug Ko razvijamo ali uporabljamo interaktivne aplikacije, imamo pogosto po- trebo po tem, da podatke ali stanje aplikacije shranimo in da jih lahko pozneje rekonstruiramo. Ta problem reˇsimo s serializacijo. V raˇcunalniˇstvu seriali- zacija pomeni postopek pretvorbe podatkovne strukture ali stanja objekta v obliko, ki jo je mogoˇce shraniti (na primer v datoteko) ali prenesti (na primer po raˇcunalniˇskem omreˇzju) in pozneje rekonstruirati (po moˇznosti v drugem raˇcunalniˇskem okolju). Ko se dobljeni niz bitov ponovno prebere v skladu z obliko serializacije, se lahko uporabi za ustvarjanje semantiˇcno enakega klona prvotnega objekta.
Izhodiˇsˇce za predlagano diplomsko temo je aplikacija za volumetriˇcno sle- denje poti (VPT), ki jo je za magistrsko nalogo razvil as. mag. ˇZiga Lesar.
Aplikacija s pomoˇcjo tehnologije WebGL 2.0 reˇsuje problem prikaza volume- triˇcnih podatkov na naˇcin, ki je neodvisen od platforme. Spletna aplikacija je bila sprva napisana v jeziku ECMAScript ES5 in brez sodobnih spletnih teh- nologij, zato je prednji del aplikacije razmeroma nestrukturiran. Diplomska naloga nadgrajuje omenjeno aplikacijo s sodobnimi spletnimi tehnologijami (predvsem zbirko tehnologij za izdelavo spletnih komponent), serializacijo in validacijo, tako da je razˇsirjanje aplikacije in dodajanje novih funkcionalnosti enostavnejˇse in hitrejˇse.
Cilji te diplomske naloge so sledeˇci:
• pretvoriti vizualne gradnike aplikacije v spletne komponente,
• razviti robusten sistem za serializacijo in deserializacijo lastnosti apli- kacije in
• omogoˇciti samodejno preverjanje pravilnosti vhodnih podatkov ob de- serializaciji.
Poglavje 2
Pregled podroˇ cja
2.1 Spletne komponente
Spletne komponente so dandanes popularna tehnologija, ki se veliko upora- blja. Prvi zaˇcetki spletnim komponentam podobnih tehnologij segajo ˇze v leto 2002. Takrat sta se Jian Yang in Mike P. Papazoglou ˇzelela spopasti s problemi, ki jih danes reˇsujemo s spletnimi komponentami, in v ta namen opisala in razvila sklop tehnologij, ki sta jih prav tako poimenovala spletne komponente [16].
Leta 2015 je izˇsla knjiga o razvoju spletnih komponent s sklopom tehno- logij Web Components [11]. Istega leta sta Michael Krug in Martin Gaedke v svoji raziskavi [5] nadgradila spletne komponente s komunikacijskimi kanali na podlagi dogodkov in moˇznostjo izmenjevanja podatkov med napravami.
Leta 2019 je Michael Herzberg v svoji doktorski nalogi [1] analiziral var- nost spletnih komponent z metodo dokazovanja pravilnosti programa. Odkril je nekaj teˇzav, na podlagi rezultatov razvil nekaj izboljˇsav varnosti in pre- dlagal reˇsitve za izboljˇsavo standarda.
Z razvojem spletnih komponent so se ukvarjale ˇse sledeˇce raziskave [9, 12, 3], a z zelo specifiˇcnimi primeri uporabe, zato za nas niso tako pomembne.
3
4 Klemen Jug
2.2 Serializacija
Leta 2012 je Kazuaki Maeda v svoji raziskavi [7] primerjal 12 razliˇcnih knjiˇznic za serializacijo objektov, ki temeljijo na XML, JSON in binarnih formatih. Izmeril je velikost serializirane datoteke in ˇcas, potreben za seriali- zacijo in deserializacijo. Ugotovil je, da so binarno zapisani podatki ˇcasovno uˇcinkovitejˇsi in da zasedejo manj prostora od tekstovnih XML ali JSON.
Kot najhitrejˇsi in prostorsko najuˇcinkovitejˇsi knjiˇznici sta se izkazali Apache Avro in Protocol Buffers, ki uporabljata binaren zapis podatkov. Nekatere knjiˇznice so se izkazale za malce slabˇse, vendar nobena ni bila bistveno boljˇsa od drugih; vse ustrezajo specifiˇcnemu primeru uporabe, za katerega so bile razvite.
Leta 2012 sta Audie Sumaray in S. Kami Makki [13] v svoji raziskavi primerjala ˇstiri formate za serializacijo na mobilnih platformah. Ugotovila sta, da je format XML v vseh pogledih slabˇsi od ostalih: je najpoˇcasnejˇsi in porabi najveˇc prostora. Priporoˇcata, da se ga izogibamo, in raje uporabljamo format JSON, ki ohranja glavne prednosti formata XML, kot je na primer ˇcloveˇska berljivost, pri ˇcemer je mnogo hitrejˇsi in prostorsko uˇcinkovitejˇsi.
Binarna formata, ki sta ju prav tako primerjala (Thrift in Protocol Buffers), sta se izkazala za ˇse hitrejˇsa in prostorsko uˇcinkovitejˇsa, vendar manj pri- lagodljiva. Zaradi tega avtorja pri naˇcrtovanju novih spletnih storitev in za shranjevanje velike koliˇcine podatkov priporoˇcata binarna formata, med- tem ko uporabo formata JSON zaradi njegove prilagodljivosti priporoˇcata za uporabo v ˇze obstojeˇcih spletnih storitvah.
Leta 2014 je Valentin Kragelj v svoji diplomski nalogi [4] pregledal in analiziral veˇc razliˇcnih tehnologij za serializacijo. Medsebojno je primerjal nekaj najpopularnejˇsih formatov: binarne formate ASN.1, BSON, Message- Pack, Protocol Buffers, Smile, Bencode in serializacijo v Javi ter tekstovne formate JSON, XML in YAML. Kodo za testiranje je napisal v programskem jeziku Java. V svojih testih je meril tri lastnosti: hitrost serializacije tabele nizov in tabele ˇstevil, hitrost deserializacije tabele nizov in tabele ˇstevil ter velikost serializiranih podatkov. Ugotovil je, da je pri serializaciji najhitrejˇsi
Diplomska naloga 5 format JSON, pri deserializaciji pa Bencode. Kar se tiˇce velikosti seriali- ziranih podatkov je najuˇcinkovitejˇsi MessagePack. Avtor je priˇcakoval, da bodo tekstovni, ˇcloveˇsko berljivi formati, v vseh pogledih slabˇsi od binarnih - da bodo potrebovali veˇc ˇcasa za serializacijo in deserializacijo, prav tako pa porabili veˇc prostora. Ta domneva se je izkazala za pravilno pri formatih XML in YAML, presenetil pa ga je JSON, ki je v hitrosti serializacije celo zmagal. Ko je med seboj podrobneje primerjal tekstovne formate, je ugoto- vil, da je XML boljˇsi pri nestrukturiranih podatkih, JSON in YAML pa pri strukturiranih, pri ˇcemer je YAML za branje razumljivejˇsi.
S problemom serializacije in deserializacije se ukvarjajo ˇse sledeˇce razi- skave [10, 8, 14, 2], vendar se osredotoˇcajo na druge programske jezike ali specifiˇcne primere uporabe in ne neposredno na jezik JavaScript ali spletne tehnologije, zato so za nas manj relevantne.
Po pregledu podroˇcja teme serializacije smo izvedeli, da je v sploˇsnem pri izbiri formata kljuˇcno vpraˇsanje, ali ˇzelimo, da je format ˇcloveˇsko berljiv; v primeru, da ni potrebe po tem, so binarni formati naˇceloma uˇcinkovitejˇsa reˇsitev. Za potrebe naˇse aplikacije smo ˇzeleli tekstovni, ˇcloveˇsko berljiv for- mat. Veˇcina virov je razglasila format JSON za najboljˇsi tekstovni format, zato smo se odloˇcili, da ga bomo uporabili tudi mi. To je bila za nas do- bra novica, ker je format JSON privzet format jezika JavaScript, v katerem je aplikacija napisana. ˇCe bi uporabili katerikoli drug format, bi morali v naˇso aplikacijo vkljuˇciti njegove knjiˇznice, s ˇcimer bi poveˇcali zapletenost aplikacije, tako pa tega ni bilo treba.
6 Klemen Jug
Poglavje 3
Opis tehnologij
3.1 Spletne komponente
Spletne komponente so sklop treh tehnologij:
• prilagodljivi elementi (angl. custom elements),
• skriti DOM (angl. shadow DOM) in
• predloge HTML (angl. HTML templates).
3.1.1 Prilagodljivi elementi
Prilagodljivi elementi (angl. custom elements) razvijalcem omogoˇcajo, da definirajo nove elemente HTML in jim doloˇcijo znaˇcko HTML, s katero jih lahko enostavno vkljuˇcijo v svoje spletne strani na enak naˇcin kakor navadne elemente HTML. Nove prilagodljive elemente je treba registrirati s funkcijo define, ki se nahaja na objektuwindow.customElements. Primer za drsnik:
window.customElements.define(’vpt-slider’, Slider);
Funkcija potrebuje dva argumenta: prvi je ime znaˇcke HTML, pod katero ˇzelimo registrirati naˇs element (ime znaˇcke prilagodljivega elementa mora nujno vsebovati vezaj), drugi pa ime razreda, v katerem so definirane njegove
7
8 Klemen Jug funkcionalnosti. Ta razred mora razˇsirjati razred HTMLElement – to je nadrazred vseh elementov HTML, tako privzetih kot prilagodljivih.
3.1.2 Skriti DOM
Skriti DOM (angl. shadow DOM) omogoˇca loˇcitev DOM prila- godljivega elementa od DOM preostalega dela aplikacije, tako da document.querySelector in podobne funkcije ne morejo dostopati do njegovih podelementov. Tako se izognemo stilskim in funkcionalnim konfliktom, ki bi lahko nastali, ˇce bi uporabljali iste identifikatorje in razrede HTML tako v naˇsi aplikaciji kot tudi v prilagodljivem elementu. Z drugimi besedami: ni treba paziti na to, da v aplikaciji in prilagodljivem elementu ne uporabljamo istih identifikatorjev in razredov HTML, kar olajˇsa programiranje in zmanjˇsa zapletenost kode. Skriti DOM vzpostavimo s funkcijo attachShadow:
this.attachShadow({mode: ’open’}).appendChild(template);
V naˇsem primeru jo kliˇcemo v razredih komponent – nanje se nanaˇsa beseda this. Atribut mode doloˇca, ali lahko od zunaj dostopamo do skritega korena elementa (angl. shadowRoot), pod katerim se skrivajo njegovi podelementi HTML. S funkcijo appendChild v isti vrstici na DOM skritega korena pri- pnemo fragment dokumenta1 (angl. document fragment) z omenjenimi pod- elementi, ki doloˇcajo vsebino naˇse spletne komponente. V naˇsem primeru jih podamo v spremenljivki template.
3.1.3 Predloge HTML
Predloga HTML (angl. HTML template) je znaˇcka, ki na spletni strani ni prikazana in je namenjena kloniranju elementov z namenom izogibanja vsa-
1Fragment dokumenta je element DOM, ki shranjuje drug dokument. Uporabljamo ga za segregacijo razliˇcnih dokumentov za namene izolacije imenskih prostorov in operacij iskanja ali spreminjanja dokumenta. Ker ga brskalnik ne prikaˇze, ko ga ustvarimo, ne vpliva na izgled spletne strani, dokler ga ne pripnemo nanjo.
Diplomska naloga 9 kokratnemu ponovnemu razˇclenjevanju. ˇCe ˇzelimo prikazati njeno vsebino, moramo to storiti programsko, tako da jo kloniramo in pripnemo nekemu prikazanemu elementu.
Naˇsa aplikacija je prvotno ˇze omogoˇcala podobno funkcionalnost na drug naˇcin: vsaka komponenta je bila definirana posebej, v svoji datoteki HTML, ustvarili pa smo jih s funkcijamaDOMUtils.instantiatealiUI.create(opi- sani bosta v nadaljevanju). Ta pristop zaradi vsakokratnega ponovnega razˇclenjevanja ni najprimernejˇsi, ampak ˇse zdaleˇc ni ozko grlo vmesnika in nikakor ne vpliva na strukturo aplikacije, zato smo se odloˇcili, da bomo ta naˇcin uporabljali ˇse naprej, namesto predlog HTML.
3.2 Ogrodje za vizualizacijo volumetriˇ cnih podatkov
Glavni trije objekti aplikacije VPT, ki vplivajo na prikaz volumetriˇcnih po- datkov, so upodabljalnik (angl. renderer), tonski slikar (angl. tone mapper) in kontekst upodabljanja (angl. rendering context). Objekt za kontekst upo- dabljanja je le eden in zato vedno isti, medtem ko imamo za upodabljalnik in tonski slikar veˇc moˇznosti, ki jih lahko menjamo. Ob vsaki menjavi kreiramo nov objekt za upodabljalnik ali tonski slikar in starega uniˇcimo. Vsak izmed teh objektov ima doloˇcene nastavitve za prikaz, ki jih lahko spreminjamo preko uporabniˇskega vmesnika.
Jedro aplikacije je razred Application – to je glavni razred, kjer se vzpo- stavi zaˇcetno stanje aplikacije in kjer se vsi njeni deli poveˇzejo med sabo. V konstruktorju tega razreda je definirana lastnost showSettings, ki doloˇca, ali naj aplikacija prikazuje uporabniˇski vmesnik za upodabljalnik, tonski sli- kar in kontekst upodabljanja. Aplikacijo je namreˇc mogoˇce uporabljati tudi brez uporabniˇskega vmesnika, vendar v tem primeru ne moremo spreminjati njenih nastavitev.
Vizualne elemente aplikacije VPT lahko razdelimo na dve kategoriji: sa- mostojne komponente in dialoge, ki so lahko sestavljeni iz veˇc razliˇcnih kom-
10 Klemen Jug ponent ali drugih dialogov.
Komponenta Izgled Accordion
(skrˇcen in razˇsirjen) Button Checkbox ColorChooser Dropdown Field
FileChooser Panel
ProgressBar Radio
Sidebar (skrˇcen in razˇsirjen)
Slider Spinner Tabs Textbox
Diplomska naloga 11 Komponenta Izgled
VectorSpinner
Transfer Function
Tabela 3.1: Seznam vseh komponent aplikacije in njihov izgled.
Vse komponente so definirane v svojem razredu, kjer je opisano njihovo delovanje. Vsak od teh razredov razˇsirja razred UIObject, ki poskrbi za pravilno instanciranje in inicializacijo komponent ter vsebuje funkcije, ki so skupne vsem komponentam (slika 3.1).
Komponente so sestavljene iz osnovnih gradnikov HTML. Njihova sestava je zato definirana v datotekah HTML. Spodaj je kot primer podana prvotna sestava komponente drsnik (angl. slider). <div> element z razredom button oznaˇcuje gumb, ki ga lahko premikamo, tisti z razredom track pa oznaˇcuje stezo, po kateri premikamo gumb:
1 <div c l a s s=" i n s t a n t i a t e s l i d e r ">
2 <div c l a s s=" c o n t a i n e r " data- b i n d =" c o n t a i n e r ">
12 Klemen Jug
Slika 3.1: Razredni diagram komponent.
3 <div c l a s s=" t r a c k "> < /div>
4 <div c l a s s=" b u t t o n " data- b i n d =" b u t t o n "> < /div>
5 < /div>
6 < /div>
Dialogi v aplikaciji VPT so vizualni elementi, sestavljeni iz veˇc kompo- nent. Razred vsakega dialoga razˇsirja razred AbstractDialog, ki poskrbi za pravilno instanciranje in inicializacijo dialoga, ter vsebuje funkcije, ki so sku- pne vsem dialogom. V prvotni razliˇcici aplikacije smo imeli 2 tipa dialogov:
samostojne in dopolnilne. Samostojni so bili glavni dialog, ki doloˇca vizu- alno obliko spletne strani aplikacije, dialog za nalaganje volumna in dialog za nalaganje slike okolja. Ti dialogi niso dopolnitev nobenega drugega razreda, zato lahko obstajajo samostojno (vidno na sliki 3.2). Po drugi strani so bili razredi dopolnilnih dialogov zgolj dopolnitev razredov upodabljalnikov, ton- skih slikarjev ali konteksta upodabljanja, da smo lahko spreminjali njihove lastnosti, in zato niso mogli obstajati samostojno (vidno na sliki 3.3). Ne glede na to, ali je ˇslo za samostojni ali dopolnilni dialog, smo jih v prvo- tni razliˇcici aplikacije VPT ustvarjali na enak naˇcin. Struktura vseh je bila opisana v JSON datotekah. Program je prebral datoteko JSON, na podlagi
Diplomska naloga 13 katere je instanciral potrebne komponente in jim nastavil podane atribute, iz njih zgradil konˇcni objekt dialoga in ga pripel v DOM spletne strani.
Slika 3.2: Prvotni razredni diagram samostojnih dialogov.
Spodaj sta kot primer dopolnilnega dialoga podana datoteka JSON in izgled (slika 3.4) dialoga za tonski slikar “range”. Gre za dialog, sestavljen iz zgolj petih komponent. Atribut type doloˇca tip komponente. V naˇsem primeru imamo komponento panela, ki vsebuje dve polji (angl. field), katerih atribut label doloˇca besedilo polja. Vsako polje vsebuje komponento tipa spinner, ki ima doloˇcenih nekaj atributov (logarithmic,value,mininstep):
1 {
2 " t y p e ": " p a n e l " , 3 " c h i l d r e n ": [
4 {
5 " t y p e ": " f i e l d " , 6 " l a b e l ": " Low :" , 7 " c h i l d r e n ": [
8 {
9 " t y p e ": " s p i n n e r " , 10 " b i n d ": " low " ,
11 " l o g a r i t h m i c ": true ,
12 " v a l u e ": 0 ,
14 Klemen Jug
Slika 3.3: Prvotni diagram dopolnilnih dialogov v povezavi z razredom, ki ga dopolnjujejo. V tem primeru gre za kontekst upodabljanja.
13 " min ": 0 ,
14 " s t e p ": 0.1
15 }
16 ]
17 } ,
18 {
19 " t y p e ": " f i e l d " , 20 " l a b e l ": " H i g h :" , 21 " c h i l d r e n ": [
22 {
23 " t y p e ": " s p i n n e r " , 24 " b i n d ": " h i g h " , 25 " l o g a r i t h m i c ": true ,
26 " v a l u e ": 1 ,
27 " min ": 0 ,
28 " s t e p ": 0.1
29 }
30 ]
31 }
32 ] 33 }
Diplomska naloga 15
Slika 3.4: Prikaz dialoga tonskega slikarja “range”.
Spodaj je kot primer samostojnega dialoga podan del prvotne razliˇcice dialoga za nalaganje slike okolja (angl. environment map). Primer prikazuje prve tri komponente tega dialoga: panelo, ki vsebuje eno polje, ki vsebuje spustni meni (angl. dropdown) z njegovimi moˇznostmi:
1 {
2 " t y p e ": " p a n e l " , 3 " c h i l d r e n ": [
4 {
5 " t y p e ": " f i e l d " , 6 " l a b e l ": " T y p e :" , 7 " c h i l d r e n ": [
8 {
9 " t y p e ": " d r o p d o w n " , 10 " b i n d ": " t y p e " ,
11 " o p t i o n s ": [
12 {
13 " v a l u e ": " f i l e " , 14 " l a b e l ": " F i l e " ,
15 " s e l e c t e d ": t r u e
16 } ,
17 {
18 " v a l u e ": " url " , 19 " l a b e l ": " URL "
20 } ,
21 {
22 " v a l u e ": " d e m o " , 23 " l a b e l ": " D e m o "
24 }
25 ...
Ta dva primera dialogov v prvotni razliˇcici aplikacije izgledata podobno in se ustvarita na povsem enak naˇcin. V diplomski nalogi smo se ustvarjanja
16 Klemen Jug samostojnega in dopolnilnega dialoga lotili na razliˇcna naˇcina. Kako, bomo razloˇzili v naslednjem poglavju.
Poglavje 4
Izboljˇ sava in poenostavitev gradnikov
4.1 Pretvorba prvotnih komponent in dialo- gov v spletne komponente
Ker so bile komponente ˇze sestavljene iz elementov HTML, dialogi pa iz veˇc komponent, je bilo smiselno, da najprej pretvorimo komponente. Ker vsak razred komponente razˇsirja razred UIObject, je bilo najbolj logiˇcno, da se tudi naˇse spletne komponente inicializirajo v tem razredu. Poskrbeli smo, da razred UIObject razˇsirja razred HTMLElement in dodali potrebno kodo, da se komponente skrijejo v skriti DOM:
1 t h i s. _ e l e m e n t = D O M U t i l s . i n s t a n t i a t e ( t e m p l a t e ) ;
2 c o n s t s h a d o w R o o t = t h i s. a t t a c h S h a d o w ({ m o d e : ’ o p e n ’}) . a p p e n d C h i l d (t h i s. _ e l e m e n t ) ;
Pomagala nam je metodainstantiaterazreda DOMUtils, ki je del prvotne aplikacije. Ta metoda prebere niz znakov, formatiran v jeziku HTML, in ga razˇcleni v fragment dokumenta, ki ga lahko uporabimo namesto znaˇcke HTML<template>. Spremenljivka template v tem primeru predstavlja ome- njeni niz znakov, ki smo ga podali v prvotnem razredu komponente, ko smo klicali konstruktor nadrazreda. Metoda DOMUtils.instantiatese je na is-
17
18 Klemen Jug tem mestu uporabljala ˇze v prvotni razliˇcici aplikacije, zato je bilo treba samo dodati kodo za vzpostavitev skritega DOM in skritega korena.
Lastnosti komponent se ob zagonu aplikacije nastavijo preko atributov HTML. Dobra praksa je, da so atributi in lastnosti sinhronizirani med sabo, saj bi uporabnik komponent lahko nastavil doloˇceno lastnost komponente in priˇcakoval, da bo kasneje dobil isto vrednost, ko bo skuˇsal prebrati istoimen- ski atribut z metodo getAttribute, ali obratno. Pri tem pomaga funkcija attributeChangedCallback razreda HTMLElement, ki se samodejno kliˇce ob ustvarjanju komponente, in vedno, ko se spremeni vrednost katerega iz- med atributov, definiranih v funkciji observedAttributes. Primer kode iz razreda za zgibni meni (angl. accordion):
1 s t a t i c get o b s e r v e d A t t r i b u t e s () { 2 r e t u r n [’ l a b e l ’, ’ c o n t r a c t e d ’];
3 } 4
5 a t t r i b u t e C h a n g e d C a l l b a c k ( name , o l d V a l u e , n e w V a l u e ) { 6 s w i t c h ( n a m e ) {
7 // g l e d e na ime a t r i b u t a o d r e a g i r a j na n j e g o v o n o v o v r e d n o s t
8 ...
9 }
10 } 11
12 get l a b e l () {
13 r e t u r n t h i s. g e t A t t r i b u t e (’ l a b e l ’) ; 14 }
15
16 set l a b e l ( v a l u e ) {
17 t h i s. s e t A t t r i b u t e (’ l a b e l ’, v a l u e ) ; 18 }
Kot lahko vidimo, komponenta opazuje dva atributa (label in contracted).
Ko se kateri od njiju spremeni, pokliˇce funkcijoattributeChangedCallback, kjer na podlagi imena atributa odreagiramo na njegovo novo vrednost. Pri tem pomagata ˇse dekoratorja get in set, ki ju definiramo za opa-
Diplomska naloga 19 zovane atribute. Dekoratorja omogoˇcata delo z objektom na enak naˇcin, kot bi dostopali do spremenljivke. Za primer sta podana za atribut label: get label vsakokrat, ko ˇzelimo dostopati do lastnosti komponente na naˇcin component.label, vrne vrednost atributa label, set label(value) pa vsakokrat, ko ˇzelimo nastaviti lastnost kompo- nente na naˇcin component.label = value, poskrbi, da se atribut te komponente nastavi na novo vrednost (tu se avtomatsko kliˇce funkcija attributeChangedCallback). Tako komponenta v resnici sploh nima lastnosti component.label, ampak se vrednost prebere in nastavi nepo- sredno iz atributa, zato sploh ni moˇznosti, da bi lastnost in atribut imela neskladno vrednost. V sploˇsnem smo morali v vse razrede komponent dodati metodi get observedAttributes in attributeChangedCallback ter za vse atribute, ki so za nas pomembni, ˇse getter in setter metodi.
Pri komponentah je bilo treba popraviti tudi njihove stilske datoteke.
Stili CSS so za vsako komponento definirani v svoji datoteki, vendar smo jih v prvotni razliˇcici aplikacije med procesom gradnje zdruˇzili v eno samo veliko datoteko CSS, z namenom zmanjˇsanja ˇstevila zahtev na streˇznik.
Ker skriti DOM loˇci DOM posamezne komponente od preostanka aplikacije, so poslediˇcno loˇceni tudi stili komponent, zato ta reˇsitev ni bila veˇc opti- malna, saj bi morali to veliko datoteko vkljuˇciti v HTML vsake komponente.
Odloˇcili smo se, da bomo vsebino stilskih datotek med procesom gradnje na- mesto v eno samo datoteko CSS zdruˇzili v datoteko tipa JSON. Tako smo omogoˇcili, da so stili posameznih komponent loˇceni med sabo, ob tem pa ohranili moˇznost, da vse stile za celotno aplikacijo pridobimo v eni sami zah- tevi. Vsebino te datoteke JSON si shranimo v globalni objekt STYLES, do katerega lahko dostopamo v posameznih razredih komponent. Tam ob klicu konstruktorja nadrazreda (UIObject) podamo ime lastnosti, ki vsebuje stile za to komponento, v oblikiSTYLES.ui.ImeKomponente. V razredu UIObject nato na podlagi vsebine te lastnosti ustvarimo element HTML <style> in ga pripnemo v skriti koren komponente.
Tista stilska pravila, ki so skupna vsem komponentam (npr. druˇzina, veli-
20 Klemen Jug kost in barva pisave), so bila prvotno definirana v posebni datoteki main.css, ki smo jo vkljuˇcili v<head> datoteke index.html. Zaradi izolacije stilov kom- ponent od preostanka aplikacije, ki je posledica uvedbe skritega DOM, v komponentah ta skupna pravila niso veˇc veljala. Zato smo morali v datoteki main.css za skupna pravila definirati prilagodljive lastnosti (angl. custom properties) in jih potem s CSS funkcijovarvkljuˇciti v stilske datoteke posa- meznih komponent. Ker je bila, tako kot vsebina stilskih datotek komponent, tudi vsebina main.css zdaj del ene same datoteke JSON, smo ta del morali programsko vkljuˇciti v glavo dokumenta, na podoben naˇcin, kot smo v po- samezne komponente vkljuˇcili vsebino njihovih stilskih datotek.
1 : r o o t {
2 - - font - f a m i l y : sans - s e r i f ;
3 - - font - s i z e : 12 px ;
4 - - c o l o r : # 3 3 3 ;
5 - - input - a p p e a r a n c e : n o n e ;
6 - - i n v i s i b l e - d i s p l a y : n o n e ! i m p o r t a n t ; 7 }
Koda 4.1: Definicija prilagodljivih lastnosti v main.css.
1 * {
2 font - f a m i l y : var ( - - font - f a m i l y ) ; 3 font - s i z e : var ( - - font - s i z e ) ; 4 c o l o r : var ( - - c o l o r ) ;
5 } 6
7 i n p u t {
8 a p p e a r a n c e : var ( - - input - a p p e a r a n c e ) ;
9 - webkit - a p p e a r a n c e : var ( - - input - a p p e a r a n c e ) ; 10 - moz - a p p e a r a n c e : var ( - - input - a p p e a r a n c e ) ; 11 }
12
13 . i n v i s i b l e {
14 d i s p l a y : var ( - - i n v i s i b l e - d i s p l a y ) ; 15 }
Koda 4.2: Vkljuˇcitev skupnih pravil v CSS vsake komponente.
Diplomska naloga 21 Pretvorba dialogov v spletne komponente je bila nekoliko kompleksnejˇsa.
Odloˇcili smo se, da bomo dopolnilne dialoge ustvarili na bolj sploˇsen in na- prednejˇsi naˇcin, ki bo opisan v podpoglavju 4.2. Zato smo se najprej lotili pretvorb samostojnih dialogov, torej glavnega dialoga, dialoga za nalaganje volumna in dialoga za nalaganje slike okolja.
Ker smo komponente lahko zdaj instancirali kar z znaˇckami HTML, ob- stoj posebnega razreda in datoteke JSON z opisom komponent glavnega di- aloga ni bil veˇc smiseln, zato smo kodo iz razreda glavnega dialoga vkljuˇcili kar v razred Application. Opis komponent glavnega dialoga smo pretvorili iz formata JSON v HTML in ga vkljuˇcili v <body> datoteke index.html – to je glavna HTML datoteka aplikacije. Tako sta ostala zgolj dialog za na- laganje volumna in dialog za nalaganje slike okolja. Oba razˇsirjata razred AbstractDialog. Prvotno je bila v konstruktorju tega razreda sledeˇca koda:
1 c o n s t c r e a t i o n = UI . c r e a t e ( J S O N . p a r s e ( s p e c ) ) ; 2 t h i s. _ o b j e c t = c r e a t i o n . o b j e c t ;
Koda je uporabljala ˇze obstojeˇco funkcijo UI.create, ki je prebrala niz znakov, ki smo ga prej s funkcijo JSON.parse pretvorili v format JSON, iz njega sestavila delujoˇc DOM objekt (podobno kot je to funkcija DOMUtils.instantiatestorila za niz znakov HTML) in obenem poskrbela, da so se instanciranim podelementom DOM objekta tudi nastavili podani atributi. Na koncu je vrnila konˇcni objekt dialoga, ki smo ga shranili v this._object in ga je bilo potem mogoˇce pripeti v DOM spletne strani.
Spremenljivka spec je bila v tem primeru omenjeni niz znakov, ki smo ga podali v prvotnem razredu dialoga, ko smo klicali konstruktor nadrazreda.
Ker so bile posamezne komponente, ki sestavljajo dialoge, zdaj pretvor- jene v spletne komponente, funkcija UI.create ni veˇc delovala. Zato smo morali, tako kot pri glavnem dialogu, definicijo dialoga pretvoriti iz zapisa JSON v HTML. Kot primer je spodaj podan del datoteke HTML dialoga za nalaganje slike okolja (angl. environment map) po pretvorbi:
1 <div c l a s s=" i n s t a n t i a t e envmap - load - d i a l o g ">
2 < vpt - p a n e l >
22 Klemen Jug
3 < vpt - f i e l d l a b e l=" T y p e : ">
4 < vpt - d r o p d o w n id=" type - d r o p d o w n ">
5 <o p t i o n v a l u e=" f i l e " s e l e c t e d> F i l e < /o p t i o n>
6 <o p t i o n v a l u e=" url "> URL < /o p t i o n>
7 <o p t i o n v a l u e=" d e m o "> D e m o < /o p t i o n>
8 < / vpt - d r o p d o w n >
9 < / vpt - f i e l d >
10 ...
V tej datoteki lahko ˇze opazimo znaˇcke HTML naˇsih prilagodljivih spletnih komponent, ki smo jih uporabili v tem dialogu (vpt-panel, vpt-field, vpt- dropdown ...). Ko je bila pretvorba dialogov v HTML konˇcana, smo jih lahko inicializirali na isti naˇcin kot posamezne komponente – s funkcijama DOMUtils.instantiatein attachShadow:
1 t h i s. _ e l e m e n t = D O M U t i l s . i n s t a n t i a t e ( s p e c ) ;
2 c o n s t s h a d o w R o o t = t h i s. a t t a c h S h a d o w ({ m o d e : ’ o p e n ’}) . a p p e n d C h i l d (t h i s. _ e l e m e n t ) ;
Spremenljivko spec smo v konstruktorju podrazreda posameznega dialoga spremenili iz prvotnega niza znakov v formatu JSON v novi niz znakov z vsebino HTML.
Na koncu je bilo treba definirati vse komponente in dialoge s funkcijo window.customElements.define. To smo storili v konstruktorju razreda Application.
4.2 Registracija lastnosti in izdelava dialogov
Kot smo zapisali v prejˇsnjem poglavju, smo se odloˇcili, da bomo dopolnilne dialoge, namesto da bi jih pretvorili iz JSON v HTML, kot smo to storili pri samostojnih, ustvarjali na drugaˇcen naˇcin. ˇCe smo v prvotni razliˇcici aplikacije ˇzeleli v nek dialog, recimo dialog upodabljalnika, dodati novo kom- ponento, smo jo morali najprej dodati v datotetko JSON, ki je opisovala dialog upodabljalnika, nato v razredu dialoga upodabljalnika poskrbeti za posluˇsalca dogodkov za novo komponento in na koncu dodati novo funkci-
Diplomska naloga 23 onalnost ˇse v glavni razred upodabljalnika. Ta postopek smo ˇzeleli poeno- staviti in posploˇsiti instanciranje komponent dialogov, da bi bilo vse v enem razredu in ne bi bilo treba spreminjati treh datotek, ko bi dodali novo kom- ponento. Zato smo se znebili vseh datotek JSON in razredov dopolnilnih dialogov (vidno na sliki 4.1). Kodo iz razredov dialogov upodabljalnikov, dialogov tonskih slikarjev in dialoga konteksta upodabljanja smo prestavili v njihove glavne razrede.
Slika 4.1: Znebili smo se veˇcine razredov dialogov in datotek JSON. Primer za kontekst upodabljanja.
V vse razrede upodabljalnikov, tonskih slikarjev in konteksta upodablja- nja smo dodali funkcijo registerSettings. V tej funkciji definiramo vse lastnosti, ki jim ˇzelimo ustvariti komponento in jih serializirati. Doloˇcimo jim ime, tip komponente, oznako in atribute, kot so na primer zaˇcetna, naj- manjˇsa in najveˇcja dovoljena vrednost, podobno kot smo to prvotno storili v posebni datoteki JSON. Primer iz razreda za tonski slikar “range”:
1 r e g i s t e r S e t t i n g s () { 2 t h i s. s e t t i n g s . low = {
3 n a m e : ’ low ’,
4 t y p e : ’ s p i n n e r ’,
5 l a b e l : ’ Low : ’,
24 Klemen Jug
6 a t t r i b u t e s : {
7 l o g a r i t h m i c : true,
8 v a l u e : 0 ,
9 min : 0 ,
10 s t e p : 0.1
11 }
12 }
13 t h i s. s e t t i n g s . h i g h = {
14 n a m e : ’ h i g h ’,
15 t y p e : ’ s p i n n e r ’,
16 l a b e l : ’ H i g h : ’,
17 a t t r i b u t e s : {
18 l o g a r i t h m i c : true,
19 v a l u e : 1 ,
20 min : 0 ,
21 s t e p : 0.1
22 }
23 }
24 }
Kot lahko vidimo, v lastnostthis.settings, ki je pred tem prazen objekt, v tem primeru dodamo dva nova objekta, ki opisujeta vsak svojo komponento.
V prvotni razliˇcici aplikacije smo imeli dve razliˇcni mnoˇzici zaˇcetnih vre- dnosti za lastnosti upodabljalnikov, tonskih slikarjev in konteksta upoda- bljanja. Prvo mnoˇzico smo uporabili, da smo ob zagonu aplikacije v kon- struktorjih teh objektov neposredno nastavili lastnosti njihovih programov za prikazovanje. Druga mnoˇzica je bila definirana v datotekah JSON dialo- gov teh objektov in se je uporabljala za zaˇcetne vrednosti elementov upo- rabiˇskega vmesnika. Prviˇc, ko smo spremenili vrednost nekemu elementu uporabniˇskega vmesnika, je to zaznal glavni razred objekta in posodobil pri- padajoˇco lastnost svojega programa za prikazovanje. Tako je lahko priˇslo do neskladij med vrednostmi iz obeh mnoˇzic, kar je slabo iz dveh razlogov:
uporabniˇski vmesnik bi v tem primeru prikazoval napaˇcne vrednosti in v primeru velikih odstopanj bi ob prvi minimalni spremembi lastnosti preko uporabniˇskega vmesnika priˇslo do ogromne razlike v prikazu objekta. Na
Diplomska naloga 25 primer, ˇce bi nastavili zaˇcetno vrednost neke lastnosti v konstruktorju upo- dabljalnika na 1, zaˇcetno vrednost elementa dialoga, s katerim spreminjamo to vrednost, pa na 100, bi ob zagonu aplikacije program upodabljalnika upo- rabljal vrednost 1. Ko bi preko uporabniˇskega vmesnika zgolj za 1 poveˇcali vrednost lastnosti, bi opazili ogromen preskok v prikazu objekta, saj bi se vrednost lastnosti programa upodabljalnika spremenila iz 1 na 101.
Ker smo imeli zdaj vse zaˇcetne vrednosti definirane v funkciji registerSettings, smo se znebili neposrednega nastavljanja v kon- struktorju in ga nadomestili z metodo initDefaults, ki jo prav tako kliˇcemo v konstruktorju razreda, takoj za funkcijo registerSettings. V tej metodi nastavimo zaˇcetne vrednosti lastnosti upodabljalnikov, tonskih slikarjev in konteksta upodabljanja na tiste, definirane v registriranih nasta- vitvah. Tako smo zagotovili, da se v obeh primerih uporablja ista mnoˇzica zaˇcetnih vrednosti in se na ta naˇcin izognili zgoraj opisanim teˇzavam.
Za ustvarjanje dialogov se ob zagonu aplikacije in vsakokrat, ko zame- njamo upodabljalnik ali tonski slikar, kliˇce funkcija makeDialog, definirana v razredu Application:
1 _ m a k e D i a l o g ( which , s e t t i n g s ) {
2 let d i a l o g P a n e l = d o c u m e n t . q u e r y S e l e c t o r (’ # attach - ’ + w h i c h ) ;
3 for (c o n s t key in s e t t i n g s ) { 4 let s e t t i n g = s e t t i n g s [ key ];
5 let n e w E l e m e n t = d o c u m e n t . c r e a t e E l e m e n t (’ vpt - ’ + s e t t i n g . t y p e ) ;
6 if ( s e t t i n g . t y p e === ’ t r a n s f e r - f u n c t i o n - w i d g e t ’) { 7 // p o s e b e n p r i m e r za g r a d n i k p r e n o s n e f u n k c i j e
8 ...
9 } e l s e {
10 for (c o n s t key in s e t t i n g . a t t r i b u t e s ) { 11 c o n s t a t t r i b u t e = s e t t i n g . a t t r i b u t e s [ key ];
12 n e w E l e m e n t . s e t A t t r i b u t e ( key , a t t r i b u t e ) ;
13 }
14 let n e w F i e l d = d o c u m e n t . c r e a t e E l e m e n t (’ vpt - f i e l d ’) ; 15 n e w F i e l d . s e t A t t r i b u t e (’ l a b e l ’, s e t t i n g . l a b e l ) ;
26 Klemen Jug
16 n e w F i e l d . a p p e n d C h i l d ( n e w E l e m e n t ) ; 17 d i a l o g P a n e l . a p p e n d C h i l d ( n e w F i e l d ) ;
18 }
19 s e t t i n g . c o m p o n e n t = n e w E l e m e n t ; 20 }
21 }
Funkcija sprejme dva argumenta. Prvi je which, ki doloˇca, za kateri dia- log gre: za upodabljalnik, tonski slikar ali kontekst upodabljanja. Argu- ment settings so nastavitve, ki jih registriramo v zgoraj opisani funkciji registerSettings. Najprej v DOM s pomoˇcjo prvega argumenta poiˇsˇcemo identifikator mesta, kamor bomo pripeli naˇs dialog. Nato se sprehodimo po nastavitvah in za vsako definirano nastavitev na podlagi njenega tipa ustva- rimo nov element HTML – to je naˇsa spletna komponenta. Potem se spreho- dimo po atributih posamezne nastavitve in jih nastavimo naˇsi komponenti.
Nato ustvarimo nov element tipa polje, mu doloˇcimo oznako, vanj vstavimo naˇso novo komponento in ga pripnemo v DOM na mesto, ki smo ga poiskali prej (poseben primer komponente je gradnik prenosne funkcije, ki ga vsta- vimo v nov element tipa panel, ki ga vstavimo v element tipa zgibni meni).
Na koncu si shranimo naˇso komponento v novo lastnost component registri- rane nastavitve, da lahko kasneje na ta naˇcin laˇzje in hitreje dostopamo do nje.
Poglavje 5
Serializacija in deserializacija podatkov
Prvotna razliˇcica aplikacije je omogoˇcala spreminjanje nastavitev za prikazo- vanje volumna, ampak teh nastavitev se ni dalo shraniti za kasnejˇso uporabo.
To pomeni, da so se vsakokrat, ko je uporabnik osveˇzil spletno stran, vse nastavitve ponastavile na privzete vrednosti in tako je moral vsakokrat po- novno nastavljati vsako nastavitev posebej, da je vzpostavil stanje, kakrˇsnega je imel pred tem. To je bilo z uporabniˇskega vidika zelo zamudno in teˇzko, saj je nastavitev veliko in si je teˇzko zapomniti vse njihove vrednosti. Vzpo- stavitev identiˇcnega stanja je bila praktiˇcno nemogoˇca, saj je roˇcna rotacija kamere na toˇcno isto mesto, kot je bila prej, v praksi neizvedljiva. Eden izmed glavnih ciljev diplomske naloge je bil omogoˇciti shranjevanje in ob- novitev stanja – serializacijo in deserializacijo – in na ta naˇcin odpraviti te teˇzave in izboljˇsati uporabniˇsko izkuˇsnjo.
5.1 Shranjevanje stanja aplikacije
V spletno stran je bilo najprej treba dodati gumb za shranjevanje (angl.
save) in gumb za nalaganje nastavitev (angl. load). V konstruktorju ra- zreda Application smo jima pripeli posluˇsalca dogodkov za klik. Posluˇsalec
27
28 Klemen Jug gumba za shranjevanje poskrbi, da se ob kliku kliˇce metoda za serializacijo, posluˇsalec gumba za nalaganje pa, da se ob kliku kliˇce metoda za deserializa- cijo. Obe sta definirani v razredu Application. Metoda za deserializacijo bo opisana v naslednjem podpoglavju, metoda za serializacijo pa izgleda takole:
1 _ s e r i a l i z e = () = > { 2 c o n s t s e t t i n g s = {
3 v e r s i o n : t h i s. s e r i a l i z a t i o n V e r s i o n , 4 r e n d e r e r : t h i s. g e t S e l e c t e d R e n d e r e r () ,
5 r e n d e r e r S e t t i n g s : t h i s. _ r e n d e r i n g C o n t e x t . g e t R e n d e r e r () . s e r i a l i z e () ,
6 t o n e M a p p e r : t h i s. g e t S e l e c t e d T o n e M a p p e r () , 7 t o n e M a p p e r S e t t i n g s : t h i s. _ r e n d e r i n g C o n t e x t .
g e t T o n e M a p p e r () . s e r i a l i z e () ,
8 c o n t e x t : t h i s. _ r e n d e r i n g C o n t e x t . s e r i a l i z e () , 9 c a m e r a : t h i s. _ r e n d e r i n g C o n t e x t . s e r i a l i z e C a m e r a ()
10 }
11 C o m m o n U t i l s . d o w n l o a d J S O N ( s e t t i n g s , ’ S e t t i n g s . j s o n ’) ; 12 }
Objekt settings vsebuje sedem lastnosti. Tri izmed njih so enostaven niz znakov (verzija, upodabljalnik in tonski slikar). Ostale ˇstiri so objekti, sesta- vljeni iz veˇc lastnosti (nastavitve upodabljalnika, tonskega slikarja, konteksta upodabljanja in kamere). this.serializationVersionje lastnost, ki jo de- finiramo v konstruktorju razreda Application. Uporabljamo jo za doloˇcanje razliˇcice serializacijske datoteke. Metodi this.getSelectedRenderer in this.getSelectedToneMapper sta definirani v razredu Application in vrneta niz znakov s kratico imena upodabljalnika ter ime tonskega slikarja. Metoda serializeCamera, ki je dostopna na objektu konteksta upodabljanja, serializira lastnosti kamere. Teh lastnosti je pet: oddaljenost bliˇznje ploskve (angl. near plane), oddaljenost oddaljene ploskve (angl. far plane), faktor poveˇcave (angl. zoom factor), vektor pozicije kamere in vektor rotacije kamere.
Vsak izmed objektov, ki jih ˇzelimo serializirati, implementira vmesnik Serializable, ki vsebuje funkcijoserialize. Ta funkcija izgleda tako:
Diplomska naloga 29
1 s e r i a l i z e () {
2 let s e t t i n g s = {};
3 for (c o n s t key in t h i s. s e t t i n g s ) { 4 let s e t t i n g = t h i s. s e t t i n g s [ key ];
5 s e t t i n g s [ key ] = s e t t i n g . c o m p o n e n t . s e r i a l i z e () ;
6 }
7 r e t u r n s e t t i n g s ; 8 }
Definira prazen objekt settings in se nato sprehodi ˇcez vse lastnosti this.settingsposameznega upodabljalnika, tonskega slikarja ali konteksta upodabljanja. Na komponenti vsake od teh lastnosti, ki smo si jih prej shranili v funkcijimakeDialog, kliˇce metodoserialize, in rezultat shrani v objekt settings. Vsaka komponenta, ki jo lahko uporabimo za spreminjanje lastnosti, ima torej metodo serialize, ki zgolj vrne vrednost te lastnosti.
Na koncu, ko se sprehodi ˇcez vse lastnosti, vrne objekt settings, ki je sedaj napolnjen z vrednostmi vseh pomembnih lastnosti, definiranih v this.settings doloˇcenega upodabljalnika, slikarja tonov ali konteksta upodabljanja.
Na koncu metoda za serializacijo razreda Application kliˇce funkcijo CommonUtils.downloadJSON(settings, ’Settings.json’), ki na naˇs raˇcunalnik prenese datoteko, v kateri so zapisane vse lastnosti trenutnega stanja aplikacije, z imenom, ki ga podamo v drugem argumentu (v naˇsem primeru Settings.json).
1 {
2 " v e r s i o n ": "1.0" , 3 " r e n d e r e r ": " mcm " , 4 " r e n d e r e r S e t t i n g s ": { 5 " e x t i n c t i o n ": 1 , 6 " a l b e d o ": 0.5 , 7 " b i a s ": 0 , 8 " r a t i o ": 1 , 9 " b o u n c e s ": 8 , 10 " s t e p s ": 8 ,
11 " t r a n s f e r F u n c t i o n ": []
30 Klemen Jug
12 } ,
13 " t o n e M a p p e r ": " a r t i s t i c " , 14 " t o n e M a p p e r S e t t i n g s ": { 15 " low ": 0 ,
16 " h i g h ": 1 ,
17 " m i d t o n e s ": 0.5 , 18 " s a t u r a t i o n ": 1 19 } ,
20 " c o n t e x t ": { 21 " f i l t e r ": true , 22 " r e s o l u t i o n ": 512 , 23 " s c a l e ": {
24 " x ": 1 , 25 " y ": 1 , 26 " z ": 1
27 } ,
28 " t r a n s l a t i o n ": { 29 " x ": 0 ,
30 " y ": 0 , 31 " z ": 0
32 }
33 } ,
34 " c a m e r a ": { 35 " n e a r ": 0.1 , 36 " far ": 5 ,
37 " z o o m F a c t o r ": 0.001 , 38 " p o s i t i o n ": {
39 " x ": 0 , 40 " y ": 0 , 41 " z ": 1.5 , 42 " w ": 1
43 } ,
44 " r o t a t i o n ": { 45 " x ": 0 , 46 " y ": 0 , 47 " z ": 0 , 48 " w ": 1
49 }
Diplomska naloga 31
50 } 51 }
Koda 5.1: Primer datoteke Settings.json s privzetimi vrednostmi lastnosti aplikacije VPT.
5.2 Obnovitev stanja aplikacije in preverja- nje veljavnosti vhodnih podatkov
Shranjevanje stanja aplikacije nam bolj malo koristi, ˇce tega stanja kasneje ni mogoˇce ponovno vzpostaviti. V prvotni razliˇcici aplikacije, ko obnovitev stanja iz shranjenih podatkov ˇse ni bila implementirana, smo se zanaˇsali na to, da so bili vhodni podatki naˇsih dialogov vedno veljavni in zato nismo imeli nobenega preverjanja veljavnosti. Ko smo implementirali deserializa- cijo, pa je bilo treba poskrbeti tudi za to. Uporabnik bi lahko, na primer roˇcno spremenil nastavitve v datoteki Settings.json na neveljavne vredno- sti ali uporabil datoteko starejˇse razliˇcice in pri tem priˇcakoval, da njegove nastavitve delujejo. A nastavitve ne bi delovale in kljub temu ne bi dobil nobenega opozorila, ali huje, celotna aplikacija bi se sesula.
Metoda za deserializacijo je, tako kot metoda za serializacijo, definirana v razredu Application, in se kliˇce, ko kliknemo gumb za nalaganje nastavitev.
Metoda najprej kliˇce funkcijo readTextFilerazreda CommonUtils, ki je del prvotne aplikacije. Ta funkcija poskrbi, da se odpre okno, v katerem izberemo datoteko, ki jo ˇzelimo deserializirati. Nato v metodi za deserializacijo pretvo- rimo vsebino izbrane datoteke v objekt JSON in zaˇcnemo s preverjanjem, ali ta objekt sploh vsebuje vse potrebne lastnosti in pod-objekte z nastavitvami.
V primeru, da manjka objekt z nastavitvami konteksta upodabljanja ali ka- mere, napako izpiˇsemo v konzolo brskalnika in ne spremenimo njunih nasta- vitev. V nasprotnem primeru izvedemo deserializacijo njunih nastavitev. V primeru, da manjka ime upodabljalnika ali tonskega slikarja, napako izpiˇsemo v konzolo, obdrˇzimo trenutno izbranega in ne izvedemo deserializacije njego-
32 Klemen Jug vih lastnosti. V primeru, da imamo veljavno ime upodabljalnika ali tonskega slikarja, ampak manjka objekt z njegovimi nastavitvami, napako izpiˇsemo v konzolo in nastavimo izbrani upodabljalnik ali tonski slikar, vendar ne izve- demo deserializacije njegovih nastavitev, kar pomeni, da uporabimo privzete vrednosti za ta objekt. V primeru, da imamo veljavno ime upodabljalnika ali tonskega slikarja in prisoten objekt z njegovimi nastavitvami, nastavimo izbrani upodabljalnik ali tonski slikar in izvedemo deserializacijo njegovih nastavitev.
Funkcija za deserializacijo nastavitev posameznega upodabljalnika, sli- karja tonov ali konteksta upodabljanja je, tako kot funkcija za serializacijo, definirana v razredu Serializable, in izgleda takole:
1 d e s e r i a l i z e ( l o a d e d S e t t i n g s , gui ) { 2 t h i s. v e r i f y S e t t i n g s ( l o a d e d S e t t i n g s ) ;
3 if ( gui ) {
4 for (c o n s t key in t h i s. s e t t i n g s ) { 5 c o n s t v a l u e = l o a d e d S e t t i n g s [ key ];
6 t h i s. s e t t i n g s [ key ]. c o m p o n e n t . d e s e r i a l i z e ( v a l u e ) ;
7 }
8 } e l s e {
9 t h i s. d e s e r i a l i z e N o G U I ( l o a d e d S e t t i n g s ) ; 10 }
11 }
Funkcija sprejme dva argumenta: prvi predstavlja naloˇzene nastavitve posameznega upodabljalnika, slikarja tonov ali konteksta upodabljanja, drugi pa pove, ali aplikacija prikazuje uporabniˇski vmesnik (angl. GUI).
Funkcija najprej kliˇce metodo za preverjanje veljavnosti vhodnih podatkov this.verifySettings, ki je prav tako del razreda Serializable in je podrob- neje obrazloˇzena v naslednjem podpoglavju. Nato imamo dve moˇznosti:
v primeru, da aplikacija ne prikazuje uporabniˇskega vmesnika, nimamo nobenih komponent, s pomoˇcjo katerih bi lahko deserializirali podatke, zato se uporabi posebna metoda za deserializacijo this.deserializeNoGUI, ki je del razreda posameznega upodabljalnika, slikarja tonov ali konteksta upodabljanja, in ta neposredno nastavi lastnosti tega razreda. V primeru,
Diplomska naloga 33 da aplikacija prikazuje uporabniˇski vmesnik, se funkcija sprehodi po vseh lastnostih this.settings posameznega upodabljalnika, tonskega slikarja ali konteksta upodabljanja, in na komponenti vsake od teh lastnosti kliˇce metodo deserialize(setting), ki zgolj nastavi njeno vrednost na tisto, shranjeno v parametru setting. To spremembo zazna tudi lastnik kompo- nente (upodabljalnik, tonski slikar ali kontekst upodabljanja), ki poskrbi za popravek lastnosti svojega programa za prikazovanje.
5.3 Funkcije za preverjanje veljavnosti vho- dnih podatkov
Kot smo ˇze povedali v prejˇsnjem podpoglavju, je funkcija za preverjanje veljavnosti vhodnih podatkov verifySettings del vmesnika Serializable in je prva funkcija, ki se kliˇce v metodi deserialize.
1 v e r i f y S e t t i n g s ( l o a d e d S e t t i n g s ) {
2 for (c o n s t r e g i s t e r e d K e y in t h i s. s e t t i n g s ) {
3 c o n s t r e g i s t e r e d S e t t i n g = t h i s. s e t t i n g s [ r e g i s t e r e d K e y ];
4 let l o a d e d V a l u e = l o a d e d S e t t i n g s [ r e g i s t e r e d K e y ];
5 if ( l o a d e d V a l u e != n u l l) { // not u s i n g !== b e c a u s e it can be u n d e f i n e d
6 l o a d e d S e t t i n g s [ r e g i s t e r e d K e y ] = F a c t o r y .
7 g e t C o m p o n e n t C l a s s F r o m T y p e ( r e g i s t e r e d S e t t i n g . t y p e ) . 8 v e r i f y ( l o a d e d V a l u e , r e g i s t e r e d S e t t i n g ) ;
9 } e l s e {
10 c o n s o l e . e r r o r (’ S e t t i n g for ’ + r e g i s t e r e d K e y + ’ m i s s i n g . U s i n g d e f a u l t v a l u e ’) ;
11 s w i t c h( r e g i s t e r e d S e t t i n g . t y p e ) {
12 // g l e d e na tip k o m p o n e n t e n a s t a v i l a s t n o s t na p r i v z e t o v r e d n o s t
13 ...
14 }
15 }
16 } 17 }
34 Klemen Jug Ce smo v metodiˇ deserialize razreda Application preverjali, ali manjka kakˇsen objekt z nastavitvami, tu preverjamo, ali manjka katera od posame- znih lastnosti tega objekta. V tem primeru izpiˇsemo napako v konzolo br- skalnika in jo nadomestimo s privzeto vrednostjo, definirano v registriranih nastavitvah upodabljalnika, tonskega slikarja ali konteksta upodabljanja. Za tiste lastnosti, ki ne manjkajo, pridobimo razred komponente glede na njihov tip. V vseh razredih komponent je definirana statiˇcna funkcija verify, ki jo uporabimo za preverjanje, ali je vrednost lastnosti pravilnega tipa glede na tip komponente. Za drsnik, spinner in vector spinner potrebujemo vrednost tipa ˇstevilo s plavajoˇco vejico (angl. float), za checkbox vrednost Boolovega tipa (angl. boolean), za gradnik prenosne funkcije vrednost tipa niz (angl.
array), za izbirnik barve (angl. color chooser) pa potrebujemo niz znakov v formatu, ˇcigar ustreznost preverjamo z regularnim izrazom. ˇCe katera od vrednosti ni pravilnega tipa, jo nadomestimo s privzeto vrednostjo in napako izpiˇsemo v konzolo. V primeru, da je nastavitev tipa ˇstevilo s plavajoˇco ve- jico, moramo poskrbeti, da je velikost tega ˇstevila veljavna. Komponente z numeriˇcnimi vrednostmi imajo lahko definirano minimalno in maksimalno vrednost, zato ˇzelimo, da je njihova vrednost v tem razponu. ˇCe ni, izpiˇsemo napako v konzolo in jo nastavimo na najbliˇzjo vrednost, ki je.
Poglavje 6 Rezultati
Rezultat diplomske naloge je poenostavitev in posploˇsitev programiranja aplikacije VPT, izolacija kode in podpora serializaciji lastnosti aplikacije.
Kot primer bomo prikazali izdelavo novega upodabljalnika in serializacijo njegovih lastnosti. V prvotni razliˇcici aplikacije bi morali ustvariti nov ra- zred za upodabljalnik, ga registrirati v kontekstu upodabljanja, zanj ustvariti razred dialoga, ta razred registrirati v razredu Application, spisati datoteko JSON, ki bi opisovala komponente dialoga in dodati novo moˇznost v seznam moˇznosti spustnega menija za upodabljalnike v glavnem dialogu. Skupno bi morali spremeniti ˇsest datotek. Sedaj pa lahko veˇcino naredimo v glavnem razredu upodabljalnika. Na koncu moramo upodabljalnik zgolj registrirati v razredu konteksta upodabljanja in dodati moˇznost v spustni meni za upoda- bljalnike. Na tak naˇcin moramo spremeniti le tri datoteke, kar je pol manj kot prej.
Za prikaz izdelave novega upodabljalnika smo podvojili razred upoda- bljalnika “MIPRenderer”. Recimo, da ˇzelimo novemu upodabljalniku dodati ˇstiri nove komponente, vsako razliˇcnega tipa, in da ˇzelimo, da je komponenta za lastnost “steps”, ki je ostala od upodabljalnika “MIPRenderer”, tipa dr- snik. V funkcijiregisterSettingsnovega upodabljalnika zgolj spremenimo tip komponente za lastnost “steps” na drsnik, dodamo ˇstiri nove lastnosti in jim doloˇcimo tip komponente, oznako in atribute (slika 6.1). Novi upo-
35
36 Klemen Jug dabljalnik avtomatsko podpira serializacijo, kar pomeni, da za shranjevanje novih lastnosti ni treba niˇcesar prilagajati – ob kliku gumba za shranjevanje se serializirajo vse nastavitve novega upodabljalnika.
Slika 6.1: Prikaz novega upodabljalnika.
1 ...
2 " r e n d e r e r ": " new " , 3 " r e n d e r e r S e t t i n g s ": { 4 " s t e p s ": 64 ,
5 " c u s t o m S p i n n e r ": 1 , 6 " c u s t o m C h e c k b o x ": false , 7 " c u s t o m C o l o r ": "# f f 0 0 f f " , 8 " c u s t o m V e c t o r ": {
9 " x ": 1 , 10 " y ": 2 , 11 " z ": 3
12 }
13 } 14 ...
Koda 6.1: Izsek iz serializacijske datoteke z nastavitvami novega upodabljalnika.
Zaradi posploˇsenega in poenostavljenega naˇcina izdelave dialogov smo se lahko znebili vseh razredov dialogov in njihovih opisov v datotekah JSON – vse skupaj dvakrat po 17 datotek (6 upodabljalnikov, 10 tonskih slikarjev in kontekst upodabljanja).
Diplomska naloga 37 Vsa koda diplomske naloge je na voljo na GitHub repozitoriju na naslovu https://github.com/Wizyard/vpt/tree/master.
Konˇcna razliˇcica aplikacije je na voljo na naslovu https://vpt-wc- serialization.herokuapp.com/.
38 Klemen Jug