Přejít k navigační liště

Zdroják » JavaScript » JAK podruhé: vektory a animace

JAK podruhé: vektory a animace

Další nahlédnutí pod pokličku Seznamu představí možnosti knihovny JAK. Kromě „neviditelných“ nástrojů pro práci s OOP, událostmi a HTTP požadavky obsahuje knihovna JAK i moduly pro grafické manipulace a animace. Právě na tyto moduly se v dnešním volném pokračování článku o knihovně JAK zaměříme.

<jarda> bez nas by to nebylo ono
<emil> tak to jsem zvedav
<lojza> aha, emil je tu taky :-(

Vektory

Základním nástrojem pro kreslení v HTML pomocí JAKu je takzvaný vektorový canvas. Jde o prázdný prvek s pevnými rozměry, do kterého můžeme umísťovat geometrická primitiva – kruhy, čáry a mnohoúhelníky. Podle prohlížeče, který máme, JAK použije buďto technologii SVG, nebo VML. Pozor – tento vektorový canvas nemá nic společného s HTML prvkem <canvas>.

var platno = JAK.Vector.getCanvas(800, 600);
document.body.appendChild(platno.getContainer());
<emil> a v jakych prohlizecich to vubec bude fungovat?
<jarda> v tech, co dobre podporuji SVG - firefox, opera, safari, chrome
<lojza> a take v internet exploreru, pocinaje verzi 6
<emil> fuuuj!

Teď je čas přidat geometrické prvky. Máme pro to k dispozici tato geometrická primitiva:

  • JAK.Vector.Cir­cle – kruh, kružnice nebo obojí
  • JAK.Vector.Line – jednoduchá nebo dvojitá (lomená) čára, volitelně s hladkými zlomy
  • JAK.Vector.Po­lygon – mnohoúhelník s volitelným orámováním
  • JAK.Vector.Path – obecná posloupnost čar, křivek a oblouků

Veškeré souřadnice pro zadávání prvků se specifikují jako instance třídy JAK.Vec2d. Zkusme tedy přidat do canvasu kruh a čáru:

var polomer = 100;
var stred = new JAK.Vec2d(400, 400); // rozmery platna
var vzhled = {
    color: "red",
    outlineColor: "black",
    outlineWidth: 8
};
var kruh = new JAK.Vector.Circle(platno, stred, polomer, vzhled);
var souradnice = [
    new JAK.Vec2d(50, 50),
    new JAK.Vec2d(50, 350),
    new JAK.Vec2d(350, 350),
    new JAK.Vec2d(350, 50),
    new JAK.Vec2d(50, 50)
];
vzhled = {
    color: "blue",
    outlineColor: "darkblue",
    width: 5,
    outlineWidth: 5,
    opacity: 0.5
};
var cara = new JAK.Vector.Line(platno, souradnice, vzhled);

<lojza> koukam, ze prvni parametr konstruktoru je to platno, do ktereho se prvek nakresli
<emil> je nekde soupis vsech tech parametru vzhledu? jde mi z nich hlava kolem...
<jarda> jasne - prece na strance projektu, http://jak.seznam.cz/example/graphics/

Nakonec ještě ukázka objektu JAK.Vector.Path, který patří k těm složitejším. Jeho hlavním (druhým) parametrem je tzv. „formátovací řetězec“, posloupnost znakových instrukcí, popisujících výsledný útvar. Zde použijeme tyto:

  • M – posun na souřadnici
  • A – eliptický oblouk
  • Z – uzavření cesty
var format = "M 80 100 A 50 80 0 1 1 80 300 Z M 320 100 A 50 80 0 1 0 320 300 Z";
var krivka = new JAK.Vector.Path(platno, format, vzhled);

<emil> ja se teda zatim docela drzel. ale tenhle "formatovaci retezec", to je imho kapitalni konina,
       co si to probuh zase vymysleli?
<lojza> no a pritom vidis, emile -- tenhle retezec je leta znamy a dodrzovany standard
        viz http://www.w3.org/TR/SVG/paths.html

PieChart a LBChart

Pomocí výše uvedených geometrických tvarů lze vyrábět i složitější konstrukce, například grafy. V JAKu jsou rovnou připraveny widgety na koláčové, čárové a sloupcové grafy.

Koláčový graf

Koláčový graf se vytvoří v HTML prvku, jehož ID je prvním parametrem konstruktoru. Tento prvek musí mít určené rozměry – graf svou velikost automaticky dopočítá tak, aby se akorát vešel. Vstupem je jedna datová sada; každá její položka je dvojice hodnota a popisek. Veškeré parametry grafu a další nastavení vzhledu upřesníme v posledním parametru, kterým je konfigurační objekt.

/* vstupni data */
var vydaje = [
    {data:11, label:"propisky" },
    {data:4, label:"papíry" },
    {data:2, label:"kancelářské svorky" },
    {data:8, label:"post-it" },
    {data:15, label:"káva" },
    {data:10, label:"cukr" },
    {data:8, label:"mléko" },
    {data:20, label:"rum" }
];

/* konfiguracni objekt */
var vzhled = {
    padding: 40,
    legend: "left"
};
new JAK.PieChart("IDprvku", vydaje, vzhled);

<jarda> tady kluci vidite, jak vypadala spotreba nasi firmy za minuly rok.
        ta cisla jsou v statisicich korun...
<lojza> neni zverejnovani takovych udaju poruseni nejakeho narizeni o obchodnim tajemstvi?

Čárový a sloupcový graf

Oba tyto grafy jsou kvůli podobnosti sloučeny do jedné třídy, JAK.LBChart. Vstupem je tentokrát množina datových sad; každá sada se zobrazí pomocí lomené čáry, nebo několika sloupců. Tyto dva způsoby zobrazení lze navíc také kombinovat.

Popisky grafu (na ose X) jsou ale pro všechny datové sady společné, proto se zadávají zvlášť, jako třetí parametr. Popisky na ose Y (jejich hodnoty a rozestup) se počítají automaticky, ale lze je ovlivňovat v konfiguračním objektu:

  • rows.count – přibližný cílový počet popisků (budou voleny ±1 tak, aby vyšly na „pěkná“ čísla)
  • zero – má-li osa Y zahrnovat nulu
  • min – nejmenší hodnota na ose Y
  • max – největší hodnota na ose Y

Konfigurační objekt dále určuje umístění legendy, vzhled sloupců, zobrazování os a další. Pro kompletní výpis je opět nejlepší navštívit domovskou stránku.

/* vstupni data */
var produktivita = [
    {
        label: "Jarda",
        data: [10, 12, 14, 16],
        type: "bar"
    },

    {
        label: "Lojza",
        data: [8, 7, 10, 11],
        type: "line",
        marker: JAK.Marker.Circle
    },

    {
        label: "Emil",
        data: [8, 9, 5, 2],
        type: "line",
        marker: JAK.Marker.Triangle
    }
];
var osaX = ["Leden", "Únor", "Březen", "Duben"];
/* konfiguracni objekt */
var vzhled = {
    padding: 40,
    barWidth: 30,
    lineWidth: 3,
    markerSize: 12,
    zero: true,
    legend: {
        draw: "right",
        width: 20
    }
};
new JAK.LBChart("IDprvku", produktivita, osaX, vzhled);

<emil> ou jee, barvickyyyy!
<lojza> ja s emilem mame caru, zatimco vedouci jarda ma sloupce - tak to je ovsem nefer
<jarda> budte radi, cary jsou hezci, muze u nich byt ta mala znacka
<lojza> kolecko, trojuhelnicek, ctverecek, krizek nebo plus

Interpolátory a animace

Animování prvků na stránce je docela běžná věc, ať jde o plynulé zmenšování a schovávání objektů, nebo „zprůhledňování“. Všechny takové animace mají jednu věc společnou: dochází k periodickému měnění jedné nebo více vlastností, typicky rozměrů, souřadnic, průhlednosti či barvy. Koncept průběžného měnění nějaké hodnoty je zobecněn do podoby tzv. „interpolátoru“ – objektu, který během dané doby opakovaně vykonává námi poskytnutou funkci a jako parametr jí poskytuje měnící se číslo. Podívejme se, jak se takový interpolátor vyrábí:

var start = 100;
var stop = 300;
var trvani = 2000;
var i = new JAK.Interpolator(start, stop, trvani, alert);
i.start();

Interpolátoru tedy zadáváme zejména počáteční a koncové hodnoty a také dobu, během které má celý proces probíhat (v milisekundách). Čtvrtým parametrem je funkce, kterou si přejeme periodicky vykonávat. Ta bude volána s parametrem, nabývajícím postupně hodnot od 100 do 300. Kolikrát se tato funkce vykoná? Těžko říct, zpravidla to není důležité. Ve výchozím nastavení každých 20 milisekund, ale tuto hodnotu je možno určit v posledním, volitelném parametru.

Odbočka pro starší a pokročilé – vlastní interpolační funkce

Možná se ptáte, jakým způsobem je počítána hodnota mezi 100 a 300. Pro tento účel je definována matematická funkce, která zobrazuje časový interval [0,1] na hodnotový interval [0,1]. Tuto interpolační funkci lze měnit pomocí vlastnosti interpolation konfiguračního objektu, který předáváme jako pátý parametr. Následující ukázka dává najevo, že existuje řada předdefinovaných interpolačních funkcí – také je ale možno zadat svoji.

var konfigurace = {};
konfigurace.interpolation = JAK.Interpolator.LINEAR;    // linearni, vychozi
konfigurace.interpolation = JAK.Interpolator.QUADRATIC; // kvadraticka
konfigurace.interpolation = JAK.Interpolator.SQRT;      // druha odmocnina
konfigurace.interpolation = JAK.Interpolator.SIN;       // sinus na [-pi/2, pi/2]
konfigurace.interpolation = JAK.Interpolator.ASIN;      // inverze predchoziho
konfigurace.interpolation = function(value) {           // vlastni interpolacni funkce
    return 1- Math.sqrt(value);
};
var start = 100;
var stop = 300;
var trvani = 2000;
var i = new JAK.Interpolator(start, stop, trvani, alert, konfigurace);
i.start();

Specializovaný interpolátor CSS

Pokud je cílem naší animace jen změna nějakého CSS parametru, může být třída JAK.Interpolator příliš obecná a těžkopádná. Pro tyto účely existuje specializovaná varianta, JAK.CSSInterpo­lator. Ta podporuje změnu několika vlastností naráz – číselných i barevných.

var prvek = JAK.gel("mojeid");
var i = new JAK.CSSInterpolator(prvek, 2000);          // druhy parametr je delka trvani (2s)
i.addProperty("width", 200, 0, "px");                  // sirka z 200 do 0 pixelu
i.addColorProperty("backgroundColor", "#000", "#fff"); // barva pozadi z cerne na bilou
i.start();
<lojza> "interpolator", to zni jako nazev noveho filmu s arnoldem schwarzeneggerem
<emil> mne to teda moc zavani matikou, takze tuhle kapitolu preskakuju
<emil> jak vidim nekde sinus, beru nohy na ramena

Timekeeper – animační dirigent

V poslední části článku ještě představíme jeden z novějších modulů JAKu, zvaný Timekeeper. Motivací pro jeho vznik byla potřeba udržovat větší množství animací zároveň, ale tak, že animace trvají různě dlouho a nemusí se nutně zcela překrývat (jinak by stačil normální interpolátor). Mít pro každou animaci vlastní interpolátor je výkonově nevýhodné, proto byl vytvořen tento modul.

Timekeeper je jedináček, takže s ním vždy pracujeme pomocí JAK.Timekeeper­.getInstance(). Funguje jako jakýsi metronom: v krátkých intervalech periodicky dává okolnímu světu vědět, že se něco děje. Každý, kdo o tom chce být notifikován, se u Timekeeperu musí nejprve zaregistrovat:

var MojeTrida = JAK.ClassMaker.makeClass({
    NAME: "MojeTrida",
    VERSION: "1.0"
});
MojeTrida.prototype.$constructor = function(jakCasto) {
    JAK.Timekeeper.getInstance().addListener(this, "tick", jakCasto);
}
MojeTrida.prototype.tick = function() {
    /* ... */
}
new MojeTrida(10);

Parametry metody addListener jsou tedy (v tomto pořadí): volaný objekt, název jeho metody a frekvence. Timekeeper tiká každých 20 milisekund, celočíselný třetí parametr říká, při kolikátém tiknutí se má metoda vykonat. V tomto případě tedy bude metoda tick pouštěna pětkrát do vteřiny. Druhá (a poslední) metoda Timekeeperu se jmenuje removeListener a celkem přímočaře ukončuje poslouchání tikání. Tímto způsobem je možno řídit velké množství opakovaných akcí, přestože na pozadí systému je jen jednou použita JavaScriptová funkce setInterval.

<emil> jenze chlapi, kdyz nechci ten metronom poslouchat, tak je trochu zbytecny, aby tikal, ne?
<jarda> vsak on take ten metronom netika, dokud neni zadny posluchac
<lojza> ba co vic - kdyz se odvesi posledni posluchac, tak se metronom zastavi

A to je vše. Snad několik obrázků vynahradilo velké množství zdrojového kódu v tomto článku; k posledním dvěma částem (interpolátory a Timekeeper) bohužel obrázky být nemohou. Ukázali jsme principy práce s vektorovou grafikou na bázi SVG či VML, animace i grafy – takřka vše, co z grafiky JAK nabízí. A protože JAK je vyvíjen jako OpenSource na Githubu, těším se na první uživatelské commity a pull requesty…

Tento článek navazuje volně na článek JAK: JavaScriptová knihovna z dílny Seznamu

Komentáře

Subscribe
Upozornit na
guest
0 Komentářů
Inline Feedbacks
View all comments

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.