I am trying to show a large image when clicking on a small image. I have a SQL table in which I store the image, then I display this image in an img control. Now I want this image to open in a bigger size popup, when the user clicks on it.
My code to the retrieve the image from the database and display it in img control is:
<script type="text/javascript">
$('#image1Large').hide().click(function() {
$(this).hide();
});
$('#image1').click(function() {
$('#image1Large').attr('src', this.src)
.show()
.offset({ top: 0, left: 0 });
});
</script>
<img runat="server" id="image1" alt="" src="" height="100" width="100"/>
<img runat="server" id="image1Large" alt=""/>
protected void LoadImage1()
{
SqlCommand cmd = new SqlCommand("sps_getimage", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#flag", 1);
cmd.Parameters.AddWithValue("#ad_id", ad_id);
con.Open();
SqlDataReader reader = cmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess);
if (reader.HasRows)
{
reader.Read();
MemoryStream memory = new MemoryStream();
long startIndex = 0;
const int ChunkSize = 256;
while (true)
{
byte[] buffer = new byte[ChunkSize];
long retrievedBytes = reader.GetBytes(0, startIndex, buffer, 0, ChunkSize);
memory.Write(buffer, 0, (int)retrievedBytes);
startIndex += retrievedBytes;
if (retrievedBytes != ChunkSize)
break;
}
byte[] data = memory.ToArray();
img1 = data;
memory.Dispose();
image1.Src = "data:image/png;base64," + Convert.ToBase64String(data);
}
con.Close();
}
This isn't really a C# or SQL problem, but rather client-side. Since you already retrieved the image and only resizing it via height="100" width="100" attributes, all you have to do is display the same image in its original size. There're many ways to do this, here is a basic one:
Add another image element to hold larger image:
<img runat="server" id="image1" alt="" src="" height="100" width="100"/>
<img runat="server" id="image1Large" />
And add this code to initially hide the larger image and show it on click:
$('#image1Large').hide().click(function(){
$(this).hide();
})
$('#image1').click(function(){
$('#image1Large').attr('src', this.src)
.show()
.offset({top:0,left:0});
})
Here is a demo: http://jsfiddle.net/QH5a8/
In a real-life scenario, you will need to adjust this (perhaps additional formatting and positioning of larger image, maybe showing it inside of a DIV container etc.) but that's the idea.
Related
I have built a page that pulls in multiple images from various webcams that we use the office to monitor road networks.
We want the images to update automatically every 30 seconds, ut my JavaScript isn't brilliant I'm afraid.
I know I can refresh the whole page easily, and I can refresh a single image just fine too. But multiple images from different URLs is proving more difficult.
The camera images are the only images on the page, if that's useful, and are displayed in HTML like such:
<figure class="fluid tiles">
<img src="cam/17002.php" alt="M" onerror="this.src = 'camoffline.png';" />
<figcaption class="textStyle">M20 00/1A J10-11<br /><small>Camera: 17002</small></figcaption>
</figure>
// get all of the images from the page
const images = document.getElementsByTagName( 'img' );
// perform this function every 30,000 ms (30 sec)
const timer = setInterval( function(){
// go through each image and reference a custom attribute
// 'data-source' to preserve the original image's src
for( var i=0, x=images.length; i<x; i++ ){
// select each image, individually
let image = images[i];
let source = image.getAttribute( 'data-source' );
// if 'data-source' does not exist, create it
if( !source ){
source = image.src;
image.setAttribute( 'data-source', source );
// give 'data-source' the original image path
}
// Add a timestamp to the image source to help mitigate
// browser caching
image.src = source + '?t=' + Date.now();
}
}, 30000 );
img{ height: 150px; }
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
<img src="https://image.shutterstock.com/z/stock-photo--week-old-cocker-spaniel-puppy-630877553.jpg">
Use .getElementsByTagName('img') to collect all the images that exist on your page.
Then, in an interval (setInterval: code that will continue to execute every ### miliseconds) create a for-loop that will iterate through the HTML collection captured with .getElementsByTagName()
One idea is to create a new attribute on each image on your page, 'data-source' (data- attributes can really be anything). 'data-source' will keep the original information for the path to the image file.
Then, using the value from the original image path, reassign that image path value to the image, but add in a timestamp as a query parameter. This is to help the browser load a new image (browser's love caching content, where they can). The browser sees image.jpeg?t=1234 and thinks it is a different image than image.jpeg?t=1233
I want to propose a slightly modified solution that uses a <canvas>. This will paint all of your sources in a fixed width container and, if they are offline, draw the "Offline" text where the source should have been.
Click the checkbox to test the offline functionality.
const sources = [
"https://cdn.sstatic.net/Sites/stackoverflow/img/sprites.svg",
"https://cdn.sstatic.net/Sites/stackoverflow/img/sprites.svg"
];
function getSources(offline = false) {
return !offline ?
sources.map(src => `${src}?cb=${Date.now()}`) :
sources.map(() => "");
}
function loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener("load", () => resolve(img));
img.addEventListener("error", () => reject(`Problem loading ${src}`));
img.src = src;
})
}
const offlineCheckbox = document.getElementsByTagName("input")[0],
canvas = document.getElementsByTagName("canvas")[0],
ctx = canvas.getContext("2d");
const {
width,
height
} = canvas;
function refresh() {
console.log("Updating");
getSources(offlineCheckbox.checked).forEach((source, idx, arr) => {
const w = width / arr.length,
dx = w * idx,
dWidth = w * (idx + 1);
loadImage(source)
.then(img => {
ctx.clearRect(dx, 0, dWidth, height);
ctx.drawImage(img, dx, 0, dWidth, height);
})
.catch(err => {
ctx.clearRect(dx, 0, dWidth, height);
ctx.strokeText("Offline", dx, height * 0.5, dWidth);
})
});
setTimeout(() => refresh(), 3 * 1000);
}
refresh();
<main>
<div>
<label><input type="checkbox"> Pretend to be offline</label>
</div>
<div>
<canvas width="400" height="400"></canvas>
</div>
</main>
You can use a timer to reset the src of the image every 30 seconds:
var img = document.querySelector("img.cam");
setInterval(function(){
// I'm appending # and a date to ensure we don't use a cached version of the file
img.src = "https://picsum.photos/200/300/?random#" + new Date() ;
}, 2000); // number is in milliseconds
img { width: 100px; }
<figure class="fluid tiles">
<img class="cam" src="cam/17002.php" alt="M" onerror="this.src='camoffline.png';" />
<figcaption class="textStyle">M20 00/1A J10-11<br /><small>Camera: 17002</small></figcaption>
</figure>
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>
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);
}
});
});
I am using Javascript to put images from Fireworks into my HTML page in a "ghost div". However, the Appointment bookings button sliced via Fireworks is not included. How would I include the link slice for the button while still getting the image effect?
Javascript Code:
$(document).ready(function() {
$('.men').click (function() {
var image = ('<img src="images/deal_men.fw.png" width="700px" height="500px" alt="Deals" />')
$('.deal_content').html(image).hide().fadeToggle('slow');
});
$('.teen').click (function() {
var image = ('<img src="images/deal_teen.fw.png" width="700px" height="500px" alt="Deals" />')
$('.deal_content').html(image).hide().fadeToggle('slow');
});
$('.couple').click (function() {
var image = ('<img src="images/deal_couples.fw.png" width="700px" height="500px" alt="Deals" />')
$('.deal_content').html(image).hide().fadeToggle('slow');
});
});
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.