Spaces:
Runtime error
Runtime error
/** | |
* Quantum Transition Animations | |
* Provides dynamic transitions and particle effects for the Quantum NLP Framework | |
*/ | |
// Wait for document to be fully loaded | |
document.addEventListener('DOMContentLoaded', function() { | |
// Initialize animations when page loads | |
initQuantumAnimations(); | |
// Add event listener for analyze button to trigger animations | |
const analyzeBtn = document.getElementById('analyze-btn'); | |
if (analyzeBtn) { | |
analyzeBtn.addEventListener('click', function() { | |
// Only trigger animation if form is valid | |
const form = document.getElementById('process-form'); | |
if (form.checkValidity()) { | |
showQuantumTransition(); | |
} | |
}); | |
// Enhanced button effects | |
analyzeBtn.addEventListener('mouseover', function() { | |
triggerSmallParticleEffect(this); | |
}); | |
} | |
// Initialize text-to-vision transitions | |
initTextToVisionTransitions(); | |
// Check if results are present and apply animations | |
const resultsContainer = document.getElementById('results-container'); | |
if (resultsContainer && resultsContainer.children.length > 0) { | |
applyResultsAnimations(resultsContainer); | |
} | |
}); | |
/** | |
* Initialize text-to-vision transitions with staggered timing | |
*/ | |
function initTextToVisionTransitions() { | |
const visionElements = document.querySelectorAll('.text-to-vision'); | |
visionElements.forEach((elem, index) => { | |
// Add a staggered delay for smoother visual effect | |
const delay = 300 + (index * 150); | |
setTimeout(() => { | |
elem.classList.add('text-to-vision-active'); | |
// Reset the animation after it completes to allow replaying | |
setTimeout(() => { | |
elem.classList.remove('text-to-vision-active'); | |
}, 1500); | |
}, delay); | |
}); | |
} | |
/** | |
* Apply animations to results container | |
*/ | |
function applyResultsAnimations(container) { | |
// Add entrance animation | |
container.style.opacity = '0'; | |
container.style.transform = 'translateY(20px)'; | |
setTimeout(() => { | |
container.style.transition = 'opacity 0.5s ease, transform 0.5s ease'; | |
container.style.opacity = '1'; | |
container.style.transform = 'translateY(0)'; | |
// Apply smoke dispersion effect to each card | |
const cards = container.querySelectorAll('.quantum-card'); | |
cards.forEach((card, index) => { | |
setTimeout(() => { | |
card.classList.add('quantum-reveal'); | |
}, 300 + (index * 150)); | |
}); | |
}, 200); | |
} | |
/** | |
* Trigger a small particle effect around an element | |
*/ | |
function triggerSmallParticleEffect(element) { | |
// Create a few particles around the button | |
const rect = element.getBoundingClientRect(); | |
const centerX = rect.left + rect.width / 2; | |
const centerY = rect.top + rect.height / 2; | |
// Create 5-10 particles | |
const count = Math.floor(Math.random() * 5) + 5; | |
for (let i = 0; i < count; i++) { | |
const particle = document.createElement('div'); | |
particle.className = 'quantum-particle'; | |
// Random position around the element | |
const angle = Math.random() * Math.PI * 2; | |
const distance = Math.random() * 20 + 10; | |
const x = centerX + Math.cos(angle) * distance; | |
const y = centerY + Math.sin(angle) * distance; | |
// Random size | |
const size = Math.random() * 4 + 2; | |
// Set styles | |
particle.style.left = x + 'px'; | |
particle.style.top = y + 'px'; | |
particle.style.width = size + 'px'; | |
particle.style.height = size + 'px'; | |
particle.style.backgroundColor = getQuantumParticleColor(); | |
// Add to body | |
document.body.appendChild(particle); | |
// Animate and remove | |
setTimeout(() => { | |
particle.remove(); | |
}, 1000); | |
} | |
} | |
/** | |
* Initialize all quantum animations and effects | |
*/ | |
function initQuantumAnimations() { | |
// Create canvas for particle effects | |
createParticleCanvas(); | |
// Pre-load any assets needed for animations | |
preloadAnimationAssets(); | |
} | |
/** | |
* Create canvas for particle animations | |
*/ | |
function createParticleCanvas() { | |
const canvas = document.createElement('canvas'); | |
canvas.id = 'quantum-particles'; | |
canvas.className = 'particle-canvas'; | |
canvas.width = window.innerWidth; | |
canvas.height = window.innerHeight; | |
// Add canvas to the body but keep it hidden initially | |
canvas.style.display = 'none'; | |
canvas.style.position = 'fixed'; | |
canvas.style.top = 0; | |
canvas.style.left = 0; | |
canvas.style.pointerEvents = 'none'; | |
canvas.style.zIndex = 1000; | |
document.body.appendChild(canvas); | |
// Handle window resize | |
window.addEventListener('resize', function() { | |
canvas.width = window.innerWidth; | |
canvas.height = window.innerHeight; | |
}); | |
} | |
/** | |
* Preload any assets needed for animations | |
*/ | |
function preloadAnimationAssets() { | |
// Add any image preloading here if needed | |
} | |
/** | |
* Show the quantum transition animation when analyzing text | |
*/ | |
function showQuantumTransition() { | |
// Get input and display areas | |
const inputArea = document.querySelector('.card-body:has(#input_text)'); | |
const resultsArea = document.querySelector('#results-container'); | |
// Show loading overlay | |
showLoadingOverlay(); | |
// Show particle effects | |
triggerParticleEffect(); | |
// The actual form submission happens normally, but we add visual effects | |
} | |
/** | |
* Show a quantum-themed loading overlay | |
*/ | |
function showLoadingOverlay() { | |
// Create overlay if it doesn't exist | |
let overlay = document.getElementById('quantum-overlay'); | |
if (!overlay) { | |
overlay = document.createElement('div'); | |
overlay.id = 'quantum-overlay'; | |
overlay.innerHTML = ` | |
<div class="quantum-loader"> | |
<div class="quantum-spinner"> | |
<div class="q-orbit q-orbit-1"></div> | |
<div class="q-orbit q-orbit-2"></div> | |
<div class="q-orbit q-orbit-3"></div> | |
<div class="q-core"></div> | |
</div> | |
<div class="quantum-message">Quantum Processing</div> | |
</div> | |
`; | |
document.body.appendChild(overlay); | |
} | |
// Show the overlay with animation | |
overlay.style.display = 'flex'; | |
setTimeout(() => { | |
overlay.classList.add('active'); | |
}, 10); | |
} | |
/** | |
* Hide the quantum loading overlay | |
*/ | |
function hideLoadingOverlay() { | |
const overlay = document.getElementById('quantum-overlay'); | |
if (overlay) { | |
overlay.classList.remove('active'); | |
setTimeout(() => { | |
overlay.style.display = 'none'; | |
}, 500); | |
} | |
} | |
/** | |
* Trigger the particle whirlwind effect | |
*/ | |
function triggerParticleEffect() { | |
const canvas = document.getElementById('quantum-particles'); | |
if (!canvas) return; | |
// Show canvas with fade-in | |
canvas.style.display = 'block'; | |
setTimeout(() => { | |
canvas.classList.add('active'); | |
}, 10); | |
// Get canvas context | |
const ctx = canvas.getContext('2d'); | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
// Create particles for the whirlwind effect | |
const particles = []; | |
const particleCount = 150; | |
// Initialize particles | |
for (let i = 0; i < particleCount; i++) { | |
particles.push({ | |
x: canvas.width / 2, | |
y: canvas.height / 2, | |
size: Math.random() * 5 + 1, | |
color: getQuantumParticleColor(), | |
speedX: (Math.random() - 0.5) * 10, | |
speedY: (Math.random() - 0.5) * 10, | |
rotationRadius: Math.random() * 100 + 50, | |
rotationSpeed: Math.random() * 0.1 + 0.02, | |
rotationAngle: Math.random() * Math.PI * 2, | |
opacity: Math.random() * 0.7 + 0.3, | |
fadeSpeed: Math.random() * 0.02 + 0.005 | |
}); | |
} | |
// Animation variables | |
let frame = 0; | |
const maxFrames = 120; | |
// Animate particles | |
function animateParticles() { | |
// Clear canvas | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
// Update and draw particles | |
for (let i = 0; i < particles.length; i++) { | |
const p = particles[i]; | |
// Update rotation angle | |
p.rotationAngle += p.rotationSpeed; | |
// Calculate position with spiral effect | |
const spiralFactor = 1 + (frame / maxFrames) * 3; | |
const rotRadius = p.rotationRadius * (1 - frame / maxFrames); | |
p.x = canvas.width / 2 + Math.cos(p.rotationAngle) * rotRadius * spiralFactor; | |
p.y = canvas.height / 2 + Math.sin(p.rotationAngle) * rotRadius; | |
// Add dispersion effect in later frames | |
if (frame > maxFrames * 0.7) { | |
p.x += p.speedX; | |
p.y += p.speedY; | |
p.opacity -= p.fadeSpeed; | |
} | |
// Draw particle | |
ctx.globalAlpha = Math.max(0, p.opacity); | |
ctx.fillStyle = p.color; | |
ctx.beginPath(); | |
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
// Increment frame | |
frame++; | |
// Continue animation or clean up | |
if (frame <= maxFrames) { | |
requestAnimationFrame(animateParticles); | |
} else { | |
// End animation with fade-out | |
canvas.classList.remove('active'); | |
// After fade-out, hide the canvas completely | |
setTimeout(() => { | |
canvas.style.display = 'none'; | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
}, 300); | |
} | |
} | |
// Start animation | |
animateParticles(); | |
// Set timeout to match form submission time | |
setTimeout(function() { | |
hideLoadingOverlay(); | |
// Add reveal animation to results when they load | |
const resultElements = document.querySelectorAll('.card'); | |
resultElements.forEach((el, index) => { | |
if (el.closest('#results-container')) { | |
// Add a staggered delay for each card | |
setTimeout(() => { | |
el.classList.add('quantum-reveal'); | |
}, index * 150); | |
} | |
}); | |
}, 2000); // Adjust timing as needed to match server response time | |
} | |
/** | |
* Get a color for quantum particles | |
*/ | |
function getQuantumParticleColor() { | |
const colors = [ | |
'#4285F4', // Blue | |
'#0F9D58', // Green | |
'#DB4437', // Red | |
'#F4B400', // Yellow | |
'#9C27B0', // Purple | |
'#00BCD4', // Cyan | |
'#3F51B5' // Indigo | |
]; | |
return colors[Math.floor(Math.random() * colors.length)]; | |
} | |
/** | |
* Apply visualization effect to quantum results | |
*/ | |
function visualizeQuantumResults() { | |
const quantumScoreEl = document.querySelector('.quantum-score'); | |
if (quantumScoreEl) { | |
// Get the quantum score | |
const score = parseFloat(quantumScoreEl.textContent); | |
// Create a visualization canvas for the score | |
createQuantumScoreVisualization(quantumScoreEl, score); | |
// Apply visualization to the entire container | |
const container = document.querySelector('.quantum-visualized'); | |
if (container) { | |
applyQuantumVisualization(container, score); | |
} | |
} | |
} | |
/** | |
* Create a visualization for the quantum score | |
*/ | |
function createQuantumScoreVisualization(element, score) { | |
// Add special particle effects around the score | |
const parentEl = element.closest('.text-end'); | |
if (!parentEl) return; | |
// Create a canvas for the visualization | |
const canvas = document.createElement('canvas'); | |
canvas.className = 'quantum-score-canvas'; | |
canvas.width = 200; | |
canvas.height = 100; | |
canvas.style.position = 'absolute'; | |
canvas.style.top = '0'; | |
canvas.style.right = '0'; | |
canvas.style.pointerEvents = 'none'; | |
canvas.style.zIndex = '1'; | |
// Insert canvas | |
parentEl.style.position = 'relative'; | |
parentEl.appendChild(canvas); | |
// Create particles | |
const ctx = canvas.getContext('2d'); | |
const particles = []; | |
const particleCount = Math.round(score * 50); // More particles for higher scores | |
// Create particles based on score | |
for (let i = 0; i < particleCount; i++) { | |
particles.push({ | |
x: canvas.width * 0.75, | |
y: canvas.height * 0.5, | |
size: Math.random() * 3 + 1, | |
color: getScoreColor(score), | |
speedX: (Math.random() - 0.5) * 2, | |
speedY: (Math.random() - 0.5) * 2, | |
opacity: Math.random() * 0.5 + 0.3, | |
life: Math.random() * 100 + 50 | |
}); | |
} | |
// Animate particles | |
function animate() { | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
let remainingParticles = 0; | |
for (let i = 0; i < particles.length; i++) { | |
const p = particles[i]; | |
if (p.life > 0) { | |
p.x += p.speedX; | |
p.y += p.speedY; | |
p.opacity = Math.max(0, p.opacity - 0.005); | |
p.life--; | |
ctx.globalAlpha = p.opacity; | |
ctx.fillStyle = p.color; | |
ctx.beginPath(); | |
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); | |
ctx.fill(); | |
remainingParticles++; | |
} | |
} | |
if (remainingParticles > 0) { | |
requestAnimationFrame(animate); | |
} | |
} | |
// Start animation | |
animate(); | |
} | |
/** | |
* Apply quantum visualization to an element | |
*/ | |
function applyQuantumVisualization(element, score) { | |
// Add the visualized class | |
element.classList.add('quantum-visualized'); | |
// Create dynamic quantum effect based on score | |
const intensity = score || 0.5; | |
// Add a pulsing background effect | |
element.style.setProperty('--quantum-pulse-intensity', intensity); | |
// Create tumbleweed whirlwind effect | |
createTumbleweeds(element, Math.round(intensity * 10)); | |
} | |
/** | |
* Create tumbleweed whirlwind particles inside an element | |
*/ | |
function createTumbleweeds(element, count) { | |
for (let i = 0; i < count; i++) { | |
const tumbleweed = document.createElement('div'); | |
tumbleweed.className = 'tumbleweed'; | |
// Random position within the element | |
const rect = element.getBoundingClientRect(); | |
const x = Math.random() * rect.width; | |
const y = Math.random() * rect.height; | |
// Random size | |
const size = Math.random() * 20 + 10; | |
// Set styles | |
tumbleweed.style.left = x + 'px'; | |
tumbleweed.style.top = y + 'px'; | |
tumbleweed.style.width = size + 'px'; | |
tumbleweed.style.height = size + 'px'; | |
// Add to the element | |
element.appendChild(tumbleweed); | |
// Animate the tumbleweed | |
animateTumbleweed(tumbleweed, rect); | |
} | |
} | |
/** | |
* Animate a tumbleweed particle | |
*/ | |
function animateTumbleweed(element, containerRect) { | |
const duration = Math.random() * 8000 + 4000; // 4-12 seconds | |
let startTime = null; | |
// The animation function | |
function animate(timestamp) { | |
if (!startTime) startTime = timestamp; | |
const elapsed = timestamp - startTime; | |
const progress = Math.min(elapsed / duration, 1); | |
// Spiral motion | |
const angle = progress * Math.PI * 6; // 3 full rotations | |
const radius = progress * 100; // Expand outward | |
const centerX = containerRect.width / 2; | |
const centerY = containerRect.height / 2; | |
const x = centerX + Math.cos(angle) * radius; | |
const y = centerY + Math.sin(angle) * radius; | |
// Apply position | |
element.style.transform = `translate(${x}px, ${y}px) rotate(${angle * 180 / Math.PI}deg)`; | |
// Fade out towards the end | |
if (progress > 0.7) { | |
element.style.opacity = 1 - ((progress - 0.7) / 0.3); | |
} | |
// Continue animation if not complete | |
if (progress < 1) { | |
requestAnimationFrame(animate); | |
} else { | |
// Remove element when animation completes | |
element.remove(); | |
} | |
} | |
// Start the animation | |
requestAnimationFrame(animate); | |
} | |
/** | |
* Get color based on score value | |
*/ | |
function getScoreColor(score) { | |
if (score < 0.3) return '#dc3545'; // Low - red | |
if (score < 0.6) return '#ffc107'; // Medium - yellow | |
if (score < 0.8) return '#0dcaf0'; // Good - cyan | |
return '#198754'; // High - green | |
} |