javascript - how to scroll page smothly until user relese mouse button - javascript

Shor question - page opened on pc with not-so-good touch-screen display. I created 2 big arrows and dont know how to program it using JS/jQuery.
First try: onClick->scroll - it works but user must tap many times to scroll article.
Second:
var scrolling = false;
$("#scUp").mouseup(function(){
$(this).css("opacity", 0.3);
scrolling = false;
}).mousedown(function(){
$(this).css("opacity", 1);
scrolling = true;
while(scrolling) {
$('html, body').stop().animate({ scrollTop: 50 }, 500);
}
event.preventDefault();
});
Doesnt work ;)
I`m trying to simulate real browser scroll arrows - until you keep preesed mouse button page scrolls down (or up).

I answered this question some time back... basically it sets a flag when the mouse is down and clears when the mouse is up. Then a setTimeout loops until the flag clears. Also, it has mousewheel and drag-and-drop functionality.
Check out the demo

Your code above doesn't work because JavaScript is not multi-threaded. That is, your while loop is eating CPU and probably preventing other code from running (i.e. the mouseup event).
I did something like this not too long back. Please feel free to check out my blog post.
Also, not sure if you're doing this or not, but make sure that you place all of your JavaScript code in jQuery's ready() function; otherwise, jQuery may not find the #scUp element.
Here's the relevant code from my old blog post:
var scrollTimer;
function scrollContent(amt)
{
$("#content").scrollTop($("#content").scrollTop()+amt);
scrollTimer = window.setTimeout("scrollContent(" + amt + ")", 25);
}
$(document).ready(function ()
{
$("#content").css("overflow", "hidden");
$("#scrollUp").mousedown(function() {
window.clearTimeout(scrollTimer); //Not necessary, but just to be sure...
$("#scrollUp").animate({"opacity": 100}, 'fast');
scrollContent(-10);
});
$("#scrollUp").mouseup(function() {
window.clearTimeout(scrollTimer);
$("#scrollUp").animate({"opacity": 0}, 'fast');
});
$("#scrollDown").mousedown(function() {
window.clearTimeout(scrollTimer); //Not necessary, but just to be sure...
$("#scrollDown").animate({"opacity": 100}, 'fast');
scrollContent(10);
});
$("#scrollDown").mouseup(function() {
window.clearTimeout(scrollTimer);
$("#scrollDown").animate({"opacity": 0}, 'fast');
});
//$("#scrollUp").css("opacity", 0); //Alternative
$("#scrollUp").animate({"opacity": 0}, 'slow');
$("#scrollDown").animate({"opacity": 0}, 'slow');
});
...and the link:
http://blake-miner.blogspot.com/2010/08/javascript-sticky-footer-and-scroll.html
Hope this helps!

In meantime I wrote this code:
var scrollId = 0;
$("#scUp").mouseup(function(){
$(this).css("opacity", 0.3);
clearInterval(scrollId);
}).mousedown(function(){
$(this).css("opacity", 1);
var scroll = function() { $("html, body").stop().animate({ scrollTop: "-=10px" }, 15); }
scroll();
scrollId = setInterval(scroll, 15);
});
$("#scDw").mouseup(function(){
$(this).css("opacity", 0.3);
clearInterval(scrollId);
}).mousedown(function(){
$(this).css("opacity", 1);
var scroll = function() { $("html, body").stop().animate({ scrollTop: "+=10px" }, 15); }
scroll();
scrollId = setInterval(scroll, 15);
});
It works BUT not on Opera ... funny thing - kiosk is based on Opera browser, so, any solution?
btw. Is there any materials about building kiosk (not outdated for 1.x version of FF) on Linux with FF (linux is no problem for me but I searching for security-plugin for FF).

<div style="position:fixed">
Up
Down
</div>
<script>
var scrollValue = 2;
function scrollAs(value) {
if(value) scrollValue = value;
document.body.scrollTop += (scrollValue - 2)*10;
if(scrollValue != 2) setTimeout(scrollAs, 100);
}
<script>

Related

How to throttle function using the mousewheel plugin?

I'm using this plugin:
https://github.com/jquery/jquery-mousewheel
It's a horizontally scrolling one-page site, and the function is intended as a "scrollsnap"-- a scroll on the current section will force snap it to the next section. However, after the first "snap", it only happens after ~5 seconds, which I believe is due to the function firing too many times in a row.
function scrollSnap() {
$('.page:not(:last-child)').each(function(){
var nextTarget = $(this).next().position().left;
$(this).mousewheel(function(){
if(event.deltaY >= 50) {
$('main').animate({
scrollLeft: nextTarget
}, 700);
console.log("scrolled to: ", nextTarget);
}
});
});
$('.page:not(:first-child)').each(function(){
var prevTarget = $(this).prev().position().left;
$(this).mousewheel(function(){
if(event.deltaY <= -50) {
$('main').animate({
scrollLeft: prevTarget
}, 700);
console.log("scrolled to: ", prevTarget);
}
});
});
}
$(document).ready(function() {
scrollSnap();
});
You can throttle events like these with something called a debounce function. You can create your own or use a utility library like lodash which has it built in.

one page scrolling website using jquery

Hi Stackoverflow fellows,
I want to create a website with one page scrolling but i don't want to use any external library. So i came-up with this technique, It works perfectly fine for a local test but i want to know if this piece of code is logical or this may have potential issues in a full website. I am asking because in my search i did not find this approach for a one page site, i want to know the reason why not this. So please point me in right direction. Any suggestions or comments are welcome. Thanks for your support. https://jsfiddle.net/emalik/xpvt214o/539446/
var current
$(function() {
var timerId;
$('.one-page').bind('DOMMouseScroll mousewheel', function(e){
e.preventDefault();
var $current = $('section.current');
if(e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0) {
//console.log(e.originalEvent.wheelDelta);
//console.log("UP");
$prev = $current.prev();
if ($prev.length) {
clearTimeout(timerId);
timerId = setTimeout(function(){
$current.removeClass('current');
$prev.addClass('current');
$('body,html').animate({
scrollTop: $('.current').offset().top
}, 200);
}, 200)
}
}
else{
// console.log("DOWN");
$next = $current.next();
if ($next.length) {
clearTimeout(timerId);
timerId = setTimeout(function(){
$current.removeClass('current');
$next.addClass('current');
$('body,html').animate({
scrollTop: $('.current').offset().top
}, 200);
, 200)
}
}
});
});

jQuery animate scrolling without $.browser & not firing twice

I found many questions regarding the cross bowser behaviour of $('html, body').animate();, but for some reason I couldn't find an answer for this one:
I want to (finally) remove $.browser, but at the same moment don't want the scroll event to be triggered twice again, which will happen in some browsers if the selector is $('html, body)
// animte page scrolling
pageScroll : function( scrollTo, speed, callback ) {
var rootElem;
scrollTo = scrollTo || 0;
speed = speed || 800;
if ( $.browser.webkit ) {
rootElem = $('body');
} else {
rootElem = $('html');
}
rootElem
.stop()
.animate(
{
scrollTop: scrollTo
}, speed, callback
);
}
I've looked into this for quite a while and haven't found a real solution other than a check on doc ready :
http://codepen.io/anon/pen/yyddER?editors=011
var mainelement;
$('html, body').animate({scrollTop: 1}, 1, function() {
if ($('html').scrollTop()) mainelement = $('html'); // FF and IE
if ($('body').scrollTop()) mainelement = $('body'); // Chrome, Safari and Opera
mainelement.scrollTop(0);
});
Assuming here the content is high enough to create a scrollbar...
Tested on the major browsers and works without a hitch.
Edit - a variation to make sure the trigger to scroll the page back is only acted upon a single time if the browser uses <html> as the main element for overflow :
var mainelement, tested = false;
$('html, body').animate({scrollTop: 1}, 1, function() {
if ($('html').scrollTop()) mainelement = $('html');
else if ($('body').scrollTop()) mainelement = $('body');
if (!tested) {
tested = true;
mainelement.scrollTop(0);
}
});
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
And later came up with this approach as well (which seems to be the most efficient) :
http://codepen.io/anon/pen/NPQNEr?editors=001
var mainelement;
$(window).scrollTop(1);
if ($('html').scrollTop()) mainelement = $('html');
else if ($('body').scrollTop()) mainelement = $('body');
mainelement.scrollTop(0);
This is the code I use in production; works just fine:
function ScrollPage(TheTop) {
TheTop = parseInt(TheTop, 10);
if (!$.isNumeric(TheTop)) {
return;
}
$('html,body').animate({ scrollTop: TheTop }, 400);
}
If the problem is that the event handler is firing twice then it means the function is somehow called twice, and that the bug is therefore elsewhere. On another note, the $.browser() function has been deprecated for a while.

Dynamic divs and scrollTop

I have a single page site:
http://chiaroscuro.telegraphbranding.com/
Each section is dynamically sized based on the user's window. I'm trying to figure out how to have a jQuery smooth scroll function scroll to the top of each section when the link is clicked. It is working great for the first section, funding areas, where I just used a simple offset().top, but the others are not working because they don't know how far to scroll because the window size is always different.
I've been trying to get offset() or position() to work, but no dice. I appreciate any advice.
Here's my jQuery:
`
$(document).ready(function () {
var slowScrollFunding = $('#funding-areas').offset().top;
var slowScrollAbout = $('#about-us').offset().top;
var slowScrollProjects = $('#our-projects').offset().top + 600;
panelOpen = true;
$('#anchor-funding-areas').click(function(event) {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content').stop(true, true).animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
// Scroll down to 'slowScrollTop'
$('html, body, #home-wrap').animate({scrollTop:slowScrollFunding}, 1000);
panelOpen = false;
});
}else{
$('html, body, #home-wrap').animate({scrollTop:slowScrollFunding}, 1000);
};
});
$('#anchor-aboutus').click(function(event) {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content').stop(true, true).animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
// Scroll down to 'slowScrollTop'
$('html, body, #aboutus-wrap').animate({scrollTop:slowScrollAbout}, 1000);
panelOpen = false;
});
}else{
$('html, body, #home-wrap').animate({scrollTop:slowScrollAbout}, 1000);
};
});
$('#anchor-ourprojects').click(function(event) {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content').stop(true, true).animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
// Scroll down to 'slowScrollTop'
$('html, body, #home-wrap').animate({scrollTop:slowScrollProjects}, 1000);
panelOpen = false;
});
}else{
$('html, body, #home-wrap').animate({scrollTop:slowScrollProjects}, 1000);
};
});
$('#header-logo').add('.homelink').click(function() {
if(panelOpen == false) {
$('.scrollableArea').css('z-index', '0');
$('#panel-content-container').show();
$('#slide-panel-content').stop(true, true).animate({height: '389px'}, 600, function() {
// Scroll down to 'slowScrollTop'
panelOpen = true;
});
};
});
});
`
$.offset and $.position can be a little unreliable, especially if you have lots of complicated layouts going on - as your page does. What I've used in the past is the following trick:
var de = document.documentElement ? document.documentElement : document.body;
var elm = $('get_your_anchor_element').get(0);
var destScroll, curScroll = de.scrollTop;
/// check for the function scrollIntoView
if ( elm.scrollIntoView ) {
/// get the browser to scrollIntoView (this wont show up yet)
elm.scrollIntoView();
/// however the new scrollTop is calculated
destScroll = de.scrollTop;
/// then set the scrollTop back to where we were
de.scrollTop = curScroll;
/// you now have your correct scrollTop value
$(de).animate({scrollTop:destScroll});
}
else {
/// most browsers support scrollIntoView so I didn't bother
/// with a fallback, but you could just use window.location
/// and jump to the anchor.
}
The above can occur on the click event. The only thing that needs to be improved is that different browsers scroll on different base elements (body or html). When I used this I had my own element that was scrollable so I didn't need to work out which one the agent was using... When I get a second I'll see if I can find a good bit of code for detecting the difference.
The above has worked in all the modern browsers I've tested (Firefox, Safari, Chrome) however I didn't need to support Internet Explorer so I'm not sure with regard to that.
update:
I'm not quite sure what is going on with your implementation - it is possible that the page is so heavy with content that you actually can see the .scrollIntoView() happening - this has never been my experience, but then I didn't have so much going on on-screen. With that in mind, I've implemented a bare bones system that I would advise you use and build each extra part you need into it:
http://pebbl.co.uk/stackoverflow/13035183.html
That way you know you have a working system to start with, and will easily detect what it is that stops it from working. With regards to chiaro.js your implementation seems to be ok - if a little exploded over many different areas of the file - however this part is slightly erroneous:
$('#anchor-aboutus').click(function() {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content')
.stop(true, true)
.animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
elm.scrollIntoView(true)
.animate({scrollTop:destScroll}, 1000);
panelOpen = false;
});
}else{
elm.scrollIntoView(true).animate({scrollTop:destScroll});
};
});
In the code above you will only get the correct value of destScroll if panelOpen === true. Ahh, actually I've also spotted another problem - which will explain why it's not working:
elm.scrollIntoView(true)
.animate({scrollTop:destScroll}, 1000);
The above code is mixing pure JavaScript and jQuery, the elm var is a normal DOM element (this supports the scrollIntoView method). But you are then attempting to chain the animate method of jQuery into the mix - you should also be triggering the animate method on the element responsible for the scrollbar. What you should use is as follows:
$('#anchor-aboutus').click(function(e) {
var currentScroll, destScroll;
e.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content')
.stop(true, true)
.animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
currentScroll = de.scrollTop;
elm.scrollIntoView(true);
destScroll = de.scrollTop;
de.scrollTop = currentScroll;
$(de).animate({scrollTop:destScroll}, 1000);
panelOpen = false;
});
}else{
currentScroll = de.scrollTop;
elm.scrollIntoView(true);
destScroll = de.scrollTop;
de.scrollTop = currentScroll;
$(de).animate({scrollTop:destScroll}, 1000);
};
});
However, what you will also need to do is make sure your de element points to the right element - either html or body depending on the browser - for this you can use this:
var de;
/// calculate which element is the scroller element
$('body, html').each(function(){
if ( this.scrollHeight > this.offsetHeight ) {
de = this;
return false;
}
});
alert( $(de).is('body') ) /// will be true for Chrome, false for Firefox.
You will need to use this code in place of the following code:
var de = document.documentElement ? document.documentElement : document.body;
The reason for changing the code you were using is as follows:
/// store the current scroll position from the de element
currentScroll = de.scrollTop;
/// get the browser to do the scrollTo calculation
elm.scrollIntoView(true);
/// store where the browser scrolled to behind the scenes
destScroll = de.scrollTop;
/// reset our scroll position to where we were before scrollIntoView()
/// if you don't reset then the animation will happen instantaneously
/// because that is what scrollIntoView does.
de.scrollTop = currentScroll;
/// wrap the normal dom element de with jquery and then animate
$(de).animate({scrollTop:destScroll}, 1000);

Cancel scrolling after user interaction

My webpage animates scrolling when users click on links to the same page. I want to cancel this animation as soon as the user tries to scroll (otherwise the user and the browser are fighting for control) – no matter whether with the mouse wheel, the keyboard or the scrollbar (or any other way – are there other ways of scrolling?). I managed to cancel the animation after the mouse wheel or keyboard are used, how do I get this working with the scrollbar?
Here is how my code looks for the keyboard:
$(document.documentElement).keydown( function (event) {
if(event.keyCode == 38 || 40) stopScroll();
});
function stopScroll() {
$("html, body").stop(true, false);
}
I also tried a more elegant way of doing this by using scroll(), the problem is that scroll() catches everything including the animated and automated scrolling. I could not think of any way to let it catch all scrolling except the animated scrolling.
you need animation marker, something like this
$("html, body").stop(true, false).prop('animatedMark',0.0).animate({scrollTop : top, animatedMark: '+=1.0'})
Here is the code, the code was mix of GWT and javascript so moved it to js, not fully tested, please try it
var lastAnimatedMark=0.0;
function scrollToThis(top){
// Select/ stop any previous animation / reset the mark to 0
// and finally animate the scroll and the mark
$("html, body").stop(true, false).prop('animatedMark',0.0).
animate({scrollTop : top, animatedMark: '+=1.0'}
,10000,function(){
//We finished , nothing just clear the data
lastAnimatedMark=0.0;
$("html, body").prop('animatedMark',0.0);
});
}
//Gets the animatedMark value
function animatedMark() {
var x=$("html, body").prop('animatedMark');
if (x==undefined){
$("html, body").prop('animatedMark', 0.0);
}
x=$("html, body").prop('animatedMark');
return x;
};
//Kills the animation
function stopBodyAnimation() {
lastAnimatedMark=0;
$("html, body").stop(true, false);
}
//This should be hooked to window scroll event
function scrolled(){
//get current mark
var currentAnimatedMark=animatedMark();
//mark must be more than zero (jQuery animation is on) & but
//because last=current , this is user interaction.
if (currentAnimatedMark>0 && (lastAnimatedMark==currentAnimatedMark)) {
//During Animation but the marks are the same !
stopBodyAnimation();
return;
}
lastAnimatedMark=currentAnimatedMark;
}
Here is the blog about it
http://alaamurad.com/blog/#!canceling-jquery-animation-after-user-interaction
Enjoy!
Here's a jquery function that should do the trick:
function polite_scroll_to(val, duration, callback) {
/* scrolls body to a value, without fighting the user if they
try to scroll in the middle of the animation. */
var auto_scroll = false;
function stop_scroll() {
if (!auto_scroll) {
$("html, body").stop(true, false);
}
};
$(window).on('scroll', stop_scroll);
$("html, body").animate({
scrollTop: val
}, {
duration: duration,
step: function() {
auto_scroll = true;
$(window).one('scroll', function() {
auto_scroll = false;
});
},
complete: function() {
callback && callback();
},
always: function() {
$(window).off('scroll', stop_scroll);
}
});
};
It's not very elegant, but you could use a flag of some kind to detect what type of scrolling you're dealing with (animated or 'manual') and always kill it when it's animated. Here's an untested example:
var animatedScroll = false;
// you probably have a method looking something like this:
function animatedScrollTo(top) {
// set flag to true
animatedScroll = true;
$('html').animate({
scrollTop : top
}, 'slow', function() {
// reset flag after animation is completed
animatedScroll = false;
});
}
function stopScroll() {
if (animatedScroll) {
$("html, body").stop(true, false);
}
}

Categories

Resources