Image.onload not executing all code - javascript

I have this piece of javascript that is taking several images and waiting for them all to load to then performs some logic on them. This is a stripped out piece of code that is still not doing what is expected:
$(window).on('load', function() {
var art = new Image();
var top_image = new Image();
var bottom_image = new Image();
var left_image = new Image();
var right_image = new Image();
art.onload = function() {
console.log("1");
top_image.onload = function() {
console.log("2");
bottom_image.onload = function() {
console.log("3");
right_image.onload = function() {
console.log("4");
left_image.onload = function() {
console.log("5");
}
}
}
}
}
art.src = 'images/prototype.jpg';
top_image.src = 'images/2_4_top_center.png';
bottom_image.src = 'images/2_4_bottom_center.png';
right_image.src = 'images/2_4_middle_right.png';
left_image.src = 'images/2_4_middle_left.png';
});
The problem is that when I hard reload the browser a seemingly random number logs appear in the console. It mostly only logs "1" but sometimes gets all the way to logging "5". I'm not sure what's happening here and why it only behaves as expected sometimes.

You just append an onclick handler to top_image when art has already loaded, therefore if top_image loads before art, the second handler would not be triggered. To solve this, attach handlers to all images before you set their source, and use promises to handle them:
const onload = img => new Promise(res => img.onload = res);
var art = new Image();
var top_image = new Image();
var bottom_image = new Image();
var left_image = new Image();
var right_image = new Image();
Promise.all([art, top_image, bottom_image, left_image, right_image].map(onload))
.then(() => {
// All loaded !!
});
// Add sources

Related

Preloading Image to Precache

I want to preload my images but don't necessarily want to append them to the DOM. If I preload an image will it effectively be precached?
My understanding is that caching works by reference to the src of an image. From playing around it seems as if preloading in order to precache does indeed work. However, I'm not sure; this may be unreliable or have some negative effect on performance.
I'm using the image constructor to preload.
const img = new Image();
img.src = imageArray[i].url;
Yes, it does indeed work.
function preloadImage(url){
const img = new Image();
img.src = imageArray[i].url;
}
However, there is a couple of approach. For example, delaying preloading until after the page loads:
function preloader() {
if (document.images) {
var img1 = new Image();
var img2 = new Image();
var img3 = new Image();
img1.src = "http://url/image-001.jpg";
img2.src = "http://url/image-002.jpg";
img3.src = "http://url/image-003.jpg";
}
}
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(preloader);

Loading multiple images with javascript

I am strugling to create a script to load multiple images for a game drawn on Canvas. The window seems to load without completing the load of all images. I've tried many ways but none of them seems to work. The function drawGameMenu() is called before the images are actually loaded and so the images are not drawn. If someone could help, I would be grateful. Here is my script, kind regards:
var imageNames = ["menuImage", "resetScoreButton", "instructionsButton", "playButton", "dialogPanel", "gamePlayImage", "exitButton", "timerPanel", "messengerPanel", "scoreBar", "yesButton", "noButton", "goButton"];
var imageFileNames = ["game_Menu", "reset_score_button", "instructions_button", "play_button", "dialog_panel", "game_play", "exit_button", "timer", "messenger_panel", "score_bar", "yes_button", "no_button", "go_button"];
var imageCollection = {};
window.addEventListener("load", function() {
var u = imageNames.length - 1;
for(i = 0; i <= u; i++) {
var name = imageNames[i];
imageCollection[name] = new Image();
imageCollection[name].src = imageFileNames[i] + ".png";
console.log(imageCollection[name]);
imageCollection[name].addEventListener('load', function() {
do {
var x = imageCollection[name].complete;
}
while(x != true);
});
}
drawGameMenu();
});
I made some changes on the script and now it works on the PC browser, but not working on smartphone. The script is the following:
window.addEventListener("load", async function loadImageCollection() {
var u = imageNames.length - 1;
for(i = 0; i <= u; i++) {
var name = imageNames[i];
imageCollection[name] = new Image();
imageCollection[name].src = imageFileNames[i] + ".png";
do {
await new Promise((resolve, reject) => setTimeout(resolve, 50));
x = imageCollection[name].complete;
console.log(x);
}
while(x == false);
}
drawGameMenu();
});
Keep it simple
Just use a simple callback and a counter to count of images as they load. Adding promises adds an additional level of complexity that is just a source of potential bugs. (the promise for each image and its callback and the need to call it on image load, and the need to handle promise.all with another callback)
const imageCollection = loadImages(
["menuImage", "resetScoreButton", "instructionsButton", "playButton", "dialogPanel", "gamePlayImage", "exitButton", "timerPanel", "messengerPanel", "scoreBar", "yesButton", "noButton", "goButton"],
["game_Menu", "reset_score_button", "instructions_button", "play_button", "dialog_panel", "game_play", "exit_button", "timer", "messenger_panel", "score_bar", "yes_button", "no_button", "go_button"],
drawGameMenu // this is called when all images have loaded.
);
function loadImages(names, files, onAllLoaded) {
var i = 0, numLoading = names.length;
const onload = () => --numLoading === 0 && onAllLoaded();
const images = {};
while (i < names.length) {
const img = images[names[i]] = new Image;
img.src = files[i++] + ".png";
img.onload = onload;
}
return images;
}
With the use of promises this becomes a very easy task. I don't know if ES6 allows it, but give it a try anyways.
var jarOfPromise = [];
for(i = 0; i <= u; i++) {
jarOfPromise.push(
new Promise( (resolve, reject) => {
var name = imageNames[i];
imageCollection[name] = new Image();
imageCollection[name].src = imageFileNames[i] + ".png";
console.log(imageCollection[name]);
imageCollection[name].addEventListener('load', function() {
resolve(true);
});
})
)
}
Promise.all(jarOfPromise).then( result => {
drawGameMenu();
});

Create one image in javascript

I have the following code to create an image with JavaScipt, the image appear on a button click. The problem is when the image is created and i click again the button another one appear, and i don't want that.
How i can solve that?
var img = new Image();
var div = document.getElementById('Table');
img.onload = function() {
div.appendChild(img);
};
img.src = 'Images/Email.png';
You could use a flag, which indicate when the image has been created, loaded and added to your DOM:
var div = document.getElementById('Table');
var hasImage = false; // flag
var button = document.getElementById('button');
button.addEventListener('click', function(event){
createImage();
});
var createImage = function(){
if(!hasImage) {
var img = new Image();
img.src = 'http://pipsum.com/435x310.jpg';
img.onload = function() {
div.appendChild(img);
hasImage = true;
};
}else{
console.log('image is already present');
}
};
<button id="button" type="button">Click Me!</button>
<div id="Table"></div >
Check if the image is already added to the DOM. If not, do so. If already added, only update the source.
It could be something like this:
var img = new Image();
var div = document.getElementById('Table');
var appended = false;
function appendImage() {
appended = true;
div.appendChild(img);
img.removeEventListener('load', appendImage);
}
function onClick() {
if (!appended) {
img.addEventListener('load', appendImage);
}
img.src = 'Images/Email.png';
}

I am trying to implement undo option in my canvas

I am trying to implement undo and redo options in my canvas.I am using the following code in my program:
var cPushArray = new Array();
var cStep = -1;
function cPush()
{
cStep++;
if (cStep < cPushArray.length)
{
cPushArray.length = cStep;
}
cPushArray.push(document.getElementById("drawingCanvas").toDataURL());
}
function cUndo()
{
if(cStep > 0)
{
cStep--;
var canvasPic = new Image();
canvasPic.src = cPushArray[cStep];
canvasPic.onload = function() { ctx.drawImage(canvasPic,0,0);}
}
}
function cRedo()
{
if(cStep < cPushArray.length-1)
{
cStep++;
var canvasPic = new Image();
canvasPic.src = cPushArray[cStep];
canvasPic.onload = function() {ctx.drawImage(canvasPic,0,0);}
}
}
But I am unable to draw anything on my canvas if I am calling the cPush() method.
Can u please tell me where am I wrong in the above code.
Do not use onload event, because it was only touched off by the DOM ready event.
var canvasPic = new Image();
canvasPic.src = cPushArray[cStep];
//if ctx has get the context of canvas, draw the pic immediately
ctx.drawImage(canvasPic,0,0);

image,onload event not working in chrome

I'm using html5 to create drag and drop image upload functionality. This works great for me in firefox but in chrome the image onload event only fires the first time. If I drag multiple images in only the first works and if I drag a second in it fails. I believe the problem is with the image onload.
here is the way my code works I have removed the irrelevant sections:
var img = document.createElement("img");
var reader = new FileReader();
var canvas = document.createElement("canvas");
var canvasData;
var ctx = canvas.getContext("2d");
var myFiles;
var i = 0;
reader.onload = (function (aImg)
{
return function (e)
{
aImg.src = e.target.result;
};
})(img);
img.onload = function (){
//resizes image
//draws it to the canvas
//posts to server
i++;
if(i < myFiles.length){
processNext(i);
}
}
function processNext(filei) {
var file = myFiles[filei];
img.file = file;
reader.readAsDataURL(file);
}
i = 0;
myFiles = files;
processNext(0);
Does anyone know why this works in firefox but not chrome?
Explanation from chromium tracker:
This is not a bug. WebKit is just more strict. You must instantiate a new Image() object before the replacement, like this:
var photo = document.getElementById('image_id');
var img = new Image();
img.addEventListener('load', myFunction, false);
img.src = 'http://newimgsource.jpg';
photo.src = img.src;
source: http://code.google.com/p/chromium/issues/detail?id=7731#c12
This is strange, none of the above worked for me. I was defining the image variable as local and change it to global and it started working. Does this make sense? Can somebody explain it?
This didnt worked for me:
function loadImage() {
var ImageToLoad = new Image();
ImageToLoad.onload = function() {
console.log("finish loading");
};
ImageToLoad.src = "myimage.png";
}
This did work:
var ImageToLoad = new Image();
function loadImage() {
ImageToLoad.onload = function() {
console.log("finish loading");
};
ImageToLoad.src = "myimage.png";
}

Categories

Resources