I put together an image preloader which works fine, but what doesn't work is updating the status after every image that has been loaded. Instead, all images are loaded and "done" (last line) is the only thing that shows up. It does work when I use an alert instead of the innerHTML command, but that is obviously of no use. What am I doing wrong?
<div id="preloader">
<span id="preloader_status"> </span>
<script language="JavaScript">
imageObj = new Image();
images = new Array();
images[0]="bigimage.gif"
images[1]="anotherbigimage.gif"
/* and so on */
var i = 0;
var o = (images.length);
for (i=0;i<o;i++) {
var status = (Math.round(100*(i/o)));
imageObj.src=images[i];
document.getElementById("preloader_status").innerHTML = status;
}
document.getElementById("preloader_status").innerHTML = "done";
</script>
</div>
To show image load progress, you will need to hook into the onload event for the images so you can track when their loading is actually complete. Images are loaded asychronously so assigning .src only STARTS the loading of the image. It is not completed until later when the onload handler is called. Because of that, your existing code will just immediately show "done" because it isn't tracking when the images are actually done loading.
In addition, you were successively assigning a new .src value to the same image object which is going to abort the previous image loading. You need to create a new image object for each new image you are loading.
You can fix your code like this:
<div id="preloader">
<span id="preloader_status"> </span>
<script language="JavaScript">
var imageSrcs = [
"bigimage.gif",
"anotherbigimage.gif"
/* and so on */
];
function preloadImages(list, statusID) {
var img, cnt = 0;
var progress = document.getElementById(statusID);
var preloads = [];
for (var i = 0; i < list.length; i++) {
img = new Image();
img.onload = function() {
++cnt;
var loadPercent = Math.round(100*(cnt/list.length));
progress.innerHTML = loadPercent;
if (cnt == list.length) {
progress.innerHTML = "done";
}
}
img.src = list[i];
preloads.push(img);
}
}
preloadImages(imageSrcs, "preloader_status");
</script>
</div>
The for loop will happen almost instantly, because images load asynchronously; setting imageObj.src will just start the image request and move on to the next. It will not block the execution of the loop. This will cause the effect you're seeing, i.e the last line of the code is executed straight away.
I think what you're looking for is the JavaScript Image onload event, which will fire when an image has finished loading.
var image = new Image();
image.onload = function() {
// always called
alert('image loaded');
};
image.src = 'image.jpg';
Code was pinched from this article.
Related
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.
I have a masonry grid where the images are black and white and when you hover over them, the color images appear. They are not composite images. They are all separate. (I'm just sorting out bugs for someone else's code)
On initial hover after a fresh page load, there is a delay (and grey overlay) when hovering over. After the initial, it's of course instantaneous when it switches to the color photo.
So what I'm trying to do is pre load the images with some javascript, but I'm having trouble doing this. Below is what I have for code. Also, this is in Wordpress. Not sure if that matters.
All of the images are background images too, not hardcoded into the html. It's all background css. Thanks for any help!
<script language="JavaScript">
$('document').ready(function preloader() {
// counter
var i = 0;
// create object
imageObj = new Image();
// set image list
images = new Array();
images[0]="images/treatment_locations.jpg"
images[1]="images/community_news_events.jpg"
images[2]="images/success_stories.jpg"
images[3]="images/self_assessment.jpg"
images[4]="images/our_associates.jpg"
images[5]="images/treatment_programs.jpg"
images[6]="images/patient_portal.jpg"
images[7]="images/FAQ.jpg"
images[8]="images/what_to_expect.jpg"
// start preloading
for(i=0; i<=8; i++)
{
imageObj.src=images[i];
}
});
</script>
If you overwrite the src in each iteration, you're not giving the browser a chance to fetch the image. You probably only preload the last image.
Try:
var imageObjs = [];
$('document').ready(function preloader() {
// counter
var i = 0;
// set image list
images = new Array();
images[0]="images/treatment_locations.jpg"
images[1]="images/community_news_events.jpg"
images[2]="images/success_stories.jpg"
images[3]="images/self_assessment.jpg"
images[4]="images/our_associates.jpg"
images[5]="images/treatment_programs.jpg"
images[6]="images/patient_portal.jpg"
images[7]="images/FAQ.jpg"
images[8]="images/what_to_expect.jpg"
// start preloading
for(i=0; i<=8; i++)
{
var imageObj = new Image();
imageObj.src=images[i];
imageObjs.push(imageObj);
}
});
That's another aproach, where it stores only the images that were successfully loaded.
var imgObjs = [];
$(document).ready(function preloader() {
// images list
var images = [
'treatment_locations.jpg',
'community_news_events.jpg',
'success_stories.jpg',
'self_assessment.jpg',
'our_associates.jpg',
'treatment_programs.jpg',
'patient_portal.jpg',
'FAQ.jpg',
'what_to_expect.jpg'
];
for (var i in images) {
var img = new Image();
img.src = 'images/' + images[i];
// stores it on array after loading
img.onload = function() {
imgObjs.push(this);
};
}
});
I am draw background on canvas and also small images on that background. But sometimes, background draw on small images. Why ?
JavaScript code -
var canvasupdate = document.getElementById("myCanvas");
ctxupdate = canvasupdate.getContext("2d");
var background = new Image();
background.src = sitePath + "ATOM/chapter1/book/" + `bgimagename`;
background.onload = function() {
ctxupdate.drawImage(background, 0, 0); // set background image
};
var imageobj = new Array();
for (var d = 0; d < calloutImageArray.length; d++) // getting small images in array
{
imageobj[d] = new Image();
(function(d) {
imageobj[d].src = sitePath + "ATOM/chapter1/book/" + calloutImageArray[d];
imageobj[d].onload = function() {
ctxupdate.drawImage(imageobj[d], calloutImageArrayX[d], calloutImageArrayY[d], calloutImageArrayW[d], calloutImageArrayH[d]);
};
})(d);
}
In above code, background image code should be execute first then call out image(small image) code execute but some time execute small images code and then background image code why?
All the images are loaded asynchronously. So sometimes the small images are loaded (and drawn) before the background image. Please take a look into e.g. Network tab in Chrome in which order the resources load is done.
The simplest solution for this problem is to move the loading of small images into the callback function for load event of the background image.
The onLoad function runs asynchronously. That means JavaScript will continue to run the rest of your code and will run the callback function when the background image is loaded. That's why your second part of the code runs first. So instead try to add your code inside the onload function like this:
var canvasupdate = document.getElementById("myCanvas");
ctxupdate = canvasupdate.getContext("2d");
var background = new Image();
background.src = sitePath + "ATOM/chapter1/book/" + `bgimagename`;
background.onload = function() {
ctxupdate.drawImage(background, 0, 0); // set background image
var imageobj = new Array();
for (var d = 0; d < calloutImageArray.length; d++) // getting small images in array
{
imageobj[d] = new Image();
(function(d) {
imageobj[d].src = sitePath + "ATOM/chapter1/book/" + calloutImageArray[d];
imageobj[d].onload = function() {
ctxupdate.drawImage(imageobj[d], calloutImageArrayX[d], calloutImageArrayY[d], calloutImageArrayW[d], calloutImageArrayH[d]);
};
})(d);
}
};
that way you can be sure that the background will be set first and then your small images. Note that I didn't try your code to check if it does what you want, I just rearranged the code blocks to show you the logic and why does not run as you would expect.
Hope it helps
I'm trying to give the user a preview of how an image will look when combined with another image before they upload the image (think gun shooting a bullet). I can get the image to load into an image element, but then the onload event doesn't fire (tested in chrome and firefox). I've tried using setTimeout as a dirty hack, but unfortunately bullet.image.height does not appear to be set within a relatively short space of time.
Here is an example of what I'm trying to do:
if (input.target.files && input.target.files[0]) {
var file = new FileReader();
file.onload = function (event) {
// this part works fine
var bullet = {};
bullet.id = 0;
bullet.image = new Image();
bullet.image.onload = function () {
// This never fires
bullet.offset_y = bullet.image.height / 2;
$('#modal-weapons-field-bullet').append('<option value="0">' + bullet.title + '</option>');
$('#modal-weapons-field-bullet').val(0);
};
bullet.src = event.target.result;
bullet.offset_x = 0;
bullet.title = input.target.files[0].name;
}
file.readAsDataURL(input.target.files[0]);
}
bullet.src should be bullet.image.src
This code is meant for a real estate website I am updating for my company. Basically, There is a table with the property name, address, etc, and an image. Originally, I was coding this website in ASP.net switch over to regular Javascript for a few reasons (hosting overhead etc).
Sections of this code are from a few different tutorials out there, one of which is an ASP.net modal div image "enlarger" tutorial, which is sort of the basis combined with a few other sites. I have yet to comment in their names etc, but I plan on giving them credit in the code. Thier links are below before I post my code.
http://archive.aspsnippets.com/post/2009/07/06/Image-Gallery-using-ASPNet-GridView-control.aspx
My code is essentially as follows (I will trim the fat and excess line breaks in the style section):
First are the modal style tags from that tutorial by Mudassar Khan (partially relevant):
<style>
body {margin:0;padding:0;height:100%;}
.modal {display: none;position: absolute;top: 0px;left: 0px;background-color:black;z-index:100;opacity: 0.8; filter: alpha(opacity=60);-moz-opacity:0.8;min-height: 100%;}
&#divImage{display: none;z-index: 1000;position: fixed;top: 0;left: 0;background-color:White;height: 550px;width: 600px;padding: 3px;border: solid 1px black;}
<style>
Then comes his script, which I may have tweaked here and there:
<script type="text/javascript">
function LoadDiv(url) {
var img = new Image();
var bcgDiv = document.getElementById("divBackground");
var imgDiv = document.getElementById("divImage");
var imgFull = document.getElementById("imgFull");
var imgLoader = document.getElementById("imgLoader");
img.src = url;
var tcopy = img.src.slice(0,(img.src.length-4)) + "_big.png";
img.src = tcopy;
img.onload = function () {
imgFull.src = tcopy
imgFull.style.display = "block";
imgLoader.style.display = "none";
};
var width = document.body.clientWidth;
if (document.body.clientHeight > document.body.scrollHeight) {
bcgDiv.style.height = document.body.clientHeight + "px";
}
else {
bcgDiv.style.height = document.body.scrollHeight + "px";
}
imgDiv.style.left = (width - 650) / 2 + "px";
imgDiv.style.top = "20px";
bcgDiv.style.width = "100%";
bcgDiv.style.display = "block";
imgDiv.style.display = "block";
return false;
}
function HideDiv() {
var bcgDiv = document.getElementById("divBackground");
var imgDiv = document.getElementById("divImage");
var imgFull = document.getElementById("imgFull");
imgLoader.style.display = "block"; // I added as it seems to bring back the loader gif
if (bcgDiv != null) {
bcgDiv.style.display = "none";
imgDiv.style.display = "none";
imgFull.style.display = "none";
}
}
</script>
Now All this above script gets called upon a onClick Event Handler on an image of each of the real estate companies properties. This will work well to both preload images with the little animated gif and the close button works fine. It works on more than one image, BUT if the image is already preloaded, I cant think of a way to force the redisplay of an already preloaded image if a user clicks on the photo, then clicks close to hide the div tag and then clicks on the same preloaded image.
That event handler looks like this:
img onClick="return LoadDiv(this.src);" src="http://www.ourcompany.com/images/prop_thumbs/Some_plaza.png" style="min-width:200 px;max-height:150 px;max-width:200 px;"
I thought global booleans would work, but then I realized, theres no telling which and what is preloaded, so the boolean might not help if you can't pass something meaningful back and forth.
I'm not asking any one to do my work for me, however I would appreciate suggestions in the right direction.
Regards and TIA!
You could make a array of all of the images with key values of loaded. For instance.
image_list = {image1:false,image2:true,image3:false};
true and false being loaded or not loaded. When an image is clicked just update the array.
image_list[image1] = true;
Did this really quick, so my syntax might be off, feel free to correct me or berate me...
Yay!!! Figured it out with the help of both jhanifen and the guy who did the tutorial I used (he actually emailed me). My code is below (its an excerpt, but you'll get the idea):
images = new Array(30);
//need to define each image to be in array
images[0]="website/images/prop_thumbs/property1_big.png";
images[1]="website/images/prop_thumbs/property2_big.png";
images[2]="website/images/prop_thumbs/property3_big.png";
//This continues for some time
imagesLoaded = new Array(30);
// per stack overflow person suggestion make array of bool values; initialize them all to false on page load
function onLoadScript() {
for (i = 0; i < imagesLoaded.length; ++ i)
{
imagesLoaded [i] = false;
}
}
// the above is called onLoad in body tag
// Changes the script for Loading the Div tag are below:
function LoadDiv(imgNum) {
var img = new Image();
var bcgDiv = document.getElementById("divBackground");
var imgDiv = document.getElementById("divImage");
var imgFull = document.getElementById("imgFull");
var imgLoader = document.getElementById("imgLoader");
img.src = images[imgNum];
if(imagesLoaded[imgNum] = true)
{ // this statement triggers same as onload below!
imgFull.src = img.src
imgFull.style.display = "block";
imgLoader.style.display = "none";
}
img.onload = function () {
imgFull.src = img.src
imgFull.style.display = "block";
imgLoader.style.display = "none";
imagesLoaded[imgNum] = true;
};
The rest of the document is the same except I changed the onClick event handler for the property images to LoadDiv(and some sequential number);
Thanks to all for your help! Particular props to both Mudassar Khan and jhanifen!