getJSON issue with loading images across Safari and iOS - javascript

I'm trying to load a series of images that disappear at an interval of 300ms on page load.
The images are chosen at random from a JSON file, based on the users screen dimensions.
This works in Chrome but seems to fail randomly, and does not work at all in Safari (pauses on a random image) or on iOS (fails to load any images at all).
Here is my code:
// get the screen orientation based on css media query
var orientation = window.getComputedStyle(document.querySelector('body'), ':after').getPropertyValue('content').replace(/['"]+/g, '');
window.slides = [];
// function to randomise the order of an array
function shuffle(a) {
var j, x, i;
for (i = a.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
x = a[i];
a[i] = a[j];
a[j] = x;
}
return a;
}
$(document).ready(function() {
$( 'html' ).addClass( 'js' ).removeClass( 'no-js' );
// define the category and number of slides
var imageDirs = { "lovers": 16 };
// get slide urls from json file
$.getJSON('slides/slides.json', function (data) {
for (var thisDir in imageDirs) {
var theseSlides = [];
theseSlides = data[thisDir][orientation];
shuffle(theseSlides)
slides = theseSlides.slice(0, imageDirs[thisDir]);
}
})
.done(function() {
// randomise order of slides
shuffle(slides);
// have one blank slide at the beginning of the animation
slides.push("initial-slide.png");
if ( slides.length ) {
for (var i = 0; i < slides.length; i++) {
$('#wrapper').append('<img class="slide" src="slides/' + slides[i] + '">');
}
}
});
});
$(window).on('load', function(){
// wait for images to load before displaying animation
$('#wrapper').waitForImages(true).done(function() {
$('#preloader').remove();
var currentSlides = [];
$('.slide').each(function(){
currentSlides.push($(this));
});
// remove slides at an interval of 300ms
var timer = setInterval(function(){
if (currentSlides.length){
currentSlides.pop().remove();
} else {
clearInterval(timer);
}
}, 300);
});
});
JSFiddle: https://jsfiddle.net/robertirish/6g41vwnL/59/
Live site: http://robertirish.com
Thanks in advance!

Thanks for the fiddle. Basically your problem is that in your load event the images haven't been appended to be the DOM yet. You can see this by logging currentSlides: https://jsfiddle.net/1fb3gczq/
So, you need to ensure the DOM is ready before you manipulate it. I've moved your function to the ajax success which works in this case, but on slower connections you'll want to only run the effect once all the images have loaded in the DOM. Here's a working fiddle: https://jsfiddle.net/rcx3w48b/

Related

phantomjs : Go till the end of dynamically loaded Facebook page

I wrote a javascript which when used in browser such as chrome, keeps on scrolling such facebook pages in which more content is loaded as you scroll.
i = 0;
minutes = 30;
counter = minutes * 60;
function repeatScroll()
{
console.log('scrolling');
if (i < counter)
{
window.scrollTo(0, document.body.scrollHeight);
i++;
}
setTimeout(repeatScroll, 5000);
}
repeatScroll();
I wanted to do same using phantomjs, but I am unable to do so. I am doubting it has something to do with the delay, but I am unable to figure it out.
This is a snippet from my phantom js code :
var url = "https://www.facebook.com/search/965993006761563/likers";
page.open(url, function (status) {
setTimeout(function () {
page.evaluate(function () {
console.log('gooooooooooooooooo');
});
page.render("liker.png");
page.evaluate(function() {
i = 0;
minutes = 30;
counter = minutes * 60;
function repeatScroll()
{
console.log('scrolling');
if (i < counter)
{
window.scrollTo(0, document.body.scrollHeight);
i++;
}
setTimeout(repeatScroll, 5000);
}
repeatScroll();
});
Console only outputs scrolling once. I am not sure what changes do I need to do.
After scrolling all the way through out I want to extract all profile id's too. Planning to add this just below the above code.
var title = page.evaluate(function() {
var e=document.getElementsByClassName("fsl fwb fcb");
var ids = [];
for(var i = 0 ; i < e.length; i++)
{
ids.push(JSON.parse(e[i].childNodes[0].getAttribute("data-gt")).engagement.eng_tid);
}
console.log(ids);
return ids;
});
Also, when I currently add it, I do not get any profile id output.
Edit : I already read this (How to scroll down with Phantomjs to load dynamic content) but this is not present in my case.

Javascript array is not recognizing called variable

function slideShow() {
var pageSplash = document.getElementById('splash');
var image = ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"];
var i = 0;
while (i <= image.length) {
if (i > image.length) {
i = 0;
}
i += 1;
pageSplash.innerHTML = '<img id ="splashImage" src="file:///C:/JonTFS/JonGrochCoding/Javascript%20Practical%20Test/' + image[i] + '">';
setTimeout('slideShow', 5000);
}
}
I'm unsure why my i variable is not being recognized as the i variable from the rest of the function, so when ever I try to run my while loop it get's an error message saying that it's undefined.
I think you want setInterval instead of setTimeout, and you want you be careful that you increment i after you you update innerHTML.
function slideShow() {
var pageSplash = document.getElementById('splash');
var image = ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"];
var i = 0;
setInterval(function () {
if (i === image.length) {
i = 0;
}
pageSplash.innerHTML = '<img id ="splashImage" src="file:///C:/JonTFS/JonGrochCoding/Javascript%20Practical%20Test/' + image[i] + '">';
i++;
}, 5000)
}
slideShow();
You don't need a while loop. You don't need to reset i. You don't need to set innerHTML.
Click Run code snippet... to see how this works. More explanation below the code
function slideShow(elem, images, delay, i) {
elem.src = images[i % images.length];
setTimeout(function() {
slideShow(elem, images, delay, i+1);
}, delay);
}
// setup slideshow 1
slideShow(
document.querySelector('#slideshow1 img'), // target element
[ // array of images
'http://lorempixel.com/100/100/animals/1/',
'http://lorempixel.com/100/100/animals/2/',
'http://lorempixel.com/100/100/animals/3/',
'http://lorempixel.com/100/100/animals/4/',
'http://lorempixel.com/100/100/animals/5/',
'http://lorempixel.com/100/100/animals/6/'
],
1000, // 1000 ms delay (1 second)
1 // start on slide index 1
);
// setup slideshow 2
slideShow(
document.querySelector('#slideshow2 img'), // target element
[ // array of images
'http://lorempixel.com/100/100/nature/1/',
'http://lorempixel.com/100/100/nature/2/',
'http://lorempixel.com/100/100/nature/3/',
'http://lorempixel.com/100/100/nature/4/',
'http://lorempixel.com/100/100/nature/5/',
'http://lorempixel.com/100/100/nature/6/'
],
500, // 500 ms delay
1 // start on slide 1
);
#slideshow1, #slideshow2 {
width: 150px;
display: inline-block;
}
<div id="slideshow1">
<h2>Animals</h2>
<p>(1000 ms delay)</p>
<!-- initial image -->
<img src="http://lorempixel.com/100/100/animals/1/">
</div>
<div id="slideshow2">
<h2>Nature</h2>
<p>(500 ms delay)</p>
<!-- initial image -->
<img src="http://lorempixel.com/100/100/sports/1/">
</div>
This is a huge improvement because your slideshow function is reusable. It means you can use the same function for any slideshow you want. You can even run multiple slideshows on the same page, as I have demonstrated here.
As others have pointed out, the while loop is unnecessary and, as I pointed out, the setTimout was incorrectly written. The following simplifies your code significantly:
var i = 0;
function slideShow() {
var pageSplash = document.getElementById('splash');
var imageArray = ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"];
if(i < imageArray.length) {
pageSplash.innerHTML = '<img title='+ imageArray[i] + ' id ="splashImage" src="file:///C:/JonTFS/JonGrochCoding/Javascript%20Practical%20Test/' + imageArray[i] + '">';
}
i++;
}
setInterval(slideShow, 2000);
See: https://jsfiddle.net/dauvc4j6/8/ for a working version.
setTimeout calls the function again so you're re-initializing i to 0 every time you call it. Since you can use setTimeout to call the function recursively you don't need the while loop. Pull i out of the function altogether and make it a global variable.
//i should be global
var i = 0;
function slideShow() {
var pageSplash = document.getElementById('splash');
var image = ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"];
if (i >= image.length) {
i = 0;
}
i += 1;
pageSplash.innerHTML = '<img id ="splashImage" src="file:///C:/JonTFS/JonGrochCoding/Javascript%20Practical%20Test/' + image[i] + '">';
//set timeout is going to call slideShow again so if it's in the function it will call recursively, if you wanted to stop after a certain point you could nest setTimeout in an if
setTimeout(slideShow, 5000);
}
//you need to initially call the function
slideShow();

Change img src every second using Jquery and Javascript

I have been trying to write a script that changes an image src every two seconds based on a list.
So, everything is inside a forloop that loops over that list:
$(document).ready(function() {
var lis = {{dias|safe}}; <----- a long list from django. This part of the code works fine.
for (i=0; i<lis.length; i++){
src_img = lis[i][1];
var timeout = setInterval(function(){
console.log(src_img)
$("#imagen").attr("src", src_img);
}, 2000)
}
});
It doesn't work, the console logs thousands of srcs that correspond to the last item on the list. Thanks a lot for your help.
you don't need to run cycle in this case, you just save "pointer" - curentImage and call next array item through function ever 2 sec
var curentImage = 0;
function getNextImg(){
var url = lis[curentImage];
if(lis[curentImage]){
curentImage++;
} else {
curentImage = 0;
}
return url;
}
var timeout = setInterval(function(){
$("#imagen").attr("src", getNextImg());
}, 2000)
var curentImage = 0;
var length = lis.length;
function NewImage(){
var url = lis[curentImage];
if(curentImage < length){
currentImage++;
}
else{
currentImage = 0;
}
return url;
}
var timeout = setInterval(function(){
$("#imagen").attr("src", getNextImg());
}, 2000)
PS: Better than the previous one, Checks for lis length and starts from first if you reach end.
You need something like this
$(document).ready(function() {
var index = 0;
setInterval(function(){
src_img = lis[index++ % lis.lenght][1]; // avoid arrayOutOfBounds
$("#imagen").attr("src", src_img);
}, 2000)
});

Javascript - Show 18 images and then stop

What I'm trying to do is to change a background image 17 times, and then stop. When the user opens a new page, the same thing should happen, load 17 images and stop. The thing is, I don't know much about javascipt (I will learn I promise.) I found a script, it works, but I geuss I have to add a break. I tried but didn't succeed. Here's the code:
var imgArr = new Array(
// relative paths of images
'images/bgshow/1.jpg',
'images/bgshow/2.jpg',
'images/bgshow/3.jpg',
'images/bgshow/4.jpg',
'images/bgshow/5.jpg',
'images/bgshow/6.jpg',
'images/bgshow/7.jpg',
'images/bgshow/8.jpg',
'images/bgshow/9.jpg',
'images/bgshow/10.jpg',
'images/bgshow/11.jpg',
'images/bgshow/12.jpg',
'images/bgshow/13.jpg',
'images/bgshow/14.jpg',
'images/bgshow/15.jpg',
'images/bgshow/16.jpg',
'images/bgshow/17.jpg'
);
var preloadArr = new Array();
var i;
/* preload images */
for(i=0; i < imgArr.length; i++) {
preloadArr[i] = new Image();
preloadArr[i].src = imgArr[i];
}
var currImg = 1;
var intID = setInterval(changeImg, 150);
/* image rotator */
function changeImg() {
$('#page-wrap').animate({opacity: 0}, 0, function() {
$(this).css('background','url(' + preloadArr[currImg++%preloadArr.length].src +') top center no-repeat');
}).animate({opacity: 1}, 0);
}
Would appreciate your help a lot!
That script will keep changing images every 150ms, due to the setInterval(changeImg, 150) call. Thus, to stop it, you need to clear the interval when you are done changing all your images. This can be done at the end of your changeImg function, add the following;
function changeImg() {
// animation code...
if (currImg == preloadArr.length) {
clearInterval(intID);
}
}
if (currImg == preloadArr.length) run not clearInterval(intID); always currImg == 0;
In fact; currImg++ add Before or "if (currImg++ == preloadArr.length)"
function changeImg() {
// animation code...
if (currImg++ == preloadArr.length) {
clearInterval(intID);
}
}

replacing images inplace

I have a array of static images that I am using for an animation.
I have one frame image that I want to update the image of and I have seen a lot of tutorials on animating images with javascript just simply update the source of an image.
frame.src = animation[2].src; etc
When I look at the resource tracking in chrome, it doesnt look like they are getting cached even thought the web browser does download the image more than once but not once for each time it is displayed, so there is still some browser caching going on.
What is the best way to replace the frame image object with another image?
Well, you can either position all images absolute and give them a z-index, then use jQuery/JS to shuffle their z-indexes, bringing a new one to the top in a cross fader style,
or you can take all the id's and fadeone in slightly faster than the last one fades out.
Like so:
function fader(func) {
var currID = $('#mainimg ul').data('currLI');
var currLiStr = '#mainimg ul li#' + currID;
img = $(currLiStr).find('img').attr('src');
nextID = (currID == 'six') ? 'one' : $(currLiStr).next().attr('id');
nextLiStr = $('#mainimg ul li#' + nextID);
$(currLiStr).fadeOut(3000);
$(nextLiStr).fadeIn(2000).find('div.inner').delay(3000).fadeIn('slow').delay(6000).fadeOut('slow');
$('#mainimg ul').data('currLI',nextID);
}
Note 'six' is the id of the last li, reseting it back to one, but if you do $('#mainimg ul li:last').attr('id'); and $('#mainimg ul li:first').attr('id') to get the last and first id's, you can allow it to cope with any amount of images (obviously this is with li's given id's one, two and so on, but if you are finding out the last and first id you could use any structure.
Or you can set a ul width a width of all the li's multiplied, and give the li's the width of the images, and set overflow to hidden, then use JS to pull the li's left by the width of 1 li on each iteration in a slider like I have done here: http://www.reclaimedfloorboards.com/
There are loads of options
I ended up using jquery's replaceWith command and gave all the frames a class "frame" that i could select with $('.frame') which happened to only select visible frames.
<script type="text/javascript">
var animation = [];
var firstFrame = 1;
var lastFrame = 96;
var animationFrames = 16;
var loadedImageCount = 0;
$(function() {
$("button, input:submit",'#forecastForm').button();
$("#progressbar").progressbar({
value: 0
});
$('#id_Species').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
$('#id_Layer').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
$('#id_StartTime').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
$('#id_EndTime').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
});
if (document.images) { // Preloaded images
loadAnimation('Dry_GEM',1,1,96);
}
function rotate(animation, frame)
{
if (frame >= animation.length)
frame = 0;
$('.frame').replaceWith(animation[frame]);
window.setTimeout('rotate(animation,'+eval(frame+1)+')',150);
}
function loadAnimation(species, layer, startTime, endTime)
{
layer = Number(layer);
startTime = Number(startTime);
endTime = Number(endTime);
if (startTime > endTime)
{
swap = startTime;
startTime = endTime;
endTime = swap;
delete swap;
}
for (i=0;i<animation.length;i++)
delete animation[i];
delete animation;
animation = []
$('#progressbar').progressbar({value: 0});
loadedImgCount = 0;
animationFrames = endTime - startTime + 1;
for(i=0;i < animationFrames;i++)
{
animation[i] = new Image();
animation[i].height = 585;
animation[i].width = 780;
$(animation[i]).attr('class','frame');
animation[i].onload = function()
{
loadedImgCount += 1;
$('#progressbar').progressbar({value: eval(loadedImgCount / animationFrames * 100)});
};
animation[i].src = 'http://[[url]]/hemi_2d/' + species + '_' + layer + '_' + eval(i+startTime) + '.png';
}
}
</script>
The easiest way to do it is create a separate hidden image for each frame. Something like this:
var nextImage = (function(){
var imagePaths='basn0g01.png,basn0g02.png,basn0g04.png,basn0g08.png'.split(','),
imageHolder=document.getElementById('custom-header'),
i=imagePaths.length, imageIndex=i-1, img;
for (;i--;) {
img=document.createElement('img');
img.src='http://www.schaik.com/pngsuite/' + imagePaths[i];
if (i) img.style.display='none';
imageHolder.appendChild(img);
}
return function(){
imageHolder.childNodes[imageIndex].style.display='none';
if (++imageIndex >= imageHolder.childNodes.length) imageIndex=0;
imageHolder.childNodes[imageIndex].style.display='inline-block';
}
}());
Try this example on this page; paste it in the console and then call nextImage() a few times. Watch the top of the page.
edit
If you already have all the images in your HTML document, you can skip most of the above and just do something like this:
var nextImage = (function(){
var imageHolder=document.getElementById('custom-header'),
images=imageHolder.getElementsByTagName('img'),
i=images.length, imageIndex=0, img;
for (;i--;) if (i) images[0].style.display='none';
return function(){
imageHolder.childNodes[imageIndex].style.display='none';
if (++imageIndex >= imageHolder.childNodes.length) imageIndex=0;
imageHolder.childNodes[imageIndex].style.display='inline-block';
}
}());

Categories

Resources