Reputation: 67
Basically I need a function, or to better say it, a window event listener that performs an action every 1000px scrolled (both from up to down and from down to up). Every answer suggested that I used a module like so:
if (window.scrollY % 1000 == 0) {//do something}
but it doesn't work because window.scrollY doesn't return every single pixel, it might return let's say 5000, so 5000%1000 is actually 0, but another time it might return a number around 5000, like 5123 which wouldn't return 0 from the module operator. This is my JS function as of now:
window.addEventListener("scroll", e => {
scrollpos = window.scrollY;
// console.log(scrollDown);
console.log("\n pos: " + scrollpos);
if (scrollpos % 1000 == 0) {
// if (imgIndex < totImg - 1) {
// imgIndex++;
// } else {
// imgIndex = 0;
// }
// imgArr[imgIndex + 1].style.opacity = "0";
// imgArr[imgIndex].style.opacity = "1";
console.log("\n\n\nworked on: " + scrollpos+"\n\n\n");
}
});
I added some console logs where you can clearly see that the window.scrollY doesn't return every single pixel, and that's why the if as it is doesn't log the message every 1000px
Upvotes: 0
Views: 209
Reputation: 8159
You can keep track of the last position and each time the scroll event triggers, add the delta into a buffer. When such buffer will be over a given threshold (1000) it will trigger another action and the buffer will be reset.
https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY
The read-only scrollY property of the Window interface returns the number of pixels that the document is currently scrolled vertically.
So that's not enough to determine how much space was traveled since the latest scroll in the past. But if we store each time the latest retrieved value, only after we already used that value to calculate the distance between the previous position and the current one, we can each time cumulate the distance scrolled so far.
When such cumulated distance is over 1000, we reset the distance buffer and the counting loops again.
Worth saying that we used the Math.abs
above the difference between the current and previous positions, because the distance is a positive value anyway.
This solution will measure the distance travelled with the scrollbar to hit those 1000px checkpoints. It means that if you keep scrolling up and down intermittently 100px in each directions, after ten times it will reach the threshold. Such strategy was applied because of this question's sentence: "[...] that performs an action every 1000px scrolled (both from up to down and from down to up)"
It wasn't narrow enough and I opted for the distance. It seems instead it meant to measure the distance only along one direction. So that in the previous scenario where you scroll intermittently up and down without never hitting the threshold in one direction, the 1000px will never trigger. So instead the question was meant to say: if you scroll up as long as 1000px before hitting the back pedal and scrolling down again, the event should trigger
I hope the OP got the difference between the two solutions instead of just concluding they both work.
let lastPos = 0;
let buffer = 0;
window.addEventListener("scroll", e => {
const scrollpos = window.scrollY;
buffer += Math.abs(scrollpos - lastPos);
lastPos = scrollpos;
if (buffer >= 1000) {
buffer = 0;
console.log(`worked on: ${scrollpos}`);
}
logNumber(buffer.toFixed(2));
});
function logNumber(value){
document.getElementById('buffer').innerText = value;
}
body{
font-size: 20px;
}
.page{
height: 1000cm;
border: solid;
padding: 1em;
}
.topnav{
position: sticky;
top: 0;
text-align: right;
padding: 3em 6em;
}
#buffer{
border: solid 4px gray;
padding: .5em;
font-size: 40px;
font-weight: 600;
font-family: sans-serif;
}
<div class="topnav">
<span id="buffer">0</span>
</div>
<div class="page">Page content...</div>
Upvotes: 1
Reputation: 26
I'm going to provide an answer, although I'm not 100% sure that I understood the problem correctly.
From what I understand, the particular issue is that your modulo operation would be true only for 0, 1000, 2000, 3000, and so on. This could be fixed quite easily, using a state variable (prevScroll
) and integer division (Math.floor(window.scrollY / threshold)
):
let prevScroll = 0
const threshold = 1000
window.addEventListener("scroll", () => {
const currScroll = Math.floor(window.scrollY / threshold)
if (currScroll !== prevScroll) {
prevScroll = currScroll
// Your code
}
})
You could use this code instead if you want to start from a certain position:
let prevScroll = 0
const threshold = 1000
const startFrom = 1200 // This could be any positive integer you want
window.addEventListener("scroll", () => {
if(window.scrollY < startFrom) {
return
}
const currScroll = Math.floor(window.scrollY / threshold)
if (currScroll !== prevScroll) {
prevScroll = currScroll
// Your code
}
})
Upvotes: 1