I need your help. My script validate images resolution before sending form.
The problem is that when script should stop because one or more photos is bigger than maximum resolution. It's not happening.
var err is counting number of bad resolution photos, but on the end, i dont know why it is always 0.
Any ideas?
jQuery("form").submit( function( e ) {
var form = this;
e.preventDefault();
var photos = document.getElementById('imgInp');
var howmany = photos.files.length;
var err = 0;
var img = new Array();
for (var i = 0; i < howmany; i++) {
if (photos.files[i]) {
img[i] = new Image();
img[i].src = window.URL.createObjectURL( photos.files[i] );
img[i].onload = function() {
window.URL.revokeObjectURL( this.src );
if( this.width < 1281 && this.height < 1025 ) {
} else {
alert('Zdjęcie jest zbyt duże');
err++;
}
};
} else {
form.submit();
}
}
if(err > 0) {
alert('Niestety ale jedno lub więcej zdjęć, które próbujesz załadować są zbyt duże (dopuszczalna rozdzielczość maksymalna to 1280 x 1024).');
} else {
alert('Ok'); // form.submit();
}
});
https://jsfiddle.net/5fv42o0e/2/
It's because
Image loading is asynchronous
Image loading takes time but browser won't pause your script it would keep running code that follows.For simplicity keeping aside your code assume I have this
var img = new Image();
img.onload = function(){ alert('image loaded');}
img.src = "lion.jpg";
alert('hello');
Because loading image will always take some finite time you would always see "hello" being alerted before "image loaded" always!
Now you can probably guess where the problem was , when your forloop was over completing all its iteration not even the first image is done loading up till that time so err is 0 therefore no error message.
How to solve?
You can choose from a variety of solutions - callbacks,promise,counters etc.Assuming it's a simple application below I have used counters to solve
<script>
var err = 0;
var counter = 0;
jQuery("form").submit( function( e ) {
var form = this;
e.preventDefault();
var photos = document.getElementById('imgInp');
var howmany = photos.files.length;
var img = new Array();
for (var i = 0; i < howmany; i++) {
if (photos.files[i]) {
img[i] = new Image();
img[i].src = window.URL.createObjectURL( photos.files[i] );
counter++;
img[i].onload = function() {
window.URL.revokeObjectURL( this.src );
if( this.width < 1281 && this.height < 1025)
{
} else {
alert('Zdjecie jest zbyt duze');
err++;
}
counter--;
if(counter === 0 ){
if(err > 0) {
alert('Niestety ale jedno lub wiecej zdjec, które próbujesz zaladowac sa zbyt duze (dopuszczalna rozdzielczosc maksymalna to 1280 x 1024).');
} else {
alert('Ok'); // form.submit();
}
}
};
}
}
});
</script>
Here is how it works : A counter will keep track of how many images are outstanding ie. for which src has been assigned but are waiting to get loaded.Increment counter each time you assign a src and decrement it each time an image gets loaded (onload function) also check if it was the last image to get loaded (check if counter is 0) if yes all images are done now run your check
Related
To continue on the question here. Since I am doing this for the first time, and I still consider myself a newbie in javascript I would like to know how to properly preload images for the browser.
This is my script:
$(document).ready(function () {
var imagesIndex = 0;
var loadedImages = new Array();
var nextImage = 0;
preload();
function preload() {
for (i = 0; i < 2; i++) {
if (nextImage < images.length) {
var img = new Image();
img.src = '/imagecache/cover/' + images[nextImage];
loadedImages[nextImage] = img;
++nextImage;
}
}
}
$('#forward').click(function() {
imagesIndex++;
preload();
if (imagesIndex > (loadedImages.length - 1)) {
imagesIndex = 0;
}
$('#image').attr({"src" : '/imagecache/cover/' + loadedImages[imagesIndex], "alt" : name});
});
$('#back').click(function() {
imagesIndex--;
if (imagesIndex < 0) {
imagesIndex = (loadedImages.length - 1);
}
$('#image').attr({"src" : '/imagecache/cover/' + loadedImages[imagesIndex], "alt" : name});
});
});
I am getting images from the global array images, and then using preload function to preload 2 at the time. I wonder what do I need to send as a source to the image element. Is that a src from the loadedImages array element or from the images array?
I'm trying to preload certain images that I have decorated with an attribute and I'm wondering if you guys can help me figure out what's going wrong here. I have
var barlen = $('#SSWEprogressbar').width(),
$elems = $('[data-srcurl]'),
n = $elems.length;
for ( var k = 0; k < n; ++k )
{
var $elem = $($elems[k]);
var img = new Image(),
url = $elem.attr('data-srcurl');
$(img).load(function(){
console.log("we're here");//TEST
$('#SSWEloaderfront').attr('src',url);
$('#SSWEloadprogress').width(k/n*barlen + "px");
});
var srctgt = $elem.attr('data-srctgt');
if ( srctgt == "srcattr" )
{
$elem.attr('src',url);
}
else if ( srctgt == "bgimg" )
{
$elem.css('background-image',url);
}
}
and then
console.log("we're here");//TEST
isn't being invoked. Any ideas?
You aren't setting the src attribute on the img element, so the load will never fire. You need to add $(img).attr('src', url);
So I have been recently developing a site, The problem is the backgrounds for each page are images, and as a result, on slower connections (which is the case of some of the target audience) the images load progressivly as they are downloaded, to resolve this I am trying to make a preloading page that does the following :
Loads the Images
Once the loading is done, redirects the user to the requested page
<script type="text/javascript">
<!--//--><![CDATA[//><!--
var images = new Array()
var count=0;
function preload() {
for (i = 0; i < preload.arguments.length; i++) {
images[i] = new Image()
images[i].src = preload.arguments[i]
}
if(count==4) {
window.location = "index.html";
}
}
preload(
"backgrounds/bg1.jpg",
"backgrounds/bg2.jpg",
"backgrounds/bg3.jpg",
"backgrounds/bg4.jpg"
)
//--><!]]>
The problem is it redirects directly (I assume that it just starts the download of the image then directly adds one to the counter variable, quickly reaching 4 and not giving the image the time to download.
Any ideas how I can either make it signal me when the images have finished downloading, or only execute the redirect after it has done downloading the images ?
You need to wait for the load event. It's quite simple:
function preload(images, timeout, cb) {
var cbFired = false,
remaining = images.length,
timer = null;
function imageDone() {
remaining--;
if(remaining === 0 && !cbFired) {
cbFired = true;
clearTimeout(timer);
cb();
}
}
function timerExpired() {
if(cbFired)
return;
cbFired = true;
cb();
}
for(var i = 0; i < images.length; i++) {
var img = new Image();
img.onload = imageDone;
img.onerror = imageDone;
img.src = images[i];
}
timer = setTimeout(timerExpired, timeout);
}
You need to check a few things so that users don't get stuck:
You need to wait for both load and error so that the page doesn't get stuck if an image fails to load.
You should set a maximum timeout.
Also, in your code, i was a global variable (no var declaration).
Here's how to use it:
var images = [ "backgrounds/bg1.jpg",
"backgrounds/bg2.jpg",
"backgrounds/bg3.jpg",
"backgrounds/bg4.jpg"];
preload(images, 10000 /* 10s */, function () {
window.location = 'next_page';
});
Modify your preloader so that it binds to the "onload" event of the Image object and when all callbacks are fired it redirects (untested sample code below):
var images = new Array()
var count = 0;
function preload() {
var numImages = preload.arguments.length
for (i = 0; i < numImages; i++) {
images[i] = new Image();
images[i].onload = doneLoading; // See function below.
images[i].src = preload.arguments[i];
}
function doneLoading() {
if (++count >= numImages) {
window.location = "index.html";
}
}
}
preload(
"backgrounds/bg1.jpg",
"backgrounds/bg2.jpg",
"backgrounds/bg3.jpg",
"backgrounds/bg4.jpg"
)
I'm trying to create a lightbox for my site, and I want it to load all the images from a given directory with a filename like image#.jpg.
This is the code I have:
for(var i=0; i<1000; i++)
{
var filename = "images/image"+i+".jpg";
$.get(filename)
.done(function() {
$('#lightbox').append('<img src="placeholder.gif">');
})
.fail(function() {
i=1000; //ugh
});
}
It kind of works, but only tries to load image1000.jpg.
Also, is there a better way to do something like this? I'm sure saying 'do this a ton of times and stop when I manually change the for loop counter' is frowned on.
If your image names are sequential like your said, you can create a loop for the names, checking at every iteration if image exists - and if it doesn't - break the loop:
var bCheckEnabled = true;
var bFinishCheck = false;
var img;
var imgArray = new Array();
var i = 0;
var myInterval = setInterval(loadImage, 1);
function loadImage() {
if (bFinishCheck) {
clearInterval(myInterval);
alert('Loaded ' + i + ' image(s)!)');
return;
}
if (bCheckEnabled) {
bCheckEnabled = false;
img = new Image();
img.onload = fExists;
img.onerror = fDoesntExist;
img.src = 'images/myFolder/' + i + '.png';
}
}
function fExists() {
imgArray.push(img);
i++;
bCheckEnabled = true;
}
Due to the nature of async execution in .onload, Javscript would not run in the order as appeared in the code. Following snippet as I leared from how to alert after all images loaded? would not work always, pass here and fail there, all depending on the sequence of browser execution. Any suggestion how to solve it? (no jQuery please, nor asking me why)
var imgLoaded = 0;
var imgToLoad = 10;
var onImgLoad = function()
{
imgLoaded++;
if(imgLoaded == imgToLoad)
{
alert("done"); //Call to our draw function
}
}
for(var i = 0; i < 10; i++)
{
images[i] = new Image();
images[i].onload = onImgLoad;
images[i].src = 'images/'+i+'.png';
}
Specifically, here is where the code fails:
imgLoaded++;
if(imgLoaded == imgToLoad) { }
As a result, sometimes the code in the IF condition might not get executed even if all images were loaded corrected.
See this fiddle : http://jsfiddle.net/wdBbX/
var images = [];
function loadImages(callBack)
{
var imgLoaded = 0;
var imgToLoad = 10;
var onImgLoad = function()
{
imgLoaded++;
if(imgLoaded == imgToLoad)
{
callBack(imgLoaded); //Call to our draw function
}
}
for(var i = 0; i < 10; i++)
{
images[i] = new Image();
images[i].onload = onImgLoad;
images[i].src = 'images/'+i+'.png';
}
}
loadImages(function(i){
alert(i);
});
i prefer the sequentially way in this case.
so you can add cool animations with css...
var current=1,toload=10;
function next(){
var img=document.createElement('img');
img.onload=function(){
current++;
current==(toload+1)?(
console.log('ALL IMAGES ARE LOADED');
// callback
):(
next()
)
document.body.appendChild(this);
}
img.src='img/'+current+'.jpg';
}
window.onload=next;
i also added the way to addan image array
var current=0,images=['img1.jpg','img2.jpg','img3.jpg','img4.jpg'];
function next(){
var img=document.createElement('img');
img.onload=function(){
current++;
current==images.length?(
console.log('ALL IMAGES ARE LOADED');
// callback
):(
next()
)
document.body.appendChild(this);
}
img.src=images[current];
}
window.onload=next;
if your not shure about all images add also a img.onerror with the same function as onload esle the loop stops.
if you don't understand something or you need it as a callback function just ask.
Here is a proper up-to-date solution, including example usage:
const preload = src => new Promise(function(resolve, reject) {
const img = document.createElement('img');
img.onload = function() {
resolve(img);
}
img.onerror = reject;
img.src = src;
});
const preloadAll = sources =>
Promise.all(
sources.map(
preload));
const sources = [
'https://i.picsum.photos/id/1000/5626/3635.jpg',
'https://i.picsum.photos/id/10/2500/1667.jpg',
'https://homepages.cae.wisc.edu/~ece533/images/cat.png',
'https://homepages.cae.wisc.edu/~ece533/images/airplane.png'
];
preloadAll(sources)
.then(images => console.log('Preloaded all', images))
.catch(err => console.error('Failed', err));
From here.