I want to have 4 buttons/links on the beginning of the page, and under them the content.
On the buttons I put this code:
Scroll to element 1
Scroll to element 2
Scroll to element 3
Scroll to element 4
And under links there will be content:
<h2 id="idElement1">Element1</h2>
content....
<h2 id="idElement2">Element2</h2>
content....
<h2 id="idElement3">Element3</h2>
content....
<h2 id="idElement4">Element4</h2>
content....
It is working now, but cannot make it look more smooth.
I used this code, but cannot get it to work.
$('html, body').animate({
scrollTop: $("#elementID").offset().top
}, 2000);
Any suggestions? Thank you.
Edit: and the fiddle: http://jsfiddle.net/WxJLx/2/
Super smoothly with requestAnimationFrame
For smoothly rendered scrolling animation one could use window.requestAnimationFrame() which performs better with rendering than regular setTimeout() solutions.
A basic example looks like this. Function step is called for browser's every animation frame and allows for better time management of repaints, and thus increasing performance.
function doScrolling(elementY, duration) {
var startingY = window.pageYOffset;
var diff = elementY - startingY;
var start;
// Bootstrap our animation - it will get called right before next frame shall be rendered.
window.requestAnimationFrame(function step(timestamp) {
if (!start) start = timestamp;
// Elapsed milliseconds since start of scrolling.
var time = timestamp - start;
// Get percent of completion in range [0, 1].
var percent = Math.min(time / duration, 1);
window.scrollTo(0, startingY + diff * percent);
// Proceed with animation as long as we wanted it to.
if (time < duration) {
window.requestAnimationFrame(step);
}
})
}
For element's Y position use functions in other answers or the one in my below-mentioned fiddle.
I set up a bit more sophisticated function with easing support and proper scrolling to bottom-most elements:
https://jsfiddle.net/s61x7c4e/
Question was asked 5 years ago and I was dealing with smooth scroll and felt giving a simple solution is worth it to those who are looking for. All the answers are good but here you go a simple one.
function smoothScroll(){
document.querySelector('.your_class or #id here').scrollIntoView({
behavior: 'smooth'
});
}
just call the smoothScroll function on onClick event on your source element.
DOCS: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Note: Please check compatibility here
3rd Party edit
Support for Element.scrollIntoView() in 2020 is this:
Region full + partial = sum full+partial Support
Asia 73.24% + 22.75% = 95.98%
North America 56.15% + 42.09% = 98.25%
India 71.01% + 20.13% = 91.14%
Europe 68.58% + 27.76% = 96.35%
Just made this javascript only solution below.
Simple usage:
EPPZScrollTo.scrollVerticalToElementById('signup_form', 20);
Engine object (you can fiddle with filter, fps values):
/**
*
* Created by Borbás Geri on 12/17/13
* Copyright (c) 2013 eppz! development, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
var EPPZScrollTo =
{
/**
* Helpers.
*/
documentVerticalScrollPosition: function()
{
if (self.pageYOffset) return self.pageYOffset; // Firefox, Chrome, Opera, Safari.
if (document.documentElement && document.documentElement.scrollTop) return document.documentElement.scrollTop; // Internet Explorer 6 (standards mode).
if (document.body.scrollTop) return document.body.scrollTop; // Internet Explorer 6, 7 and 8.
return 0; // None of the above.
},
viewportHeight: function()
{ return (document.compatMode === "CSS1Compat") ? document.documentElement.clientHeight : document.body.clientHeight; },
documentHeight: function()
{ return (document.height !== undefined) ? document.height : document.body.offsetHeight; },
documentMaximumScrollPosition: function()
{ return this.documentHeight() - this.viewportHeight(); },
elementVerticalClientPositionById: function(id)
{
var element = document.getElementById(id);
var rectangle = element.getBoundingClientRect();
return rectangle.top;
},
/**
* Animation tick.
*/
scrollVerticalTickToPosition: function(currentPosition, targetPosition)
{
var filter = 0.2;
var fps = 60;
var difference = parseFloat(targetPosition) - parseFloat(currentPosition);
// Snap, then stop if arrived.
var arrived = (Math.abs(difference) <= 0.5);
if (arrived)
{
// Apply target.
scrollTo(0.0, targetPosition);
return;
}
// Filtered position.
currentPosition = (parseFloat(currentPosition) * (1.0 - filter)) + (parseFloat(targetPosition) * filter);
// Apply target.
scrollTo(0.0, Math.round(currentPosition));
// Schedule next tick.
setTimeout("EPPZScrollTo.scrollVerticalTickToPosition("+currentPosition+", "+targetPosition+")", (1000 / fps));
},
/**
* For public use.
*
* #param id The id of the element to scroll to.
* #param padding Top padding to apply above element.
*/
scrollVerticalToElementById: function(id, padding)
{
var element = document.getElementById(id);
if (element == null)
{
console.warn('Cannot find element with id \''+id+'\'.');
return;
}
var targetPosition = this.documentVerticalScrollPosition() + this.elementVerticalClientPositionById(id) - padding;
var currentPosition = this.documentVerticalScrollPosition();
// Clamp.
var maximumScrollPosition = this.documentMaximumScrollPosition();
if (targetPosition > maximumScrollPosition) targetPosition = maximumScrollPosition;
// Start animation.
this.scrollVerticalTickToPosition(currentPosition, targetPosition);
}
};
Smooth scrolling - look ma no jQuery
Based on an article on itnewb.com i made a demo plunk to smoothly scroll without external libraries.
The javascript is quite simple. First a helper function to improve cross browser support to determine the current position.
function currentYPosition() {
// Firefox, Chrome, Opera, Safari
if (self.pageYOffset) return self.pageYOffset;
// Internet Explorer 6 - standards mode
if (document.documentElement && document.documentElement.scrollTop)
return document.documentElement.scrollTop;
// Internet Explorer 6, 7 and 8
if (document.body.scrollTop) return document.body.scrollTop;
return 0;
}
Then a function to determine the position of the destination element - the one where we would like to scroll to.
function elmYPosition(eID) {
var elm = document.getElementById(eID);
var y = elm.offsetTop;
var node = elm;
while (node.offsetParent && node.offsetParent != document.body) {
node = node.offsetParent;
y += node.offsetTop;
} return y;
}
And the core function to do the scrolling
function smoothScroll(eID) {
var startY = currentYPosition();
var stopY = elmYPosition(eID);
var distance = stopY > startY ? stopY - startY : startY - stopY;
if (distance < 100) {
scrollTo(0, stopY); return;
}
var speed = Math.round(distance / 100);
if (speed >= 20) speed = 20;
var step = Math.round(distance / 25);
var leapY = stopY > startY ? startY + step : startY - step;
var timer = 0;
if (stopY > startY) {
for ( var i=startY; i<stopY; i+=step ) {
setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
leapY += step; if (leapY > stopY) leapY = stopY; timer++;
} return;
}
for ( var i=startY; i>stopY; i-=step ) {
setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
}
return false;
}
To call it you just do the following. You create a link which points to another element by using the id as a reference for a destination anchor.
<a href="#anchor-2"
onclick="smoothScroll('anchor-2');">smooth scroll to the headline with id anchor-2<a/>
...
... some content
...
<h2 id="anchor-2">Anchor 2</h2>
Copyright
In the footer of itnewb.com the following is written: The techniques, effects and code demonstrated in ITNewb articles may be used for any purpose without attribution (although we recommend it) (2014-01-12)
You could also check this great Blog - with some very simple ways to achieve this :)
https://css-tricks.com/snippets/jquery/smooth-scrolling/
Like (from the blog)
// Scroll to specific values
// scrollTo is the same
window.scroll({
top: 2500,
left: 0,
behavior: 'smooth'
});
// Scroll certain amounts from current position
window.scrollBy({
top: 100, // could be negative value
left: 0,
behavior: 'smooth'
});
// Scroll to a certain element
document.querySelector('.hello').scrollIntoView({
behavior: 'smooth'
});
and you can also get the element "top" position like below (or some other way)
var e = document.getElementById(element);
var top = 0;
do {
top += e.offsetTop;
} while (e = e.offsetParent);
return top;
Why not use CSS scroll-behavior property
html {
scroll-behavior: smooth;
}
The browser support is also good
https://caniuse.com/#feat=css-scroll-behavior
For a more comprehensive list of methods for smooth scrolling, see my answer here.
To scroll to a certain position in an exact amount of time, window.requestAnimationFrame can be put to use, calculating the appropriate current position each time. To scroll to an element, just set the y-position to element.offsetTop.
/*
#param pos: the y-position to scroll to (in pixels)
#param time: the exact amount of time the scrolling will take (in milliseconds)
*/
function scrollToSmoothly(pos, time) {
var currentPos = window.pageYOffset;
var start = null;
if(time == null) time = 500;
pos = +pos, time = +time;
window.requestAnimationFrame(function step(currentTime) {
start = !start ? currentTime : start;
var progress = currentTime - start;
if (currentPos < pos) {
window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
} else {
window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
}
if (progress < time) {
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
});
}
Demo:
function scrollToSmoothly(pos, time) {
var currentPos = window.pageYOffset;
var start = null;
if(time == null) time = 500;
pos = +pos, time = +time;
window.requestAnimationFrame(function step(currentTime) {
start = !start ? currentTime : start;
var progress = currentTime - start;
if (currentPos < pos) {
window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
} else {
window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
}
if (progress < time) {
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
});
}
document.getElementById("toElement").addEventListener("click", function(e){
scrollToSmoothly(document.querySelector('div').offsetTop, 500 /* milliseconds */);
});
document.getElementById("backToTop").addEventListener("click", function(e){
scrollToSmoothly(0, 500);
});
<button id="toElement">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element
<button id="backToTop">Scroll back to top</button>
</div>
The SmoothScroll.js library can also be used, which supports scrolling to an element on the page in addition to more complex features such as smooth scrolling both vertically and horizontally, scrolling inside other container elements, different easing behaviors, scrolling relatively from the current position, and more.
document.getElementById("toElement").addEventListener("click", function(e){
smoothScroll({toElement: document.querySelector('div'), duration: 500});
});
document.getElementById("backToTop").addEventListener("click", function(e){
smoothScroll({yPos: 'start', duration: 500});
});
<script src="https://cdn.jsdelivr.net/gh/LieutenantPeacock/SmoothScroll#1.2.0/src/smoothscroll.min.js" integrity="sha384-UdJHYJK9eDBy7vML0TvJGlCpvrJhCuOPGTc7tHbA+jHEgCgjWpPbmMvmd/2bzdXU" crossorigin="anonymous"></script>
<button id="toElement">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element
<button id="backToTop">Scroll back to top</button>
</div>
Alternatively, you can pass an options object to window.scroll which scrolls to a specific x and y position and window.scrollBy which scrolls a certain amount from the current position:
// Scroll to specific values
// scrollTo is the same
window.scroll({
top: 2500,
left: 0,
behavior: 'smooth'
});
// Scroll certain amounts from current position
window.scrollBy({
top: 100, // could be negative value
left: 0,
behavior: 'smooth'
});
If you only need to scroll to an element, not a specific position in the document, you can use Element.scrollIntoView with behavior set to smooth.
document.getElementById("elemID").scrollIntoView({
behavior: 'smooth'
});
I've been using this for a long time:
function scrollToItem(item) {
var diff=(item.offsetTop-window.scrollY)/8
if (Math.abs(diff)>1) {
window.scrollTo(0, (window.scrollY+diff))
clearTimeout(window._TO)
window._TO=setTimeout(scrollToItem, 30, item)
} else {
window.scrollTo(0, item.offsetTop)
}
}
usage:
scrollToItem(element) where element is document.getElementById('elementid') for example.
Variation of #tominko answer.
A little smoother animation and resolved problem with infinite invoked setTimeout(), when some elements can't allign to top of viewport.
function scrollToItem(item) {
var diff=(item.offsetTop-window.scrollY)/20;
if(!window._lastDiff){
window._lastDiff = 0;
}
console.log('test')
if (Math.abs(diff)>2) {
window.scrollTo(0, (window.scrollY+diff))
clearTimeout(window._TO)
if(diff !== window._lastDiff){
window._lastDiff = diff;
window._TO=setTimeout(scrollToItem, 15, item);
}
} else {
console.timeEnd('test');
window.scrollTo(0, item.offsetTop)
}
}
you can use this plugin. Does exactly what you want.
http://flesler.blogspot.com/2007/10/jqueryscrollto.html
If one need to scroll to an element inside a div there is my solution based on Andrzej Sala's answer:
function scroolTo(element, duration) {
if (!duration) {
duration = 700;
}
if (!element.offsetParent) {
element.scrollTo();
}
var startingTop = element.offsetParent.scrollTop;
var elementTop = element.offsetTop;
var dist = elementTop - startingTop;
var start;
window.requestAnimationFrame(function step(timestamp) {
if (!start)
start = timestamp;
var time = timestamp - start;
var percent = Math.min(time / duration, 1);
element.offsetParent.scrollTo(0, startingTop + dist * percent);
// Proceed with animation as long as we wanted it to.
if (time < duration) {
window.requestAnimationFrame(step);
}
})
}
Why not use this easy way
Native JS
document.querySelector(".layout").scrollIntoView({
behavior: "smooth",
});
Smooth scrolling with jQuery.ScrollTo
To use the jQuery ScrollTo plugin you have to do the following
Create links where href points to another elements.id
create the elements you want to scroll to
reference jQuery and the scrollTo Plugin
Make sure to add a click event handler for each link that should do smooth scrolling
Creating the links
<h1>Smooth Scrolling with the jQuery Plugin .scrollTo</h1>
<div id="nav-list">
Scroll to element 1
Scroll to element 2
Scroll to element 3
Scroll to element 4
</div>
Creating the target elements here only the first two are displayed the other headings are set up the same way. To see another example i added a link back to the navigation a.toNav
<h2 id="idElement1">Element1</h2>
....
<h2 id="idElement1">Element1</h2>
...
<a class="toNav" href="#nav-list">Scroll to Nav-List</a>
Setting the references to the scripts. Your path to the files may be different.
<script src="./jquery-1.8.3.min.js"></script>
<script src="./jquery.scrollTo-1.4.3.1-min.js"></script>
Wiring it all up
The code below is borrowed from jQuery easing plugin
jQuery(function ($) {
$.easing.elasout = function (x, t, b, c, d) {
var s = 1.70158; var p = 0; var a = c;
if (t == 0) return b;
if ((t /= d) == 1) return b + c;
if (!p) p = d * .3;
if (a < Math.abs(c)) {
a = c; var s = p / 4;
} else var s = p / (2 * Math.PI) * Math.asin(c / a);
// line breaks added to avoid scroll bar
return a * Math.pow(2, -10 * t) * Math.sin((t * d - s)
* (2 * Math.PI) / p) + c + b;
};
// important reset all scrollable panes to (0,0)
$('div.pane').scrollTo(0);
$.scrollTo(0); // Reset the screen to (0,0)
// adding a click handler for each link
// within the div with the id nav-list
$('#nav-list a').click(function () {
$.scrollTo(this.hash, 1500, {
easing: 'elasout'
});
return false;
});
// adding a click handler for the link at the bottom
$('a.toNav').click(function () {
var scrollTargetId = this.hash;
$.scrollTo(scrollTargetId, 1500, {
easing: 'elasout'
});
return false;
});
});
Fully working demo on plnkr.co
You may take a look at the soucre code for the demo.
Update May 2014
Based on another question i came across another solution from kadaj. Here jQuery animate is used to scroll to an element inside a <div style=overflow-y: scroll>
$(document).ready(function () {
$('.navSection').on('click', function (e) {
debugger;
var elemId = ""; //eg: #nav2
switch (e.target.id) {
case "nav1":
elemId = "#s1";
break;
case "nav2":
elemId = "#s2";
break;
case "nav3":
elemId = "#s3";
break;
case "nav4":
elemId = "#s4";
break;
}
$('.content').animate({
scrollTop: $(elemId).parent().scrollTop()
+ $(elemId).offset().top
- $(elemId).parent().offset().top
}, {
duration: 1000,
specialEasing: { width: 'linear'
, height: 'easeOutBounce' },
complete: function (e) {
//console.log("animation completed");
}
});
e.preventDefault();
});
});
This has been asked before and I got my code running.
The problem is with some weird viewport sizes the script seems to freeze.
There is nothing you can do but kill the tab.
I tried to script some backup that will kill the loop if its frozen, but it does not seem to get the job done.
Can anyone tell me whats wrong? Or show me an error in the script in general thats causing the freeze?
Thats the site where the code is running:
http://unkn0wn3d.com
JS Code is eithere there:
http://unkn0wn3d.com/css/pos.js
or here:
var pos = function(){
var containerW = $("article").width();
var containerH = $("article").height();
var langH = parseInt($( ".languages" ).position().top + $( ".languages" ).height());
var langW = parseInt($( ".languages" ).position().left + $( ".languages" ).width());
var creditW = parseInt($( ".credit" ).position().left - $(".link:first").width() + 15);
var positions = [];
var froze = false;
setTimeout(function(){froze=true;}, 2000)
$('.link').each(function() {
var coords = {
w: $(this).outerWidth(true)+5,
h: $(this).outerHeight(true)+5
};
var success = false;
while (!success)
{
coords.x = parseInt(Math.random() * (containerW-coords.w));
coords.y = parseInt(Math.random() * (containerH-coords.h));
var success = true;
$.each(positions, function(){
if (froze){return false;}
if (
(coords.x <= langW &&
coords.y <= langH) ||
(coords.x >= creditW &&
coords.y <= langH) ||
(coords.x <= (this.x + this.w) &&
(coords.x + coords.w) >= this.x &&
coords.y <= (this.y + this.h) &&
(coords.y + coords.h) >= this.y)
)
{
success = false;
}
});
}
positions.push(coords);
$(this).css({
top: coords.y + 'px',
left: coords.x + 'px',
display: 'block'
});
})};
var waitForFinalEvent = (function () {
var timers = {};
return function (callback, ms, uniqueId) {
if (!uniqueId) {
uniqueId = "Don't call this twice without a uniqueId";
}
if (timers[uniqueId]) {
clearTimeout (timers[uniqueId]);
}
timers[uniqueId] = setTimeout(callback, ms);
};
})();
$(document).ready(
pos()
);
$(window).resize(function () {
waitForFinalEvent(function(){pos();}, 500, "resize");
});
You have 2 problems. I don't see where you are doing it, but the size of your A.link elements is being controlled only by the height of the viewport. So if the viewport is tall and narrow, then the links are large, and it's simply impossible to fit them all.
The second problem is that if the links can't be placed your code just keeps trying forever. The timer will never fire because the main script is still busy running. Rather than just do
while (!success)
it would be better to do a limited number of attempts:
var success = false;
for (var attempt = 0; !success && attempt < 50; attempt++)
{
....
}
By limiting the number of tries it will stop it freezing, even if the links are left overlapping. Then you can remove froze and the timer.
Even better would be to introduce a tolerance as the number of attempts increases - so they are allowed to overlap a little bit.
Your while loop never terminates since inside it you wrote var success = true
You redefined your success variable again by using var, so now you have 2 instances of success and the first one is never set to true so the loop never terminates. Try removing var from var success = true
The below is the source code of a simple parallax plugin:
/*
Plugin: jQuery Parallax
Version 1.1.3
Author: Ian Lunn
Twitter: #IanLunn
Author URL: http://www.ianlunn.co.uk/
Plugin URL: http://www.ianlunn.co.uk/plugins/jquery-parallax/
Dual licensed under the MIT and GPL licenses:
http://www.opensource.org/licenses/mit-license.php
http://www.gnu.org/licenses/gpl.html
*/
(function( $ ){
var $window = $(window);
var windowHeight = $window.height();
$window.resize(function () {
windowHeight = $window.height();
});
$.fn.parallax = function(xpos, speedFactor, outerHeight) {
var $this = $(this);
var getHeight;
var firstTop;
var paddingTop = 0;
//get the starting position of each element to have parallax applied to it
$this.each(function(){
firstTop = $this.offset().top;
});
if (outerHeight) {
getHeight = function(jqo) {
return jqo.outerHeight(true);
};
} else {
getHeight = function(jqo) {
return jqo.height();
};
}
// setup defaults if arguments aren't specified
if (arguments.length < 1 || xpos === null) xpos = "50%";
if (arguments.length < 2 || speedFactor === null) speedFactor = 0.1;
if (arguments.length < 3 || outerHeight === null) outerHeight = true;
// function to be called whenever the window is scrolled or resized
function update(){
var pos = $window.scrollTop();
$this.each(function(){
var $element = $(this);
var top = $element.offset().top;
var height = getHeight($element);
// Check if totally above or totally below viewport
if (top + height < pos || top > pos + windowHeight) {
return;
}
console.log(firstTop + " " + pos);
$this.css('backgroundPosition', xpos + " " + Math.round((firstTop - pos) * speedFactor) + "px");
});
}
$window.bind('scroll', update).resize(update);
update();
};
})(jQuery);
Now suppose i call the plugin , like so , on multiple elements.
$('#intro').parallax("50%", .8);
$('#second').parallax("50%", 0.1);
$('.bg').parallax("50%", 0.4);
$('#third').parallax("50%", 0.3);
What am i really doing ? creating multiple instances of the plugin ?
A demo of the plugin itself can be seen HERE.
No, you are not creating multiple instances of the plugin.
What you are doing is that you are calling this function multiple times:
$.fn.parallax = function(xpos, speedFactor, outerHeight) {
This is perfectly fine to do.
What you really are looking at is a jQuery extension method. This method merges the contents of an object onto the jQuery prototype to provide new jQuery instance methods.
Whenever you see the fn property, you are looking at an alias to the prototype property of jQuery.
Lets examine some lines in the parallax script you are embedding:
$.fn.parallax = function(xpos, speedFactor, outerHeight) {
This line is the start of a new jQuery prototype extension method that takes three arguments
Here is a more simple example that extends jQuery with a new method
$(function () {
// declare the new method greenify
$.fn.greenify = function() {
// The element that this method is used on will have the color green by using jQuery .css();
this.css( "color", "green" );
};
// Then to use your brand new jQuery extension method simply do this
$( "a" ).greenify();
$('.myElem').greenify();
$('#someElemId').greenify();
});
What is happening is that we are using the same method and applying it to different elements in the dom.
I hope this made it clearer what is really going on and how extension methods work.
I'm trying to have a bunch of variables reset themselves on a resize (I'm just a little crazy like that. Yes, I know virtually no one will do it as their using the page). I want to be able to have the plugin that I created (hScroll) reset it's variables when the user resizes the page. I only want to declare them and set them within one line, so I tried using the window.variableName = ... but that didn't seem to work. Once again, all I want to be able to do is have to declare and set the variable within one line, and on resize, have the variables reestablish themselves, since a few are size dependent. As you can see, I have also tried the triggerHandler method as well, but it does not seem to be working.
(function($) {
$.fn.extend({
hScroll: function(options) {
var defaults = {
container: "nav",
sliderName: ".sliderName",
partContainer: ".beep"
};
var o = $.extend(defaults, options);
return this.each(function() {
// I want to set global variables and have them reset... START
var slider = $(o.container + " " + o.sliderName),
sliderWidth = slider.outerWidth(),
container = $(o.container),
containerWidth = container.outerWidth(),
containerInnerWidth = containerWidth - (2 * parseInt(container.css("padding-left"))),
sliderPieces = slider.children(o.partContainer),
numberOfPieces = sliderPieces.length,
containerWidth = $(o.container).width(),
piecesWidth = 0;
// set slide widths
if (containerInnerWidth > sliderWidth / numberOfPieces) {
piecesWidth = sliderWidth / numberOfPieces
} else {
piecesWidth = containerInnerWidth;
}
sliderPieces.width(piecesWidth);
// set gutter and how many pieces can be seen at once.
var wholePiecesSeen = Math.floor(containerInnerWidth / piecesWidth),
gutter = parseInt((containerInnerWidth - (wholePiecesSeen * piecesWidth)) / 2);
// END - I want this block to be reset when the window is resized.
var isContainerBigEnough = function() {
if (containerInnerWidth > sliderWidth) {
$(o.container).removeClass("tooBig");
} else {
$(o.container).addClass("tooBig");
}
}
isContainerBigEnough();
// arrow variables
$(o.container + " .previous").click(function() {
var addOn = 0,
newPosition = 0,
thisFarGone = parseInt(slider.css("left")),
moveThisFar = piecesWidth,
allTheWay = containerInnerWidth - sliderWidth;
// always make sure to center your tiles
if (thisFarGone == allTheWay) {
moveThisFar = moveThisFar - gutter;
console.log(moveThisFar);
console.log("in");
};
newPosition = -thisFarGone - moveThisFar;
//make sure it doesn't go too far
if (newPosition < 0) {
newPosition = 0;
}
newPosition = parseInt(newPosition); // - addOn);
slider.css({
"left": (-newPosition) + "px"
});
});
$(o.container + " .next").click(function() {
var addOn = 0,
newPosition = 0,
thisFarGone = parseInt(slider.css("left")),
moveThisFar = piecesWidth;
// always make sure to center your tiles
if (thisFarGone == 0 ||
thisFarGone == -0 ||
thisFarGone == undefined) {
moveThisFar = moveThisFar - gutter;
};
newPosition = moveThisFar - thisFarGone;
//make sure it doesn't go too far
if (newPosition > sliderWidth - containerInnerWidth) {
newPosition = sliderWidth - containerInnerWidth;
}
newPosition = parseInt(newPosition); // - addOn);
slider.css({
"left": (-newPosition) + "px"
});
});
$(window).resize(function() {
console.log("working");
$(o.container).triggerHandler("hScroll");
});
});
}
});
})(jQuery);
$(document).ready(function() {
$(".posts-timeline").hScroll({
container: ".posts-timeline",
sliderName: "#slider",
partContainer: ".post"
});
});
Something like this?
console.log("working");
$(o.container).hScroll("hScroll");
Maybe not exactly that, but if you want those variables to be reassigned, I'm guessing that would wind up being done somewhere in $(window).resize(function() {
I have a Javascript file that I am using to try to animate a dropdown menu. I have the "Toggle" function in that file set to run when I click on a certain div. Here's the script I'm using:
var up = true;
function Toggle(x)
{
if (up)
{
for (var i = x.offsetTop; i <= 0; i++)
{
x.style.top = i;
if (i == 0)
{
up = false;
}
}
}
else if (up == false)
{
for (var i = x.offsetTop; i >= -50; i--)
{
x.style.top = i;
if (i == -50)
{
up = true;
}
}
}
}
In the HTML div I want to animate, I have the "onclick" property set to "onclick=Toggle(this)". The first for loop works as it should (it sets the div's top offset to 0). However, the second for loop doesn't set the offsetTop. I know that the for loop is activating because I've tested it and it gives me every integer between 0 and -50. Why isn't it setting the offset position?
1) You must specify a unit to the top ie: x.style.top = i +"px"
2) Your function won't animate instead of you use a setInterval or a setTimeout
Like you asked, an example. I wouldn't do it like this for one of my project, but i kept your function to make you more familiar with the code.
I Used setTimeout instead of setInterval because setInterval must be cleared when not needed and setTimeout is just launched one time :
var Toggle = (function() { // use scope to define up/down
var up = true;
return function(element) {
var top = parseInt(element.style.top, 10); // element.offsetTop ?
if ( !top ) {
top = 0;
}
if (up) {
if (element.offsetTop < 0) { // if we are not at 0 and want to get up
element.style.top = (top+1) + "px";
setTimeout(function() { Toggle(element); }, 10); // recall the function in 10 ms
} else { // we change up value
up = !up;
}
}
else {
if (element.offsetTop > -50) {
element.style.top = (top-1) + "px";
setTimeout(function() { Toggle(element); }, 10); // recall the function in 10 ms
} else {
up=!up;
}
}
}
})();
You'd have to use x.style.top = i + 'px' as top and similar css properties must define the type (px, em, %, etc.) unless they are 0, as this is 0 in any case.
But your script would actually snap the div directly to -50px, as you do not wait between those iteration steps.
I'd recommend to use a library like jQuery to use it's animate() method.
function Toggle(obj) {
$(obj).animate({
top: parseInt($(obj).css('top')) === 0 ? '-50px' : '0px'
})
}