这与创建图块地图(64x64像素PNG)有关。
出于演示目的,我简化了代码,并将网格缩小为3x3字段。
问题本质上是,当我绘制网格时,图像仍在加载,因此画布在第一次加载时不会显示。但是,刷新后,网格将正常加载,因为现在已缓存所有图像文件。
<body>
<canvas id="canvas" width="200px" height="200px"></canvas>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// 3X3 GRID
var mapArray=[
["tile1","tile3","tile1"],
["tile1","tile1","tile2"],
["tile3","tile1","tile2"]
];
var tile1 = new Image();
var tile2 = new Image();
var tile3 = new Image();
tile1.src='../images/test/tile1.png';
tile2.src='../images/test/tile2.png';
tile3.src='../images/test/tile3.png';
var posX=0;
var posY=0;
for(var i=0; i < mapArray.length; i++) {
for(var j=0; j < mapArray[i].length; j++) {
switch(mapArray[i][j]) {
case "tile1":
context.drawImage(tile1, posX, posY, 64, 64);
break;
case "tile2":
context.drawImage(tile2, posX, posY, 64, 64);
break;
case "tile3":
context.drawImage(tile3, posX, posY, 64, 64);
break;
}
posX+=64;
}
posX=0;
posY+=64;
}
</script>
</body>
可以找到类似的问题:
Canvas image not displaying until second attempt
Why do my canvases only load on refresh?
在这种情况下,尽管我尝试生成的不仅是一张图像,而且还生成了一张图像网格,但由于一点都没有加载,我试图解决这个问题似乎遇到了问题:
<body>
<canvas id="canvas" width="200px" height="200px"></canvas>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// 3X3 GRID
var mapArray=[
["tile1","tile3","tile1"],
["tile1","tile1","tile2"],
["tile3","tile1","tile2"]
];
var tile1 = new Image();
var tile2 = new Image();
var tile3 = new Image();
var posX=0;
var posY=0;
for(var i=0; i < mapArray.length; i++) {
for(var j=0; j < mapArray[i].length; j++) {
switch(mapArray[i][j]) {
case "tile1":
//use onload so drawing waits until image file is loaded
tile1.onload = function() {
//draw image
context.drawImage(tile1, posX, posY, 64, 64);
};
//load image file
tile1.src='../images/test/tile1.png';
break;
case "tile2":
tile2.onload = function() {
context.drawImage(tile2, posX, posY, 64, 64);
};
tile2.src='../images/test/tile2.png';
break;
case "tile3":
tile3.onload = function() {
context.drawImage(tile3, posX, posY, 64, 64);
tile3.src='../images/test/tile3.png';
break;
}
posX+=64;
}
posX=0;
posY+=64;
}
</script>
</body>
如您所见,我的3个开关选项现在都在等待图像加载,然后再绘制。
我在某处读到它可能与FOR循环有关,我不得不使用IIFE,我在这里可以找到更多信息: What is the (function() { } )() construct in JavaScript? 但是,我完全不熟悉这个术语/概念,也不知道自己是否走对了。
我还试图通过外部js加载,然后在body标签中加载onload =“ drawTileMap()”,但是这甚至引发了更时髦的行为,因为那样的话,它实际上似乎是加载随机图块而不是整个网格
任何帮助,不胜感激!
答案 0 :(得分:0)
我不建议您沿第二个代码块尝试的路线。将资源加载例程和画布渲染功能分开(如您在第一个代码示例中尝试的那样),以实现更好的维护。 JavaScript是一种基于异步事件的语言,请充分利用它。
我已将您的代码分为两个函数。一种检查是否加载了所有图像,然后在这种情况下调用第二个函数(作为参数传递给它)。
如果您感到舒适并理解了我的示例的工作原理,则应该阅读JavaScript Promises(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise),因为它们是处理回调的异步操作的更通用,更好的方法。
下面的示例代码:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// 3X3 GRID
var mapArray = [
["tile1", "tile3", "tile1"],
["tile1", "tile1", "tile2"],
["tile3", "tile1", "tile2"]
];
var tile1 = new Image();
var tile2 = new Image();
var tile3 = new Image();
var nrOfImagesLoaded = 0;
// Using base64 datauri's, so the script doesn't depend on external resources
tile1.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAZElEQVR42u3QAQ0AAAjDMO5fNGCD0GUKmq7a/xYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgfgMNmH/BjHDEMQAAAABJRU5ErkJggg==';
tile2.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAY0lEQVR42u3QAQ0AAAjDMO5fNGCD0M1BU70/LgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMD9Bs3Jf8EvyPO9AAAAAElFTkSuQmCC';
tile3.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAYklEQVR42u3QAQ0AAAgDoL9/aM3hhAg0mcljFSBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAu5bjgl/wXGcqdoAAAAASUVORK5CYII=';
tile1.onload = function() {nrOfImagesLoaded++;}
tile2.onload = function() {nrOfImagesLoaded++;}
tile3.onload = function() {nrOfImagesLoaded++;}
// Function that takes another function as an argument and calls it when
// all 3 images have been loaded
function callWhenImagesLoaded(callback) {
// Call the function when all 3 tiles have been loaded
if(nrOfImagesLoaded == 3) {
callback();
// Otherwise poll again in 500 milliseconds to see if they are loaded
} else {
setTimeout(function() { callWhenImagesLoaded(callback) }, 500);
}
}
// Call this, when all images are loaded
function allImagesAreNowLoaded() {
var posX = 0;
var posY = 0;
for (var i = 0; i < mapArray.length; i++) {
for (var j = 0; j < mapArray[i].length; j++) {
switch (mapArray[i][j]) {
case "tile1":
context.drawImage(tile1, posX, posY, 64, 64);
break;
case "tile2":
context.drawImage(tile2, posX, posY, 64, 64);
break;
case "tile3":
context.drawImage(tile3, posX, posY, 64, 64);
break;
}
posX += 64;
}
posX = 0;
posY += 64;
}
}
// Tie it all togther - call allImagesAreNowLoaded when all 3 tiles have been loaded
callWhenImagesLoaded(allImagesAreNowLoaded);
<canvas id="canvas" width="200px" height="200px"></canvas>