Vytváření obrázkových grafů pomocí PHP 2.

28. června 2001

Dnes přicházím s druhou, závěrečnou polovinou PHP skriptu pro vytváření obrázkových grafů. V poněkud rozsáhlejším článku si ukážeme, jak načíst data z databáze a kreslit jejich křivky do grafu.

Minule jsme si připravili všechny potřebné hodnoty, aby graf byl snadno modifikovatelný. Jak rozměrově, tak i počtem hodnot. Dnes všechny připravené a vypočítané parametry použijeme. Dostáváme se totiž k vlastnímu kreslení grafu.

// nejprve pošlu hlavičku obrázku
Header(„Content-Type: image/gif“);
// vytvořím prázdný obrázek
$im = ImageCreate($sirka_obrazku, $vyska_obrazku);
// nadefinuji si barvy, ktere budu potřebovat
$bila = ImageColorAllocate($im, 255, 255, 255);
$cerna = ImageColorAllocate($im, 0, 0, 0);
$cervena = ImageColorAllocate($im, 255, 0, 0);
$zelena = ImageColorAllocate($im, 0, 255, 0);

Zahájíme vlastní práci s grafikou. Nejprve odešleme hlavičku obrázku. Protože chceme vytvořit obrázek ve formátu GIF, je zde uvedeno image/gif. Kdybychom chtěli vytvořit obrázek PNG, museli bychom za poslední lomítko místo gif napsat png, u JPG obrázku potom jpg.

Dále vytvoříme v paměti prázdný obrázek požadovaných rozměrů. Do proměnné $im obdržíme jeho identifikátor, pomocí kterého dále s obrázkem pracujeme. A nakonec nadefinujeme a v paletě obrázku alokujeme barvy, které budeme používat. Bílou barvou nebudeme sice kreslit, ale bude použita jako pozadí obrázku.

//nakreslím osu x
ImageLine($im, $bod0_x-1, $vyska_obrazku-$bod0_y,
  $sirka_obrazku-$pravy_okraj, $vyska_obrazku-$bod0_y, $cerna);
//nakreslím osu y
ImageLine($im, $bod0_x, $vyska_obrazku-$bod0_y+1, $bod0_x, $horni_okraj, $cerna);

Nakreslíme osy x a y. Použijeme k tomu funkci $ImageLine, jejímiž parametry jsou: identifikátor obrázku do nějž kreslíme, x-ová souřadnice počátečního bodu, y-ová souřadnice počátečního bodu, x-ová souřadnice koncového bodu, y-ová souřadnice koncového bodu a nakonec barva čáry.

Dlužno podotknout, že počátek souřadnicového systému vlastního obrázku je v levém horním rohu. A na to nesmíme při kreslení našeho grafu, který má samozřejmě počátek blízko levého dolního rohu, zapomenout.

//nejprve si spočítám, kolik asi popisek osy y se mi na výšku vejde
$pocet_popisek_osy_y = round(($vyska_obrazku – $bod0_y – $horni_okraj)
  / (2 * ImageFontHeight($fontsize)));
//podle toho spočítám krok osy y
$krok_hodnot_osy_y = ceil(($max-$min)/($pocet_popisek_osy_y));
//vypočítám převodní koeficient osy y
$koeficient_y = floor(($vyska_obrazku – $bod0_y – $horni_okraj) / ($max – $min));
// vypíši hodnoty osy y
for ($i=$min;$i<=$max; $i+=$krok_hodnot_osy_y)
{
  $pomy = $vyska_obrazku – $bod0_y – (($i-$min) * $koeficient_y);
  // ryska na ose y
  ImageLine($im, $bod0_x-2, $pomy, $bod0_x+1, $pomy, $cerna);
  // popiska rysky na ose y
  ImageString($im, $fontsize, 0, $pomy-round(ImageFontHeight($fontsize)/2),
            str_pad($i, $cislic_osy_y-1, “ „, STR_PAD_LEFT),
            $cerna);
}
// a ještě vypíši název osy y
ImageString($im, $fontsize, 0, $horni_okraj,
            str_pad($nazev_osy_y, $cislic_osy_y-1, “ „, STR_PAD_LEFT),
            $cerna);

Na osu y postupně vyneseme cejchování, popisky hodnot a název osy. Postup je vidět v předchozí ukázce kódu. Musíme si nejprve určit, v jakém intervalu osu y ocejchujeme. Dále musíme vypočítat koeficient, kterým budeme násobit y-ové hodnoty grafu. Tento koeficient využijeme nejen při kreslení křivek grafu, ale i teď hned při cejchování osy y. Nakonec ještě vypíšeme název osy.

//vypočítám převodní koeficient osy x
$koeficient_x = floor(($sirka_obrazku – $bod0_x – $pravy_okraj) / $pocet_hodnot);
//zjistím si, jak budu vypisovat popisky osy x
$pocet_popisek_osy_x = $sirka_obrazku / (ImageFontHeight($fontsize) * 2);
if ($pocet_popisek_osy_x > $pocet_hodnot)
  $interval_popisek_x = 1; //budu zobrazovat popisku každé hodnoty osy x
else
  //budu zobrazovat popisky pouze určitých hodnot osy x
  $interval_popisek_x = ceil($pocet_hodnot / $pocet_popisek_osy_x);

Podobným způsobem si připravíme i osu x. Zde však předem víme počet hodnot, které chceme na ose x vynášet ($pocet_hodnot), a potřebujeme zjistit, jestli se nám na šířku grafu vejdou popisky všech hodnot, nebo jestli budeme některé vynechávat. Vypočítáme si vlastně krok pro osu x. Do proměnné $pocet_hodnot si uložíme, kolikátou hodnotu na ose x budeme popisovat. Pokud je to 1, jako v první větvi podmínky if, znamená to, že budeme popisku tisknout u každé 1., tedy u každé hodnoty. V případě vyššího čísla, např. 2, to bude pouze každá druhá popiska.

//provedu dotaz do databáze, na hodnoty grafu
@$vysledek = mysql_query(„select den, muzi, zeny“
  .“ from lide“
  .“ order by den“);
if (!$vysledek):
{ // mám smůlu, nepodařilo se mi získat data z tabulky
  // vypíšu o tom do obrázku zprávu
  ImageString($im, $fontsize, $bod0_x+5, $horni_okraj,
            „Nepodařilo se přečíst hodnoty grafu z tabulky“,
            $cerna);
}
else:
{

Začínáme pracovat na vykreslení křivek grafu. Tomu samozřejmě předchází dotaz do databáze a zjištění hodnot grafu. Pokud se mi nezdaří z databáze data přečíst, mohu o tom vypsat zprávu do obrázku. Teď už to jde, protože obrázek je již vytvořen.

  $pocet = mysql_NumRows($vysledek);
  if ($pocet_hodnot > $pocet)
    $pocet_hodnot = $pocet; // kdyby mezitim nahodou nekdo nejaky udaj vymazal
  //vypisu prvni popisku osy x
  ImageStringUp($im, $fontsize, $bod0_x-round(ImageFontHeight($fontsize)/2), $vyska_obrazku,
            str_pad(mysql_result($vysledek, 0, „den“), $cislic_osy_x-1, “ „, STR_PAD_LEFT),
            $cerna);
  $posledni_x = $bod0_x;
  $posl_y_zeny = $vyska_obrazku – $bod0_y
      – ((mysql_result($vysledek, 0, „zeny“) – $min) * $koeficient_y);
  $posl_y_muzi = $vyska_obrazku – $bod0_y
      – ((mysql_result($vysledek, 0, „muzi“) – $min) * $koeficient_y);

Podařilo se načíst data z tabulky, a my si pro kontrolu zjistíme, zda se jejich počet od prvního dotazu náhodou nezměnil. Pokud by někdo nějakou větu vymazal, dostali bychom hodnot méně, než očekáváme, a na konci vykreslovací smyčky by došlo k chybě.

Pokud náhodou data mezitím přibyla, budeme přebývající ignorovat, protože na ně stejně nemáme místo. Do proměnných $posledni_x, $posl_y_zeny a $posl_y_muzi si budeme v  každém kroku ukládat polohy naposledy nakreslených bodů, abych z nich mohli pokračovat přímkou do dalších bodů. A protže teď jsme teprve na počátku, na první hodnotě osy x, pouze si do těchto proměnných uložíme hodnoty, ze kterých budeme kreslit přímky do 2. bodu.

  $i = 1;
  while ($i<$pocet_hodnot):
    // vypočítám x polohu této hodnoty grafu
    $pom_x = ($i * $koeficient_x) + $bod0_x;
    // vypočítám y polohu obou hodnot
    $pom_y_zeny = $vyska_obrazku – $bod0_y
      – ((mysql_result($vysledek, $i, „zeny“) – $min) * $koeficient_y);
    $pom_y_muzi = $vyska_obrazku – $bod0_y
      – ((mysql_result($vysledek, $i, „muzi“) – $min) * $koeficient_y);
    //nakreslím křivky od minulého k tomuto bodu
    ImageLine($im, $posledni_x, $posl_y_zeny, $pom_x, $pom_y_zeny, $cervena);
    ImageLine($im, $posledni_x, $posl_y_muzi, $pom_x, $pom_y_muzi, $zelena);
    // vykreslím rysku na ose x
    ImageLine($im, $pom_x, $vyska_obrazku – $bod0_y + 2,
      $pom_x, $vyska_obrazku – $bod0_y – 2, $cerna);
    // vypíšu popisku osy x
    if (round($i/$interval_popisek_x) == ($i/$interval_popisek_x))
      ImageStringUp($im, $fontsize, $pom_x – round(ImageFontHeight($fontsize)/2),
        $vyska_obrazku,
        str_pad(mysql_result($vysledek, $i, „den“), $cislic_osy_x-1, “ „, STR_PAD_LEFT),
        $cerna);
    // nastavím současné hodnoty jako minulé
    $posledni_x = $pom_x;
    $posl_y_zeny = $pom_y_zeny;
    $posl_y_muzi = $pom_y_muzi;
    $i++;
  endwhile;

Pomocí této smyčky vykreslíme celý graf. Nejprve vypočítáme pomocí koeficientů x-ovou a y-ové souřadnice kreslených bodů. Nakreslíme křivky z minulých bodů do těchto bodů. Uděláme rysku na osu x. A pokud je to zrovna ryska, ktará spadá do intervalu pro vypsání popisky osy x, vytiskneme i popisku osy x. Nakonec uložíme současné souřadnice pro použití v příštím kroku do pomocných proměnných.

  //vypíši název osy x
  ImageString($im, $fontsize, $sirka_obrazku – $pravy_okraj, $vyska_obrazku-$bod0_y + 5,
      $nazev_osy_x, $cerna);

Dokončili jsme vykreslování obou křivek grafu, a teď nám zbývá vytisknout název osy x.

  $pom_x = $sirka_obrazku – $pravy_okraj;
  //vypíši legendu pro muže
  ImageString($im, $fontsize, $pom_x + $delka_vzorku_legendy + ImageFontWidth($fontsize),
    $horni_okraj, $nazev_krivky_1, $cerna);
  //vzorek pro legendu
  $pom_y = $horni_okraj + round(ImageFontHeight($fontsize)/2);
  ImageLine($im, $pom_x, $pom_y, $pom_x + $delka_vzorku_legendy, $pom_y, $cervena);
  //vypíši legendu pro ženy
  ImageString($im, $fontsize, $pom_x + $delka_vzorku_legendy + ImageFontWidth($fontsize),
  $horni_okraj + (ImageFontHeight($fontsize) * 2), $nazev_krivky_2, $cerna);
  $pom_y += + (ImageFontHeight($fontsize) * 2);
  ImageLine($im, $pom_x, $pom_y, $pom_x + $delka_vzorku_legendy, $pom_y, $zelena);

Aby byl graf kompletní, musíme jej opatřit legendou. Vzorkem čar, které barvou odpovídají křivkám grafu, včetně popisu, které hodnoty křivky této barvy představují.

}
endif;
mysql_Close();
ImageGIF($im);
?>

Ukončíme větev, ve které jsme vykreslovali graf a uzavřeme spojení s databází. Nakonec přichází příkaz, kterým uzavřeme obrázek a odešleme jej návštěvníkovi stránky. Pracovali jsme s formátem GIF, proto příkaz ImageGIF. Pokud bychom vytvářeli obrázek PNG, byl by zde příkaz ImagePNG, v případě obrázku JPG pochopitelně ImageJPG.

Z libovolného HTML dokumentu teď můžeme zavolat náš skript pomocí tagu IMG, a dostaneme celý graf ve formě obrázku. V tomto tagu můžeme skript zavolat s parametry, kterými určíme velikost požadovaného grafu.

Tag pro zobrazení grafu je úplně obyčejný:

<IMG SRC=“graf.php“>

Pro určení velikosti požadovaného grafu můžeme zadat parametry sirka a vyska:

<IMG SRC=“graf.php?sirka=300&vyska=200″>

Pokud budeme chtít být opravdu důslední:

<IMG SRC=“graf.php?sirka=300&vyska=200″ WIDTH=“300″ HEIGHT=“200″ BORDER=“0″ ALT=“Graf“>

Skript graf.php můžeme zavolat prostým zadáním jeho URL. Např. www.nasedomena.cz/graf.php. Pak se nám v prohlížeči zobrazí obrázek grafu ve standardních rozměrech, tedy 600×400 bodů. Skript ale můžeme volat z nějakého HTML dokumentu pomocí standardního tagu pro zobrazení obrázků – IMG. To se nám samozřejmě hodí, pokud potřebujeme graf nějak okomentovat, nebo zakomponovat do standardního vzhledu našeho webu.

Abychom mohli snadno měnit velikost obrázku z jiných HTML dokumentů, naprogramovali jsme si do skriptu jednoduchou pomůcku. Kontrolujeme, jestli jsou zadány nějaké hodnoty v proměnných $sirka a $vyska. Pokud ano, standardní rozměry grafu se změní na tyto hodnoty. Pamatujete? A teď se dostáváme k tomu, jak předat požadovanou šířku a výšku našemu skriptu. Do pole SRC tagu IMG, kterým voláme náš skript, napíšeme toto: "graf.php?sirka=300&vyska=200". Jsou to parametry, pro které si PHP automaticky vytvoří proměnné $sirka a $vyska, a vloží do nich hodnoty 300 a 200. Není nic snažšího. Možná namítnete, že velikost obrázku se přece ovlivňuje pomocí height a width. Máte pravdu. Ale v žádném případě by se neměly tyto parametry používat tak, že se pomocí nich zobrazí obrázek 800×600 bodů jako náhled ve velikosti 150×100 bodů. Pro tyto účely bychom měli mít dvě verze obrázků. Velké a jejich zmenšeniny.

Po Internetu bychom měli posílat a stahovat pouze nezbytně nutné množství dat. Jde o rychlost a o peníze. Proto si, pokud chceme jen náhled grafu, už při volání skriptu rovnou řekneme, pomocí parametrů sirka a vyska, že chceme náš graf jen malý. Není nic snažšího, než udělat tento malý náhled jako hypertextový odkaz (<a href=“…), a při kliknutí na náhled grafu se skript zavolá ještě jednou, a zobrazí se v normální velikosti.

A to je už opravdu vše. Celý příklad si můžete stáhnout zde. Obsahuje kromě skriptu, který jsme právě probrali, také i skript pro vytvoření tabulky lidé s demonstračními hodnotami. Dále je zde soubor zobraz_graf.htm, v němž je ukázáno, jak zobrazit graf v HTML dokumentu, i včetně volání skriptu s parametry.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *