在使用Canvas的drawImagw方法時有個小地方要特別注意。
Image對象必須滿足以下條件之一才能成功
- 是以存在的img dom且圖以載入完成
- javascript中Image物件的src屬性值以載入完成
考慮以下範例
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d')
// ... do something here
let img = new Image()
img.src = 'a/image/src/link.png'
ctx.drawImage(img, 0, 0) // 失敗
原因是給img的屬性src屬於異步載入, 所以上面這段程式在src未載入完全時就執行了drawImage導致不符合預期的情況產生。
參考以下做法解決此問題
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d')
// ... do something here
let img = new Image()
img.addEventListener.('load', event => {
ctx.drawImage(img, 0, 0)
}, false)
img.src = 'a/image/src/link.png'
這個重點其實在MDN的文件中也有清楚的描述到, 但往往在開發過程中老是一股腦地埋沒在實作中卻忽略了把文件看好看滿, 才會有種又踩到雷的感覺。
延伸同樣的需求, 但把圖片改成多圖
let images = ['a.png', 'b.png', 'c.png']
let tasks = []
for (let index in images) {
tasks.push((() => {
return new Promise(resolve => {
let img = new Image()
img.addEventListener("load", event => resolve(img), false)
img.src = images[index]
})
})())
}
Promise.all(tasks).then(images => {
// draw images in here ..
})
JSBin Demo
以上程式至少要把 images 裡頭的圖片網址改成有效網址才能成功運作
在實際使用的情況也建議要在Promise補上錯誤處理來提高可用性
範例中迴圈for/in遍覽的部分亦可使用forEach或其它方式。