I introduced the basics of Canvas drawing before, but this time I will introduce drawing a circle with gradient effect.

A gradual circle

Gradients are widely used, and it’s cool to combine them with circles to make progress bars. Today we’ll draw a circle like this:

Canvas gradient

Based on Canvas drawing, we know that the main methods for painting Canvas are ctx.fillStyle and ctx.strokeStyle. Here is a circle, so the strokeStyle method is mainly discussed, and fillStyle method is also applicable.

Take a look at the circle above, like “bending” a linear gradient into a circle. Canvas has support for linear gradients, we can try it:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext('2d');
    ctx.lineWidth = 7;

    ctx.beginPath(); // Open a new road
    ctx.moveTo(170.120);

    var grd=ctx.createLinearGradient(0.0.170.0);
    grd.addColorStop("0"."black");
    grd.addColorStop("0.3"."magenta");
    grd.addColorStop("0.5"."blue");
    grd.addColorStop("0.6"."green");
    grd.addColorStop("0.8"."yellow");
    grd.addColorStop(1."red");

    ctx.strokeStyle = grd;
    ctx.arc(120.120.50.0 ,Math.PI*2);
    ctx.stroke(); / / draw circlesCopy the code

What it looks like:

  • ctx.createLinearGradientCreate a linear gradient object, where the first two arguments are the x and y coordinates of the starting point, and the last two arguments are the x and y coordinates of the ending point, and here is a horizontal linear gradient.
  • grd.addColorStopSet the gradient point, similar to cSS3 gradientcolor-stop.
  • After setting the gradient object, apply the gradient object tostrokeStyleYou can achieve the gradient effect.

Add some animation to facilitate the progress bar:

    var canvas = document.getElementById("canvas1");
    var ctx1 = canvas.getContext('2d');
    //
    // Set the gradient parameters in the middle of the same code
    //
    function draw(ctx, x) {
        ctx.clearRect(0.0.300.300);
        ctx.beginPath();
        ctx.strokeStyle = grd;//'#ff4444';
        if (x < Math.PI*2) {
            x += Math.PI/100;
        } else {
            x = 0;
        }
        ctx.arc(80.80.50.0, x, false); / / draw circles
        ctx.stroke();
        requestAnimationFrame(function () {
            draw(ctx, x);
        });
    }

    requestAnimationFrame(function () {
        draw(ctx1, 0);
    });Copy the code

Now we have animation, we have gradients, but one of the biggest problems is that this is a gradient from left to right, with the top and bottom colors being symmetrical. And we want the effect to be asymmetric up and down.

Asymmetrical gradient ring

Canvas provides linear gradient and radial gradient (that is, gradient from the center of the circle to the outside, with the same color on a circle), neither of which can satisfy the rough circle drawn by our designers.

Instead, use another thing called ctx.Createpattern.

The createPattern method is defined as follows:

The createPattern() method repeats the specified element in the specified direction. Elements can be images, videos, or other Canvas elements. Repeated elements can be used to draw/fill rectangles, circles, lines, etc.

It says you can specify a picture to draw a circle.

Here’s the code:

    var canvas = document.getElementById("canvas2");
    var ctx2 = canvas.getContext('2d');
    ctx2.lineWidth = 8;
    ctx2.lineCap="round";

    var img;
    img = new Image();
    img.src = "./bg.png";

    if (img.complete) {
       setImageFill();
    } else {
       img.onload = setImageFill;
    }

    var newFill = null;
    function setImageFill() {
        newFill = ctx2.createPattern(img, 'no-repeat');
        drawNew(ctx2, 0);
    }

    function drawNew(ctx, x) {
        ctx.clearRect(0.0.300.300);
        ctx.beginPath();
        ctx.strokeStyle = newFill;
        if (x < Math.PI*2) {
            x += Math.PI/100;
        } else {
            x = 0;
        }
        ctx.arc(50.50.46.0, x, false);
        ctx.stroke();
        requestAnimationFrame(function () {
            drawNew(ctx, x);
        });
    }Copy the code

What it looks like:

There are a few things to note about this code:

  1. The first is to load the picture, to wait for the picture after loading to draw, you can also consider the picture base64 in;
  2. ctx2.createPattern(img, 'no-repeat')Create a Pattern without repeating the image.
  3. ctx.arc(50, 50, 46, 0, x, false);Notice when you draw a circle if you want to draw a radius of 50, you have to subtract 50 from half of the width of the stroke, which is 50-8/2 and that’s where the radius 46 came from. Because stroke is to put the line in the middle and then spread it out to the sides, so setlineWidthWhen it’s 8, the actual stroke we see is 4;
  4. ctx2.lineCap="round";Set both ends of the stroke to be circles.

And here’s the picture we used:

If you want to support various sizes, you can now draw the picture on another canvas and make a resize.

    var bg = $('<canvas>') [0];
    var size = 100;
    bg.width = size;
    bg.height = size;
    bg.getContext('2d').drawImage(img, 0.0, size, size);Copy the code

So far, such a SAO qi ring is finished.

Full code: github.com/bob-chen/ca…

Tips: Mobile solution to Canvas sawtooth

The Canvas is actually a bitmap. When the hd screen is running sideways on the mobile terminal, we need to draw a larger Canvas according to window.devicePixelRatio, and then reduce it. The principle is similar to that of using double map on the mobile terminal, which can solve the sawtooth problem to a large extent, and it can hardly be seen under the white background. But a closer look at the black background shows a slight jagged edge.

    //Variables global to the chart
    var width = context.canvas.width;
    var height = context.canvas.height;

    //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
    if (window.devicePixelRatio) {
        context.canvas.style.width = width + "px";
        context.canvas.style.height = height + "px";
        context.canvas.height = height * window.devicePixelRatio;
        context.canvas.width = width * window.devicePixelRatio;
        context.scale(window.devicePixelRatio, window.devicePixelRatio);
    }Copy the code

reference

www.w3school.com.cn/tags/canvas…

www.w3school.com.cn/tags/canvas…

P.S. has added an IMPLEMENTATION of SVG: a round-SVG implementation that is even scarier than expected