Dynamické barvy
Využití zaškrtávacího políčka
Následující applet je určen jako demonstrace řešení jedné úlohy Matematické olympiády. Při řešení je třeba sestrojit větší počet úseček a jejich průsečíků, přičemž v každém kroku nás zajímají jen některé, zatímco ostatní spíše překážejí.[br]Jednak tedy můžeme ty překážející úsečky skrýt (pomocí Podmínky zobrazení objektu) nebo naopak ty důležité barevně zvýraznit.[br]V appletu je dostupné menu, takže je možné zjistit, jak jsou nastaveny dynamické barvy úseček a bodů:[br]například bod G má vlastnost [i]RGB Dynamické barvy[/i] nastavenu tak, aby po zaškrtnutí [i]políčka[/i][br]s názvem[size=100] [color=#ff0000]s[/color][/size] (řešení – 3. část) zčervenal, jinak bude černý: [br]Červená:[color=#ff0000] s[/color] Zelená: 0 Modrá: 0
Podmínka zobrazení objektu a dynamické barvy
Zvýraznění silnějšími čarami a většími body
Pokud nestčí změna barvy, můžeme změnit také "mohutnost" objektů. Ale na rozdíl od dynamických barev, není možné tloušťku čáry či velikost bodu nastavit dynamicky přímo ve vlastnostech objektu,[br]ale stačí na to Geogebra Script, který se vykoná při změně stavu zaškrtávacího políčka.[br]Začneme tedy trochu skriptovat.[br]K jednotlivým tlačítkům ošetříme událost OnClick.[br][br]Každé zaškrtávací políčko nese skript [i]Po aktualizaci[/i], který (stejně jako výše u dynamických barev) využívá toho, že logická hodnota true se může vyjádřit hodnotou 1 a false hodnotou 0. [br]Pro políčko [b]o[/b] zvýrazňující první část konstrukce (úsečky t, k, j, n a body I, F, H) to je: [br][br]SetLineThickness( t, 1+3*o ) [br]SetLineThickness( k, 1+3*o ) [br]SetLineThickness( j, 1+3*o ) [br]SetLineThickness( n, 1+3*o ) [br]SetPointSize( I, 3+2*o ) [br]SetPointSize( F, 3+2*o ) [br]SetPointSize( H, 3+2*o )[br]SetPointStyle( I, 2-2*o ) [br]SetPointStyle( F, 2-2*o )[br]SetPointStyle( H, 2-2*o )
Silnější čáry a větší body
Změna vzhledu po kliknutí na objekt - javascript
Listeners
Listener je funkce, která reaguje na nějakou událost v appletu.[br]Musíme ji jednak naprogramovat, jednak ji musíme při načítání appletu "registrovat", k čemuž jsou v GeoGebra Apps API připravené funkce.[br]V našem appletu tedy máme:[br][br]function ggbOnInit() {[br] ggbApplet.registerClickListener("vyznac");[br]}[br][br]Funkci daného jména naprogramujeme tak, aby po kliknutí na objekt s názvem [color=#ff0000]AA[/color] vyznačení všech objektů zrušila a po kliknutí na kterýkoliv jiný objekt tento zvýraznila (předepsaným způsobem).[br][i]Poznámka:[/i] V appletu ani nepoužíváme tlačítko, jen bod – jen jako demonstraci, že se nemusí klikat vždy jen na tlačítko. Ale mohlo by, samozřejmě.[br][br]Funkce si ještě zaslouží komentář, dvě větve podmínky (ošetření, je-li objekt, na který klikáme, ovladač,[br]nebo vyznačovaný objekt v konstrukci) jsou zde úmyslně řešeny různě, [br]první (if (par == "AA")) trochu nedbale, nestará se o typ objektu (a v tomto případě to nevadí), [br]druhá větev (else) je napsána pečlivěji a zkoumá, jestli jsme kliknuli na bod nebo čáru. Někdy (jindy) se to může hodit.[br][br]function vyznac(par) {[br] var typ = ggbApplet.getObjectType(par); [color=#3c78d8]// zjistíme, nač jsme kliknuli[/color][br] if (par == "AA") { [color=#3c78d8]// když je to klikátko-tlačítko (které ruší zvýraznění)[/color][br] var pocet = ggbApplet.getObjectNumber();[br] for (i = 0; i < pocet; i++) { [color=#3c78d8] // projedeme všechny objekty[/color][br] var jmeno = ggbApplet.getObjectName(i);[br] if (jmeno != "AA") { [color=#3c78d8] // a pokud ten objekt není to naše klikátko[/color][br] ggbApplet.setLineThickness(jmeno, 2);[br] ggbApplet.setPointSize(jmeno, 3);[br] ggbApplet.setColor(jmeno, 0, 0, 0);[br] } [color=#3c78d8]// nastavíme mu "tuctový" vzhled[/color][br] }[br] } else { [color=#6aa84f] // pokud jsme ale klikli na objekt, tak ho chceme zvýraznit[/color][br] if (typ != "point") {[br] ggbApplet.setLineThickness(par, 8); [color=#6aa84f]// a tak bude čára tlustší[/color][br] } else {[br] ggbApplet.setPointSize(par, 6); [color=#6aa84f]// a bod větší[/color][br] }[br] ggbApplet.setColor(par, 255, 0, 0); [color=#ff0000]// a jakýkoliv objekt červený[/color][br] }[br]}[br][br]Kód, který provádíme se všemi objekty, můžeme také úsporněji[br]zapsat pomocí javascriptové iterace přes prvky pole:[br]pole.forEach(nejaka_funkce); [br]například napíšeme-li si funkci s názvem zbledni, pak zapíšeme:[br][br]var prvky = ggbApplet.getAllObjectNames(); [br]prvky.forEach(zbledni);
Kliknutím na "Vrátit vzhled" zrušíme zvýraznění všech objektů
Klik tam a klik zpátky
Pokud nám nevyhovuje hromadné rušení zvýraznění (třeba se jen "uklikneme" a chceme zrušit zvýraznění jen toho jednoho objektu), můžeme z aktuálního stavu objektu nějak poznat, zda je zvýrazněný nebo ne, a podle toho kliknutím stav změníme. To jde řešit různě. Třeba zkoumat barvu... [br]Nebo k tomu účelu využijeme nějakou zrovna nepoužívanou vlastnost. V naší ukázce je to vrstva objektu. V appletu jsme nepotřebovali objekty skládat do vrstev, tak si to můžeme dovolit.[br]Pak v appletu není žádné tlačítko pro vrácení vzhledu a reakce na kliknutí vypadá například takto:[br][br]function vyznac(par) {[br] var i = ggbApplet.getLayer(par); [color=#3c78d8]// zjistíme, ve které vrstvě objekt leží (nevyznačené leží v 0)[/color][br] ggbApplet.setLayer(par, Math.abs(1 - i)); [color=#3c78d8]// a změníme ji 0 <--> 1[/color][br] var typ = ggbApplet.getObjectType(par); [color=#3c78d8]// stejné jako nahoře, můžeme se starat o typ a nemusíme[/color][br] if (i == 1) { [color=#3c78d8]// byl-li objekt zvýrazněný (ve vrstvě 1)[/color][br] ggbApplet.setLineThickness(par, 2); [color=#3c78d8]// nastavíme mu "tuctový" vzhled[/color][br] ggbApplet.setPointSize(par, 3);[br] ggbApplet.setColor(par, 0, 0, 0);[br] } else { [color=#6aa84f]// jinak (ve vrstvě 0)[/color][br] if (typ != "point") {[br] ggbApplet.setLineThickness(par, 8); [color=#6aa84f]// čára bude tlustší[/color][br] } else {[br] ggbApplet.setPointSize(par, 6); [color=#6aa84f]// a bod větší[/color][br] }[br] ggbApplet.setColor(par, 255, 0, 0); [color=#ff0000]// a kterýkoliv objekt červený[/color][br] }[br]}[br]
Návrat vyznačených objektů k původnímu vzhledu
Barva, síla, ... ale cokoliv
Pro návrat k původnímu vzhledu je třeba při zvýraznění uložit výchozí stav. Použijeme k tomu pole. V javascriptu může být pole "děravé", což se nám bude hodit, pokud bychom barvu (či jiné atributy vzhledu nastavovali) jen pro některé objekty. Můžeme totiž chtít mít zvýrazněných několik objektů současně a ty pak vrátit na jejich (třeba každého jiný) výchozí stav.[br][br]Funkce vypadá docela podobně, jen je delší jednak o ukládání do pole,[br]jednak o použití uložené barvy. Příkaz setColor totiž vyžaduje zadat barvu po složkách, zatímco funkce getColor získá barvu jako jedno hexadecimální číslo.[br][br]Jako indikátor toho, zda je objekt zvýrazněn, opět použijeme vrstvu.[br][br]function ggbOnInit() {[br] ggbApplet.registerClickListener("emph");[br]}[br]var colors = []; // pole na barvy[br]var sizes = []; // pole na velikosti bodů[br]var thicks = []; // pole na síly čar[br][br]function emph(par) {[br] var i = ggbApplet.getLayer(par);[br] ggbApplet.setLayer(par, Math.abs(1 - i));[br] var index = 0;[br] while (ggbApplet.getObjectName(index) != par) { [br] index++; // zjistíme, jaké číslo má v konstrukci objekt, na který jsme kliknuli [br] } // a to bude index do polí s vlastnostmi [br] if (i == 0) { [color=#3c78d8] // chceme zvýrazňovat[/color][br] colors[index] = ggbApplet.getColor(par); [color=#3c78d8] // uložíme původní stav[/color][br] thicks[index] = ggbApplet.getLineThickness(par);[br] sizes[index] = ggbApplet.getPointSize(par);[br] ggbApplet.setLineThickness(par, 8); [color=#3c78d8]// a zvýrazníme[/color][br] ggbApplet.setPointSize(par, 6);[br] ggbApplet.setColor(par, 255, 0, 0);[br] } else { [color=#3c78d8] [color=#6aa84f]// chceme se vrátit k původnímu stavu[/color][/color] [br] ggbApplet.setLineThickness(par, thicks[index]); [color=#6aa84f]// obnovíme původní sílu čáry a velikost bodu[/color][br] ggbApplet.setPointSize(par, sizes[index]);[br] var saved = colors[index]; [color=#6aa84f]// vezmeme původní barvu a rozebereme na složky[/color][br] var ur = parseInt(saved.substr(1, 2), 16);[br] var ug = parseInt(saved.substr(3, 2), 16);[br] var ub = parseInt(saved.substr(5, 2), 16);[br] ggbApplet.setColor(par, ur, ug, ub); [color=#6aa84f]// ... a vrátíme[/color][br] }[br]}[br][br]Jednodušší varianta pak uloží všechny barvy (či další vlastnosti) hned po načtení appletu, tedy ve funkci ggbOnInit().[br]var prvky = [];[br]var barvy = [];[br]function ggbOnInit() {[br] ggbApplet.registerClickListener("obarvi");[br] prvky = ggbApplet.getAllObjectNames(); [br] prvky.forEach(ulozBarvu);[br]}[br]
Kliknutím přepínáme zvýraznění a původní stav, i pro více objektů zároveň
Poslední sestrojený prvek při krokování konstrukce
Krokování konstrukce
Budeme potřebovat postupně krokovat připravenou složitější konstrukci a nespokojíme se buď s tím, jak je zvýrazněný poslední objekt (budeme chtít výraznější vyznačení). Nebo nejsme spokojeni s tím, že je zvýrazněný jenom jeden (naposledy sestrojený) objekt a budeme chtít, aby souvislosti posledních kroků zůstávaly viditelné, zvýrazněné. Připravené ukázky se tedy budou lišit tím, zda dříve sestrojené objekty postupně ztrácejí výraznost, nebo zda zdůrazňujeme jen dosud poslední sestrojený objekt. [br][br]Pokud navíc krokujeme konstrukci pomocí bodů zastavení (a to se děje velmi často, protože v konstrukci bývá hodně "samozřejmých" konstrukčních čar, jejichž sestrojení přeskakujeme, aby nebylo krokování příliš dlouhé), bude potřeba zvláštní pozornosti. [br][br]Ke zvýraznění jsme použili číslo [color=#0000ff][i]krok[/i][/color] definované jako [color=#0000ff]ConstructionStep() [/color], tedy jako pořadové číslo prvku, který se právě sestrojil.[br]Aktivace bodů zastavení hodnotu objektu [color=#0000ff][i]krok[/i][/color] nijak neovlivní, vždy se jedná o číslo objektu v konstrukci, nikoli o číslo snímku-zastávky v nastaveném krokování.[br][br]Objekt [color=#0000ff][i]krok[/i][/color] využijeme pro skriptování: nebudeme psát skripty pro jednotlivé objekty ani definovat funkci sloužící jako Listener, ale ošetříme událost [color=#0000ff]OnUpdate[/color] objektu [color=#0000ff][i]krok[/i][/color].[br]Celý javascript je velmi krátký:[br][br]Na kartě [color=#0000ff]OnUpdate[/color] objektu [color=#0000ff][i]krok[/i][/color] naprogramujeme:[br][br]var pocet = ggbApplet.getObjectNumber(); [color=#3c78d8]// počet objektů v konstrukci[/color][br]var j = 1;[br]for (i = 1; i < pocet; i++) { [color=#3c78d8] // všem objektům v konstrukci[/color] [color=#3c78d8]určíme tloušťku čáry[/color][br] j = Math.max(1, 8 + i - ggbApplet.getValue("krok")); [color=#3c78d8]// nedávno sestrojeným větší, starším 1[/color][br] ggbApplet.setLineThickness(ggbApplet.getObjectName(i), j); [color=#3c78d8] // nastavíme ji[/color][br]};[br](viz první ukázka níže)[br]To, že měníme atributy objektů, které ještě nejsou sestrojené, v tomto případě nevadí. V této ukázce navíc neřešíme, jestli je objekt opravdu čára, a neměníme vlastnosti bodů. Jak zjistit typ objektu jsme[br]ukázali v předchozích kapitolách.[br][br][color=#ff0000]Pozor na to, že [/color][color=#0000ff]ggbApplet.getObjectNumber() [color=#ff0000]udává skutečný počet objektů v konstrukci[/color][/color][color=#ff0000], zatímco [/color][color=#0000ff]ConstructionStep()[/color] [color=#ff0000]počítá počet příkazů. Jakmile tedy sestrojíme například čtverec, začnou se tato dvě čísla lišit.[/color][br][br]V konstrukcích, kde sestrojíme každý bod či čáru samostatně, návod můžeme použít tak, jak je.[br][br]Jinak můžeme zkusit dotázat se na konstrukční krok daného prvku [color=#0000ff]ConstructionStep(object)[/color] a testovat ten. Tady už je ale třeba dát pozor jednak na dotaz na objekty, které zatím (v dané fázi krokování) nejsou sestrojeny – u nich se nemůžeme ptát na jejich konstrukční krok –, jednak na cyklické odkazy, které tak mohou snadno vzniknout.[br][br]Následující postup předpokládá, že v appletu máme volnou[br]číselnou proměnnou kr pro zjištění kroku konstrukce[br]aktuálně zpracovávaného prvku. Objekt krok je ve[br]shodě s výše uvedenými postupy definován jako aktuální krok konstrukce ConstructionStep().[br][br]Podobně jako výše můžeme pracovat rovnou s polem názvů[br]objektů a provedeme iteraci přes všechny prvky pole forEach():[br][br]var prvky = ggbApplet.getAllObjectNames();[br]prvky.forEach(nastavSilu);[br][br]function nastavSilu(prvek) {[br] if (ggbApplet.isDefined(prvek)) {[br] ggbApplet.evalCommand("SetValue(kr,ConstructionStep(" + prvek + "))"); [color=#0000ff]// aktuální krok[/color][br] var p = ggbApplet.getValue("kr");[br] var k = ggbApplet.getValue("krok");[br] j = Math.max(1, 8 + p - k);[br] ggbApplet.setLineThickness(prvek, j);[br] }[br]}[br](viz druhá ukázka níže)[br]Ukázky se na pohled neliší (jsou zde pro stažení) protože v konstrukci nejsou objekty typu mnohoúhelník, které způsobí to, že se rozejte pořadí příkazu s číslem objektu v konstrukci.
Postup, kde nehlídáme rozdíl mezi číslem v poli objektů a pořadovým čislem v konstrukci
Postup důsledně kontrolující konstrukční kroky
Přístup "všechno nebo nic"
Pokud budeme trasovat opravdu každý konstrukční krok, můžeme být striktnější a používat jen dvě tloušťky čar.[br]A nebo tři, čtyři, když dopíšeme nastavení pro předposlední, předpředposlední,... krok. [br]Ilustrujeme jen zmíněný přístup "všechno nebo nic".[br][br]var pocet = ggbApplet.getObjectNumber();[br]var j = 1;[br]for (i = 0; i < pocet; i++) {[br] j = (i + 1 == ggbApplet.getValue("krok")) ? 8 : 1;[br] ggbApplet.setLineThickness(ggbApplet.getObjectName(i), j);[br]};[br][br]V níže vloženém appletu, kde jsou použité body zastavení, nedělá to, co bychom si přáli.
Takhle raději ne, to nefunguje
Podobně s barvami
Analogie téhož:[br][br]var pocet = ggbApplet.getObjectNumber();[br]var kr = ggbApplet.getValue("krok");[br]for (i = 0; i < pocet; i++) {[br] if ((kr-1 - i) < 4) {[br] ggbApplet.setColor(ggbApplet.getObjectName(i), 255, 0, 0);[br] } else {[br] ggbApplet.setColor(ggbApplet.getObjectName(i), 0, 0, 0);[br] }[br]}