Speed up wheel scroll based event - javascript

I have a custom script which advances a small icon upon wheel scroll. It works well but it's not advancing the element as quickly as I would like. I'd like to increase the distance that the element (pill) moves per wheel scroll. How can I alter the code to facilitate this? Thanks for any insight. Code:
function wheel(e) {
var modelContentWrapper = $('.model-content-wrapper');
var howModelWorks_steps = $('#howModelWorks_steps');
var currentIndex = $('.model-content.active', modelContentWrapper).index();
var $pill = $('.step_' + (currentIndex + 1) + ' > a.clickable-icon');
var $li = $('ul.steps li');
var $pillStep = ($li.width()) / wheelSpeed;
direction = 'right';
if ((e.wheelDelta && e.wheelDelta >= 0) || (e.detail && e.detail < 0)) {
wheelValue++;
if ((firstElement && parseInt($pill.css('margin-left')) > initialIconLeft) || (!firstElement)) {
$pill.css('margin-left', (parseInt($pill.css('margin-left')) - $pillStep) + 'rem');
}
if (wheelValue >= wheelSpeed) {
wheelValue = wheelValue - wheelSpeed;
forceModelBackward();
}
//direction = 'left';
}
else {
wheelValue--;
//direction = 'right';
if (!lastElement) {
$pill.css('margin-left', (parseInt($pill.css('margin-left')) + $pillStep) + 'rem');
}
if (Math.abs(wheelValue) == wheelSpeed) {
wheelValue = wheelValue + wheelSpeed;
forceModelForward();
}
}
//if (wheelValue > (wheelSpeed * 5) || wheelValue < (wheelSpeed * -5)) {
if (stepsCounter == 1 || stepsCounter == 4) {
enableScroll();
}
preventDefault(e);
}

Try adding the follow to your event listener..
capture: true,
passive: true
Passive Event Listeners allow you to attach un-cancelable handlers to events, letting browsers optimize around your event listeners. The browser can then, for example, keep scrolling at native speed without waiting for your event handlers to finish executing.
Usage
Probably what is used mostly:
// Really, if you're using wheel, you should instead be using the 'scroll' event,
// as it's passive by default.
document.addEventListener('wheel', (evt) => {
// ... do stuff with evt
}, true)
You’ll need to replace it with this:
document.addEventListener('wheel', (evt) => {
// ... do stuff with evt
}, {
capture: true,
passive: true
})
Copied information from alligator dot io

Related

How can I make the webpage slow down autoscrolling on a button press?

As the title says - I'm looking to add some auto-scrolling on a specific webpage but the script that I have at the moment stops it completely from scrolling, which doesn't look visually appealing during presentations IMHO.
Is there a possibility to slow down instead of harshly stopping the auto-scrolling of the webpage on a specific keystroke?
This is the JS that I tried.
let scrollerID;
let paused = true;
let speed = 2; // 1 - Fast | 2 - Medium | 3 - Slow
let interval = speed * 5;
function startScroll(){
let id = setInterval(function() {
window.scrollBy(0, 2);
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
// Reached end of page
stopScroll();
}
}, interval);
return id;
}
function stopScroll() {
clearInterval(scrollerID);
}
document.body.addEventListener('keypress', function (event)
{
if (event.which == 13 || event.keyCode == 13) {
// It's the 'Enter' key
if(paused == true) {
scrollerID = startScroll();
paused = false;
}
else {
stopScroll();
paused = true;
}
}
}, true);
Thanks in advance!

How to control the interval of time between triggering of mousewheel event

I'm currently writing a website for a movie making company, which shows their different movies in full-screen.
I put each video in a list, and wrote a function that takes the user to the next video everytime a mousewheel event is triggered. The problem is that when the user is mousewheeling with a trackpad, it triggers multiple events at once, so I figured, I just had to set an interval between each triggering, depending on a variable "animating" that would be either true or false.
So here's my code :
let animating = false
$(window).bind('mousewheel', function (event) {
if (event.originalEvent.wheelDelta >= 0 && actuallyPlaying === false && animating === false) {
animating = true;
goToPreviousVideo();
setInterval(function () {
animating = false
}, 2000)
}
else {
if (actuallyPlaying === false && animating === false) {
animating = true;
goToNextVideo();
setInterval(function () {
animating = false
}, 2000)
};
}
});
And this piece of code works fine, but only for a few video "swipes". I noticed that after two or three times, this function stops working, and many events get triggered at the same time, which results in skipping all the videos and going from the top of the page straight to the bottom.
Do you guys have any idea why this isn't working ?
I'm also adding the code of goToNextVideo() and goToPreviousVideo() in case the problem is with them :
let i = 1 //
const goToNextVideo = function () {
if (i === 4) { // because I've got 4 videos
return;
} else {
$('html, body').animate({
scrollTop: $(`.video-${i + 1}`).offset().top
}, 500);
$(`.video-${i + 1}`).get(0).play();
i += 1
$(`.video-${i - 1}`).get(0).pause();
}
};
const goToPreviousVideo = function () {
if (i === 1) {
return
} else {
$('html, body').animate({
scrollTop: $(`.video-${i - 1}`).offset().top
}, 500);
$(`.video-${i}`).get(0).pause();
i -= 1
$(`.video-${i}`).get(0).play();
}
};
Thanks for your help !
Wish you all a great day
its seems your error is coming from the fact you dont clear the setInterval,
let animating = -1;
$(window).bind('mousewheel', function (event) {
if (event.originalEvent.wheelDelta >= 0 && actuallyPlaying === false && animating < 0) {
animating = setInterval(function () {
clearInterval(animating);
animating = -1;
}, 2000)
goToPreviousVideo();
}
else {
if (actuallyPlaying === false && animating < 0) {
animating = setInterval(function () {
clearInterval(animating);
animating = -1;
}, 2000)
goToNextVideo();
}
}
});
I am not able to understand where the problem is lying but
I have a cleaner and better approach to doing this Please tell if it works
var lastVideoChangeAnimation = Date.now()-2001;
$(window).bind('mousewheel', function (event) {
if (event.originalEvent.wheelDelta >= 0 && actuallyPlaying === false && Date.now()-lastAlertTime>2000) {
lastVideoChangeAnimation = Date.now();
goToPreviousVideo();
}
else if (actuallyPlaying === false && Date.now()-lastAlertTime>2000) {
lastVideoChangeAnimation = Date.now();
goToNextVideo();
};
});
THERE CAN ALSO BE A PROBLEM THAT THERE OCCURS SOME SORT OF ERROR AND YOUR CODE STOPS EXECUTING.
SO JUST CHECK IF THE CONSOLE IS GIVING SOME ERROR WITH POINTING TOWARDS THE FILE WHERE THESE TWO CODES ARE SAVED.
Also please tell in the comment that did it worked

mousewheel e.delta not working right in firefox?

I'm making a single-page website that reacts to mouse wheel events.
var supportsWheel = false;
function DoSomething (e) {
if (e.type == "wheel") supportsWheel = true;
else if (supportsWheel) return;
var delta = ((e.deltaY || -e.wheelDelta || e.detail) >> 10) || 1;
//if mousewheel is going up
if (delta > 0) {
slideDown();
}
//if mousewheel is going down
else if (delta < 0) {
slideUp();
}
}
document.addEventListener('wheel', DoSomething);
document.addEventListener('mousewheel', DoSomething);
document.addEventListener('DOMMouseScroll', DoSomething);
So this works perfectly in chrome and safari but in firefox, both directions of the mouse wheel activate slideDown() function. As opposed to declaring slideUp when the mouse wheel goes up and slideDown when it's going down. Any ideas how to fix it?
This is because you normalize deltaY = 0 as down, and that you probably have some smooth-scrolling set-up in Firefox, or in your OS:
This smooth scrolling feature will make your delta get linearly smaller, until they reach 0. So, when you initiate a Wheel event from your mouse/scrollpad, it will often end with an event which deltaY will be 0.
You can check this theory with this modified code, which will output the cases where the deltaY is 0 separately.
var supportsWheel = false;
function DoSomething(e) {
if (e.type == "wheel") supportsWheel = true;
else if (supportsWheel) return;
var e_delta = (e.deltaY || -e.wheelDelta || e.detail);
var delta = e_delta && ((e_delta >> 10) || 1) || 0;
if (delta > 0) {
slideDown();
} else if (delta < 0) {
slideUp();
} else if (!delta) {
donnotSlide();
}
}
document.addEventListener('wheel', DoSomething);
function slideDown() {
console.log('down');
}
function slideUp() {
console.log('up');
}
function donnotSlide() {
console.log('was zero');
}
Use your mouse wheel
But to say the truth, I don't really see why you do normalize this delta info... Usually you want to react to its values.

KeyDown doesn't continuously fire when pressed and hold

I have this Plunkr,
This contains a div, on which I bind a keydown event. On pressing right or left arrow, the div should start moving.
This works, in all browsers, but when the key is pressed and hold, the first keydown event is fired immediately (div once moves), and it waits for a time gap, and then it continues to move.
So this means the keydown event is once fired, then the browser waits to detect if there is a subsequent keyUp event as well, then after a short time (when there is no keyup), it continues to fires keydown events.
(to see the problem, focus on window, press right arrow and hold, div should move once 5px, then wait, and then again continue to move)
Question: Is there a way around, so I can just keep the key pressed, and div should immediately start moving, without waiting to detect subsequent keyup (once)?
$(function() {
$(window).keydown(function(e) {
console.log(e.keyCode)
if (e.keyCode == 39)
move(5, 'left', $('.mover'))
else if (e.keyCode == 37)
move(-5, 'left', $('.mover'))
})
})
function move(offset, direction, target) {
console.log($(target))
$(target).css(direction, (parseInt($(target).css(direction)) + offset) + 'px')
}
.mover {
height: 50px;
width: 50px;
display: inline-block;
background: black;
position: absolute;
left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class='mover'></div>
I would suggest something on a timeout, like this
http://codepen.io/kevrowe/pen/qEgGVO
$(function() {
var direction,
movingTimeout = -1;
$(window).on('keydown', function(e) {
if (e.keyCode == 39) {
direction = 'right';
} else if (e.keyCode == 37) {
direction = 'left';
}
startMoving(direction);
});
function stopMoving() {
clearTimeout(movingTimeout);
movingTimeout = -1;
}
function startMoving(direction) {
if (movingTimeout === -1) {
loop(direction);
}
}
function loop(direction) {
move(direction === 'left' ? -5 : 5, $('.mover'));
movingTimeout = setTimeout(loop, 10, direction);
}
function move(offset, $target) {
$target.css('left', (parseInt($target.css('left')) + offset) + 'px')
}
$(window).on('keyup', function(e) {
stopMoving();
});
})
When keydown event occurs on the key you want to track, then store this information in a mapping or a flag somewhere.
When keyup event occurs, then clear the flag for the given key.
Then, on a timer, you could poll the state of the key mapping, and move the object for whatever key direction is being pressed.
Possibly there is a better solution then polling, but I don't know of a way to test if a key is down other than polling.
On keyup, would also need to check if needed to interrupt moving the object.
One solution would be to just continuously run the move function in a loop until keyup happens
if (e.keyCode == 39){
var stop = setInterval(function(){
move(5, 'left', $('.mover'))
}, 25);
window.on("keyup", function(){
//stop the loop
clearInterval(stop);
//and remove the keyup listener
window.off("keyup", arguments.callee);
})
} else if //etc...
For those that might interest, here is another approach to handle bi-directional movement. Ex: up + right keys = "North East" direction :
const FPS = 60;
const STEP = 5;
const UP_KEY = 90; // Z
const DOWN_KEY = 83; // S
const LEFT_KEY = 81; // Q
const RIGHT_KEY = 68; // D
const pressedKeys = [];
let movingTimeout = null;
function handleKeyDown(e) {
pressedKeys[e.keyCode] = true;
switch(e.keyCode) {
case DOWN_KEY:
case LEFT_KEY:
case RIGHT_KEY:
case UP_KEY:
e.preventDefault();
startMoving();
}
}
function handleKeyUp(e) {
pressedKeys[e.keyCode] = false;
const shouldStop = !pressedKeys[UP_KEY]
&& !pressedKeys[DOWN_KEY]
&& !pressedKeys[LEFT_KEY]
&& !pressedKeys[RIGHT_KEY]
;
if(shouldStop) {
stopMoving();
}
}
function startMoving() {
if(!movingTimeout){
loop();
}
}
function stopMoving() {
clearTimeout(movingTimeout);
movingTimeout = null;
}
function loop() {
const x = pressedKeys[RIGHT_KEY] ? STEP
: pressedKeys[LEFT_KEY] ? -STEP : 0;
const y = pressedKeys[DOWN_KEY] ? STEP
: pressedKeys[UP_KEY] ? -STEP : 0;
move(x, y);
movingTimeout = setTimeout(loop, 1000 / FPS);
}
function move(x, y) {
// Implement you own logic here for positioning / handling collisions
// Ex: store.dispatch({ type: "MOVE_PLAYER", x, y });
console.log(`Moving ${x} ${y} !`);
}
window.addEventListener('keydown', e => handleKeyDown(e));
window.addEventListener('keyup', e => handleKeyUp(e));
Hope this helps.
Cheers !
pure javascript
<input id="some" type="text">
var input=document.getElementById("some");
input.addEventListener("keydown",function(e){
if (e.which == 40) {
var stop = setInterval(function(){
console.log("ss:");
}, 60);
window.addEventListener("keyup", function(){
//stop the loop
clearInterval(stop);
//and remove the keyup listener
window.removeEventListener("keyup", arguments.callee);
})
}
})

mouse wheel to be use for swipe

i have a function which works for mouse wheel and i want to use the same function for swipe.
// Mouse Wheel support
this.MouseWheel =
{
init: function()
{
// Init mouse wheel listener
if(window.addEventListener)
{
my.ImageFlowDiv.addEventListener('DOMMouseScroll', my.MouseWheel.get, false);
}
my.Helper.addEvent(my.ImageFlowDiv,'mousewheel',my.MouseWheel.get);
},
get: function(event)
{
var delta = 0;
if (!event)
{
event = window.event;
}
if (event.wheelDelta)
{
delta = event.wheelDelta / 120;
}
else if (event.detail)
{
delta = -event.detail / 3;
}
if (delta)
{
my.MouseWheel.handle(delta);
}
my.Helper.suppressBrowserDefault(event);
},
handle: function(delta)
{
alert('handle called');
var change = false;
var newImageID = 0;
if(delta > 0)
{
if(my.imageID >= 1)
{
newImageID = my.imageID -3;
change = true;
}
}
else
{
if(my.imageID < (my.max-1))
{
newImageID = my.imageID +4;
change = true;
}
}
/* Glide to next (mouse wheel down) / previous (mouse wheel up) image */
if(change)
{
//alert('new image id='+newImageID);
my.glideOnEvent(newImageID);
}
}
};
Earlier i used the touchswipe plugin and it was working fine but i want to use another plugin as touchswipe is disturbing touch support.
$("#imageFlow").swipe({
swipe:function(event, direction, distance, duration, fingerCount) {
alert('swipe called');
if(direction == 'left') {
my.MouseWheel.handle(-1);
} else if (direction == 'right') {
my.MouseWheel.handle(1);
}
}
});
Have you taken a look at Hammer JS? I find their syntax is fairly simple to use and does not interfere with my other touch events.
Your code could then look similar to this:
Hammer($('#imageFlow')).on("swipe", function(event) {
console.log('swipe called'); //(instead of alert)
if (event.gesture.direction === 'left'){
my.MouseWheel.handle(-1);
} else if (event.gesture.direction === 'right'){
my.MouseWheel.handle(1);
};
});
In the docs
Also bear in mind to use 3 equals signs in JavaScript. so:
if (myName === 'Jean-Marie'){//dostuff}
instead of
if (myName == 'Jean-Marie'){//dostuff}

Categories

Resources