Implementácia aplikácie eAurela

Z Kiwiki
Skočit na navigaci Skočit na vyhledávání


Celková implementácia všetkých častí aplikácie eAurela vychádza zo špecifikácie požiadaviek a návrhu štruktúry. Sú tu popísané jednotlivé časti aplikácie, ich funkcionalita a implementácia. Prvá časť tejto kapitoly sa bude venovať používateľskému rozhraniu, následne bude vysvetlené, ako funguje navigácia v aplikácií. Ďalšia časť popisuje komunikáciu so serverom, získavanie a uchovávanie dát. Na záver je v kapitole popísaný dizajn aplikácie a zobrazenie dát pomocou dizajnových prvkov a pomocou grafov z knižnice recharts.

Používateľské rozhranie

Všetky časti aplikácie, ktoré spolu vytvárajú používateľské rozhranie (UI), sú implementované v súlade s navrhnutou štruktúrou v časti [structure]. Pomocou týchto častí používateľ pracuje a komunikuje s aplikáciou. Každá časť aplikácie je samostatný reactový komponent, ktorý sa môže skladať aj z viacerých komponentov. V princípe rozdeľujú tieto komponenty aplikáciu na tri časti:

  • prístup k dátam,
  • prezentácia dát používateľovi,
  • spravovanie systému (iba pre administrátorov).


Prístup k dátam

Pre prístup k dátam slúžia komponenty Home a Appilist. Komponent Home je prvý vykreslený komponent po spustení aplikácie eAurela. Po prihlásení do systému sa zobrazí komponent Applist (viď obr. 1.1 a obr. 1.2).

Obr 4.1 Prihlasovacia obrazovka (komponent Home)
Obr 4.2 Obrazovka pre výber aplikácie (komponent Applist)


Prezentácia dát používateľovi

Po výbere aplikácie zo spoločnosti v komponente Applist sa vykresľuje komponent Sectors. V tomto komponente si používateľ môže prezerať poslednú nameranú hodnotu zo senzorov v danom sektore, alebo si môže zvoliť vykreslenie grafu, ktorý zobrazuje krivky zo všetkých senzorov za určité obdobie. Tieto dve časti komponentu Sectors je možné vidieť na obrázkoch obr. 1.3. a obr. 1.4.

Obr 4.3 Posledné namerané hodnoty v oblasti Letné sídlo (komponent Sectors)
Obr 4.4 Vykreslenie grafu z oblasti Letné sídlo (komponent Sectors)


Spravovanie systému

Z funkčých požiadaviek R02 a R04 vyplýva, že administrátori systému budú mať možnosť spravovať systém cez aplikáciu eAurela. V prípade, že je používateľ na serveri pre autorizáciu uvedený ako administrátor, v komponente Applist po kliknutí na Možnosti sa mu zobrazí možnosť prejsť do časti spravovania tohto serveru. Podobne aj v komponente Sectors sa používateľovi zobrazí možnosť spravovania danej aplikácie v prípade, že má na serveri aplikácie uvedené administrátorské oprávnenia.

Obr 4.5 Spravovanie serveru pre autorizáciu (komponent AuthAdministration)
Obr 4.6 Spravovanie konkrétnej aplikácie (komponent ManageAdministration)

Navigácia v aplikácií

Jadrom celej aplikácie je knižnica React Router (https://github.com/ReactTraining/react-router). Tá zabezpečuje navigáciu medzi oknami (komponentami) v aplikácii eAurela. Táto knižnica slúži pre vytvorenie navigácie v aplikáciách naprogramovaných vo frameworku React. V jedno-oknových aplikáciach existuje iba jedna HTML stránka. Táto stránka je znovu použitá pri vykreslení rôznych komponentov v závislosti od navigácie. V knižnici React router sú tri primárne kategórie komponentov:

  • smerovače (routers), ako <BrowserRouter> a <HashRouter>,
  • porovnávače (route matchers), ako <Route> a <Switch>,
  • samotná navigácia (navigation), ako <Link>, <NavLink> a <Redirect>.


Smerovače

Sada react-router-dom sa používa v internetových projektoch a poskytuje komponenty BrowserRouter a HashRouter. V aplikácií eAurela je použitá práve sada react-router-dom. Hlavný rozdiel medzi komponentami BrowserRouter a HashRouter je spôsob ako pracujú s URL adresou a ako komunikujú s internetovým serverom (Nodejs serverom). BrowserRouter používa regulárny tvar URL adresy (tak ako ho je možné vidieť v prehliadači). Tento spôsob práce s URL adresou by bol dostačujúci v prípade, že by bola aplikácia zobrazovaná iba v prehliadači. Vzhľadom na to, že aplikácia bude slúžiť aj ako desktopová aplikácia, bolo výhodnejšie použiť práve HashRouter. Ten aktuálnu URL adresu ukladá ako mriežkovú časť (hash portion), teda URL adresa môže vyzerať napríklad http://priklad.com/#/hladana/stranka. Nakoľko mriežka nie je nikdy posielaná na server, netreba server špeciálne konfigurovať a navigácia bude fungovať v internetovom prehliadači a aj v desktopovej aplikácií. Pre správne použitie smerovača, je potrebné, aby bol umiestnený v jadre komponentovej hierarchie.


Porovnávače

Existujú dva komponenty pre porovnávanie: Switch a Route. Keď je vykreslený Switch, prehľadá všetkých potomkov Route, kým nenájde jedného, ktorého adresa sa zhoduje s aktuálnou URL adresou. Ak ho nájde, vykreslí ho a všetky ostatné komponenty ignoruje. Ak nenájde žiadnu zhodu, nevykreslí nič (null).


Navigácia

React Router poskytuje Link komponent na vytváranie odkazov v aplikácií. Kedykoľvek je vykreslený Link, vykreslí sa vlastne HTML tag <a>. Komponent NavLink je špeciálny druh Link komponentu, ktorému sa môže nastaviť vlastnosť active v prípade, že sa cesta zhoduje s URL adresou. Kedykoľvek treba vynútiť navigáciu, môže sa použiť komponent Redirect. Keď sa vykreslí, bude navigovať podľa jeho vlastnosti to . Použitie komponentu Redirect je ukázané a popísané v kóde [lst:ProtectedRoute].

<HashRouter>
    <div className="App">
        <Switch>
            <Route exact path={"/"} component={Home} />
            <ProtectedRoute exact path={"/applist"}
                component={AppList}
             />  
            <ProtectedAppRoute exact path={"/sectors"}
                component={Sectors}
            />
        </Switch>
     </div>
</HashRouter>

Kód 4.1: Zjednodušená ukážka použitia react-router-dom komponentov v aplikácií


Vytvorenie chránenej cesty

Ak nastane situácia, kedy je ku komponentu možné pristúpiť iba v určitom prípade (napríklad používateľ musí byť prihlásený, aby získal prístup k určitým častiam aplikácie), treba použiť tzv. chránenú cestu (ProtectedRoute). Keďže React Router taký komponent neposkytuje a do aplikácie majú prístup iba prihlásený používatelia, je potrebné chránenú cestu vytvoriť. Chránená cesta sa vytvorí modifikovaním už existujúceho komponentu Route. Vytváranie chránenej cesty je ukázané v kóde [lst:ProtectedRoute].

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
export const ProtectedRoute = ({ component: Component,
                                            path, ...rest }) => {
    // v premennej sa uchováva stav, či je používateľ prihlásený
    const isAuth = sessionStorage.getItem('isLoggedIn'); 
    return (
        <Route    // vykreslenie klasického komponentu <Route>
            path={path}
            {...rest}
            render={props => {
                return isAuth ?
                    <Component {...props} {...rest} /> 
    /* ak používateľ nie je prihlásený, vykreslí sa <Redirect>,
    ktorý používateľa presmeruje na obrazovku Home */
                    : <Redirect to="/" />
            }} />
    )
}

Kód 4.2: Vytvorenie chránenej cesty z komponentu <Route>

Získavanie a uchovávanie dát zo servera

Všetky dáta, ktoré aplikácia eAurela získava a prezentuje používateľovi, získava zo vzdialeného servera. Prístup k údajom na serveri zabezpečuje REST API (časť [API]). Aplikácia neponúka ukladanie dát pre neskoršie zobrazenie, ale vždy zobrazuje aktuálne dáta (funkčné požiadavky R06 a R08).

Získavanie dát zo servera

Existuje viacero spôsobov, ako komunikovať so vzdialeným serverom v React aplikácií. Väčšina vyžaduje dodatočnú inštaláciu knižnice určenej pre túto komunikáciu. V aplikácii eAurela však bol použitý spôsob priamo dostupný vo frameworku React, bez nutnosti inštalovať dodatočnú knižnicu. Pre túto komunikáciu slúži metóda fetch. Táto metóda preberá minimálne jeden parameter a to práve URL adresu servera. V aplikácii eAurela sa odovzdávajú tejto metóde vždy 2 parametre. Prvý parameter je textový reťazec a predstavuje URL adresu servera. Druhý parameter je objekt, ktorého povinná vlastnosť je metóda (method). Tu sa určí typ metódy (post, get, put alebo delete). Ďalej sa v tomto objekte môže zadefinovať hlavička (headers) a telo (body) požiadavku. Tieto vlastnosti nie sú povinné a zadávajú sa podľa toho, ako je to zadefinované na strane servera. Obsahujú informácie, ktoré sú nevyhnutné pre správne odoslanie požiadavku. V hlavičke to môžu byť napríklad prihlasovacie údaje používateľa, JWT token pre autorizovanie, alebo aj meno aplikácie, do ktorej sa používateľ snaží prihlásiť. Pri vytváraní alebo upravovaní používateľa, spoločnosti, senzora a podobne, sa v tele požiadavku odošle táto informácia ako JSON objekt konvertovaný na textový reťazec.

body: JSON.stringify({
                    login: this.state.login,
                    password: sha256(this.state.password),
                    firstname: this.state.firstname,
                    surname: this.state.surname,
                    isAdmin: this.state.isAdmin,
                    enabled: this.state.enabled,
                    Companies: this.state.Companies
                })

Kód 4.3: Príklad požiadavky pri vytváraní nového používateľa


fetch("http://login.nsoric.com/nsoric/auth/login/",
    {
        method: 'POST',
        headers: { login: name, password: sha256(password) }
    }
)
    .then(response => response.json())
    .then(result => {
        if (result.user.enabled) 
            this.props.handleSuccessfulAuth(result.user, result.JWT);
        else { 
            if (result.message === "user does not exists") 
                alert("Zle zadané prihlasovacie údaje!");
         }

Kód 4.4: Ukážka metódy fetch (zjednodušené prihlásenie používateľa do aplikácie)


Metóda fetch je asynchrónna a teda vracia dátový typ promise. To znamená, že metóda vráti synchrónne objekt promise ako dočasnú návratovú hodnotu predtým, než bude známa reálna hodnota. Potom, čo sa asynchrónna operácia dokončí, objekt zavolá callbak s výsledkom alebo chybou. Je to z toho dôvodu, aby aplikácia mohla normálne fungovať, kým získa odpoveď zo servera. Promise môže nadobúdať 3 stavy:

  • Čakajúci (Pending) - v tomto stave je zahájená asynchrónna operácia, ale ešte nie je známy výsledok,
  • Splnený (Resolved alebo aj Fulfilled) - v tomto stave je asynchrónna operácia dokončená úspešne a objekt volá úspešný callback,
  • Zamietnutý (Rejected) - v tomto stave je asynchónna operácia dokončená neúspešne a objekt volá neúspešný callback. .

Konkrétne príklady dátového typu promise z aplikácie je možné vidieť v časti [serverResponses] na obrázku [fig:response1] (splnený stav) a na obrázkoch [fig:response404] a [fig:response500] (zamietnutý stav). Na obrázku [fig:response2] je vidieť hodnotu, ktorú vrátila callback funkcia po úspešnom dokončení asynchrónnej funkcie.

V kóde [fetchRequest] sú v premennej response uložené práve informácie o promise objekte (stav a hodnota). V premennej result je už uložená finálna hodnota zo serveru vo formáte JSON.

Uchovávanie dát

Ako bolo spomenuté v časti [sec:IntroToReact], komponenty v React aplikácií majú svoje vlastnosti (props) a spravujú svoj vnútorný stav (state). Na základe stavu a vlastností je postavená komunikácia medzi jednotlivými komponentmi v aplikácií. Vo vnútri jedného komponentu sa definuje stav a ten sa odovzdá druhému komponentu ako jeho vlastnosť. Problém nastáva pri obnovení stránky (okna aplikácie). Pri obnovení stránky sa obnovuje aj stav komponentov (a teda s tým spojené aj vlastnosti). Aby sa zabránilo strate dát uchovaných v stave komponentu, existujú 2 možnosti:

  • ukladanie dát do lokálneho úložiska prehliadača (localStorage a sessionStorage),
  • nastavovanie stavu po každom vykreslení komponentu (metóda componentDidMount).


Lokálne úložisko prehliadača

Internetové aplikácie môžu ukladať dáta lokálne do úložiska používateľovho prehliadača. Tieto úložiská sú takmer rovnaké, jediným rozdielom je, že dáta uložené v localStorage nemajú žiadnu expiračnú dobu. V aplikácií eAurela je používaný sessionStorage, ktorý je automaticky vymazaný pri zatvorení prehliadača (v tomto prípade aj pri zatvorení Electron aplikácie). Ten v aplikácii uchováva dôležité informácie zo servera, ktoré nemôžu byť počas chodu aplikácie stratené. Jedná sa napríklad o údaje prihláseného používateľa (aplikácia tak vie, kto je prihlásený), JWT token, ktorý je posielaný v každej požiadavke na server. Pri strate týchto údajov po obnovení stránky, by sa aplikácia stala nefunkčnou. Tieto úložiská uchovávajú dáta vo forme textového reťazca. Preto dáta iného dátového typu treba vždy pred uložením konvertovať na textový reťazec.

sessionStorage.setItem('user', JSON.stringify(res1));
sessionStorage.setItem('JWT', res2);

Kód 4.5: Príklad uloženia hodnôt do sessionStorage

V kóde [sessionStorage.setItem] sú prvé parametre (’user’ a ’JWT’) názov, pod ktorým budú dáta dostupné a druhé parametre sú samotné dáta, ktoré sa ukladajú. Získanie dát zo sessionStorage je ukázané v kóde [sessionStorage.getItem].

const user = JSON.parse(sessionStorage.getItem('user'));
const jwt = sessionStorage.getItem('JWT');

Kód 4.6: Príklad použitia hodnôt zo sessionStorage

Síce sa sessionStorage vymaže automaticky pri zatvorení aplikácie, treba ho manuálne vymazať v prípade, že sa používateľ odhlási zo systému, no aplikáciu eAurela nechá otvorenú. Pre manuálne vymazanie celého obsahu úložiska slúži metóda sessionStorage.clear().


Metóda componentDidMount

Ďalšou možnosťou, ako predísť strate údajov, je posielanie požiadaviek a následné nastavovanie stavu v metóde componentDidMount. Táto metóda prebehne vždy, keď je komponent vykreslený. Posielanie požiadaviek na server (fetch) je doporučené robiť práve v tejto metóde.

componentDidMount() {
    this.setState({ isLoading: true })
    const ID = this.props.activeSector.id;
    fetch(this.state.url + "/manage/sector/" + ID + "/last-values/",
        {
            method: 'GET',
            headers: {Authorization: "Bearer " + this.state.jwt}
        }
    )
        .then(response => response.json())
        .then(result => {
            // nastavenie stavu z odpovede zo servera
            this.setState({ Sensors: result, isLoading: false })
        })
        .catch(error => console.log(error))
}

Kód 4.7: Odoslanie požiadavku v metóde componentDidMount()


Keďže namerané hodnoty zo senzorov majú byť vždy aktuálne, získavajú sa v tejto metóde. Komponent tak vždy po obnovení stránky má novú odpoveď zo servera s aktuálnymi nameranými hodnotami. Komponent obsahujúci metódu componentDidMount sa vždy vykresľuje na dvakrát. Napríklad v komponente Sectors sa najskôr vykreslia základné informácie o oblastiach a sektoroch a ikona načítavania, ktorá hovorí o tom, že aplikácia komunikuje so serverom (prebieha metóda componentDidMount).

Obr 4.7 Vykreslenie komponentu bez dát zo servera

Hneď ako aplikácia dostane odpoveď zo servera, ktorá obsahuje aktuálne údaje, na obrazovku sa dodatočne vykreslia tieto údaje bez toho, aby sa ostatné časti komponentu znovu vykresľovali.

Obr 4.8 Vykreslenie komponentu s dátami zo servera

Návrh dizajnu aplikácie

Komponenty v aplikácií sú základným stavebným blokom používateľského rozhrania. Ich vzhľad tvorí veľkú časť toho, ako bude aplikácia nakoniec vyzerať, ako ju bude vidieť samotný používateľ. Možností, ako upravovať štýl a vzhľad komponentov, je viacero. V aplikácií sú používané dva spôsoby úpravy vzhľadu komponentov: pomocou štylizovaných komponentov a pomocou CSS.

Štylizované komponenty

Tento spôsob úpravy dizajnu je v aplikácií využívaný najviac. Pre jednoduchosť bola použitá knižnica reactstrap (http://reactstrap.github.io/), ktorá obsahuje už vytvorené komponenty s hotovým dizajnom. Tie sú jednoducho vložené do vnútra komponentu, kde majú byť použité. Reactstrap je knižnica obsahujúca komponenty z React Bootstrap 4. Knižnica nie je závislá na jQuery alebo na Bootstrap javascript.


Komponenty pre interakciu s používateľom: <Input>, <Table> a <Form>

Keďže React používa syntax JSX (časť [sec:IntroToReact]), pre interakciu s používateľom boli použité komponenty Input a Form. Tieto komponenty fungujú na podobnom princípe, ako v jazyku HTML. Input slúži ako vstup, kam používateľ zadáva údaje (text, heslo a podobne). Form je formulár, v ktorom sa nachádza viacero vstupných polí a potvrdením tohto formulára sa odosiela požiadavka na server.

Obr 4.9 Formulár pre prihlásenie do aplikácie

V časti spravovania systému boli údaje pre ich sprehľadnenie vypísané na obrazovku do tabuľky. Pri upravovaní údajov zo servera bol použitý formulár, ktorý obsahoval tabuľku so vstupnými poľami (viď obrázok 1.10).

Obr 4.10 Formulár s tabuľkou pre vytvorenie používateľa


Komponenty pre zobrazenie informácií: <Card>, <ListGroup>

Komponent Card (karta) v aplikácií zobrazuje informácie získané zo servera. Karta sa skladá z viacerých ďalších komponentov (potomkov), ktoré slúžia pre presné zadefinovanie miesta, kde bude údaj zobrazený. To slúži pre prehľadné zobrazenie dát. Prvý doplňujúci komponent karty je hlavička karty (CardHeader). V komponente Applist sa do hlavičky vypisuje názov spoločnosti, spolu aj s malým logom. Pri údajoch zo senzorov (obrazovka Sectors) sa do hlavičky vypisuje názov senzora a stav batérie (ak daný senzor batériu má). Ďalší dôležitý komponent pri vykresľovaní karty je jej telo (CardBody). V okne Applist je do tela karty vložený titulok (CardTitle). Ten zobrazuje doplňujúce informácie o spoločnosti, ako adresu a podobne. Najdôležitejší komponent v tele karty je ListGroup. Tento komponent slúži pre vypísanie zoznamu aplikácií v danej spoločnosti, z ktorej si používateľ môže vybrať a prihlásiť sa do nej. V časti Sectors je telo karty použité na zobrazenie ID senzora, poslednej nameranej hodnoty zo senzora spolu s dátumom a časom, kedy bola táto hodnota nameraná.

Obr 4.11 Použitie karty pre výpis údajov


Komponenty pre navigáciu: <Navbar>, <Nav>, <NavLink>

Tieto komponenty slúžia pre jednoduchú navigáciu, či už medzi jednotlivými časťami aplikácie, alebo pri prechádzaní informácií. Za zmienku stojí v tejto časti komponent NavLink. Komponent s takým istým názvom je aj v knižnici react-router-dom (časť 1.2). Tieto komponenty vykonávajú v podstate to isté, rozdiel je v dizajne. Nevýhoda tohto komponentu je obnovenie obrazovky po kliknutí na tento odkaz, s čím môžu nastať problémy, ako boli popísané v časti 1.3.2. Aby sa odstránilo obnovovanie stránky pri kliknutí na odkaz, priradí sa mu funkcionalita komponentu Link z knižnice react-router-dom, ktorý presmeruje používateľa bez obnovenia stránky. Takto zapísaný NavLink sa správa ako Link, pričom mu zostane jeho dizajn. Takisto obsahuje vlastnosť active, ktorá v aplikácií slúži na zvýraznenie časti, v ktorej sa používateľ nachádza (viď obr. 1.12).

<NavLink
    tag={Link}      // priradenie funkcionality komponentu <Link>
    to={props.path} // cesta, kam bude používateľ presmerovaný
    onClick={handleClick} // funkcia vykonaná po kliknutí
    >  
    {props.link}    // hodnotu vlastnosti vidí používateľ ako odkaz
</NavLink>

Kód 4.8: Príklad prepojenia komponentov <NavLink> a <Link>

Komponenty Nav a Navbar slúžia ako rodičovské komponenty pre zoskupenie viacerých prvkov na navigáciu, alebo zobrazenie rôznych informácií. Rozdiel je v tom, že Navbar má viacero možností nastavenia vzhľadu (od ktorých sa odvíja aj vzhľad "potomkov"), ale dá sa použiť iba horizontálne, pričom Nav sa dá použiť aj vertikálne.

Obr 4.12 Komponenty <NavLink>, <Nav> a <Navbar>

Úprava vzhľadu pomocou CSS

V aplikácií bol taktiež na úpravu vzhľadu použitý jazyk CSS. Pre nastavenie základných vlastností aplikácie eAurela, ako štýl písma a podobne, bol použitý klasický spôsob vloženia odkazu na externý .css súbor do koreňového komponentu aplikácie. Taktiež aj pre dodatočnú úpravu niektorých komponentov z knižnice reactstrap bol zvolený tento spôsob. React dovoľuje ale aj používanie CSS priamo vo vnútri komponentov. Tento spôsob bol použitý v aplikácií najmenej a bol použitý hlavne na prvky, ktorých vzhľad bolo treba dynamicky meniť (ako napríklad komponent NavLink pri nastavení spomenutej vlastnosti active).

<NavLink
    tag={Link}
    /* štýl sa bude meniť vzhľadom na pravdivostnú
    hodnotu premennej props.Graphs */
    style={!props.Graphs ? {
    color: "black",
    backgroundColor: "white",
    boxShadow: "0px 0px 0px 1px lightgrey"
    } : style}
    to="sectors"
    active={!props.Graphs}
</NavLink>

Kód 4.9: Dynamické nastavenie štýlu komponentu <NavLink>


Vykreslovanie grafov

Vzhľadom na funkčnú požiadavku R08 bolo potrebné v aplikácií eAurela zabezpečiť prácu s grafmi. Pre framework React existuje viacero knižníc pre prácu a zobrazenie grafov. V aplikácii eAurela je použitá knižnica recharts (http://recharts.org/en-US/) pre jej bezplatnú dostupnosť a veľmi dobre vypracovanú dokumentáciu. Graf sa vykresľuje v samostatnom komponente SensorGraphs, ktorý je následné vykreslený v komponente Sectors po zvolení možnosti "Časový záznam". Na nasledujúcom obrázku je zobrazený graf v aplikácii eAurela s hodnotami z časového intervalu tridsať dní.

Obr 4.13 Vykreslenie grafu v komponente <Sectors>

Knžinica recharts ponúka veľké množstvo grafov, či už čiarové, stĺpcové, koláčové a podobne. Keďže má aplikácia vykresľovať zmenu nameraných hodnôt z časového intervalu všetkých senzorov nachádzajúcich sa v sektore, bol použitý základný čiarový graf (LineChart). Vzhľadom na to, že v jednom grafe sa bude nachádzať viacero kriviek (podľa počtu senzorov), z dokumentácie recharts bol vybraný čiarový graf s názvom "LineChartHasMultiSeries". Aby boli jednotlivé krivky správne vykreslené, komponent LineChart musí prevzať dáta upravené do správneho formátu.

const series = [
  {
    name: 'Senzor 1',
    data: [
        {
            date: "",
            value: 
        },
        { ... }, ...
    ],
  },
  { ... }, ...
];

Kód 4.10: Vzor formátu dát pre LineChart


Konštanta series je pole, kde každý prvok poľa predstavuje objekt s dvoma vlastnosťami: name a data. Vlastnosť name obsahuje názov senzora, ktorý bude vypísaný v legende spolu s odpovedajúcou farbou krivky. Vlastnosť data obsahuje konkrétne namerané dáta. Data je taktiež pole objektov, kde jednotlivé objekty obsahujú taktiež dve vlastnosti: date (dátum, kedy bola hodnota nameraná) a value (nameraná hodnota). Táto konštanta je zadefinovaná vo funkcii pre vykreslenie komponentu (render).

render() {
    const series = this.getChartData(Sensors, Measurements);
    return ( ... )
}

Kód 4.11: Zadefinovanie konštanty series


V odpovedi zo servera dostaneme dve polia: sensors, kde sú uložené všeobecné informácie o senzoroch a measurements, kde sú namerané hodnoty za dané obdobie. Takáto odpoveď zo serveru vyzerá podobne ako na obrázku obr. 1.14.

Obr 4.14 Odpoveď zo servera pri vykreslovaní grafu

O spracovanie údajov zo servera do správneho formátu sa v aplikácií starajú dve metódy. Prvá metóda je getChartData, ktorá ako parametre preberá namerané údaje zo servera (measurements), a taktiež všetky údaje o senzoroch (sensors). Táto metóda prechádza pole všetkých senzorov a pre vyhovujúce senzory (nevyhovujúce sú v tomto prípade senzory snímajúce stav batérie) priradí názov senzora.

getChartData(sensors, measurements) {
        let chartData = [];
            for (let i = 0; i < sensors.length; i++) {
                if (isNaN(sensors[i].uid) || this.DecToBin(sensors[i].uid).substring(0, 8) !== "00000000") {
                    chartData[i] = {
                        name: sensors[i].name,
                        data: this.getData(sensors[i].uid, measurements)
                    }
                }
            }
    return chartData;
}

Kód 4.12: Metóda getChartData


Pre zjednodušenie ukážky boli z kódu odstránené dodatočné podmienky ošetrujúce výnimočné stavy, ktoré môžu nastať pri komunikovaní so serverom. Práve v týchto podmienkach je použitý parameter measurements. Taktiež je použitý ako vstupný parameter funkcie getData, ktorá vyplní vlastnosť data konkrétnymi hodnotami (dátumom, časom a konkrétnou hodnotou). Táto metóda preberá ako vstupný parameter aj ID senzora, aby bolo možné prideliť namerané hodnoty k správnemu senzoru. Táto metóda prechádza všetky namerané údaje a hľadá tie, ktoré boli namerané senzorom s príslušným ID.

getData(id, measurements) {
    let data = [];
    let k = 0;
    for (let i = (measurements.length - 1); i >= 0; i--) {
        for (let j = 0; j < measurements[i].values.length; j++) {
            if (id === measurements[i].values[j].sid) {
                data[k] = {
                    date: measurements[i].date.substring(0, 10) + " " + measurements[i].date.substring(11, 19),
                    value: measurements[i].values[j].value !== null ? measurements[i].values[j].value : null
                }   
                break;
            }
        }
        k++;    
    }
    return data;
}

Kód 4.13: Metóda getData


Aj v tejto ukážke boli pre zjednodušenie kódu vynechané podmienky ošetrujúce stavy, spôsobujúce chyby v aplikácií.

Samotný komponent LineChart sa skladá z viacerých ďalších komponentov, ktoré upresňujú rozloženie jednotlivých prvkov grafu a umiestnenie údajov. ResponsiveContainer definuje šírku a výšku grafu. Komponenty XAxis a YAxis určujú, ktoré dáta sú vykreslené na každej z osí, či sa jedná o textové, alebo číselné údaje. Komponent Legend vykresľuje legendu ku grafu, Tooltip zobrazí nápovedu o konkrétnom dátume (nápovedu používateľ zobrazí prejdením kurzora do časti grafu, kde si chce prezrieť konkrétne hodnoty). Line je samotná krivka, ktorej sa definujú dáta, ktoré sa použijú na vykreslenie. Keďže v aplikácií sa vykresľuje viacero kriviek do jedného grafu, bola použitá javascriptová metóda map pre prechádzanie konštanty series a pre každý jej prvok sa vykreslí vlastná krivka. Kód [LineChart] zobrazuje implementáciu grafu v aplikácií aj s popisom jednotlivých častí a výsledný graf je možné vidieť na obrázku 1.15.

<ResponsiveContainer width="95%" height="90%">
     <LineChart>
    <CartesianGrid strokeDasharray="3 3" />
    <XAxis
        dataKey="date"      // dáta zobrazené na osi X
        type="category"     // textový údaj (dátum a čas)
        allowDuplicatedCategory={false} // údaj sa nesmie opakovať
        minTickGap={10} />  // medzera medzi údajmi v popise
    <YAxis dataKey="value" />
    <Tooltip />
    <Legend />
    {series.map((s, index) => (
        <Line
            key={index}     
            dataKey="value"     // kľúčová hodnota
            data={s.data}       // pôvod dát
            name={s.name}       // názov senzoru
            stroke={this.getRandomColor()}  // farba krivky
            dot={false} />
    ))}
    </LineChart>
</ResponsiveContainer>

Kód 4.14: Implementácia grafu LineChart


Vzhľadom na to, že recharts pri vykreslení viacerých kriviek do jedného grafu priradí všetkým základnú (rovnakú) farbu, bola pre lepšie rozlíšenie kriviek implementovaná funkcia getRandomColor, ktorá každej krivke priradí náhodnú farbu.

Obr 4.15 Ukážka grafu s popisom jednotlivých komponentov