I am looking for a way to scale images of a web page for mobile devices. My approach is to store the dimensions of each image using JavaScript, and if the screen of the user is smaller than a certain value, all images will be resized using JavaScript. My problem is that the following function does not detect if the images are already loaded, so the result would be 0 for not loaded images. My question is, how can I implement a check, so that the function will compute the image size only after the image was completely loaded? I am not using jQuery.
function storeImageSizes() {
isizes = [];
imgs = document.getElementById('content').getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
isizes[i] = [
window.getComputedStyle(imgs[i]).getPropertyValue('width').replace('px', '') * 1,
window.getComputedStyle(imgs[i]).getPropertyValue('height').replace('px', '') * 1
];
}
}
Add a listener to be called when all DOM elements load. ie:
document.addEventListener("load", (function(){
isizes = [];
imgs = document.getElementById('content').getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
isizes[i] = [
window.getComputedStyle(imgs[i]).getPropertyValue('width').replace('px', '') * 1,
window.getComputedStyle(imgs[i]).getPropertyValue('height').replace('px', '') * 1
];
}
})
Did you try image.onload?
Also, check this answer out. It highlights the use of image.onload and also avoids browser cache issues.
You can use the following solution to perform image analysis after the images are already loaded:
document.querySelector('#image').addEventListener('load', storeImageSizes);
Calling storeImageSizes() in window.load function should fix the problem
$( window ).on( "load", function() { ... })
It basically is an event which is triggered when all the images and the complete page is loaded. Since you want the function to run when all the images are loaded you should use this event.
Note the difference between document.ready and window.load.
document.ready runs when the DOM is ready where as window.load runs once the complete page is loaded i.e., images/iframes etc.
Take reference from here Simple example using Jquery
Related
I've got a problem with some Javascript-generated content :
I use the onload() event of my html page to load HTML code from a server and inject it in the page. Since it already is html I use the innerHtml property of the nodes I want to fill with content.
Once I've injected the HTML I call a handmade adjustHeights() function that normalizes the height of the elements I created this way to make them all match the height of the tallest element.
All of this works perfectly unless the code inside innerHtml contains some sort of image or other media that takes time to load (particularly videos) because adjustHeights() is called between the injection of the code and the end of the loading time of the image/video/etc.
Is there any way to wait for every element to be loaded before calling adjustHeights() ? I've already tried the document.onreadystatechange property but the state is already on 'completed' when I start to inject code.
If it's possible I would rather not use time-based calls on adjustHeights().
To make it clearer here's an example :
var mylist = document.getElementById('mycontent');
var li;
for (var i = 0; i < res.length; i++)
{
li = document.create('li');
li.innerHTML=res[i];
mylist.appendChild(li);
}
adjustHeights();
To do this without adding an inline onload attribute to all the images/videos/etc you will have to observe the DOM for changes. Then on every change, you have to fetch all the new media and add the onload event to them from the callback. To prevent checking each element every time, once they've been loaded you could mark them as such by adding a data-loaded="true" property for instance.
A cross-browser solution to observe DOM changes can be found in this answer: Detect changes in the DOM. I will not repeat it here (but it's included in the demo below).
Note: I use images as an example, but this should also work for videos and other media.
On every DOM change first you check for images without the data-loaded attribute that are already loaded anyway (this could happen when an image was still in the browser's cache) by checking element.complete. If so, fire the callback function and add the attribute to it.
If .complete is not the case, add an onload event to them that also fires the callback once it is loaded.
// Observe the DOM for changes
observeDOM(document.body, function(){
checkNewMedia();
});
// Loop through all new media, add the event
var checkNewMedia = function() {
// extend this by using document.querySelectorAll("img:not([data-loaded), video:not([data-loaded])") etc.
var media = document.querySelectorAll('img:not([data-loaded]');
for(var i = 0; i < media.length; i++) {
addMediaLoadedEvent(media[i]);
}
}
// Fire the callback if complete, otherwise bind to onload
var addMediaLoadedEvent = function(element) {
if (element.complete) {
onMediaLoaded(element);
} else {
element.addEventListener('load', function(event) {
onMediaLoaded(event.target);
});
}
}
// The callback that is fired once an element is loaded
var onMediaLoaded = function(element) {
element.setAttribute('data-loaded', 'true');
adjustHeights(); // <-- your function
}
DEMO: fire event on each image load
If you only want to fire the event once all images are loaded, you could add an extra check that counts how many images are still not loaded:
// The callback that is fired once an image is loaded
var onMediaLoaded = function(element) {
element.setAttribute('data-loaded', 'true');
// only fire when there are no media elements without the 'data-loaded' attribute left
// again, can be extended to use video, etc.
if(document.querySelectorAll('img:not([data-loaded])').length === 0) {
adjustHeights(); // <-- your function
}
}
DEMO: fire event on all images loaded
For image and other sort of media, you should use "onload" event so that you can call adjust height after that.
Example:
<img src="someimage.png" onload="loadImage()" >
<script>
function loadImage() {
// code to adjust heights
}
</script>
Here is the standard version:
var img = document.querySelector('img')
function loaded() {
alert('loaded');
// do something to adjust height
}
if (img.complete) {
loaded()
} else {
img.addEventListener('load', loaded)
img.addEventListener('error', function() {
alert('error')
})
}
We have a print functionality in our application where we are printing images in the browser. We are dynamically forming the HTML div with all the image sources [image source is from the webservice url]
When we trigger 'Windows.Print()' , only the first image is always available in print preview (chrome) and remaining images are displayed blank.
If i trigger the print event for the second time, all the images are getting printed without any issue because all the images are cached by that time.
Please let me know how to push all my images in cache before printing. I need to do this in javascript. Dont want to make any html change.
I am using backbone.js and creating a model view with the images. Then Binding the view in HTML. Then i ma using for printing. This works fine in IE and Safari. but not in chrome, it shows print preview screen and always trying to load all the images from browser cache. But i will not be having those images in the browser while giving printing. All my images sources are dynamic and coming from the service. I am just setting the url dynamically to the image source.
<%_.each( Documents, function(oDocument) {%>
<div class="images span1">
<img src="<%- oDocument.URL%>" width="98" height="70" />
</div>
<% });%>
in print preview only one image is coming rest all coming as dots. if i cancel the print and give print again all are coming fine.
Thanks,
Jeevitha
This can be done purely in JavaScript by using the Image object.
var cachedImage = new Image();
cachedImage.addEventListener('load', function () {
alert('Cached image loaded');
});
cachedImage.src = 'http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png';
I have created a working JSFIDDLE example showing this at http://jsfiddle.net/pwdst/wc1zrL0v/
The new images could be created in response to a user event, for example clicking on a button, or even scrolling past a certain position. If the image from the server has the proper cache headers, it will then be retained in the browser cache for later use in your print page.
You will be able to see the request in the "Network" tab of the Chrome dev tools, or by using the excellent Fiddler tool from Telerik. Successful load will also trigger the load event listener added in the code sample.
I have called the custom function with the array of images i want to cache. Used Jquery 'Deffered' to hold the next operation until all the images are loaded. This is working very fine
var $deferredimages = $.Deferred();
var items = []; // load all the images paths
PreloadImages(items, loadImageitem, function (){
$deferredimages.resolve();
})
function PreloadImages(items, preloadimages, allDone) {
var count = items.length;
// this callback counts down the things to do.
var pendingimages = function (items, i) {
count--;
if (0 == count) {
allDone(items);
}
};
for (var i = 0; i < items.length; i++) {
// 'do' each thing, and await callback.
preloadimages(items, i, pendingimages);
}
}
function loadImageitem(items, i, onComplete) {
var onLoad = function (e) {
e.target.removeEventListener("load", onLoad);
// this next line can be removed.
// only here to prove the image was loaded.
document.body.appendChild(e.target);
// notify that we're done.
onComplete(items, i);
}
var img = new Image();
img.addEventListener("load", onLoad, false);
img.src = items[i];
img.style.visibility = 'hidden';
}
Reference http://jsfiddle.net/8baGb/1/
I want to do some interface fixes after all images are loaded (need the heights of the elements that hold images and use them to change the heights of other elements) I attach load event to all images but my load function is executed only once. I've try to use only jQuery:
$(function() {
var $img = $('img');
var length = $img.length;
var count = 0;
function load() {
console.log(++count + ' == ' + length);
if (count == length) {
// all images loaded
}
}
$img.load(load).error(load);
});
I also try to use onload and onerror events:
$img.each(function() {
this.onload = load;
this.onerror = load;
});
but when page is loaded I've got just one log:
1 == 33
(I'm testing in Chromium on Xubuntu with Dev Tools and cache disabled)
What I've doing wrong here? How to execute code after all images are loaded?
Sounds like you should be handling on the window's load event:
$( window ).load(function() {
// Glorious code!!
}
From the docs: "Run a function when the page is fully loaded including graphics."
http://api.jquery.com/load-event/
Execute the function when the page has finished loading
$(window).load
That way all elements are in place and ready to be 'measured'
Hello Stack Overflow community, recently, I've been working on a quick image display using jQuery. It has a list of possible images that can be picked and displayed at random. The issue is, after the page has finished loading, jQuery ceases to detect image load errors for if the image is invalid.
My current method of finding and fixing errors is as follows:
$('img').error(function() {
$(this).attr('src',getImgUrl());
});
This, in normal circumstances such as the page being loaded, picks a valid image, even if multiple invalid images are specified in a row. However, after the page is finished loading, if an invalid image is picked, and fails to load, this function is not even called. Strangely enough though, if I add an onerror attribute to all images, they are always called from the onerror no matter if the page was freshly loaded or not, so why is jQuery having this issue? Any help is appreciated, thanks.
UPDATE:
It also appears this is happening to other jQuery functions as well, such as click.
UPDATE:
It would appear to be an issue with jQuery recognizing new elements on a page, such as newly created images.
UPDATE for those asking getImageUrl:
function getImgUrl()
{
var text = (Math.round(Math.random() * 3)).toString();
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for(var i=0; i < 4; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return '/' + text;
}
All this does is pick a random URL, which matches occasionally to an image on my web-server that has many many images.
It would appear that jQuery has issues recognizing new elements on the page, so the way I fixed this was instead of deleting and adding images to the page, I just edited the existing SRC of images when doing changes, which strangely enough, the jQuery error function responds perfectly to.
Here's the refresh function I ended up coming up with for all interested:
function refreshImages()
{
var images = 10;
for(var i = 0;i < images;i++)
{
var url = getImgUrl();
$('#thumb' + i).attr('src',url);
if(i == 0)
{
$('#fullimage').attr('src',url);
$('.thumb').css('border','2px solid white');
}
}
resize();
}
Code example:
var img = $("img");
var n = img.length;
var i = 0;
function loadImg(i) {
if( i < n ) {
$(img[i]).load( function() {
console.log("img["+i+"] loaded");
i++;
loadImg(i);
});
} else {
console.log("img["+i+"] loaded");
return false;
}
}
loadImg(0);
This code works, but when image already in a browser cache - jQuery.load is not firing.
How can I check to see if the picture is in a browser cache and forcibly fire jQuery.load?
Thanks.
Paul Irish has written a neat little plugin for that. It does exactly what you want, including images loaded from cache:
https://github.com/paulirish/jquery.imgloaded
I've updated your fiddle with the above plugin included. This should answer your question:
http://jsbin.com/acuhaf/9/edit
The jQuery documentation says:
Caveats of the load event when used with images
A common challenge developers attempt to solve using the .load() shortcut is to execute a function when an image (or collection of images) have completely loaded.
There are several known caveats with this that should be noted.
These are:
- It doesn't work consistently nor reliably cross-browser
- It doesn't fire correctly in WebKit if the image src is set to the same src as before
- It doesn't correctly bubble up the DOM tree
- Can cease to fire for images that already live in the browser's cache
You may want to use other library to preload images. I would recommend PreloadJS