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 | |
| } |