1. ホーム
  2. Web制作
  3. html5

キャンバスが折り畳みパスを描くアニメーション

2022-01-21 22:21:43

先日、読者からWeChatでこんな質問を受けました。

そのひとつが、次の画像のようなダッシュパスアニメーション効果です。

上記のようなパスアニメーションを実装するには、一般的にsvgのアニメーション機能を利用することができます。または、パス計算と組み合わせたキャンバス描画を使用して実現します。
キャンバスで描画する場合、困難な点として

  • サブパスの計算が必要で、この部分の計算が複雑になる。(これは確かに可能です。)
  • グラデーションの計算です。図からわかるように、アニメーションのサブパスにはグラデーション効果があり、グラデーションを分割して計算するのは煩雑になりそうです。

今回は、clipメソッドを使って、クリップの領域を動的に移動させ、近似値を実現するアイデアを紹介します。その方法を紹介します。

灰色のパスの描画

パスを描画するコードは比較的単純なので、ここでは詳しく説明せず、以下のコードでポリラインパスの描画をシミュレートしています。

ValueError: source code string cannot contain null bytes

その効果は次の通りです。

明るいパスの描画

明るいパスを描画するコードは、スタイルが明るい色であることを除いて、灰色のパスを描画するコードと同じです。

OSError: [WinError 123] Incorrect filename, directory name or volume label syntax. : '<frozen importlib._bootstrap>'

その効果は次の通りです。

クリップは、明るい色のパスを描画する領域を制御します。

canvas の clip メソッドは、描画領域を制御し、それによって賢明な描画パスの一部を制御することができます: 。

        ctx.beginPath();
        ctx.rect(offset,0,100,500); // offset is equal to 0
        ctx.clip();
           ...
        ctx.stroke(); 

クリップ後、明るいパスは以下のように部分的にしか描画されません。

<イグ

アニメーションの効果

明るい道が大通りを移動する効果は、以下のコードで、offsetの値を常に変化させることで実現できます。

 offset += 2;
 if(offset > 600){
       offset = 100;
 }
requestAnimationFrame(animate);


最終的にはこのようになります。

グラデーション

グラデーションは任意の経路をたどることができないことは分かっているので、線を計算するのであれば、分割して計算するのは面倒だ。実はこの場合、線分といっても全体の進行方向は常に左から右なので、左から右へのグラデーションで近似することができます。

function createGradient(ctx,x0,y0,x1,y1){
          var grd = ctx.createLinearGradient(x0,y0,x1,y1);
           grd.addColorStop(0,'#129ab3');
           grd.addColorStop(1,"#19b5fe");
           return grd;
}

ctx.strokeStyle = createGradient(ctx,offset,0,offset + 100,0);



最終的には以下のようになります。

フルコード

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>line animate</title>
    <style>
        canvas {
            border: 1px solid #000;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        var ctx = document.getElementById( 'canvas' ).getContext( '2d' );
        var w = canvas.width,
                h = canvas.height;

        var x = w / 2,y = h / 2;

        function setupCanvas(canvas) {
            let width = canvas.width,
            height = canvas.height,
            dpr = window.devicePixelRatio || 1.0;
            if (dpr ! = 1.0 ) {
            canvas.style.width = width + "px";
            canvas.style.height = height + "px";
            canvas.height = height * dpr;
            canvas.width = width * dpr;
            ctx.scale(dpr, dpr);
            }
        }
        setupCanvas(canvas);
        var offset = 100;
        function createGradient(ctx,x0,y0,x1,y1){
           var grd = ctx.createLinearGradient(x0,y0,x1,y1);
           grd.addColorStop(0,'#9a12b3');
           grd.addColorStop(1,"#19b5fe");
           return grd;
        }

        function animate(){
            ctx.fillStyle = "black";
            ctx.fillRect(0,0,canvas.width,canvas.height);
            ctx.lineWidth = 3;
            ctx.save();
            ctx.beginPath();    
            ctx.moveTo(100,100);
            ctx.lineTo(200,100);
            ctx.lineTo(230,200);
            ctx.lineTo(250,50);
            ctx.lineTo(270,180);
            ctx.lineTo(300,60);
            ctx.lineTo(330,160);
            ctx.lineTo(350,60);
            ctx.lineTo(380,100);
            ctx.lineTo(480,100);
            ctx.strokeStyle = "gray";
            ctx.lineJoin = "round";
            ctx.stroke(); 

            ctx.beginPath();
            ctx.rect(offset,0,150,500);
            ctx.clip();
            ctx.beginPath();
            ctx.moveTo(100,100);
            ctx.lineTo(200,100);
            ctx.lineTo(230,200);
            ctx.lineTo(250,50);
            ctx.lineTo(270,180);
            ctx.lineTo(300,60);
            ctx.lineTo(330,160);
            ctx.lineTo(350,60);
            ctx.lineTo(380,100);
            ctx.lineTo(480,100);
            ctx.lineWidth = 4;
            ctx.strokeStyle = createGradient(ctx,offset,0,offset + 150,0);
            ctx.lineCap = "round";
            // ctx.globalCompositeOperation = 'lighter';
            ctx.lineJoin = "round";
            ctx.stroke(); 

            ctx.restore();

            offset += 2;
            if(offset > 600){
                offset = 100;
            }

            requestAnimationFrame(animate);
        }

        animate();
    </script>
</body>
</html>



概要

全体としては、パスの長さやグラデーション効果を厳密に制御するのではなく、近似性を利用することで、上記の機能を実現しやすくしています。  人間の目は時に細部を識別できないことがあり、視覚化は時にそれを"feel"させる唯一の方法なので、目的は達成されます。
上記の解決策は、折り返し経路の全体的な方向が同じである場合にのみ有効です。全体的な方向が水平に右へ、次に垂直に下へ、あるいは逆方向である場合は、うまくいきません。

キャンバス描画フォールドパスアニメーションについてのこの記事はこれで終わりです、キャンバスフォールドパスアニメーションに関するより多くの関連するコンテンツは、スクリプトハウスの過去の記事を検索してくださいまたは、次の関連記事を閲覧を続ける、私はあなたがよりスクリプトハウスをサポートすることを願っていますよ。