0

HTML5の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/ 誰かが答えを知っていますか?図形やテキストで正常に機能します。

4

1 に答える 1

2

globalCompositeOperation(xor)は、「時計の針」のような回転線では機能しません…。理由は次のとおりです。

垂直線を引くと仮定します。次に、最初の線の右側に2番目の垂直線を描画します。2番目の垂直線が最初の線と半分 重なっていると仮定します。

Canvas.globalCompositeOperation =” xor”を使用すると、重複する領域が削除されるため、2行目では、最初の行の半分とそれ自体の半分が削除されます。

コードとフィドルは次のとおりです: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によって提供され、拡張された回答が可能になりました]

私はあなたの新しいコードを見て、いくつかの変更と最適化を提案しています。

元の答えで言ったように、斜めに描かれた線を効果的に消すことはできません。これは、ブラウザが自動的に行うアンチエイリアシングによるものです。キャンバスのアンチエイリアシングをオフにすることはできません。

変更後の結果のフィドルは次のとおりです。http: //jsfiddle.net/m1erickson/9QD65/

変更点:

信じられないかもしれませんが、通常、各アニメーションループ中にキャンバスを完全に消去して完全に再描画します。Canvasは、これらの再描画を処理するのに十分な速さです。特に、CanvasがGPUで高速化されているためです。どうしてもパフォーマンスを最適化する必要がある場合は、消去/再描画する必要のあるキャンバスの「ダーティ」領域を定義し、他の領域は以前に描画したままにすることができます。実際には、このタイプのパフォーマンスが必要になると、キャンバスは非常に複雑になるため、ダーティエリアを定義するよりも完全にクリア/再描画する方が効率的です。

最適化:

これらの値は一度計算して再利用できるため、canvas、context、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>
于 2013-02-25T06:56:08.993 に答える