使用globalCompositeOperation与行?

时间:2013-02-25 04:24:10

标签: html html5-canvas globalcompositeoperation

我正在尝试用HTML 5的canvas元素制作一个时钟。

我要做的是每秒做一行,然后删除上一行。

我想使用globalCompositeOperation='xor';绘制另一行来删除上一行,但它不起作用!

以下是代码:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Clock</title>
    </head>

    <body onload="spin()">
    <canvas id="myCanvas" width="578" height="400"></canvas>
    <script>
    var firstTime = 0;
    var prevX=null;
    var prevY=null;

    function spin() {
        //get the canvas element
        var canvas = document.getElementById('myCanvas');
        var context = canvas.getContext('2d');

        //get the right angle for the clock hand
        var date = new Date;
        var seconds = date.getSeconds();
        var a = seconds*6;
        var angleRadian = a*Math.PI/180;
        var angle = 1/2*Math.PI - angleRadian;

        if(a > 360)
            a = 0; 
        //Erase the previous line, if it has been drawn.
        if(prevX!=null)
            erasePrevLine(angle, canvas, context);
        //draw line
        drawLine(angle, 100, canvas, context);
        //repeat for the next second
        setTimeout(spin, 500);
    }
    function drawLine(angle, radius, canvas, context)   {
        var centerX = canvas.width/2;
        var centerY = canvas.height/2;

        var xTarget = centerX + Math.cos(angle)*radius;
        var yTarget = centerY - Math.sin(angle)*radius;

        //save this state to be erased
        prevX = xTarget;
        prevY = yTarget;

        //draw
        context.beginPath();
        context.moveTo(centerX,centerY);
        context.lineTo(xTarget, yTarget);
        context.stroke();
    }
    function erasePrevLine(angle, canvas, context)  {
        context.globalCompositeOperation = 'xor';
        var centerX = canvas.width/2;
        var centerY = canvas.height/2;
        prevAngle = angle + (Math.PI/180*6);
        var xTarget = prevX;
        var yTarget = prevY;

        //draw on the previous line
        context.beginPath();
        context.moveTo(centerX,centerY);
        context.lineTo(xTarget, yTarget );
        context.stroke();
    }
    </script>
    </body>
    </html>

以下是实例:http://jsfiddle.net/pyerT/1/ 有人知道答案吗?它适用于形状和文字..

1 个答案:

答案 0 :(得分:2)

globalCompositeOperation(xor)无法像“时钟指针”那样在旋转行上运行......这就是原因:

假设您绘制一条垂直线。然后在第一条右侧绘制第二条垂直线。假设第二条垂直线将第一条线重叠一半。

Canvas.globalCompositeOperation =“xor”会导致重叠区域被删除,因此第二行会删除 half 第一行以及自身的一半。

这是代码和小提琴:http://jsfiddle.net/m1erickson/e24KU/

    function drawLine(){
        ctx.globalCompositeOperation="xor";
        ctx.strokeStyle="red";
        ctx.lineWidth=10;
        ctx.beginPath();
        ctx.moveTo(posX,10);
        ctx.lineTo(posX,100);
        ctx.stroke();
        posX+=5;
    }

这是一个围绕中心点的“时钟指针”的小提琴:http://jsfiddle.net/m1erickson/hW2EY/

但是,如果我们尝试在旋转线上使用“xor”,则线条会以>覆盖,因此xor不完整。

这是一个小提琴,显示旋转时“xor”行无效:http://jsfiddle.net/m1erickson/f7hHx/

[编辑:OP提供的新代码允许扩展答案]

我查看了您的新代码,并建议进行一些更改和优化。

正如我在原始答案中所说,无法有效地删除以某个角度绘制的线条。这是由于浏览器自动执行的抗锯齿 - 无法关闭画布的antiAliasing。

以下是更改后结果的小提琴:http://jsfiddle.net/m1erickson/9QD65/

的变化:

信不信由你:通常在每个动画循环中完全擦除并完全重绘画布! Canvas真的足够快,可以处理这些重绘 - 特别是现在画布是GPU加速的。如果绝对需要优化您的性能,您可以定义必须擦除/重绘的画布的“脏”区域,并保留以前绘制的其他区域。实际上,一旦你需要这种类型的性能,你的画布就会非常复杂,以至于完全清除/重绘比尝试定义脏区更有效。

优化:

将画布,上下文,centerX,centerY移出动画循环,因为这些值可以计算一次并重复使用。

以下是我建议的代码供您查看:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Clock</title>
    </head>

    <body onload="spin()">
    <canvas id="myCanvas" width="578" height="400"></canvas>
    <script>
    var firstTime = 0;
    var canvas = document.getElementById('myCanvas');
    var context = canvas.getContext('2d');
    var centerX=canvas.width/2;
    var centerY=canvas.height/2;
    var canvasWidth=canvas.width;
    var canvasHeight=canvas.height;

    function spin() {
        //get the right angle for the clock hand
        var date = new Date;
        var seconds = date.getSeconds();
        var a = seconds*6;
        var angleRadian = a*Math.PI/180;
        var angle = 1/2*Math.PI - angleRadian;

        if(a > 360)
            a = 0; 
        //draw line
        drawLine(angle, 100, canvas, context, "black",1);
        //repeat for the next second
        setTimeout(spin, 500);
    }

    function drawLine(angle, radius, canvas, context)   {
        var xTarget = centerX + Math.cos(angle)*radius;
        var yTarget = centerY - Math.sin(angle)*radius;

        //clear the canvas
        context.clearRect(0,0,canvasWidth,canvasHeight);

        //draw
        context.save();
        context.beginPath();
        context.moveTo(centerX,centerY);
        context.lineTo(xTarget, yTarget);
        context.stroke();
        context.restore()
    }

    </script>
    </body>
    </html>