Prevent automatic scroll and scroll to div - javascript

I know there are many similar posts, but still I haven't get to the code I need.
Basically, I want to make a presentation the first time the user scrolls down. For that, I want to prevent the default action of scroll and (if it's scrolling down) make an animation to the next div.
window.scrolledToRed = false
window.scrolledToGreen = false
window.scrollTo = (to, guard ) =>
$('html, body').animate({
scrollTop: $(to).offset().top
}, 1000, =>
window[guard] = true
)
window.addEventListener 'wheel', (e) ->
if (e.wheelDelta < 0)
if (!window.scrolledToRed)
scrollTo('.red', 'scrolledToRed')
else if (!window.scrolledToYellow)
scrollTo('.green', 'scrolledToGreen')
I've created a Fiddle that represents the problem:
https://jsfiddle.net/pn6zqgwu/2/
When the user scrolls down the first time I want to take him to the red div and the next time to the green one.
None of the solutions I've tried really worked, since it was both "jumping" and scrolling where I want.
Any idea of how to solve the problem?
Thanks in advanced

Maybe you need to call e.preventDefault() to prevent browser default scroll behavior

I have made a fiddle for you, you can make more checks and add animations
var redTouched = false;
var greenTouched = false;
function scrollCb() {
event.preventDefault();
console.log(event.wheelDelta)
if (event.wheelDelta < 0) {
if (!redTouched) {
$(window).scrollTop($('.red').position().top);
redTouched = true;
} else if (redTouched && !greenTouched) {
$(window).scrollTop($('.green').position().top);
greenTouched = true;
} else if (redTouched && greenTouched) {
window.removeEventListener('mousewheel', scrollCb)
}
} else {
window.removeEventListener('mousewheel', scrollCb)
}
window.addEventListener('mousewheel', scrollCb);
https://jsfiddle.net/jacobjuul/b0k03wtr/

Related

After preventing the default scroll event, scrollIntoView(); doesn't work Properly on Firefox desktop?

In my scenario the code should prevent the the default scroll event and use scrollIntoView() to move the user to a specific section according to the scroll direction.
https://stackoverflow.com/a/4770179/9164633 I used this method to prevent the scroll default event.
And I detect the direction like so,
preventDefault(e) {
e.preventDefault();
if(this.waiting == false && this.forceInitialScroll != true) {
if(e.deltaY && e.deltaY > 7) {
this.scrollDirection = 'down';
this.checkScroll()
}else if(e.deltaY && e.deltaY < -7) {
this.scrollDirection = 'up';
this.checkScroll()
}else {
}
}
},
and Im pretty sure that both are working fine.
After preventing the scroll and detecting the scroll direction I try to scroll the user to the section like so,
checkScroll() {
let element;
if(this.scrollDirection == 'down' && this.scrollIndex != 4 ) {
element = document.getElementById(`section-${this.scrollIndex+1}`);
}else if(this.scrollDirection == 'up' && this.scrollIndex != 0) {
element = document.getElementById(`section-${this.scrollIndex-1}`);
}
this.waiting = true;
if(element) {
console.log(element)
element.scrollIntoView({
behavior: 'smooth',
block: 'center',
})
}
setTimeout(() => {
if(this.waiting == true) {
this.waiting = false;
this.scrollDirection = null;
}
}, 450)
},
this.waiting is used to prevent the user form scrolling more than one section at a time.
On firefox the browser doesnt scroll the user properly though its working fine on chrome.
Apparently Firefox's behavior with event.preventDefault() was that it blocked any kind of user scrolling and even the js manual scrolling.
The problem in my case was solved by hiding the scroll in css instead of js by using overflow: hidden; and then controlling the scroll manually instead of preventing the default behavior.

ScrollTop with button & scroll with JQuery

I have a website with two scroll options. When you scroll down, it scrolls to the anchor Point 1.
I also have a Button which jumps to the same anchor point.
My problem: When I click the Button, the site jumps to the Anchor, but because there are two ways to the anchor, it triggers the first scroll option as well.
jQuery(document).ready(function($) {
var flag = true;
$(window).scroll(function () {
if (flag == true) {
scroll = $(window).scrollTop();
if (scroll > 50) $('#scroll-down')[0].click();
flag = false;
}
});
$(window).scroll(function () {
if (flag == false) {
scroll = $(window).scrollTop();
if (scroll < 50 )
flag = true;
}
});
});
Any solutions for this ?
From the screencast you sent, this code should scroll to the bottom of the banner when the button is clicked (provided you correctly place the anchor div):
jQuery(document).ready(function ($) {
// The button is assumed to have an id of 'scroll-down' - triggered when clicked
$('#scroll-down').on('click', function () {
// Move to the pre-defined anchor point
// Insert <div id="scroll-down-anchor"></div> to where you want to scroll to
$('html, body').animate({
scrollTop: $('[id=scroll-down-anchor]').position().top
// Set the speed of the scroll here (currently set to 1000 ms)
}, 1000);
});
});
I'm still not sure from the screencast what you want to do with the behaviour based on the window position when the window is scrolled.
UPDATE: In light of the screencast and further information.
The code has been updated, BUT, although this is, I think, what your code was trying to achieve, I don't think the effect is very nice at all because you're intercepting a user's intention, hijacking it, and making something different happen. It's also very choppy, and to improve that would probably take many more lines of code (eg to determine speed of existing scroll, intercept that and make it accelerate organically - way beyond the scope of this kind of answer). Maybe there's a plugin out there to do this nicely.
Anyway, I think this code completes what you were trying to achieve, but the end effect, although subjective, is not very nice in my opinion. I've put in explanatory comments:
jQuery(document).ready(function ($) {
// Variable to store scrolling state
var scrolling = false;
// Variable to store position to determine whether scrolling up or scrolling down
var previousScroll = 0;
$(window).scroll(function () {
// Only is state is not 'scrolling' (ie not to run if button has been clicked)
if (scrolling === false) {
// Get position
var currentScroll = $(this).scrollTop();
// Compare position to stored variable: scrolling up or scrolling down
if (currentScroll > previousScroll) {
// Determine if position is 'within the zone' - set here to 50px
if (currentScroll < 50 && currentScroll !== 0) {
console.log('IN ZONE');
// Trigger button click
$('#scroll-down').trigger('click');
} else {
// Normal scrolling down code, outside zone
console.log('SCROLLING DOWN ');
}
}
else {
// Scrolling up code
console.log('SCROLLING UP ');
}
// Set variable for comparison of next scroll event
previousScroll = currentScroll;
}
});
// The button is assumed to have an id of 'scroll-down' - triggered when clicked
$('#scroll-down').on('click', function () {
// Set the scrolling state
scrolling = true;
// Animate with callback to set scrolling back to 'true' when complete
$('html, body').animate({ scrollTop: $('[id=scroll-down-anchor]').position().top }, 1000, function () {
// Callback code - set scrolling state to be false when animation has finished
scrolling = false;
});
});
});

JavaScript media queries breaking greensock

I am trying to create a Navigation Bar that slides in and out when clicked on using JavaScript and Greensock. For some reason, the on click action is randomly not working when clicked on at different sizes but sometimes it works perfectly fine.
My code is below, you can find a live example of this navigation at: http://www.kramergraphicdesign.com/Maura_Website/
var resize = function(){
var viewportWidth = $(window).width();
var lastLiWith = $('#logo').width();
console.log(openOrShut + " this is the true false var");
if ($(window).width() >= 0 && $(window).width() <= 639 ) {
console.log("mobile");
$("#logo, #close, .arrow-right").click(function()
{
console.log("mobile-click");
if(openOrShut === false)
{
TweenLite.to("#custom-nav",".5",{x:viewportWidth-lastLiWith});
openOrShut = true;
}
else{
TweenLite.to("#custom-nav",".5",{x:0});
openOrShut = false;
}
});
}
else if ($(window).width() >= 640 ) {
console.log("tablet");
$("#logo, #close, .arrow-right").click(function()
{
console.log("tablet-click");
if(openOrShut === false)
{
TweenLite.to("#custom-nav",".5",{x:400});
openOrShut = true;
}
else{
TweenLite.to("#custom-nav",".5",{x:0});
openOrShut = false;
}
});
}
else if ($(window).width() >= 1025 && $(window).width() <= 10000 ) {
console.log("dekstop");
$("#logo, #close, .arrow-right").click(function()
{
console.log("desktop-click");
if(openOrShut === false)
{
TweenLite.to("#custom-nav",".5",{x:400});
openOrShut = true;
}
else{
TweenLite.to("#custom-nav",".5",{x:0});
openOrShut = false;
}
});
}
};
$(document).ready(resize);
$(window).resize(function(){
resize();
});
First of all, the resize event can occur an awful lot, especially during a drag to resize the window. This means two things:
Minimise the amount of work you do so it runs fast, or debounce the function (e.g. using Lodash) so it only runs after you stop receiving resize events for a short time.
More importantly, you are adding a new click handler every single time.
So the reason it "randomly" doesn't do anything is that whenever you click, you actually run your function to toggle the menu many, many times if you have previously resized the window at all. If that number of times happens to be even, then there is no net effect.
There are probably a number of ways to fix this, but here are two:
Attach a click handler once, but check the width inside the handler to determine how far to animate it to / how to respond differently to different sizes.
Unregister existing click events first (using jQuery's .off()) before re-adding them, so there is only ever the one handler registered. I recommend using an event namespace so you can deregister everything on the namespace at once.
Bonus observation: your condition for the tablet widths means the desktop code will never run, because there is no <= 1024 condition for the tablet block.

Scroll position based javascript animation does not revert to it's original state when scrolling back up

See the JSFiddle here: http://jsfiddle.net/jL6d2qp6/
I have an animation that is supposed to keep the #top element in a fixed position at the top of the page, except for when the #login element is on the screen. To control this, I am using a javascript function that runs every 10ms and switches out the css class for #top, and when I scroll down, it updates as expected, but when I try to scroll back up, nothing happens.
javascript code in question:
offScreen = function(id, targetValue)
{
var offset = $("#top").offset();
var w = $(window);
var height = $(id).innerHeight();
var finalOffset = (offset.top + height) - w.scrollTop();
if (finalOffset < targetValue)
{
return true;
}
else
{
return false;
}
}
function updateTopMenu()
{
if (offScreen("#login", 81) === false)
{
if($("#top").hasClass("top-bar-absolute") === false)
{
$("#top").addClass("top-bar-absolute");
console.log("added top-bar-absolute");
}
if($("#top").hasClass("top-bar-fixed") === true)
{
$("#top").removeClass("top-bar-fixed");
console.log("removed top-bar-fixed");
}
}
if(offScreen("#login", 81) === true)
{
if($("#top").hasClass("top-bar-absolute") === true)
{
$("#top").removeClass("top-bar-absolute");
console.log("removed top-bar-absolute");
}
if($("#top").hasClass("top-bar-fixed") === false)
{
$("#top").addClass("top-bar-fixed");
console.log("added top-bar-fixed");
}
}
}
$("#top").ready( function() {
setInterval(updateTopMenu, 10);
});
Also, if there is a better way to accomplish this, I'd like it because this feels kind of cheaty.
The easiest way to achieve this is listening to the scroll event on the window. This is called every time the user scrolls. Then you can check whether the user scrolled past the login box, i.e. beyond the login box's height.
If the login box is no longer in the window, assign the #top box a class like .sticky that will change its position to position: fixed. And otherwise remove this class.
Checkout this jsFiddle.

Distinguishing between the user scrolling and programmatically scrolling using Javascript

I'm creating a scrolling effect using JQuery and I'm wondering if it's possible to distinguish between the user scrolling vs. programmatically scrolling.
I have something like this:
$('#element').on('scroll',function(e){
$('#element').stop(true); // stop previous scrolling animation
$('#element').animate({ // start new scrolling animation (maybe different speed, different direction, etc)
scrollTop:...
});
});
However, this event is triggered during every step of the animation. How can I tell if this event was triggered by the user or by the animation?
Use a variable to determine when you are scrolling programmatically
Example:
var programScrolling = false;
$('#element').on('scroll',function(e){
if (programScrolling) {
return;
}
$('#element').stop(true); // stop scrolling animation
programScrolling = true;
$('#element').animate({
scrollTop:...
});
programScrolling = false;
});
Not sure if that is exactly what you want, but the concept should work.
I would make functions for different kinds of scrollings to detect them and call a scroll handler for all of them, like so:
JS Fiddle
$(window).bind('mousewheel DOMMouseScroll', function(event){
var direction;
if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
direction = 'up';
}
else {
direction = 'down';
}
scrollHandler(direction, 'mouseWheel');
event.preventDefault();
});
var scrollHandler = function(direction, origin) {
var height = $(document).scrollTop();
var movement = (direction == 'up') ? -100 : 100;
console.log(origin);
$('body').stop(true);
$('body').animate({
scrollTop: height + movement
}, 250);
};
Then you can do different stuff according to the origin of the event!
You could also check if the user scrolls to the same direction that the screen is scrolling and do something different, or whatever you want with the info passed by the mousewheel event.
Original mousewheel event function copied from THIS answer
I would suggest possibly using the .originalEvent method. The downside is, this is very browser dependent. See here. Hopefully the following helps:
$('#element').scroll(function(e){
var humanScroll = e.originalEvent === undefined;
if(humanScroll) {
$(this).stop(true);
}
})

Categories

Resources