Spis treści

Jak zrobić własną ikonę SVG?

Mam pomysł na własne ikony SVG, którymi mogłabym oznaczyć tagi oraz kategorie na moim blogu. Oto mój plan:

  1. Sprawdzić, jakie tagi i kategorie posiada mój blog.
  2. Stworzyć plik(i) .svg z odpowiadającymi im ikonami.
  3. Zmienić motyw bloga tak, aby wyświetlał ikony obok kategorii i tagów.

Oto utworzone ikony - do ich wykonania użyłam jedynie (najlepszego na świecie) edytora tekstu:

Obraz svg zawierający wszystkie ikony

Tagi i kategorie bloga: ripgrep

Najpierw chcę się dowiedzieć, jakich ikon będę w ogóle potrzebować. Planuję więc przeszukać wpisy na bogu i sprawdzić, ile już "wygenerowałam" tagów. Jeśli niezbyt wiele, to jest szansa, że podejmę się tworzenia własnych ikon.

Do wyszukania w metadanych postów przypisanych im tagów i kategorii używam fantastycznego programu ripgrep:

1
2
3
4
  rg -IN -e "\.\. (tags:|category:)(.*)$" -r '$2'  posts/ |\
  tr ', ' '\n\n' |\
  sort |\
  uniq
  • Opcja -I nie wypisuje nazw plików, w których znaleziono dopasowanie
  • Opcja -N wyłącza wypisywanie numerów wierszy w plikach, w których znaleziono dopasowanie
  • Opcja -e określa wyrażenie regularne, którego szukam; tu: chcę uzyskać napis znajdujący się po tags: lub category:, poprzedzony dwoma kropkami i spacją (taki jest format metadanych w postach ze źródłem reStructuredText)
  • Opcja -r definiuje tekst zastąpienia, w którym mogę się odwołać się do indeksu bądź nazwy grupy dopasowania; tu: grupa druga; pierwszą grupę stanowi alternatywa

Ponieważ posty mogą być oznaczone wieloma tagami oddzielonymi przecinkiem, używam tr do zamiany przecinkow (i - dla ujednolicenia - spacji) na znaki nowego wiersza, po czym sortję i usuwam duplikaty inkantacją sort | uniq.

Tworzenie ikon - kartka, ołówek i edytor tekstowy

Planuję zatem utworzyć sześć ikon:

  • aoc (choinka świąteczna)
  • blog (kartka i pióro)
  • grafika (obrazek z ramką i haczykiem)
  • howto (śrubokręt?)
  • programowanie (klawiatura)

Spróbuję naszkicować jakieś obrazki, a później zamknąć je w kwadracie 100x100. Ogólne właściwości elementów svg znajdujących się na tej stronie są opisane następującym fragmentem css-a. Dzięki narysowanej szarej obwódce widzę wyraźnie położenie obrazka wewnątrz obszaru ikony.

1
2
3
4
5
6
7
8
  svg {
    stroke: rgb(0, 0, 0);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
    border: 1px solid darkgray;
  }

Każda z ikon będzie zdefiniowana wenątrz taga <svg>, którego atrybuty width i height zdefiniują wymiary ikony, przy pomocy taga defs zawierającego definicje (potencjalnie wielu) elementów; żaden z nich nie będzie jednak wyrenderowany. Dopiero użycie jednej z definicji (tag use) spowoduje jego wyrenderowanie.

Choinka

Narysuję bardzo prostą, symboliczną choinkę - trójkąt równramienny - z “soplem” u góry - w kształcie równoległoboku. Użyję do tego elementu path (ścieżki), którego atrybut d (data) będzie zawierał dyrektywy:

  • M x y ustawiającą punkt początkowy ścieżki na (x, y)
  • L x y dodający segment ścieżki od wcześniejszej pozycji do pozycji (x, y)
  • Z dodający ostatni segment od bieżącej pozycji do punktu początkowego (czyli segment “zamykający” ścieżkę)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  <svg width="100" height="100">
  <defs>
    <g id="choinka" >
      <path d="
      M 50 3
      L 45 13
      L 50 23
      L 13 90
      L 87 90
      L 50 23
      L 55 13
      Z
      "> </path>
    </g>
  </defs>
  <use href="#choinka" x="0" y="0"></use>
  </svg>

A tu gotowy svg:

Blog - prosta ikona: kartka i pióro

Kolejna ikona to blog. Będzie to prosta kartka (prostokąt) z kilkoma liniami tekstu i proste pióro. Tag defs zawiera definicję trzech elementów: notes to prostokąt, blogline to linia, którą użyję trzy razy, za każdym razem zwiększając pozycję y, a pen to zamknięta ścieżka złożona z pięciu linii.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13

  <svg width="100" height="100">
  <defs>
    <rect id="notes" x="0" y="0" width="70" height="90"/>
    <line id="blogline" x1="0" y1="0" x2="40" y2="0"></line>
    <path id="pen" d="M 0 10 L 6 0 L 12 10 L 12 80 L 0 80 Z" ></path>
  </defs>
  <use href="#notes" x="5" y="5"></use>
  <use href="#blogline" x="20" y="20"></use>
  <use href="#blogline" x="20" y="35"></use>
  <use href="#blogline" x="20" y="50"></use>
  <use href="#pen" x="85" y="12"></use>
  </svg>

Grafika

Ikona kategorii “grafika” to prosta ramka z haczykiem do zwieszenia na ścianie. Po zastanowieniu dodałam jeszcze trzy symboliczne kółeczka.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  <svg id="icon-graphics" width="100" height="100">
  <defs>
    <rect id="ext" x="0" y="0" width="70" height="70"/>
    <rect id="int" x="0" y="0" width="60" height="60"/>
    <path id="hook" d="M 0 10 L 5 0 L 10 10 " ></path>
    <g id="graphics">
      <use href="#hook" x="45" y="0"></use>
      <use href="#ext" x="10" y="10"></use>
      <use href="#int" x="15" y="15"></use>
      <circle r="10" cx="20" cy="40"/>
      <circle r="5" cx="40" cy="60"/>
      <circle r="8" cx="55" cy="30"/>
    </g>
  </defs>
  <use href="#graphics" x="10" y="10"></use>
  </svg>

Howto i tutoriale - ikona śrubokręta

To będzie wyzwanie - jak wygląda śrubokręt? Wykorzystam jego symetrię: zbuduję grupę ścieżek opisującą prawą część śrubokręta (#screwpath), a następnie użyję tej grupy w odbicu względem osi Y (złożenie transformacji skalowania i przesunięcia) tak, aby otrzymać nową grupę (#screw) zawierającą obydwie części, prawą i lewą.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
  <svg id="icon-screw" width="100" height="100">
    <defs>
      <g  id="screw" >
        <g  id="screwpath">
          <path d="
          M 50 0 L 53 0 L 55 5 
          L 55 10 L 53 15 L 53 60 L 60 60 
          L 60 65 L 53 65 L 60 70 L 60 95 
          L 55 97 L 50 99">
          </path>
          <path d="M 55 75 L 55 90"></path>
          <path d="M 53 75 L 53 90"></path>
        </g>
        <use href="#screwpath" 
        transform="scale(-1, 1) translate(-100, 0)"></use>
      </g>
    </defs>
    <use href="#screw" x="0" y="0" ></use>
  </svg>

Programowanie - ikona klawiatury

Załóżmy, że dobrą ikoną programowania będzie klawiatura. U góry narysuję trzy kółka (diody led), później narysuję cztery poziome linie (jedna ścieżka utworzona przez cztery fragmenty) oraz linie pionowe, spośród których dwie pierwsze i dwie ostatnie będą dłuższe (to boczne krawędzie klawiszy z prawej i lewej strony klawiatury).

Użwam dwóch nowych dyrektyw:

  • h <d> rysuje linię poziomą o długości od bieżącej pozycji
  • V <y> rysuje linię pionową do współrzędnej y wynoszącej
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  <svg id="icon-kbd" width="100" height="100">
  <defs>
    <g  id="kbd">
      <rect x="0" y="0" width="95" height="55"></rect>
      <circle r="3" cx="8" cy="9"></circle>
      <circle r="3" cx="15" cy="9"></circle>
      <circle r="3" cx="22" cy="9"></circle>
      <path d="
      M 5 15 h 80 
      M 5 25 h 80 
      M 5 35 h 80 
      M 5 45 h 80
      "></path>
      <path d="
      M 5 15 V 45 
      M 15 15 V 45 
      M 25 15 V 35 
      M 35 15 V 35 
      M 45 15 V 35 
      M 55 15 V 35
      M 65 15 V 35 
      M 75 15 V 45 
      M 85 15 V 45
      "></path>
    </g>
    </defs>
    <use href="#kbd" x="0" y="20" ></use>
  </svg>

Utworzenie jednego pliku .svg

Moim celem jest utworzenie jednego pliku .svg zawierającego wszystkie ikony i definicje widoków na każdą z nich.

Utworzyłam plik icons.svg, w którym zgromadziłam utworzone tutaj definicje ikon. Dodałam do niego atrybut style, aby przeglądarka miała możliwość wyrenderowania tego obrazka. Określiłam w nim również szerokość i wysokość (500px na 100px). Wyświetlam kolejne elementy zdefiniowane w defs od strony lewej do prawej, co 100 pikseli (z niewielkim przesunięciem w pionie w przypadku #graphics oraz #kbd):

1
2
3
4
5
6

    <use href="#choinka" x="0" y="0"></use>
    <use href="#blog-with-pen" x="100" y="0"></use>
    <use href="#graphics" x="200" y="10"></use>
    <use href="#screw" x="300" y="0" ></use>
    <use href="#kbd" x="400" y="20" ></use>

Dodatkowo, w sekcji <defs/>, utworzyłam widoki na poszczególne elementy (wykorzystując viewBox) i nadałam im opowiednie atrybuty id:

1
2
3
4
5
6

    <view id="icon-aoc" viewBox="0 0 100 100"/>
    <view id="icon-blog" viewBox="100 0 100 100"/>
    <view id="icon-grafika" viewBox="200 10 100 100"/>
    <view id="icon-howto" viewBox="300 0 100 100"/>
    <view id="icon-programowanie" viewBox="400 20 100 100"/>

Dzięki temu mogę w html-u użyć elementu img ze ścieżką do widoku; na przykład, aby wyświetlić jedynie klawiaturę, piszę tak:

1
  <img src="/icons.svg#icon-kbd" width="100px" height="100px"/>

Cały icons.svg:

<img src="/icons.svg" alt=“Obraz svg zawierający wszystkie ikony” width=“500px” height=“100px” />

A tutaj poszczególne fragmenty:

SVG fragment identifiers
Nie wiem jeszcze dlaczego nie działają fragment identtifiers po migracji bloga do Hugo. Muszę to zbadać.

Fragment #icon-aoc:

Fragment #icon-blog:

<img src="/icons.svg#icon-blog" width=“100px” height=“100px” /> Fragment #icon-grafika:

<img src="/icons.svg#icon-grafika" width=“100px” height=“100px” />

Fragment #icon-howto:

<img src="/icons.svg#icon-howto" width=“100px” height=“100px” />

Fragment #icon-programowanie:

<img src="/icons.svg#icon-programowanie" width=“100px” height=“100px” />

Żródła

Odnośniki do artykułów, z których korzystałam:

  1. Ręczne tworzenie svg (svg authoring)
  2. Tworzenie ikon svg
  3. Ilustrowany przewodnik po elemencie path
  4. Użycie SVG w html5