Sloupcový graf pomocí <div>

Připravíme si pomocný obrázek bar.png, který uzavřeme do kontejneru s přiřazenou pozicí relative. Uvnitř kontejneru můžeme obrázek pozicovat jako absolute a budeme měnit jeho rozměry pomocí CSS. Pro svislý graf ponecháme konstantní width, změnou souřadnic height a top vykreslíme obrázek podle potřeby. Souřadnice obrázku se udávají k levému hornímu rohu kontejneru. Praktické příklady můžete vidět v ukázkách Spotřeba surovin, nebo Energetika.

 

Vlevo vidíte příklad zjednodušeného grafu z úvodní stránky aplikace Protokoly výroby. Na tomto příkladu si vysvětlíme základy kreslení sloupcového grafu. Následně uvedu rozšířený příklad sloupcového grafu ze stejné aplikace a pokusím se popsat některé z dalších možností.


<style type="text/css">
.card {width: 240px; height: 165px; position: relative;}
.cont {position: relative; width: 14px; height: 165px; float: left;}
.bar  {position: absolute; width: 13px; left: 0;}
</style>

<body>

<div class="card">
...
<div class="cont">
<img class="bar" style="top: 85px; height: 75px;" src="bar.png">
</div>
...
</div>

</body>

CSS třída card bude sloužit pro vymezení kreslící plochy grafu. Následující třídy cont, bar a v další ukázce i mark slouží pro každý sloupec kresleného grafu. Třída cont je kontejner pro jednotlivé sloupce grafu. Do tohoto prvku budeme vkládat obrazové prvky img. Důležitá je pozice kontejneru relative, což nám umožní využít uvnitř tohoto tágu pozicování typu absolute. Dále kontejneru nastavíme float: left;, aby se jednotlivé sloupce grafu řadily za sebou. Šířka kontejneru je o jeden pixel větší, než šířka sloupce bar a jednotlivé sloupce grafu budou oddělěny mezerou jeden pixel. Obrazové části grafu bar a (mark) jsou typu img a jejich pozice jsou typu absolute, konstantní část pozic je uvedena v deklaraci CSS, proměná část pozic je doplněna do in-line stylu podle výpočtu skriptu na serveru.

HTML část ukázky obsahuje vymezení kreslící oblasti pomocí <div class="card" ... a kreslení jednoho sloupce grafu <div class="cont" ... Obrazový prvek img má přiřazen in-line styl, ve kterém jsou stanoveny pozice top a height, určené výpočtem na serveru. Souřadný systém do kterého kreslíme sloupec má počátek v levém horním rohu konteineru.

 

 
sortiment
datum
plán

Jednoduchý graf nyní rozšíříme. Přidáme pozadí grafu, přidáme další grafický prvek označující žádanou hodnotu (zde stanovený výrobní plán) a rozšíříme o funkce pro zobrazení číselných hodnot v legendě pod grafem a navigaci pro přechod na stránku připravenou pro tisk výrobního protokolu. Pokud máte zapnutý JavaScript, zkuste DHTML funkce přejetím myší nad grafem a kliknutím na graf.


<style type="text/css">
/* sloupcovy graf a znacky */
.card {width: 240px; height: 165px; position: relative;}
.back {position: absolute; width:240px; height: 180px;
       top: 0; left: 0; z-index: 0;
}
.cont {position: relative; width: 14px; height: 165px; float: left;}
.bar  {position: absolute; width: 13px; left: 0; z-index: 1;}
.mark {position: absolute; width:  9px; height:   9px;
 left:2px; z-index:2;}

/* dynamicka legenda pod grafem */
div.L, div.C, div.R {
 font: normal 100 11px Arial, SansSerif, Verdana;
 background: transparent; color: #666; border: 0; padding: 0;
 position: absolute; top: 162px; height: 16px; width: 55px;
}
div.L {left:  10px; text-align: left;}
div.C {left:  92px; text-align: right;}
div.R {left: 172px; text-align: right;}
</style>

<script type="text/javascript">
function Show(st, dt, pt) {
  document.getElementById("st").innerHTML = st;
  document.getElementById("dt").innerHTML = dt;
  document.getElementById("pt").innerHTML = pt;
}
function Print(dt) {
  alert("simulace tisku protokolu ze dne" + dt);
}
</script>

<body>

<div class="card" onmouseout="Show('sortiment','datum','plán')">
<img class="back" src="card.png">
<div class="cont" style="width: 7px;"> </div>
...
<div class="cont"
 onmouseover="Show('A19fn','1.4.','112,0%')"
 onclick="Print('1.4.2006')">
<img class="bar"  style="top: 85px; height: 75px;" src="bar.png">
<img class="mark" style="top: 90px;" src="mark.png">
</div>
...
<div class="L" id="st">sortiment</div>
<div class="C" id="dt">datum</div>
<div class="R" id="pt">plán</div>
</div>

</body>

V sekci CSS definujeme část pro kreslení grafu. Třída card a back slouží pro definici oblasti pro kreslení grafu a jeho pozadí. Obě třídy bychom mohli sloučit do jedné a přidat definici pozadí, ale při tisku by záleželo na uživatelském nastavení browseru. Většinou je nastaven na tisk bez pozadí a v takovém případě by pozadí grafu nebylo vykresleno. Třídy cont, bar a mark byly popsány v úvodu. CSS třídy L, C, R slouží pro zobrazení legendy pod grafem. Mohly by být definovány jako ID, pak by ale mohl být na stránce pouze jediný graf.

V části JavaScript vidíte funkci Show() pro dynamické zobrazení hodnot grafu v legendě pod grafem. Funkce Print  zajistí navigaci na stránku s protokolem pro tisk. Stránce report.asp je předáno požadovné datum formou queryStringu. V ukázce je stránka protokolu simulována alertem, což je naznačeno i ve výpisu kódu.

HTML kód. Úvodní tři řádky zajistí definici oblasti pro kreslení, volání funkce pro resetování hodnot legendy, vykreslení pozadí grafu a pomocný prázdný prvek div pro nastavení levého okraje grafu. Příklad jednoho sloupce grafu je ve výpisu na následujících 6 řádcích. Každý sloupec grafu je zabalen do kontejneru (<div class="cont" ...), parametry tohoto kontejneru jsou volání funkcí JavaScriptu pro přejetí kurzoru myši a kliknutí na příslušný sloupec. Dále zde zobrazíme grafické prvky do kterých jsou doplněny pozice stylu. Poslední část HTML kódu jsou 3 prvky div pro zobrazení legendy.

Černé části kódu jsou konstantní, červené části doplňuje server podle výpočtu z aktuálních hodnot a liší se pro každý sloupec grafu. Nesmíme zapomenout testy na grafický rozsah výsledného sloupce tak, aby pozice top nebyla záporná a výška sloupce nepřesáhla výšku kontejneru. Jinak bude graf rozhozený. Deklarace DOCTYPE by měla přepnout browser IE do standardního módu XHTML.

Dynamické funkce onMouseOver a onClick připojené ke kontejneru cont mají odlišné chování v jednotlivých browserech. Ve standardních prohlížečích je chování bez problémů, funkce se aktivují v kterékoli pozici myši nad každým kontejnerem. V IE6 i 7 se tyto funkce uplatní jen nad obsahem kontejneru, zde pouze nad sloupcem grafu. Běžný uživatel to ani nezaznamená, protože myš přirozeně namíří na sloupec grafu.

Řešení je několik: do konteineru cont můžeme přidat další starý dobrý absolutně pozicovaný transparent.gif zabírající celý rozměr kontejneru a teprve přes něj kreslit sloupec grafu (je použito na posledním sloupci grafu). Dále můžeme obrázek pozadí grafu přiřadit k prvku card pomocí CSS, jak bylo zmíněno výše (pokud ovšem netrváme na správném tisku pozadí). Nebo celý graf nakreslit pomocí staré dobré tabulky (viz minulý článek).

updated 08.05.2006