##要約
結論からいうと画像の読み込みは一瞬では終わらないのでonload後に描くよう意識しないとダメよってだけの話です。
##問題
画像を表示させてその裏側に円を付けたいと思った私がいます。画像はcanvasのdrawImage()で、円はcanvasのarc()で描きます。しかし、これを正直に書くだけではループして連発する際に上手く行かないんですね。これの解決策を備忘録で残します。
##問題のコード
const canvas=document.createElement("canvas");
canvas.width = 600;
canvas.id = "FieldCanvas";
canvas.height = 400;
const ctx = canvas.getContext("2d");
document.getElementById("main").appendChild(canvas);
//ここまでキャンバスを用意するための前置き
ctx.beginPath();
for(let yoko=0;yoko<10;yoko++){
let img=new Image(15,15);
img.src="./imgbox/magicCamp.svg";
ctx.arc(yoko*15*2+15,15,15,0,2*Math.PI);
ctx.fill();
ctx.drawImage(img,yoko*15*2,0,30,30);
}
ctx.closePath();
赤い魔法陣の画像も現れるはずなんだが、.arc()で描いた緑円しかない。drawImageは完全に忘れ去られているようだ。。
##解決方法
画像読み込みができてないのにfor文が次の描画に走ってしまうからdrawImageが無視されてしまっている模様。ならば.onloadイベントを用意すれば良いのでは?
//描画部分のみ
ctx.beginPath();
var img=new Image(15,15);
for(let yoko=0;yoko<10;yoko++){
img.src="./imgbox/magicCamp.svg";
ctx.arc(yoko*15*2+15,15,15,0,2*Math.PI);
ctx.fill();
img.onload=()=>{
ctx.drawImage(img,yoko*15*2,0,30,30);
}
}
ctx.closePath();
ちなみにfor文の「let yoko」をvarで宣言すると円は正常に出るが、画像は全て最後のyoko座標で出るので、忘れるなよ私。。
##もう少し安定的な策
画像の描画は「onload」完了後にする、でとりあえず解決なのだが、そこそこ複雑なコードで組んでみると再び表示が不安定になることがあった。当時はonloadの発火の後で円も含めて全ての描画をするように変更したら上手くいったが原因はよくわからない。この辺について、詳しくなったら追記したいと思う。
//onload()の中に画像以外の描画処理もまとめる。こっちのほうがましか?
for(let yoko=0;yoko<10;yoko++){
var img=new Image();
img.src="./imgbox/magicCamp.svg";
img.onload=()=>{
ctx.fillStyle="#ff6";
ctx.beginPath();
ctx.arc(yoko*15*2+15,15,15,0,2*Math.PI);
ctx.fill();
ctx.closePath();
ctx.drawImage(img,yoko*15*2,0,30,30);
}
}