HTML帆布绘制方法()方法不加载第一次加载的图块图(多个图像的网格)



这是关于创建图块地图(64x64 Pixel pngs)。

出于演示目的,我简化了我的代码,并将网格简化为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>

可以找到类似的问题:

画布图像直到第二次尝试

才显示

为什么我的帆布仅在刷新上加载?

在这种情况下,尽管我不仅要生成一个图像,而且要生成图像的网格,而我试图解决这一点似乎陷入了问题,因为什么都没有加载:

<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,我在这里发现了更多:什么是JavaScript中的(function(){})()构造?但是,完全不熟悉这个术语/概念,也不知道我是否处于正确的道路上。

我还试图通过外部JS加载它,然后在身体标签中onload =" drawtilemap()",但是这会抛出更时髦的行为,因为它似乎确实在加载了随机的瓷砖而不是整个网格。

任何帮助!

我不建议您在第二个代码块中尝试的路线。保持资源加载例程和画布渲染功能分开(如您在第一个代码示例中尝试执行的那样),以更好地维护。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>

最新更新