/** * Cyber Network Background Animation * Generiert dynamisch ein animiertes Netzwerk für den Hintergrund */ class CyberNetwork { constructor(options = {}) { this.options = { container: options.container || document.body, nodeCount: options.nodeCount || 30, connectionCount: options.connectionCount || 50, packetCount: options.packetCount || 15, animationSpeed: options.animationSpeed || 1.0, ...options }; this.nodes = []; this.connections = []; this.packets = []; this.initialized = false; this.containerElement = null; this.networkGridElement = null; this.glowOverlayElement = null; } init() { if (this.initialized) return; // Container erstellen this.containerElement = document.createElement('div'); this.containerElement.className = 'cyber-network-bg'; // Grid erstellen this.networkGridElement = document.createElement('div'); this.networkGridElement.className = 'network-grid'; this.containerElement.appendChild(this.networkGridElement); // Glow Overlay erstellen this.glowOverlayElement = document.createElement('div'); this.glowOverlayElement.className = 'glow-overlay'; this.containerElement.appendChild(this.glowOverlayElement); // Nodes generieren this.generateNodes(); // Connections generieren this.generateConnections(); // Data packets generieren this.generateDataPackets(); // Container zum DOM hinzufügen if (typeof this.options.container === 'string') { const container = document.querySelector(this.options.container); if (container) { container.appendChild(this.containerElement); } else { document.body.appendChild(this.containerElement); } } else { this.options.container.appendChild(this.containerElement); } this.initialized = true; // Animation starten window.addEventListener('resize', this.handleResize.bind(this)); this.startAnimationCycle(); } generateNodes() { const containerWidth = window.innerWidth; const containerHeight = window.innerHeight; for (let i = 0; i < this.options.nodeCount; i++) { const x = Math.random() * containerWidth; const y = Math.random() * containerHeight; const node = document.createElement('div'); node.className = 'node'; node.style.left = `${x}px`; node.style.top = `${y}px`; // Größen-Variation für visuelle Tiefe const size = 2 + Math.random() * 4; node.style.width = `${size}px`; node.style.height = `${size}px`; // Speichern der Position für spätere Referenz node._data = { x, y, size }; this.containerElement.appendChild(node); this.nodes.push(node); } } generateConnections() { for (let i = 0; i < this.options.connectionCount; i++) { // Zufällige Nodes auswählen const startNodeIndex = Math.floor(Math.random() * this.nodes.length); let endNodeIndex; do { endNodeIndex = Math.floor(Math.random() * this.nodes.length); } while (endNodeIndex === startNodeIndex); const startNode = this.nodes[startNodeIndex]; const endNode = this.nodes[endNodeIndex]; const startData = startNode._data; const endData = endNode._data; // Verbindung erstellen const connection = document.createElement('div'); connection.className = 'connection'; // Position und Rotation berechnen const dx = endData.x - startData.x; const dy = endData.y - startData.y; const length = Math.sqrt(dx * dx + dy * dy); const angle = Math.atan2(dy, dx) * (180 / Math.PI); connection.style.width = `${length}px`; connection.style.left = `${startData.x}px`; connection.style.top = `${startData.y}px`; connection.style.transform = `rotate(${angle}deg)`; // Variation in der Animations-Geschwindigkeit connection.style.animationDuration = `${3 + Math.random() * 4}s`; // Speichern der verbundenen Nodes connection._data = { startNode: startNodeIndex, endNode: endNodeIndex, length }; this.containerElement.appendChild(connection); this.connections.push(connection); } } generateDataPackets() { for (let i = 0; i < this.options.packetCount; i++) { this.createNewDataPacket(); } } createNewDataPacket() { if (this.connections.length === 0) return; // Zufällige Verbindung auswählen const connectionIndex = Math.floor(Math.random() * this.connections.length); const connection = this.connections[connectionIndex]; const connectionData = connection._data; const startNode = this.nodes[connectionData.startNode]; const startData = startNode._data; // Data Packet erstellen const packet = document.createElement('div'); packet.className = 'data-packet'; // Position auf dem Startknoten packet.style.left = `${startData.x}px`; packet.style.top = `${startData.y}px`; // Zufällige Geschwindigkeit const travelTime = (4 + Math.random() * 4) / this.options.animationSpeed; packet.style.setProperty('--travel-time', `${travelTime}s`); // Ziel-Koordinaten berechnen const endNode = this.nodes[connectionData.endNode]; const endData = endNode._data; const travelX = endData.x - startData.x; const travelY = endData.y - startData.y; packet.style.setProperty('--travel-x', `${travelX}px`); packet.style.setProperty('--travel-y', `${travelY}px`); // Farb-Variation if (Math.random() > 0.5) { packet.style.background = 'rgba(76, 223, 255, 0.8)'; // Akzentfarbe } this.containerElement.appendChild(packet); this.packets.push(packet); // Nach Ende der Animation neues Paket erstellen setTimeout(() => { if (this.containerElement.contains(packet)) { this.containerElement.removeChild(packet); } const index = this.packets.indexOf(packet); if (index > -1) { this.packets.splice(index, 1); this.createNewDataPacket(); } }, travelTime * 1000); } handleResize() { if (!this.initialized) return; // Bei Größenänderung alles neu generieren this.reset(); this.init(); } reset() { if (!this.initialized) return; // Alle Elemente entfernen this.nodes.forEach(node => node.remove()); this.connections.forEach(connection => connection.remove()); this.packets.forEach(packet => packet.remove()); this.nodes = []; this.connections = []; this.packets = []; if (this.containerElement) { this.containerElement.remove(); } this.initialized = false; } startAnimationCycle() { // Regelmäßig neue Pakete erstellen für mehr Dynamik setInterval(() => { if (this.packets.length < this.options.packetCount * 1.5) { this.createNewDataPacket(); } }, 1000 / this.options.animationSpeed); } } // Exportieren als Modul export default CyberNetwork;