svg anim
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() { // {
if (!document.querySelector(selector)) {
console.error('Missing element:', selector);
allElementsFound = false;
}
});
if (!allElementsFound) {
console.error('Required elements not found, retrying in 2 seconds...');
setTimeout(arguments.callee, 2000);
return;
}
// ===== CONFIGURATION =====
const config = {
svgSelector: '.my-animated-svg',
containerSelector: '.svg-container',
targetImageSelector: '.target-image',
taglineSelector: '.tagline', // Selector for tagline element
relativePosition: {
fromTop: 70, // Final position from top of target image
fromLeft: 100 // Final position from left of target image
},
numberOfPasses: 3, // Number of passes before final positioning
initialSpeed: 3000, // Initial duration for first pass (ms)
speedReduction: 0.5, // Each pass gets faster (multiply duration by this)
fadeInDuration: 0,
finalScale: 0.35,
// Final explosion effect settings
explosionScale: 3, // Scale multiplier for explosion (3 = 300%)
explosionDuration: 2500, // Duration of explosion and fade out (ms)
fadeInTargetImage: true, // Whether to fade in the target image during explosion
// Gradient pulse settings
gradientSlowPulse: 10000, // Slow pulse duration in ms (10 seconds)
gradientPauseBeforeRestart: 1000, // Pause before restarting slow pulse (1 second)
// Container resize settings
containerResizeDelay: 0, // Delay before container resize (1 second)
containerResizeDuration: 2000, // Duration of container resize animation (2 seconds)
containerFinalHeight: '100vh', // Final height of container after animation
// Countdown settings
showCountdown: true, // Enable/disable countdown
countdownStart: 5, // Starting number
countdownOpacity: 0.3 // Semi-transparency (0.3 = 30% opacity)
};// Get elements
const svg = document.querySelector(config.svgSelector);
const container = document.querySelector(config.containerSelector);
const targetImage = document.querySelector(config.targetImageSelector);
const taglines = document.querySelectorAll(config.taglineSelector);
const countdown = document.querySelector('.countdown-number');
if (!svg || !container || !targetImage) {
console.error('Required elements not found');
return;
}// Store original dimensions
const originalWidth = svg.offsetWidth;
const originalHeight = svg.offsetHeight;
let isAnimating = false;
// Hide target image initially if fade-in is enabled
if (config.fadeInTargetImage) {
targetImage.style.opacity = '0';
targetImage.style.transition = `opacity ${config.explosionDuration}ms ease-in`;
}// Calculate final position relative to target image
function calculateFinalPosition() {
const targetRect = targetImage.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const targetRelativeTop = targetRect.top - containerRect.top;
const targetRelativeLeft = targetRect.left - containerRect.left;
const finalLeft = targetRelativeLeft + config.relativePosition.fromLeft;
const finalTop = targetRelativeTop + config.relativePosition.fromTop;
return { top: finalTop, left: finalLeft };
}// Main animation sequence
async function animateSequence() {
if (isAnimating) return;
isAnimating = true;
console.log('Starting progressive speed animation...');
const containerWidth = container.offsetWidth;
const svgWidth = originalWidth;
// Calculate total animation duration for countdown
let countdownTotalDuration = config.fadeInDuration;
let tempSpeed = config.initialSpeed;
for (let i = 0; i {
currentNumber--;
if (currentNumber > 0) {
countdown.textContent = currentNumber;
// Apply scaling directly
countdown.style.transform = 'scale(1.3)';
countdown.style.transition = 'transform 0.5s ease-out';
setTimeout(() => {
countdown.style.transform = 'scale(1)';
}, 50);
} else {
// Make sure it fully disappears
countdown.style.opacity = '0';
countdown.style.visibility = 'hidden';
countdown.textContent = ''; // Clear the text
clearInterval(countdownTimer);
}
}, countdownInterval);
}
// Start with slow gradient pulse
container.style.animation = `gradientShift ${config.gradientSlowPulse}ms ease-in-out infinite`;
// Calculate scale reduction per pass
const totalPasses = config.numberOfPasses + 1; // +1 for final positioning pass
const scaleReductionPerPass = (1 - config.finalScale) / totalPasses;
// Setup initial position (left side, centered vertically)
svg.style.left = `-${svgWidth}px`;
svg.style.top = '50%';
svg.style.transition = 'none';
// Phase 1: Fade in
console.log('Fading in...');
svg.style.opacity = '1';
await delay(config.fadeInDuration);
// Phase 2: Multiple passes with increasing speed and progressive scaling
let currentSpeed = config.initialSpeed;
let currentScale = 1;
for (let pass = 1; pass 0) {
const taglineDuration = config.explosionDuration + config.gradientPauseBeforeRestart;
taglines.forEach(tagline => {
tagline.style.transition = `opacity ${taglineDuration}ms ease-out, filter ${taglineDuration}ms ease-out`;
tagline.style.opacity = '1';
tagline.style.filter = 'blur(0px)';
});
}
// Fade in target image at the same time as explosion
if (config.fadeInTargetImage) {
targetImage.style.opacity = '1';
}
svg.style.transition = `transform ${config.explosionDuration}ms cubic-bezier(0, 0, 0.2, 1), opacity ${config.explosionDuration}ms ease-out`;
svg.style.transform = `translate(-50%, -50%) scale(${config.finalScale * config.explosionScale})`;
svg.style.opacity = '0';
await delay(config.explosionDuration);
// Wait 1 second then restart slow gradient pulse
await delay(config.gradientPauseBeforeRestart);
container.style.animation = `gradientShiftSlow ${config.gradientSlowPulse}ms ease-in-out infinite`;
// Wait then resize container
await delay(config.containerResizeDelay);
console.log('Resizing container...');
container.style.transition = `min-height ${config.containerResizeDuration}ms ease-in-out`;
container.style.minHeight = config.containerFinalHeight;
await delay(config.containerResizeDuration);
console.log('Animation complete!');
isAnimating = false;
}// Helper function for delays
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}// Start animation on page load
animateSequence();// Restart animation on container click
container.addEventListener('click', function() {
if (isAnimating) return;
console.log('Restarting animation...');
// Reset all styles
svg.style.transition = 'none';
svg.style.opacity = '0';
svg.style.left = `-${originalWidth}px`;
svg.style.top = '50%';
svg.style.transform = 'translateY(-50%)';
svg.style.width = `${originalWidth}px`;
svg.style.height = `${originalHeight}px`;
svg.style.animation = 'none';
svg.classList.remove('blur-light', 'blur-medium', 'blur-heavy', 'blur-extreme', 'blur-super');
// Reset target image opacity if fade-in is enabled
if (config.fadeInTargetImage) {
targetImage.style.transition = 'none';
targetImage.style.opacity = '0';
targetImage.offsetHeight; // Force reflow
targetImage.style.transition = `opacity ${config.explosionDuration}ms ease-in`;
}
// Reset tagline
if (taglines && taglines.length > 0) {
taglines.forEach(tagline => {
tagline.style.transition = 'none';
tagline.style.opacity = '0';
tagline.style.filter = 'blur(10px)';
tagline.offsetHeight; // Force reflow
});
}
// Reset countdown
if (countdown) {
countdown.style.opacity = '0';
countdown.style.visibility = 'hidden';
countdown.textContent = '';
}
// Reset gradient
container.style.animation = `gradientShift ${config.gradientSlowPulse}ms ease-in-out infinite`;
// Reset container height
container.style.transition = 'none';
container.style.minHeight = '100vh';
container.offsetHeight; // Force reflow
container.style.transition = `min-height ${config.containerResizeDuration}ms ease-in-out`;
svg.offsetHeight; // Force reflow
setTimeout(animateSequence, 100);
});
// Update position on resize
window.addEventListener('resize', function() {
if (!isAnimating && svg.style.transform.includes('translate(-50%, -50%)')) {
const finalPosition = calculateFinalPosition();
svg.style.left = `${finalPosition.left}px`;
svg.style.top = `${finalPosition.top}px`;
}
});
} catch (error) {
console.error('Animation script error:', error);
}
}, 1500); // Add delay here
});