Now that I have an SVG image, that is, the site logo, it might be time to explore more ways to mess with SVG images.

So, what if I want to create a “spinner” based on the site logo?

The reference implementation

The Angular Material component library does contain an SVG-based spinner.

A question to ask is: how can they animate the starting point and ending point of the arc, when the SVG circle element does not actually provide attributes for that?

The answer is somewhat surprising: they don’t draw an arc; they draw a circle in dashed line. It just happens that the dashed line has the period length equal to the perimeter of the circle.

<circle
    *ngSwitchCase="true"
    cx="50%"
    cy="50%"
    [attr.r]="_circleRadius"
    [style.animation-name]="'mat-progress-spinner-stroke-rotate-' + diameter"
    [style.stroke-dashoffset.px]="_strokeDashOffset"
    [style.stroke-dasharray.px]="_strokeCircumference"
    [style.stroke-width.%]="_circleStrokeWidth"></circle>

CSS Animation

While the reference implementation uses Angular, it is because it tries to provide a complex API: one could control the size of the circle, the width of the line, and switch between determinate mode and indeterminate mode, etc.

For a simple example, implementing a spinner does not involve any Javascript code. I just needed to embed a CSS animation in it. Here is the code:

<svg width="64mm" height="64mm" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
    <defs>
    <style type="text/css">
    @keyframes rotate {
        0%      { stroke-dashoffset: 0;}
        100%   { stroke-dashoffset: 160.5874481201172;}
    }
    path {
         animation: rotate 2s linear 0s infinite;
    }
    </style>
    </defs>
    <g>
    <path d="m32.585 22.364 6.1468 0.254 0.762 4.1148 3.9624 0.254c0.6096-2.9972 0.9652-6.096 0.9652-9.144l-0.508-0.508h-24.028l-0.254 2.9464c1.1684 0.508 2.4384 0.9652 3.81 1.27v25.806c-1.3716 0.3048-2.6416 0.762-3.81 1.27v
2.7432h18.288l0.254-2.7432-6.096-0.508c0.4064-2.3368 0.508-4.6228 0.508-7.1628v-4.318l8.89 0.9652c0.254-2.2352 0.254-4.0132 0-6.2484l-8.89 0.9652z" fill="none" stroke="#000"
          stroke-dasharray="60.5874481201172 100"
          stroke-dashoffset=0
          />
    </g>
</svg>

It should be self-evident how it works.

However, where does I get the magical number 160.5874481201172, that is, the perimeter of the weird “F” shape?

Getting the perimeter

A quick Google search leads to this StackOverflow discussion. Essentially, what works is the following code:

var myPath = document.getElementById("word");
var length = myPath.getTotalLength();
console.log(length);

By using Javascript to dynamically get the perimeter, one avoids the magical numbers in the code. The downside is that there is now Javascript code to maintain.

OK. Now I am back on the Angular track, and this is now maintained as an Angular component.

Demo!

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.