function find_image_dm(imgsrc){
window.imgwidth = "";
var img = new Image();
img.onload = function test() {
var width = this.width;
var height = this.height;
if (height > 300) {
var x = height/300;
window.imgwidth = Math.ceil(width/x);
}
}
img.src = imgsrc;
return(window.imgwidth);
}
I want to return window.imgwidth so i can use it else where but if I try to alert it or anything like that it shows up blank. How do I return its value. window.imgwidth is my attempt to create a global variable. I do not need the width of the window
The problem with your attempt is that the onload callback executes asynchronously. Because of this, you cannot reliably return anything since the onload callback is executed at some future time. Instead of thinking in terms of return values, think about passing a callback function parameter to your find_image_dm function:
function find_image_dm(imgsrc, callback)
{
var img = new Image();
img.onload = function()
{
callback(this.width, this.height);
};
img.src = imgsrc;
}
Which you'd use like this:
function onReturnSize(w, h)
{
console.log('image width is', w);
console.log('image height is', h);
}
find_image_dm('http://placekitten.com/2200/1200', onReturnSize);
Demo: http://jsfiddle.net/mattball/pTKW4/
The problem i think is when you execute find_img_dm, you are trying to return the width value immediately. This won't work because the img.onload most likely won't be fired before the function finishes executing.
What you would need to do is in the onload event handler, put a call to another function, passing in the width value, and have that function do what you need to do when the image is loaded. Then you will know that at that point, the image is loaded and the width value is available.
OK try this. You have to return the value of window.imgwidth within the function test:
function find_image_dm(imgsrc){
window.imgwidth = "";
var img = new Image();
img.onload = function test() {
var width =this.width
var height= this.height;
if(height > 300){
var x = height/300;
console.log(Math.ceil(width/x));
window.imgwidth = Math.ceil(width/x);
console.log(window.imgwidth);
alert (window.imgwidth);
return window.imgwidth;
}
}
img.src = imgsrc;
}
Ok. Another stab at this, #Tom.
There may be two issues here, from what I can see.
There will be no calculation of window.imgwidth if your if statement returns false, as this appears to be the only place you are calculating it.
The window.imgwidth is being calculated in function test() but not returned.
Looking at your code it seems the issue is you aren't technically loading the image before trying to get the height because you are setting the src after the the onload call.
If you are using jQuery you should try and leverage it.
function find_image(imgsrc) {
var imgWidth,
img = $('<img/>').attr('src', imgsrc).load(function() {
var $img = $(this),
height = $img.height(),
width = $img.width();
if (height > 300) {
var x = height/300;
imgWidth = Math.ceil(width/x);
}
});
return imgWidth;
}
Ok... I went through your code and found a problem with your script. You are using image.onload function, so when u load image source, image loads and then only dimension are available and stored on the window.imgwidth.
All goes fine, but problem is, when u call the function, it takes time to load the u image, so if you try to get the window.imgwidth, as the resource is still loading you wont get the window.imgwidth. Return value also will not work as codes do not wait till the image loads so although the image is loading the code block execution will be completed so you wont have any data in window.imgwidth.
If you try to alert window.imgwidth after certain duration when image loading is completed then you can see that window.imgwidth has the value. And also you have the if block which stores the data in window.imgwidth only when the height more than 300 but you dont have else block so you need to implement that too as a fallback :) .
Let me know if i said it hard way :-D
Related
I am trying to return a value inside a function but the variable is only changed inside a function. outside the function the variable remains the same.
I have tried the following:
//variable file_exist still has the value true in it.
img.onerror = function () {
file_exist = false;
};
//returns function(){ reutnr false;};
file_exist = img.onerror = function () {
return false;
};
I cant seem to get the value outisde of this function. Is there a way to get the value false?
full code:
var i = 1;
var file_exist = true;
while(file_exist){
var img = document.createElement("img");
img.src = "ws-img/"+id+"-"+i+".jpg";
//deleted some code since no need here for the exampled
img.onerror = function () {
file_exist = false;
console.log(file_exist);//shows false
};
console.log(file_exist);//shows true
i++;
}
This is not my preferred method, but it will work in your specific scenario...
var imageCount = 0;
function loadImage(onComplete) {
imageCount++;
var img = document.createElement("img");
img.onerror = function () {
// there was an error, so we're assuming there are no more images
onComplete();
};
img.onload = function() {
// the image has loaded - add it to the DOM?
// call this function again to load the next image
loadImage(onComplete);
};
img.src = "ws-img/" + id + "-" + imageCount +".jpg";
// cached images won't trigger onload
if (img.complete) img.onload();
}}
loadImage(function() {
alert("images have all loaded");
});
It creates the image element, as you were doing, for image #1, then on success it will increment the counter and run itself again. That will try and load image #2, and so on and so on. When it errors it stops and executes the callback function so you know all the images are loaded.
There are issues with this though. If an image doesn't load for any reason, it will stop and load no more images. A much better solution would be to either construct the page with all the images, using server-side code (PHP in your case), or if you do want to perform the image load at client-side create an API call that gives you a list of all the images. Javascript can make 1 call to get that data and then load all the images, safe in the knowledge that they do exist.
I have read countless of answers of this issue and I came up with the following, but it doesn't work either.
function fitToParent(objsParent, tagName) {
var parent, imgs, imgsCant, a, loadImg;
//Select images
parent = document.getElementById(objsParent);
imgs = parent.getElementsByTagName(tagName);
imgsCant = imgs.length;
function scaleImgs(a) {
"use strict";
var w, h, ratioI, wP, hP, ratioP, imgsParent;
//Get image dimensions
w = imgs[a].naturalWidth;
h = imgs[a].naturalHeight;
ratioI = w / h;
//Get parent dimensions
imgsParent = imgs[a].parentNode;
wP = imgsParent.clientWidth;
hP = imgsParent.clientHeight;
ratioP = wP / hP;
//I left this as a test, all this returns 0 and false, and they shouldn't be
console.log(w);
console.log(h);
console.log(ratioI);
console.log(imgs[a].complete);
if (ratioP > ratioI) {
imgs[a].style.width = "100%";
} else {
imgs[a].style.height = "100%";
}
}
//Loop through images and resize them
var imgCache = [];
for (a = 0; a < imgsCant; a += 1) {
imgCache[a] = new Image();
imgCache[a].onload = function () {
scaleImgs(a);
//Another test, this returns empty, for some reason the function fires before aplying a src to imgCache
console.log(imgCache[a].src);
}(a);
imgCache[a].src = imgs[a].getAttribute('src');
}
}
fitToParent("noticias", "img");
To summarise, the problem is the event onload triggers before the images are loaded (or that is how I understand it).
Another things to add:
I don't know at first the dimensions of the parent nor the child,
because they varied depending of their position on the page.
I don't want to use jQuery.
I tried with another function, changing the onload event to
window, and it worked, but it takes a lot of time to resize because
it waits for everything to load, making the page appear slower,
that's how I came to the conclusion the problem has something to do
with the onload event.
EDIT:
I made a fiddle, easier to look at the problem this way
https://jsfiddle.net/whn5cycf/
for some reason the function fires before aplying a src to imgCache
Well, the reason is that you are calling the function immedeatly:
imgCache[a].onload = function () {
}(a);
// ^^^ calls the function
You call the function and assign undefined (the return value of that function) to .onload.
If you want to use an IIFE to capture the current value of a, you have to make it return a function and accept a parameter to which the current value of a is assigned to:
imgCache[a].onload = function (a) {
return function() {
scaleImgs(a);
};
}(a);
Have a look again at JavaScript closure inside loops – simple practical example .
I draw several images with a function that performs something similar to:
context.drawImage(img, width / 2 * (-1), height / 2 * (-1), width, height);
I've read that I need to wait for the image to be loaded before I can draw it, with something like this:
img.onload = function() {
context.drawImage(img, width / 2 * (-1), height / 2 * (-1), width, height);
};
However this causes the image to be drawn but afterwards, nothing is drawn since I call up my draw function every few milliseconds as it's part of the 'animation' loop for a simple game.
Is there a way that I can wait for the onload event before I continue running code in my init() function?
I suppose something like:
var image_loaded = false;
img.onload = function() {
image_loaded = true;
};
if(image_loaded) {
animate();
}
Should work? Unless I need to add a timeOut function to keep calling the init() until image_loaded is true?
Live Demo
var imagesLoaded = [],
images = [
'http://www.zombiegames.net/inc/screenshots/The-Last-Stand-Union-City.png',
'http://www.zombiegames.net/inc/screenshots/Lab-of-the-Dead.png',
'http://www.zombiegames.net/inc/screenshots/Zombotron.png',
'http://www.zombiegames.net/inc/screenshots/Road-of-the-Dead.png'],
canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = 640;
canvas.height = 480;
function init(){
// just loops through the images.
if(imagesLoaded.length > 0){
ctx.drawImage(imagesLoaded[0], 0, 0, 640, 480);
imagesLoaded.push(imagesLoaded.shift());
}
setTimeout(init,500);
}
function preload(){
for(var i = 0; i < images.length; i++){
(function(value){
return function(){
var loadedImage = new Image();
loadedImage.src = images[value];
loadedImage.onload = function(){
imagesLoaded.push(loadedImage);
}
}();
})(i);
}
checkLoaded();
}
function checkLoaded(){
if(imagesLoaded.length === images.length){
console.log(imagesLoaded.length);
init();
} else{
setTimeout(checkLoaded,30);
}
}
preload();
Above is an example of how to preload images and wait to do anything else. Basically what you do is have all your images in an array, and add the onload event to each of them. As they load I through them into another array that holds all the loaded images. Once the length of the two arrays match all of the images are ready to use.
Another way would be to increment a counter as they load and check its value against the length of the array. When the counter variable is equal to the length of the images array it means they've all loaded and are ready to use.
I created a simple and small library to make the load of images easy.
Check the demo
See the library code below:
// Simple Image Loader Library
window.Loader = (function () {
var imageCount = 0;
var loading = false;
var total = 0;
// this object will hold all image references
var images = {};
// user defined callback, called each time an image is loaded (if it is not defined the empty function wil be called)
function onProgressUpdate() {};
// user defined callback, called when all images are loaded (if it is not defined the empty function wil be called)
function onComplete() {};
function onLoadImage(name) {
++imageCount;
console.log(name + " loaded");
// call the user defined callback when an image is loaded
onProgressUpdate();
// check if all images are loaded
if (imageCount == total) {
loading = false;
console.log("Load complete.");
onComplete();
}
};
function onImageError(e) {
console.log("Error on loading the image: " + e.srcElement);
}
function loadImage(name, src) {
try {
images[name] = new Image();
images[name].onload = function () {
onLoadImage(name);
};
images[name].onerror = onImageError;
images[name].src = src;
} catch (e) {
console.log(e.message);
}
}
function getImage(/**String*/ name){
if(images[name]){
return (images[name]);
}
else{
return undefined;
}
}
// pre-load all the images and call the onComplete callback when all images are loaded
// optionaly set the onProgressUpdate callback to be called each time an image is loaded (useful for loading screens)
function preload( /**Array*/ _images, /**Callback*/ _onComplete, /**Callback <optional>*/ _onProgressUpdate) {
if (!loading) {
console.log("Loading...");
loading = true;
try {
total = _images.length;
onProgressUpdate = _onProgressUpdate || (function(){});
onComplete = _onComplete || (function(){});
for (var i = 0; i < _images.length; ++i) {
loadImage(_images[i].name, _images[i].src);
}
} catch (e) {
console.log(e.message);
}
} else {
throw new Error("Acess denied: Cannot call the load function while there are remaining images to load.");
}
}
// percentage of progress
function getProgress() {
return (imageCount / total)*100;
};
// return only the public stuff to create our Loader object
return {
preload: preload,
getProgress: getProgress,
getImage: getImage,
images: images // have access to the array of images might be useful but is not necessary
};
})();
How it works
To make sure that images are loaded and they could be used by your application the library have the Loader.preload method.
The preload method will receive an array of objects, each object containing the name and the src properties of an image you want to load. Optionally you can setup the onComplete callback (to be called when all images are loaded) and the onProgressUpdate callback (to be called each time an image is loaded). The onProgressUpdate callback is useful if you want to create a loading screen for your application.
Use the Loader.getProgress() to obtain the percentage of images loaded at any time.
To obtain the reference of an image loaded, call Loader.getImage(name) where name is the name property (a String) of the image.
If you for some reason needs iterate over all images use Loader.images. It's the object containing all references for the images in its properties.
Use like this:
var images = [{name: "img1", src: "http://...a.."},
{name: "img2", src: "http://...b.."},
...
{name: "imgN", src: "http://...N.."}];
function onProgressUpdate(progress){
...
drawProgressBar(progress); // just an example of what you can do
...
}
function onComplete(){
...
// get an Image from Loader object
var texture = Loader.getImage("img2");
// or use this:
var texture = Loader.images.img2; // or still Loader.images["img2"]
...
// iterate over the images
for (var img in Loader.images){
console.log(Loader.images[img].src);
}
....
}
Loader.preload(images, onComplete, onProgressUpdate);
Check the demo if you didn't.
function LoadResources(){
alert("In load socket");
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var tiles= new Array();
var loadedCount=0;
for (x = 101; x <= 155; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "Resources/ClassicCardImages/deck1/dood_deck/"+x+".GIF";
imageObj.onload=function(){
loadedCount++;
if(loadedCount==55){
cardsImagesLoaded();
}else {
alert(loadedCount);
}
};
tiles.push(imageObj);
}
};
So when i call the function LoadResources() it does give the alert "in load socket" but does not gives the alert while in imageObj.onload function.
You can use window.onload function i.e "window.onload = function() {..}" and my function in it while use in the body of html document.
Plus i m running it on Google chrome .Is there the problem with chrome's onload or something .
You are trying to increase the loading counter even if the onload function are called only once (at the moment when the images has been loaded completely), so there is no way to trigger the alert many times. For me it's not quite obvious what are you trying to do. Anyway if you want to load multiple images with onload function the best practice is to use a closure, otherwise on each iteration it may happens that at the end of the loop you will get only the last image loaded. I'm not going into detail into what a closure is, but the principle is something like this:
for (var i = 0; i< 4; i++) {
var imgObj = new Image();
imgObj.onload = (function(img) {
return function () {
ctx.drawImage(imgObj, 0, 0);
}
})(i);
imgObj.src = 'image.png';
}
This way by calling a new function you will create a new execution context retaining the value of i on each iteration.
I am just adding a little help for your code.
For assigning functions the way you're doing it , it is cheaper to do it the way below.
for (x = 101; x <= 155; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "Resources/ClassicCardImages/deck1/dood_deck/"+x+".GIF";
imageObj.onload= imageOnLoad;
}
function imageOnLoad(){
loadedCount++;
if(loadedCount==55){
cardsImagesLoaded();
}else {
alert(loadedCount);
}
};
tiles.push(imageObj);
}
I'm writing a simple 2D side scroller game using JavaScript + Canvas. I am trying to do this while learning OO JavaScript. I'm encountering an issue where my image will not draw to the canvas, despite being loaded correctly. Here's the code:
//===================================
// class - Canvas
//===================================
var classCanvas = function(id){
canvas = document.getElementById(id);
context = canvas.getContext("2d");
}
//===================================
// abstract class - Image Drawer
//===================================
var classImageDrawer = function(that){
this.draw = function(){
context.drawImage(that.img,
that.spriteCoordsX,
that.spriteCoordsY,
that.width,
that.height,
that.posX,
that.posY,
that.width,
that.height);
}
}
//===================================
// class - Level
//===================================
var classLevel = function(name, src){
this.name = name;
this.img = new Image();
this.img.src = src;
this.img.onload = function(){ };
this.spriteCoordsX = 0;
this.spriteCoordsY = 0;
this.posY = 0;
this.posX = 0;
this.height = 400;
this.width = 600;
this.drawer = new classImageDrawer(this);
}
//==================================
// Begin
//==================================
var game = new classCanvas("playground");
game.LevelOne = new classLevel("LevelOne", "images/foreground-land.png");
game.LevelOne.drawer.draw();
I have checked the code, and I know the image is getting loaded correctly. No errors occur during runtime, the image "foreground-land.png" simply DOESN'T show up on the canvas!
Your image may be loading fine, but as far as I can tell your call to game.LevelOne.drawer.draw() has no guarantee that foreground-land.png has loaded at that point (remember, images are loaded asynchronously without blocking the execution of other code).
Your onload function for the image object in your classLevel class is empty and anonymous. Nothing happens when the image is finished loading. I'm not sure how you want to structure your code given everything else you have going on, but you should only allow the call to game.LevelOne.drawer.draw() to succeed if the resources it depends upon have been fully loaded. The best way to do this would be to hook into the onload callback for all resources you require for that object (in this case, it's just the one image).
Loading images is an async operation, you are (basically) ignoring the loading process, and acting as though it is sync operations.
One thing you could look at is using a 3rd parameter as a callback ("LevelOne", "images/foreground-land.png", function() { this.drawer.draw() }) and doing that as the onload