简体   繁体   中英

How to animate and erase an arc in HTML5

Here is my question : I have an animation, that builds are circle. See : http://jsfiddle.net/2TUnE/

JavaScript:

var currentEndAngle = 0
var currentStartAngle = 0;
var currentColor = 'black';

setInterval(draw, 50);


function draw() { /***************/

    var can = document.getElementById('canvas1'); // GET LE CANVAS
    var canvas = document.getElementById("canvas1");
    var context = canvas.getContext("2d");
    var x = canvas.width / 2;
    var y = canvas.height / 2;
    var radius = 75;

    var startAngle = currentStartAngle * Math.PI;
    var endAngle = (currentEndAngle) * Math.PI;

    currentEndAngle = currentEndAngle + 0.01;

    var counterClockwise = false;

    context.beginPath();
    context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
    context.lineWidth = 15;
    // line color
    context.strokeStyle = currentColor;
    context.stroke();

    /************************************************/
}

When the circle is completely drawn, I would like it to start erasing, the same way it was created (so slowly removes the black). Once the whole circle is erased, i would create the black circle again, creating some kind of "waiting / loading" effect.

What i tried to do, is check if the currentEndAngle is 2 (so the circle is complete), and then move the startAngle, but it didn't work.

Any idea?

Thanks!

EDIT : Forgot to say, the animation is gonna be over an image, so it has to be "transparent" and not white

Look whats up in this JSFiddle: http://jsfiddle.net/fNTsA/

This method is basically your code, only we use a modulo to control state. Checking if the radius is 2 is only half-right, to toggle drawing white or drawing black you should do half the radius modulo 2. The first time around you have floor(0..2/2) % 2 == 0, the second you have floor(2..4/2) % 2 == 1, and so on.

Also because the line is antialiased, it helps to have the start angle overwrite what's been drawn already, otherwise you get extra white lines you probably don't want. For the same reason, when drawing the white circle, you should draw a slightly thicker line (smaller radius, thicker line). Otherwise the antialiasing leaves behind some schmutz -- a faint outline of the erased circle.

I put the radius and width into globals which you'd put at the top:

var lineRadius = 75;
var lineWidth = 15;

And likewise this is my modulo thing, pretty standard:

currentStartAngle = currentEndAngle - 0.01;
currentEndAngle = currentEndAngle + 0.01;

if (Math.floor(currentStartAngle / 2) % 2) {
  currentColor = "white";
  radius = lineRadius - 1;
  width = lineWidth + 3;
} else {
  currentColor = "black";
  radius = lineRadius;
  width = lineWidth;
}

Fun challenge! Try the following (updated fiddle here ). I've tried to include plenty of comments to show my thinking.

    // Moved these to global scope as you don't want to re-declare 
    // them in your draw method each time your animation loop runs
    var canvas = document.getElementById("canvas1");
    var context = canvas.getContext("2d");
    var x = canvas.width / 2;
    var y = canvas.height / 2;
    var radius = 75;

    // Use objects to hold our draw and erase props
    var drawProps = {
      startAngle: 0,
      speed: 2,
      color: 'black',
      counterClockwise: false,
      globalCompositeOperation: context.globalCompositeOperation,
      lineWidth: 15            
    };

    var eraseProps = {
      startAngle: 360,
      speed: -2,
      color: 'white',
      counterClockwise: true,
      globalCompositeOperation: "destination-out",
      lineWidth: 17 // artefacts appear unless we increase lineWidth for erase
    };

    // Let's work in degrees as they're easier for humans to understand
    var degrees = 0; 
    var props = drawProps;

    // start the animation loop
    setInterval(draw, 50);

    function draw() { /***************/

        degrees += props.speed;

        context.beginPath();
        context.arc(
            x, 
            y, 
            radius, 
            getRadians(props.startAngle), 
            getRadians(degrees), 
            props.counterClockwise
        );
        context.lineWidth = props.lineWidth;
        context.strokeStyle = props.color;
        context.stroke();

        // Start erasing when we hit 360 degrees
        if (degrees >= 360) {
            context.closePath();
            props = eraseProps;
            context.globalCompositeOperation = props.globalCompositeOperation;
        }

        // Start drawing again when we get back to 0 degrees
        if (degrees <= 0) {
            canvas.width = canvas.width; // Clear the canvas for better performance (I think)
            context.closePath();
            props = drawProps;
            context.globalCompositeOperation = props.globalCompositeOperation;
        }
        /************************************************/
    }  

    // Helper method to convert degrees to radians
    function getRadians(degrees) {
        return degrees * (Math.PI / 180);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM