So I have two functions. One to load the image and the other to resize its container element. Naturally the image element needs to be loaded, before any measurements can be taken. It looks something like this:
var imgEl;
loadImage(imgSrc);
// only call the below, once the above has finished loading and appending the image.
resizeModal();
function loadImage(imgSrc) {
var image = new Image();
image.src = imgSrc;
image.onload = function() {
imgEl = $('<img src='+image.src+'/>');
imgEl.prependTo(modal);
}
}
function resizeModal() {
// Do stuff based off the imgEl once it's been loaded and appended
var width = imgEl.width();
modal.width(width)
}
I've tried using $.Deferred, but I'm apparently missing something, as "B" always gets logged before "A":
var imgEl;
loadImage(imgSrc).done( resizeModal() )
function loadImage(imgSrc) {
var def = $.Deferred();
var image = new Image();
image.src = imgSrc;
image.onload = function() {
imgEl = $('<img src='+image.src+'/>');
imgEl.prependTo(modal);
console.log("A");
def.resolve();
}
return def;
}
function resizeModal() {
console.log("B");
// Do stuff based off the imgEl once it's been loaded and appended
var width = imgEl.width();
modal.width(width)
}
That's because you are explicitly calling resizeModal before the promise is resolved:
loadImage(imgSrc).done( resizeModal() )
Just like with foo(bar()), this will call resizeModal and pass its return value to done().
You want to pass the function itself instead:
loadImage(imgSrc).done(resizeModal)
This basically means "call resizeModal once you are done".
var loadImage = function(imgSrc, callback) {
var imgEl;
var image = new Image();
image.src = imgSrc;
image.onload = function() {
imgEl = $('<img src='+image.src+'/>');
imgEl.prependTo(modal);
}
callback(imgEl);
}
var resizeModal = function(imgEl) {
// Do stuff based off the imgEl once it's been loaded and appended
var width = imgEl.width();
modal.width(width)
return width; // or whatever you are trying to get from this.
}
var finalOutput = loadImage(imgSrc, resizeModal);
Have you tried a structure like this?
Related
i have this function to create new images to load them in memory
function preloadImgs() {
var imgDomain = "http://imgs.domain/";
if (document.images) {
var img1 = new Image();
var img2 = new Image();
var img3 = new Image();
img1.src = imgDomain + "images/1/cover.jpg";
img2.src = imgDomain + "images/2/cover.jpg";
img3.src = imgDomain + "images/3/cover.jpg";
} }
// initialize the function
preloadImgs()
i need a way to know when all images in preloadImgs() function have been loaded , how can i achive that using the same code that i have provided ?
You can use a promise pattern.
https://developers.google.com/web/fundamentals/getting-started/primers/promises
Although these aren't natively supported everywhere, jQuery (tagged) provides an implementation:
https://api.jquery.com/promise/
Combined with img.onload to resolve the promises you can respond to an array of promises by:
var arrayOfPromises = [];
var $deferred = $.Deferred();
var img = new Image();
img.onload = function() {
// Check your support needs # http://caniuse.com/#search=naturalWidth
if (img.naturalWidth && img.naturalHeight) {
$deferred.resolve()
} else {
$deferred.reject();
}
};
img.onerror = $deferred.reject;
img.src = 'someimage.png';
arrayOfPromises.push($deferred);
$.when.apply($, arrayOfPromises).then(function() {
// your callback, images all loaded
alert('OK')
}, function() {
// Any failed image load occur
alert('FAIL')
});
I have my main function which calls my loadtexture function that loads two images and returns a base64 encode of the combined image but it keeps skipping my onload functions when it's trying to load the images.
$(document).ready(function () {
var modelPath = "models/testhiddenUV.obj";
var texture = loadTexture();
loadModel(texture, modelPath, "designCanvas");
});
function loadTexture() {
var frontImage = new Image();
var backImage = new Image();
var canvas = document.getElementById("designCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#FFF";
ctx.fillRect(0,0,1024,1024);
//skips whole onload functions to the end
frontImage.onload = function() {
frontImage.src = "models/wine.jpg";
ctx.drawImage(frontImage,0,0);
backImage.onload = function() {
backImage.onload = "models.petro21.jpg";
ctx.drawImage(backimage, 804, 0);
return canvas.toDataUrl("image/png");
}
}
To me the code looks right and should execute, am I missing something with the onload function? Why does it skip those lines of code?
.onload
is an asynchronous call-back. And you have to call it in order for it to run.
So basically:
frontImage.onload = function() {
ctx.drawImage(frontImage,0,0);
}
frontImage.src = URL.createObjectURL("models/wine.jpg");
backImage.onload = function() {
ctx.drawImage(backimage, 804, 0);
}
backImage.src = URL.createObjectURL("whateverURIyouhave");
I have been trying to draw a tile-like map to the canvas, although if i try to draw the same sprite twice, it will only render the final call of drawImage. Here is my code if it helps :
window.onload = function(){
function get(id){
return document.getElementById(id);
}
var canvas = get("canvas");
ctx = canvas.getContext("2d");
canvas.width = 160;
canvas.height = 160;
grass = new Image();
water = new Image();
grass.src = "res/Grass.png";
water.src = "res/Water.png";
path = {
draw: function(image,X,Y){
X = (X*32)-32;
Y = (Y*32)-32;
image.onload = function(){
ctx.drawImage(image,X,Y);
}
},
}
path.draw(water,2,2);
path.draw(grass,1,2);
path.draw(grass,1,1);
path.draw(water,2,1);
}
You're overwriting onload on the image next time you call it.
Think of it this way:
var image = {
onload: null
};
// Wait for the image to "load"
// Remember, onload is asynchronous so it won't be called until the rest of
// your code is done and the image is loaded
setTimeout(function() {
image.onload();
}, 500);
image.onload = function() {
console.log('I will never be called');
};
image.onload = function() {
console.log('I overwrite the previous one');
};
Instead, you might try waiting for your images to load then do the rest of your logic.
var numOfImagesLoading = 0;
var firstImage = new Image();
var secondImage = new Image();
// This is called when an image finishes loading
function onLoad() {
numOfImagesLoading -= 1;
if (numOfImagesLoading === 0) {
doStuff();
}
}
function doStuff() {
// This is where you can use your images
document.body.appendChild(firstImage);
document.body.appendChild(secondImage);
}
firstImage.src = 'http://placehold.it/100x100';
firstImage.onload = onLoad;
numOfImagesLoading += 1;
secondImage.src = 'http://placehold.it/200x200';
secondImage.onload = onLoad;
numOfImagesLoading += 1;
I have an image that changes when the user clicks a different thumbnail.
How do I make it reliably get the dimensions of the image that is about to be loaded?
Currently I have:
$('#mainImg').animate({opacity: 0.01}, 500, function() {
$('#mainImg').attr('src', '/cakes/' + file);
setTimeout(function() {
center('#mainImg');
$('#mainImg').animate({opacity: 1.00}, 500);
}, 100)
})
Which is a work around that is a little more reliable than what I previously had:
$('#mainImg').fadeOut('fast', function(){
$('#mainImg').attr('src', '/cakes/'+file);
center('#mainImg');
$('#mainImg').fadeIn('fast');
})
Function center is for now just:
function center(imageElement)
{
var ph = $(imageElement).parent().height();
var pw = $(imageElement).parent().width();
var ih = $(imageElement).height();
var iw = $(imageElement).width();
alert(iw)
}
You should preload image first to have reliable dimensions. Try something like this:
$('#mainImg').animate({opacity: 0.01}, 500, function() {
var $this = $(this),
src = '/cakes/' + file;
preloadImage(src, function() {
$this.attr('src', src);
center($this);
$this.animate({opacity: 1.00}, 500);
});
});
preloadImage(src, callback) {
var img = new Image();
img.onload = callback;
img.src = src;
}
Also modify center function to use already available cached variable:
function center($imageElement) {
var ih = $imageElement[0].height;
var iw = $imageElement[0].width;
alert(iw)
}
I think you'll have to preload that image, something like this:
var image = new Image();
image.src = "https://www.google.nl/images/srpr/logo11w.png";
image.onload = function () {
// Do whatever you want with this.width and this.height overhere.
console.log(this.width);
console.log(this.height);
}
Simular to the already posted answers but with a fallback for the browsers that do not support the load event for images properly:
$('#mainImg').animate({opacity: 0.01}, 500, function() {
// run the load event only once
$('#mainImg').one('load', function() {
// do whatever you want to do if image is loaded...
console.log(this.width);
console.log(this.height);
})
.attr('src', '/cakes/' + file);
.each(function() {
//Cache fix for browsers that don't trigger .load()
if(this.complete) $(this).trigger('load');
});
})
I need to be able to wait to start a function until the height and width of an image are available. When this code calls start(), it still says the height and width are zero:
var img = new Image();
init = function() {
img.onload = this.start();
img.src = "sky.jpg";
}
start = function() {
alert("Start called.\nwidth:"+img.width+"\nheight"+img.height);
}
init();
How can I make it wait until the dimensions are available before calling start()?
var img = new Image();
var start = function() {
alert("Start called.\nwidth:"+img.width+"\nheight"+img.height);
}
var init = function() {
img.onload = start;
img.src = "sky.jpg";
}
init();
Change this.start() to start.
I also scoped your functions.