I am working on a bit of javascript to plot data on a <canvas
>. The data points are marked by one of several different (small) image files. I am attempting to have the plot method wait until all the images are loaded. My best attempt thus far is such:
var icon = {
left : {
air : new Image(),
bone : new Image(),
},
right : {
air: new Image(),
bone : new Image(),
},
};
icon.left.air.src = option.imgPath + 'left.air.png';
icon.right.air.src = option.imgPath + 'right.air.png';
icon.left.bone.src = option.imgPath + 'left.bone.png';
icon.right.bone.src = option.imgPath + 'right.bone.png';
function main() {
Canvas.draw();
// Make sure our image icons are loaded before we try to plot
$(icon.left.air).load(function() {
$(icon.right.air).load(function() {
$(icon.left.bone).load(function() {
$(icon.right.bone).load(function() {
Data.plot();
});
});
});
});
}
This works as expected most of the time. On occasion, it will fail and no data will be plotted. Inserting several console.log() statements shows that the script will silently stop working through the series of .load() statements, though code that comes after will be executed.
My questions are as follow开发者_如何学Gos: Am I approaching this the right way? Is there a way to attach an event to my icon object that will fire once all of the images inside are loaded?
This is a jquery plugin, so obviously jquery-based solutions are just as acceptable as vanilla javascript.
Forgive me if I'm wrong, but isn't there a flaw in your load
logic? What happens if right.air
gets loaded before left.air
? The innermost load
events will never trigger, and the plot won't start then, will it?
I would do this differently: Have four flags and the respective load
event set its own flag to true
. Check at the end of each event whether all four flags are set to true. If they are, you're good to go.
And what baloo says: You need to bind the load
event before assigning a src
.
This should do the trick. It guarantees that Data.plot()
will not be called until after all images has loaded and the main function has run.
...
function collected(count, fn){
var loaded = 0;
return function(){
if (++loaded === count){
fn();
}
}
}
// four calls + the trigger in 'main'
var onLoad = collected(5, function(){
Data.plot();
});
icon.left.air.load = onLoad;
icon.right.air.load = onLoad;
icon.left.bone.load = onLoad;
icon.right.bone.load = onLoad;
// set the src AFTER load to make this reliable
icon.left.air.src = option.imgPath + 'left.air.png';
icon.right.air.src = option.imgPath + 'right.air.png';
icon.left.bone.src = option.imgPath + 'left.bone.png';
icon.right.bone.src = option.imgPath + 'right.bone.png';
function main() {
Canvas.draw();
onLoad(); // this will be the last (or first, second, third, fourth) call needed to execut Data.plot();
}
Bind the load() events before you point the Image src's
Or they might be loaded before the event is created
And like Pekka suggests, create all the events separate. Keep a counter or check the .complete property for the images to see if they all are loaded
精彩评论