我发现了一些竞争条件,在HTML5 canvas
中以编程方式绘制JavaScript
。在尝试在加载图像之前修改图像时会出现这种情况,并且我已经能够使用该技术修复大部分图像:
var myImage = document.createElement('img');
myImage.onload = function(){
console.log("image src set!");
};
myImage.src="img/foobar.png";
我正在为几张图片之一做这个操作,我发生了一件奇怪的事情。基本上,图像在加载之前绘制到画布。我甚至试图通过使用布尔值来指定图像是否已被绘制来解决问题。这是我输出的代码。要理解上下文,此代码是每秒调用以更新画布的函数的一部分。
if (!at_arrow_black)//one of two images used to show an arrow on the canvas
{
at_arrow_black = document.createElement('img');
at_arrow_black.onload = function() {
if (foregroundColor === "black")//which image to draw depends on the foreground color
{
console.log("black load");
context.drawImage(at_arrow_black, canvas.width*.775, canvas.height*.66, canvas.width*.075, font*4/5);
}
};
at_arrow_black.src = "img/at_arrow.png";
}
else
{
if (foregroundColor === "black")
{
if (hasDrawnArrow)//this starts as false
{
console.log("1. black draw");
context.drawImage(at_arrow_black, canvas.width*.775, canvas.height*.66, canvas.width*.075, font*4/5);
}
else
{
logDebug("2. black draw");
hasDrawnArrow = true;
}
}
}
这导致画布首先在此循环的第一次迭代中绘制一个箭头,然后绘制另一个箭头(并且在稍微不同的位置)。我得到的输出:
2. black draw
black load
1. black draw
这是预期的输出 - 但为什么画布仍然会绘制图像?这是某种竞争条件吗?我该怎么做才能解决它?
答案 0 :(得分:1)
如果您正在加载多个图像,您可能需要自己构建一个图像加载器,以便在开始使用它们之前加载所有图像。
以下是一个例子:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas1=document.getElementById("canvas1");
var ctx1=canvas1.getContext("2d");
var canvas2=document.getElementById("canvas2");
var ctx2=canvas2.getContext("2d");
var imageURLs=[];
var imagesOK=0;
var imagesFailed=0;
var imgs=[];
imageURLs.push("http://upload.wikimedia.org/wikipedia/commons/d/d4/New_York_City_at_night_HDR_edit1.jpg");
imageURLs.push("http://www.freebestwallpapers.info/bulkupload//20082010//Places/future-city.jpg");
loadAllImages();
function loadAllImages(){
for (var i = 0; i < imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = onLoad;
img.onerror = onFail;
img.src = imageURLs[i];
}
}
var imagesAllLoaded = function() {
if (imagesOK+imagesFailed==imageURLs.length ) {
// all images are processed
// ready to use loaded images
// ready to handle failed image loads
ctx1.drawImage(imgs[0],0,0,canvas1.width,canvas1.height);
ctx2.drawImage(imgs[1],0,0,canvas2.width,canvas2.height);
}
};
function onLoad() {
imagesOK++;
imagesAllLoaded();
}
function onFail() {
// possibly log which images failed to load
imagesFailed++;
imagesAllLoaded();
};
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas1" width=300 height=300></canvas><br/>
<canvas id="canvas2" width=300 height=300></canvas>
</body>
</html>
这是JSFiddle。
答案 1 :(得分:0)
我知道已经有一个已接受的答案,但无论如何这里都是另一种选择。
您需要等到所有图片都加载完毕。我使用一个图像加载器,在加载所有图像时设置一个标志,这样我的脚本就可以继续了。
function ImageLoader(sources, callback)
{
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for (var src in sources) {
numImages++;
}
for (var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if (++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
// *** The images you want to laod
var sources = {
background: 'images/bg.png',
assets: 'images/assets.png',
};
// *** What you want to happen once all images have loaded...
ImageLoader(sources, function(images) {
// *** Example of what I usually do
_images = images;
_setImagesReady = true;
});
// *** Access the image by specifying it's property name you defined. eg:
ctx.drawImage(_image.background, 0, 0);