Favicons are a an important a part of on-line branding, they give a visible cue to customers, and assist them distinguish your web page from others. Despite the fact that maximum favicons are static, it’s imaginable to create animated favicons as neatly.

A continuously transferring favicon is unquestionably hectic for many customers, and in addition harms accessibility, on the other hand when it’s handiest animated for a little while in accordance with a person motion or a background tournament, corresponding to a web page load, it will possibly supply further visible knowledge—due to this fact making improvements to person enjoy.

On this put up, I’ll display you how you can create an animated round loader in a HTML canvas, and the way you’ll be able to use it as a favicon. An animated favicon loader is a useful gizmo to visualize the growth of any motion carried out on a web page, corresponding to record importing or symbol processing. You’ll be able to take a look on the demo belonging to this educational on Github as neatly.

Canvas Loader Gif DemoCanvas Loader Gif Demo

1. Create the component

First, we want to create a canvas animation that attracts a complete circle, 100% in general (this will probably be necessary once we want to increment the arc).



I’m the usage of the usual favicon dimension, 16*16 pixels, for the canvas. You’ll be able to use a dimension larger than that if you need, however notice that the canvas symbol will probably be scaled right down to the 162 pixel house when it’s carried out as a favicon.

2. Test if is supported

Throughout the onload() tournament handler, we get a reference for the canvas component [cv] the usage of the querySelector() manner, and refer its 2D drawing context object [ctx] with the assistance of the getContext() method.

onload = serve as() {
    cv = record.querySelector('#cvl'),
    ctx = cv.getContext('2nd');

    if (!!ctx) {
        /* ... */
    }
};

We additionally want to test if the canvas is supported by means of the UA by means of ensuring that the drawing context object [ctx] exists and isn’t undefined. We’ll position the entire code belonging to the burden tournament into this if situation.

3. Create the preliminary variables

Let’s create 3 extra international variables, s for the beginning perspective of the arc, tc for the identification for the setInterval() timer, and pct for the share price of the similar timer. The code tc = pct = 0 assigns 0 because the preliminary price for the tc and pct variables.

onload = serve as() {
    cv = record.querySelector('#cvl'),
    ctx = cv.getContext('2nd');

    if (!!ctx) {
        s = 1.5 * Math.PI,
        tc = pct = 0;
    }
};

To turn how the worth of s was once calculated, let me briefly give an explanation for how arc angles paintings.

Arc angles

The subtended angle (the perspective composed of the 2 rays that outline an arc) of the circumference of a circle is 2π rad, the place rad is the radian unit image. This makes the perspective for 1 / 4 arc equivalent to 0.5π rad.

subtended angle of circumferencesubtended angle of circumference
IMAGE: Wikipedia

When visualizing the loading growth, we would like the circle at the canvas to be drawn from the end place somewhat than the default proper.

Going clockwise (default course arc is drawn at the canvas) from the suitable place, the end level is reached after 3 quarters, i.e. at an perspective of 1.5π rad. Therefore, I’ve created the variable s = 1.5 * Math.PI to later denote the beginning perspective for the arcs to be drawn from at the canvas.

4. Taste the circle

For the drawing context object, we outline the lineWidth and strokeStyle houses of the circle we’re going to attract your next step. The strokeStyle assets stands for its colour.

onload = serve as() {
    cv = record.querySelector('#cvl'),
    ctx = cv.getContext('2nd');

    if (!!ctx) {
        s = 1.5 * Math.PI,
        tc = pct = 0;

        ctx.lineWidth = 2;
        ctx.strokeStyle = 'fuchsia';
    }
};

5. Draw the circle

We upload a click on tournament handler to the Load button [#lbtn] which triggers a setInterval timer of 60 milliseconds, that executes the serve as liable for drawing the circle [updateLoader()] each 60ms until the circle is totally drawn.

The setInterval() manner returns a timer identification to spot its timer which is assigned to the tc variable.

onload = serve as() {
    cv = record.querySelector('#cvl'),
    ctx = cv.getContext('2nd');

    if (!!ctx) {
        s = 1.5 * Math.PI,
        tc = pct = 0,
        btn = record.querySelector('#lbtn');

        ctx.lineWidth = 2;
        ctx.strokeStyle = 'fuchsia';

        btn.addEventListener('click on', serve as() {
            tc = setInterval(updateLoader, 60);
        });
    }
};

6. Create the updateLoader() customized serve as

It’s time to create the customized updateLoader() serve as this is to be known as by means of the setInterval() manner when the button is clicked (the development is brought about). Let me display you the code first, then we will move together with the rationale.

serve as updateLoader() {
    ctx.clearRect(0, 0, 16, 16);
    ctx.beginPath();
    ctx.arc(8, 8, 6, s, (pct * 2 * Math.PI / 100 + s));
    ctx.stroke();

    if (pct === 100) {
        clearInterval(tc);
        go back;
    }

    pct++;
}

The clearRect() manner clears the oblong house of the canvas outlined by means of its parameters: the (x, y) coordinates of the top-left nook. The clearRect(0, 0, 16, 16) line erases the whole lot within the 16*16 pixels canvas now we have created.

The beginPath() manner creates a brand new trail for the drawing, and the stroke() manner paints on that newly created trail.

On the finish of the updateLoader() serve as, the share depend [pct] is incremented by means of 1, and previous to the increment we test if it equals to 100. When it’s 100%, the setInterval() timer (recognized by means of the timer identification, tc) is cleared with the assistance of the clearInterval() manner.

The primary 3 parameters of the arc() manner are the (x, y) coordinates of middle of the arc and its radius. The fourth and 5th parameters constitute the get started and finish angles at which the drawing of the arc starts and ends.

We already determined the start line of the loader circle, which is on the perspective s, and it’ll be the similar in the entire iterations.

The top perspective on the other hand will increment with the p.c depend, we will calculate the dimension of the increment within the following approach. Say 1% (the worth 1 out of 100) is an identical to perspective α out of 2π in a circle (2π = perspective of the entire circumference), then the similar will also be written as the next equation:

1/100 = α/2π

On rearranging the equation:

α = 1 * 2π /100
α = 2π/100

So, 1% is an identical to the perspective 2π/100 in a circle. Thus, the top perspective all through every p.c increment is computed by means of multiplying 2π/100 by means of the share price. Then the result’s added to s (get started perspective), so the arcs are drawn from the similar beginning place each time. Because of this we used the pct * 2 * Math.PI / 100 + s method to calculate the top perspective within the code snippet above.

7. Upload the favicon

Let’s position a favicon hyperlink component into the HTML segment, both without delay or by way of JavaScript.


Within the updateLoader() serve as, first we fetch the favicon the usage of the querySelector() manner, and assign it to the lnk variable. Then we want to export the canvas symbol each time an arc is drawn into an encoded image by means of the usage of the toDataURL() manner, and assign that information URI content material because the favicon symbol. This creates an animated favicon which is the similar because the canvas loader.

onload = serve as() {
    cv = record.querySelector('#cvl'),
    ctx = cv.getContext('2nd');

    if (!!ctx) {
        s = 1.5 * Math.PI,
        tc = pct = 0,
        btn = record.querySelector('#lbtn'),
        lnk = record.querySelector('hyperlink[rel="icon"]');

        ctx.lineWidth = 2;
        ctx.strokeStyle = 'fuchsia';

        btn.addEventListener('click on', serve as() {
            tc = setInterval(updateLoader, 60);
        });
    }
};

serve as updateLoader() {
    ctx.clearRect(0, 0, 16, 16);
    ctx.beginPath();
    ctx.arc(8, 8, 6, s, (pct * 2 * Math.PI / 100 + s));
    ctx.stroke();

    lnk.href= cv.toDataURL('symbol/png');

    if (pct === 100) {
        clearTimeout(tc);
        go back;
    }

    pct++;
}

You’ll be able to take a look on the complete code on Github.

Bonus: Use the loader for async occasions

When you want to make use of this canvas animation together with a loading motion in a internet web page, assign the updateLoader() serve as as the development handler for the progress() tournament of the motion.

As an example, our JavaScript will exchange like this in AJAX:

onload = serve as() {
    cv = record.querySelector('#cvl'),
    ctx = cv.getContext('2nd');

    if (!!ctx) {
        s = 1.5 * Math.PI,
        lnk = record.querySelector('hyperlink[rel="icon"]');

        ctx.lineWidth = 2;
        ctx.strokeStyle = 'fuchsia';
    }

    var xhr = new XMLHttpRequest();
    xhr.addEventListener('growth', updateLoader);
    xhr.open('GET', 'https://xyz.com/abc');
    xhr.ship();
};

serve as updateLoader(evt) {
    ctx.clearRect(0, 0, 16, 16);
    ctx.beginPath();
    ctx.arc(8, 8, 6, s, (evt.loaded*2*Math.PI/evt.general+s));
    ctx.stroke();

    lnk.href = cv.toDataURL('symbol/png');
}

Within the arc() manner, change the share price [pct] with the loaded assets of the development—it denotes how a lot of the record has been loaded, and rather than 100 use the total assets of the ProgressEvent, which denotes the entire quantity to be loaded.

There’s no use for setInterval() in such circumstances, because the growth() tournament is routinely fired because the loading progresses.

The put up How to Create an Animated Favicon Loader with JavaScript gave the impression first on Hongkiat.

WordPress Website Development

[ continue ]