🚨 Putin is a war criminal. Russians are bombing hospitals. πŸ’”πŸ‡ΊπŸ‡¦

Quick primer on SVG paths

SVG, or Scalable Vector Graphics, is a file format for vector drawings. I had a problem to solve - I wanted to animate an SVG from JavaScript. I’ll describe how and what I learned on how SVG paths work to solve my problem.

The problem

I wanted to animate Varasto’s vector logo - to make the “hard drive LEDs” (the circles on the right) toggleable on/off individually:

The path to the solution

Understanding the structure of the drawing

Browsers can draw & debug SVG natively. I opened the SVG in Brave to begin understanding how the image is made up:

I identified the <path> element that contains the LEDs. The problem is that the same element contains a bunch of other stuff too.

Maybe I can break the LEDs away from the larger path into three more paths (one for each invividual LED), so instead of:

<path d="all the stuff" />

I want this:

<path d="most of the stuff" />
<path d="led 1" />
<path d="led 2" />
<path d="led 3" />

How does the path element work?

It looks like garbage:

<path d="M142.4 25.604a1.218 1.218 0 000-2.435 1.218 1.218 0 000 2.435zM111.586 25.822l1.778-1.778c.3-.302.3-.793 0-1.093a.771.771 0 00-.546-.224.77.77 0 00-.545.224l-1.779 1.779a.767.767 0 000 1.092.79.79 0 001.092 0z..."/>

I read the tutorials (mentioned in Additional reading) to understand, that this is a highly-compressed form that we can expand to make it easier to understand. There might be tools for this (I tried to quickly find but came up short) but I did this by hand.

The above is the same as:

M 142.4 25.604
a 1.218 1.218 0 000-2.435 1.218 1.218 0 000 2.435
z
M 111.586 25.822
l 1.778-1.778
c .3-.302.3-.793 0-1.093
a .771.771 0 00-.546-.224.77.77 0 00-.545.224
l -1.779 1.779
a .767.767 0 000 1.092.79.79 0 001.092 0
z
... lots of more

What do those letters mean?

For each letter, reading from the tutorial I built a quick reference for myself:

UPPERCASE = absolute coordinate
lowercase = relative coordinate

m = move
a = arc
l = line to
c = cubic curve
z = (close path) draw line from last point to first

Identifying code for the LEDs

Now having prettified the whole path and understanding something about the letters, I began to see the a pattern for the circles:

  • Move to coordinates
  • Draw arc
  • Close path
    • This doesn’t seem to be required though - I tried removing this and the image didn’t change at all.

So, the code for each LED looked like this:

M 142.4 25.604
a 1.218 1.218 0 000-2.435 1.218 1.218 0 000 2.435
z

I verified this by removing that piece of code and reloading the page in browser:

The result

Now it was just a matter of moving the code for the LEDs to separate paths, and giving each element an ID (so I can control them from JavaScript).

Here’s the new SVG (some parts omitted):

<svg xmlns="http://www.w3.org/2000/svg" width="591.04" height="163.84" viewBox="0 0 156.379 43.349">
  <g fill="#337ab7">
    <path id="ledTop"    d="M142.4 15.402a 1.217 1.217 0 000-2.433 1.218 1.218 0 000 2.432z" />
    <path id="ledMiddle" d="M142.4 25.604a 1.217 1.217 0 000-2.433 1.218 1.218 0 000 2.432z" />
    <path id="ledBottom" d="M142.4 35.673a 1.217 1.217 0 000-2.433 1.218 1.218 0 000 2.432z" />
    <path d="original with led elements removed.."/>
    <path d="original unchanged.."/>
  </g>
</svg>

And here’s a proof of concept JavaScript for animating:

const leds = {
    top: document.querySelector('#ledTop'),
    middle: document.querySelector('#ledMiddle'),
    bottom: document.querySelector('#ledBottom'),
}
const randomLedState = (chance) => Math.random() < chance/100;
const ledVisibility = (el, visible) => { el.style.visibility = visible ? 'visible' : 'hidden'; }

setInterval(() => {
    ledVisibility(leds.top, randomLedState(75));
    ledVisibility(leds.middle, randomLedState(50));
    ledVisibility(leds.bottom, randomLedState(25));
}, 100);

And here’s how it looks:

Looks pretty badass, if I can say so myself.

Additional reading


comments powered by Disqus