240 lines
7.1 KiB
JavaScript
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;
|