// Animated Network Background let canvas, ctx, networkImage; let isImageLoaded = false; let animationSpeed = 0.0003; // Reduzierte Geschwindigkeit für sanftere Rotation let scaleSpeed = 0.0001; // Reduzierte Geschwindigkeit für sanftere Skalierung let opacitySpeed = 0.0002; // Reduzierte Geschwindigkeit für sanftere Opazitätsänderung let rotation = 0; let scale = 1; let opacity = 0.7; // Höhere Basisopazität für bessere Sichtbarkeit let scaleDirection = 1; let opacityDirection = 1; let animationFrameId = null; let isDarkMode = document.documentElement.classList.contains('dark'); let loadAttempts = 0; const MAX_LOAD_ATTEMPTS = 2; // Initialize the canvas and load the image function initNetworkBackground() { // Create canvas element if it doesn't exist if (!document.getElementById('network-background')) { canvas = document.createElement('canvas'); canvas.id = 'network-background'; canvas.style.position = 'fixed'; canvas.style.top = '0'; canvas.style.left = '0'; canvas.style.width = '100%'; canvas.style.height = '100%'; canvas.style.zIndex = '-5'; // Höher als -10 für den full-page-bg canvas.style.pointerEvents = 'none'; // Stellt sicher, dass der Canvas keine Mausinteraktionen blockiert document.body.appendChild(canvas); } else { canvas = document.getElementById('network-background'); } // Set canvas size to window size with pixel ratio consideration resizeCanvas(); // Get context with alpha enabled ctx = canvas.getContext('2d', { alpha: true }); // Load the network image - versuche zuerst die SVG-Version networkImage = new Image(); networkImage.crossOrigin = "anonymous"; // Vermeidet CORS-Probleme // Keine Bilder laden, direkt Fallback-Hintergrund verwenden console.log("Verwende einfachen Hintergrund ohne Bilddateien"); isImageLoaded = true; // Animation ohne Hintergrundbild starten startAnimation(); // Handle window resize window.addEventListener('resize', debounce(resizeCanvas, 250)); // Überwache Dark Mode-Änderungen document.addEventListener('darkModeToggled', function(event) { isDarkMode = event.detail.isDark; }); } // Hilfsfunktion zur Reduzierung der Resize-Event-Aufrufe function debounce(func, wait) { let timeout; return function() { const context = this; const args = arguments; clearTimeout(timeout); timeout = setTimeout(function() { func.apply(context, args); }, wait); }; } // Resize canvas to match window size with proper pixel ratio function resizeCanvas() { if (!canvas) return; const pixelRatio = window.devicePixelRatio || 1; const width = window.innerWidth; const height = window.innerHeight; // Set display size (css pixels) canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; // Set actual size in memory (scaled for pixel ratio) canvas.width = width * pixelRatio; canvas.height = height * pixelRatio; // Scale context to match pixel ratio if (ctx) { ctx.scale(pixelRatio, pixelRatio); } // Wenn Animation läuft und Bild geladen, zeichne erneut if (isImageLoaded && animationFrameId) { drawNetworkImage(); } } // Start animation function startAnimation() { if (animationFrameId) { cancelAnimationFrame(animationFrameId); } // Start animation loop animate(); } // Draw network image function drawNetworkImage() { if (!ctx) return; // Clear canvas with proper clear method ctx.clearRect(0, 0, canvas.width / (window.devicePixelRatio || 1), canvas.height / (window.devicePixelRatio || 1)); // Save context state ctx.save(); // Move to center of canvas ctx.translate(canvas.width / (2 * (window.devicePixelRatio || 1)), canvas.height / (2 * (window.devicePixelRatio || 1))); // Rotate ctx.rotate(rotation); // Scale ctx.scale(scale, scale); // Set global opacity, angepasst für Dark Mode ctx.globalAlpha = isDarkMode ? opacity : opacity * 0.8; if (isImageLoaded && networkImage.complete) { // Bildgröße berechnen, um den Bildschirm abzudecken const imgAspect = networkImage.width / networkImage.height; const canvasAspect = canvas.width / canvas.height; let drawWidth, drawHeight; if (canvasAspect > imgAspect) { drawWidth = canvas.width / (window.devicePixelRatio || 1); drawHeight = drawWidth / imgAspect; } else { drawHeight = canvas.height / (window.devicePixelRatio || 1); drawWidth = drawHeight * imgAspect; } // Draw image centered ctx.drawImage( networkImage, -drawWidth / 2, -drawHeight / 2, drawWidth, drawHeight ); } else { // Fallback: Zeichne einen einfachen Hintergrund mit Punkten drawFallbackBackground(); } // Restore context state ctx.restore(); } // Fallback-Hintergrund mit Punkten und Linien function drawFallbackBackground() { const width = canvas.width / (window.devicePixelRatio || 1); const height = canvas.height / (window.devicePixelRatio || 1); // Zeichne einige zufällige Punkte ctx.fillStyle = isDarkMode ? 'rgba(139, 92, 246, 0.2)' : 'rgba(139, 92, 246, 0.1)'; for (let i = 0; i < 50; i++) { const x = Math.random() * width; const y = Math.random() * height; const radius = Math.random() * 3 + 1; ctx.beginPath(); ctx.arc(x - width/2, y - height/2, radius, 0, Math.PI * 2); ctx.fill(); } } // Animation loop function animate() { // Update animation parameters rotation += animationSpeed; // Update scale with oscillation scale += scaleSpeed * scaleDirection; if (scale > 1.05) { // Kleinerer Skalierungsbereich für weniger starke Größenänderung scaleDirection = -1; } else if (scale < 0.95) { scaleDirection = 1; } // Update opacity with oscillation opacity += opacitySpeed * opacityDirection; if (opacity > 0.75) { // Kleinerer Opazitätsbereich für subtilere Änderungen opacityDirection = -1; } else if (opacity < 0.65) { opacityDirection = 1; } // Draw the image drawNetworkImage(); // Request next frame animationFrameId = requestAnimationFrame(animate); } // Cleanup Funktion für Speicherbereinigung function cleanupNetworkBackground() { if (animationFrameId) { cancelAnimationFrame(animationFrameId); animationFrameId = null; } if (canvas && canvas.parentNode) { canvas.parentNode.removeChild(canvas); } window.removeEventListener('resize', resizeCanvas); } // Führe Initialisierung aus, wenn DOM geladen ist if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initNetworkBackground); } else { initNetworkBackground(); } // Führe Cleanup durch, wenn das Fenster geschlossen wird window.addEventListener('beforeunload', cleanupNetworkBackground);