I'm using IntersectionObserver to replace an initially-loaded image with another one as the original image comes into the user's viewport.
I want the image to fade in, as opposed to just straight replacement.
I've tried adding a Jquery loader to the image, but it is not working as I'd like.
function fadeIn(obj) {
$(obj).fadeIn(1000);
}
document.addEventListener("DOMContentLoaded", function() {
var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
if ("IntersectionObserver" in window) {
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let lazyImage = entry.target;
$(lazyImage).on('load', fadeIn(lazyImage));
lazyImage.src = lazyImage.dataset.src;
lazyImage.srcset = lazyImage.dataset.srcset;
lazyImage.classList.remove("lazy");
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<img
class="lazy"
src="https://classroomclipart.com/christmas-tree-with-bright-lights-decoration-animated-clipart-motion-lights-gifts-presents-2.gif"
data-src="https://classroomclipart.com/TN_december-happy-holidays_2.jpg"
data-srcset="https://classroomclipart.com/sm-santa-claus-and-reindeer-singing-christmas-carols-clipart.jpg 2x, https://classroomclipart.com/TN_december-happy-holidays_2.jpg 1x"
width="100"
height="100"
>
Here is a solution that works decently well using jQuery animation: https://jsfiddle.net/ea7fxrL5/
There are two problems in your current code as far as I can tell:
The fadeIn function is actually being called before the image's source is changed to the "TN_december-happy-holidays_2.jpg" image because the load event is triggered immediately on intersection, since the image's "christmas-tree" src has already been loaded.
The image is already at full opacity, so it needs to be hidden before you can fade it in.
Hope this helps!
Related
I am using an AOS (animate-on-scroll) library in my html to help fade in the images, but javascript to trigger the actual fading-in. I want the image to fade-in when I am scrolling past, but not to fade back out when I scroll back up. The code below is what I've tried so far, but the image isn't showing up. I've seen a way to do this in jQuery, but I wanted to see if I could do it in plain JS. I got the image to show up and fade-in using the onscroll handler, but ran into the problem of it fading-in repeatedly if I moved back to the top of the page. Below is what I have using an event listener
HTML:
//sets the point at which the image will fade in
let pic = document.getElementById("pic");
let characterCaption = document.getElementById("characters");
let triggerAt = 100;
function getPic() {
pic.onscroll;
let topOfImage = pic.scrollTop + triggerAt;
return topOfImage;
}
window.addEventListener("scroll", fadeInImage);
//attempt to fade in image at certain point and prevent image from fading in again
function fadeInImage() {
let currentPosition = window.pageYOffset;
let topOfImage = getPic();
if (currentPosition > topOfImage) {
pic.style.visibility = "visible";
characterCaption.style.visibility = "visible";
window.removeEventListener("scroll", fadeInImage);
}
}
<img id="pic" src="https://cdn.vox-cdn.com/thumbor/MZRJnpwAMIHQ5-XT4FwNv0rivw4=/1400x1400/filters:format(jpeg)/cdn.vox-cdn.com/uploads/chorus_asset/file/19397812/1048232144.jpg.jpg" width="500px" height="650px" data-aos="fade-left" data-aos-duration="2000" data-aos-easing="ease-in-sine">
<p id="characters"> picture caption </p>
I am working on simple gallery with pictures. I wanted to use bLazy plugin to load images, all works fine except the fact that I wanted to load image list via external JSON file and because of that images elements are not created fast enough, so when bLazy script is loaded, it can't see images yes.
If I use setTimeout it works, but it is a nasty way of doing things... Any ideas how to refactor my code?
Please note that it work in progress and I will use routers later...
app.js:
var allPics = Vue.extend({
el: function () {
return "#gallery";
},
data: function () {
return {
pics: {},
folders: {
full: "img/gallery/full_size/",
mid: "img/gallery/mid/",
small: "img/gallery/small/",
zoom: "img/gallery/zoom/"
}
};
},
created: function () {
this.fetchData();
},
ready: function () {
setTimeout(function () {
var bLazy = new Blazy({
});
}, 1000);
},
methods: {
fetchData: function () {
var self = this;
$.getJSON("js/gallery.json", function (json) {
self.pics = json;
})
}
}
});
var router = new VueRouter({
});
router.start(allPics, 'body', function () {
});
HTML:
<div id="gallery" class="gallery">
<div v-for="pic in pics.gallery" class="gallery_item">
<div class="img_div">
<img class="b-lazy"
src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
data-src= "{{* folders.mid + pic.name}}"
alt="{{pic.alt}}" >
</div>
</div>
You might want to check https://github.com/aFarkas/lazysizes, it detects DOM changes automatically, so you don't have to do any setTimeout hacks.
Only add the script and add the class lazyload as also use data-src instead of src and you are done.
I am also working with a small gallery of images and using image-background on divs instead of < img > tags since they offer more control over nested elements positioning and allows to use background-size: cover property.
What i do to preload images is something like this:
var imageUrl = ....
var img = new Image();
img.onload = function() {
this.$els.divId.style.backgroundImage = "url(" + imageUrl + ")";
$(this.$els.divId).fadeIn(1000); // fade in div using jquery
};
img.src = imageUrl;
That way when the image is loaded and cached in the browser i can fade in the image div for a smooth effect.
Note that the divId element is hidden (using display: false) from the start and no background-image property is assigned.
Also onload event should be set before assigning imageUrl to img.src so you don't miss the onload event if the image is already cached.
This functionality can also be added to a mixin or an utils class and keeps things simple. It can also adapted to < img > by setting the onload listener, fadeIn and src on an existing img element.
You can trying to revalidate: "blazy.revalidate()", after fetch function.Or to revalidate in the "updated". I was helped.
Use Vue.nextTick. Reference.
Defer the callback to be executed after the next DOM update cycle
Vue.nextTick(() => {
new Blazy();
});
I'm having trouble finding any good information on how to make a javascript(or jquery) progress bar WITH text that tells you the percentage.
I don't want a plug in, I just want to know how it works so that I can adapt it to what I need. How do you preload images and get a variable for the number of images that are preloaded. Also, how do you change html/css and-or call a function, based on the number of images that are loaded already?
<img> elements have an onload event that fires once the image has fully loaded. Therefore, in js you can keep track of the number of images that have loaded vs the number remaining using this event.
Images also have corresponding onerror and onabort events that fire when the image fails to load or the download have been aborted (by the user pressing the 'x' button). You also need to keep track of them along with the onload event to keep track of image loading properly.
Additional answer:
A simple example in pure js:
var img_to_load = [ '/img/1.jpg', '/img/2.jpg' ];
var loaded_images = 0;
for (var i=0; i<img_to_load.length; i++) {
var img = document.createElement('img');
img.src = img_to_load[i];
img.style.display = 'hidden'; // don't display preloaded images
img.onload = function () {
loaded_images ++;
if (loaded_images == img_to_load.length) {
alert('done loading images');
}
else {
alert((100*loaded_images/img_to_load.length) + '% loaded');
}
}
document.body.appendChild(img);
}
The example above doesn't handle onerror or onabort for clarity but real world code should take care of them as well.
What about using something below:
$('#btnUpload').click(function() {
var bar = document.getElementById('progBar'),
fallback = document.getElementById('downloadProgress'),
loaded = 0;
var load = function() {
loaded += 1;
bar.value = loaded;
/* The below will be visible if the progress tag is not supported */
$(fallback).empty().append("HTML5 progress tag not supported: ");
$('#progUpdate').empty().append(loaded + "% loaded");
if (loaded == 100) {
clearInterval(beginLoad);
$('#progUpdate').empty().append("Upload Complete");
console.log('Load was performed.');
}
};
var beginLoad = setInterval(function() {
load();
}, 50);
});
JSFIDDLE
You might also want to try HTML5 progress element:
<section>
<p>Progress: <progress id="p" max=100><span>0</span>%</progress></p>
<script>
var progressBar = document.getElementById('p');
function updateProgress(newValue) {
progressBar.value = newValue;
progressBar.getElementsByTagName('span')[0].textContent = newValue;
} </script>
</section>
http://www.html5tutorial.info/html5-progress.php
I have an img tag on my web page. I give it the url for an IP camera from where it get images and display them. I want to show image when it is completely loaded. so that I can avoid flickering. I do the following.
<img id="stream"
width="1280" height="720"
alt="Press reload if no video displays"
border="0" style="cursor:crosshair; border:medium; border:thick" />
<button type="button" id="btnStartLive" onclick="onStartLiveBtnClick()">Start Live</button>
javascript code
function LoadImage()
{
x = document.getElementById("stream");
x.src = "http://IP:PORT/jpg/image.jpg" + "?" + escape(new Date());
}
function onStartLiveBtnClick()
{
intervalID = setInterval(LoadImage, 0);
}
in this code. when image is large. it takes some time to load. in the mean time it start showing the part of image loaded. I want to display full image and skip the loading part Thanks
Preload the image and replace the source of the <img /> after the image has finished loading.
function LoadImage() {
var img = new Image(),
x = document.getElementById("stream");
img.onload = function() {
x.src = img.src;
};
img.src = "http://IP:PORT/jpg/image.jpg" + "?_=" + (+new Date());
}
You can use the complete property to check if the image has finished loading. However, I think there are other issues with your code, mainly you are repeatedly loading the same image. Instead, you should load it only once and then check the complete property in an interval.
Something like this should work:
function LoadImage()
{
x = document.getElementById("stream");
x.src = "http://IP:PORT/jpg/image.jpg" + "?" + escape(new Date());
x.style.visibility = 'hidden';
}
function CheckIsLoaded() {
x = document.getElementById("stream");
if (x.complete) x.style.visibility = 'visible';
}
function onStartLiveBtnClick()
{
LoadImage();
intervalID = setInterval(CheckIsLoaded, 0);
}
The following appears to work fine for me
<img src="/path/to/image.png"
class="d-none"
onload="this.classList.remove('d-none')"
>
Basically I hide the img element and show it only after the image is loaded. Here d-none is the bootstrap class that defines display:none but you can define your own class if you are not using bootstrap.
If you would like to reserve the space for the image even adding a default background, you can use a wrapper div with ratio ratio-4x3 (for bootstrap) or its equivalance CSS (e.g. padding a wrapper with height=0 in proportion to width), and set a background to img through css.
Page in question: http://phwsinc.com/our-work/one-rincon-hill.asp
In IE6-8, when you click the left-most thumbnail in the gallery, the image never loads. If you click the thumbnail a second time, then it will load. I'm using jQuery, and here's my code that's powering the gallery:
$(document).ready(function() {
// PROJECT PHOTO GALLERY
var thumbs = $('.thumbs li a');
var photoWrapper = $('div.photoWrapper');
if (thumbs.length) {
thumbs.click( function(){
photoWrapper.addClass('loading');
var img_src = $(this).attr('href');
// The two lines below are what cause the bug in IE. They make the gallery run much faster in other browsers, though.
var new_img = new Image();
new_img.src = img_src;
var photo = $('#photo');
photo.fadeOut('slow', function() {
photo.attr('src', img_src);
photo.load(function() {
photoWrapper.removeClass('loading');
photo.fadeIn('slow');
});
});
return false;
});
}
});
A coworker told me that he's always had problems with the js Image() object, and advised me to just append an <img /> element inside of a div set to display:none;, but that's a little messy for my tastes--I liked using the Image() object, it kept things nice and clean, no unnecessary added HTML markup.
Any help would be appreciated. It still works without the image preloading, so if all else fails I'll just wrap the preloading in an if !($.browser.msie){ } and call it a day.
I see you've fixed this already, but I wanted to see if I could get the pre-loading to work in IE as well.
try changing this
photo.fadeOut('slow', function() {
photo.attr('src', img_src);
photo.load(function() {
photoWrapper.removeClass('loading');
photo.fadeIn('slow');
});
});
to this
photo.fadeOut('slow', function() {
photo.attr('src', img_src);
if (photo[0].complete){
photoWrapper.removeClass('loading');
photo.fadeIn('slow');
} else {
photo.load(function() {
photoWrapper.removeClass('loading');
photo.fadeIn('slow');
});
}
});