Files
website/static/js/modules/cyber-network.js

240 lines
7.1 KiB
JavaScript

/**
* 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;