Einen RGB-Farbverlauf (Schwarz-Rot-Gold) in JS/TS programmieren?



  • Hallo, bisher sieht das so aus:

    EinenFarbverlauf(schwarzrotgold)programmieren:\color{#0f0000}{E}\color{#100000}{i}\color{#110000}{n}\color{#120000}{e}\color{#140000}{n}\color{#150000}{ }\color{#170000}{F}\color{#1a0000}{a}\color{#1c0000}{r}\color{#200000}{b}\color{#240000}{v}\color{#2b0000}{e}\color{#330000}{r}\color{#400000}{l}\color{#550000}{a}\color{#800000}{u}\color{#ff0000}{f}\color{#ff0f00}{ }\color{#ff1000}{(}\color{#ff1100}{s}\color{#ff1200}{c}\color{#ff1400}{h}\color{#ff1500}{w}\color{#ff1700}{a}\color{#ff1a00}{r}\color{#ff1c00}{z}\color{#ff2000}{-}\color{#ff2400}{r}\color{#ff2b00}{o}\color{#ff3300}{t}\color{#ff4000}{-}\color{#ff5500}{g}\color{#ff8000}{o}\color{#ffff00}{l}\color{#ffff00}{d}\color{#ffff00}{)}\color{#ffff00}{ }\color{#ffff00}{p}\color{#ffff00}{r}\color{#ffff00}{o}\color{#ffff00}{g}\color{#ffff00}{r}\color{#ffff00}{a}\color{#ffff00}{m}\color{#ffff00}{m}\color{#ffff00}{i}\color{#ffff00}{e}\color{#ffff00}{r}\color{#ffff00}{e}\color{#ffff00}{n}\color{#ffff00}{:}

    Das Problem ist aber,

    • die Überläufe von Schwarz nach Rot und von Rot zu Gelb sind zu schnell,
    • das Gelb zum Schluss ist nicht gut zu lesen, das sollte eher Orange sein ...
    function pad(num, size) {
        num = num.toString();
        while (num.length < size) num = "0" + num;
        return num;
    }
    
    const msg:string = "Einen Farbverlauf (schwarz-rot-gold) programmieren:";
    let r = 0;
    let g = 0;
    let b = 0;
    let s = "$";
    for (let i = 0; i < msg.length; i++) {
        if (i < msg.length / 3) {
            r = Math.round(1.0 / (msg.length / 3 - i) * 255);
        } else if (i < msg.length / 3 * 2) {
            g = Math.round(1.0 / (msg.length / 3 * 2 - i) * 255);
        }
        s += `\\color{#${pad(r.toString(16), 2)}${pad(g.toString(16), 2)}${pad(b.toString(16), 2)}}{${msg.charAt(i)}}`
    }
    s += "$"
    console.log(s);
    

    Hat vielleicht jemand eine Idee, wie man die Logik (Zeile 13 bis 17) verbessern könnte? Wäre es vielleicht besser, zuerst ins HSV-Modell zu konvertieren?



  • Hier noch zum selber ausprobieren: https://www.mycompiler.io/view/AHGryTi1A0P



  • Wenn du 2 Farbverläufe (Schwarz->Rot und dann Rot->Gelb) haben willst, warum berechnest du diese dann nur bis Ein-Drittel (msg.length / 3) und Zwei-Drittel (msg.length / 3 * 2), anstatt bis zur Hälfte (msg.length / 2) und zum Ende (msg.length)?
    Außerdem paßt dein Ausdruck innerhalb vom unteren Math.round nicht (es soll ja jeweils ein Wert von 0-255 herauskommen).

    Hier mein Code dazu: myCompiler

    Mit dem Ergebnis:

    EinenFarbverlauf(schwarzrotgold)programmieren:\color{#000000}{E}\color{#0a0000}{i}\color{#140000}{n}\color{#1e0000}{e}\color{#280000}{n}\color{#320000}{ }\color{#3c0000}{F}\color{#460000}{a}\color{#500000}{r}\color{#5a0000}{b}\color{#640000}{v}\color{#6e0000}{e}\color{#780000}{r}\color{#820000}{l}\color{#8c0000}{a}\color{#960000}{u}\color{#a00000}{f}\color{#aa0000}{ }\color{#b40000}{(}\color{#be0000}{s}\color{#c80000}{c}\color{#d20000}{h}\color{#dc0000}{w}\color{#e60000}{a}\color{#f00000}{r}\color{#fa0000}{z}\color{#fa0500}{-}\color{#fa0f00}{r}\color{#fa1900}{o}\color{#fa2300}{t}\color{#fa2d00}{-}\color{#fa3700}{g}\color{#fa4100}{o}\color{#fa4b00}{l}\color{#fa5500}{d}\color{#fa5f00}{)}\color{#fa6900}{ }\color{#fa7300}{p}\color{#fa7d00}{r}\color{#fa8700}{o}\color{#fa9100}{g}\color{#fa9b00}{r}\color{#faa500}{a}\color{#faaf00}{m}\color{#fab900}{m}\color{#fac300}{i}\color{#facd00}{e}\color{#fad700}{r}\color{#fae100}{e}\color{#faeb00}{n}\color{#faf500}{:}

    PS: Um die Leerzeichen nicht verschwinden zu lassen, müssen diese mit \ escaped werden:

    Einen Farbverlauf (schwarzrotgold) programmieren:\color{#000000}{E}\color{#0a0000}{i}\color{#140000}{n}\color{#1e0000}{e}\color{#280000}{n}\color{#320000}{\ }\color{#3c0000}{F}\color{#460000}{a}\color{#500000}{r}\color{#5a0000}{b}\color{#640000}{v}\color{#6e0000}{e}\color{#780000}{r}\color{#820000}{l}\color{#8c0000}{a}\color{#960000}{u}\color{#a00000}{f}\color{#aa0000}{\ }\color{#b40000}{(}\color{#be0000}{s}\color{#c80000}{c}\color{#d20000}{h}\color{#dc0000}{w}\color{#e60000}{a}\color{#f00000}{r}\color{#fa0000}{z}\color{#fa0500}{-}\color{#fa0f00}{r}\color{#fa1900}{o}\color{#fa2300}{t}\color{#fa2d00}{-}\color{#fa3700}{g}\color{#fa4100}{o}\color{#fa4b00}{l}\color{#fa5500}{d}\color{#fa5f00}{)}\color{#fa6900}{\ }\color{#fa7300}{p}\color{#fa7d00}{r}\color{#fa8700}{o}\color{#fa9100}{g}\color{#fa9b00}{r}\color{#faa500}{a}\color{#faaf00}{m}\color{#fab900}{m}\color{#fac300}{i}\color{#facd00}{e}\color{#fad700}{r}\color{#fae100}{e}\color{#faeb00}{n}\color{#faf500}{:}

    Edit: Link korrigiert



  • @Th69 Danke! ☺

    Ja, die zwei Punkte waren das, was ich nicht vermocht hatte, zu sehen...

    So ist es so, wie es "sein soll". 🙂



  • @Th69 sagte in Einen RGB-Farbverlauf (Schwarz-Rot-Gold) in JS/TS programmieren?:

    Hier mein Code dazu: myCompiler
    Mit dem Ergebnis:

    ... Das ist aber noch meiner... Du musst forken und dann neu speichern!



  • YAY !! Ich habe alleine Feuer gemacht !!! ;):\color{#000000}{Y}\color{#0b0000}{A}\color{#160000}{Y}\color{#210000}{\ }\color{#2d0000}{!}\color{#380000}{!}\color{#430000}{\ }\color{#4e0000}{I}\color{#590000}{c}\color{#640000}{h}\color{#6f0000}{\ }\color{#7a0000}{h}\color{#860000}{a}\color{#910000}{b}\color{#9c0000}{e}\color{#a70000}{\ }\color{#b20000}{a}\color{#bd0000}{l}\color{#c80000}{l}\color{#d30000}{e}\color{#df0000}{i}\color{#ea0000}{n}\color{#f50000}{e}\color{#f50000}{\ }\color{#f50b00}{F}\color{#f51600}{e}\color{#f52100}{u}\color{#f52d00}{e}\color{#f53800}{r}\color{#f54300}{\ }\color{#f54e00}{g}\color{#f55900}{e}\color{#f56400}{m}\color{#f56f00}{a}\color{#f57a00}{c}\color{#f58600}{h}\color{#f59100}{t}\color{#f59c00}{\ }\color{#f5a700}{!}\color{#f5b200}{!}\color{#f5bd00}{!}\color{#f5c800}{\ }\color{#f5d300}{;}\color{#f5df00}{-}\color{#f5ea00}{)}\color{#f5f500}{:}

    function pad(num, size) {
        num = num.toString();
        while (num.length < size) num = "0" + num;
        return num;
    }
    
    function color(a, n) {
        return Math.round(1.0 / n * a * 256);
    }
    
    const msg:string = "YAY !! Ich habe alleine Feuer gemacht !!! ;-):";
    const n:number = msg.length;
    let r = 0;
    let g = 0;
    let b = 0;
    let s = "$";
    for (let i = 0; i < msg.length; i++) {
        if (i < n / 2) {
            r = color(i, n / 2.0);
        } else {
            g = color(i - n / 2.0, n / 2.0);
        }
        let c = msg.charAt(i);
        if (c == ' ') {
            s += `\\color{#${pad(r.toString(16), 2)}${pad(g.toString(16), 2)}${pad(b.toString(16), 2)}}{\\${c}}`
        } else {
            s += `\\color{#${pad(r.toString(16), 2)}${pad(g.toString(16), 2)}${pad(b.toString(16), 2)}}{${c}}`
        }
    }
    s += "$"
    console.log(s);
    
    

    Es ist aber immer noch nicht so gut zu lesen (wie bei dir zum Beispiel) ... Was ist noch falsch?\color{#000000}{E}\color{#050000}{s}\color{#0b0000}{\ }\color{#100000}{i}\color{#150000}{s}\color{#1b0000}{t}\color{#200000}{\ }\color{#250000}{a}\color{#2b0000}{b}\color{#300000}{e}\color{#350000}{r}\color{#3b0000}{\ }\color{#400000}{i}\color{#450000}{m}\color{#4b0000}{m}\color{#500000}{e}\color{#550000}{r}\color{#5b0000}{\ }\color{#600000}{n}\color{#650000}{o}\color{#6b0000}{c}\color{#700000}{h}\color{#750000}{\ }\color{#7b0000}{n}\color{#800000}{i}\color{#850000}{c}\color{#8b0000}{h}\color{#900000}{t}\color{#950000}{\ }\color{#9b0000}{s}\color{#a00000}{o}\color{#a50000}{\ }\color{#ab0000}{g}\color{#b00000}{u}\color{#b50000}{t}\color{#bb0000}{\ }\color{#c00000}{z}\color{#c50000}{u}\color{#cb0000}{\ }\color{#d00000}{l}\color{#d50000}{e}\color{#db0000}{s}\color{#e00000}{e}\color{#e50000}{n}\color{#eb0000}{\ }\color{#f00000}{(}\color{#f50000}{w}\color{#fb0000}{i}\color{#fb0000}{e}\color{#fb0500}{\ }\color{#fb0b00}{b}\color{#fb1000}{e}\color{#fb1500}{i}\color{#fb1b00}{\ }\color{#fb2000}{d}\color{#fb2500}{i}\color{#fb2b00}{r}\color{#fb3000}{\ }\color{#fb3500}{z}\color{#fb3b00}{u}\color{#fb4000}{m}\color{#fb4500}{\ }\color{#fb4b00}{B}\color{#fb5000}{e}\color{#fb5500}{i}\color{#fb5b00}{s}\color{#fb6000}{p}\color{#fb6500}{i}\color{#fb6b00}{e}\color{#fb7000}{l}\color{#fb7500}{)}\color{#fb7b00}{\ }\color{#fb8000}{.}\color{#fb8500}{.}\color{#fb8b00}{.}\color{#fb9000}{\ }\color{#fb9500}{W}\color{#fb9b00}{a}\color{#fba000}{s}\color{#fba500}{\ }\color{#fbab00}{i}\color{#fbb000}{s}\color{#fbb500}{t}\color{#fbbb00}{\ }\color{#fbc000}{n}\color{#fbc500}{o}\color{#fbcb00}{c}\color{#fbd000}{h}\color{#fbd500}{\ }\color{#fbdb00}{f}\color{#fbe000}{a}\color{#fbe500}{l}\color{#fbeb00}{s}\color{#fbf000}{c}\color{#fbf500}{h}\color{#fbfb00}{?} 😟

    https://www.mycompiler.io/view/EW3Gi0PLAIo



  • Sorry, habe den Link oben korrigiert.

    Dein Code sollte jetzt (fast) identisch zu meinem sein (nur hast du 256 anstatt 255 als Faktor und das 1.0 / ... ist überflüssig, wenn du die Division als letztes durchführst).

    Je länger der Text ist, desto kleiner sind ja die Farbübergänge, d.h. je mehr Buchstaben sind gelb(lich) am Ende. Du könntest dafür dann den Faktor auf z.B. 220 verändern (also weniger hellgelb am Ende):

    Es ist aber immer noch nicht so gut zu lesen (wie bei dir zum Beispiel) ... Was ist noch falsch?\color{#000000}{E}\color{#050000}{s}\color{#0b0000}{\ }\color{#100000}{i}\color{#150000}{s}\color{#1b0000}{t}\color{#200000}{\ }\color{#250000}{a}\color{#2b0000}{b}\color{#300000}{e}\color{#350000}{r}\color{#3a0000}{\ }\color{#400000}{i}\color{#450000}{m}\color{#4a0000}{m}\color{#500000}{e}\color{#550000}{r}\color{#5a0000}{\ }\color{#600000}{n}\color{#650000}{o}\color{#6a0000}{c}\color{#700000}{h}\color{#750000}{\ }\color{#7a0000}{n}\color{#800000}{i}\color{#850000}{c}\color{#8a0000}{h}\color{#8f0000}{t}\color{#950000}{\ }\color{#9a0000}{s}\color{#9f0000}{o}\color{#a50000}{\ }\color{#aa0000}{g}\color{#af0000}{u}\color{#b50000}{t}\color{#ba0000}{\ }\color{#bf0000}{z}\color{#c50000}{u}\color{#ca0000}{\ }\color{#cf0000}{l}\color{#d50000}{e}\color{#da0000}{s}\color{#df0000}{e}\color{#e40000}{n}\color{#ea0000}{\ }\color{#ef0000}{(}\color{#f40000}{w}\color{#fa0000}{i}\color{#fa0000}{e}\color{#fa0500}{\ }\color{#fa0900}{b}\color{#fa0e00}{e}\color{#fa1200}{i}\color{#fa1700}{\ }\color{#fa1c00}{d}\color{#fa2000}{i}\color{#fa2500}{r}\color{#fa2900}{\ }\color{#fa2e00}{z}\color{#fa3200}{u}\color{#fa3700}{m}\color{#fa3c00}{\ }\color{#fa4000}{B}\color{#fa4500}{e}\color{#fa4900}{i}\color{#fa4e00}{s}\color{#fa5300}{p}\color{#fa5700}{i}\color{#fa5c00}{e}\color{#fa6000}{l}\color{#fa6500}{)}\color{#fa6900}{\ }\color{#fa6e00}{.}\color{#fa7300}{.}\color{#fa7700}{.}\color{#fa7c00}{\ }\color{#fa8000}{W}\color{#fa8500}{a}\color{#fa8a00}{s}\color{#fa8e00}{\ }\color{#fa9300}{i}\color{#fa9700}{s}\color{#fa9c00}{t}\color{#faa000}{\ }\color{#faa500}{n}\color{#faaa00}{o}\color{#faae00}{c}\color{#fab300}{h}\color{#fab700}{\ }\color{#fabc00}{f}\color{#fac100}{a}\color{#fac500}{l}\color{#faca00}{s}\color{#face00}{c}\color{#fad300}{h}\color{#fad700}{?}

    Oder eben doch im HSV-Farbraum rechnen und dann nur den Farbwert (H) ändern - und Sättigung (S) sowie Helligkeit (V) auf einen konstanten Wert einstellen. Dafür dann am besten entsprechende Umrechnungsmethoden HSV <-> RGB verwenden.



  • @Th69 Ich danke dir, das Thema ist gelöst ...

    Und ja, eigentlich ist es "richtiger", den Aktualisierungsschritt erst am Schleifenrumpfende zu machen! r == Red soll aber durchaus den Wert 255 annehmen können. 😵

    Bräuchte das jetzt eigentlich nur noch für bash/sed/awk/printf ... Hat da vielleicht noch jemand eine Idee?



  • Falls das noch jemand außer mir braucht, hier noch einmal in Schön, funktioniert mit geraden und ungeraden Längen:

    function pad(num, size) {
        num = num.toString();
        while (num.length < size) num = "0" + num;
        return num;
    }
    
    function color(a, n, maxIncl) {
        return Math.round(1.0 / n * a * maxIncl);
    }
    
    const msg:string = "Testtext:";
    const n1:number = msg.length;
    const n2:number = n1 / 2;
    const n3:number = n1 % 2 / 2.0;
    let r = 0;
    let g = 0;
    let b = 0;
    let s = "$";
    for (let i = 0; i < n1; i++) {
        if (i < n2) {
            r = color(i + 1, n2 + n3, 255);
        } else {
            g = color(i - n2 + n3 + 1, n2 + n3, 256 / 4 * 3);
        }
        console.log(r, g, b);
        let c = msg.charAt(i);
        if (c == ' ') {
            s += `\\color{#${pad(r.toString(16), 2)}${pad(g.toString(16), 2)}${pad(b.toString(16), 2)}}{\\${c}}`
        } else {
            s += `\\color{#${pad(r.toString(16), 2)}${pad(g.toString(16), 2)}${pad(b.toString(16), 2)}}{${c}}`
        }
    }
    s += "$"
    console.log(s);
    
    

    Testtext:\color{#330000}{T}\color{#660000}{e}\color{#990000}{s}\color{#cc0000}{t}\color{#ff0000}{t}\color{#ff4d00}{e}\color{#ff7300}{x}\color{#ff9a00}{t}\color{#ffc000}{:}

    https://www.mycompiler.io/view/BJaAO36TutX

    Zeile 23 finde ich noch etwas unübersichtlich, aber das geht vielleicht nicht anders ... habe nun schon wie wild hin und her gerechnet.

    So, ✅



  • @noLust Vielleicht noch eine Anmerkung für solche Farbverläufe: Man kann sowas auch recht elegant mit Standardwerkzeugen aus der Computergrafik angehen anstatt es so problemspezifisch direkt zu programmieren. In diesem Fall z.B. mit Linearer Interpolation zwischen zwei Punkten:

    a+t(ba)a + t(b-a)

    Diese Formel beschreibt eine Gerade zwischen den Punkten aa und bb in einem Raum beliebiger Dimension (a,bRna, b \in \mathbb{R}^n). tt ist ein Skalar (tRt \in \mathbb{R}) und das Ergebnis der Formel ist aa, wenn t=0t = 0 und bb, wenn t=1t = 1. Für tt zwischen 00 und 11 liegt es auf der Strecke zwischen aa und bb im entsprechenden Verhältnis, also für t=0.25t = 0.25 z.B. auf dem Viertel des Weges zwischen aa und bb.

    Man kann jetzt aa und bb als Start- und Ziel-Farbe z.B. im 3-dimensionalen RGB-Farbraum (oder HSV oder was auch immer) interpretieren und sich so die Zwischen-Farbwerte ausrechnen. Dafür muss man lediglich den Zeichen-Index auf das Intervall [0,1][0, 1] umrechnen. Z.B. mit (i - i_startfarbe) / (i_zielfarbe - i_startfarbe).

    Ich habe mich aus Spaß auch mal an einer generischen Variante versucht (wollte eh nochmal was mit JS herumspielen 😁 ). Die ermöglicht es, beliebige (und auch beliebig viele) Farben in einem Array zu definieren, mit denen dann der farbige Text erzeugt wird. Vielleicht kann dir das ja als Inspiration dienen:

    https://www.mycompiler.io/view/HaRbj7tNfne

    Mit den beliebigen Farben hat man dann auch die Möglichkeit, den Farbverlauf feiner zu justieren, wenn einem das Ergebnis nicht gefällt. Z.B. noch ein Orange einfügen und das Intervall in Richtung Gelb etwas schmaler machen.



  • @Finnegan sagte in Einen RGB-Farbverlauf (Schwarz-Rot-Gold) in JS/TS programmieren?:

    Computergrafik

    Ach, daher kommt der Spaß. 😅 Ja, ich hatte das (meiner Zeit) noch in der Schule berechnen müssen. 👴 Aber da ging es darum, den PONR bei Flugzeugen zu berechnen (die nur strikt geradeaus fliegen) ... aber naja, Mathematik.



  • @noLust sagte in [Einen RGB-Farbverlauf (Schwarz-Rot-Gold) in JS/TS programmieren?]

    Ach, daher kommt der Spaß. 😅 Ja, ich hatte das (meiner Zeit) noch in der Schule berechnen müssen. 👴 Aber da ging es darum, den PONR bei Flugzeugen zu berechnen (die nur strikt geradeaus fliegen) ... aber naja, Mathematik.

    Ich würde nicht behaupten, dass es "da her" kommt, aber Linearer Interpolation begegnet man dort an vielen Stellen. Mathematisches Standardwerkzeug halt und eine intuitive Methode, das Problem zu betrachten - zumindest aus meiner Perspektive intuitiver als dein Ansatz 😉



  • Ich muss mal schauen, ob mein altes Mathebuch noch wiederauffindbar ist... dann scanne ich die Aufgabe mal ein... die Formulierung war ganz interessant, ich weiß sie aber nicht mehr aus dem ff.

    Kleiner Ansporn für mich selber: Ich tippe auf Seite 104. 😃



  • Ist leider weg. 😞


Log in to reply