Animate when the first image is loaded [duplicate] - javascript

I want to set a background image on the body tag, then run some code - like this:
$('body').css('background-image','http://picture.de/image.png').load(function() {
alert('Background image done loading');
// This doesn't work
});
How can I make sure the background image is fully loaded?

try this:
$('<img/>').attr('src', 'http://picture.de/image.png').on('load', function() {
$(this).remove(); // prevent memory leaks as #benweet suggested
$('body').css('background-image', 'url(http://picture.de/image.png)');
});
this will create a new image in memory and use load event to detect when the src is loaded.
EDIT: in Vanilla JavaScript it can look like this:
var src = 'http://picture.de/image.png';
var image = new Image();
image.addEventListener('load', function() {
body.style.backgroundImage = 'url(' + src + ')';
});
image.src = src;
it can be abstracted into handy function that return a promise:
function load(src) {
return new Promise((resolve, reject) => {
const image = new Image();
image.addEventListener('load', resolve);
image.addEventListener('error', reject);
image.src = src;
});
}
const image = 'http://placekitten.com/200/300';
load(image).then(() => {
body.style.backgroundImage = `url(${image})`;
});

I have a jQuery plugin called waitForImages that can detect when background images have downloaded.
$('body')
.css('background-image','url(http://picture.de/image.png)')
.waitForImages(function() {
alert('Background image done loading');
// This *does* work
}, $.noop, true);

pure JS solution that will add preloader, set the background-image and then set it up for garbage collection along with it's event listener:
Short version:
const imageUrl = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
let bgElement = document.querySelector("body");
let preloaderImg = document.createElement("img");
preloaderImg.src = imageUrl;
preloaderImg.addEventListener('load', (event) => {
bgElement.style.backgroundImage = `url(${imageUrl})`;
preloaderImg = null;
});
A bit longer with nice opacity transition:
const imageUrl = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
let bgElement = document.querySelector(".bg-lazy");
bgElement.classList.add("bg-loading");
let preloaderImg = document.createElement("img");
preloaderImg.src = imageUrl;
preloaderImg.addEventListener('load', (event) => {
bgElement.classList.remove("bg-loading");
bgElement.style.backgroundImage = `url(${imageUrl})`;
preloaderImg = null;
});
.bg-lazy {
height: 100vh;
width: 100vw;
transition: opacity 1s ease-out;
}
.bg-loading {
opacity: 0;
}
<div class="bg-lazy"></div>

There are no JS callbacks for CSS assets.

Something like this:
var $div = $('div'),
bg = $div.css('background-image');
if (bg) {
var src = bg.replace(/(^url\()|(\)$|[\"\'])/g, ''),
$img = $('<img>').attr('src', src).on('load', function() {
// do something, maybe:
$div.fadeIn();
});
}
});

I've located a solution that worked better for me, and which has the advantage of being usable with several images (case not illustrated in this example).
From #adeneo's answer on this question :
If you have an element with a background image, like this
<div id="test" style="background-image: url(link/to/image.png)"><div>
You can wait for the background to load by getting the image URL and
using it for an image object in javascript with an onload handler
var src = $('#test').css('background-image');
var url = src.match(/\((.*?)\)/)[1].replace(/('|")/g,'');
var img = new Image();
img.onload = function() {
alert('image loaded');
}
img.src = url;
if (img.complete) img.onload();

Here is a small plugin I made to allow you to do exactly this, it also works on multiple background images and multiple elements:
Read the article:
http://catmull.uk/code-lab/background-image-loaded/
or go straight to the plugin code:
http://catmull.uk/downloads/bg-loaded/bg-loaded.js
So just include the plugin and then call it on the element:
<script type="text/javascript" src="http://catmull.uk/downloads/bg-loaded/bg-loaded.js"></script>
<script type="text/javascript">
$('body').bgLoaded();
</script>
Obviously download the plugin and store it on your own hosting.
By default it adds an additional "bg-loaded" class to each matched element once the background is loaded but you can easily change that by passing it a different function like this:
<script type="text/javascript" src="http://catmull.uk/downloads/bg-loaded/bg-loaded.js"></script>
<script type="text/javascript">
$('body').bgLoaded({
afterLoaded : function() {
alert('Background image done loading');
}
});
</script>
Here is a codepen demonstrating it working.
http://codepen.io/catmull/pen/Lfcpb

I did a pure javascript hack to make this possible.
<div class="my_background_image" style="background-image: url(broken-image.jpg)">
<img class="image_error" src="broken-image.jpg" onerror="this.parentElement.style.display='none';">
</div>
Or
onerror="this.parentElement.backgroundImage = "url('image_placeHolder.png')";
css:
.image_error {
display: none;
}

https://github.com/alexanderdickson/waitForImages
$('selector').waitForImages({
finished: function() {
// ...
},
each: function() {
// ...
},
waitForAll: true
});

Here is a simple vanilla hack ~
(function(image){
image.onload = function(){
$(body).addClass('loaded-background');
alert('Background image done loading');
// TODO fancy fade-in
};
image.src = "http://picture.de/image.png";
})(new Image());

Related

Preload images and use them as backgound of div element

I am running a very simple slide show that changes the background of a div after some time. The problem is that the images are loaded too slow and a blank screen appears between image changes. Now I want to preload the images and I found these answers, but they did not work, and:
var myImage = new Image();
myImage.src = 'picture.jpg';
Can I somehow use this myImage as background-image of a div? Or do you know any other methods for preloading background-images?
Using :after pseudo-elements did not work.
You can do that using blobs and URL.createObjectURL().
let imgUrl = "https://i.imgur.com/VG2UvcY.jpg";
const preloadBtn = document.getElementById("preload-btn"),
showBtn = document.getElementById("show-btn");
preloadBtn.addEventListener("click", async () => {
imgUrl = URL.createObjectURL(
await (await fetch(imgUrl)).blob()
);
preloadBtn.disabled = true;
});
showBtn.addEventListener("click", () => {
document.body.style.backgroundImage = `url("${imgUrl}")`
});
body {
background-size: cover;
}
<button id="preload-btn">Preload big image</button>
<button id="show-btn">Show big image</button>

How can I test if a link is valid in Javascript or JQuery? [duplicate]

This question already has answers here:
How do I check if file exists in jQuery or pure JavaScript?
(19 answers)
Closed 3 years ago.
We are currently developing a web interface (only for viewing) for one of our applications, which is C++ based. The web application uses Bootstrap. I am a JavaScript and JQuery beginner.
At the top of the web page I need to display a thumbnail if it's available, otherwise a default picture.
I have the link to the thumbnail, even if it's not pointing at any resources (the picture can be deleted for different reasons that are irrelevant here, and this is not an error). The link to the thumbnail has the following format /resources/id={some_id}
Using jquery, I do the following :
<html>
<body>
<img id="thumbnail" />
<script>
var jobId = getUrlVars()["jobId"];
$.getJSON("/jobs?jobId=" + jobId, function(jobDescription) {
/* thumbnailSrc will always contain something valid,
but that can point to some not existing picture */
let thumbnailSrc = jobDescription.thumbnailSrc;
$('#thumbnail').attr("src", thumbnailSrc);
});
</script>
</body>
</html>
If the link is valid, everything is fine; otherwise, it displays a broken picture. I would like to test if thumbnailSrc is a valid link (not returning a 404 error) to be able to do something like:
<script>
var jobId = getUrlVars()["jobId"];
$.getJSON("/jobs?jobId=" + jobId, function(jobDescription) {
let thumbnailSrc = jobDescription.thumbnailSrc;
if (/* thumbnailSrc link is working */)
$('#thumbnail').attr("src", thumbnailSrc);
else
$('#thumbnail').attr("src", "/resources/default_picture.png");
});
</script>
How can I test in Javascript (or JQuery) if a link is valid?
Use a callback function like below
<img src="image.gif" onerror="myFunction()">
<script>
function myFunction() {
alert('The image could not be loaded.');
}
</script>
You can assign to your image an onerror event, and inside it you can assign to src the fallback source, e.g. in jQuery it would be like this:
$(function() {
$('#thumbnail').on('error', function() {
let fallback_img_src = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png';
$(this).attr('src', fallback_img_src);
});
let wrong_img_src = 'wrong_img_src.jpg';
$('#thumbnail').attr('src', wrong_img_src);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img id="thumbnail" />
The following loads the image and if 404, loads the default:
let src = "https://lh3.googleusercontent.com/PS1VZpazvgLZx9GkeudW7vn4JAMp42SpLcV3ugn45z5HFdnx5iXxENLdjN3ZhaYhAa3aByKe9HJAT_b-0LIJeeJGL2-_vS7RxLKQv6kEAA";
let srcBad = "https://lh3.googleusercontent.com/not_exist";
let srcDefault = "https://storage.googleapis.com/gd-wagtail-prod-assets/images/evolving_google_identity_2x.max-4000x2000.jpegquality-90.jpg";
let elImg = document.createElement("img");
let elImg2 = document.createElement("img");
function loadImage(el, src, srcDefault) {
el.addEventListener("load", function(ev) {
document.body.appendChild(el);
});
el.addEventListener("error", function(ev) {
console.log("load error, using default");
el.src = srcDefault;
});
el.src = src;
}
loadImage(elImg, src, srcDefault);
loadImage(elImg2, srcBad, srcDefault);
img {
width: 200px
}
In jQuery:
let src = "https://lh3.googleusercontent.com/PS1VZpazvgLZx9GkeudW7vn4JAMp42SpLcV3ugn45z5HFdnx5iXxENLdjN3ZhaYhAa3aByKe9HJAT_b-0LIJeeJGL2-_vS7RxLKQv6kEAA";
let srcBad = "https://lh3.googleusercontent.com/not_exist";
let srcDefault = "https://storage.googleapis.com/gd-wagtail-prod-assets/images/evolving_google_identity_2x.max-4000x2000.jpegquality-90.jpg";
let elImg = document.createElement("img");
let elImg2 = document.createElement("img");
function loadImage(el, src, srcDefault) {
$(el).on("load", function(ev) {
document.body.appendChild(el);
});
$(el).on("error", function(ev) {
console.log("load error, using default");
el.src = srcDefault;
});
el.src = src;
}
loadImage(elImg, src, srcDefault);
loadImage(elImg2, srcBad, srcDefault);
img {
width: 200px
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

bLazy and Vue.js - DOM not ready fast enough

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();
});

Something goes wrong with fadeIn

Hello I want to fadeOut image, and then do fadeIn with a new one, so I wrote a simple code, but something goes wrong, because when .photo img fadesOut, then fadesIn this same photo, but after, a few second its changes because of new "src", but even if browser didn't load a new image, the old one shound't show, becuase src is changed, but it shows, and after a second, maybe two changes to the new one. Can somebody tell me what's wrong?
var dimage = $next.children("img").attr("rel");
$(".photo img").fadeOut("slow", function () {
$(".photo img").attr("src", dimage);
$(".photo img").fadeIn("slow");
});
This may be because the image has to load after the src is altered.
Consider putting the image in a tag, then setting the css property to display:none. This way the image will preload in the browser before your script runs and will be available when it does.
you aren't giving the new image enough time to load.
function loadImage (src) {
return $.Deferred(function(def){
var img = new Image();
img.onload = function(){
def.resolve(src);
}
img.src = src;
}).promise();
}
var dimage = $next.children("img").attr("rel");
var imageLoadedDef = loadImage(dimage);
$(".photo img").fadeOut("slow", function () {
def.done(function(src){
$(".photo img").attr("src", src);
$(".photo img").fadeIn("slow");
});
});
the problem as highlighted is about images not ready for display when you call them, so the solution is to preload them before starting the slideshow, create a function with an array of images path
function preLoad(){
var imgs = {'test1.jpg', 'test2.jpg', 'test3.jpg'};
var img = document.createElement('img');
for(var i = 0; i < imgs.leght; i++){
img.src = imgs[i]; //all images gets preloaded at this stage
}
startSlider(); //here you will do your code
}

Restart a gif animation without reloading the file

Is it possible to restart a gif animation without downloading the file every time?
My current code looks like this:
var img = new Image();
img.src = 'imgages/src/myImage.gif';
$('#id').css('background-image', 'url("' + img.src + '?x=' + Date.now() + '")' );
Edit
When I insert the gif into the dom it didn't restart the gif animation. I can only achieve this by appending a random string to the image src but this will download the image again.
I want to know if it is possible to restart the gif animation without downloading the gif.
I've had similar requirement.
var img = document.createElement("img"),
imageUrl = "http://i73.photobucket.com/albums/i231/charma13/love240.gif";
img.src = imageUrl;
document.body.appendChild(img);
window.restartAnim = function () {
img.src = "";
img.src = imageUrl;
}
for example on facebook - animated emoticons are not .gifs but a set of static frames on png file with dynamically set background offset. This way you have full control over your animation from javascript - you can even pause/unpause it or change its speed.
It's possible to split your .gif file into separate frames and generate a .png file on server side dynamically.
This looks like a good weekend project for me ;)
restartGif(imgElement){
let element = document.getElementById(imgElement);
if (element) {
var imgSrc = element.src;
element.src = imgSrc;
}
}
// Example:
restartGif("gif_box")
function refreshgif() {
var giffile = $(".gif-class");
giffile.src = giffile.src;
}
I had a similar problem and I solved it by adjusting the image's display attribute before restarting the gif. Also, set the timeout to make sure that the restarting the gif will run after the image attribute is changed.
const img = document.getElementById("gif");
img.style = "display: none;";
img.style = "display: block;";
setTimeout(() => {
img.src = img.src;
}, 0);
This is inspired by this answer.
Just make it loop forever? otherwise you could use an ajax request every (duration of gif) to restart it.
even with javascript it would be possible;
var gif
window.onload=function () {
gif=document.getElementById('id')
setInterval(function () {
gif.src=gif.src.replace(/\?.*/,function () {
return '?'+new Date()
})
},5000)//duration of your gif
}
This may help you,
var img = new Image();
src = 'imgages/src/myImage.gif';
img.src=src;
$('body').append(img);
setInterval(function(){
t=new Date().getTime();
$("img").attr("src", src+'?'+t);
},5000);
create a function in javascript and then reput the image in the same place. when you want to replay the Gif call this function.
function replayGif(){
var img = new Image();
img.src = 'imgages/src/myImage.gif';
$('#id').css('background-image', 'url("' + img.src + '?x=' + Date.now() + '")' );
}
The simplest javascript solution:
Function:
function restartGif(ImageSelector){
var imgSrc=document.querySelector(ImageSelector).src;
document.querySelector(ImageSelector).src=imgSrc;
}
Call function:
restartGif(SELECTOR) // Example: restartGif('.homer')
Example: http://jsfiddle.net/nv3dkscr/
Try to set the src of the gif animation to itself or set it to an empty string followed by the original src again. ;)

Categories