Musik-Knopf wird zum Chamäleon - passt Farben live an jede Seite an
Bisher kannte der Knopf nur 3 feste Weltfarben (dogfather/hasidog/ spicymedia). Jetzt analysiert main.js (musikKnopfFarbenAnpassen) per Canvas das tatsächliche Bild jeder einzelnen Seite - Durchschnittsfarbe plus die kräftigste Farbe darin, als Verlauf - und setzt sie live als --music-c1/--music-c2 auf den Knopf. Bildquelle in Prioritätsreihenfolge: 1) scharfes Hero-Banner-Bild, 2) Startseiten-Artwork, 3) Ambiente-Hintergrundbild der Seite. Ohne Bild fällt der Knopf sauber auf die normale Weltfarbe zurück. Läuft beim ersten Laden UND nach jedem nahtlosen Seitenwechsel (SPA-Navigation), damit die Farbe wirklich bei jeder Seite mitwechselt.
This commit is contained in:
@@ -267,6 +267,134 @@
|
||||
});
|
||||
}
|
||||
|
||||
/* ===================================================================
|
||||
Musik-Knopf: Chamäleon-Farben
|
||||
|
||||
Der Knopf soll nicht nur zwischen 3 festen Weltfarben wechseln,
|
||||
sondern sich an das tatsächliche Bild JEDER einzelnen Seite anpassen
|
||||
— Durchschnittsfarbe plus die kräftigste (sattste) Farbe darin, als
|
||||
kleiner Verlauf. Bildquelle in Prioritätsreihenfolge:
|
||||
1. Das scharfe Banner-Bild im Kopfbereich (.hero-banner img)
|
||||
2. Das Artwork der Startseite (.hero-artwork, CSS-Hintergrund)
|
||||
3. Das Ambiente-Hintergrundbild der Seite (--page-bg am <body>)
|
||||
Gibt es nichts davon (reine Text-Hero-Seiten wie Links oder Videos),
|
||||
fällt der Knopf sauber auf die normale Weltfarbe zurück (siehe CSS:
|
||||
var(--music-c1, var(--accent))).
|
||||
|
||||
Bilder sind alle selbst gehostet (gleiche Domain) — Canvas-Auslesen
|
||||
funktioniert dadurch ohne CORS-Probleme.
|
||||
=================================================================== */
|
||||
function bildquelleErmitteln() {
|
||||
const banner = document.querySelector(".hero-banner img");
|
||||
if (banner && banner.getAttribute("src")) return banner;
|
||||
|
||||
const artwork = document.querySelector(".hero-artwork");
|
||||
if (artwork) {
|
||||
const hintergrund = getComputedStyle(artwork, "::before").backgroundImage;
|
||||
const ersteEbene = hintergrund && hintergrund.split(",")[0];
|
||||
const treffer = ersteEbene && ersteEbene.match(/url\(["']?(.*?)["']?\)/);
|
||||
if (treffer && treffer[1]) return treffer[1];
|
||||
}
|
||||
|
||||
const seitenBg = getComputedStyle(document.body).getPropertyValue("--page-bg");
|
||||
const treffer2 = seitenBg && seitenBg.match(/url\(["']?(.*?)["']?\)/);
|
||||
if (treffer2 && treffer2[1]) return treffer2[1];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function rgbNachHsl(r, g, b) {
|
||||
r /= 255; g /= 255; b /= 255;
|
||||
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||
let h = 0, s = 0;
|
||||
const l = (max + min) / 2;
|
||||
if (max !== min) {
|
||||
const d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch (max) {
|
||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
||||
case g: h = (b - r) / d + 2; break;
|
||||
default: h = (r - g) / d + 4;
|
||||
}
|
||||
h *= 60;
|
||||
}
|
||||
return [h, s * 100, l * 100];
|
||||
}
|
||||
|
||||
const begrenzen = (wert, min, max) => Math.min(max, Math.max(min, wert));
|
||||
|
||||
let musikFarbLauf = 0;
|
||||
|
||||
function musikKnopfFarbenAnpassen() {
|
||||
const knopf = document.getElementById("music-toggle");
|
||||
if (!knopf) return;
|
||||
const lauf = ++musikFarbLauf;
|
||||
|
||||
const zuruecksetzen = () => {
|
||||
knopf.style.removeProperty("--music-c1");
|
||||
knopf.style.removeProperty("--music-c2");
|
||||
};
|
||||
|
||||
const quelle = bildquelleErmitteln();
|
||||
if (!quelle) {
|
||||
zuruecksetzen();
|
||||
return;
|
||||
}
|
||||
|
||||
const verarbeiten = (bild) => {
|
||||
if (lauf !== musikFarbLauf) return; // zwischenzeitlich schon weitergeklickt
|
||||
try {
|
||||
const groesse = 28;
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = groesse;
|
||||
canvas.height = groesse;
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(bild, 0, 0, groesse, groesse);
|
||||
const daten = ctx.getImageData(0, 0, groesse, groesse).data;
|
||||
|
||||
let rSumme = 0, gSumme = 0, bSumme = 0, n = 0;
|
||||
let besteSaettigung = -1, satR = 0, satG = 0, satB = 0;
|
||||
for (let i = 0; i < daten.length; i += 4) {
|
||||
const r = daten[i], g = daten[i + 1], b = daten[i + 2];
|
||||
rSumme += r; gSumme += g; bSumme += b; n++;
|
||||
const hsl = rgbNachHsl(r, g, b);
|
||||
if (hsl[2] > 15 && hsl[2] < 88 && hsl[1] > besteSaettigung) {
|
||||
besteSaettigung = hsl[1]; satR = r; satG = g; satB = b;
|
||||
}
|
||||
}
|
||||
const r = Math.round(rSumme / n), g = Math.round(gSumme / n), b = Math.round(bSumme / n);
|
||||
|
||||
const [h1, s1, l1] = rgbNachHsl(r, g, b);
|
||||
const farbe1 = `hsl(${Math.round(h1)}deg ${Math.round(begrenzen(s1, 42, 92))}% ${Math.round(begrenzen(l1, 40, 62))}%)`;
|
||||
|
||||
let farbe2;
|
||||
if (besteSaettigung > 18) {
|
||||
const [h2, s2, l2] = rgbNachHsl(satR, satG, satB);
|
||||
farbe2 = `hsl(${Math.round(h2)}deg ${Math.round(begrenzen(s2, 50, 95))}% ${Math.round(begrenzen(l2, 42, 66))}%)`;
|
||||
} else {
|
||||
farbe2 = `hsl(${Math.round((h1 + 45) % 360)}deg ${Math.round(begrenzen(s1, 45, 90))}% ${Math.round(begrenzen(l1 + 8, 42, 68))}%)`;
|
||||
}
|
||||
|
||||
knopf.style.setProperty("--music-c1", farbe1);
|
||||
knopf.style.setProperty("--music-c2", farbe2);
|
||||
} catch {
|
||||
zuruecksetzen(); // z.B. wenn das Bild aus irgendeinem Grund nicht lesbar ist
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof quelle === "string") {
|
||||
const bild = new Image();
|
||||
bild.addEventListener("load", () => verarbeiten(bild));
|
||||
bild.addEventListener("error", zuruecksetzen);
|
||||
bild.src = quelle;
|
||||
} else if (quelle.complete && quelle.naturalWidth > 0) {
|
||||
verarbeiten(quelle);
|
||||
} else {
|
||||
quelle.addEventListener("load", () => verarbeiten(quelle), { once: true });
|
||||
quelle.addEventListener("error", zuruecksetzen, { once: true });
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================================================================
|
||||
Nahtloser Seitenwechsel — damit die Musik nicht abreißt
|
||||
|
||||
@@ -382,6 +510,7 @@
|
||||
renderHeader(); // markiert den richtigen Menüpunkt als aktiv
|
||||
window.scrollTo(0, 0);
|
||||
document.body.classList.remove("seite-laedt");
|
||||
musikKnopfFarbenAnpassen(); // Chamäleon-Knopf an die neue Seite anpassen
|
||||
|
||||
await skripteUebernehmen(dok);
|
||||
}
|
||||
@@ -430,6 +559,7 @@
|
||||
renderFooter();
|
||||
renderFog();
|
||||
renderMusicWidget();
|
||||
musikKnopfFarbenAnpassen();
|
||||
nahtloseNavigationAktivieren();
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user