Using arrow keys to navigate grid of divs wount scroll overflown contents - javascript

Here's a solution i found on stackoverflow
this solution works for me except that when the contents of the div is overflown the contents do not scroll alongside the arrow keys, like scroll seems to be much slower after the 5 or 6 rows.
Please here's an updated jsFiddle of the answer above
var position = { x: 0, y: 0 };
var calendarMap = [];
$(document).ready(function () {
$('.row').each(function () {
calendarMap.push([]);
$('.day, .date', this).each(function () {
calendarMap[calendarMap.length - 1].push($(this));
});
});
highlightCell();
});
$(window).on('keydown', function (e) {
if (e.keyCode === 37) // left
moveLeft();
else if (e.keyCode === 38) // up
moveUp();
else if (e.keyCode === 39) // right
moveRight();
else if (e.keyCode === 40) // down
moveDown();
highlightCell();
});
function moveLeft() {
position.x--;
if (position.x < 0)
position.x = 0;
}
function moveUp() {
position.y--;
if (position.y < 0)
position.y = 0;
}
function moveRight() {
position.x++;
if (position.x >= calendarMap[0].length)
position.x = calendarMap[0].length - 1;
}
function moveDown() {
position.y++;
if (position.y >= calendarMap.length)
position.y = calendarMap.length - 1;
}
function highlightCell() {
$('.day, .date').removeClass('selected');
calendarMap[position.y][position.x].addClass('selected');
}

If I understand this, your issue is that when scrolling with arrow-keys on your keyboard, your "selected character" inside the calender moves faster than the actual scroll bar...
This is because you are both moving the "selected" object AND scrolling with your keys. Moving the "selected" object within the calender is going on simultaneously to the regular scrolling. So two behaviors are going on at the same time, independent of each other, each triggered by the arrow key.
One solution would be to add a JS behavior to add extra scrolling with arrow-key usage... but then if the user uses their mouse to scroll in the window, things will be "off" again.
You can check out this post, it might help:
JScrollPane scrolling with arrow keys

Related

OnMouseScroll increment a variable JS

I want to make a JS function.
It will work like this :
If I use my Mouse Wheel to Scroll Down so my variable will decrement. And if I use my Mouse Wheel to Scroll Up my variable will increment
I want to put that in a Condition with a max and min number.
I will send you a screenshot of my website and you will understand
So like you see, I need to make it work without scrollbar. I've only one page in 100vh.
I've make something very bad but you will understand the idea
https://jsfiddle.net/tuzycreo/
i= 1;
if (i>0 && i<5) {
//if(MouseScrollUp)
//i++;
document.querySelector('.number').innerHTML = i;
//else if(MouseScrollDown)
//i--;
// document.querySelector('.number').innerHTML = number;
}
Thanks you guys !
You can try like this,
var scrollCount = 0,
latestScrollTop = 0,
doc = document.documentElement,
top = 0;
// Bind window scroll event
$(window).bind('scroll', function (e) {
top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
if (latestScrollTop < top) {
// Scroll down, increment value
scrollCount += 1;
} else {
// Scroll up, decrement value
scrollCount -= 1;
}
// Store latest scroll position for next position calculation
latestScrollTop = top;
});
I make something that is working for me
https://jsfiddle.net/u93c9eth/2/
var scrollCount = 1;
window.addEventListener('mousewheel', function(e){
if(e.wheelDelta<0 && scrollCount<5){
scrollCount++;
}
else if(e.wheelDelta>0 && scrollCount>1){
scrollCount--;
}
document.querySelector('.number').innerHTML = scrollCount;
});

Avoid jittery scrolling on horizontal touchpads when using Nicescroll and mousewheel.js

So I'm using mousewheel.js to handle mousewheel scrolling in any part of the document so I can scroll a custom scroller made by Nicescroll.
You can check a fiddle of it working here
Here's part of the code that handles the scrolling:
function activate_mousewheel()
{
$(document).bind('mousewheel', function(event, delta, deltaX, deltaY)
{
if(delta < 0)
{
console.log(1);
$('#postscroller').scrollTop($('#postscroller').scrollTop() + 60);
}
else
{
console.log(2);
$('#postscroller').scrollTop($('#postscroller').scrollTop() - 60);
}
});
}
Now my problem is that when this is used in a computer with a touchpad with horizontal scrolling enabled the movement is all jittery rendering it unusable. So this problem will affect people using any kind of laptop with horizontal scrolling like a chromebook or a macbook.
I've tried doing various fixes, playing with the deltas but to no avail.
I was hoping someone here could find a solution.
Thanks.
I had to find a solution for the problem myself, and after hours of trying and beeing creative here is what i came up with. Of course you have to modify it to integrate it to work smoothly with nicescroll etc. as this is plain JS:
Well I needed to get a solution. So I found a acceptable solution for this problem:
var scrolling = false;
var oldTime = 0;
var newTime = 0;
var isTouchPad;
var eventCount = 0;
var eventCountStart;
var mouseHandle = function (evt) {
var isTouchPadDefined = isTouchPad || typeof isTouchPad !== "undefined";
console.log(isTouchPadDefined);
if (!isTouchPadDefined) {
if (eventCount === 0) {
eventCountStart = new Date().getTime();
}
eventCount++;
if (new Date().getTime() - eventCountStart > 50) {
if (eventCount > 5) {
isTouchPad = true;
} else {
isTouchPad = false;
}
isTouchPadDefined = true;
}
}
if (isTouchPadDefined) {
// here you can do what you want
// i just wanted the direction, for swiping, so i have to prevent
// the multiple event calls to trigger multiple unwanted actions (trackpad)
if (!evt) evt = event;
var direction = (evt.detail<0 || evt.wheelDelta>0) ? 1 : -1;
if (isTouchPad) {
newTime = new Date().getTime();
if (!scrolling && newTime-oldTime > 550 ) {
scrolling = true;
if (direction < 0) {
// swipe down
} else {
// swipe up
}
setTimeout(function() {oldTime = new Date().getTime();scrolling = false}, 500);
}
} else {
if (direction < 0) {
// swipe down
} else {
// swipe up
}
}
}
}
And registering the events:
document.addEventListener("mousewheel", mouseHandle, false);
document.addEventListener("DOMMouseScroll", mouseHandle, false);
Here is how it works:
When the user first scrolls, it will detect and check that in 50ms not more than 5 events got triggered, which is pretty unusual for a normal mouse, but not for a trackpad.
Then there is the else part, which is not for importance for the detection, but rather a trick to call a function once like when a user swipes. Please come at me if I wasn't clear enough, it was very tricky to get this working, and is of course a less than ideal workaround.
Edit: I optimized the code now as much as I can. It detects the mouseroll on the second time and swipe on trackpad instantly. Removed also a lot of repeating and unnecessary code.
The mousewheel event fires a lot of times. So to regulate the event, so it doesn't fire as much, use a throttle function.
https://lodash.com/docs#throttle
Because the event will not fire as often, the performance should be better.
function onMouseWheel(event, delta, deltaX, deltaY)
{
if(delta < 0)
{
console.log(1);
$('#postscroller').scrollTop($('#postscroller').scrollTop() + 60);
}
else
{
console.log(2);
$('#postscroller').scrollTop($('#postscroller').scrollTop() - 60);
}
});
function activate_mousewheel()
{
$(document).bind('mousewheel', _.throttle(onMouseWheel, 100);
}

Javascript: Moving an Object with Arrow Keys

Im making a simple Tetris game. So far I have a Tetris piece that rotates when the space bar is clicked.
The next step for me is to move the objects left and right using the arrow keys. From looking at other Stack Questions I found that this was possible by changing the margins.
var angle = 0;
var obj = document.getElementById('image')
document.onkeydown = checkKey;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '32') {
rotate();
}
else if (e.keyCode == '37') {
moveLeft();
}
else if (e.keyCode == '39') {
moveRight();
}
}
function rotate() {
angle = angle + 90;
console.log(angle)
obj.className = "image" + angle;
console.log(obj.className)
if (angle == 360) {
angle = 0;
}
}
function moveLeft() {
obj.style.left = parseInt(obj.style.left) - 5 + 'px';
}
function moveRight() {
obj.style.left = parseInt(obj.style.left) + 5 + 'px';
}
For some reason this isn't working for me.
I've also re-created my code in a JSFiddle using a banana instead of a Tetris piece.
The problem is not with your Javascript, but with your styles. You need to absolutely position your image (banana in this case), and set an initial "left" value. The position: absolute; can be set either in the HTML or CSS, but the left: 0; must be set in the HTML style attribute. Here is an updated jsfiddle with the changes.

Add 1 to variable if scrolldown and subtract 1 to variable if scrollup

The title pretty much sums it up.
How do I add 1 to a variable if the user scrolls down, and subtract 1 to the same variable if the user scrolls up.
The variable must start with 0.
EDIT: For clarification, it must constantly add/subtract 1 if the user is scrolling up/down, and stop adding/subtracting if the user stops.
var x = 0;
$(document).on('mousewheel DOMMouseScroll', function (event) {
if (event.type == 'mousewheel') {
// scroll
if (event.originalEvent.wheelDelta > 0) {
// scroll down
x++;
}
else {
// scroll up
x--;
}
}
else if (event.type == 'DOMMouseScroll') {
if (event.originalEvent.detail > 0) {
// scroll down
x++;
}
else {
// scroll up
x--;
}
}
});
See jsFiddle

Scrolling child div scrolls the window, how do I stop that?

I have a div, with a scroll bar, When it reaches the end, my page starts scrolling. Is there anyway I can stop this behavior ?
You can inactivate the scrolling of the whole page by doing something like this:
<div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>
Found the solution.
http://jsbin.com/itajok
This is what I needed.
And this is the code.
http://jsbin.com/itajok/edit#javascript,html
Uses a jQuery Plug-in.
Update due to deprecation notice
From jquery-mousewheel:
The old behavior of adding three arguments (delta, deltaX, and deltaY)
to the event handler is now deprecated and will be removed in later
releases.
Then, event.deltaY must now be used:
var toolbox = $('#toolbox'),
height = toolbox.height(),
scrollHeight = toolbox.get(0).scrollHeight;
toolbox.off("mousewheel").on("mousewheel", function (event) {
var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
return !blockScrolling;
});
Demo
The selected solution is a work of art. Thought it was worthy of a plugin....
$.fn.scrollGuard = function() {
return this
.on( 'wheel', function ( e ) {
var event = e.originalEvent;
var d = event.wheelDelta || -event.detail;
this.scrollTop += ( d < 0 ? 1 : -1 ) * 30;
e.preventDefault();
});
};
This has been an ongoing inconvenience for me and this solution is so clean compared to other hacks I've seen. Curious to know how more about how it works and how widely supported it would be, but cheers to Jeevan and whoever originally came up with this. BTW - stackoverflow answer editor needs this!
UPDATE
I believe this is better in that it doesn't try to manipulate the DOM at all, only prevents bubbling conditionally...
$.fn.scrollGuard2 = function() {
return this
.on( 'wheel', function ( e ) {
var $this = $(this);
if (e.originalEvent.deltaY < 0) {
/* scrolling up */
return ($this.scrollTop() > 0);
} else {
/* scrolling down */
return ($this.scrollTop() + $this.innerHeight() < $this[0].scrollHeight);
}
})
;
};
Works great in chrome and much simpler than other solutions... let me know how it fares elsewhere...
FIDDLE
You could use a mouseover event on the div to disable the body scrollbar and then a mouseout event to activate it again?
E.g. The HTML
<div onmouseover="disableBodyScroll();" onmouseout="enableBodyScroll();">
content
</div>
And then the javascript like so:
var body = document.getElementsByTagName('body')[0];
function disableBodyScroll() {
body.style.overflowY = 'hidden';
}
function enableBodyScroll() {
body.style.overflowY = 'auto';
}
As answered here, most modern browsers now support the overscroll-behavior: none; CSS property, that prevents scroll chaining. And that's it, just one line!
Here's a cross-browser way to do this on the Y axis, it works on desktop and mobile. Tested on OSX and iOS.
var scrollArea = this.querySelector(".scroll-area");
scrollArea.addEventListener("wheel", function() {
var scrollTop = this.scrollTop;
var maxScroll = this.scrollHeight - this.offsetHeight;
var deltaY = event.deltaY;
if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
event.preventDefault();
}
}, {passive:false});
scrollArea.addEventListener("touchstart", function(event) {
this.previousClientY = event.touches[0].clientY;
}, {passive:false});
scrollArea.addEventListener("touchmove", function(event) {
var scrollTop = this.scrollTop;
var maxScroll = this.scrollHeight - this.offsetHeight;
var currentClientY = event.touches[0].clientY;
var deltaY = this.previousClientY - currentClientY;
if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
event.preventDefault();
}
this.previousClientY = currentClientY;
}, {passive:false});
I wrote resolving for this issue
var div;
div = document.getElementsByClassName('selector')[0];
div.addEventListener('mousewheel', function(e) {
if (div.clientHeight + div.scrollTop + e.deltaY >= div.scrollHeight) {
e.preventDefault();
div.scrollTop = div.scrollHeight;
} else if (div.scrollTop + e.deltaY <= 0) {
e.preventDefault();
div.scrollTop = 0;
}
}, false);
If I understand your question correctly, then you want to prevent scrolling of the main content when the mouse is over a div (let's say a sidebar). For that, the sidebar may not be a child of the scrolling container of the main content (which was the browser window), to prevent the scroll event from bubbling up to its parent.
This possibly requires some markup changes in the following manner:
<div id="wrapper">
<div id="content">
</div>
</div>
<div id="sidebar">
</div>
See it's working in this sample fiddle and compare that with this sample fiddle which has a slightly different mouse leave behavior of the sidebar.
See also scroll only one particular div with browser's main scrollbar.
this disables the scrolling on the window if you enter the selector element.
works like charms.
elements = $(".selector");
elements.on('mouseenter', function() {
window.currentScrollTop = $(window).scrollTop();
window.currentScrollLeft = $(window).scrollTop();
$(window).on("scroll.prevent", function() {
$(window).scrollTop(window.currentScrollTop);
$(window).scrollLeft(window.currentScrollLeft);
});
});
elements.on('mouseleave', function() {
$(window).off("scroll.prevent");
});
You can inactivate the scrolling of the whole page by doing something like this but display the scrollbar!
<div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>
$this.find('.scrollingDiv').on('mousewheel DOMMouseScroll', function (e) {
var delta = -e.originalEvent.wheelDelta || e.originalEvent.detail;
var scrollTop = this.scrollTop;
if((delta < 0 && scrollTop === 0) || (delta > 0 && this.scrollHeight - this.clientHeight - scrollTop === 0)) {
e.preventDefault();
}
});
Based on ceed's answer, here is a version that allows nesting scroll guarded elements. Only the element the mouse is over will scroll, and it scrolls quite smoothly. This version is also re-entrant. It can be used multiple times on the same element and will correctly remove and reinstall the handlers.
jQuery.fn.scrollGuard = function() {
this
.addClass('scroll-guarding')
.off('.scrollGuard').on('mouseenter.scrollGuard', function() {
var $g = $(this).parent().closest('.scroll-guarding');
$g = $g.length ? $g : $(window);
$g[0].myCst = $g.scrollTop();
$g[0].myCsl = $g.scrollLeft();
$g.off("scroll.prevent").on("scroll.prevent", function() {
$g.scrollTop($g[0].myCst);
$g.scrollLeft($g[0].myCsl);
});
})
.on('mouseleave.scrollGuard', function() {
var $g = $(this).parent().closest('.scroll-guarding');
$g = $g.length ? $g : $(window);
$g.off("scroll.prevent");
});
};
One easy way to use is to add a class, such as scroll-guard, to all the elements in the page that you allow scrolling on. Then use $('.scroll-guard').scrollGuard() to guard them.
If you apply an overflow: hidden style it should go away
edit: actually I read your question wrong, that will only hide the scroll bar but I don't think that's what you are looking for.
I couldn't get any of the answers to work in Chrome and Firefox, so I came up with this amalgamation:
$someElement.on('mousewheel DOMMouseScroll', scrollProtection);
function scrollProtection(event) {
var $this = $(this);
event = event.originalEvent;
var direction = (event.wheelDelta * -1) || (event.detail);
if (direction < 0) {
if ($this.scrollTop() <= 0) {
return false;
}
} else {
if ($this.scrollTop() + $this.innerHeight() >= $this[0].scrollHeight) {
return false;
}
}
}

Categories

Resources