nmdx-portfolio / script.js
dodey917's picture
Need you to debug the website code and create more html page for click and fix live chat to work
3206283 verified
// Shockwave animation
const canvas = document.getElementById('shockwaveCanvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const shockwaves = [];
class Shockwave {
constructor(x, y) {
this.x = x;
this.y = y;
this.radius = 0;
this.maxRadius = 300;
this.speed = 2;
this.opacity = 0.5;
this.color = `rgba(16, 185, 129, ${this.opacity})`;
}
update() {
this.radius += this.speed;
this.opacity = 0.5 * (1 - this.radius / this.maxRadius);
this.color = `rgba(16, 185, 129, ${this.opacity})`;
}
draw() {
ctx.strokeStyle = this.color;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.stroke();
// Second ring
ctx.strokeStyle = `rgba(59, 130, 246, ${this.opacity * 0.5})`;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius * 0.8, 0, Math.PI * 2);
ctx.stroke();
}
isDead() {
return this.radius > this.maxRadius;
}
}
function animateShockwaves() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Create new shockwave randomly
if (Math.random() < 0.02) {
shockwaves.push(new Shockwave(
Math.random() * canvas.width,
Math.random() * canvas.height
));
}
// Update and draw shockwaves
for (let i = shockwaves.length - 1; i >= 0; i--) {
const wave = shockwaves[i];
wave.update();
wave.draw();
if (wave.isDead()) {
shockwaves.splice(i, 1);
}
}
requestAnimationFrame(animateShockwaves);
}
animateShockwaves();
// Resize canvas on window resize
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});
// Add interactive shockwave on click
document.addEventListener('click', (e) => {
shockwaves.push(new Shockwave(e.clientX, e.clientY));
});
// Service filtering (only if on services page)
if (document.querySelector('.filter-tag')) {
const filterTags = document.querySelectorAll('.filter-tag');
const serviceCards = document.querySelectorAll('.service-card');
filterTags.forEach(tag => {
tag.addEventListener('click', () => {
const filter = tag.dataset.filter;
// Update active state
filterTags.forEach(t => t.classList.remove('bg-emerald-600', 'text-white'));
tag.classList.add('bg-emerald-600', 'text-white');
// Filter cards
serviceCards.forEach(card => {
if (filter === 'all' || card.dataset.category === filter) {
card.style.display = 'block';
setTimeout(() => card.classList.add('visible'), 100);
} else {
card.style.display = 'none';
card.classList.remove('visible');
}
});
});
});
}
// Timeline animation on scroll
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -100px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
}, observerOptions);
// Observe elements for animation
document.querySelectorAll('.timeline-item, .service-card, .skill-bar').forEach(el => {
observer.observe(el);
});
// Testimonial slider
let currentSlide = 0;
const testimonialsContainer = document.getElementById('testimonialsContainer');
const totalSlides = 3;
function goToSlide(slideIndex) {
currentSlide = slideIndex;
testimonialsContainer.style.transform = `translateX(-${slideIndex * 100}%)`;
// Update dots
document.querySelectorAll('.testimonials-slider button').forEach((dot, index) => {
if (index === slideIndex) {
dot.classList.remove('bg-gray-600');
dot.classList.add('bg-emerald-500');
} else {
dot.classList.remove('bg-emerald-500');
dot.classList.add('bg-gray-600');
}
});
}
// Auto-advance testimonials
setInterval(() => {
currentSlide = (currentSlide + 1) % totalSlides;
goToSlide(currentSlide);
}, 5000);
// Contact form submission
document.getElementById('contactForm').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Object.fromEntries(formData);
// Show loading state
const submitBtn = e.target.querySelector('button[type="submit"]');
const originalText = submitBtn.textContent;
submitBtn.innerHTML = '<span class="loading"></span> Sending...';
submitBtn.disabled = true;
try {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 2000));
// Show success message
const successMsg = document.getElementById('successMessage');
successMsg.style.transform = 'translateX(0)';
// Reset form
e.target.reset();
// Hide success message after 3 seconds
setTimeout(() => {
successMsg.style.transform = 'translateX(100%)';
}, 3000);
} catch (error) {
console.error('Error:', error);
alert('Error sending message. Please try again.');
} finally {
// Reset button
submitBtn.textContent = originalText;
submitBtn.disabled = false;
}
});
// FAQ toggle function
window.toggleFAQ = function(button) {
const content = button.nextElementSibling;
const icon = button.querySelector('i');
content.classList.toggle('hidden');
icon.style.transform = content.classList.contains('hidden') ? 'rotate(0deg)' : 'rotate(180deg)';
};
// Smooth scroll for navigation links
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'
});
}
});
});
// Parallax scrolling effect
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
const parallaxElements = document.querySelectorAll('.parallax');
parallaxElements.forEach(el => {
const speed = el.dataset.speed || 0.5;
el.style.transform = `translateY(${scrolled * speed}px)`;
});
});
// Add reveal animation to elements on scroll
const revealElements = document.querySelectorAll('.service-card, .timeline-item');
const revealOnScroll = () => {
revealElements.forEach(element => {
const elementTop = element.getBoundingClientRect().top;
const elementBottom = element.getBoundingClientRect().bottom;
if (elementTop < window.innerHeight && elementBottom > 0) {
element.classList.add('visible');
}
});
};
window.addEventListener('scroll', revealOnScroll);
revealOnScroll(); // Initial check
// Dynamic skill bar animation
const skillBars = document.querySelectorAll('.skill-bar');
const animateSkillBars = () => {
skillBars.forEach(bar => {
const rect = bar.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
const progressBar = bar.querySelector('.bg-gradient-to-r');
const width = progressBar.style.width || '0%';
if (width === '0%') {
progressBar.style.width = progressBar.parentElement.previousElementSibling.querySelector('span:last-child').textContent;
}
}
});
};
window.addEventListener('scroll', animateSkillBars);
animateSkillBars();
// Keyboard navigation support
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeCaseStudy();
}
});
// Performance optimization - Debounce scroll events
let scrollTimeout;
window.addEventListener('scroll', () => {
if (scrollTimeout) {
window.cancelAnimationFrame(scrollTimeout);
}
scrollTimeout = window.requestAnimationFrame(() => {
// Scroll-based animations here
revealOnScroll();
animateSkillBars();
});
});