创建多个画布模式失败

时间:2019-01-11 18:12:52

标签: javascript jquery canvas chart.js

我正在尝试创建一组用于Chart.js甜甜圈图的模式,所以我要这样做:

var surfacePatterns;
var surfaceNames = ['Unknown', 'Paved', 'Unpaved', 'Concrete', 'Cobblestone', 'Metal', 'Wood', 'Ground', 'Sand', 'Grass'];


$(document).ready(() => {    
    surfacePatterns = [];
    console.log(surfacePatterns);
    for (i = 0; i < surfaceNames.length; i++) {
        var temp = new Image();
        temp.onload = () => surfacePatterns.push($("#canvas1")[0].getContext('2d').createPattern(temp, 'repeat'));
        temp.src = '../img/surfaces/'+ surfaceNames[i] + '.jpg';
    }
});

function chart(){
   console.log(surfacePatterns);
}

按下按钮即可调用chart()函数。我故意等待几秒钟,以便它可以加载图像并创建图案,但是当我调用该函数时,它会显示以下信息:

console

在9张图像中,只有8张和9张被转换为图案,其余为空。我不知道发生了什么,因为我没有错误并且找到了所有图像。如果我按预期在surfaceNames中更改了一个String,则会收到一个错误消息,即找不到图像,并且如果我使用模式8和9,它们可以很好地工作。

另一个奇怪的事情:如果我改变

temp.onload = () => surfacePatterns.push($("#canvas1")[0].getContext('2d').createPattern(temp, 'repeat'));

temp.onload = () => surfacePatterns[i] = canvas1[0].getContext('2d').createPattern(temp, 'repeat');

整个数组完全为空(= / =空)。同样,将数组初始化为空数组后的第一个日志为我提供了一个长度为9的空数组,我不知道为什么,因为什么都没有发生。

2 个答案:

答案 0 :(得分:1)

在这种情况下,如果在“ for”中多次调用异步函数,则必须等待所有调用。如果不等待,则会丢失一些异步调用,并且得到一个空数组。

如果您可以删掉,我会尝试解决该问题。

window.surfacePatterns = [];
window.c = 0;
//window.surfaceNames = ['Unknown', 'Paved', 'Unpaved', 'Concrete', 'Cobblestone', 'Metal', 'Wood', 'Ground', 'Sand', 'Grass'];
window.surfaceNames = ["https://www.worldatlas.com/r/w1200-h630-c1200x630/upload/37/99/85/northern-pygmy-owl.jpg",
"https://www.friendsofwehr.org/wp-content/uploads/2013/06/Great-horned_Owl_RWD_at_CRC1transparent.jpg"];

$(document).ready(() => {  
    console.log('Step 1: ',window.surfacePatterns);
    for (i = 0; i < window.surfaceNames.length; i++) {
        var temp = new Image();
        temp.onload = function(){ 
	        var my = $(".canvas1")[0].getContext('2d').createPattern(temp, 'repeat');
    	    console.log('Step inside async: ',my);
        	window.surfacePatterns.push(my);
          window.c++;
          if (window.surfaceNames.length === c) {
            console.log('Complete async calls: ',window.surfacePatterns);
          }
        }
        //temp.src = '../img/surfaces/'+ window.surfaceNames[i] + '.jpg';
        temp.src = "https://www.friendsofwehr.org/wp-content/uploads/2013/06/Great-horned_Owl_RWD_at_CRC1transparent.jpg"

    }
    console.log('Outside For: ', window.surfacePatterns);
});

function chart(){
	console.log(window.surfacePatterns);
}
<!DOCTYPE html>
<html>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas class="canvas1"></canvas>
<canvas class="canvas1"></canvas>

</body>
</html>

最好告诉我

答案 1 :(得分:1)

您需要等待所有模式加载后才能记录阵列。实际上,数组应该是等待所有模式的结果,而不是异步填充的外部作用域中的变量。参见Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

关于如何解决此问题,您可以在将每个回调转换为待处理的承诺后使用Promise.all()

const surfaceNames = ['stackoverflow.com', 'codegolf.stackexchange.com', 'superuser.com', 'codereview.stackexchange.com'];
const context = document.querySelector('#canvas1').getContext('2d');
const promises = surfaceNames.map(surfaceName =>
  new Promise((resolve, reject) => {
    const image = new Image();

    image.addEventListener('load', () => {
      resolve(context.createPattern(image, 'repeat'));
    });
    image.addEventListener('error', () => {
      reject(new Error(`${surfaceName} failed to load ${image.src}`));
    });
    image.src = `https://${surfaceName}/favicon.ico`;
  }).catch(error => {
    // populating array with null entry and logging error
    // instead of ignoring all the other pending promises
    console.log(error.message);
    return null;
  })
);

Promise.all(promises).then(surfacePatterns => {
  console.log(surfacePatterns.map(pattern => pattern.constructor.name));
});
<canvas id="canvas1"></canvas>

如您所见,每一个都成功地以CanvasPattern解析。