-
Notifications
You must be signed in to change notification settings - Fork 0
/
momentum.js
149 lines (119 loc) · 4.69 KB
/
momentum.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
function SmoothScroll(target, speed, smooth) {
if (target === document)
target =
document.scrollingElement ||
document.documentElement ||
document.body.parentNode ||
document.body; // cross browser support for document scrolling
var moving = false;
var pos = target.scrollTop;
var frame =
target === document.body && document.documentElement
? document.documentElement
: target; // safari is the new IE
target.addEventListener("mousewheel", scrolled, { passive: false });
target.addEventListener("DOMMouseScroll", scrolled, { passive: false });
function scrolled(e) {
e.stopPropagation(); // Prevent all scrolling events from bubbling up or affecting other scrollable elements
e.preventDefault(); // disable default scrolling
var delta = normalizeWheelDelta(e);
var scale = 1; // Adjust this value based on platform or device if necessary
if (Math.abs(delta) < 1) {
scale = 30; // Handle smaller deltas from trackpads or high-precision devices
}
// Cap the delta to avoid large jumps
delta = Math.max(-1, Math.min(1, delta));
pos += -delta * speed * scale;
pos = Math.max(-50, Math.min(pos, target.scrollHeight - frame.clientHeight + 50)); // limit scrolling
if (!moving) update();
}
function normalizeWheelDelta(e) {
if (e.deltaY) {
return -e.deltaY; // Standard Wheel Event
}
if (e.detail) {
return -e.detail / 3; // Firefox or older browsers
}
return e.wheelDelta / 120; // IE, Safari, Chrome
}
function update() {
moving = true;
const currentPos = target.scrollTop; // Cache current position
var delta = (pos - currentPos) / smooth;
target.scrollTop += delta;
if (Math.abs(delta) > 0.5 && target.scrollTop !== currentPos) {
requestFrame(update); // Continue scrolling only if scroll position changed
} else {
moving = false; // Stop if we are close enough or no further movement
}
}
var requestFrame = (function () {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (func) {
window.setTimeout(func, 1000 / 120);
}
);
})();
// Attach listeners on hover
target.addEventListener("mouseenter", function () {
target.addEventListener("wheel", scrolled, { passive: false });
});
// Remove listeners when mouse leaves
target.addEventListener("mouseleave", function () {
target.removeEventListener("wheel", scrolled);
});
this.scrollTo = function (targetElement) {
pos = target.scrollTop;
var targetPos = targetElement.getBoundingClientRect().top + pos;
function animateScroll() {
var delta = (targetPos - pos) / smooth;
pos += delta;
target.scrollTop = pos;
if (Math.abs(delta) > 0.5) {
requestFrame(animateScroll);
} else {
moving = false;
}
}
animateScroll();
};
}
// Function to check if an element is scrollable
function isScrollable(el) {
const hasScrollableContent = el.scrollHeight > el.clientHeight;
const overflowYStyle = window.getComputedStyle(el).overflowY;
const isOverflowAutoOrScroll = overflowYStyle === 'auto' || overflowYStyle === 'scroll';
return hasScrollableContent && isOverflowAutoOrScroll;
}
// Apply SmoothScroll to all scrollable elements and the document itself
function applySmoothScrollToAll() {
// Apply to the document (page scroll)
new SmoothScroll(document, 150, 50);
// Find all scrollable elements and apply SmoothScroll
const allElements = document.querySelectorAll('*');
allElements.forEach(el => {
if (isScrollable(el)) {
new SmoothScroll(el, 150, 50);
}
});
}
// Reapply smooth scroll whenever elements are dynamically added
function reapplySmoothScrollOnMutation() {
const observer = new MutationObserver(() => {
applySmoothScrollToAll();
});
observer.observe(document.body, {
childList: true, // Watch for new elements being added
subtree: true, // Observe the entire subtree
});
}
// Run after the DOM is fully loaded
window.addEventListener('DOMContentLoaded', () => {
applySmoothScrollToAll();
reapplySmoothScrollOnMutation(); // Observe and reapply for dynamic content
});