JS wait for CSS background image to load - javascript

It's easy to keep javascript waiting for some images to load if those are classic HTML images.
But I can't figure how to do the same if the image is loaded as a CSS backuground-image!
Is it possible?
The jQuery .load() method doesn't seem to apply.. and I'm short of ideas

It looks for elements with src attribute or backgroundImage css property and calls an action function when theirs images loaded.
/**
* Load and wait for loading images.
*/
function loadImages(images, action){
var loaded_images = 0;
var bad_tags = 0;
$(images).each(function() {
//alert($(this).get(0).tagName+" "+$(this).attr("id")+" "+$(this).css("display"));
var image = new Image();
var src = $(this).attr("src");
var backgroundImage = $(this).css("backgroundImage");
// Search for css background style
if(src == undefined && backgroundImage != "none"){
var pattern = /url\("{0,1}([^"]*)"{0,1}\)/;
src = pattern.exec(backgroundImage)[1];
}else{
bad_tags++;
}
// Load images
$(image).load(function() {
loaded_images++;
if(loaded_images == ($(images).length - bad_tags))
action();
})
.attr("src", src);
});
}

One alternate approach would be to fetch the image data via AJAX as a base64 encoded png and apply it to the element's background-image property.
For example:
$.get('/getmyimage', function(data) {
// data contains base64 encoded image
// for ex: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==
$('#yourElement').css('background-image', 'url("' + data + '")');
});
You will also need a server side script that reads the image, converts it into base64 encoded png (and cache it maybe) and return the same.

Try this one...
Its a jQuery-Plugin which gives you control to wait for images to be loaded
Project-Home
Thread # SO
Official way to ask jQuery wait for all images to load before executing something
Answer # SO
(ShortLink)

this is untested code but try this:
$(document).ready(
function()
{
var imgSrc = $('theTargerElement').css('background-image');
var imgTag = $('<img>').attr('src',imgSrc).appendTo( 'body' );
}
);
$(document)
.load(
function()
{
// do stuff
}
);

Related

Image source not changing with JavaScript

Please answer this question, as I am struggling a lot with it.
I am trying to change image source on mouse over. I am able to do it, but image is not displaying on page.
I am trying to change image source to cross domain URL. I can see that in DOM image source is changing but on page its not.
I have tried all solutions mentioned in LINK, but none of them is working.
Please let me solution to problem.
NOTE:
I can see in network tab image is taking some time to download (about 1 sec).
It is an intermediate issue, sometime image is loading and sometimes its not
CODE:
document.getElementsByTagName('img')[0].addEventListener('mouseover', function()
{
document.getElementsByTagName('img')[0].setAttribute('src', 'url/of/the/image');
});
have you tried loading images before everything else?
function initImages(){
var imC = 0;
var imN = 0;
for ( var i in Images ) imN++;
for(var i in Images){
var t=Images[i];
Images[i]=new Image();
Images[i].src=t;
Images[i].onload = function (){
imC++;
if(imC == imN){
console.log("Load Completed");
preloaded = 1;
}
}
}
}
and
var Images = {
one image: "path/to/1.png",
....
}
then
if( preloaded == 1 ){
start_your_page();
}
Here the code that will remove the img tag and replace it with a new one:
document.getElementsByTagName('img')[0].addEventListener('mouseover', function() {
var parent = document.getElementsByTagName('img')[0].parentElement;
parent.removeChild(document.getElementsByTagName('img')[0]);
var new_img = document.createElement("img");
new_img.src = "https://upload.wikimedia.org/wikipedia/commons/6/69/600x400_kastra.jpg";
parent.appendChild(new_img);
});
<img src="https://www.w3schools.com/w3images/fjords.jpg">
I resolved the issue using code:
function displayImage() {
let image = new image();
image.src="source/of/image/returned/from/service";
image.addEventListener('load', function () {
document.getElementsByTagName('img')[0].src = image.src;
},false);
}
Here in code, I am attaching load event to image, source of image will be changed after image is loaded.

show alternate image if img src is not found - knockout

I have this piece of code.
<img data-bind="attr: {src: 'imagePath'}, style: { 'background-image': 'url('imagePath')' }" class="img-responsive">
The problem is it is showing two images. One is the image coming from src and other one coming from background image. My goal was to enable the background image when the src image is not available.
What you can do is create a custom binding, let's call it safeSrc.
In this binding, you listen to the load and error events of your image - rendering your image if it's loaded successfully and rendering a fallback if it is not.
In practice, it could look like the following:
ko.bindingHandlers.safeSrc = {
update: function(element, valueAccessor) {
var options = valueAccessor();
var src = ko.unwrap(options.src);
$('<img />').attr('src', src).on('load', function() {
$(element).attr('src', src);
}).on('error', function() {
$(element).attr('src', ko.unwrap(options.fallback));
});
}
};
And then, you can apply the binding like this:
<img alt="Foo" data-bind="safeSrc: {src: imageObservable, fallback: 'https://example.com/fallback.png'}" />
Note that this presumes you're using jQuery - but you can easily rewrite the event listener.
Finally, I would also like to say that you should be rendering a different src instead of the background image - unless you have a specific reason to require one?
Either way, you can simply change the line $(element).attr('src', ko.unwrap(options.fallback)); to $(element).css('background-image', 'url(' + ko.unwrap(options.fallback) + ')');.
JS Fiddle Demo
Here, you can see it all in action: https://jsfiddle.net/13vkutkv/2/
(EDIT: I replaced the cheeky hotlink to the Knockout JS logo with Placehold.it)
P.S.: Depending on how you wish to interact with the element in future (interacting with/updating the binding), you may wish to use applyBindingsToNode (i.e. the Knockout-way), rather than manipulating the src attribute directly on the DOM element.
To show alternate image if img src is not found make alternate image link in your server logic and use only src: 'imagePath' in your front-end
Or if it is important to do it in front-end, you should look at this post:
Display alternate image
I always check my images with a deferred object to be sure they will load. This is using the jquery deferred method, but you could use any deferred library. I coded this from memory, so there may be some errors.
<img data-bind="attr: {src: $root.imagePath()}, style: { 'background-image': 'url('imagePath')' }" class="img-responsive">
var myController = function()
{
var self = this;
this.imagePath = ko.observable('myPath.png'); // Make the image url an observable
var getImagePath = function(path)
{
var imagePath = this.imagePath();
isLoaded(imagePath).done(function(result)
{
// The image will load fine, do nothing.
}).fail(function(e)
{
self.imagePath('defaultImageOnFail.png'); // replace the image if it fails to load
});
};
getImagePath();
};
var isLoaded = function(img)
{
var deferred = new $.Deferred();
var imgObj = $("<img src='"+img+"'/>");
if(imgObj.height > 0 || imgObj.width > 0)
{
deferred.resolve(true);
}
else
{
imgObj.on("load", function(e)
{
deferred.resolve(true);
});
imgObj.on("error", function(e)
{
console.info("VoteScreenController.isLoaded URL error");
deferred.reject();
});
}
return deferred.promise();
};

jQuery or Javascript check if image loaded

I know there is a lot of these on Stackoverflow but I haven't found one that works for me in a recent version of jquery (1.10.2).
I did try:
$(".lazy").load(function (){}
But I believe after some research using .load to detect image load is deprecated in jQuery 1.8. What I need to do is fire an image resize function once the images are loaded. I don't have control over the
HTML and at the moment I am having to add the image dimensions via jQuery by attaching an attribute (via .attr()) once page loads so that I can use lazyload js.
The problem is that I need an accurate way to hold off all my various scripts until the image has loaded properly else the functions sometimes fire before every image had loaded. I have tried using $(window).load(function (){}); however it sometimes still fires before every image had loaded.
I usually do this:
var image = new Image();
image.onload = function () {
console.info("Image loaded !");
//do something...
}
image.onerror = function () {
console.error("Cannot load image");
//do something else...
}
image.src = "/images/blah/foo.jpg";
Remember that the loading is asynchronous so you have to continue the script inside the onload and onerror events.
There's also a useful .complete property of an image object, you can use it if you have already set the .src of your <img> before attaching to it any event listeners:
var img=document.getElementById('myimg');
var func=function(){
// do your code here
// `this` refers to the img object
};
if(img.complete){
func.call(img);
}
else{
img.onload=func;
}
Reference: http://www.w3schools.com/jsref/prop_img_complete.asp
I would give the images that require this constraint a class like mustLoad where:
<img class="mustLoad" src="..." alt="" />
and then create a generic image load handler function, such as:
$('img.mustLoad').on('load',function(){
/* Fire your image resize code here */
});
Edit:
In response to your comments about deprecating .load() above, .load() was deprecated, in favor of .on('load') to reduce ambiguity between the onLoad event and Ajax loading.
In the case of waiting of loading multiple images:
var images = $("#div-with-images img");
var unloaded = images.length;
images.on('load', function(){
-- unloaded;
if (!unloaded) {
// here all images loaded, do your stuff
}
});
What I need to do is fire an image resize function once the images are loaded.
Are you sure that you need the image to be loaded? Waiting for an image to load before resizing it can cause a large jump in the page layout, especially if the images have large file sizes, such as animated GIFs.
Usually, for an image resize, you only need to know the intrinsic dimensions of the image. While there is no event to tell you this, it's easy enough to poll the images for the data. Something like this could be particularly effective:
<img src="..." data-resizeme="123" />
(function() {
var images, l, i, tmp;
if( document.querySelectorAll) {
images = [].slice.call(document.querySelectorAll("img[data-resizeme]"),0);
}
else {
tmp = document.getElementsByTagName("img");
images = [];
// browser compatibility is fun!
for( i=tmp.length-1; i>=0; i--) {
if( tmp[i].getAttribute("data-resizeme")) images.unshift(tmp[i]);
}
}
for( i=images.length-1; i>=0; i--) {
images[i].onload = resizeImage;
images[i].onerror = cancelImageResize;
}
var timer = setInterval(function() {
for( i=images.length-1; i>=0; i--) {
if( images[i].width) {
resizeImage.call(images[i]);
images[i].onload = null;
cancelImageResize.call(images[i]);
}
}
if( images.length == 0) clearInterval(timer);
},100); // adjust granularity as needed - lower number is more responsive.
function cancelImageResize() {
var i;
for( i=images.length-1; i>=0; i--) {
if( images[i] == this) {
images.splice(i,1);
break;
}
}
}
function resizeImage() {
console.log("Image "+this.src+" is "+this.width+"x"+this.height);
}
})();
Hope this helps!

How to do a process after completion of another one in JavaScript

I want to add an image by Javascript, then calculating the html element width as
window.onload=function(){
document.getElementById('x').addEventListener('click', function(e){
var el = document.getElementById('xx');
el.innerHTML = '<img src="img.jpg" />';
var width = el.offsetWidth;
.....
}, false);
}
but since JavaScript conduct all processes simultaneously, I will get the width of the element before loading the image. How can I make sure that the image has been loaded into the content; then calculating the element width?
UPDATE: Thanks for the answers, but I think there is a misunderstanding. img src="img.jpg" /> does not exist in the DOM document. It will be added later by Javascript. Then, when trying to catch the element by Id, it is not there probably.
You can give the img an ID and do the following :-
var heavyImage = document.getElementById("my-img");//assuming your img ID is my-img
heavyImage.onload = function(){
//your code after image is fully loaded
}
window.onload=function(){
document.getElementById('x').addEventListener('click', function(e){
var el = document.getElementById('xx');
var img = new Image();//dynamically create image
img.src = "img.jpg";//set the src
img.alt = "alt";
el.appendChild(img);//append the image to the el
img.onload = function(){
var width = el.offsetWidth;
}
}, false);
}
This is untested, but if you add the image to the DOM, set an onload/load event-handler and then assign the src of the image, the event-handling should fire (once it's loaded) and allow you to find the width.
This is imperfect, though, since if the image is loaded from the browser's cache the onload/load event may not fire at all (particularly in Chromium/Chrome, I believe, though this is from memory of a bug that may, or may not, have since been fixed).
For the chrome bug you can use the following:-
var BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';//create a blank source
var tImg = document.getElementById("my-img");//get the image
var origSrc = tImg.src;//get the original src
tImg.src = BLANK;//change the img src to blank.
tImg.src = origSrc;//Change it back to original src. This will lead the chrome to load the image again.
tImg.onload= function(){
//your code after the image load
}
You can use a library called PreloadJS or you can try something like this:
//Somewhere in your document loading:
loadImage(yourImage, callbackOnComplete);
function loadImage(image, callbackOnComplete){
var self = this;
if(!image.complete)
window.content.setTimeout(
function() { self.loadImage(image, callbackOnComplete)}
,1000);
else callbackOnComplete();
}
I did this when I worked with images base64 which delay on loading.

Images not loaded when I display ajax content

I'm using jquery.load to pull in a fragment of html from another page. The fragment contains quite a large background image. Once the load function has finished and it calls it's callback I set the fragment to display block in the page - problem is that as the html loads I see the new content without the background image....the background image loads later.
Whats a good method of making sure the image is loaded before I show the ajax content?
You could do this...
$('button').click(function() {
$('#element').load('/echo/html/', function(responseText) {
// For testing
responseText = '<link href="http://sstatic.net/stackoverflow/all.css?v=ded66dc6482e" rel="stylesheet" type="text/css" /><div class="ac_loading" style="width: 200px; height: 200px;">ABC</div>';
var element = $(this),
responseTemp = $('<div />').hide().html(responseText).appendTo('body'),
styles = responseTemp.find('link[type="text/css"]'),
stylesHook = $('head link[type="text/css"]:last');
if (stylesHook.length === 0) {
stylesHook = $('head *:last-child');
}
styles.insertAfter(stylesHook);
preloadSrc = responseTemp.find('div').css('backgroundImage').replace(/^url\(["']?(.*?)["']?\)$/, '$1'), image = new Image();
image.onload = function() {
styles.add(responseTemp).remove();
element.html(responseText);
}
image.src = preloadSrc;
});
});
jsFiddle.

Categories

Resources