Fix: network background loading and fallback mechanism: Implement a retry logic for loading the network background image with a maximum of two attempts, first trying the SVG version and then falling back to a JPG if necessary. Add a fallback background drawing function to maintain visual continuity when image loading fails. Update placeholder comment in JPG file to reflect the use of an SVG alternative.

This commit is contained in:
2025-04-27 06:26:10 +02:00
parent 74307ba345
commit e46264b201
4 changed files with 172 additions and 30 deletions

View File

@@ -11,6 +11,8 @@ 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() {
@@ -36,16 +38,34 @@ function initNetworkBackground() {
// Get context with alpha enabled
ctx = canvas.getContext('2d', { alpha: true });
// Load the network image
// Load the network image - versuche zuerst die SVG-Version
networkImage = new Image();
networkImage.crossOrigin = "anonymous"; // Vermeidet CORS-Probleme
networkImage.src = '/static/network-bg.jpg';
// Fallback auf lokalen Pfad, falls der absolute Pfad fehlschlägt
// Event-Handler für Fehler - Fallback auf Standard-Hintergrund
networkImage.onerror = function() {
networkImage.src = 'static/network-bg.jpg';
loadAttempts++;
if (loadAttempts < MAX_LOAD_ATTEMPTS) {
// Wenn SVG fehlschlägt, versuche JPG
if (networkImage.src.endsWith('svg')) {
networkImage.src = '/static/network-bg.jpg';
} else {
// Wenn beide fehlschlagen, starte einfach Animation ohne Hintergrund
console.log("Konnte kein Hintergrundbild laden, verwende einfachen Hintergrund");
isImageLoaded = true; // Trotzdem Animation starten
startAnimation();
}
} else {
// Zu viele Versuche, verwende einfachen Hintergrund
console.log("Konnte kein Hintergrundbild laden, verwende einfachen Hintergrund");
isImageLoaded = true; // Trotzdem Animation starten
startAnimation();
}
};
// Versuche zuerst die SVG-Version zu laden
networkImage.src = '/static/network-bg.svg';
networkImage.onload = function() {
isImageLoaded = true;
startAnimation();
@@ -102,9 +122,6 @@ function resizeCanvas() {
// Start animation
function startAnimation() {
if (!isImageLoaded) return;
// Cancel any existing animation
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
@@ -115,7 +132,7 @@ function startAnimation() {
// Draw network image
function drawNetworkImage() {
if (!isImageLoaded || !ctx) return;
if (!ctx) return;
// Clear canvas with proper clear method
ctx.clearRect(0, 0, canvas.width / (window.devicePixelRatio || 1), canvas.height / (window.devicePixelRatio || 1));
@@ -135,33 +152,57 @@ function drawNetworkImage() {
// Set global opacity, angepasst für Dark Mode
ctx.globalAlpha = isDarkMode ? opacity : opacity * 0.8;
// 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;
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 {
drawHeight = canvas.height / (window.devicePixelRatio || 1);
drawWidth = drawHeight * imgAspect;
// Fallback: Zeichne einen einfachen Hintergrund mit Punkten
drawFallbackBackground();
}
// Draw image centered
ctx.drawImage(
networkImage,
-drawWidth / 2,
-drawHeight / 2,
drawWidth,
drawHeight
);
// 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

View File

@@ -1,5 +1,7 @@
/* Dies ist ein Platzhalter für das Netzwerk-Hintergrundbild.
/* Dies ist ein Platzhalter für das Netzwerk-Hintergrundbild mit Base64-Kodierung.
Das eigentliche Bild sollte hier durch eine echte JPG-Datei ersetzt werden.
Empfohlene Bildgröße: mindestens 1920x1080px
Optimaler Stil: Dunkler Hintergrund mit abstrakten Verbindungslinien und Punkten */
Optimaler Stil: Dunkler Hintergrund mit abstrakten Verbindungslinien und Punkten
Da wir keine echte JPG-Datei erstellen können, verwende stattdessen eine SVG-Datei mit dem gleichen Namen. */

View File

@@ -0,0 +1,99 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080" viewBox="0 0 1920 1080">
<defs>
<linearGradient id="bg-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#0e1220" />
<stop offset="100%" stop-color="#1a1f38" />
</linearGradient>
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
</defs>
<!-- Background -->
<rect width="100%" height="100%" fill="url(#bg-gradient)" />
<!-- Connection Lines -->
<g stroke-opacity="0.3" filter="url(#glow)">
<line x1="200" y1="300" x2="500" y2="200" stroke="#8b5cf6" stroke-width="1.5" />
<line x1="500" y1="200" x2="800" y2="400" stroke="#8b5cf6" stroke-width="1.5" />
<line x1="800" y1="400" x2="1100" y2="300" stroke="#58a9ff" stroke-width="1.5" />
<line x1="1100" y1="300" x2="1400" y2="500" stroke="#58a9ff" stroke-width="1.5" />
<line x1="1400" y1="500" x2="1600" y2="200" stroke="#7e3ff2" stroke-width="1.5" />
<line x1="200" y1="300" x2="400" y2="600" stroke="#7e3ff2" stroke-width="1.5" />
<line x1="400" y1="600" x2="700" y2="800" stroke="#8b5cf6" stroke-width="1.5" />
<line x1="700" y1="800" x2="1000" y2="700" stroke="#58a9ff" stroke-width="1.5" />
<line x1="1000" y1="700" x2="1300" y2="800" stroke="#8b5cf6" stroke-width="1.5" />
<line x1="1300" y1="800" x2="1600" y2="600" stroke="#7e3ff2" stroke-width="1.5" />
<line x1="1600" y1="600" x2="1700" y2="900" stroke="#58a9ff" stroke-width="1.5" />
<line x1="400" y1="200" x2="600" y2="350" stroke="#7e3ff2" stroke-width="1.5" />
<line x1="600" y1="350" x2="900" y2="250" stroke="#8b5cf6" stroke-width="1.5" />
<line x1="900" y1="250" x2="1200" y2="400" stroke="#58a9ff" stroke-width="1.5" />
<line x1="1200" y1="400" x2="1500" y2="300" stroke="#8b5cf6" stroke-width="1.5" />
<line x1="300" y1="700" x2="550" y2="550" stroke="#7e3ff2" stroke-width="1.5" />
<line x1="550" y1="550" x2="800" y2="650" stroke="#58a9ff" stroke-width="1.5" />
<line x1="800" y1="650" x2="1100" y2="550" stroke="#8b5cf6" stroke-width="1.5" />
<line x1="1100" y1="550" x2="1400" y2="650" stroke="#7e3ff2" stroke-width="1.5" />
<line x1="1400" y1="650" x2="1650" y2="450" stroke="#58a9ff" stroke-width="1.5" />
<line x1="1650" y1="450" x2="1800" y2="500" stroke="#8b5cf6" stroke-width="1.5" />
</g>
<!-- Connection Points -->
<g fill-opacity="0.8" filter="url(#glow)">
<circle cx="200" cy="300" r="4" fill="#8b5cf6" />
<circle cx="500" cy="200" r="5" fill="#8b5cf6" />
<circle cx="800" cy="400" r="6" fill="#8b5cf6" />
<circle cx="1100" cy="300" r="5" fill="#58a9ff" />
<circle cx="1400" cy="500" r="4" fill="#58a9ff" />
<circle cx="1600" cy="200" r="6" fill="#7e3ff2" />
<circle cx="400" cy="600" r="5" fill="#7e3ff2" />
<circle cx="700" cy="800" r="4" fill="#8b5cf6" />
<circle cx="1000" cy="700" r="6" fill="#58a9ff" />
<circle cx="1300" cy="800" r="5" fill="#8b5cf6" />
<circle cx="1600" cy="600" r="4" fill="#7e3ff2" />
<circle cx="1700" cy="900" r="6" fill="#58a9ff" />
<circle cx="400" cy="200" r="4" fill="#7e3ff2" />
<circle cx="600" cy="350" r="5" fill="#7e3ff2" />
<circle cx="900" cy="250" r="6" fill="#8b5cf6" />
<circle cx="1200" cy="400" r="4" fill="#58a9ff" />
<circle cx="1500" cy="300" r="5" fill="#8b5cf6" />
<circle cx="300" cy="700" r="6" fill="#7e3ff2" />
<circle cx="550" cy="550" r="4" fill="#7e3ff2" />
<circle cx="800" cy="650" r="5" fill="#58a9ff" />
<circle cx="1100" cy="550" r="6" fill="#8b5cf6" />
<circle cx="1400" cy="650" r="4" fill="#7e3ff2" />
<circle cx="1650" cy="450" r="5" fill="#58a9ff" />
<circle cx="1800" cy="500" r="6" fill="#8b5cf6" />
</g>
<!-- Stars/Dots in Background -->
<g fill="#ffffff" fill-opacity="0.3">
<circle cx="250" cy="150" r="1" />
<circle cx="450" cy="350" r="1" />
<circle cx="650" cy="150" r="1" />
<circle cx="850" cy="350" r="1" />
<circle cx="1050" cy="150" r="1" />
<circle cx="1250" cy="350" r="1" />
<circle cx="1450" cy="150" r="1" />
<circle cx="1650" cy="350" r="1" />
<circle cx="1850" cy="150" r="1" />
<circle cx="250" cy="550" r="1" />
<circle cx="450" cy="750" r="1" />
<circle cx="650" cy="550" r="1" />
<circle cx="850" cy="750" r="1" />
<circle cx="1050" cy="550" r="1" />
<circle cx="1250" cy="750" r="1" />
<circle cx="1450" cy="550" r="1" />
<circle cx="1650" cy="750" r="1" />
<circle cx="1850" cy="550" r="1" />
<circle cx="250" cy="950" r="1" />
<circle cx="450" cy="850" r="1" />
<circle cx="650" cy="950" r="1" />
<circle cx="850" cy="850" r="1" />
<circle cx="1050" cy="950" r="1" />
<circle cx="1250" cy="850" r="1" />
<circle cx="1450" cy="950" r="1" />
<circle cx="1650" cy="850" r="1" />
<circle cx="1850" cy="950" r="1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB