如何在HTML5中动画和擦除圆弧

时间:2012-08-15 18:37:05

标签: javascript html5 animation canvas geometry

这是我的问题:我有一个动画,构建是圆形。请参阅: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();

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

当圆圈被完全绘制时,我希望它以与创建时相同的方式开始擦除(因此慢慢移除黑色)。一旦整个圆圈被擦除,我将再次创建黑色圆圈,创造某种“等待/加载”效果。

我试图做的是检查currentEndAngle是否为2(所以圆圈完成),然后移动startAngle,但它不起作用。

有什么想法吗?

谢谢!

编辑:忘了说,动画会在图像上面,所以它必须是“透明的”而不是白色

2 个答案:

答案 0 :(得分:4)

看看这个JSFiddle:http://jsfiddle.net/fNTsA/

这个方法基本上就是你的代码,只有我们使用模数来控制状态。检查半径是否为2只是右半边,要切换绘图白色或绘制黑色,你应该做半径模数的一半2.第一次你有地板(0..2 / 2)%2 == 0,第二个你有楼层(2..4 / 2)%2 == 1,依此类推。

另外,因为线是抗锯齿的,所以有助于让起始角度覆盖已经绘制的线条,否则你会得到额外的白线,你可能不想要。出于同样的原因,在绘制白色圆圈时,应绘制稍粗的线(较小的半径,较粗的线)。否则,抗锯齿会留下一些schmutz - 擦除圆圈的微弱轮廓。

我把半径和宽度放在你放在顶部的全局变量中:

var lineRadius = 75;
var lineWidth = 15;

同样这是我的模数,非常标准:

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;
}

答案 1 :(得分:1)

有趣的挑战!尝试以下(更新的小提琴here)。我试图包含大量的评论以表明我的想法。

    // 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);
    }