indexpost archiveatom feed syndication feed icon

Messing with SVG

2021-06-19

I recently picked up a copy of SVG Essentials and have been reading it to get a better grasp on the fundamentals of the format and learn where I might use it. To really ease into things slowly I started with some very simple graphics of my own.

An Icon

I added an icon to the Atom feed link at the top of each page of this site. Rather than pushing a second request for such an inconsequential image asset I have inlined it into the site generator page templates. I started from this SVG off of wikimedia and began trimming things down.

syndication feed icon
<svg xmlns="http://www.w3.org/2000/svg"
     viewBox="0 0 8 8" width="128" height="128">
  <title>syndication feed icon</title>
  <circle cx="1" cy="6.5" r="1" fill="#000"/>
  <path d="m 0 4.5 a 3 3 0 0 1 3 3 h 1 a 4 4 0 0 0 -4 -4 z 
           M 0 2.5 a 5 5 0 0 1 5 5 h 1 a 6 6 0 0 0 -6 -6"
        fill="#000"/>
</svg>

The whole thing is made up of just the three distinct elements. First up is the circle and there is nothing surprising about it. The next two elements are more interesting and utilize a single <path> element which proves to be a much more fine-grained control than an element like <circle>. In an effort to understand it fully I started with just one piece:

<svg xmlns="http://www.w3.org/2000/svg"
     viewBox="0 0 8 8" width="128" height="128">
  <path d="m 0 4.5 a 3 3 0 0 1 3 3 h 1 a 4 4 0 0 0 -4 -4 z"
        fill="#000"/>
</svg>

The first piece seen above is defined by the series of instructions m 0 4.5 a 3 3 0 0 1 3 3 h 1 a 4 4 0 0 0 -4 -4 z. These can be further broken out into the individual instructions and their arguments:

m 0 4.5
move to relative position (0, 4.5)
a 3 3 0 0 1 3 3
The arc (a) is defined by an ellipse with the following properties, where the final two digits designate the end of the stroke (relative):
  • rx = 3
  • ry = 3
  • x axis rotation = 0
  • large arc flag = 0
  • sweep flag = 1
  • dx = 3
  • dy = 3
h 1
horizontal line of length 1
a 4 4 0 0 0 -4 -4
  • rx = 4
  • ry = 4
  • x axis rotation = 0
  • large arc flag = 0
  • sweep flag = 0
  • dx = -4
  • dy = -4
z
close form, return to initial position (0, 4.5) in this case

To understand the arc elements I found it helpful to break things down even further:

I think it is instructive to look at the components of a single path element. Here the red arc is drawn left to right first, followed by the orange horizontal line, the blue arc is drawn from right to left before returning to the starting position to complete the shape.

The second, larger arc is necessarily similar to the first but you might notice the start and end positions are shifted by 1, making the difference in radius of the two ellipses exactly 1. Additionally, the second arc has a sweep flag of 1 instead of 0 in order to achieve the right-to-left movement. The <path> element handles any number of instructions so the beginning of the next element is begun after the above is finished; rather than constructing a new <path> node.

A Diagram

Pleasantly surprised with how easy it was to accomplish a basic icon I started thinking of where else I might use SVG images. It happened that I was reading through the Mercurial evolve guide and found at one point a placeholder with the following:

[diagram: Venn diagram showing nested strict subsets]

I thought of all the times I have found myself trying (and failing) to get a clear picture of a whiteboard with my phone or to draw up a diagram in an Office product like PowerPoint and realized such a simple diagram would be a breeze with SVG:

full repository obsolete changesets hidden changesets repo ⊇ obsolete ⊇ hidden
    <svg xmlns="http://www.w3.org/2000/svg"
         width="450" height="200">

      <circle cx="100" cy="100" r="95" fill="#3e26a8"/>
      <text x="200" y="40">full repository</text>

      <circle cx="120" cy="120" r="50" fill="#01bac4"/>
      <text x="200" y="90">obsolete changesets</text>

      <circle cx="130" cy="130" r="20" fill="#f9fb15"/>
      <text x="200" y="135">hidden changesets</text>

      <text x="20" y="220">repo ⊇ obsolete ⊇ hidden</text>
    </svg>

Another Diagram

When I previously wrote about understanding Asteroids I slipped an SVG diagram I had written by hand into the explanation text as well to demonstrate a point about the different hit radii.

    <svg xmlns="http://www.w3.org/2000/svg"
         viewBox="0 0 60 50" width="400" height="300">
      <circle cx="27" cy="26" r="23" fill="none" stroke="orange" stroke-dasharray="4 2"/>
      <circle cx="27" cy="26" r="13" fill="none" stroke="red" stroke-dasharray="4 1"/>
      <polygon id="asteroid" points="15 13
                                     27 15
                                     40 10
                                     47 15
                                     45 21
                                     49 27
                                     36 36
                                     39 40
                                     28 48
                                     25 35
                                     5 34
                                     15 25"
               fill="none" stroke="black">
      </polygon>
    </svg>

Comparing to Alternatives

Rooting through old posts I took a look at an image I drew by hand with a tablet for a post on K-D Trees. I distinctly remember being annoyed with my own handwriting using the tablet and figured I may as well try something similar in SVG:

5,7 4,5 6,8 3,2 3,9 9,1
    <svg xmlns="http://www.w3.org/2000/svg"
         viewBox="0 0 90 70" width="400" height="300">
      <line x1="50" y1="10" x2="25" y2="30" stroke-width="0.5" stroke="black"/>
      <line x1="25" y1="30" x2="10" y2="50" stroke-width="0.5" stroke="black"/>
      <line x1="25" y1="30" x2="35" y2="50" stroke-width="0.5" stroke="black"/>
      <line x1="50" y1="10" x2="75" y2="30" stroke-width="0.5" stroke="black"/>
      <line x1="75" y1="30" x2="60" y2="50" stroke-width="0.5" stroke="black"/>
      <line x1="75" y1="30" x2="60" y2="50" stroke-width="0.5" stroke="black"/>

      <circle cx="50" cy="10" r="5" stroke-width="0.5" stroke="black" fill="white"/>
      <text x="50" y="10" font-size="4px" text-anchor="middle" dominant-baseline="middle">5,7</text>

      <circle cx="25" cy="30" r="5" stroke-width="0.5" stroke="black" fill="white"/>
      <text x="25" y="30" font-size="4px" text-anchor="middle" dominant-baseline="middle">4,5</text>

      <circle cx="75" cy="30" r="5" stroke-width="0.5" stroke="black" fill="white"/>
      <text x="75" y="30" font-size="4px" text-anchor="middle" dominant-baseline="middle">6,8</text>

      <circle cx="10" cy="50" r="5" stroke-width="0.5" stroke="black" fill="white"/>
      <text x="10" y="50" font-size="4px" text-anchor="middle" dominant-baseline="middle">3,2</text>

      <circle cx="35" cy="50" r="5" stroke-width="0.5" stroke="black" fill="white"/>
      <text x="35" y="50" font-size="4px" text-anchor="middle" dominant-baseline="middle">3,9</text>

      <circle cx="60" cy="50" r="5" stroke-width="0.5" stroke="black" fill="white"/>
      <text x="60" y="50" font-size="4px" text-anchor="middle" dominant-baseline="middle">9,1</text>
    </svg>

While not distinctly better than my previous attempt, the file size is drastically smaller (and obviously scales better). The PNG image I produced using Krita is about 13KB which seems pretty heavy for such a simple image. Also interesting is comparing a similar image from the Wikipedia page on KD Trees, where the SVG was created in Inkscape. The result is reasonably similar to what I have above but is 14KB in size. For reference, that is not much smaller than this entire page with all of the graphics embedded in it directly (about 16KB).

Having found so many uses for SVG in such a short amount of time is satisfying and I think I'll make an effort to incorporate them into my own writing where it makes sense. While I have never really achieved any proficiency with graphics programs outside of Microsoft Paint it is nice to find I can create usable graphics in a text editor.