Budoucnost vektorové grafiky na webu, 2. část

Proč bychom měli kvůli vektorové grafice studovat hromadu nových nestandardních technik a postupů? Proč dělat věci dvojím způsobem? Proč ta schizofrenie, když nám stačí ty znalosti, které už máme dnes!

Skutečná síla spojení SVG+XHTML

Existuje standardní mechanismus, který dovoluje webdesignerům umístit do jednoho jediného XML souboru data v několika různých nářečích jazyka XML - jedná se o tzv. jmenné prostory XML ("name space").

Nepočítám-li Amayu, tak jsou Opera 9 a Mozilla Firefox 1.5 prvními dostupnými webovými prohlížeči, které dokážou kombinaci XHTML+SVG vykreslit.

Tento známý příklad pro Mozillu Firefox používá CSS pseudo-třídy ":hover" k vytvoření "roll-over" efektu (ukázka)

Aktualizováno: Demonstrační kód pocházel ve své originální podobě ze stránek Mozilla SVG. Původně jsem jej převzal, aniž by mne napadlo v něm hledat nějaké chyby. V tomto XML kódu se ale bohužel nacházelo několik věcí ne úplně splňujících podmínky normy SVG - a ty způsobily problémy prohlížeči Opera 9. Nyní je XHTML+SVG zcela ve shodě se standardem (a funkční v Opeře 9, Firefoxu 1.5, Safari 2 + SVG).

Nyní bych ctěné čtenáře rád upozornil speciálně na způsoby CSS formátování v ukázkách. Možnosti stylování grafických (!) prvků jsou velice rozsáhlé a přitom v podstatě identické (!) s postupy běžnými u textových dokumentů HTML.

<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:svg="http://www.w3.org/2000/svg" >
<head>
  <style>
    circle:hover {fill-opacity:0.9;}
  </style>
</head>
<body>
  <svg:svg>
    <svg:g style="fill-opacity:0.7;">
      <svg:circle cx="6cm" cy="2cm" r="100"
        style="fill:red; stroke:black; stroke-width:0.1cm"
        transform="translate(0,50)" />
      <svg:circle cx="6cm" cy="2cm" r="100"
        style="fill:blue; stroke:black; stroke-width:0.1cm"
        transform="translate(70,150)" />
      <svg:circle cx="6cm" cy="2cm" r="100"
        style="fill:green; stroke:black; stroke-width:0.1cm"
        transform="translate(-70,150)"/>
    </svg:g>
  </svg:svg>
</body>
</html>

Prvek SVG se chová jako blokový prvek CSS. Vtipnou demonstraci reálných výhod standardní vektorové grafiky představuje i následující ukázka, ve které jsem nadefinoval rozměry SVG bloku s id="vector2" pomocí relativních CSS souřadnic "em". Pokud si v prohlížeči změníte měřítko zobrazení, změní se potom spolu s velikostí písma i rozměry takto vložených SVG grafik. A tyto obrázky budou v libovolném zvětšení absolutně ostré, nerozmazané, nekostičkované!

Měňte si velikost okna prohlížeče jak chcete, ale SVG písmo na pozadí bude stále vyplňovat celou plochu a stále bude stejně hladké. Červeno-modrý vektorový tvar se zvětšuje spolu s textem (ukázka)

Praktická poznámka: Vykreslování písem - zvláště ve FF - není zatím zcela přesné. Vývojová verze DeerPark v současnosti vykresluje písma v tomto příkladu zcela špatně - použijte proto FF 1.5. Obzvláště zde, na rozhraní mezi HTML a SVG, vývojáři kráčí nevyšlapanou cestičkou... Bude asi ještě chvíli trvat než se vše 100% odladí - definice velikosti SVG bloku není bohužel ještě zcela spolehlivá a stejně funkční ve všech SVG prohlížečích. Opera 9 ovšem jednoznačně vede.

Povšimněte si jak přirozeně můžete pomocí CSS třídy nastavit kupříkladu parametry SVG prvku stop, definujícího bod na přechodu barev (viz druhý SVG blok s id="vector1"):

<?xml version="1.0" encoding="utf-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>SVG + XHTML + CSS</title>
  <style>
    html,body {
      font-family:`Helvetica CE`,Helvetica,sans-serif;
      border:0; margin:0; padding:0;
      position:absolute; z-index:0; left:0%; top:0%; width:100%; height:100%;
    }
    h1,p {
      padding:0px 16px;
    }
    <!-- následují styly pro SVG elementy -->
    text.tx0 {
      font-family:`Helvetica CE`,Helvetica,sans-serif;
      font-size:55px; fill:blue; fill-opacity:.2
    }
    stop.begin { stop-color:#dff; }
    stop.end { stop-color:#7af; }
  </style>
</head>
<body>

<h1>Příklad SVG + XHTML + CSS</h1>
<p>Tento XML dokument obsahuje data ve formátech XHTML a SVG.</p>
<p>Pozadí je vektorové a definuje jej SVG element s id=`vector1`.</p>
<p>
  <svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="vector2"
    viewBox="0 0 100 100" width="3em" height="3em">
    <linearGradient id="gradient2">
      <stop stop-color="red" offset="0%"/>
      <stop stop-color="blue" offset="100%"/>
    </linearGradient>
    <polygon points="0,0 0,100 100,00"
             fill="url(#gradient2)"/>
    <circle cx="100" cy="100" r="71"
      fill="url(#gradient2)"
      transform="rotate(135,100,100)"/>
  </svg>
Na počátku tohoto odstavce je jako součást "tekoucího" textu vložen další SVG prvek s id=`vector2` a nastylován tak, aby se jeho velikost měnila spolu s textem.
</p>
<p>A to vše je jen jedna malá součást revoluce, kterou přináší nativní implementace SVG do světa webu!
</p>
  <svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="vector1"
    viewBox="0 0 100 100" preserveAspectRatio="none"
    style="position:absolute; top:0; left:0; width:100%; height:100%; z-index:-1;">
    <linearGradient id="gradient">
      <stop class="begin" offset="0%"/>
      <stop class="end" offset="100%"/>
    </linearGradient>
    <rect x="0" y="0" width="100" height="100" style="fill:url(#gradient)" />
    <text x="0" y="77" class="tx0" >SVG</text>
    <text x="9" y="66" class="tx0" >SVG</text>
    <text x="3" y="60" class="tx0" >SVG</text>
  </svg>
</body>
</html>

Kombinace různých druhů XML dat

SVG standard 1.1 vyžaduje od prohlížeče schopnost pracovat s prvky v cizím jmenném prostoru. Jinými slovy, pokud do SVG souboru vložíte data v jiném XML "name space", tato se stanou součástí objektového stromu DOM a je s nimi možno následně manipulovat využitím skriptovacího jazyka. Tím nám vypadává ze hry Opera 8, jelikož implementovaná SVG Tiny 1.1 neobsahuje podporu skriptování. Opera 9 za to už věc zvládá na jedničku.

Grafika vygenerovaná JavaScriptem z tabulkových dat vložených uvnitř SVG souboru (ukázka)

Obecná XML data vložená v SVG vypadají následovně:

 <data:polozka>
   <data:popis>výsledek</data:popis>
   <data:hodnota>7</data:hodnota>
 </data:polozka>

Tento příklad opět není v podstatě nikterak odlišný od "obyčejného" DHTML. Jen při hledání objektů navíc specifikujeme i konkrétní jmenný prostor ("name space"):

// ziska seznam s daty
seznamPopisu = doc.getElementsByTagNameNS(data_ns, "popis");
seznamHodnot = doc.getElementsByTagNameNS(data_ns, "hodnota");

To stejné při vytváření prvků pomocí funkcí DOM:

pathElement = doc.createElementNS(svg_ns, "path");

Jediné co je odlišné od HTML jsou jména prvků, se kterými pracujeme. Pro plné pochopení algoritmu je potřebné znát mj. význam atributu `d` v prvku path. (Zmíněný atribut obsahuje příkazy definující tvar křivek a čar.) V následující ukázce jsem odstranil některé méně zajímavé části:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" viewBox="0 0 1000 700" onload="onLoad(evt)">
<title>Generování SVG obrazu z dat v jiném XML "namespace"</title>

<defs>
<script type="text/ecmascript"><![CDATA[
var svg_ns = "http://www.w3.org/2000/svg";
var bd_ns = "http://example.org/Example";

function onLoad(evt){
  // ukazatel na objektovy model SVG dokumentu
  var svgElement = evt.target;
  var doc = svgElement.ownerDocument;

  // ukazatel na zdrojova XML data
  var resultsElement = doc.getElementById(`vysledky`);
  var gElement = doc.getElementById(`graf`);

  // spocita pocet polozek
  RegionNodeList = doc.getElementsByTagNameNS(bd_ns, "polozka");
  pocetPolozek = RegionNodeList.length;

  // ziska seznam s daty
  seznamPopisu = doc.getElementsByTagNameNS(bd_ns, "popis");
  seznamHodnot = doc.getElementsByTagNameNS(bd_ns, "hodnota");

  // zjisti maxHodn. hodnotu v grafu
  var maxHodn = 0, h;
  for (ix = 0; ix < pocetPolozek; ix++) {
    h = Number(seznamHodnot.item(ix).firstChild.nodeValue);
    if(h>maxHodn) maxHodn = h;
  }

  // generovani grafu
  for (ix = 0; ix < pocetPolozek; ix++) {
    popis = seznamPopisu.item(ix).firstChild.nodeValue;
    hodnota = Number(seznamHodnot.item(ix).firstChild.nodeValue);
    x = ix*1000/pocetPolozek + 70;
    y = 600 - hodnota*500/maxHodn;
    sirka = 1000/pocetPolozek/2.8;

    // textovy popis osy X
    textElement = doc.createElementNS(svg_ns, "text");
    textNode = doc.createTextNode(popis);
    textElement.appendChild(textNode);
    textElement.setAttributeNS(null, "x", x);
    textElement.setAttributeNS(null, "y", 640 );
    gElement.appendChild(textElement);

    ...

    // generovani elementu "path" pro sloupec
    pathElement = doc.createElementNS(svg_ns, "path");
    dAttribute = `M` + (x-sirka) + `,600 L`;
    dAttribute = dAttribute + (x-sirka) +  `,` + y + ` L`;
    dAttribute = dAttribute + (x+sirka) + `,` + y + ` L`;
    dAttribute = dAttribute + (x+sirka) + `,600 Z`;
    gray =  Math.round(Number(255 * (ix+2)) / (pocetPolozek+2));
    pathElement.setAttributeNS(null, "d", dAttribute);
    pathElement.setAttributeNS(null, "fill", "rgb("+gray+","+gray+","+gray+")");
    pathElement.setAttributeNS(null, "stroke", "black");
    pathElement.setAttributeNS(null, "stroke-width", "2");
    gElement.appendChild(pathElement);
  } /* ix */
} /* onLoad() */
]]></script>
</defs>

<g xmlns:data="http://example.org/Example">
<data:vysledky id="results">
 <data:polozka>
   <data:popis>výsledek</data:popis>
   <data:hodnota>7</data:hodnota>
 </data:polozka>
 <data:polozka>
   <data:popis>aa</data:popis>
   <data:hodnota>5</data:hodnota>
 </data:polozka>
 ...
</data:vysledky>
</g>

<text x="500" y="32" font-family="Helvetica" font-size="32" text-anchor="middle">
SVG graf automaticky vygenerovaný z obecných XML dat
</text>

<g id="graf" font-family="Helvetica" text-anchor="middle" font-size="24">
<desc>Na toto misto skript pripoji elementy grafu</desc>
</g>

<rect x="1" y="1" width="999" height="699" fill="none" stroke="blue"/>
</svg>

XSLT transformace

Další úžasné možnosti nativního SVG se otevírají při nasazení XSLT. Touto technologií můžeme konvertovat XML data do podoby vektorové grafiky jen za pomoci sofistikovaných stylopisů - bez jakýchkoli doplňkových programů či skriptů. Zdrojem může být databáze a cílem HTML nebo stejně tak dobře SVG.

V pokračování tohoto textu bych si rád posvítítil na použití XSLT transformací podrobněji tak, abyste je byli schopni sami použít např. k vytvoření grafu z číselných dat ve formátu XML (viz ukázka SVG grafiky o kousek níže).

Uvědomte si také, že navzdory poměrně malému využívání v současnosti - díky konzervativnímu přístupu dnešních webdesignerů - je XSLT velmi dobře zavedená technogie, která byla v prohlížečích IE a Mozilla Firefox implementována již před relativně dlouhou dobou a dnes tudíž už je spolehlivá a stabilní. Navíc současné verze zbývajících browserů Opera, Safari / Konqueror už její implementací disponují rovněž. (Nemluvě o existujících implementacích na straně serveru.) Takže: Zpět do budoucnosti!

Jdeme na věc, nastal čas

Nebojte se, buďte v pohodě. Vše co potřebujete je skutečně jen XML, skripty ponechte v minulosti! V následující ukázce vidíte útržek souboru ve standardním formátu tabulkového kalkulátoru Excel, vyexportovaný z Open Office verze 2:

<ss:Worksheet ss:Name="Tabulkový list 1">
  <Table ss:StyleID="ta1">
    <Column ss:StyleID="Default" ss:Span="1" ss:Width="64.2614"/>
    <Row ss:Height="12.8409">
      <Cell>
        <Data ss:Type="Number">
          0
        </Data>
      </Cell>
      <Cell ss:Formula="=SIN(RC[-1])*COS(RC[-1])">
        <Data ss:Type="Number">
          0
        </Data>
      </Cell>
    </Row>

  ...

  </Table>
  <x:WorksheetOptions/>
</ss:Worksheet>

Jediné co je třeba udělat pro získání regulérní webové stránky je přidání odkazu na transformační styl XSLT do hlavičky XML dat:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="table2svg.xsl" media="screen"?>

<?mso-application progid="Excel.Sheet"?>
<Workbook ...>
...
</Workbook>

Dotyčný XML soubor nyní můžete směle předhodit libovolnému modernímu prohlížeči (Mozilla Firefox 1.5, Opera 9, Safari 2 s SVG podporou) a voi-la - tak jednoduché to je!

Graf ve formátu SVG vygenerovaný automaticky mechanismem XSLT z tabulkových dat exportovaných z běžné aplikace typu Office (ukázka)

Webové služby atd.

A nakonec zmíním potenciální možnost využití pro vizualizaci (opět XML) dat získaných pomocí tzv. "webových služeb". Mozilla Firefox standardně obsahuje podporu pro SOAP i WSDL, takže v cestě nestojí absolutně nic.

Stručný přehled SVG standardu a jeho podpory v Mozille Firefoxu 1.5

  1. vektorové tvary - ANO
  2. jednobarevné výplně - ANO
  3. přechody barev - ANO
  4. textury - NE
  5. text + tspan - ANO
  6. tref (text odkazem) - NE
  7. text na křivce - NE
  8. SVG písma - NE
  9. transformace - ANO
  10. ořezávání (clipping) - ANO
  11. maskování (masking) - NE
  12. bitmapové filtry - NE
  13. animace SMIL - NE
  14. skriptování - ANO

Implementace SVG v Mozille Firefoxu 1.6 (DeerPark)

  1. vektorové tvary - ANO
  2. jednobarevné výplně - ANO
  3. přechody barev - ANO
  4. textury - ANO
  5. text + tspan - ANO
  6. tref (text odkazem) - NE
  7. text na křivce - ANO
  8. SVG písma - NE
  9. transformace - ANO
  10. ořezávání (clipping) - ANO
  11. maskování (masking) - NE
  12. bitmapové filtry - cca 25%
  13. animace SMIL - cca 15%
  14. skriptování - ANO

Diskuze (35) Další článek: Specifikace nové grafické karty GeForce 7900GT a GTX známy

Témata článku: , , , , , , , , , , , , , , , , , , , , , , , , ,