Edited at

HTML5のcanvas内に複数の画像を任意の順序で表示する

More than 5 years have passed since last update.


概説

HTML5のcanvas内に1枚の画像を表示するのは簡単です。

複数の画像を表示するのも結構簡単なのですが、これを任意の順序で表示しようとするとちょっと工夫が必要でした。


まずは1枚の画像を表示してみます。


JavaScript

<body>

<canvas id="canvas" width="600" height="400"></canvas>
<script>
(function() {
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var image = new Image();
image.src = '1.png';
image.addEventListener('load', function() {
context.drawImage(image, 0, 0, 150, 100);
}, false);
})();
</script>
</body>



問題なく表示されます。

1枚のみ


次に同じ要領で、4枚の画像を左上から順にちょっとずつずらして重なるように表示してみたいと思います。


JavaScript

<body>

<canvas id="canvas" width="600" height="400"></canvas>
<script>
(function() {
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var image1 = new Image();
image1.src = '1.png';
image1.addEventListener('load', function() {
context.drawImage(image1, 0, 0, 150, 100);
}, false);

var image2 = new Image();
image2.src = '2.png';
image2.addEventListener('load', function() {
context.drawImage(image2, 50, 70, 150, 100);
}, false);

var image3 = new Image();
image3.src = '3.png';
image3.addEventListener('load', function() {
context.drawImage(image3, 100, 140, 150, 100);
}, false);

var image4 = new Image();
image4.src = '4.png';
image4.addEventListener('load', function() {
context.drawImage(image4, 150, 210, 150, 100);
}, false);
})();
</script>
</body>



単純に同じ処理を連続で書くと、画像のサイズによって読み込み順が保証されないため、うまくいかないパターンが発生します。どうやら、2枚目、4枚目よりも1枚目と3枚目が後に読み込まれたため、このような表示になっているようです。

4枚でうまくいってないパターン


画像サイズによって読み込み順が変わることがあるということが分かったので、今度は4枚の画像の読み込みが終わった時点で、表示を行うようしてみます。


JavaScript

<body>

<canvas id="canvas" width="600" height="400"></canvas>
<script>
(function() {
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var srcs = [
'1.png',
'2.png',
'3.png',
'4.png',
];
var images = [];
for (var i in srcs) {
images[i] = new Image();
images[i].src = srcs[i];
}

var loadedCount = 1;
for (var i in images) {
images[i].addEventListener('load', function() {
if (loadedCount == images.length) {
var x = 0;
var y = 0;
for (var j in images) {
context.drawImage(images[j], x, y, 150, 100);
x += 50;
y += 70;
}
}
loadedCount++;
}, false);
}
})();
</script>
</body>



期待する表示になりました。

4枚でうまくいったパターン