• Nebyly nalezeny žádné výsledky

Formulář bez zabezpečení proti XSS (zdroj: autor)

Po zabezpečení proti XSS se správně vypíše pouze text zadaný uživatelem (viz obrázek 11).

Zadávání identických nebo lineárně závislých omezení bylo nutné zamezit. Před porovnáváním omezení je nejprve nutné obě omezení převést na základní tvar. Nejprve je vytvořeno pole normalized, do kterého jsou vloženy parametry zadaného omezení. Poté je pro tyto 4 parametry nalezen největší společný dělitel. Pokud je největší společný dělitel větší než 1, znamená to, že zadaná nerovnice není v základním tvaru. Vydělením všech hodnot největším společným dělitelem je získán základní tvar. Poté jsou pomocí cyklu postupně procházena všechna již zadaná omezení a každé z nich je stejným způsobem převedeno na základní tvar a porovnáno se zadávaným omezením. Pokud jsou obě omezení (v základním tvaru) shodná, je vytvořena chybová hláška pro uživatele. Viz výpis 2.

Výpis 2 Zabezpečení zadávání identických nebo lineárně závislých omezení let congruence = false;

let normalized = [x1, x2, x3, b]

//nsd = největší společný dělitel

const nsd = findGCD(normalized, normalized.length) if (nsd > 1){

normalized = [normalized[0]/nsd, normalized[1]/nsd, normalized[2]/nsd, normalized[3]/nsd]

}

for (i = 0; i < localStorage.length; i++) { //ulož do proměnné položku z localstorage

let currentItem = JSON.parse(localStorage.getItem(localStorage.key(i)));

//zjisti největší společný dělitel pro současnou položku let nsdOfCurrent =

findGCD([currentItem[0],currentItem[1],currentItem[2],currentItem[4]],4);

if (nsdOfCurrent > 1){

currentItem = [currentItem[0]/nsdOfCurrent, currentItem[1]/nsdOfCurrent, currentItem[2]/nsdOfCurrent, currentItem[3], currentItem[4]/nsdOfCurrent]

}

//zjisti zda jsou obě omezení v základním tvaru shodné, včetně operátoru

if (normalized[0] == currentItem[0] && normalized[1] ==currentItem[1] && normalized[2]

== currentItem[2] && type == currentItem[3] && normalized[3] == currentItem[4]){

congruence = true;

} }

//pokud jsou omezení shodné, vytvoř chybovou hlášku if (congruence === true){

alert("You have already entered constraint with same parameter values.");

return;

}

Pokud uživatel zadá mezeru v čísle v jakémkoliv z polí, jež je určeno pouze pro zadávání čísel, pak už zadaný údaj není považován za číslo, ale text, tudíž není formulářem ani

javascriptovou kontrolou uznán a je vytvořena chybová hláška. Zadání nulového omezení je také ošetřeno. V případě chybného zadání údajů jsou vypisovány chybové hlášky pro uživatele, tyto hlášky informují o špatném zadání dat. Zároveň upozorňují uživatele na to, kde udělal chybu.

2.2.4 Ukládání dat

Pro snadnější práci s aplikací je vhodné zadané omezení a účelovou funkci ukládat do místního úložiště. Veškerá zadaná omezení jsou průběžně serializována (převedena na String) a uložena do místního úložiště. Pokud uživatel opustí stránku a později se k ní vrátí, jsou poslední zadaná omezení a účelová funkce načteny z paměti z předchozí práce s aplikací. To zabraňuje opětovnému zdlouhavému zadávání všech omezení a účelové funkce.

Rychlé smazání všech omezení umožňuje tlačítko „Clear all“. To se automaticky zobrazí v případě, že je zadáno více než jedno omezení.

2.2.5 Zobrazení hraničních rovin a průhlednost

V případech, kdy je zadáno velké množství omezení, se výsledný graf stává pro uživatele nepřehledným. Proto lze v aplikaci pomocí posuvníku měnit průhlednost hraničních rovin (omezení) nebo kompletně vypnout jejich zobrazení. V takovém případě se uživateli zobrazí pouze výsledná množina přípustných řešení.

2.2.6 Použité knihovny

Popisovaná aplikace využívá následující javascriptové knihovny: JQuery, Math.js, Plotly.js.

Uvedené knihovny jsou při načítání aplikace stahovány ze sítě pro doručování obsahu (content delivery network – CDN) jejich tvůrců.

JQuery

Knihovna jQuery je používaná, neboť díky snadno použitelnému rozhraní značně usnadňuje procházení a manipulaci s HTML dokumenty a objektovým modelem dokumentu (DOM), manipulaci s událostmi a AJAX (Asynchronous Javascript and XML). Cílem této knihovny je zjednodušit použití Javascriptu ve webových aplikacích. Díky této knihovně je mnoho běžných úkolů, které bez použití jQuery vyžadují mnoho řádků kódu, velmi zkráceno a zabaleno do metod, které lze volat jedním řádkem kódu.

Math.js

Vzhledem k tomu, že aplikace vyžaduje výpočet velkého množství matematických operací, mnohdy i velmi složitých, je použita knihovna Math.js. Tato knihovna nabízí velkou sadu integrovaných funkcí. Umožňuje také využití integrovaného řešení pro práci s různými typy dat, jako jsou například čísla, velká čísla a matice. Obsahuje funkce, které počítají

determinant matice, faktoriál čísla a funkci pro vyhodnocení rovnic či nerovnic. Všechny funkce použité v aplikaci a jejich stručný popis je možné nalézt v tabulce 1.

Tabulka 1 funkce knihovny Math.js použité v aplikaci (zdroj: autor)

Funkce Popis

det Funkce počítá determinant ze zadané matice.

factorial Funkce počítá faktoriál ze zadaného čísla.

evaluate Funkce vyhodnocuje rovnice či nerovnice a

vrací hodnotu typu boolean.

bignumber Funkce umožňuje práci s velkými čísly a jejich

uložení.

add Funkce pro sčítání dvou čísel.

multiply Funkce pro násobení dvou čísel.

round Funkce pro zaokrouhlování čísel.

smaller Funkce porovnává, jestli je první číslo menší

než druhé, a vrací hodnotu typu boolean.

larger Funkce porovnává, jestli je první číslo větší než

druhé, a vrací hodnotu typu boolean.

equal Funkce určuje rovnost dvou čísel a vrací

hodnotu typu boolean.

Plotly.js

Tato knihovna umožňuje samotné vykreslování grafu. Je postavena na knihovnách d3.js a stack.gl. Plotly je open source knihovna a je tedy zcela zdarma. Knihovna umožňuje vykreslování trojrozměrných grafů, nabízí srozumitelné uživatelské rozhraní určené k prohlížení grafu a zvládá zpracovávat větší množství dat.

V pravé horní části grafu je možné nalézt ovládací prvky grafu. Viz obrázek 12, kde jsou zobrazeny všechny prvky a očíslovány směrem zleva doprava čísly 1 až 8. V tabulce 2 je popsána funkcionalita jednotlivých prvků. Číslování prvků odpovídá číslování na obrázku 12.

Obrázek 12 Ovládací prvky grafu (zdroj: autor)

Tabulka 2 Popis ovládacích prvků grafu (zdroj: autor)

Číslo prvku Popis

1 Stáhnout aktuální pohled na graf ve formátu PNG

2 Přiblížení

3 Pohled kamery

4 Rotace kamery

5 Otočení grafu

6 Resetovat kameru do výchozího pohledu

7 Resetovat kameru do posledního uloženého

pohledu

8 Přepínač zobrazení dat při najetí myší na objekt

2.3 Algoritmus aplikace

Pro spuštění aplikace stačí zadat do libovolného prohlížeče webovou adresu aplikace (LPgraph.com). Jakmile se načte celá stránka, vše je připravené k zadání modelu úlohy a následné vykreslení grafu.

Po spuštění aplikace se před uživatelem zobrazí hlavní zadávací pole nazvané „Model“

(viz obrázek 13). Zde se nachází všechny formuláře určené k zadání vstupních dat. V části nazvané „non-negativity constraints“, si pomocí zaškrtávacích políček uživatel upravuje omezení nezápornosti. Ve výchozím stavu jsou všechna tato políčka zaškrtnuta. Platí tedy omezení x1, x2, x3 ≥ 0. Část „Add constraint“ slouží k zadávání jednotlivých omezení.

Uživatel může zadávat omezení ve tvaru rovnice i nerovnice. Po tomto kroku přidá omezení

seřazena abecedně podle jejich názvu. Pro odebrání omezení pak slouží tlačítko „remove“, které je u každého vypsaného omezení.

Část „Objective function“ slouží k zadání účelové funkce. Uživatel v této části podle předepsaného formátu vyplní všechna vstupní pole, následně z menu vybere, zda chce funkci maximalizovat nebo minimalizovat, a poté ji uloží pomocí tlačítka „+“. Jakmile je funkce uložena, celá část pro zadávání účelové funkce zmizí a nelze přidat další účelovou funkci. Nejedná se o aplikaci umožňující vícekriteriální programování. Zadaná účelová funkce je pak vypsána pod všemi zadanými omezeními. Pokud ji chce uživatel upravit, nejprve použije tlačítko „remove“. Uvedené tlačítko nalezne vedle vypsané účelové funkce.

Po použití se účelová funkce smaže a objeví se opět pole k zadání účelové funkce.

Obrázek 13 Formuláře k zadání vstupu od uživatele (zdroj: autor)

Po zadání modelu uživatel použije tlačítko „Plot!“. To spustí funkci, která zajišťuje celý výpočet a vykreslení samotného grafu.

V následujících částech kapitoly se budu postupně zabývat podrobným popisem jednotlivých částí tohoto výpočtu i samotným vykreslením grafu.

2.3.1 Výpočet základních přípustných řešení

První částí výpočtu je získání všech základních přípustných řešení. Dále bude popsán průběh tohoto výpočtu. Pro snazší pochopení algoritmu je na obrázku 14 vytvořen diagram, který ho popisuje.

Nejprve se vytvoří pole FeasiblesArr, do něhož je potřeba vložit všechny názvy omezení, aby z nich později byly vytvořeny kombinace. Poté jsou pomocí „for“ cyklu, procházena omezení uložená v místním úložišti prohlížeče a postupně přidávána do pole. Jakmile je dokončen tento cyklus, jsou v poli FeasiblesArr uloženy všechny názvy omezení.

Následuje spuštění funkce combine, ta postupně v cyklu vytváří z pole FeasiblesArr unikátní kombinace trojic (trojice proto, že se jedná o trojrozměrný graf) omezení.

Pro takto vzniklou kombinaci jsou vytvořeny tři pomocné proměnné constraint1, constraint2, constraint3 a do nich je přiřazen objekt, který představuje zápis rovnice či nerovnice omezení v jednom z následujících tvarů:

1 2 3

Tento objekt je získán z místního úložiště, kde jsou uložena všechna omezení, ovšem v již serializované podobě (v datovém typu String). Proto je nutné převést tuto podobu zpět na objekt. Převedení nám umožňuje využití funkce parse (viz následující výpis).

constraint1 = JSON.parse(localStorage.getItem(combiResFeas[0]));

constraint2 = JSON.parse(localStorage.getItem(combiResFeas[1]));

constraint3 = JSON.parse(localStorage.getItem(combiResFeas[2]));

Následně je vytvořena proměnná (viz Výpis 3) matrixDelta4 (typu pole), která představuje zápis matice ve formátu: podle (Kannan, Dinakaran a Lavanya, 2004, s. 8) spočítá determinant matice ∆4:

1 1 1

Výpis 3 Výpočet determinantu matice (zdroj: autor) //spočítá delta4 pro danou kombinaci

matrixDelta4 = [

[constraint1[0], constraint1[1], constraint1[2]], [constraint2[0], constraint2[1], constraint2[2]], [constraint3[0], constraint3[1], constraint3[2]]

];

delta4 = math.det(matrixDelta4);

Pokud platí ∆4 = 0, znamená to, že daná kombinace třech omezení nemá průsečík a pokračuje se další kombinací.

Pokud platí ∆4≠ 0, je nutné dopočítat podle (Kannan, Dinakaran a Lavanya, 2004, s.8)

1, ∆2, ∆3 následovně:

Souřadnice jsou definovány soustavou rovnic (1.3.1), ze kterých vyplývá, že platí:

1

Výpis 4 Výpočet průsečíků poloprostorů omezení (zdroj: autor) if(delta4 !== 0) {

//spočítá ostatní delty matrixDelta1 = [

[constraint1[1], constraint1[2], -constraint1[4]], [constraint2[1], constraint2[2], -constraint2[4]], [constraint3[1], constraint3[2], -constraint3[4]]

];

matrixDelta2 = [

[constraint1[2], -constraint1[4], constraint1[0]], [constraint2[2], -constraint2[4], constraint2[0]], [constraint3[2], -constraint3[4], constraint3[0]]

];

matrixDelta3 = [

[-constraint1[4], constraint1[0], constraint1[1]], [-constraint2[4], constraint2[0], constraint2[1]], [-constraint3[4], constraint3[0], constraint3[1]]

];

Jakmile máme určeny souřadnice průsečíku, je nutné ověřit, zda průsečík splňuje podmínky všech omezení. Ne všechny tyto získané průsečíky náleží do množiny přípustných řešení.

Proto je potřeba je postupně dosadit do všech zadaných omezení. V případě, že splní podmínky všech omezení, jedná se o základní přípustné řešení a souřadnice tohoto řešení jsou přidány do polí FeasiblePointsX1, FeasiblePointsX2, FeasiblePointsX3.

Pokud alespoň jedné z rovnic nevyhovuje, nejedná se o základní přípustné řešení, dále už není potřebné, proto se „zahodí“ a pokračuje se v cyklu dalším výpočtem (viz výpis 5).

Výpis 5 Validace průsečíků (zdroj: autor)

//pokud se jedná o účelovou funkci v localstorage, přeskočí v cyklu 4

//jinak načte potřebné parametry nerovnice do proměnné 5

if(localStorage.key(j) === "/>>$ObjFunction|") { 6

continue;

7

} else{

8

loaded = JSON.parse(localStorage.getItem(localStorage.key(j)));

9

} 10

//levá a pravá strana nerovnice 11

//vytváří nerovnici či rovnici k následnému vyhodnocení z levé a pravé strany nerovnice či 15

//pokud platí všechny nerovnice či rovnice pro dané x1, x2, x3 --> push do pole základních 24

2.3.2 Výpočet hraničních přípustných řešení

Dalším krokem výpočtu je výpočet tzv. hraničních přípustných řešení. Pomocí nich se zjistí, zda má úloha alternativní optimální řešení. V případě, že úloha má neomezenou množinu přípustných řešení (pokračuje do nekonečna), jsou tyto body použity k vykreslení takové neomezené množiny přípustných řešení. Tu lze však zobrazit pouze částečně a uživateli nastínit, jakým směrem pokračuje do nekonečna. Na obrázku 15 je ukázka neomezené množiny, která pokračuje do nekonečna ve směru oranžových šipek (oranžové šipky jsou doplněné ručně). Žluté body na obrázku jsou právě hraniční přípustná řešení.

Obrázek 15 Ukázka neomezené množiny přípustných řešení (zdroj: autor)

Při výpočtu hraničních přípustných řešení, je nejprve nutné získat maximální hodnoty všech os grafu. Ty poté vynásobíme konstantou multiplier (v současné chvíli nastaveno na 1,8).

Tím je docíleno, že v případě vykreslování neomezené množiny přípustných řešení, bude zobrazena v určitém poměru ke zbytku grafu. Poté přidáme do soustavy omezení tři další omezení (hraniční) v následujícím tvaru:

1 2 3

, , . x graphMaxX1 multiplier x graphMaxX2 multiplier x graphMaxX3 multiplier

 

 

 

(2.2.6)

kde proměnné graphMaxX1, graphMaxX2, graphMaxX3 jsou získaná maxima jednotlivých os grafu a multiplier přednastavená konstanta.

Následně je třeba vytvořit pole, které bude obsahovat všechna omezení, včetně třech nově vzniklých, aby mohly být vypočítány všechny průsečíky hraničních rovin (omezení). Proto je vytvořeno nové pole BorderPsArr. Toto pole vznikne sloučením pole FeasiblesArr a třech nových omezení. Obsahuje tedy všechna omezení zadaná uživatelem a tři nová hraniční omezení (2.2.6). S daným polem provede práci funkce combineBorderP. Tato funkce pracuje téměř stejně jako funkce combine. Vypočítá všechny průsečíky omezení a uloží je jako pole do proměnných BorderPointsX1, BorderPointsX2, BorderPointsX3.

Jelikož tato pole obsahují i některé souřadnice průsečíků z množiny základních přípustných řešení, je nutné odfiltrovat tyto shodné průsečíky. To zajišťuje následující část kódu, která vytvoří tři nová pole filteredX1, filteredX2, filteredX3 s průsečíky s hraničními omezeními, která nahrazují pole BorderPointsX1, BorderPointsX2, BorderPointsX3. V těchto polích už nejsou souřadnice duplicitních průsečíků (viz výpis 6).

Výpis 6 Filtrace shodných bodů (zdroj: autor)

let filteredX1 = [];

let filteredX2 = [];

let filteredX3 = [];

//vyfiltruje stejné body z polí BorderPoints a FeasiblePoints, uloží do nového pole ty, které jsou jedinečné

for(i=0; i<BorderPointsX1.length;i++){

let c = true;

let t = [BorderPointsX1[i], BorderPointsX2[i], BorderPointsX3[i]];

for(j=0;j<FeasiblePointsX1.length;j++){

let f = [FeasiblePointsX1[j], FeasiblePointsX2[j], FeasiblePointsX3[j]];

if(JSON.stringify(t) === JSON.stringify(f)){

c = false;

se pouze odlišnými názvy některých proměnných a některé funkce sloužící k porovnávání hodnot by byly nahrazeny funkcemi inverzními. Diagram lze nalézt v příloze B.

V současné fázi výpočtu jsou k dispozici základní přípustná řešení a hraniční přípustná řešení. Jejich souřadnice jsou uloženy v polích FeasiblePointsX1, FeasiblePointsX2, FeasiblePointsX3 a v polích filteredX1, filteredX2, filteredX3. Nyní je potřeba všechny tyto průsečíky postupně dosazovat do uživatelem zadané účelové funkce a hledat bod, v němž účelová funkce dosahuje maxima nebo minima. (viz výpis 7)

Výsledek úlohy může mít mnoho podob. Zde se pokusím popsat jednotlivé situace.

Pokud hodnota účelové funkce dosahuje lepšího maxima nebo minima v průsečíku hraničních omezení, boolean hodnota proměnné valueBetter je nastavena na true. To znamená, že úloha nemá optimální řešení, jelikož má neomezenou hodnotu účelové funkce.

Pokud maximum nebo minimum pro danou účelovou funkci dosahuje stejné hodnoty (maxima nebo minima) v průsečíku hraničních omezení jako v bodě, který je součástí základních přípustných řešení, pak se boolean hodnota proměnné valueEqual nastaví na true. To znamená, že výsledkem je polopřímka (případně polorovina) a tento průsečík hraničních omezení (bod) udává její směr. Úloha má alternativní optimální řešení.

Pokud hodnoty v průsečících hraničních omezení jsou horší než v bodech základních přípustných řešení, její optimální řešení spočívá v množině základních přípustných řešení.

Výpis 7 Hledání optima účelové funkce (maxima) (zdroj: autor) //maximalizace účelové funkce

1

if(objectiveFunction[3] === "max") { 2

//maxFeas je hodnota pro první bod 3

//pokud máme nějaké hraniční průsečíky 8

if(filteredX1.length>0){

9

maxBorder = firstBorder;

10

SolutionCoordX1border[0] = filteredX1[0];

11

SolutionCoordX2border[0] = filteredX2[0];

12

SolutionCoordX3border[0] = filteredX3[0];

13 14 } 15

for(i = 1; i < FeasiblePointsX1.length; i++) { 16

//a je výpočet hodnoty pro další průsečík 17

a = math.bignumber(math.add(math.round(math.multiply(objectiveFunction[0], 18

//pokud body mají shodnou hodnotu 22

SolutionCoordX1feas[0] = FeasiblePointsX1[i];

31

SolutionCoordX2feas[0] = FeasiblePointsX2[i];

32

SolutionCoordX3feas[0] = FeasiblePointsX3[i];

33 34 } 35 }

//porovnávání pro hraniční body 36

a = math.bignumber(math.add(math.round(math.multiply(objectiveFunction[0], 40

SolutionCoordX1border.push(filteredX1[i]);

45

SolutionCoordX2border.push(filteredX2[i]);

46

SolutionCoordX3border.push(filteredX3[i]);

47

SolutionCoordX1border[0] = filteredX1[i];

52

SolutionCoordX2border[0] = filteredX2[i];

53

SolutionCoordX3border[0] = filteredX3[i];

54

//pokud je výsledná hodnota účelové funkce u hraničních průsečíků stejná jako u průsečíků 63

//pokud je výsledná hodnota účelové funkce u hraničních průsečíků lepší než u průsečíků 68

2.3.4 Grafické zobrazení všech typů výsledků

Vyobrazení výsledků je poměrně složité, jelikož může nastat několik případů. V první fázi je nutné odlišit tři typy výstupů, které mohou nastat.

První možností je, že proměnné valueEqual a valueBetter zároveň nabývají hodnoty false.

V tomto případě se optimální řešení nachází v množině základních přípustných řešení.

V takovém případě je nejprve vykreslován objekt, jehož vrcholy jsou všechny body z množiny základních přípustných řešení. Tyto vrcholy jsou pak v grafu vyznačeny jako modré body. Poté je třeba vykreslit optimální řešení. To může mít trojí podobu. Řešením může být bod, úsečka nebo rovinná výseč. O jaké řešení se jedná, poznáme z délky pole, v němž jsou uloženy souřadnice výsledných bodů. Pokud je délka pole rovna jedné, výsledkem je bod. Pokud je délka pole rovna dvěma, výsledkem je úsečka mezi dvěma body, které máme v poli. Jestliže je délka pole rovna třem, výsledkem je rovinná výseč.

Druhou možností je, že hodnota proměnné valueEqual je rovna true. To nastane, pokud hledaný extrém účelové funkce, má stejnou hodnotu v bodě ze základních přípustných řešení jako v bodě z hraničních přípustných řešeních. Optimálním řešením je v tomto případě polopřímka, případně polorovina či rovinná výseč. Počáteční bod této polopřímky je ten bod ze základních přípustných řešení, se kterým hledaná účelová funkce nabývá extrému. Směr této polopřímky je určen pomocí bodu z hraničních přípustných řešení, v němž hodnota účelové funkce taktéž nabývá extrému. Při vykreslování roviny nebo rovinné výseče jsou sloučeny pole výsledných bodů ze základních přípustných řešení a pole výsledných bodů z hraničních přípustných řešení.

Třetí možností je, že hledaný extrém účelové funkce má „lepší“ hodnoty v nějakém bodě z hraničních přípustných řešení než v bodě z množiny základních přípustných řešení.

V takovém případě je hodnota proměnné valueBetter rovna true. To znamená, že neexistuje optimální řešení, jelikož hodnota účelové funkce je neomezená. V tomto případě je v grafu vykreslena pouze množina přípustných řešení, která pokračuje do nekonečna ve směru žlutých bodů (tyto body pouze pomáhají vyznačit směr, nemají jiný účel). Uživateli je zobrazena hláška, že optimální řešení neexistuje (viz obrázek 28).

Pokud nastane situace, kdy uživatel zadá úlohu, která má prázdnou množinu přípustných řešení, jelikož poloprostory omezení se „rozcházejí“, je upozorněn hláškou, algoritmus je zastaven a dále nepokračuje. Taková situace se pozná, pokud pole FeasiblePointsX1, FeasiblePointsX2, FeasiblePointsX3 jsou prázdná, tedy nemáme žádná základní přípustná řešení. V tomto případě je zobrazen pouze graf se zadanými omezeními.

2.3.5 Použití knihovny Plotly k vykreslení grafu Implementace knihovny

Knihovna je do webové aplikace implementována pomocí odkazu ke stažení ze CDN

v rodičovském elementu body. To zajišťuje, že se při každém načtení webové stránky stahuje nejaktuálnější verze této knihovny.

<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>

Příprava knihovny

V počáteční fázi je na stránce vytvořen prázdný div s unikátním identifikátorem, do něhož je poté vykreslován graf. Následuje vytvoření konstanty v Javascriptu, do které je přiřazen objekt daného „divu“. Dalším potřebným krokem je vytvoření dvou konstant layout a config. Tyto dvě konstanty jsou objekty, ze kterých si později knihovna shromažďuje nastavení pro graf, více o těchto proměnných dále (Vykreslování).

Vykreslování

K vykreslování slouží především dvě funkce. Funkce newPlot a funkce addTrace.

V popisované aplikaci je třeba do grafu postupně přidávat velké množství objektů různých typů, proto po stisknutí tlačítka „Plot!“ je nejprve pomocí funkce newPlot vykreslen prázdný graf a do něj se v průběhu výpočtu přidávají objekty.

Plotly.newPlot(myDiv, [], layout, config);

Prvním parametrem funkce newPlot je myDiv. To je objekt, ve kterém je uložen odkaz na samotný předpřipravený HTML element (typu div), do něhož se graf vykresluje.

Do prázdných hranatých závorek by se většinou vkládal objekt skládající se z dat pro graf, typu objektu a dalších popisných parametrů. Zde jsou pouze prázdné závorky, jelikož zatím je vytvářen prázdný graf.

V objektu layout je potřeba nastavit některé parametry, které určují rozložení grafu.

Například se zde určuje velikost písma nebo názvy os grafu (viz výpis 8).

Výpis 8 Konstanta layout (zdroj: autor)

title: 'x<sub>1</sub>', },

yaxis: {

title: 'x<sub>2</sub>', },

zaxis: {

title: 'x<sub>3</sub>', }

} };

V objektu config se nastavují další parametry pro graf. V případě této aplikace tak, aby byl graf responzivní, tedy zabíral vždy maximální plochu v přiřazeném HTML elementu, a aby nebylo zobrazeno logo vykreslovací knihovny.

const config = {responsive: true, displaylogo: false,};

V průběhu algoritmu se přidávají do „prázdného“ grafu různé typy objektů, a to pomocí funkce addTraces. Na následujícím výpisu (výpis 9) lze například vidět, jak jsou

V průběhu algoritmu se přidávají do „prázdného“ grafu různé typy objektů, a to pomocí funkce addTraces. Na následujícím výpisu (výpis 9) lze například vidět, jak jsou