jQuery event after div background-image is rendered - javascript

Thanks for taking some of your time.
I was wondering if there was a possible way using jQuery to trigger a function right after a div background image is finished downloading and rendered.
Let's say you have this div
<div id="img1" class="img1"> </div>
where img1 style is
.img1 {
background-image: some_big_image.png;
background-position:center;
background-repeat:no-repeat;
background-size:cover;
display: none;
}
concidering this javascript function
function showDiv() {
$("#img1").fadeIn(1000);
}
Is there a way to call the previous function right after the image is rendered?
By rendered I mean resized to fit nicely within its div and ready to be shown.
I found a lot of infos about triggering a function after page load or after downloading image but nothing about post-render.
You guys are the bests. Thank you in advance.

Try
var img = new Image();
img.src = "/some_big_image.png";
img.onload = function( ) {
$("#img1").css("background-image", "url('" + img.src + "')" ).fadeIn(1000);
}
Fiddle here

I know you already accepted an answer above, but this can be simplified grealy to just use the jquery magic function
$(function() {
$("#img1").fadeIn(1000);
}
You replied above that the onload event wasn't working for you. The $(function() { //code here } ); fires when the dom is completely ready (not sure if all browsers do this by default for the onload event), so perhaps that is why you were having issues. It is also handy because you can call it multiple places on your page and they will be combined (rather then directly setting onload, which will be overriden if its set somewhere else)
Fiddle here: http://jsfiddle.net/5cR4G/8/

Related

Why is my div not updating when changing its class with JavaScript?

I currently have a div that's used to display and image via CSS.
For example:
HTML
<div id="myDiv" class="play"></div>
CSS
.play{background: url('../img/playIcon_black.png') no-repeat;}
This image appears as it should.
What I'm attempted to do is to change the image by changing the class (via JavaScript).
Example:
CSS
.pause{background: url('../img/pauseIcon_black.png') no-repeat;}
JavaScript
function myFunction() {
myDiv.className = "pause";
}
When I call myFunction() everything seems to work correctly with one exception. Occasionally the image does not update in the browser.
A few things to note:
I'm certain the function is being called correctly. If I put a console.log() statement within the function, it prints when it should. Additionally, if I inspect the element within the browser, the class is in fact changed to .pause
The image changes from the "play icon" to blank once the function is called, BUT upon hovering over the div the images then appears permanently.
This only seems to happen once the page is initially loaded. Meaning, I can only recreate the issue once upon refresh, then everything works correctly after that.
I have attempted to clear my cache but nothing seems to have changed.
(I'm not sure how relevant this is) I'm calling myFunction() via onended attribute of an audio tag.
For example:
<audio onended="myFunction()"></audio>
But I'm not certain if this would affect anything because the function appears to be called correctly.
Any ideas of why this might be happening?
So the issue is that when you change the class, the browser has to fetch the new image, which takes time. One way to fix the issue is by using sprites, where both images are actually in one image and you only show a piece of that image at a time.
Another solution is to preload the image and then apply the preloaded image source to your new element like this:
var image = newImage();
image.src = '../img/pauseIcon_black.png';
function myFunction() {
var cssBackground = 'url(' + image.src + ') no-repeat';
myDiv.style.background = cssBackground;
// Optionally with jQuery instead:
// $('#myElementID').css('background', cssBackground);
}
Note that if you call myFunction before the image loads you'll encounter the same error. The difference is that this will load the image when the page is loaded (or more properly, when this JS executes and myFunction is assigned) rather than when myFunction is called. To ensure the image is loaded you can use the onLoad event handler for the image object. For more details on preloading images check out this answer: preload image then change background javascript
You need to get the element id
function myfunction(){
var myDivElem = document.getElementById('myDiv');
myDivElem.className = 'pause';
}
You can use document.getElementById("myDiv").className="";in your function
OK if you don't want use first solution you can use second one:
You can add a class to element using
document.getElementById("myDiv").className +=" n";
Then add a class named .play.n to your css file after class named.play
Then add your image address.
If you want to manipulate the div with id "myDiv". Use it as
document.getElementById('myDiv').class
Sample codesnippet: example snippet

onload not working in <img> element

I don't understand why this function doesn't fire. I want to declare an image in HTML with a single onload function, which will automatically take care of the image's source and mouseover/out functions.
The HTML looks like this:
<img id="menuBtnNovo" onload="imgButton(this)"/>
and the JS function imgButton looks like this:
function imgButton(e){
window.alert("asdasdad");
e.src="images/def/" + e.Id + ".png";
e.onmouseover= function(){ *change image here*}
e.onmouseout= function(){ *change image back here*}
}
Now, not even the alert pops up, and I don't know why. I tried putting script in <head> and setting src to none src="" in the <img>. I'm using Firefox, but it doesn't work in Edge either.
Question is: how do I fire onload function on an image element?
Also, if you have any idea of your own way of implementing this behaviour of automatically loading certain images (that would actually be buttons/links), feel free to share it. I'm new to JS but not to programming.
As you might see, all images are in "images/def/..." and all images for when the mouse is over the img are in "images/mo/...".
I always try and let browser do image replacements, but if you have to use script, than you can do something like this on DOM ready, or window load event:
$('img[data-regular]').each(function(i) {
var thisImage = $(this);
var regular = thisImage.data('regular');
var hover = thisImage.data('hover');
thisImage.attr('src', regular);
/* Preload image for hover */
$('<img/>')[0].src = hover;
/* Set events */
thisImage.on('mouseenter', function(e) {
thisImage.attr('src', hover);
}).on('mouseleave', function(e) {
thisImage.attr('src', regular);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img data-regular="https://placehold.it/350x150" data-hover="https://placehold.it/450x200" />
Also on JSFiddle.

Preload all CSS images while showing a preloader

I have a website heavily loaded with images. It's quite unattractive to see the images coming up slowly. I've seen a few websites show a preloader which hides that ugly loading phase. I'm not talking about the <img /> tag here, but I'm talking about CSS background-images.
I do not understand how to achieve this effect using JavaScript and/or jQuery.
P.S: I also seeking links to plugins if there are any available.
Start of with setting the css:
#myElement
{
background-image: url('loading.gif');
}
Then use the following javascript function:
function loadImage()
{
var img = new Image;
img.src = "http://path/to/img";
img.onload = function()
{
var myElement = document.getElementById("myElement");
myElement.style.backgroundImage = "url('" + this.src + "')";
}
}
fire the function in the body onload like this:
<body onload="loadImage();">
or add it to another init script which fires from here.
Hope this will get you going!

Javascript replace( ) function running more than once on the same image

I'm running a Javascript replace function to replace standard images with class="replace-2x"on my jQuery Mobile site with Retina-quality images if the user is on a mobile device with Retina display. For example, on a Retina device, logo.png will be replaced with logo#2x.png. The JS function is here:
function highdpi_init() {
$(".replace-2x").each(function () {
var src = $(this).attr("src");
$(this).attr("src", src.replace(".png", "#2x.png").replace(".jpg", "#2x.jpg"));
});
}
$(".page").live('pageinit',function(event){
highdpi_init();
});
I'm now running into an issue where the replace function is running more than once. So for example, it replaces logo.png with logo#2x.png as the page is loading, but then as the page continues to load, it KEEPS replacing .png with #2x.png in the img src over and over so that the image tag ends up looking like this:
<img src="mobile/images/logo#2x#2x#2x#2x#2x#2x#2x#2x#2x#2x#2x.png" class="replace-2x" alt="logo" width="200">
How can I prevent this from replacing on a single img element more than once? Keep in mind, I will have multiple images on the same page, so the function will need to apply to all images, but only one time each.
The problem is surely that your 'pageinit' event is being called more than once. You can either follow MДΓΓ БДLL's idea (which won't work if images are dynamically added) or you can make your handler smarter so that it doesn't replace the src if it already was replaced
function highdpi_init() {
$(".replace-2x").each(function () {
var $this = $(this);
var src = $this.attr("src");
$this.attr("src", src.replace(".png", "#2x.png").replace(".jpg", "#2x.jpg"));
// Remove the class so it doesn't replace it again
$this.removeClass('replace-2x')
});
}
You don't need JS for this, you could do it in CSS only.
<link rel="stylesheet" media="only screen and (-webkit-min-device-pixel-ratio: 2)" href="/css/highdpi.css"/>
You could make your images look like
<img src="transparent.gif" class="logo-a" alt="logo" width="200" />
And in highdpi.css you could do
img.logo-a {
background-image: url('file#2x.png')
}
And in lowdpi.css
img.logo-a {
background-image: url('file.png')
}
Using .one() should work since it is just a binding and if you are using Jquery Mobile the way that is suggested it will be just fine. That is unless you are passing back the html from the server. In which case it would be a good idea to add an extra condition to make sure that the src doesn't already have #2x.png before replacing.
There is disappointingly little documentation on pageinit on the offical jQuery Mobile docs. So I'm going to speculate here. It looks like pageinit is used to fire events for when a specific DOM element has finished loading, since it may not have been loaded on the initial page load (deferred until needed). That being said, it may be that adding/altering images to the DOM element in question fires the pageinit again. Could you tag each updated image with something that says, 'hey, I've already been updated to 2x'? Something such as
$.data(targetimg, 'retinafied', true);
And then check for that value before replacing the src?

How can I determine if an image has loaded, using Javascript/jQuery?

I'm writing some Javascript to resize the large image to fit into the user's browser window. (I don't control the size of the source images unfortunately.)
So something like this would be in the HTML:
<img id="photo"
src="a_really_big_file.jpg"
alt="this is some alt text"
title="this is some title text" />
Is there a way for me to determine if the src image in an img tag has been downloaded?
I need this because I'm running into a problem if $(document).ready() is executed before the browser has loaded the image. $("#photo").width() and $("#photo").height() will return the size of the placeholder (the alt text). In my case this is something like 134 x 20.
Right now I'm just checking if the photo's height is less than 150, and assuming that if so it is just alt text. But this is quite a hack, and it would break if a photo is less than 150 pixels tall (not likely in my particular case), or if the alt text is more than 150 pixels tall (could possibly happen on a small browser window).
Edit: For anyone wanting to see the code:
$(function()
{
var REAL_WIDTH = $("#photo").width();
var REAL_HEIGHT = $("#photo").height();
$(window).resize(adjust_photo_size);
adjust_photo_size();
function adjust_photo_size()
{
if(REAL_HEIGHT < 150)
{
REAL_WIDTH = $("#photo").width();
REAL_HEIGHT = $("#photo").height();
if(REAL_HEIGHT < 150)
{
//image not loaded.. try again in a quarter-second
setTimeout(adjust_photo_size, 250);
return;
}
}
var new_width = . . . ;
var new_height = . . . ;
$("#photo").width(Math.round(new_width));
$("#photo").height(Math.round(new_height));
}
});
Update: Thanks for the suggestions. There is a risk of the event not being fired if I set a callback for the $("#photo").load event, so I have defined an onLoad event directly on the image tag. For the record, here is the code I ended up going with:
<img id="photo"
onload="photoLoaded();"
src="a_really_big_file.jpg"
alt="this is some alt text"
title="this is some title text" />
Then in Javascript:
//This must be outside $() because it may get called first
var isPhotoLoaded = false;
function photoLoaded()
{
isPhotoLoaded = true;
}
$(function()
{
//Hides scrollbars, so we can resize properly. Set with JS instead of
// CSS so that page doesn't break with JS disabled.
$("body").css("overflow", "hidden");
var REAL_WIDTH = -1;
var REAL_HEIGHT = -1;
$(window).resize(adjust_photo_size);
adjust_photo_size();
function adjust_photo_size()
{
if(!isPhotoLoaded)
{
//image not loaded.. try again in a quarter-second
setTimeout(adjust_photo_size, 250);
return;
}
else if(REAL_WIDTH < 0)
{
//first time in this function since photo loaded
REAL_WIDTH = $("#photo").width();
REAL_HEIGHT = $("#photo").height();
}
var new_width = . . . ;
var new_height = . . . ;
$("#photo").width(Math.round(new_width));
$("#photo").height(Math.round(new_height));
}
});
Either add an event listener, or have the image announce itself with onload. Then figure out the dimensions from there.
<img id="photo"
onload='loaded(this.id)'
src="a_really_big_file.jpg"
alt="this is some alt text"
title="this is some title text" />
Using the jquery data store you can define a 'loaded' state.
<img id="myimage" onload="$(this).data('loaded', 'loaded');" src="lolcats.jpg" />
Then elsewhere you can do:
if ($('#myimage').data('loaded')) {
// loaded, so do stuff
}
The right answer, is to use event.special.load
It is possible that the load event will not be triggered if the image is loaded from the browser cache. To account for this possibility, we can use a special load event that fires immediately if the image is ready. event.special.load is currently available as a plugin.
Per the docs on .load()
You want to do what Allain said, however be aware that sometimes the image loads before dom ready, which means your load handler won't fire. The best way is to do as Allain says, but set the src of the image with javascript after attaching the load hander. This way you can guarantee that it fires.
In terms of accessibility, will your site still work for people without javascript? You may want to give the img tag the correct src, attach you dom ready handler to run your js: clear the image src (give it a fixed with and height with css to prevent the page flickering), then set your img load handler, then reset the src to the correct file. This way you cover all bases :)
As per one of the recent comments to your original question
$(function() {
$(window).resize(adjust_photo_size);
adjust_photo_size();
function adjust_photo_size() {
if (!$("#photo").get(0).complete) {
$("#photo").load(function() {
adjust_photo_size();
});
} else {
...
}
});
Warning This answer could cause a serious loop in ie8 and lower, because img.complete is not always properly set by the browser. If you must support ie8, use a flag to remember the image is loaded.
Try something like:
$("#photo").load(function() {
alert("Hello from Image");
});
There's a jQuery plugin called "imagesLoaded" that provides a cross-browser compatible method to check if an element's image(s) have been loaded.
Site: https://github.com/desandro/imagesloaded/
Usage for a container that has many images inside:
$('container').imagesLoaded(function(){
console.log("I loaded!");
})
The plugin is great:
works for checking a container with many images inside
works for check an img to see if it has loaded
I found this worked for me
document.querySelector("img").addEventListener("load", function() { alert('onload!'); });
Credit goes totaly to Frank Schwieterman, who commented on accepted answer. I had to put this here, it's too valuable...
Any comments on this one?
...
doShow = function(){
if($('#img_id').attr('complete')){
alert('Image is loaded!');
} else {
window.setTimeout('doShow()',100);
}
};
$('#img_id').attr('src','image.jpg');
doShow();
...
Seems like works everywhere...
I just created a jQuery function to load an image using jQuerys Deferred Object which makes it very easy to react on load/error event:
$.fn.extend({
loadImg: function(url, timeout) {
// init deferred object
var defer = $.Deferred(),
$img = this,
img = $img.get(0),
timer = null;
// define load and error events BEFORE setting the src
// otherwise IE might fire the event before listening to it
$img.load(function(e) {
var that = this;
// defer this check in order to let IE catch the right image size
window.setTimeout(function() {
// make sure the width and height are > 0
((that.width > 0 && that.height > 0) ?
defer.resolveWith :
defer.rejectWith)($img);
}, 1);
}).error(function(e) {
defer.rejectWith($img);
});
// start loading the image
img.src = url;
// check if it's already in the cache
if (img.complete) {
defer.resolveWith($img);
} else if (0 !== timeout) {
// add a timeout, by default 15 seconds
timer = window.setTimeout(function() {
defer.rejectWith($img);
}, timeout || 15000);
}
// return the promise of the deferred object
return defer.promise().always(function() {
// stop the timeout timer
window.clearTimeout(timer);
timer = null;
// unbind the load and error event
this.off("load error");
});
}
});
Usage:
var image = $('<img />').loadImg('http://www.google.com/intl/en_com/images/srpr/logo3w.png')
.done(function() {
alert('image loaded');
$('body').append(this);
}).fail(function(){
alert('image failed');
});
See it working at: http://jsfiddle.net/roberkules/AdWZj/
This function checks if an image is loaded based on having measurable dimensions. This technique is useful if your script is executing after some of the images have already been loaded.
imageLoaded = function(node) {
var w = 'undefined' != typeof node.clientWidth ? node.clientWidth : node.offsetWidth;
var h = 'undefined' != typeof node.clientHeight ? node.clientHeight : node.offsetHeight;
return w+h > 0 ? true : false;
};
We developed a page where it loaded a number of images and then performed other functions only after the image was loaded. It was a busy site that generated a lot of traffic. It seems that the following simple script worked on practically all browsers:
$(elem).onload = function() {
doSomething();
}
BUT THIS IS A POTENTIAL ISSUE FOR IE9!
The ONLY browser we had reported issues on is IE9. Are we not surprised? It seems that the best way to solve the issue there is to not assign a src to the image until AFTER the onload function has been defined, like so:
$(elem).onload = function() {
doSomething();
}
$(elem).attr('src','theimage.png');
It seems that IE 9 will sometimes not throw the onload event for whatever reason. Other solutions on this page (such as the one from Evan Carroll, for example) still did not work. Logically, that checked if the load state was already successful and triggered the function and if it wasn't, then set the onload handler, but even when you do that we demonstrated in testing that the image could load between those two lines of js thereby appearing not loaded to the first line and then loading before the onload handler is set.
We found that the best way to get what you want is to not define the image's src until you have set the onload event trigger.
We only just recently stopped supporting IE8 so I can't speak for versions prior to IE9, otherwise, out of all the other browsers that were used on the site -- IE10 and 11 as well as Firefox, Chrome, Opera, Safari and whatever mobile browser people were using -- setting the src before assigning the onload handler was not even an issue.
May I suggest a pure CSS solution altogether?
Just have a Div that you want to show the image in. Set the image as background. Then have the property background-size: cover or background-size: contain depending on how you want it.
cover will crop the image until smaller sides cover the box.
contain will keep the entire image inside the div, leaving you with spaces on sides.
Check the snippet below.
div {
height: 300px;
width: 300px;
border: 3px dashed grey;
background-position: center;
background-repeat: no-repeat;
}
.cover-image {
background-size: cover;
}
.contain-image {
background-size: contain;
}
<div class="cover-image" style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>
<br/>
<div class="contain-image" style="background-image:url(https://assets1.ignimgs.com/2019/04/25/avengers-endgame-1280y-1556226255823_1280w.jpg)">
</div>
I find that this simple solution works best for me:
function setEqualHeight(a, b) {
if (!$(a).height()) {
return window.setTimeout(function(){ setEqualHeight(a, b); }, 1000);
}
$(b).height($(a).height());
}
$(document).ready(function() {
setEqualHeight('#image', '#description');
$(window).resize(function(){setEqualHeight('#image', '#description')});
});
</script>
image.complete might be another option https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/complete

Categories

Resources