generated from Templates_CodeFirst/templateHtmlCss
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
6.4 KiB
209 lines
6.4 KiB
class PortfolioAnimations {
|
|
constructor() {
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.setupIntersectionObserver();
|
|
this.setupMagneticEffects();
|
|
this.setupParallaxEffects();
|
|
this.addFloatingShapes();
|
|
}
|
|
|
|
|
|
setupIntersectionObserver() {
|
|
const observerOptions = {
|
|
threshold: 0.1,
|
|
rootMargin: '0px 0px -50px 0px'
|
|
};
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
const element = entry.target;
|
|
const animation = element.dataset.animation;
|
|
const delay = element.dataset.delay || 0;
|
|
|
|
setTimeout(() => {
|
|
element.classList.add(`animate-${animation}`);
|
|
|
|
if (element.dataset.counter) {
|
|
this.animateCounter(element);
|
|
}
|
|
}, delay);
|
|
|
|
observer.unobserve(element);
|
|
}
|
|
});
|
|
}, observerOptions);
|
|
|
|
document.querySelectorAll('.animate-on-scroll').forEach(el => {
|
|
observer.observe(el);
|
|
});
|
|
}
|
|
|
|
setupMagneticEffects() {
|
|
document.querySelectorAll('.magnetic').forEach(button => {
|
|
button.addEventListener('mousemove', (e) => {
|
|
const rect = button.getBoundingClientRect();
|
|
const x = e.clientX - rect.left - rect.width / 2;
|
|
const y = e.clientY - rect.top - rect.height / 2;
|
|
|
|
button.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(1.02)`;
|
|
});
|
|
|
|
button.addEventListener('mouseleave', () => {
|
|
button.style.transform = 'translate(0px, 0px) scale(1)';
|
|
});
|
|
});
|
|
}
|
|
|
|
setupParallaxEffects() {
|
|
window.addEventListener('scroll', () => {
|
|
const scrolled = window.pageYOffset;
|
|
const parallaxElements = document.querySelectorAll('.parallax');
|
|
|
|
parallaxElements.forEach(element => {
|
|
const speed = element.dataset.speed || 0.5;
|
|
const yPos = -(scrolled * speed);
|
|
element.style.transform = `translateY(${yPos}px)`;
|
|
});
|
|
});
|
|
}
|
|
|
|
animateCounter(element) {
|
|
const target = parseInt(element.dataset.counter);
|
|
const duration = 2000;
|
|
const start = 0;
|
|
const increment = target / (duration / 16);
|
|
let current = start;
|
|
|
|
const timer = setInterval(() => {
|
|
current += increment;
|
|
if (current >= target) {
|
|
current = target;
|
|
clearInterval(timer);
|
|
}
|
|
element.textContent = Math.floor(current);
|
|
}, 16);
|
|
}
|
|
|
|
addFloatingShapes() {
|
|
const hero = document.querySelector('.hero-gradient');
|
|
if (!hero) return;
|
|
|
|
const shapesContainer = document.createElement('div');
|
|
shapesContainer.className = 'floating-shapes';
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
const shape = document.createElement('div');
|
|
shape.className = 'floating-shape';
|
|
shapesContainer.appendChild(shape);
|
|
}
|
|
|
|
hero.appendChild(shapesContainer);
|
|
}
|
|
|
|
static typeWriter(element, text, speed = 100) {
|
|
let i = 0;
|
|
element.textContent = '';
|
|
|
|
function type() {
|
|
if (i < text.length) {
|
|
element.textContent += text.charAt(i);
|
|
i++;
|
|
setTimeout(type, speed);
|
|
}
|
|
}
|
|
|
|
type();
|
|
}
|
|
|
|
static revealText(element) {
|
|
const text = element.textContent;
|
|
const words = text.split(' ');
|
|
element.innerHTML = '';
|
|
|
|
words.forEach((word, index) => {
|
|
const span = document.createElement('span');
|
|
span.textContent = word + ' ';
|
|
span.style.opacity = '0';
|
|
span.style.transform = 'translateY(20px)';
|
|
span.style.transition = `all 0.6s ease ${index * 0.1}s`;
|
|
element.appendChild(span);
|
|
|
|
setTimeout(() => {
|
|
span.style.opacity = '1';
|
|
span.style.transform = 'translateY(0)';
|
|
}, 100);
|
|
});
|
|
}
|
|
|
|
static setupSmoothScroll() {
|
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
anchor.addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
const target = document.querySelector(this.getAttribute('href'));
|
|
|
|
if (target) {
|
|
target.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start'
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
new PortfolioAnimations();
|
|
PortfolioAnimations.setupSmoothScroll();
|
|
});
|
|
|
|
window.PortfolioAnimations = PortfolioAnimations;
|
|
|
|
function initScrollAnimations() {
|
|
const observerOptions = {
|
|
threshold: 0.1,
|
|
rootMargin: '0px 0px -50px 0px'
|
|
};
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
const delay = entry.target.dataset.delay || 0;
|
|
setTimeout(() => {
|
|
entry.target.classList.add('visible');
|
|
}, delay);
|
|
}
|
|
});
|
|
}, observerOptions);
|
|
|
|
document.querySelectorAll('.animate-on-scroll').forEach(el => {
|
|
observer.observe(el);
|
|
});
|
|
}
|
|
|
|
function initMagneticEffect() {
|
|
const magneticElements = document.querySelectorAll('.magnetic');
|
|
|
|
magneticElements.forEach(el => {
|
|
el.addEventListener('mousemove', (e) => {
|
|
const rect = el.getBoundingClientRect();
|
|
const x = e.clientX - rect.left - rect.width / 2;
|
|
const y = e.clientY - rect.top - rect.height / 2;
|
|
|
|
el.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(1.02)`;
|
|
});
|
|
|
|
el.addEventListener('mouseleave', () => {
|
|
el.style.transform = 'translate(0px, 0px) scale(1)';
|
|
});
|
|
});
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
initScrollAnimations();
|
|
initMagneticEffect();
|
|
});
|