Placeholder while an image is loading with Ember.js [duplicate] - javascript

I'm currently working on a web application which has a page which displays a single chart (a .png image). On another part of this page there are a set of links which, when clicked, the entire page reloads and looks exactly the same as before except for the chart in the middle of the page.
What I want to do is when a link is clicked on a page just the chart on the page is changed. This will speed things up tremendously as the page is roughly 100kb large, and don't really want to reload the entire page just to display this.
I've been doing this via JavaScript, which works so far, using the following code
document.getElementById('chart').src = '/charts/10.png';
The problem is that when the user clicks on the link, it may take a couple of seconds before the chart changes. This makes the user think that their click hasn't done anything, or that the system is slow to respond.
What I want to happen is display a spinner / throbber / status indicator, in place of where the image is while it is loading, so when the user clicks the link they know at least the system has taken their input and is doing something about it.
I've tried a few suggestions, even using a psudo time out to show a spinner, and then flick back to the image.
A good suggestion I've had is to use the following
<img src="/charts/10.png" lowsrc="/spinner.gif"/>
Which would be ideal, except the spinner is significantly smaller than the chart which is being displayed.
Any other ideas?

I've used something like this to preload an image and then automatically call back to my javascript when the image is finished loading. You want to check complete before you setup the callback because the image may already be cached and it may not call your callback.
function PreloadImage(imgSrc, callback){
var objImagePreloader = new Image();
objImagePreloader.src = imgSrc;
if(objImagePreloader.complete){
callback();
objImagePreloader.onload=function(){};
}
else{
objImagePreloader.onload = function() {
callback();
// clear onLoad, IE behaves irratically with animated gifs otherwise
objImagePreloader.onload=function(){};
}
}
}

You could show a static image that gives the optical illusion of a spinny-wheel, like these.

Using the load() method of jQuery, it is easily possible to do something as soon as an image is loaded:
$('img.example').load(function() {
$('#spinner').fadeOut();
});
See: http://api.jquery.com/load-event/

Use the power of the setTimeout() function (More info) - this allows you set a timer to trigger a function call in the future, and calling it won't block execution of the current / other functions (async.).
Position a div containing the spinner above the chart image, with it's css display attribute set to none:
<div> <img src="spinner.gif" id="spinnerImg" style="display: none;" /></div>
The nbsp stop the div collapsing when the spinner is hidden. Without it, when you toggle display of the spinner, your layout will "twitch"
function chartOnClick() {
//How long to show the spinner for in ms (eg 3 seconds)
var spinnerShowTime = 3000
//Show the spinner
document.getElementById('spinnerImg').style.display = "";
//Change the chart src
document.getElementById('chart').src = '/charts/10.png';
//Set the timeout on the spinner
setTimeout("hideSpinner()", spinnerShowTime);
}
function hideSpinner() {
document.getElementById('spinnerImg').style.display = "none";
}

Use CSS to set the loading animation as a centered background-image for the image's container.
Then when loading the new large image, first set the src to a preloaded transparent 1 pixel gif.
e.g.
document.getElementById('mainimg').src = '/images/1pix.gif';
document.getElementById('mainimg').src = '/images/large_image.jpg';
While the large_image.jpg is loading, the background will show through the 1pix transparent gif.

Building on Ed's answer, I would prefer to see something like:
function PreLoadImage( srcURL, callback, errorCallback ) {
var thePic = new Image();
thePic.onload = function() {
callback();
thePic.onload = function(){};
}
thePic.onerror = function() {
errorCallback();
}
thePic.src = srcURL;
}
Your callback can display the image in its proper place and dispose/hide of a spinner, and the errorCallback prevents your page from "beachballing". All event driven, no timers or polling, plus you don't have to add the additional if statements to check if the image completed loading while you where setting up your events - since they're set up beforehand they'll trigger regardless of how quickly the images loads.

Some time ago I have written a jQuery plugin which handles displaying a spinner automatically http://denysonique.github.com/imgPreload/
Looking in to its source code should help you with detecting when to display the spinner and with displaying it in the centre of the loaded image.

I like #duddle's jquery method but find that load() isn't always called (such as when the image is retrieved from cache in IE). I use this version instead:
$('img.example').one('load', function() {
$('#spinner').remove();
}).each(function() {
if(this.complete) {
$(this).trigger('load');
}
});
This calls load at most one time and immediately if it's already completed loading.

put the spinner in a div the same size as the chart, you know the height and width so you can use relative positioning to center it correctly.

Aside from the lowsrc option, I've also used a background-image on the img's container.

Be aware that the callback function is also called if the image src doesn't exist (http 404 error). To avoid this you can check the width of the image, like:
if(this.width == 0) return false;

#iAn's solution looks good to me. The only thing I'd change is instead of using setTimeout, I'd try and hook into the images 'Load' event. This way, if the image takes longer than 3 seconds to download, you'll still get the spinner.
On the other hand, if it takes less time to download, you'll get the spinner for less than 3 seconds.

I would add some random digits to avoid the browser cache.

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

rotate image urls in img tag to preload all

I'm currently writing an HTML5 P&C aventure.
Since there are many images and sprites to load before the game can start I wanted to preload all images.
My idea was to create a single <img> and make it visibility: hidden;, so the user does not see anything.
After every loaded image I want to execute a function that updates a progressbar.
So I did something like this:
loadImages: function () {
$('#preLoader').attr('src', this.__images[0]).on('load', this.loadCallback);
},
loadCallback: function () {
this.__images.splice(0, 1);
Game.events.trigger('progressbar:bar:step');
if(this.__images.length > 0) {
this.loadImages();
}
else if(!this.__fired) {
this.__fired = true;
this.trigger('finished');
}
}.$bound(),
this.__images is an array containing all urls to be loaded, the callback function basically calls the progressbar to update and checks if there are images left and then again calls the first function.
Thing is, that it seems, that the load event does not really wait until the image is loaded, because under a 1ms after the src attribut of the <img> has been changed the callback gets fired.
So this might not work properly
Is there a way to achieve this like I want to?
Basically I want the image to be loaded complete and then fire the callback, then again load the image, etc... until all images in the array are loaded.
I ended up using this jquery plugin: http://alz.so/imageloader/
It has all the functionality I need and even more.

HTML / Javascript wait for graphics to be drawn

I've heard about the onload function which is called after the element is fully loaded.
In the case of graphics or images, does that mean it will wait until the image is displayed in the browser?
<body onload="foo()">...
<img onload="bar();"....
If not, is there a way to get the event when all graphics are drawn and images are displayed on a page?
In my case it´s only one 1600*1200 jpeg image and i draw on it. But the image has to be displayed before i start drawing, even with the onload event i see the drawed lines before the image appear.
Yes body onload will wait until all images (and other content) are loaded/displayed in the browser. The img onload will wait until that specific image has loaded/is displayed
Images have a complete property that's true when they are loaded.
e.g. would test if everything has loaded:
var allImagesLoaded = true;
$("IMG").each(function(){ allImagesLoaded &= $(this).attr("complete"); });
if(allImagesLoaded){ alert("Done!");}
Images raise a load event once they've finished loading
why dont you keep a counter for your images that will decrement by one on each image load.
check if it equal to 0 then call some another function.
in this way you can do the thing you want to when all images are loaded
$(function() {
$('img').one('load',function() {
// fire when image loads decrement the counter
if counter ==0
fireanotherfunction()
});
});
by above code u can attain your purpose
When reading the jQuery ready API documentation here:
While JavaScript provides the load event for executing code when a
page is rendered, this event does not get triggered until all assets
such as images have been completely received.
So onload is launched after everything has been loaded (and displayed).
See the window.load event:
The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images and sub-frames have finished loading.
This is exact what you want, I believe.
JQuery's $(document).ready is not what you want:
In cases where code relies on loaded assets (for example, if the dimensions of an image are required), the code should be placed in a handler for the load event [instead of the ready event].
If you're using plain JS, window.load is what you want.
If you are using jQuery, you'll want $(document).load.
try jquery ready function
$(document).ready(function(){
bar();
});
I'm not sure if it works, but it's a try :D
I have the same problem developing a web view for an Android app. The load events (both for window and image element) as well as the complete state of the image element fire too early. My (svg) image has not yet finished drawing and thus calculations on the size go wrong.
The only workaround that I have found is a very short timer (1ms or maybe 10ms). That works for me because I have only one such image to consider. And since I start this timer when the image data has already loaded, this short lapse should be long enough for the device to paint the image.
window.addEventListener('load', function() {
var img = document.getElementById('logo');
window.setTimeout(function(){
var imgRatio = img.naturalWidth / img.naturalHeight;
var renderedWidth = parseInt(window.getComputedStyle(img).width.match(/(\d+)px/));
console.log(renderedWidth, img.complete);
if (renderedWidth < img.naturalWidth) {
img.style.height = (renderedWidth / imgRatio) + 'px';
}
}, 1);
}
Instead of the window load event, the image's load event should also work. But I found it safer to wait for everything, because other elements might affect the drawing of my image.

Image width traces zero with onload when cached

I'm building a Javascript lightbox and I'm trying to adjust the size once the image has loaded. I'm using the code below, which works fine - it outputs the correct width once loaded.
My problem:
When I refresh, it will load the image instantly from the cache, and it seems to bypass the load. I get an instant zero for the width. Why does this happen?
My code:
var oImage = new Image();
oImage.src = 'http://mydomain.com/image.png';
container.html(oImage);
oImage.onload = function(){
alert(this.width);
}
** Update **
#Alex: This is the code I've tried with your plugin, I assume I'm probably doing something wrong. I'd be eager to get this working because your plugin looks quite good.
container.waitForImages(function() {
var cWidth = $(this).width();
alert("width: "+cWidth); // returns 0 - works first time but not cached
});
// Adding the image to the container for preload
container.html('<img src="mygraphic.png" />');
You need to do a few things...
Check the complete property of the img element.
Attach the load event before setting the src property.
Also, I found creating a new Image and assigning the src there is the best way to determine if the image has loaded or not.
You may want to switch the .html() and the .onload() calls.
If the image is loading from cache, I'm imagining that the .html() call completes before the script has had a chance to attach a function handler to the image's onload event. Therefore, effectively bypassing the load event itself (as the image has already loaded).
If it's still downloading the image (i.e. not cached), there will be more than enough time to call the .onload attach before the image completely finishes rendering.
While you're at it, you may want to do this the jQuery way, just so you're attaching events more similarly to DOM2 than DOM0.
var image = $('<img/>', {
src : 'http://mydomain.com/image.png'
}).load(function () {
alert(this.width);
})
// maybe clear container before if you want
.appendTo(container);
If we're going to have to set the src after the onload, we might as well do this instead:
var image = $('<img/>')
.load(function () {
alert(this.width);
})
.attr('src','http://mydomain.com/image.png')
.appendTo(container)
;
Hopefully that works cleanly.
This answer JavaScript: Know when an image is fully loaded suggests that you should set onload before setting src

Pre Load images to display later on click event jQuery

I have a web page where lots of images called from server using image
scr attribute.
I have created a function like which is triggered by td click.
function GoToStep(stepNo) {
var imgSrc = $("#h1" + stepNo).val();
$(".img_vertical").css("background-image", "url(" + imgSrc + ")");
}
Now the problem is this. For slower connections the images come after some
moment.
Can I pre load images to avoid waiting time when user clicks
td?
I have seen some jquery function to pre load images.
Kindly give some idea how can I achieve it.
Pre-loading an image is equivalent to loading an image but never displaying it. So, you can easily do it like this:
<img src="image.png" alt="" style="display:none;"/>
Now this image will be loaded as soon as the html starts rendering. Whenever you need to use this image as a display or background, just set the address to image.png and it will automatically be fetched from browser's cache.
This can be done using some javascript functions. Quoting from another question.
function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
$('<img/>')[0].src = this;
// Alternatively you could use:
// (new Image()).src = this;
});
}
// Usage:
preload([
'img/imageName.jpg',
'img/anotherOne.jpg',
'img/blahblahblah.jpg'
]);
Explanation of how javascript preloaders work (different question)
[...] The way it works is simply by creating a new Image object and setting
the src of it, the browser is going to go grab the image. We're not
adding this particular image to the browser, but when the time comes
to show the image in the page via whatever method we have setup, the
browser will already have it in its cache and will not go fetch it
again. [...]
So in your case, you should use something like
$(function() {
// Do stuff when DOM is ready
preload([
'img/bg1.jpg',
'img/bg2.jpg',
'img/bg3.jpg'
]);
});

Categories

Resources