my-animation-lib
Version:
A powerful animation library combining Three.js, GSAP, custom scroll triggers, and advanced effects with MathUtils integration
203 lines (172 loc) • 5.36 kB
JavaScript
import { gsap } from 'gsap';
export class HiTechScroller {
constructor(container, options = {}) {
this.container = container;
this.options = {
speed: options.speed || 1,
smoothness: options.smoothness || 0.1,
showProgress: options.showProgress || true,
showIndicator: options.showIndicator || true,
...options
};
this.currentScroll = 0;
this.targetScroll = 0;
this.isScrolling = false;
this.progressBar = null;
this.scrollIndicator = null;
this.sections = [];
this.init();
}
init() {
this.setupContainer();
this.createProgressBar();
this.createScrollIndicator();
this.setupEventListeners();
this.animate();
}
setupContainer() {
this.container.style.position = 'relative';
this.container.style.overflow = 'hidden';
this.container.style.height = '100vh';
}
createProgressBar() {
if (!this.options.showProgress) return;
this.progressBar = document.createElement('div');
this.progressBar.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 0%;
height: 3px;
background: linear-gradient(90deg, #00ff88, #00ccff, #ff0088);
z-index: 1000;
transition: width 0.1s ease;
`;
document.body.appendChild(this.progressBar);
}
createScrollIndicator() {
if (!this.options.showIndicator) return;
this.scrollIndicator = document.createElement('div');
this.scrollIndicator.style.cssText = `
position: fixed;
right: 20px;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 100px;
background: rgba(255, 255, 255, 0.2);
border-radius: 2px;
z-index: 1000;
`;
const indicatorDot = document.createElement('div');
indicatorDot.style.cssText = `
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 20px;
background: linear-gradient(180deg, #00ff88, #00ccff);
border-radius: 2px;
transition: top 0.1s ease;
`;
this.scrollIndicator.appendChild(indicatorDot);
this.indicatorDot = indicatorDot;
document.body.appendChild(this.scrollIndicator);
}
setupEventListeners() {
window.addEventListener('wheel', this.handleWheel.bind(this));
window.addEventListener('keydown', this.handleKeydown.bind(this));
window.addEventListener('resize', this.handleResize.bind(this));
}
handleWheel(event) {
event.preventDefault();
const delta = event.deltaY * this.options.speed;
this.targetScroll += delta;
this.targetScroll = Math.max(0, this.targetScroll);
this.targetScroll = Math.min(this.getMaxScroll(), this.targetScroll);
this.isScrolling = true;
setTimeout(() => {
this.isScrolling = false;
}, 150);
}
handleKeydown(event) {
switch (event.key) {
case 'ArrowDown':
case 'PageDown':
event.preventDefault();
this.scrollTo(this.targetScroll + window.innerHeight);
break;
case 'ArrowUp':
case 'PageUp':
event.preventDefault();
this.scrollTo(this.targetScroll - window.innerHeight);
break;
case 'Home':
event.preventDefault();
this.scrollTo(0);
break;
case 'End':
event.preventDefault();
this.scrollTo(this.getMaxScroll());
break;
}
}
handleResize() {
this.updateProgressBar();
this.updateScrollIndicator();
}
animate() {
if (Math.abs(this.currentScroll - this.targetScroll) > 0.1) {
this.currentScroll += (this.targetScroll - this.currentScroll) * this.options.smoothness;
this.updateScroll();
}
requestAnimationFrame(this.animate.bind(this));
}
updateScroll() {
this.container.style.transform = `translateY(-${this.currentScroll}px)`;
this.updateProgressBar();
this.updateScrollIndicator();
}
updateProgressBar() {
if (this.progressBar) {
const progress = (this.currentScroll / this.getMaxScroll()) * 100;
this.progressBar.style.width = `${progress}%`;
}
}
updateScrollIndicator() {
if (this.indicatorDot) {
const progress = (this.currentScroll / this.getMaxScroll()) * 80;
this.indicatorDot.style.top = `${progress}%`;
}
}
getMaxScroll() {
return Math.max(0, this.container.scrollHeight - window.innerHeight);
}
scrollTo(position, duration = 1) {
gsap.to(this, {
targetScroll: position,
duration: duration,
ease: "power2.out"
});
}
scrollToSection(index, duration = 1) {
if (this.sections[index]) {
const position = this.sections[index].offsetTop;
this.scrollTo(position, duration);
}
}
addSection(section) {
this.sections.push(section);
}
destroy() {
window.removeEventListener('wheel', this.handleWheel);
window.removeEventListener('keydown', this.handleKeydown);
window.removeEventListener('resize', this.handleResize);
if (this.progressBar) {
document.body.removeChild(this.progressBar);
}
if (this.scrollIndicator) {
document.body.removeChild(this.scrollIndicator);
}
}
}