Możliwości SVG w aplikacjach webowych

SVG (ang. Scalable Vector Graphics) jest językiem służącym do definiowania dwuwymiarowych grafik opartych na wektorach. W porównaniu do formatów jak PNG i JPG, SVG charakteryzuje się tym, że grafiki są renderowane bez utraty jakości, ponadto do ich edycji nie jest wymagany edytor graficzny.

Możliwość zastosowania wektorowych elementów w aplikacjach webowych zapewnia nam szereg ciekawych opcji. Jednym z oczywistych wniosków podczas używania obrazów rastrowych jest fakt, że każdy pixel jest dokładnie zdefiniowany i nie jest możliwe programistyczne manipulowanie wybranymi częściami obrazka. W SVG istnieją znaczniki typu path wewnątrz kontenera svg, dzięki którym wymienione wcześniej operacje stanowią łatwość.

Szybkie podstawy

Na początek zdefiniujmy sobie układ współrzędnych w SVG 100×100. Przyda się on nam w kolejnych przykładach dla lepszej wizualizacji oraz zrozumienia tego w jaki sposób możemy pozycjonować poszczególne elementy. Do uzyskania tego celu zdefiniujmy linie na osi X oraz osi Y. Na ten moment wystarczy nam wiedza o atrybucie d znacznika path oraz atrybut viewBox tagu svg pozwalający na określenie wymiarów kontenera. Możliwe było również zwykłe użycie znacznika line – specyficzne do tej koncepcji, ale dla celów dydaktycznych przeanalizujmy zachowanie rysowania dowolnej ścieżki. Specyfikacja SVG informuje nas o pięciu komendach pozwalających na renderowanie ścieżek linii. Po dokładny opis sugeruję lekturę samej specyfikacji (SVG Paths). Po zapoznaniu się jesteśmy gotowi stworzyć prosty układ współrzędnych.
<svg viewBox="0 0 100 100" 
style="border: 2px solid gray; background: rgba(0,0,0,0.3);">
    <path stroke="white" stroke-width=".5" d="M10 0 V100" />
    <path stroke="white" stroke-width=".5" d="M20 0 V100" />
    ...
    <path stroke="white" stroke-width=".5" d="M0 10 H100" />
    <path stroke="white" stroke-width=".5" d="M0 20 H100" />
     ...
</svg>

Zdefiniowanie elementów

Gdy mamy gotowy układ współrzędnych możemy zająć się umieszczaniem na nim wybranych przez siebie układów. SVG oferuje szeroki zasób znaczników (źródło), w tym momencie skupmy się na tagach rect, circle oraz polyline. Postawmy sobie prosty cel narysowania trzech często spotykanych kształtów.
  <circle 
  cx="20" 
  cy="30" 
  r="20" 
  style="fill: rgba(0,0,0,0.75)"/>
  
  <rect 
  x="45" 
  y="30" 
  width="15" 
  height="20" 
  style="fill: rgba(0,0,0,0.75)" />
  
  <polyline points="80,10 70,50 90,50" 
  style="fill: rgba(0,0,0,0.75)"/>

Jak widać nie ma tu wiele filozofii, jedyne co definiujemy to współrzędne oraz promień okręgu, a dla prostokątu również jego wymiary. Efekt:

x=45, y=30x=20, y=30

To wszytko?

Zdefiniowaliśmy układ współrzędnych oraz kilka prostych kształtów, no ale kto pytał?
 
Osobiście jedną z rzeczy, która mnie zachwyciła podczas pracy w projekcie ze sporym zaangażowaniem SVG było używanie filtrów (zaawansowane przykłady użycia filtrów). Dodawanie patternów, tekstur, efektów jak np. szum Perlina oraz efektów 3D stoi przed nami otworem, a próg wejścia wcale nie jest taki wysoki.

Filtry oraz animacje

Spośród wielu dostępnych filtrów, moim zdaniem jednym z fajniejszych do zobrazowania sobie ogólnego potencjału jest feDiffuseLighting wewnątrz którego definiujemy fePointLight jako źródło światła. Położenie światła możemy definiować w dowolnym punkcie na układzie współrzędnych, a efekt jest moim zdaniem całkiem efektowny.
 
Dzięki użyciu efektów światła możemy uwydatnić trójwymiarowość obiektu, jego rozjaśnienie lub wyszczególnienie jakiejś konkretnej części. Do bardziej wnikliwej analizy polecam przestudiowanie tego artykułu.

Jak widać umieściłem również znacznik animate w celu zobrazowania dynamicznej zmiany położenia światła oraz wizualnego wpływu na cały układ współrzędnych oraz na elementy w nim zawarte. Na takie operacje również pozwala nam specyfikacja SVG.

<filter id="lightMe1">
    <feDiffuseLighting in="SourceGraphic" result="light"
    lighting-color="white">
    <fePointLight x="0" y="60" z="25">
    <animate 
        attributeName="x" 
        values="0;100;0" 
        dur="3s" 
        repeatCount="indefinite" />
    </fePointLight>
    </feDiffuseLighting>
    
    <feComposite in="SourceGraphic" in2="light"
    operator="arithmetic" k1="1" k2="0" k3="0" k4="0"/>
</filter>
  
<g filter="url(#lightMe1)">
    <circle  cx="20" cy="30" r="20" fill="red" />
    <rect x="45" y="30" width="15" height="20" fill="green" />
    <polyline points="80,10 70,50 90,50" fill="blue"/>
</g>

Znacznik <g/>
<g/> może służyć jako kontener przechowujący kilka elementów SVG. Transformacje oraz atrybuty są dziedziczone przez jego dzieci, dzięki czemu nie musimy definiować filtru osobno dla każdego elementu. Ma również kilka innych zastosowań i jest przydatny we współpracy z tagiem <use/>

Podsumowanie

Mimo ogromu możliwości zastosowania SVG, rzadko jest ono stosowane w bardziej zaawansowanych projektach (poza oczywiście ikonkami lub mniej zaawansowanymi wizualnie elementami). Zdecydowanie zaletą jest dosyć łatwa, wręcz prymitywna składnia. Definiujemy komponenty od góry do dołu i nie ma większego znaczenia w jaki sposób je pogrupujemy, pamiętając jedynie o zasadzie, że im niżej w kodzie umieszczony element tym bardziej „wysunięty” jest on na przód. 
 
Wadą może być czasem sam performance w przypadku generowania większej ilości elementów, jakby nie patrzeć muszą być one generowane w drzewie DOM. Alternatywą jest Canvas oraz WebGL, który umożliwa również na renderowanie grafiki 3D, co jest potencjalnym tematem na osobny artykuł.
 
Jedną z popularniejszych bibliotek dla grafiki 2D eksploatującej WebGL jest PixiJS, a dla entuzjastów 3D zdecydowanie polecam Three.js – potencjał jest ogromny.
Michał Walczuk

Front End Developer w Dogtronic. Specjalista od rzeczy ruchomych, płynnych i po prostu ładnych.

Zostaw komentarz

18 + osiemnaście =

Top