Know offset of a div placed after lazy load images - javascript

I have a div wrapper in which lazy load images are present. Then I have a div below those images and I want to make it Sticky.
<div id="someWrapper">
<img class="lazy" data-original="someImageURL"></img>
<img class="lazy" data-original="someImageURL"></img>
<img class="lazy" data-original="someImageURL"></img>
<img class="lazy" data-original="someImageURL"></img>
<div class="sticky">SomeContents</div> <!-- want to make this sticky on scrool -->
</div>
In order to make them sticky I need offset of the div. Problem is offset is not fixed on the page because of lazy load images that keep pushing the div downward. Image heights are unknown. No of images are 4. Tried using appear event on the last load element but its not giving me accurate results. Please help me how to solve this problem. I want to get offset of the sticky div so I can make a check on the scroll event.

After playing around and some research achieved the desired like this:
function activateStickyScrollEvent(offSetValue){
//code to activate scroll event
}
var lazyLength=$('#someWrapper lazy').length;
var lazyCount=0;
$('#someWrapper lazy').one('appear',function(){
++lazyCount;
if(lazyCount===lazyLength){
var getWrapperOffset=$('#someWrapper').offSet().top;
activateStickyScrollEvent(getWrapperOffset);
})

So, as I said, you may have to check if the last image in the set has been loaded, and then check for the element's offset. Here is a demo of how it could be done. Feel free to adapt the code to suit your needs.
//Ref to the wrapper
var $wrapper = $("#someWrapper");
//Ref to the last image in the set
var lastImgSrc = $wrapper.find(" > img:last").attr("data-original");
var image = new Image();
image.onload = function () {
//do something on load...
var offset = $wrapper.find(".sticky").offset();
alert (offset.top);
}
image.onerror = function () {
//do something on error...
}
image.src = lastImgSrc;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="someWrapper">
<img class="lazy" data-original="someImageURL" />
<img class="lazy" data-original="someImageURL" />
<img class="lazy" data-original="http://dreamatico.com/data_images/sea/sea-4.jpg" src="http://dreamatico.com/data_images/sea/sea-4.jpg" width="100%" />
<img class="lazy" data-original="http://dreamatico.com/data_images/sea/sea-3.jpg" src="http://dreamatico.com/data_images/sea/sea-3.jpg" width="100%" />
<div class="sticky">SomeContents</div> <!-- want to make this sticky on scrool -->
</div>
Hope that helps.

You can count images to load, and the get the offset (OFFSET in my example) :
$(function() {
function imageLoaded() {
counter--;
if( counter === 0 ) {
// Here All your "lazy" images are loaded
var OFFSET = $('#someWrapper').offset().top; <---- you can get offset
}
}
var images = $('.lazy'),
counter = images.length; // initialize the counter
images.each(function() {
if( this.complete ) {
imageLoaded.call( this );
} else {
$(this).one('load', imageLoaded);
}
});
});

Related

How to use JS to get HTML img height and set it as a variable?

In the following snippet, I'm trying to get the height of any image nested inside a particular class. Once that image height is gathered, I need to store it in a variable to be used elsewhere.
The two issues I'm running into are:
The second image is coming back as 0px
Storing the dynamic image height result as a variable
let getImgHeight = (()=> {
let images = document.querySelectorAll('.wistia img');
images.forEach(image => console.log(`${image.clientHeight}px`));
})();
<div class="wistia">
<img src="https://media.moddb.com/images/members/5/4550/4549205/duck.jpg" alt="">
<img src="https://www.thedesignwork.com/wp-content/uploads/2011/10/Random-Pictures-of-Conceptual-and-Creative-Ideas-02.jpg" alt="">
</div>
You get zero because you check the image height before it was loaded. You can easily check it if you wrap your function in some long timeout.
The better approach is to wait for all the loading images (ignoring ones that are already loaded) and after that get their height.
Here is an example below:
let getImgHeight = (()=> {
let images = document.querySelectorAll('.wistia img');
Promise.all(Array.from(images)
.filter(img => !img.complete)
.map(img => new Promise(resolve => {
img.onload = img.onerror = resolve; })
)
).then(() => {
images.forEach(image => console.log(`${image.clientHeight}px`));
});
})();
<div class="wistia">
<img src="https://media.moddb.com/images/members/5/4550/4549205/duck.jpg" alt="">
<img src="https://www.thedesignwork.com/wp-content/uploads/2011/10/Random-Pictures-of-Conceptual-and-Creative-Ideas-02.jpg" alt="">
</div>
UPDATE 1
As long as you want
to set the height of the parent container
I'd suggest rewriting your code as follows:
const images = document.querySelectorAll('.wistia img');
for (const image of Array.from(images)) {
if (image.complete) {
image.parentElement.style.height = image.clientHeight + 'px';
} else {
image.onload = () => {
image.parentElement.style.height = image.clientHeight + 'px';
}
}
}
<div class="wistia">
<img src="https://media.moddb.com/images/members/5/4550/4549205/duck.jpg" alt="">
</div>
The issue is most likely that you're trying to get the height of an image that hasn't finished loading. The best way to deal with that is to use the load event listener. You can then store the height as a data-attribute which is one way of making it a dynamic variable.
document.addEventListener('DOMContentLoaded', () => {
let images = document.querySelectorAll('.wistia img');
images.forEach(image => {
image.addEventListener('load', e => {
e.target.setAttribute('data-height', `${image.clientHeight}px`)
console.log(`${e.target.clientHeight}px`);
if (document.querySelectorAll('.wistia img[data-height]').length === images.length) {
console.log("ALL IMAGES LOADED");
}
});
});
});
<div class="wistia">
<img src="https://media.moddb.com/images/members/5/4550/4549205/duck.jpg" alt="">
<img src="https://www.thedesignwork.com/wp-content/uploads/2011/10/Random-Pictures-of-Conceptual-and-Creative-Ideas-02.jpg" alt="">
</div>
I tried your code in JSFiddle and it worked as expected. Check the version of jQuery you're using.

Wait for image to load plugin not functioning

I'm using the plugin from https://github.com/alexanderdickson/waitForImages to detect when is the image loaded.
Below is my code:
$('.marquee').waitForImages(function() {
console.log('All images have loaded.');
setTimeout(startMarquee);
}, function(loaded, count, success) {
console.log(loaded + ' of ' + count +
' images has ' + (success ? 'loaded' : 'failed to load') + '.');
$(this).addClass('loaded');
});
I will start a marquee scrolling of images when the images is loaded complete.
My problem is, some images had not yet load but just show a small empty square box like this:
,
the plugin also consider it already load. Any idea how to fix it?
Does showing a small empty square box only is consider image loaded?
Just write your own.
<marquee id="marquee" style="visiblity:hidden">
<img src="image1.jpg" onload="countMe(this,1)" onerror="countMe(this,0)"/>
<img src="image1.jpg" onload="countMe(this,1)" onerror="countMe(this,0)"/>
<img src="image1.jpg" onload="countMe(this,1)" onerror="countMe(this,0)"/>
</marquee>
<script>
var imageCount = 0, nofImages=$("#marquee img");
function countMe(img,success) {
if (!success) $(img).hide();
imageCount++;
if (imageCount == nofImages) $("#marquee").show();
}
</script>
If you want to give the image a chance and not load the marquee if permanent error you can try
<marquee id="marquee" style="visiblity:hidden">
<img src="image1.jpg" onload="countMe(this)" onerror="reloadMe(this)"/>
<img src="image2.jpg" onload="countMe(this)" onerror="reloadMe(this)"/>
<img src="image3.jpg" onload="countMe(this)" onerror="reloadMe(this)"/>
</marquee>
<script>
var imageCount = 0, nofImages=$("#marquee img");
function countMe(img) {
imageCount++;
if (imageCount == nofImages) $("#marquee").show();
}
function reloadMe(img) {
var tries = img.getAttribute("tries")?parseInt(img.getAttribute("tries"),10):1;
if (tries) == 3) return; // stop it
tries++;
img.setAttribute("tries",tries);
img.src=img.src;
}
</script>
If you want to wait till all page images loaded before running your marquee code you can use:
$(window).on("load", function() {
// all page html and images loaded
});
More details can be found in this questions:
Official way to ask jQuery wait for all images to load before executing something

Is it possible to clone an image after load in other parts of the page without loading?

I'm faced with a simple problem. Let says my user load around 150 images through a simple <img data-image='1' src="myimg1.jpg"> <img data-image=2' src="myimg2.jpg"> .. etc
When the user hovers over one of he images.I wish to display this myimg-thisimage.jpg in a small menu at the bottom of the screen. As of now, I'm changing the src attribute in my menu as:
$('#info-poster').attr("src","myimage-thisimage.jpg");
Note: myimage-thisimage.jpg is the current hovered over image.
But, when I do this. The browser is reloading the image (because, there is a small delay). Is there any way to bypass this loading since the user has already loaded the image using a clever way of cloning a DOM element maybe?
PS: The browser image cache is enabled. Therefore, the cache isnt the problem.
Edit: I know one way is to create 300 image elements and hide the other 150 of them. But in a scenario (definitely possible) where there are close to 500 images I would have to create around 1000 DOM elements which would be a big performance issue.
You can use a canvas element to show the thumbnail, this way the image is copied and scaled locally. In the following snippet I added two canvas, in the first one the image is scaled while keeping the aspect ratio (I use the Letterboxing and Pillarboxing techniques when required); in the second one the image is stretched. I also added another image at the bottom which is ignored, as it doesn't have the data-image attribute.
Is important not to use the scaling algorithm of drawImage as it produces unsmooth results when you reduce the image a lot. To achieve this, set the logical size of the canvas to match the natural size of the image. Then copy the image to the canvas by calling the drawImage method. Finally set the display size of the canvas to the desired one. This way the browser uses a better algorithm to scale the image.
Here are some outstanding quotes from the specification of the drawImage() method:
You can be sure the image will not be reloaded, and that you have to use the natural size of the image to avoid scaling with drawImage:
If the original image data is a bitmap image, the value painted at a point in the destination rectangle is computed by filtering the original image data.
The browser decides which scaling algorithm to use. At the moment of writing this: Edge, Chrome and Firefox don't use nothing better than the bilinear or nearest-neighbor algorithms. This may change in the future:
The user agent may use any filtering algorithm (for example bilinear interpolation or nearest-neighbor).
function initCanvas(id,image,naturalWidth,naturalHeight){
var canvas = document.getElementById(id);
var ctx = canvas.getContext("2d");
// Set the logical size of the canvas to match the
// natural size of the image, this way we don't use
// the scaling algorithm of drawImage (It isn't good
// for reducing big images as it produces unsmooth results).
$(canvas).attr("width",naturalWidth) ;
$(canvas).attr("height",naturalHeight) ;
// Copy the image:
ctx.drawImage(image,0,0,naturalWidth,naturalHeight);
return canvas ;
}
function clearCanvas(id){
var canvas = document.getElementById(id);
var ctx = canvas.getContext("2d");
ctx.clearRect(0,0,canvas.width,canvas.height);
}
$(window).on("load", function( ){
var images = $("img").filter(function(){
var dataImage = $(this).data("image") ;
if( typeof dataImage != "number" ) return false ;
var number = parseInt(dataImage,10) ;
return number > 0 && dataImage === number ;
}) ;
images.on("mouseenter", function( ){
var naturalWidth = $(this).prop("naturalWidth") ;
var naturalHeight = $(this).prop("naturalHeight") ;
// Scaled thumbnail:
// Copy the image to canvas-scaled and get a reference to it:
var scaledCanvas = initCanvas("canvas-scaled",this,naturalWidth,naturalHeight);
// Calculate the display size of the canvas:
var hwfactor = naturalHeight/naturalWidth ;
var whfactor = naturalWidth/naturalHeight ;
var scaledWidth, scaledHeight ;
if( hwfactor >= 1 ){ // Pillarboxing
scaledHeight = "100px" ;
scaledWidth = (100*whfactor)+"px" ;
}
else{ // Letterboxing
scaledWidth = "100px" ;
scaledHeight = (100*hwfactor)+"px" ;
}
// Now we change the display size of the canvas.
// A better scaling algorithm will be used.
$(scaledCanvas).css("width",scaledWidth);
$(scaledCanvas).css("height",scaledHeight);
// Stretched thumbnail:
// Copy the image to canvas-stretched. The display size
// of canvas-stretched is already set in the style section.
initCanvas("canvas-stretched",this,naturalWidth,naturalHeight);
});
images.on("mouseleave", function( ){
clearCanvas("canvas-scaled");
clearCanvas("canvas-stretched");
});
});
body{
background: #000;
}
.wrapper img{
width: 100px ;
height: auto ;
}
#banner{
display: block ;
width: 100% ;
height: 40px ;
padding-top: 1pt ;
}
#canvas-stretched{
width: 100px ;
height: 100px ;
}
.canvas-wrapper{
display: -webkit-inline-flex ;
display: inline-flex ;
-webkit-justify-content: space-around ;
justify-content: space-around ;
-webkit-align-items: center ;
align-items: center ;
vertical-align: bottom ;
border: 1px solid #888 ;
width: 100px ;
height: 100px ;
overflow: hidden ;
}
.viewer{
display: inline-block ;
}
.viewer span{
color: #ddd ;
font-family: sans-serif ;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<span class="wrapper">
<img data-image="1" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/550px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg"/>
<img data-image="2" src="https://upload.wikimedia.org/wikipedia/en/8/81/Megadrive_another_world.png"/>
<img data-image="3" src="https://upload.wikimedia.org/wikipedia/en/e/ee/TheKlingonHamlet.jpg"/>
</span>
<span class="viewer">
<span>scaled</span><br>
<div class="canvas-wrapper">
<canvas id="canvas-scaled"></canvas>
</div>
</span>
<span class="viewer">
<span>stretched</span><br>
<div class="canvas-wrapper">
<canvas id="canvas-stretched"></canvas>
</div>
</span>
<img id="banner" src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/The_southern_plane_of_the_Milky_Way_from_the_ATLASGAL_survey.jpg/320px-The_southern_plane_of_the_Milky_Way_from_the_ATLASGAL_survey.jpg"/>
This line is the problem:
$('#info-poster').attr("src","myimage-thisimage.jpg");
The browser is reloading the image because you reasign(bad practice) the "src" attribute.
Instead, you can use CSS options to display/hide "myimage-thisimage.jpg".
Since you use jQuery, we can make use of the methods: hide/show.
You mentioned "clone", I don't think you mean HTML elements clonning.
Example: (live on JS Bin)
<img id="dummy" width="200" height="150" data-image='1' src="http://europunkt.ro/wp-content/uploads/2016/06/romania.jpg">
<!-- Hidden by default -->
<img style="display:none" id="info-poster" width="200" height="150">
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script>
var $dummy = $("#dummy");
var $infoPoster = $("#info-poster");
var infoPosterHasLoaded = false;
$dummy.on("mouseenter", function() {
// add the src attribute ONLY once
if(infoPosterHasLoaded === false){
$infoPoster.attr("src", "http://www.ilovemaramures.com/wp-content/uploads/2012/05/Pasul-Prislop.jpg")
infoPosterHasLoaded = true;
}
$infoPoster.show();
});
$dummy.on("mouseleave", function() {
$infoPoster.hide();
});
</script>
For a more fancy "hide/show" you can check jQuery Effects.
Edit - after I read your comment
In case you want to use the "data-image" attribute from the hovered element, check these objects: event.target, event.currentTarget, this
New JS Bin version.
I believe that what you are wanting is possible with the jQuery .clone() and .append() function. See the example below.
jQuery.clone()
jQuery.append()
$(function() {
$('img#ToClone').click(function(){
var imageClone = $('#ToClone').clone();
var cloneDestination = $('#CloneTo');
cloneDestination.append(imageClone);
});
});
div
{
padding:2px;
background:blue;
}
div#CloneTo
{
background:green;
}
img{
height:50px;
width:50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<p>Click on the red square to clone it below.</p>
<img id="ToClone" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGlSURBVHhe7dCxTQQAEMRACiGk/86o4UmMxEpY/KW8R5ddtH575GnFOijWQbEOinVQrINiHRTroFgHxTr4Pdbbq2K/KNZgvyjWYL8o1mC/KNZgv3gq1uf7x389Fn5jvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgvyjWYL8o1mC/KNZgv3gq1utgvyjWYL8o1mC/KNZgvyjWYL/4452finVQrINiHRTroFgHxToo1kGxDor1tMfjC8KHtIEDA9XCAAAAAElFTkSuQmCC" />
</div>
<div id="CloneTo">
<p>Clone should appear here.</p>
<!-- The cloned image should appear here. -->
</div>
You may convert the image requests at server to respond with base64 string which you can store in your own cache.
Sample code below:
HTML
<img id="image1Id" src="" />
<input type="button" onclick='javascript:loadSomeThing("image1", "", "image1Id");' value="Load Image1" />
Script
var imageArray = [];
function loadSomeThing(key, someUrl, elementId) {
var imageData = imageArray[key];
if (!imageData) {
imageData = ajaxGetImageData(someUrl);
imageArray[key] = imageData;
}
document.getElementById(elementId).src = imageData;
}
function ajaxGetImageData(url) {
//Code to get base64 image string
return "data:image/jpeg;base64,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";
}
Demo
jsFiddle
You should let the browser to do the cache handling.
I suggest you could have a <img id="info-poster" src="myimage-thisimage.jpg" class="hide-on-load"/>, so then if your browser want to load a new copy of the image, it would do it before the user mouse over your other images. (if it is a small/acceptable image that user may have to download it every page load)
Then you could simply bind $("img.bind-event").on("mouseenter", function() { $("#info-poster").show(); }); and $("img.bind-event").on("mouseleave", function() { $("#info-poster").hide(); });
IDEA
initial markup
<img data-src='myimg1.jpg' data-image='1' src='placeholder.jpg'>
after myimg1.jpg has loaded dynamically (*)
<img data-image='1' src='blob:asdfasdfasdfasdfadfa'>
Then on 'mouseenter'
infoPosterEl.src = thisImageEl.src
// update image src to an object url(e.g. "blob:") will not bother http comm.
(*)
// Fetch acutal image as blob
// Create object url for the blob
// Update this <img> src to the object url
You can store the path to each image in an array, iterate array using Array.prototype.forEach(), set the background of each <img> element using url("/path/to/image"); at mouseover of each <img> set background-size of menu element to 100% 100% at index of hovered <img> element within collection using Array.prototype.slice(), Array.prototype.splice(). The approach should request each image from server at most once, toggling the image displayed at menu element to correspond to hovered image.
var urls = ["http://placehold.it/100x100?text=1"
, "http://placehold.it/100x100?text=2"
, "http://placehold.it/100x100?text=3"
, "http://placehold.it/100x100?text=4"
, "http://placehold.it/100x100?text=5"]
, sources = []
, sizes = []
, imgs = document.querySelectorAll(".img")
, menu = document.querySelector(".menu");
function toggleImage(index) {
this.onmouseover = function() {
var curr = sizes.slice(0);
curr.splice(index, 1, "100% 100%");
menu.style.backgroundSize = curr.join(",");
}
}
urls.forEach(function(path, index) {
sources.push("url(" + path + ")");
sizes.push("0% 0%");
imgs[index].style.background = sources[index];
toggleImage.call(imgs[index], index);
});
menu.style.background = sources.join(",");
menu.style.backgroundSize = sizes.join(",");
.menu {
left: calc(100vw / 2 - 50px);
position: relative;
width: 75px;
height: 75px;
display: block;
}
<img class="img" width="100" height="100" src="" /><img class="img" width="100" height="100" /><img class="img" width="100" height="100" /><img class="img" width="100" height="100" /><img class="img" width="100" height="100" />
<div class="menu">
</div>

Imageflip on imagemap, but keep the map coordinates

I have a rather complex imagemap with several mapped areas.
Most of the mapped areas are just mapped for mouseovers and links. But some arease have a JS onClick() which results in an imageflip. The new, flipped image is basically the old image, with a few "new things" on it.
Two things need to happen which I cannot figure out:
The new image needs to stay there. What is happening no is that as soon as I move the mouse out of the mapped area, it flipps back to the old image.
I need the imagemap (of the "old" image) to work on the new image, which appears on the flip.
JAVASCRIPT
//PRELOAD IMAGES FOR CLICK AND MOUSEOVER
cuentaBoca = new Image(655, 338)
cuentaBoca.src = "imagenes_png/pag2/cuentame_bocadilla.png";
cuenta = new Image(655, 338)
cuenta.src = "imagenes_png/pag2/cuentame_h.png";
//JS FUNCTION FOR CLICK
function bocadillaC() {
document.getElementById('garfio').src = cuentaBoca.src;
}
//JS FUNCTION FOR MOUSEOVER
function cuentaH() {
document.getElementById('garfio').src = cuenta.src;
return true;
}
HTML
<!-- INSERT THE PICTURE -->
<img name="garfio" id="garfio" src="imagenes_png/pag2/base.png" width="655" height="338" border="0" usemap="#m_garfio" alt="" />
<!-- CREATE THE MAP -->
<map name="m_garfio" id="m_garfio">
<area shape="poly" id="bocadilla" coords="7,205,12,197,20,191,24,189,34,185,45,182,58,180,74,180,86,180,94,181,103,182,112,185,114,186,130,178,135,177,137,179,134,184,130,192,135,195,138,199,142,204,143,209,138,218,125,227,113,231,100,235,86,236,70,236,53,235,41,233,34,231,23,226,15,221,11,217,8,212,7,205"
onMouseOver="cuentaH()" onClick="bocadillaC(); return false" alt="" />
</map>
</div>
Here a Fiddel http://jsfiddle.net/emedrs9n/
Clicking on the "Cuentame" (balloon) has the onClick() effect
Try to redefine the original function on click. Example
function bocadillaC() {
cuentaH = original = bocadillaC;
// redefine other functions
leftH = function() {
document.getElementById('garfio').src = left_with_yellow_cloud.src;
};
rightH = function() {
document.getElementById('garfio').src = right_with_yellow_cloud.src;
};
cuentaH = function() {
document.getElementById('garfio').src = cuenta_with_yellow_cloud.src;
};
// ...
document.getElementById('garfio').src = cuentaBoca.src;
}
And you need to redefine other functions with images. But, for example, for this state there is no a similar image with yellow cloud.
But in fact you need to use power of HTML/CSS, don't draw image on each case and do it simpler without image map.
This does what you seem to ask. Two images are displayed. When I roll the mouse over the upper image, the lower image changes and does not change back. The images vane2.jpg and vane2.png are mirror images.
<html>
<head>
<script type="text/javascript">
function setimage () {
document.getElementById('hisArea').src = "vane2.png";
}
</script>
</head>
<body>
<img id="myArea" onMouseOver="setimage();" width="176" height="176" src="vane1.jpg">
<BR>
<img id="hisArea" width="176" height="176" src="vane2.jpg">
</body>
</html>

Use Javascript to load some images last

Hi I just wondered if this is possible. I have quite a few images on my website and I have made them as small file size as possible. Some of the images are used as a slideshow but there are all loaded in one go. Is there a way using javascript to make the slideshow images load last so that the background images etc load up first and the slideshow loads at the end.
The images are in the main body of the page and are "slideshowified" using javascript.
The code for this images is simple:
<div id="pics">
<img src="images/cs9.png" width="270px" height="270px" alt="teaching"/>
<img src="images/cs1.png" width="200px" height="200px" alt="teaching"/>
<img src="images/cs3.png" width="200" height="200px" alt="teaching"/>
<img src="images/cs5.png" width="200" height="200px" alt="teaching"/>
<img src="images/cs6.png" width="200" height="200px" alt="teaching"/>
<img src="images/cs7.png" width="200" height="200px" alt="teaching"/>
<img src="images/cs4.png" width="200" height="200px" alt="teaching"/>
<img src="images/cs12.png" width="200" height="200px" alt="teaching"/>
<img src="images/cs8.png" width="200" height="200px" alt="teaching"/>
<img src="images/cs10.png" width="200" height="200px" alt="teaching"/>
<img src="images/cs14.png" width="200" height="200px" alt="teaching"/>
</div>
Any idea would be great
Thanks
Edit - See the bottom of this answer, a much better idea came to me
Original Answer
Yes, totally possible. Others have noted plug-ins for doing this, which are great in that they come pre-tested and such, but if you want to do it yourself it's surprisingly easy. You add img elements to the DOM (document object model):
function addAnImage(targetId, src, width, height) {
var img;
img = document.createElement('img');
img.src = src;
img.style.width = width + "px";
img.style.height = height + "px";
target = document.getElementById(targetId);
target.appendChild(img);
}
(I couldn't immediately recall how to set the alt attribute; it may well be img.alt = "...";)
Naturally you'll want to add some error checking to that. :-) So for one of your images, you want to add them to the pics div, so for example:
addAnImage('pics', 'images/cs12.png', 200, 200);
Set up a function to add your images and call it when the page is loaded (either using window.onload or whatever support your JavaScript library, if any, has for doing things a bit earlier than that). For instance, your load script might look like this (I don't typically use window.onload, but it's convenient for an example):
function pageLoad() {
var images = [
{src: "images/cs9.png", width: 270, height: 270, alt: "teaching"},
{src: "images/cs1.png", width: 200, height: 200, alt: "teaching"},
{src: "images/cs3.png", width: 200, height: 200, alt: "teaching"},
// ..., make sure the last one *doesn't* have a comma at the end
];
var index;
// Kick start the load process
index = 0;
nextImageHandler();
// Load an image and schedule the next
function nextImageHandler() {
var imgdata;
imgdata = images[index];
addOneImage('pics', imgdata.src, imgdata.width, imgdata.height);
++index;
if (index < images.length) {
window.setTimeout(nextImagePlease, 200);
}
}
}
window.onload = pageLoad;
On window load, that will load the first image and then schedule the next one to be loaded 200ms (a fifth of a second) later. When that happens, it'll schedule the next, etc., etc., until it's loaded all of the images.
JavaScript libraries like jQuery, Prototype, Closure, etc. typically have various helper functions for this sort of thing.
Updated answer
The above is fine, but it means that you have to completely change how you layout your pages, and you have to intermix content stuff (the image sources and sizes) with your JavaScript, etc. Blech.
How 'bout this: Make all of your image tags that are the same size refer to the same image:
<div id="pics">
<img src="images/w270h270.png" width="270" height="270" alt="teaching"/>
<img src="images/w200h200.png" width="200" height="200" alt="teaching"/>
<img src="images/w200h200.png" width="200" height="200" alt="teaching"/>
...
These would be placeholders. Then, add data attributes to them with the real image source:
<div id="pics">
<img src="images/w270h270.png" data-src="cs9.png" width="270" height="270" alt="teaching"/>
<img src="images/w200h200.png" data-src="cs1.png" width="200" height="200" alt="teaching"/>
<img src="images/w200h200.png" data-src="cs3.png" width="200" height="200" alt="teaching"/>
...
Attributes in the form data-xyz will be valid as of HTML5 (and they work today, they just don't validate).
Now the magic: Once the main load is completed, you walk through the img tags in the DOM, updating their src to make their data-src attribute:
function pageLoad() {
var nodeList, index;
// Get a NodeList of all of the images on the page; will include
// both the images we want to update and those we don't
nodeList = document.body.getElementsByTagName('img');
// Kick-start the process
index = 0;
backgroundLoader();
// Our background loader
function backgroundLoader() {
var img, src;
// Note we check at the beginning of the function rather than
// the end when we're scheduling. That's because NodeLists are
// *live*, so they can change between invocations of our function.
// So avoid going past what is _now_ the end of the list.
// And yes, this means that if you remove images from
// the middle of the document while the load process is running,
// we may end up missing some. Don't do that, or account for it.
if (index >= nodeList.length) {
// we're done
return;
}
// Get this image
img = nodeList[index];
// Process it
src = img.getAttribute("data-src");
if (src) {
// It's one of our special ones
img.src = src;
img.removeAttribute("data-src");
}
// Schedule the next one
++index;
window.setTimeout(backgroundLoader, 200);
}
}
window.onload = pageLoad;
Again, you'll want to add error handling and that's completely untested, but fundamentally it should work.
You can use a jquery Lazy Load plugin
you can use a lazy loading script. A good example is (jquery):
http://www.appelsiini.net/projects/lazyload
In the window onload event, use document.createElement to create images, and element.appendChild to insert them where desired.
I think you could write a javascript that will insert some tags after the page is loaded. In this manner the slideshow won't interfer with main content load.
I think this is quite late (10 years later) 😂😂, but I wrote an adaptation of the first answer.
Assuming you have some images you want to be affected but the rest to load first like:
<!-- Load Earlier -->
<img src="linktoimg">
<!-- Load After DOM loaded -->
<img data-src="linktoimg">
If you noticed, the ones to load later, I used a data-src attribute to specify the src it should use.
Javascript
function pageLoad() {
var $imgList = document.body.getElementsByClassName('img-speed');
// Kick-start the process
var $i = 0;
imgLoader();
function imgLoader() {
var $img, $src;
if ($i >= $imgList.length) {
//Done
return;
}
// Get this image
$img = $imgList[$i];
$src = $img.getAttribute('data-src');
if ($src) {
// It's one of our special ones
$img.src = $src;
$img.removeAttribute('data-src');
}
// Schedule the next one
++$i;
window.setTimeout(imgLoader, 200);
}
}
window.onload = pageLoad;
Uses a bit of jquery though.

Categories

Resources