I have a text static text element that changes when user scrolls more than 600px and again when it scrolls more than 1400px
$(window).scroll(function () {
if ($(this).scrollTop() > 600) {
$('.p-circle').html('Text 1');
$('.p-circle-s').html('Text 2');
}
});
$(window).scroll(function () {
if ($(this).scrollTop() > 1400) {
$('.p-circle').html('Text 1 updated');
$('.p-circle-s').html('Text 2 updated');
}
});
How can I make a basic animation of fading for them, I tried next variants and they don't work well (it is fading 2 times)
if (scrollTop > 600 && scrollTop <= 1400) {
$('.p-circle').fadeOut(500, function() {
$(this).text('Text 1').fadeIn(500);
});
$('.p-circle-s').fadeOut(500, function() {
$(this).text('Text 2').fadeIn(500);
});
} else if (scrollTop > 1400 && scrollTop <= 2100) {
$('.p-circle').fadeOut(500, function() {
$(this).text('Text 1 updated').fadeIn(500);
});
$('.p-circle-s').fadeOut(500, function() {
$(this).text('Text 2 Updated').fadeIn(500);
});
}
I think you're on the right track, however your logic in that last bit there isn't testing whether the transition already happened. Something along the lines of:
if ($(this).scrollTop() > 600 && $(this).scrollTop() <= 1400 && $(".p-circle").text() != 'Text 1')
I think I got your values wrong, but here's a fiddle to get you on the right track...
https://jsfiddle.net/64mj3k7n/3/
A better solution would be to create a function (or Class) Waypoints, to be used like:
Waypoints(window, [0, 100, 600, 1400], (wp) => {
console.log(wp); // {index:Int, value:Int}
});
which accepts three arguments:
an Element (or String selector) to scroll-watch
an Array of scrollY waypoints values
a callback Function
The callbacks is triggered only once a scroll index changes — in order to prevent buildups on every scroll Event call.
/**
* Waypoints
* Trigger callbacks on a scrollY milestone
* #url https://stackoverflow.com/a/70520524/383904
* #param {string|object} el String selector or Element object
* #param {array} waypoints Array of px from lower to higher
* #param {function} cb Callback function
*/
function Waypoints(el, waypoints = [0], cb) {
el = (typeof el === "string") ? document.querySelector(el) : el;
const wp = [...waypoints].reverse();
const wpTot = wp.length;
const getIndex = (n) => {
const i = wp.findIndex(m => m <= n);
return wpTot - 1 - (i < 0 ? wpTot : i);
};
let index = -1;
const getTask = () => {
const i = getIndex(el.scrollY);
if (index === i) return; // No task to trigger
index = i; // Update index
const value = wp[wpTot - 1 - i]; // Get the waypoint name
cb({ index, value }); // Trigger the callback
};
el.addEventListener("scroll", getTask);
window.addEventListener("DOMContentLoaded", () => getTask);
window.addEventListener("load", () => getTask);
getTask();
}
/**
* YOUR APP:
*/
const $circle1 = $('.p-circle');
const $circle2 = $('.p-circle-s');
const circle1txt = ["Text 1 scroll", "Text 1", "Text 1 updated"];
const circle2txt = ["Text 2 scroll", "Text 2", "Text 2 updated"];
Waypoints(window, [0, 600, 1400], (wp) => {
$circle1.fadeOut(500, () => {
$circle1.text(circle1txt[wp.index]).fadeIn(500);
});
$circle2.fadeOut(500, () => {
$circle2.text(circle2txt[wp.index]).fadeIn(500);
});
});
body { height: 3000px; } /* Just to force some scrollbars for this demo */
[class^="p-"] { position: fixed; }
.p-circle-s { top: 2rem; }
<div class="p-circle"></div>
<div class="p-circle-s"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
Related
Selenium:
I am new to WebDriverJS. I have tried this approach in Java.
Long repaeted = 0l, scrollHeight = 0l, returnHeight = 0l;
while(true){
if (repaeted == 0) {
returnHeight = (Long) jse.executeScript("var scroll =document.documentElement.scrollHeight;window.scrollTo(0, scroll); return scroll;");
System.out.println("Height : "+scrollHeight +"\t Chnage : "+returnHeight+ "\t Repeated : "+repaeted);
scrollHeight = returnHeight;
}else {
returnHeight = (Long) jse.executeScript("var scroll = document.documentElement.scrollHeight;window.scrollTo(0, scroll); return scroll;");
System.out.println("Height : "+scrollHeight +"\t Chnage : "+returnHeight+ "\t Repeated : "+repaeted);
if (scrollHeight.intValue() == returnHeight.intValue()) {
System.out.println("Break.."+ returnHeight);
break;
} else { scrollHeight = returnHeight; }
}
repaeted++;
}
but I am facing problem in webdriverjs while iterating the loop.
var webdriver = require('..'),
By = webdriver.By,
until = webdriver.until;
// make sure chromedriver can be found on your system PATH
var driver = new webdriver.Builder()
.forBrowser('chrome')
.withCapabilities(webdriver.Capabilities.chrome())
.build();
driver.get('https://in.yahoo.com/').then(function(){
var window = new webdriver.WebDriver.Window(driver);
window.maximize();
driver.manage().timeouts().implicitlyWait(1000 * 3);
})
.then(function(){
console.log('Entered');
var check = 0, count = 0
for(var i = 0; i< 50; i++){
//driver.sleep(1000 * 2);
driver.executeScript('var dynamicscroll = document.documentElement.scrollHeight;window.scrollTo(0, dynamicscroll);return dynamicscroll;').then(function(height){
console.log('Check : '+check+' Height : '+height +' Repeated : '+(count++));
if(check === 0 || check !== height){console.log('continue'); check = height; }
else { console.log('break'); i = 100; }
});
}
})
.then(null, function(err) {
console.error("An error was thrown! By Promise..." + err);
});
driver.quit();
In my code I have hardcoded for loop to iterate until 50 times and I want to quit/break the loop when the scroll height is reached to end. In this approach, I want to remove hardcode like java-code because I don't know how many times to iterate for other applications whose scroll is kept on increasing dynamically.
For example, Facebook application, Yahoo News...
Scrolling to the bottom of a dynamic page can be challenging depending on how it is implemented by the page.
First you'll have to find the container with the scrollbar since it can be different from the one linked to window.scrollTo.
Then scroll the container by increasing scrollTop until the scrollHeight becomes steady with no pending requests. To check if there are pending requests, either evalute jQuery.active if the page has JQuery or hook XMLHttpRequest to monitor the calls on send.
Here is an example using on a generic function to scroll to the bottom of the page a number of times or until the end:
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().forBrowser('chrome').build();
driver.get('https://groups.google.com/forum/#!search/webdriverjs');
// scroll to the bottom 3 times
driver.executeAsyncScript(scrollBottom, 3)
.then(n => console.log(`scrolled ${n} time(s)`));
// scroll to the bottom until the end
driver.executeAsyncScript(scrollBottom)
.then(n => console.log(`scrolled ${n} time(s)`));
function scrollBottom(){
var count = arguments[arguments.length - 2] || 0x7fffffff;
var callback = arguments[arguments.length - 1];
/* get the scrollable container */
var elm = document.elementFromPoint(window.innerWidth - 25, window.innerHeight / 2);
for ( ;elm && (++elm.scrollTop, !elm.scrollTop); elm=elm.parentElement);
elm = elm || document.documentElement;
/* hook XMLHttpRequest to monitor Ajax requests */
if (!('idle' in XMLHttpRequest)) (function(){
var n = 0, t = Date.now(), send = XMLHttpRequest.prototype.send;
var dispose = function(){ --n; t = Date.now(); };
var loadend = function(){ setTimeout(dispose, 1) };
XMLHttpRequest.idle = function() { return n > 0 ? 0 : Date.now() - t; };
XMLHttpRequest.prototype.send = function(){
++n;
this.addEventListener('loadend', loadend);
send.apply(this, arguments);
};
})();
/* scroll until steady scrollHeight or count of scroll and no pending request */
var i = 0, scrollHeight = -1, scrollTop = -1;
(function scroll(){
if ((scrollHeight === elm.scrollHeight || i === count) && XMLHttpRequest.idle() > 60)
return callback(i);
scrollTop = elm.scrollTop;
scrollHeight = elm.scrollHeight;
if (i < count)
i += (elm.scrollTop = 0x7fffffff, scrollTop !== elm.scrollTop);
setTimeout(scroll, 100);
})();
}
Or by scrolling until the height no longer increases during a specific time (5 seconds here) :
function scrollBottom(){
var count = arguments[arguments.length - 2] || 0x7fffffff;
var callback = arguments[arguments.length - 1];
var timeout = 5000; /* 5 seconds timeout */
var i = 0;
/* get the scrollable container */
var elm = document.elementFromPoint(window.innerWidth - 25, window.innerHeight / 2);
for ( ;elm && (++elm.scrollTop, !elm.scrollTop); elm=elm.parentElement);
elm = elm || document.documentElement;
/* scroll while the height is increasing or until timeout */
(function scroll(){
var endtime = Date.now() + timeout;
var height = elm.scrollHeight;
elm.scrollTop = 0x7fffffff; /* scroll */
setTimeout(function check(){
if (Date.now() > endtime) /* returns if waited more than 5 sec */
callback(i);
else if (elm.scrollHeight == height) /* wait again if same height */
setTimeout(check, 60);
else if (++i === count) /* returns if scrolled the expected count */
callback(i);
else /* scroll again */
setTimeout(scroll, 60);
}, 250);
})();
}
From experience, the quickest way to scroll to the end of a page is to look for the footer element and movetoit, usually #footer or .footer or just footer selector will do it. E.g.:
footer = driver.findElement({id: "footer"});
driver.executeScript("arguments[0].scrollIntoView(false);", footer);
In the case of 'endless' streams like Facebook, Twitter, etc. They may block you when you reach a limit so it's okay to combine max iterations with window.scrollTo(0, 300); recursively and wait for some seconds after each scroll.
Pure JavaScript:
In JavaScript we can use setTimeout() function. which will call the specified function recursively after the time delay you specified.
I have tested the google groups application, whose div tag vertical scroll dynamically increases. To load the content I used the time delay of 5000. you can test this code in browser's console use this URL: https://groups.google.com/forum/#!search/webdrierjs.
var i = 0, height = 0, check = 0, t = null;
flow();
function run(arg){
var objDiv = document.querySelector('div.IVILX2C-b-F');
objDiv.scrollTop = objDiv.scrollHeight;
return objDiv.scrollHeight;
}
function flow() {
i++;
switch(i){
case 0: height = run(i);
sleep(5000);
break;
case -1: run(i);
clearTimeout(t); //stops flow
break;
default: check = run(i);
console.log('Return Height : '+check +' Count : '+i);
if(check === height){ i = -2;
console.log('Break message : '+i);
}else {
console.log('Changed...');
height = check;
}
sleep(5000);
break;
}
}
function sleep(delay) { t=setTimeout("flow()",delay);} //starts flow control again after time specified.
//function sleep(delay) { var start = new Date().getTime(); while (new Date().getTime() < start + delay); flow(); } // stops execution and then continues.
but even I cannot run this script using WebDriver/WebDriverJS because it is not going to call recursive function on time delay.
I am aware that this is kind of an old topic, yet I've still came across it while I had similar problem. Given sollutions didn't quite suite me.
I wrote my own function - without using any "arguments[...]" as argument of driver.executeScript(...).
...I just don't get that "arguments[...]" to be honest... x)
Below I'm presenting my solution.
(I believe its shorter and cleaner. And uses async/await syntax instead of ".then(s)")
// scroller.service.ts
import { WebDriver } from 'selenium-webdriver';
export async function scrollTillEnd(driver: WebDriver): Promise<void> {
const scrollDownTillEnd = async () => {
let counter = 0
let heightBefore = 0
let heightAfter = 0
let shouldContinue = true
const scrollDown = () => window.scrollBy(0, document.body.scrollHeight || document.documentElement.scrollHeight)
const scrollAndCalc = async () => {
heightBefore = document.body.scrollHeight || document.documentElement.scrollHeight
scrollDown()
await new Promise((res) => setTimeout(() => res(null), 2000)) // sleep in vanillaJS
heightAfter = document.body.scrollHeight || document.documentElement.scrollHeight
shouldContinue = heightAfter != heightBefore
counter++
console.log({ shouldContinue, heightBefore, heightAfter, counter })
}
while (shouldContinue) {
await scrollAndCalc()
}
}
await driver.executeScript(scrollDownTillEnd)
}
(executed on chrome 97 )
// example usage:
class App{
// ...
private async initDriver() {
this.driver = await new DriverInitiator().getDriver()
await this.driver.get(this.url)
}
private initPagesModels() {
this.cookiesWelcome = new CookiesWelcomePage(this.driver)
}
async runExample() {
await this.initDriver()
this.initPagesModels()
await this.driver.sleep(1000)
await this.cookiesWelcome.acceptCookies()
await scrollTillEnd(this.driver) // this is the part where i call my scrolling function :)
console.log("selenium script ended.")
await this.driver.sleep(5000)
await this.driver.quit();
}
}
I built a slider that moves left or right if some items are hidden. Obviously this needs to work responsively, so I am using a resize (smartresize) function to check when the browser is resized. It works, but after resizing when you click more (right arrow) it takes 2-5 seconds to actually calculate what is hidden and then execute.
Can anyone explain to me why this is happening, and how to possibly fix it?
Thanks!
$(window).smartresize(function () {
var cont = $('#nav-sub-menu-2 .container');
var ul = $('#nav-sub-menu-2 ul');
var li = $('#nav-sub-menu-2 ul li');
var amount = li.length;
var width = li.width();
var contWidth = cont.width();
var ulWidth = width * amount;
var remainder = ulWidth - contWidth;
ul.width(ulWidth);
if(remainder <= 0) {
$('.more, .less').fadeOut();
} else {
$('.more').fadeIn();
}
$('.more').click(function() {
ul.animate({ 'right' : remainder });
$(this).fadeOut();
$(".less").fadeIn();
});
$('.less').click(function() {
ul.animate({ 'right' : 0 });
$(this).fadeOut();
$(".more").fadeIn();
});
}).smartresize();
It could be because it is recalculating the screen size at every interval as you are resizing...
Try using a debouncer to delay the function calls until everything's settled.
/* Debounce Resize */
function debouncer( func , timeout ) {
var timeoutID , timeout = timeout || 200;
return function () {
var scope = this , args = arguments;
clearTimeout( timeoutID );
timeoutID = setTimeout( function () {
func.apply( scope , Array.prototype.slice.call( args ) );
} , timeout );
}
}
$( window ).resize( debouncer( function ( e ) {
/* Function */
}));
This is the markup for my navigation:
<div class="navigation navigation-fixed-top">
Home
About
</div>
And I have this jquery script, which is checking if href="#home" has class active to do something and if not to do something else.
This is the code:
var isActive = $('a[href="#home"]').hasClass('active');
$(".navigation")
.toggleClass("navigation-fixed-bottom", isActive)
.toggleClass("navigation-fixed-top", !isActive);
This is partially working because the class="active" is added automatically when I'm going the #about section or I'm clicking on it. It does this without refreshing the page so I need a way to to make this work without refreshing the page.
Any suggestions on how can I do this with jQuery/Javascript ?
UPDATE:
this is the name of the plugin Scrollit.js
THIS IS THE CODE RESPONSIBLE FOR ADDING THE ACTIVE CLASS ON THE NAVIGATION ELEMENTS:
(function($) {
'use strict';
var pluginName = 'ScrollIt',
pluginVersion = '1.0.3';
/*
* OPTIONS
*/
var defaults = {
upKey: 38,
downKey: 40,
easing: 'linear',
scrollTime: 600,
activeClass: 'active',
onPageChange: null,
topOffset : 0
};
$.scrollIt = function(options) {
/*
* DECLARATIONS
*/
var settings = $.extend(defaults, options),
active = 0,
lastIndex = $('[data-scroll-index]:last').attr('data-scroll-index');
/*
* METHODS
*/
/**
* navigate
*
* sets up navigation animation
*/
var navigate = function(ndx) {
if(ndx < 0 || ndx > lastIndex) return;
var targetTop = $('[data-scroll-index=' + ndx + ']').offset().top + settings.topOffset + 1;
$('html,body').animate({
scrollTop: targetTop,
easing: settings.easing
}, settings.scrollTime);
};
/**
* doScroll
*
* runs navigation() when criteria are met
*/
var doScroll = function (e) {
var target = $(e.target).closest("[data-scroll-nav]").attr('data-scroll-nav') ||
$(e.target).closest("[data-scroll-goto]").attr('data-scroll-goto');
navigate(parseInt(target));
};
/**
* keyNavigation
*
* sets up keyboard navigation behavior
*/
var keyNavigation = function (e) {
var key = e.which;
if(key == settings.upKey && active > 0) {
navigate(parseInt(active) - 1);
return false;
} else if(key == settings.downKey && active < lastIndex) {
navigate(parseInt(active) + 1);
return false;
}
return true;
};
/**
* updateActive
*
* sets the currently active item
*/
var updateActive = function(ndx) {
if(settings.onPageChange && ndx && (active != ndx)) settings.onPageChange(ndx);
active = ndx;
$('[data-scroll-nav]').removeClass(settings.activeClass);
$('[data-scroll-nav=' + ndx + ']').addClass(settings.activeClass);
};
/**
* watchActive
*
* watches currently active item and updates accordingly
*/
function navPosition() {
$('[data-scroll-nav]').toggleClass('navigation-fixed-bottom navigation-fixed-top');
}
var updateActive = function(ndx, navPosition) {
var watchActive = function() {
var winTop = $(window).scrollTop();
var visible = $('[data-scroll-index]').filter(function(ndx, div) {
return winTop >= $(div).offset().top + settings.topOffset &&
winTop < $(div).offset().top + (settings.topOffset) + $(div).outerHeight()
});
var newActive = visible.first().attr('data-scroll-index');
updateActive(newActive);
};
/*
* runs methods
*/
$(window).on('scroll',watchActive).on('scroll');
$(window).on('keydown', keyNavigation);
$('body').on('click','[data-scroll-nav], [data-scroll-goto]', function(e){
e.preventDefault();
doScroll(e);
});
};
}(jQuery));
$('[data-scroll-nav]').removeClass(settings.activeClass)
.toggleClass('navigation-fixed-bottom navigation-fixed-top');
and/or
$('[data-scroll-nav=' + ndx + ']').addClass(settings.activeClass)
.toggleClass('navigation-fixed-bottom navigation-fixed-top');
If you wanted to keep the original code cleaner, you could do a callback:
function myCallBackFunction() {
$('[data-scroll-nav]').toggleClass('navigation-fixed-bottom navigation-fixed-top');
}
var updateActive = function(ndx, myCallbackFunction) {..}
use jquery on to bind handlers to events you want to respond
$("a.active").on('click',function(){});
I have a gallery of three Grids with images. The grid sizes changes depending on the screen size, and I have achieved that using Media-Query - ie, on desktop the grid's width will be 33% to make three columns view next to each other, and on tablet it will be 50% to make two columns view, and on phone it will be a 100% for each grid making one column view.
The reason I did this is to create a tiled gallery with images of different heights - and if I did it the normal way it will generate White-empty-spaces when floating.
So to fix this problem, and with the help of few members on this website, we have created a JavaScrip function that will MOVE all of the images that are inside Grid3 equally to Grid1 & Grid2 when screen size is tablet, so we get rid of the third grid making a view of fine two columns. Everything is working great!
Now, the problem is - on Chrome & IE - The function is being fired before its time for some reason that I need your help to help me find it! Please try it your self here: [http://90.195.175.51:93/portfolio.html][2]
Slowly on Chrome or IE - (try it on Firefox as well) - try to re-size the window from large to small, you will notice that BEFORE the top header changes to be a responsive Header (which indicate that you are on a small screen) the images have been sent to Grid1 and Grid 2! but a few px before the time. As on the function it says to fire it on <770.
Hope my question is clear enough for you to help me solve this issue which is stopping me from launching my website. Thanks.
Here is the JavaScrip:
//Gallery Grid System//
var testimonial = $(".testimonial, .galleryItem", "#grid3");
(function () {
$(document).ready(GalleryGrid);
$(window).resize(GalleryGrid);
})(jQuery);
function GalleryGrid() {
var grid3 = $('#grid3');
var width = $(window).width();
if (width < 1030 && width > 770) {
var grid1 = $('#grid1');
var grid2 = $('#grid2');
for (var i = 0; i < testimonial.length; i++) {
if (i < testimonial.length / 2) {
grid1.append(testimonial[i]);
} else {
grid2.append(testimonial[i]);
}
}
} else {
grid3.append(testimonial);
}
}
Note: The following is the whole page with all the functions:
$(document).ready(function () {
//Prevent clicking on .active links
$('.active').click(function (a) {
a.preventDefault();
});
//Allow :active on touch screens
document.addEventListener("touchstart", function () {}, true);
//Hide toolbar by default
window.addEventListener('load', function () {
setTimeout(scrollTo, 0, 0, 0);
}, false);
//Scroll-up button
$(window).scroll(function () {
if ($(this).scrollTop() > 100) {
$('.scrollup').fadeIn();
} else {
$('.scrollup').fadeOut();
}
});
$('.scrollup').click(function () {
$("html, body").animate({
scrollTop: 0
}, 600);
return false;
});
//StickyBox
$(function () {
$.fn.scrollBottom = function () {
return $(document).height() - this.scrollTop() - this.height();
};
var $StickyBox = $('.detailsBox');
var $window = $(window);
$window.bind("scroll resize", function () {
var gap = $window.height() - $StickyBox.height() - 10;
var footer = 288 - $window.scrollBottom();
var scrollTop = $window.scrollTop();
$StickyBox.css({
top: 'auto',
bottom: 'auto'
});
if ($window.width() <= 770) {
return;
$StickyBox.css({
top: '0',
bottom: 'auto'
});
}
if (scrollTop < 50) {
$StickyBox.css({
bottom: "auto"
});
} else if (footer > gap - 100) {
$StickyBox.css({
top: "auto",
bottom: footer + "px"
});
} else {
$StickyBox.css({
top: 80,
bottom: "auto"
});
}
});
});
//Change items location depending on the width of the screen//
$(function () { //Load Ready
function myFunction() {
var insert = $(window).width() <= 770 ? 'insertBefore' : 'insertAfter';
$('#home-sectionB img')[insert]($('#home-sectionB div'));
$('#home-sectionD img')[insert]($('#home-sectionD div'));
}
myFunction(); //For When Load
$(window).resize(myFunction); //For When Resize
});
//Contact Form//
$(".input").addClass('notSelected');
$(".input").focus(function () {
$(this).addClass('selected');
});
$(".input").focusout(function () {
$(this).removeClass('selected');
});
$(document).ready(function () {
GalleryGrid();
$(window).resize(GalleryGrid);
});
//Gallery Grid System//
var testimonial = $(".testimonial, .galleryItem", "#grid3");
(function () {
$(document).ready(GalleryGrid);
$(window).resize(GalleryGrid);
})(jQuery);
function GalleryGrid() {
var grid3 = $('#grid3');
var width = $(window).width();
if (width < 1030 && width > 770) {
var grid1 = $('#grid1');
var grid2 = $('#grid2');
for (var i = 0; i < testimonial.length; i++) {
if (i < testimonial.length / 2) {
grid1.append(testimonial[i]);
} else {
grid2.append(testimonial[i]);
}
}
} else {
grid3.append(testimonial);
}
}
//Testimonials Animation//
$(".testimonial").hover(function () {
$(".testimonial").addClass('testimonialNotActive');
$(this).removeClass('testimonialNotActive').addClass('testimonialActive');
},
function () {
$(".testimonial").removeClass('testimonialNotActive');
$(this).removeClass('testimonialActive');
});
//Portfolio Gallery Filter//
(function () {
var $portfolioGallerySection = $('#portfolio-sectionB'),
$filterbuttons = $('#portfolio-sectionA a');
$filterbuttons.on('click', function () {
var filter = $(this).data('filter');
$filterbuttons.removeClass('portfolio-sectionAClicked');
$(this).addClass('portfolio-sectionAClicked');
$portfolioGallerySection.attr('class', filter);
$('.galleryItem').removeClass('selectedFilter');
$('.galleryItem.' + filter).addClass('selectedFilter');
});
}());
});
Your problem is that CSS media queries and jQuery's $(window).width() do not always align.
function getCSSWidth() {
var e = window, a = 'inner';
if (!('innerWidth' in window )) {
a = 'client';
e = document.documentElement || document.body;
}
return e[ a+'Width' ];
}
Use this instead of $(window).width()
modified from http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/
I think this could solve your problem (but I'm not quite sure)
//Put that before the document ready event
(function($,sr){
// debouncing function from John Hann
// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
};
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
}
// smartresize
jQuery.fn[sr] = function(fn){ return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
})(jQuery,'smartresize');
// Here you call GalleryGrid (replace $(window).resize(GalleryGrid) with that):
$(window).smartresize(GalleryGrid);
http://www.paulirish.com/2009/throttled-smartresize-jquery-event-handler/
The reason is your vertical scrollbar. Your content is fixed at width=1030, but when the window size is 1030, the size of the viewport is actually: window size (1030) - vertical scroll bar
Try setting
<body style="overflow:hidden">
You will see that it works correctly when the scrollbar is removed. Or try setting:
<link href="assets/css/tablets-landscape.css" rel="stylesheet" type="text/css" media="screen and (max-width : 1045px)"/>
Set max-width:1045px to make up for scrollbar, you will see that it works correctly.
Your javascript should be like this:
var width = $(window).width() + verticalscrollbarWidth;
The code (from an old plugin that I am trying to make responsive) slides a set of images across every n seconds. It uses setInterval code as below, and works well on Firefox. On Chrome it runs once only, and debugging indicates that the second setInteral function is just not called. Please help as its diving me mad. Running example at http://lelal.com/test/site10/index.html (sorry about the load time)
play = setInterval(function() {
if (!busy) {
busy = true;
updateCurrent(settings.direction);
slide();
}
}, settings.speed);
The complete plugin code is below (sorry its long)
/*
* jQuery Queue Slider v1.0
* http://danielkorte.com
*
* Free to use and abuse under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*/
(function($){
var QueueSlider = function(element, options) {
var play = false,
busy = false,
current = 2,
previous = 2,
widths = [],
slider = $(element),
queue = $('ul.queue', slider),
numImages = $('img', queue).size(),
viewportWidth = slider.width(),
settings = $.extend({}, $.fn.queueSlider.defaults, options);
$(window).resize(function(){
if(busy !== false)
clearTimeout(busy);
busy = setTimeout(resizewindow, 200); //200 is time in miliseconds
});
function resizewindow() {
viewportWidth = slider.width();
if (settings.scale > 0) {
slider.css('height',viewportWidth * settings.scale);
computeQueueWidth();
}
queue.css('left', -getQueuePosition());
busy = false;
}
function requeue() {
$('li', queue).each(function(key, value) {
$(this).attr('class', 'slide-' + (key+1));
});
}
function updateCurrent(dir) {
current += dir;
if (current < 1) {
current = numImages;
} else if (current > numImages) {
current = 1;
}
}
function getQueuePosition() {
var i = 0, index = current-1,
queuePosition = (viewportWidth - widths[index]) / -2;
for (i = 0; i < index; i++) { queuePosition += widths[i]; }
return queuePosition;
}
function computeQueueWidth() {
var queueWidth = 0;
// factor = slider.height() / settings.imageheight;
// settings.imageheight = settings.imageheight * factor;
// Get the image widths and set the queue width to their combined value.
$('li', queue).each(function(key, value) {
var slideimg = $("img", this),
slide = $(this),
// width = slide.width() * factor,
width = slideimg.width();
slide.css('width', width+'px');
queueWidth += widths[key] = width;
});
queue.css('width', queueWidth + 500);
}
function slide() {
var animationSettings = {
duration: settings.transitionSpeed,
queue: false
};
// Emulate an infinte loop:
// Bring the first image to the end.
if (current === numImages) {
var firstImage = $('li.slide-1', queue);
widths.push(widths.shift());
queue.css('left', queue.position().left + firstImage.width()).append(firstImage);
requeue();
current--; previous--;
}
// Bring the last image to the beginning.
else if (current === 1) {
var lastImage = $('li:last-child', queue);
widths.unshift(widths.pop());
queue.css('left', queue.position().left + -lastImage.width()).prepend(lastImage);
requeue();
current = 2; previous = 3;
}
// Fade in the current and out the previous images.
if (settings.fade !== -1) {
$('li.slide-'+current, queue).animate({opacity: 1}, animationSettings);
$('li.slide-'+previous, queue).animate({opacity: settings.fade}, animationSettings);
}
// Animate the queue.
animationSettings.complete = function() { busy = false; };
queue.animate({ left: -getQueuePosition() }, animationSettings);
previous = current;
}
//
// Setup the QueueSlider!
//
if (numImages > 2) {
// Move the last slide to the beginning of the queue so there is an image
// on both sides of the current image.
if (settings.scale > 0) {
slider.css('height',viewportWidth * settings.scale);
}
computeQueueWidth();
widths.unshift(widths.pop());
queue.css('left', -getQueuePosition()).prepend($('li:last-child', queue));
requeue();
// Fade out the images we aren't viewing.
if (settings.fade !== -1) { $('li', queue).not('.slide-2').css('opacity', settings.fade); }
// Include the buttons if enabled and assign a click event to them.
if (settings.buttons) {
slider.append('<button class="previous" rel="-1">' + settings.previous + '</button><button class="next" rel="1">' + settings.next + '</button>');
$('button', slider).click(function() {
if (!busy) {
busy = true;
updateCurrent(parseInt($(this).attr('rel'), 10));
clearInterval(play);
slide();
}
return false;
});
}
// Start the slideshow if it is enabled.
if (settings.speed !== 0) {
play = setInterval(function() {
if (!busy) {
busy = true;
updateCurrent(settings.direction);
slide();
}
}, settings.speed);
}
}
else {
// There isn't enough images for the QueueSlider!
// Let's disable the required CSS and show all one or two images ;)
slider.removeClass('queueslider');
}
};
$.fn.queueSlider = function(options) {
return this.each(function(key, value) {
var element = $(this);
// Return early if this element already has a plugin instance.
if (element.data('queueslider')) { return element.data('queueslider'); }
// Pass options to plugin constructor.
var queueslider = new QueueSlider(this, options);
// Store plugin object in this element's data.
element.data('queueslider', queueslider);
});
};
$.fn.queueSlider.defaults = {
scale: 0,
imageheight: 500,
fade: 0.3, // Opacity of images not being viewed, use -1 to disable
transitionSpeed: 700, // in milliseconds, speed for fade and slide motion
speed: 7000, // in milliseconds, use 0 to disable slideshow
direction: 1, // 1 for images to slide to the left, -1 to silde to the right during slideshow
buttons: true, // Display Previous/Next buttons
previous: 'Previous', // Previous button text
next: 'Next' // Next button text
};
}(jQuery));
Have a look here:
http://www.w3schools.com/jsref/met_win_setinterval.asp
The setInterval() method will continue calling the function until clearInterval() is called, or the window is closed.
Looks like you're calling clearInterval after the first usage of play, which makes it stop working.