スタートページJavascriptCANVAS

アニメーション(2)

以前の図を消す


基本的には、追加表示した部分(動かした画像)だけを消去することはできません。
追加表示する以前に、CANVASの全ピクセル(この時点の背景)を一時保存してから追加表示を行い、その後保存したものを復元することにより、以前に動かした部分を消去したように見せるのです。

その追加表示と復元の操作に遅延時間を与えることにより「追加表示=動き」とするのです。

次のようなループになります。
    背景の表示;
    var imgData = ctx.getImageData(0, 0, cw, ch); // 背景の全ピクセルの取得 backup
    var t = 0; // ループ初期設定など
    var timerId = setInterval(function(){
      ctx.putImageData(imgData, 0, 0); // 背景の復元 restore
      追加表示;
      if(ループ打切条件) {
        clearInterval(timerId); // ループ打切
        // 打切後の処理
      }
      t++; // ループ打切判定のための処理など
    }, 経過時間ミリ秒);
    // ループ以前に実行され、ループ打切後にここには来ません。上のループ打切条件で処理します。

例1:追加表示部分をすべて消去する場合


function graph1() {
    // ===== 背景の表示
    cw = 400; ch = 400;
    xmin = -4; xmax = 4; ymin = -4; ymax = 4;
    setCanvas("canvas1", "white");
    drawLineYscale(1, "gray", 1, "black", 4);
    drawLineXscale(1, "gray", 1, "black", 4);
    // ===== 背景の保存 
    var imgData = ctx.getImageData(0, 0, cw, ch);
    var dx = 1;
    var t = 0;
    // ===== ループ
    var timerId = setInterval(function(){
        ctx.putImageData(imgData, 0, 0);
        x = xmin + dx*t;
        drawRect(x,1, x+dx,0, "red", 2, "yellow");
        if(x>xmax) {    // ループ打切
            drawRect(0,1, 1,2, "black", 2, "red");
            clearInterval(timerId);
        }
        t = t+1;
    }, 500);
}

追加表示の一部は消去しない場合

消去しない部分を表示した後に保存する必要があります。
 そのため、消去しない部分を先に、消去する部分を後に記述することが重要です。


            // ここまでは例1と同じ
    var timerId = setInterval(function(){
        ctx.putImageData(imgData, 0, 0);             // 消去しない部分も復元される
        x = xmin + dx*t;
        // ===== 消去しない部分
        drawRect(x,-1, x+dx,-2, "blue", 2, "lime"); // 消去しない部分の表示
        imgData = ctx.getImageData(0, 0, cw, ch);    // 消去しない部分も含めて保存
        drawRect(x,1, x+dx,0, "red", 2, "yellow");   // 消去する部分の表示
        if(x>xmax) {
            drawRect(0,1, 1,2, "black", 2, "red");
            clearInterval(timerId);
        }
        t = t+1;
    }, 500);

複数の経過速度の設定はできない

一つの function 内で、複数の遅延ループを設定できません。
 次のように、記述してもエラーになります。
  var timerId1 = setInterval(function(){
    :
clearInterval(timerId1);
    :
}, 500);
  var timerId2 = setInterval(function(){
    :
clearInterval(timerId2);
    : }, 1000);


xycoordinate.jsでの記述

xycoordinate.jsでは、
    var imgData = ctx.getImageData(0, 0, cw, ch); での imgData をグローバル変数 canvasImageData に設定することができます。
 ある関数で backupCanvas(); によりcanvasを canvasImageData に保管し、
 他の関数で restoreCanvas(); により canvasImageData から canvas を復元できます。
 これを利用して、複数の関数で異なる経過速度の設定ができるのですが、うまく動くのは「追加表示の表示を消去しない場合」に限られ、消去をする場合は、互いの restoreCanvas/ctx.putImageData(imgData, 0, 0) が影響し合って、ぎこちなくなります(経過速度が極度に短いときはよいかもしれません)。

例3:追加表示を消去しない場合


function graph3() {
    graph31();
    graph32(); // このような記述でも並行して実行される
}
function graph31() {
    cw = 400; ch = 400;
    xmin = -4; xmax = 4; ymin = -4; ymax = 4;
    setCanvas("canvas2", "white");
    drawLineYscale(1, "gray", 1, "black", 4);
    drawLineXscale(1, "gray", 1, "black", 4);
    backupCanvas();  // 背景を保存
    var dx = 1;
    var t = 0;
    var timerId = setInterval(function(){
        x = xmin + dx*t;
        drawRect(x,1, x+dx,0, "red", 2, "yellow");
        if(x>xmax) {
            backupCanvas();
            clearInterval(timerId);
        }
        t = t+1;
    }, 500);
}
function graph32() {
    cw = 400; ch = 400;
    xmin = -4; xmax = 4; ymin = -4; ymax = 4;
    setCanvas("canvas2", "white");
    restoreCanvas();  // graph31 の restore で背景を記述しているのでここでは不要
    var dx = 1;
    var t = 0;
    var timerId = setInterval(function(){
        x = xmin + dx*t;
        drawRect(x,-1, x+dx,-2, "blue", 2, "lime");
        if(x>xmax) {
            backupCanvas();
            clearInterval(timerId);
        }
        t = t+1;
    }, 1000);
}

例3:追加表示の消去する場合


function graph4() {
    graph41();
    graph42();
}
function graph41() {
    cw = 400; ch = 400;
    xmin = -4; xmax = 4; ymin = -4; ymax = 4;
    setCanvas("canvas2", "white");
    drawLineYscale(1, "gray", 1, "black", 4);
    drawLineXscale(1, "gray", 1, "black", 4);
    backupCanvas();
    var dx = 1;
    var t = 0;
    var timerId = setInterval(function(){
        restoreCanvas(); // ======= ★★ graph42に影響
        x = xmin + dx*t;
        drawRect(x,1, x+dx,0, "red", 2, "yellow");
        if(x>xmax) {
            clearInterval(timerId);
        }
        t = t+1;
    }, 500);
}
function graph42() {
    cw = 400; ch = 400;
    xmin = -4; xmax = 4; ymin = -4; ymax = 4;
    setCanvas("canvas2", "white");
    restoreCanvas();
    var dx = 1;
    var t = 0;
    var timerId = setInterval(function(){
        restoreCanvas();  // ======= ★★ graph41に影響
        x = xmin + dx*t;
        drawRect(x,-1, x+dx,-2, "blue", 2, "lime");
        if(x>xmax) {
            clearInterval(timerId);
        }
        t = t+1;
    }, 1000);
}