JavaScript Image onload not called - javascript

I'm trying to draw an image on the Canvas in Javascript, but ofcourse I want to wait until the image is loaded. However, my onload function seems to be never called.
Here is what I've tried:
function GameObject(x, y)
{
this.x = x;
this.y = y;
this.image = {};
this.loaded = false;
this.load = function(filename)
{
this.image = new Image();
this.image.onload = function()
{
alert("image loaded");
this.loaded = true;
};
this.image.src = filename;
};
};
I'm calling the load function like this:
$( document ).ready(function()
{
main();
});
var player = new Player(0, 0);
function main()
{
player.load("images/player.png");
};
and Player inherits from GameObject.
When using FireBug, it looks like the image is loaded, however the alert "image loaded" is never shown and this.loaded remains false.
What could be wrong?
EDIT: The image is now loaded (there was an error in the path name), but this.loaded is never set to true, while the alert is called.

You should look for loaded field in player.image object.
In order to loaded be assigned to the player object you should rewrite part of your code like this:
this.load = function(filename)
{
var self = this;
this.image = new Image();
this.image.onload = function()
{
alert("image loaded");
self.loaded = true;
};
this.image.src = filename;
};
The problem is that when onload is called the context (to what this points) is the image object. So you have to save your initial context in the self.

you may think that it's a hard way but believe me it's not:
if you want to use jQuery load Event for images let me tell you a truth : "That Is a SHIT" so you should use :
.imagesLoaded()
but before using that you should first download it here
after downloading do these steps:
attach your .imagesLoaded() library js file into your first code as you did for main jQuery.js
write this code for the image you want to check if loaded or not:
$('#container').imagesLoaded()
.always( function( instance ) {
console.log('all images loaded');
})
.done( function( instance ) {
console.log('all images successfully loaded');
})
.fail( function() {
console.log('all images loaded, at least one is broken');
})
.progress( function( instance, image ) {
var result = image.isLoaded ? 'loaded' : 'broken';
console.log( 'image is ' + result + ' for ' + image.img.src );
});
put the address of you picture instead of #container in the code
ENJOY:))

Related

Do images stay loaded when passed through a functions return

I have the following code that I have written in Javascript:
function newImage(name) {
img = new Image();
img.onload = function () {
loaded++;
console.log("Loading: " + Math.round(loaded / 6 * 100) + "% complete");
};
img.src = "./assets/" + name;
return img;
}
var img1 = newImage("img1");
var img2 = newImage("img2");
var img3 = newImage("img3");
I want to know if the image that starts loading in the img variable stays loaded when it is returned to the img1 variable. As in, it will not re-run the onload function.
The answer is the image won't be downloaded again.
Here's a fiddle you can use to see that:
https://jsfiddle.net/uglynakedguy/eu4okzpx/7/
function newImage(name) {
img = new Image();
img.onload = function () {
loaded++;
console.log("Loading: " + Math.round(loaded / 6 * 100) + "% complete");
};
img.src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500";
return img;
}
var imageLoaded = newImage("img1");
document.addEventListener('click', function (event) {
if (!event.target.matches('.add')) return;
document.body.appendChild(imageLoaded);
}, false);
If you check the JS, it has your function. First thing we do when page loads is getting the image. Then, when you click on the button, we inject your image in the page.
You will see that if the image has been loaded, when we inject it, it renders SUPER FAST, it is not downloaded again. You can prove that in network tab too, it will be listed once.

Trying to reload Image variable until successful or a max amount of attempts is reached

I am trying to create a function that will recursively try to reload an image until it either is successful, or a maximum amount of attempts is reached. I have created this function, but it doesn't work (is it due to the fact that the reference to the image has changed?):
function reload (image, URL, maxAttempts)
{
image.onerror = image.onabort = null;
if (maxAttempts > 0)
{
var newImg = new Image ();
newImg.src = URL;
newImg.onerror = image.onabort = reload (image, URL, maxAttempts - 1);
newImg.onload = function () {
newImg.onerror = newImg.onabort = null;
image = newImg;
}
}
else
{
alert ("Error loading image " + URL); /* DEBUG */
}
}
Which is used in the following manner:
var globalTestImage = new Image ();
reload (globalTestImage, "testIMG.jpg", 4);
Rather than it attempting to load "testIMG.jpg" four times, and waiting in between attempts, it instead tries to load it twice, and regardless of whether it was successful the second time around it will display the error message.
What am I doing there? More precisely, why is it acting the way it is, rather than retrying to load the image 4 times?
(function ($) {
var retries = 5; //<--retries
$( document).ready(function(){
$('img').one('error', function() {
var $image = $(this);
$image.attr('alt', 'Still didn\'t load');
if (typeof $image !== 'undefined') {
if (typeof $image.attr('src') !== 'undefined') {
$image.attr('src', retryToLoadImage($image));
}
}
});
});
function retryToLoadImage($img) {
var $newImg = $('<img>');
var $src = ($img.attr('src')) || '';
$newImg.attr('src', $src);
$newImg.one('error', function() {
window.setTimeout(function(){
if (retries > 0) {
retries--;
retryToLoadImage($newImg);
}
}, 1000); //<-retry interval
});
$newImg.one('load', function() {
return $newImg.attr('src');
});
}
})(jQuery);
Some code I wrote for the same case a while ago. Hope it helps you!
In the end I solve this issue in a simple (if inelegant) way:
try
{
canvas.getContext("2d").drawImage (testImage, 0, 0);
backgroundLoaded = true;
}
catch (err)
{
testImage = new Image ();
testImage.src = "placeholder.jpg";
}
The idea is that if an image failed to load, it will fail when rendering it on the canvas, producing an error. When such an error happens, we can create a new image and try again.

Function returns the value before Jquery Image load is executed

if (DataService.Validation(file)) {
//angularjs call to api controller
};
//DataService
Validation: function (file) {
var Url = URL.createObjectURL(file);
var img = new Image();
$(img).load(function () {
var imgwidth = this.width;
var imgheight = this.height;
if (imgheight > 400) {
viewModel.ErrorMessage = 'The Image height cannot be more then 400 px.';
return false;
}
});
img.src = Url;
if (file == null) {
viewModel.ErrorMessage = 'Please select a file to upload.';
return false;
}
if (viewModel.Name == null) {
viewModel.ErrorMessage = 'Name is a required field.';
return false;
}
return true;
}
The above validation function is completing the execution and returning true without the code inside img load function is checked..It means tht even if the image is greater then 400px the validation returns true as the code inside load runs after a long time once the whole Jquery ajax call is sent to api controller..
What I am trying to achieve is that the Validation should not return the value until the code inside the image load is executed.
I had same issue while checking dimension of image as image loading is asynchronous . Also as said by #Abhinandan
"IMG load function will execute only after your image is completely loaded by the browser and since its asynchronous your function will not wait for it to execute"
I used following approach. Hope it will help.
Set one extra attribute in image tag while on change of file like below
$('input[type=file]').on('change',function(){
element = $(this);
var files = this.files;
var _URL = window.URL || window.webkitURL;
var image, file;
image = new Image();
image.src = _URL.createObjectURL(files[0]);
image.onload = function() {
element.attr('uploadWidth',this.width);
element.attr('uploadHeigth',this.width);
}
});
and now you can modify your function to below
$.validator.addMethod('checkDim', function (value, element, param) {
var image = new Image();
var file = element.files[0];
var _URL = window.URL || window.webkitURL;
image.src = _URL.createObjectURL(file);
if(element.uploadWidth== param[0] element.uploadHeigth== param[1]){
return true;
}
else{
return false;
}
}, 'Image dimension must be as specified');
It work for me
The behaviour is correct as your function will return with 'true' value always.
IMG load function will execute only after your image is completely loaded by the browser and since its asynchronous your function will not wait for it to execute.
Also if you want to check the width/height of image being loaded, use naturalWidth/naturalHeight as this will give the right values and not the one assigned to the image by css.
What you can do is inside image-load function,you can call your function with true/false value as parameter.

JScript: How can I throw an error message when image is not loaded?

I have a image loader function, that calls a function when all images are loaded, regardless how many I load. But currently it fails when a image src file name is not valid, because onload is not called.
How can I throw an error message, if an image is not loaded?
loadImage: function(image, id, fn) {
var bgImg = new Image(),
self = this;
// counting images currently loaded
this._loadingImages++;
// set image source and onload callback
bgImg.src = image;
bgImg.onload = function() {
fn(image, id);
self._loadingImages--;
if( self._loadingImages === 0 ) self.imagesLoaded();
}
},
loadImage: function (image, id, fn) {
var bgImg = new Image(),
self = this;
// counting images currently loaded
this._loadingImages++;
// set image source and onload callback
bgImg.src = image;
bgImg.onerror = function () {
// your error code
}
bgImg.onload = function () {
fn(image, id);
self._loadingImages--;
if (self._loadingImages === 0) {
self.imagesLoaded();
}
}
};
This should work.
This Thread can help you: Check if an image is loaded (no errors) in JavaScript
I guess with jQuery you can achieve this such the answer on the link that I've copied below:
$("<img/>")
.load(function() { console.log("image loaded correctly"); })
.error(function() { console.log("error loading image"); })
.attr("src", $(originalImage).attr("src"))
;
Thanks to t.niese, this is my solution:
loadImage: function(image, id, fn) {
var bgImg = new Image(),
self = this;
// counting images currently loaded
this._loadingImages++;
// set error and onload callback and then image source
bgImg.onerror = function() {
throw new Error( "ERROR" );
};
bgImg.onload = function() {
fn(image, id);
self._loadingImages--;
if( self._loadingImages === 0 ) self.imagesLoaded();
}
bgImg.src = image;
},

Getting the dimensions of a newly updated image element

I'm having an issue with getting the dimensions of a newly updated image element.
I'm using FileReader to display a preview of an image file on screen.
Once the filereader and associated code has finished executing, I retrieve the new dimensions of the image element so I can adjust them accordingly.
On some browsers, the info doesn't get updated straight away and I need to include a delay before I can retrieve the new dimensions. This results in the new image being resized according to the previous image's dimensions, and not its own.
How can I be sure the new image has been fully loaded?
I would have thought FileReader().onloadend would have been sufficient but apparently not. I think this is executed once the fileReader has loaded it, not when the DOM has rendered it. (Am I right?)
Then I found this question, which suggests using a timeout of 1 millisecond. This works sometimes, but not always. It seems to be down to the speed the browser is rendering the image (more-so available resources rather than filesize). Do we have no other way of detecting a change in these parameters?
HTML
<img src="#.png" alt=""/>
<input id="fileInput" type="file" accept='image/*' onChange="loadIt()" />
JS
preview = getElementsByTagName('img')[0];
function loadIt() {
var imgReader = new FileReader();
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
imgReader.onloadstart = function(e) {
//
}
imgReader.onload = function (imgReaderEvent) {
if (isImage()) {
preview.src = imgReaderEvent.target.result;
//
}
else {
preview.src = 'error.png';
//
}
}
imgReader.onloadend = function(e) {
setImage();
setTimeout(function(){
setImage();
}, 1);
setTimeout(function(){
setImage();
}, 2000);
//
}
};
function setImage() {
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
//
};
You should call preview.onload or preview.onloadend on your image to detect that it has finished loading. You're also calling your events after you readAsDataURL The code should look like this
var preview=document.getElementsByTagName("img")[0];
function loadIt() {
var imgReader=new FileReader();
imgReader.onload=function(){
if (isImage()) {
preview.src = imgReader.result;
preview.onload=setImage;
} else {
preview.src = 'error.png';
//
}
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
}
function setImage(){
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
}
You're calling imgReader.readAsDataURL before your .onload and .onloadend is set.
I do not know what some of the variables are with-in the body of your setImage();however, start here:
function loadIt() {
var preview = getElementsByTagName('img')[0],
setImage = function () {
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
},
imgReader = new FileReader();
imgReader.onloadstart = function(e) {};
imgReader.onload = function (imgReaderEvent) {
if (isImage()) {
preview.src = imgReaderEvent.target.result;
}
else {
preview.src = 'error.png';
};
};
imgReader.onloadend = function(e) {setImage();};
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
};

Categories