admin管理员组

文章数量:1326282

Here is my question : I have an animation, that builds are circle. See : /

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 pletely 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 plete), 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

Here is my question : I have an animation, that builds are circle. See : http://jsfiddle/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 pletely 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 plete), 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

Share Improve this question edited Aug 15, 2012 at 21:20 Ebpo asked Aug 15, 2012 at 18:37 EbpoEbpo 8044 gold badges14 silver badges22 bronze badges 4
  • 1 Have you considered writing an animated SVG and just embedding it as an image? – Mechanical snail Commented Aug 15, 2012 at 20:33
  • I have no idea what it is. It's my first shot at HTML5. I'll look into this. – Ebpo Commented Aug 15, 2012 at 21:20
  • 1 SVG is a vector graphics image format that natively supports animation. See w3/TR/SVG/animate.html for the spec and developer.mozilla/en-US/docs/SVG/SVG_animation_with_SMIL for some examples. – Mechanical snail Commented Aug 15, 2012 at 21:22
  • SVG is part of the HTML5 spec. – Spudley Commented Aug 15, 2012 at 21:24
Add a ment  | 

2 Answers 2

Reset to default 4

Look whats up in this JSFiddle: http://jsfiddle/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 ments 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);
    }

本文标签: javascriptHow to animate and erase an arc in HTML5Stack Overflow