基本的には、追加表示した部分(動かした画像)だけを消去することはできません。
追加表示する以前に、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++; // ループ打切判定のための処理など
}, 経過時間ミリ秒);
// ループ以前に実行され、ループ打切後にここには来ません。上のループ打切条件で処理します。
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では、
var imgData = ctx.getImageData(0, 0, cw, ch);
での imgData をグローバル変数 canvasImageData に設定することができます。
ある関数で backupCanvas(); によりcanvasを canvasImageData に保管し、
他の関数で restoreCanvas(); により canvasImageData から canvas を復元できます。
これを利用して、複数の関数で異なる経過速度の設定ができるのですが、うまく動くのは「追加表示の表示を消去しない場合」に限られ、消去をする場合は、互いの restoreCanvas/ctx.putImageData(imgData, 0, 0) が影響し合って、ぎこちなくなります(経過速度が極度に短いときはよいかもしれません)。
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);
}
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);
}