SVG - styly výplní a značky připojované ke křivkám

30. 8. 2007
Doba čtení: 13 minut

Sdílet

V dnešním článku si řekneme, jakým způsobem je možné v souborech typu SVG (Scalable Vector Graphics) specifikovat barvu a styl výplně. Kromě toho si ukážeme změnu stylu obrysové čáry a vytváření značek (symbolů) na koncích úseček. Tyto značky je možné použít například při vytváření šipek a podobných objektů.

Obsah

1. Styl vykreslovaných křivek a obrysů základních geometrických tvarů
2. Demonstrační příklad – změna typu čáry
3. Symboly připojené na začátek či konec křivek
4. Demonstrační příklad – symbol umístěný na koncích úseček
5. Styly výplní cest a základních geometrických tvarů
6. Barva a průhlednost výplně
7. Demonstrační příklad – barva a průhlednost výplně
8. Obsah dalšího pokračování tohoto seriálu

1. Styl vykreslovaných křivek a obrysů základních geometrických tvarů

V předchozí části tohoto seriálu jsme se dozvěděli, jakým způsobem je možné nastavovat barvu obrysů vykreslovaných objektů, tloušťku obrysových čar, styl jejich ukončení (rovný řez či kruhový oblouk) a styl napojení lomených čar na sebe (existují celkem tři možnosti napojení). V souborech typu SVG je však možné měnit i další vlastnosti křivek/cest a obrysů základních geometrických tvarů. Zejména se jedná o nastavení typu čáry a také o volbu symbolu, který může být připojen na začátek či konec vykreslované křivky. Pokud má tento symbol tvar malého trojúhelníku, jak tomu ostatně bude ve druhém demonstračním příkladu, vznikne jeho připojením (samozřejmě s vhodnou orientací) šipka, je však možné použít prakticky libovolný tvar. Symbol je možné použít u otevřených cest, úseček i lomených čar (polyčar) a v některých případech dokonce i u mnohoúhelníku.

Nejprve si řekněme, jakým způsobem je možné měnit typ čáry. Pro tento účel se používá atribut stroke-dasharray, jehož hodnotou je seznam číselných hodnot oddělených čárkami (pozor – pro oddělení hodnot nelze použít pouze bílé znaky jako u definice cest!). Hodnoty uložené na lichých místech udávají délku čárek, tj. vykreslovaných částí, hodnoty na sudých místech značí naopak délku mezer mezi čárkami. To znamená, že například zápis stroke-dasharray=„10,1“ vede k vytvoření úsečky, křivky či obrysu základního geometrického tvaru, které je složeny vždy z čárky dlouhé deset jednotek za kterou následuje mezera o šířce jedné délkové jednotky. Kromě číselných údajů bez udané veličiny (absolutní délková míra) je možné uvést i hodnoty se znakem procenta – tato délka je odvozena od velikosti pohledu.

K atributu stroke-dasharray se vztahuje ještě atribut stroke-dashoffset jehož číselná hodnota udává posun začátku vykreslování stylu čáry od skutečného počátku tvaru (cesty, úsečky atd.). Pro jaké účely je možné offset použít? Zejména pro animaci (animovaný typ čáry vyvolává efekt pohybu, čehož je možné využít například pro „rozpohybování“ schématických nákresů), ale také pro zajištění, aby došlo ke korektnímu napojení čar na sebe, tj. nedojde k napojení jednotlivých segmentů „vykreslených“ mezerou. I hodnota atributu stroje-dashoffset může být zadána v absolutních délkových jednotkách nebo relativně (za číslem je znak procenta). Pokud není tento atribut uveden, použije se jeho implicitní hodnota, což je 0 délkových jednotek (při měřítku 1:1 délková jednotka odpovídá jednomu pixelu).

2. Demonstrační příklad – změna typu čáry

Ukažme si význam obou atributů stroke-dasharray a stroke-dashoffset na konkrétním příkladu. Na něm si také znovu zopakujeme význam značky <g> pro seskupování objektů se stejnými vlastnostmi. Nejprve je vykresleno jedenáct úseček o různém sklonu, jejichž typ není specifikován. Z tohoto důvodu jsou úsečky vykresleny plnou čarou, přesně podle normy SVG. Následuje sedm vodorovných úseček, u nichž se mění typ čáry. První úsečka je složena z čar o délce 9 jednotek, za níž následuje mezera o délce jedné délkové jednotky. Poslední úsečka používá čáry o délce 3 a mezery o délce 7 jednotek. Svislé úsečky, které jsou vykresleny následně, mají stejný typ čáry, liší se však jejich offset. Poslední úsečka se sklonem 45° je širší, styl konců je nastaven na kruhový oblouk a i typ čáry je odlišný – výsledkem je „vytečkovaný“ tvar.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="400"
     height="400"
     viewBox="0 0 200 200"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">

     <!-- úsečky vykreslené implicitním stylem -->
     <g fill="none" stroke="#808080" stroke-width="0.5">
         <line x1="0" y1="0"   x2="0"   y2="199" />
         <line x1="0" y1="20"  x2="20"  y2="199" />
         <line x1="0" y1="40"  x2="40"  y2="199" />
         <line x1="0" y1="60"  x2="60"  y2="199" />
         <line x1="0" y1="80"  x2="80"  y2="199" />
         <line x1="0" y1="100" x2="100" y2="199" />
         <line x1="0" y1="120" x2="120" y2="199" />
         <line x1="0" y1="140" x2="140" y2="199" />
         <line x1="0" y1="160" x2="160" y2="199" />
         <line x1="0" y1="180" x2="180" y2="199" />
         <line x1="0" y1="199" x2="200" y2="199" />
     </g>

     <!-- vodorovné úsečky s měnícím se typem čáry -->
     <g fill="none" stroke="#008080" stroke-width="2">
         <line stroke-dasharray="9,1" x1="20" y1="10" x2="180" y2="10" />
         <line stroke-dasharray="8,2" x1="20" y1="20" x2="180" y2="20" />
         <line stroke-dasharray="7,3" x1="20" y1="30" x2="180" y2="30" />
         <line stroke-dasharray="6,4" x1="20" y1="40" x2="180" y2="40" />
         <line stroke-dasharray="5,5" x1="20" y1="50" x2="180" y2="50" />
         <line stroke-dasharray="4,6" x1="20" y1="60" x2="180" y2="60" />
         <line stroke-dasharray="3,7" x1="20" y1="70" x2="180" y2="70" />
     </g>

     <!-- svislé úsečky s pevně nastaveným typem čáry, ale změnou offsetu -->
     <g fill="none" stroke="#c08000" stroke-width="2" stroke-dasharray="10,10">
         <line stroke-dashoffset="0" x1="110" y1="80" x2="110" y2="180" />
         <line stroke-dashoffset="1" x1="120" y1="80" x2="120" y2="180" />
         <line stroke-dashoffset="2" x1="130" y1="80" x2="130" y2="180" />
         <line stroke-dashoffset="3" x1="140" y1="80" x2="140" y2="180" />
         <line stroke-dashoffset="4" x1="150" y1="80" x2="150" y2="180" />
         <line stroke-dashoffset="5" x1="160" y1="80" x2="160" y2="180" />
         <line stroke-dashoffset="6" x1="170" y1="80" x2="170" y2="180" />
         <line stroke-dashoffset="7" x1="180" y1="80" x2="180" y2="180" />
     </g>

     <!-- šikmá vytečkovaná úsečka -->
     <line
         fill="none"
         stroke="red"
         stroke-width="4"
         stroke-linecap="round"
         stroke-dasharray="1,10,1,5"
         x1="30" y1="80" x2="100" y2="150" />
</svg> 

5301
Obrázek 1: První demonstrační příklad po vykreslení v SVG prohlížeči

3. Symboly připojené na začátek či konec křivek

Na začátek či konec otevřených křivek, tj. u cest (path), úseček a lomených čar a také k libovolnému vrcholu lomených čar (polyline) a mnohoúhelníků (polygon) je možné připojit vybraný symbol. Samotný symbol je specifikován pomocí SVG značky <marker>, ke které se vztahuje poměrně velké množství atributů (viz tabulka uvedená pod tímto odstavcem). Uvnitř značky <marker>, která je párová, se většinou nachází vložená značka se specifikací cesty, kterou je definován vlastní vizuální tvar značky. Vzhledem k tomu, že symbol může mít různou velikost a orientaci v závislosti na geometrickém tvaru, ke kterému je připojen, je nutné při jeho vytváření nastavit poměrně velké množství atributů, z nichž ty nejvíce používané jsou uvedeny v následující tabulce:

Atribut Význam
id jednoznačný identifikátor značky použitý při připojení symbolu ke geometrickému tvaru
refX relativní poloha počátku symbolu ve směru osy x
refY relativní poloha počátku symbolu ve směru osy y
markerUnits zadává jednotky použité pro při vytváření symbolu
markerWidth šířka oblasti, ve které je symbol vykreslen
markerHeight výška oblasti, ve které je symbol vykreslen
orient způsob orientace symbolu vůči křivce, ke které je napojen
viewBox rozsah hodnot souřadnic, které omezují symbol ze všech čtyř stran

Význam atributu id je zřejmý: symbol musí být pojmenován, aby ho bylo možné připojit k některé cestě či základnímu geometrickému tvaru. Hodnota atributu refX a refY určuje pozici počátku symbolu. Například u šipky používající jako symbol malý trojúhelník by byl refX nastaven na nulu a refY na polovinu šířky trojúhelníku, aby bylo dosaženo vycentrování konce šipky na její osu. Atributy markerUnits, markerWidth a markerHeight se navzájem ovlivňují a slouží ke specifikaci relativní velikosti symbolu vůči cestě/tvaru, ke kterému je připojen.

Typicky bývá hodnota atributu markerUnits nastavena na „strokeWidth“, což znamená, že se velikost symbolu mění současně se šířkou cesty/tvaru (to je výhodné především u šipek). Druhá povolená hodnota je „userSpaceOnUse“, potom je velikost symbolu zadaná přímo v uživatelských souřadnicích. Hodnoty atributů markerWidth a markerHeight udávají relativní velikost obdélníkové oblasti, do které je symbol zvětšen, aby se jeho krajní body této hranice dotýkaly.

Význam atributu orient spočívá v možnosti specifikace algoritmu pro otočení symbolu v závislosti na orientaci křivky, ke které je symbol připojen. Většinou je použita hodnota „auto“, která značí, že se má symbol otáčet tak, aby byl orientován ve směru osy křivky. Stanovení osy nemusí být v některých případech jednoduché (představme si Bézierovu křivku, která je navázána na kolmo orientovanou úsečku), ovšem norma specifikuje takové chování prohlížečů, že výsledek ve většině případů odpovídá představám autora. Posledním významným atributem je viewBox, kterým je udána plocha, ve které je symbol vykreslen. Při připojení symbolu na křivku je tato plocha zvětšena či zmenšena tak, aby odpovídala hodnotám vypočteným na základě atributů markerUnits, markerWidth a markerHeight.

4. Demonstrační příklad – symbol umístěný na koncích úseček

V dnešním druhém demonstračním příkladu je ukázáno vytvoření symbolu šipky, který je následně připojen na několik úseček, které se liší svou orientací a tloušťkou. Symbol je pojmenován jednoduše „sipka“, má nastavenu plochu o rozměrech 10×10 jednotek a jeho referenční bod leží na souřadnicích [0, 5], tedy v polovině výšky plochy, do které se vykresluje. Při vykreslení symbolu se jeho velikost vypočte relativně k šířce křivky tak, aby výška symbolu byla rovna trojnásobku šířky křivky a délka čtyřnásobkem šířky. Orientace je automaticky zvolena s ohledem na tečnu ke křivce v bodě jejího začátku či konce. Tento symbol je připojen k začátkům a/nebo koncům úseček pomocí atributu marker-start a marker-end, jejichž hodnotou je odkaz na symbol. Teoreticky by mohl být použit i atribut marker (stejný symbol na začátku i na konci), InkScape, který jsem použil pro zobrazování, však tento atribut nezpracuje korektně:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="400"
     height="400"
     viewBox="0 0 200 200"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">

     <!-- vytvoření symbolu -->
    <defs>
        <marker id="sipka"
            viewBox="0 0 10 10" refX="0" refY="5"
            markerUnits="strokeWidth"
            markerWidth="4" markerHeight="3"
            orient="auto">
            <path d="M 0 0 L 10 5 L 0 10 z" />
        </marker>
    </defs>

     <!-- úsečky vykreslené implicitním stylem -->
     <g fill="none" stroke="#808080" stroke-width="0.5">
         <line x1="0" y1="0"   x2="0"   y2="199" />
         <line x1="0" y1="20"  x2="20"  y2="199" />
         <line x1="0" y1="40"  x2="40"  y2="199" />
         <line x1="0" y1="60"  x2="60"  y2="199" />
         <line x1="0" y1="80"  x2="80"  y2="199" />
         <line x1="0" y1="100" x2="100" y2="199" />
         <line x1="0" y1="120" x2="120" y2="199" />
         <line x1="0" y1="140" x2="140" y2="199" />
         <line x1="0" y1="160" x2="160" y2="199" />
         <line x1="0" y1="180" x2="180" y2="199" />
         <line x1="0" y1="199" x2="200" y2="199" />
     </g>

     <!-- vodorovné úsečky se šipkami na začátku a/nebo konci -->
     <g fill="none" stroke="#008080" stroke-width="2">
         <line x1="20"  y1="10" x2="180" y2="10" marker-end="url(#sipka)" />
         <line x1="20"  y1="20" x2="180" y2="20" marker-start="url(#sipka)" />
         <line x1="20"  y1="30" x2="180" y2="30" marker-start="url(#sipka)" marker-end="url(#sipka)" />
         <line x1="180" y1="40" x2="20"  y2="40" marker-end="url(#sipka)" />
         <line x1="180" y1="50" x2="20"  y2="50" marker-start="url(#sipka)" />
         <line x1="180" y1="60" x2="20"  y2="60" marker-start="url(#sipka)" marker-end="url(#sipka)" />
         <line x1="20"  y1="70" x2="180" y2="70" />
     </g>

     <!-- svislé úsečky se šipkami -->
     <g fill="none" stroke="#c08000">
         <line stroke-width="0" x1="40"  y1="80" x2="40"  y2="160" marker-end="url(#sipka)" />
         <line stroke-width="1" x1="60"  y1="80" x2="60"  y2="160" marker-end="url(#sipka)" />
         <line stroke-width="2" x1="80"  y1="80" x2="80"  y2="160" marker-end="url(#sipka)" />
         <line stroke-width="3" x1="100" y1="80" x2="100" y2="160" marker-end="url(#sipka)" />
         <line stroke-width="4" x1="120" y1="80" x2="120" y2="160" marker-end="url(#sipka)" />
         <line stroke-width="5" x1="140" y1="80" x2="140" y2="160" marker-end="url(#sipka)" />
         <line stroke-width="6" x1="160" y1="80" x2="160" y2="160" marker-end="url(#sipka)" />
         <line stroke-width="7" x1="180" y1="80" x2="180" y2="160" marker-end="url(#sipka)" />
     </g>

</svg> 

5302
Obrázek 2: Druhý demonstrační příklad po vykreslení v SVG prohlížeči

5. Styly výplní cest a základních geometrických tvarů

U vyplňovaných grafických objektů, tj. jak cest, tak i základních geometrických tvarů, je možné zvolit barvu a styl výplně, přiřadit k výplni gradientní přechod, výplňový vzorek atd. Dnes si řekneme, jak lze zvolit barvu výplně a popř. i její průhlednost. V následující části tohoto seriálu se budeme zabývat pokročilejšími způsoby vyplňování, zejména oblíbeným gradientním přechodům, které je možné použít například při vytváření stínovaných objektů, objektů s odlesky atd. Konkrétní použití gradientních výplní je obsahem několika webových tutoriálů i knih. V češtině se jedná především o literaturu k CorelDraw!, vysvětlené postupy je však možné použít i pro soubory SVG vznikající například v programu Xara nebo stále se vylepšujícímu Inkscape.

6. Barva a průhlednost výplně

Barva výplně se nastavuje velmi jednoduše. U vyplňovaného tvaru se uvede atribut fill, jehož hodnotou je požadovaná barva výplně. Způsob specifikace barvy jsme si vysvětlili v předchozí části, typicky je použit řetězec #rrggbb, kde rr, gg a bb jsou hexadeciálně zapsané hodnoty 0016-ff16. Implicitně je objekt vyplněn zcela neprůhlednou barvou, to je však možné změnit zadáním atributu fill-opacity. Hodnotou tohoto atributu by mělo být číslo v rozsahu 0,0..1,0. Nulová hodnota značí plně průhlednou výplň (0 %), jednička úplnou neprůhlednost (100 %), což je také implicitní hodnota tohoto atributu. Hodnoty, které leží mimo rozsah 0,0..1,0 jsou ořezány, není tedy možné docilovat zajímavých efektů například zadáním záporné průhlednosti.

7. Demonstrační příklad – barva a průhlednost výplně

V dnešním třetím a současně i posledním demonstračním příkladu je na podkladové ploše vykresleno několik úseček (stejně jako v příkladech předchozích). Nad těmito úsečkami jsou vykresleny kružnice, z nichž čtyři jsou neprůhledné a u dvou spodních kružnic je nastavena průhlednost na 20 %, resp. 50 %. Způsob zjištění, které objekty mají být vykresleny dříve a které později, je velmi jednoduchý – záleží na pořadí objektů v SVG souboru. Prohlížecí program jednoduše postupně načítá jednotlivé objekty a vykresluje je. To znamená, že v našem případě jsou nejdříve vykresleny úsečky a teprve poté kružnice (pořadí vykreslování má u neprůhledných i průhledných objektů samozřejmě svůj význam). Zdrojový kód třetího demonstračního příkladu vypadá následovně:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="400"
     height="400"
     viewBox="0 0 200 200"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">

     <!-- úsečky vykreslené implicitním stylem -->
     <g fill="none" stroke="#808080" stroke-width="0.5">
         <line x1="0" y1="0"   x2="0"   y2="199" />
         <line x1="0" y1="20"  x2="20"  y2="199" />
         <line x1="0" y1="40"  x2="40"  y2="199" />
         <line x1="0" y1="60"  x2="60"  y2="199" />
         <line x1="0" y1="80"  x2="80"  y2="199" />
         <line x1="0" y1="100" x2="100" y2="199" />
         <line x1="0" y1="120" x2="120" y2="199" />
         <line x1="0" y1="140" x2="140" y2="199" />
         <line x1="0" y1="160" x2="160" y2="199" />
         <line x1="0" y1="180" x2="180" y2="199" />
         <line x1="0" y1="199" x2="200" y2="199" />
     </g>

     <!-- kružnice bez nastavených stylů -->
     <circle cx="80" cy="80" r="25" />

     <!-- kružnice bez nastavených stylů -->
     <circle cx="40" cy="40" r="25" fill="#ffaaaa" stroke="black" stroke-width="4" />

     <!-- kružnice s nastaveným stylem výplně a barvy obrysu -->
     <circle cx="120" cy="40" r="25" fill="#aaffaa" stroke="black" stroke-width="4" />

     <!-- poloprůhledná kružnice s nastaveným stylem výplně a barvy obrysu -->
     <circle cx="40" cy="120" r="25" fill="#ffffaa" fill-opacity="0.2" stroke="black" stroke-width="4" />

     <!-- kružnice s nastaveným stylem výplně a barvy obrysu -->
     <circle cx="120" cy="120" r="25" fill="#aaffff" stroke="black" stroke-width="4" />

     <!-- poloprůhledná kružnice s nastaveným stylem výplně a barvy obrysu -->
     <circle cx="80" cy="160" r="25" fill="#aaffaa" fill-opacity="0.5" stroke="black" stroke-width="4" />

</svg> 

ict ve školství 24

5303
Obrázek 3: Třetí demonstrační příklad po vykreslení v SVG prohlížeči

8. Obsah dalšího pokračování tohoto seriálu

V následující části seriálu o grafickém formátu SVG si popíšeme způsob vytváření gradientních výplní a také metodu, pomocí které se zjistí, které části plochy leží uvnitř objektů a které jsou vně.

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.