JS slideshow works one way - javascript

My slideshow is suffering from erratic behaviour. it's driven by pagers which the user clicks. when the corresponding pager is clicked, the next image is made visible (opacity/filter) and set as z-index 5 so that it should sit beneath the present image (z-index 10). The current image is then faded-out and finally, the next image is set to current and the image that has faded out is set to z-index 0. However, this only works when clicking back to a previous image (in Chrome, ie is behaving even more strangely.) in the order of images. That is to say,
chrome:
"list_slide1" to "list_slide3" instant jump with no fade
"list_slide3" to "list_slide1" fade behaves correctly
then...
"list_slide1" to "list_slide3" instant jump no fade "list_slide3" to
"list_slide2" fade behaves correctly
or...
"list_slide1" to "list_slide6" instant jump no fade
"list_slide6" to any preceding list-slide1-5 fade behaves correctly
IE:
"list_slide1" to "list_slide3" instant jump with no fade
"list_slide3" to "list_slide1" a second pause then jump
The pagers and the images are dynamically generated from a database (hence the little piece of PHP at the bottom of the code). it contains as many items as are listed for the page in the database.
a few notes:
1) the fade function is my own take on
http://javascript.info/tutorial/animation and has worked just fine in
another slideshow elsewhere on the site.
2) getElementsByClass is from http://www.robertnyman.com and returns
parent and child elements of the requested class in an array (hence
why I call current[0] etc.)
thanks.
<script type="text/javascript">
var pager = document.getElementById('pager1');
var list_pagers = document.getElementById('pagers')
var i = 0;
var next_slide = function(next) {
if (next.className !== 'slide_current') {
if (getElementsByClassName('slide_pending').length === 0) {
var current = getElementsByClassName('slide_current');
next.className = 'slide_pending';
next.style.zIndex = 5;
next.style.opacity = 1;
next.style.filter = 'alpha(opacity = 100)';
next.style.display = 'block';
fade(current[0], linear, 1000);
var fadeSlide = switcher(next, current);
}
}
}
var switcher = function(now, then) {
setTimeout(function() {
now.className = 'slide_current';
now.style.zIndex = 10;
now.style.opacity = 1;
now.style.filter = 'alpha(opacity = 100)';
then[0].className = 'slide_hide';
then[0].style.zIndex = 0;
then[0].style.opacity = 0;
then[0].style.filter = 'alpha(opacity = 0)';
then[0].style.display = 'none';
}, 1001);
}
<?php
// dynamically build event for each pager/slide in the show.
for ($k = 1; $k <= $i; $k++) {
echo 'var next_slide' .$k. ' = document.getElementById("list_slide" +' .$k. '); ',
'addEvent(list_pagers.childNodes[' .($k - 1). '], "click", function () {next_slide(next_slide' .$k. ')}); ';
}
?>

Forgive me for not posting an answer to your exact problem, but I would steer away from writing Javascript plugins yourself for the following reasons:
Hundreds of them exist on the Web already, some of which are developed on GitHub as open source, preventing potential issues through collaborative development.
There is no need to reinvent the wheel; simply spend 20 minutes googling javascript sliders and find one that you can customise to your needs.
A couple I like using are 'caroufredsel', which is responsive and offers a few nice features (dynamically adding items, callbacks etc).
Another is 'flexslider'.

SOLUTION:
the problem was that the <div> tags i was trying to fade each contained an <img> and another <div>... the CSS being applied was either working inconsistently/erratically or - as is IE's wont - not-at-all.... The solution was - rather than animating the fade of the parent <div> - animating the respective child components separately. At first, it looked like the IE solution was completely unto itself; in fact, it was insightful to creating a neat, lightweight non-JQuery slideshow for all the browsers. One trade-off was that I had to incorporate all the styling into the element tags rather than a separate CSS. This seemed like the only viable option in this instance by virtue of the nature of the DOM requests being made...
Questions/feedback gratefully received:
<script type="text/javascript">
var list_pagers = document.getElementById('pagers')
var i = 0;
<?php
// dynamically build event for each pager/slide in the show.
for ($k = 1; $k <= $i; $k++) {
echo 'var next_slide' .$k. ' = document.getElementById("list_slide" +' .$k. '); ',
'addEvent(list_pagers.childNodes[' .($k - 1). '], "click", function () {next_slide(next_slide' .$k. ')}); ';
}
?>
var next_slide = function(next) {
if (next.className !== 'slide_current') {
if (navigator.appName === 'Microsoft Internet Explorer') {
//IE 7 & 8
if ((navigator.appVersion.search('MSIE 8.0') >= 1) || (navigator.appVersion.search('MSIE 7.0') >= 1)) {
var current = getElementsByClassName('slide_current')[0].childNodes[0];
var currentBar = getElementsByClassName('slide_current')[0].childNodes[1];
var nextBar = next.childNodes[1];
var nextSlide = next.childNodes[0];
} else {
//IE 9
var current = getElementsByClassName('slide_current')[0].childNodes[1];
var currentBar = getElementsByClassName('slide_current')[0].childNodes[2];
var nextBar = next.childNodes[2];
var nextSlide = next.childNodes[1];
}
// give the next slide and its header (nextBar) a temporary status of zIndex 5/6
nextSlide.style.zIndex = 5;
nextBar.style.zIndex = 6;
nextSlide.style.filter = "alpha(opacity=100)";
nextBar.style.filter = "alpha(opacity=85)";
fade(currentBar, linear, 500); // fade currentBar out
fade(current, linear, 500); // fade current out
//once we've faded out current slides, it's time to replace them with th
setTimeout(function() {
getElementsByClassName('slide_current')[0].className = 'slide_hide';
next.className = 'slide_current';
nextSlide.style.opacity = 1; // IE 9 includes opacity...
nextBar.style.opacity = 1; // IE 9 includes opacity...
nextSlide.style.filter = "alpha(opacity=100)";
nextBar.style.filter = "alpha(opacity=85)";
nextSlide.style.zIndex = 10;
nextBar.style.zIndex = 11;
}, 500);
} else {
// NON IE TAGS
var current = getElementsByClassName('slide_current')[0];
current.childNodes[1].style.zIndex = 10; // [1] the child <img> tag
current.childNodes[2].style.zIndex = 11; // [2] the child <div> tag
current.childNodes[1].style.opacity = 1;
current.childNodes[2].style.opacity = 0.85;
next.childNodes[1].style.zIndex = 5;
next.childNodes[2].style.zIndex = 6;
next.childNodes[1].style.opacity = 1;
next.childNodes[2].style.opacity = 0.85;
fade(current.childNodes[1], linear, 600); // fade current out
fade(current.childNodes[2], linear, 600); // fade current out
var fadeSlide = setTimeout(function() {switcher(next, current)}, 500);
var switcher = function(now, then, nowBar, thenBar) {
then.className = 'slide_hide';
then.childNodes[1].style.opacity = 0;
then.childNodes[2].style.opacity = 0;
now.className = 'slide_current';
now.childNodes[1].style.opacity = 1;
now.childNodes[2].style.opacity = 0.85;
now.style.opacity = 1;
}
}
}
}
</script>

Related

How to disable a jquery function from executing for a certain amount of time

I have a jQuery function that calculates the distance between two slideshows and detects to see if they have been scrolled past yet and tells it to display the first slide with important information on it.
However, it displays it once, but then the if statement loops and keeps displaying it, which would be expected.
I am wondering if there is a way to force the function to wait 25-ish seconds before it executes again? Any help would be much appreciated.
Here is the jQuery code:
$(window).scroll(function() {
$('.infoIdentifier').each(function() {
var scroll = $(window).scrollTop();
var objectpos = $(this).offset().top - 600;
var nextobject = $(this).parent().nextAll('.slideshow').children(".infoIdentifier")
if (nextobject.length === 0) {
var nextobjectpos = 10000;
} else {
var nextobjectpos = nextobject.offset().top - 600;
}
if (scroll > objectpos && scroll < nextobjectpos) {
var $this = $(this).parent('.slideshow');
var $currentSlide = $this.find('.active');
var $nextSlide = $this.children('.jumbotron').first();
$nextSlide.fadeIn(500).addClass('active');
$currentSlide.fadeOut(500).removeClass('active');
}
});
});
As for HTML, the slideshows are held in a main container, and each slide show with important information is tagged as class = 'infoIdentifier'. This part of the function does its job. The calculations are fine and the application of classes is fine, however, how do I disable the if (scroll > objectpos && scroll < nextobjectpos){ statement for x amount of seconds. Any help would be much appreciated. Thank you!
Here's one way to achieve this. I added a boolean outside of your scroll function called wait, which is set to false initially.
Then I added !wait as a condition to your if logic, which means it will only validate if wait is currently false.
Then inside that block, I set wait to true, and started a setTimeout for 25 seconds, after which wait is set back to false.
During those 25 seconds, that slideshow code will not run.
var wait = false;
$(window).scroll(function() {
$('.infoIdentifier').each(function() {
var scroll = $(window).scrollTop();
var objectpos = $(this).offset().top - 600;
var nextobject = $(this).parent().nextAll('.slideshow').children(".infoIdentifier")
if (nextobject.length === 0) {
var nextobjectpos = 10000;
} else {
var nextobjectpos = nextobject.offset().top - 600;
}
if (!wait && scroll > objectpos && scroll < nextobjectpos) {
var $this = $(this).parent('.slideshow');
var $currentSlide = $this.find('.active');
var $nextSlide = $this.children('.jumbotron').first();
$nextSlide.fadeIn(500).addClass('active');
$currentSlide.fadeOut(500).removeClass('active');
wait = true;
setTimeout(function() {
wait = false;
}, 25000);
}
});
});

jQuery nicescroll is not working with dynamic content and other JavaScript function that makes random effect

So here is the thing, I have a sidebar that has big height due the lots of navigation links. And I'm using jQuery nicescroll plugin to make it look fine. In the sidebar I also have h3 tag which makes a random effect of showing letters (see the code) every 4 seconds. So, when it's on - scroll is not working at all for these 4 seconds and you can't do any scrolling. I tried to use $("#sidebar").getNiceScroll().resize() but it doesn't work either. Is there any way to make it work?
<div id="sidebar">
<h3 id="output">Random</h3>
</div>
//Calling for nicescroll function for my sidebar
$(function(){
$("#sidebar").niceScroll({ cursorcolor:"#66aee9", cursorfixedheight: 400 });
})
//Random effect for my h3 tag
setInterval(function(){
$(document).ready(function(){
var theLetters = "abcdefghijklmnopqrstuvwxyz#%&^+=-"; //You can customize what letters it will cycle through
var ctnt = "Random"; // Your text goes here
var speed = 50; // ms per frame
var increment = 8; // frames per step. Must be >2
var clen = ctnt.length;
var si = 0;
var stri = 0;
var block = "";
var fixed = "";
//Call self x times, whole function wrapped in setTimeout
(function rustle (i) {
setTimeout(function () {
if (--i){rustle(i);}
nextFrame(i);
si = si + 1;
}, speed);
})(clen*increment+1);
function nextFrame(pos){
for (var i=0; i<clen-stri; i++) {
//Random number
var num = Math.floor(theLetters.length * Math.random());
//Get random letter
var letter = theLetters.charAt(num);
block = block + letter;
}
if (si == (increment-1)){
stri++;
}
if (si == increment){
// Add a letter;
// every speed*10 ms
fixed = fixed + ctnt.charAt(stri - 1);
si = 0;
}
$("#output").html(fixed + block);
block = "";
}
});
}, 4000);
I change to rows and check it in jsfiddle, looks like working scroll fine.
Before:
setInterval(function(){
$(document).ready(function(){
...
});
}, 4000);
After:
$(document).ready(function(){
setInterval(function(){
...
}, 4000);
});

How to transform a generic Animated JS script to work with many classes id

I don't know how I can explain my problem... but I have a Animated JS script and this JS Works fine.
This script identify by CLASS NAME each ICONS on the page marked by the class name - and animated this icons with a delay between each icon.
Then I have in my page 3 sections (all in the same page):
1- About Us
2- Services
3- Clients
I create this script to use in SERVICES SECTION where I have 20 services, with 20 icons - animated one after other on screen.
But now, I want to use this script in About Us and Clients Sections to animated the icons in this sections
My problem:
The script Works fine for 1 section. If I use in other section I need to wait all animations from the other sections stop to start the animations from the actual sector. (All animations are "scrollbar controlled")
To correct this I clone the script 2x and change the class name for each section.
Problem solved!
But I need to write 3x the same script and only change a class name..
If I need to create another 10 sections, a I will need to write the same script 10x..
There is a way to avoid this?
SORRY! I'M A BEGINNER IN JS.. I understand many things, but I'm not a expert.
var $animation_elements = $('.animation-element');
var $window = $(window);
const MULTIPLIER = 800;
var countInView = 0;
var timeouts = [];
for (i = 0; i < $animation_elements.length; i++)
timeouts[i] = [];
function check_if_in_view() {
var window_height = $window.height();
var window_top_position = $window.scrollTop();
var window_bottom_position = (window_top_position + window_height + 15);
for(var i=0; i < $animation_elements.length ; i++) {
var $element = $animation_elements.eq(i);
var element_height = $element.outerHeight();
var element_top_position = $element.offset().top;
var element_bottom_position = (element_top_position + element_height);
if ((element_bottom_position >= window_top_position) &&
(element_top_position <= window_bottom_position)) {
if($element.is($('i').parent()) && !$element.hasClass('in-view')) {
var delay = MULTIPLIER * ++countInView;
$element.addClass('paused');
(function(delay, $element, savedtimeout){
savedtimeout[i][0] = setTimeout(function() {
$element.removeClass('paused');
countInView--;
}, delay);
}(delay, $element, timeouts));
}
$element.addClass('in-view');
} else {
if($element.hasClass('in-view')) {
$element.removeClass('in-view');
}
if($element.hasClass('paused')) {
if(timeouts[i][0] != null) {
//Retira o timeout da fila
clearTimeout(timeouts[i][0]);
countInView--;
}
$element.removeClass('paused');
} // end if
} // end if
} // end for
}
$window.on('scroll resize', check_if_in_view);
$window.trigger('scroll');
Then i change:
var $animation_elements = $('.animation-element');
var $animation_elements = $('.animation-element2');
var $animation_elements = $('.animation-element3');
And copy+paste all the rest

Text pagination inside a DIV with image

I want to paginate a text in some div so it will fit the allowed area
Logic is pretty simple:
1. split text into words
2. add word by word into and calculate element height
3. if we exceed the height - create next page
It works quite good
here is JS function i've used:
function paginate() {
var newPage = $('<pre class="text-page" />');
contentBox.empty().append(newPage);
var betterPageText='';
var pageNum = 0;
var isNewPage = false;
var lineHeight = parseInt(contentBox.css('line-height'), 10);
var wantedHeight = contentBox.height() - lineHeight;
for (var i = 0; i < words.length; i++) {
if (isNewPage) {
isNewPage = false;
} else {
betterPageText = betterPageText + ' ' + words[i];
}
newPage.text(betterPageText + ' ...');
if (newPage.height() >= wantedHeight) {
pageNum++;
if (pageNum > 0) {
betterPageText = betterPageText + ' ...';
}
newPage.text(betterPageText);
newPage.clone().insertBefore(newPage)
betterPageText = '...';
isNewPage = true;
} else {
newPage.text(betterPageText);
}
}
contentBox.craftyslide({ height: wantedHeight });
}
But when i add an image it break everything. In this case text overflows 'green' area.
Working fiddle: http://jsfiddle.net/74W4N/7/
Is there a better way to paginate the text and calculate element height?
Except the fact that there are many more variables to calculate,not just only the word width & height, but also new lines,margins paddings and how each browser outputs everything.
Then by adding an image (almost impossible if the image is higher or larger as the max width or height) if it's smaller it also has margins/paddings. and it could start at the end of a line and so break up everything again.basically only on the first page you could add an image simply by calculating it's width+margin and height+margin/lineheight. but that needs alot math to get the wanted result.
Said that i tried some time ago to write a similar script but stopped cause of to many problems and different browser results.
Now reading your question i came across something that i read some time ago:
-webkit-column-count
so i made a different approach of your function that leaves out all this calculations.
don't judge the code as i wrote it just now.(i tested on chrome, other browsers need different prefixes.)
var div=document.getElementsByTagName('div')[0].firstChild,
maxWidth=300,
maxHeigth=200,
div.style.width=maxWidth+'px';
currentHeight=div.offsetHeight;
columns=Math.ceil(currentHeight/maxHeigth);
div.style['-webkit-column-count']=columns;
div.style.width=(maxWidth*columns)+'px';
div.style['-webkit-transition']='all 700ms ease';
div.style['-webkit-column-gap']='0px';
//if you change the column-gap you need to
//add padding before calculating the normal div.
//also the line height should be an integer that
// is divisible of the max height
here is an Example
http://jsfiddle.net/HNF3d/10/
adding an image smaller than the max height & width in the first page would not mess up everything.
and it looks like it's supported by all modern browsers now.(with the correct prefixes)
In my experience, trying to calculate and reposition text in HTML is almost an exercise in futility. There are too many variations among browsers, operating systems, and font issues.
My suggestion would be to take advantage of the overflow CSS property. This, combined with using em sizing for heights, should allow you to define a div block that only shows a defined number of lines (regardless of the size and type of the font). Combine this with a bit of javascript to scroll the containing div element, and you have pagination.
I've hacked together a quick proof of concept in JSFiddle, which you can see here: http://jsfiddle.net/8CMzY/1/
It's missing a previous button and a way of showing the number of pages, but these should be very simple additions.
EDIT: I originally linked to the wrong version for the JSFiddle concept
Solved by using jQuery.clone() method and performing all calculations on hidden copy of original HTML element
function paginate() {
var section = $('.section');
var cloneSection = section.clone().insertAfter(section).css({ position: 'absolute', left: -9999, width: section.width(), zIndex: -999 });
cloneSection.css({ width: section.width() });
var descBox = cloneSection.find('.holder-description').css({ height: 'auto' });
var newPage = $('<pre class="text-page" />');
contentBox.empty();
descBox.empty();
var betterPageText = '';
var pageNum = 0;
var isNewPage = false;
var lineHeight = parseInt(contentBox.css('line-height'), 10);
var wantedHeight = contentBox.height() - lineHeight;
var oldText = '';
for (var i = 0; i < words.length; i++) {
if (isNewPage) {
isNewPage = false;
descBox.empty();
}
betterPageText = betterPageText + ' ' + words[i];
oldText = betterPageText;
descBox.text(betterPageText + ' ...');
if (descBox.height() >= wantedHeight) {
if (i != words.length - 1) {
pageNum++;
if (pageNum > 0) {
betterPageText = betterPageText + ' ...';
}
oldText += ' ... ';
}
newPage.text(oldText);
newPage.clone().appendTo(contentBox);
betterPageText = '... ';
isNewPage = true;
} else {
descBox.text(betterPageText);
if (i == words.length - 1) {
newPage.text(betterPageText).appendTo(contentBox);
}
}
}
if (pageNum > 0) {
contentBox.craftyslide({ height: wantedHeight });
}
cloneSection.remove();
}
live demo: http://jsfiddle.net/74W4N/19/
I actually came to an easier solution based on what #cocco has done, which also works in IE9.
For me it was important to keep the backward compatibility and the animation and so on was irrelevant so I stripped them down. You can see it here: http://jsfiddle.net/HNF3d/63/
heart of it is the fact that I dont limit height and present horizontal pagination as vertical.
var parentDiv = div = document.getElementsByTagName('div')[0];
var div = parentDiv.firstChild,
maxWidth = 300,
maxHeigth = 200,
t = function (e) {
div.style.webkitTransform = 'translate(0,-' + ((e.target.textContent * 1 - 1) * maxHeigth) + 'px)';
div.style["-ms-transform"] = 'translate(0,-' + ((e.target.textContent * 1 - 1) * maxHeigth) + 'px)';
};
div.style.width = maxWidth + 'px';
currentHeight = div.offsetHeight;
columns = Math.ceil(currentHeight / maxHeigth);
links = [];
while (columns--) {
links[columns] = '<span>' + (columns + 1) + '</span>';
}
var l = document.createElement('div');
l.innerHTML = links.join('');
l.onclick = t;
document.body.appendChild(l)

ProcessMessages() in Javascript

I want to drop a div down to a certain height to display some additional content. For that I wrote following dropbox() function:
<script type="text/javascript">
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
function dropbox(element){
var obj = document.getElementById(element);
if(obj) {
var element = document.getElementById(element),
style = window.getComputedStyle(element),
height = style.getPropertyValue('height');
height = height.substring(0,2);
var i = 0;
for (i = height; i<200; i++)
{
sleep(100);
var tst = i+"px";
//alert(tst);
obj.style.height = tst;
}
//alert(i);
} else {
}
}
</script>
Now the problem I'm experiencing is, the box actually isn't visible during the roll down process but only after the loop has completed but I want it to look like the "Check Availability"-box on http://www.thedana.com/. How do I get this accomplished?
Thank you!
Here is a sample code. It may help you
<div class="right_content">
We deliver quick and easy registration.
Mysites.com is our hosting server and we've buit our website under observation of Mysite.com
</div>
<p class="flip">Know About us</p>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js">
</script>
<script type="text/javascript">
$(document).ready(function(){
$(".flip").mouseover(function(){
$(".right_content").slideToggle("slow");
});
});
</script>
You cannot use looping delays in browser javascript as it will make the browser unresponsive to both input and screen updating and waste the battery on a mobile device.
Instead, you should use setTimeout() which lets you schedule an activity for some time in the future. Good animation uses a tweening algorithm that schedules the next tick of the animation, then compares the elapsed time and calculates where the next animation step should be drawn and is continually self correcting in this way.
Also, if you do a Google search for javascript animation, you will find many helpful pieces of prewritten code for doing animation with plain javascript. In addition, all the major javascript libraries (such as jQuery or YUI) have significant animation capabilities built in and already written for you.
Here's a simple example:
function dropbox(elem, finalHt, duration) {
var start = new Date().getTime();
var tick = 20;
var startHt = parseInt(elem.style.height, 10);
var growHt = finalHt - startHt;
function next() {
var now = new Date().getTime();
var percent = (now - start) / duration;
var target = Math.round(startHt + (growHt * percent));
elem.style.height = Math.min(target, finalHt) + "px";
if (target < finalHt) {
setTimeout(next, tick);
}
}
setTimeout(next, tick);
}
function run() {
var item = document.getElementById("box");
item.style.height = "10px";
dropbox(item, 300, 2000);
}
Working example and more generalized code: http://jsfiddle.net/jfriend00/QxXMK/

Categories