Utwórz kolor szesnastkowy na podstawie ciągu znaków za pomocą JavaScript

141

Chcę utworzyć funkcję, która zaakceptuje dowolny stary ciąg (zwykle będzie to pojedyncze słowo) i na tej podstawie w jakiś sposób wygeneruje wartość szesnastkową między #000000i #FFFFFF, więc mogę użyć jej jako koloru dla elementu HTML.

Może nawet skrócona wartość szesnastkowa (np #FFF.:), jeśli jest to mniej skomplikowane. W rzeczywistości idealny byłby kolor z palety „bezpiecznej w Internecie”.

Darragh Enright
źródło
2
Czy możesz podać przykładowe dane wejściowe i / lub linki do podobnych pytań?
qw3n
2
To nie jest odpowiedź, ale przydatne mogą być następujące: Aby zamienić liczbę szesnastkową na liczbę całkowitą, użyj parseInt(hexstr, 10). Aby przekonwertować liczbę całkowitą na szesnastkową, użyj n.toString(16), gdzie n jest liczbą całkowitą.
Cristian Sanchez
@ qw3n - przykładowe dane wejściowe: tylko krótkie, zwykłe stare ciągi tekstowe ... takie jak „medycyna”, „chirurgia”, „neurologia”, „praktyka ogólna” itp. Od 3 do powiedzmy 20 znaków ... nie można znaleźć drugie, ale tutaj jest pytanie java: stackoverflow.com/questions/2464745/… @Daniel - Dzięki. Muszę usiąść i spróbować jeszcze raz poważnie. mogłoby się przydać.
Darragh Enright

Odpowiedzi:

176

Po prostu przenoszę Java z szesnastkowego kodu koloru Compute dla dowolnego ciągu do Javascript:

function hashCode(str) { // java String#hashCode
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
       hash = str.charCodeAt(i) + ((hash << 5) - hash);
    }
    return hash;
} 

function intToRGB(i){
    var c = (i & 0x00FFFFFF)
        .toString(16)
        .toUpperCase();

    return "00000".substring(0, 6 - c.length) + c;
}

Aby dokonać konwersji, zrobiłbyś:

intToRGB(hashCode(your_string))
Cristian Sanchez
źródło
1
świetny! dzięki, to działa dobrze. Nie wiem zbyt wiele o operatorach bitowych i innych rzeczach, więc Twoja pomoc przy przenoszeniu jest doceniana.
Darragh Enright
Musi wypełnić ciągi hex, takie jak:("00" + ((this >> 24) & 0xFF).toString(16)).slice(-2) + ("00" + ((this >> 16) & 0xFF).toString(16)).slice(-2) + ("00" + ((this >> 8) & 0xFF).toString(16)).slice(-2) + ("00" + (this & 0xFF).toString(16)).slice(-2);
Thymine,
2
Konwertuję kilka tagów gatunków muzycznych na kolory tła i zaoszczędziło mi to dużo czasu.
Kyle Pennell,
Chciałbym móc przekonwertować to na php.
Nimitz E.,
6
Mam pewne problemy z prawie tymi samymi kolorami dla podobnych ciągów, na przykład: intToRGB(hashCode('hello1')) -> "3A019F" intToRGB(hashCode('hello2')) -> "3A01A0" I poprawiam twój kod, dodając mnożenie dla końcowej wartości skrótu:return 100 * hash;
SirWojtek
185

Oto adaptacja odpowiedzi CD Sancheza, która konsekwentnie zwraca 6-cyfrowy kod koloru:

var stringToColour = function(str) {
  var hash = 0;
  for (var i = 0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 5) - hash);
  }
  var colour = '#';
  for (var i = 0; i < 3; i++) {
    var value = (hash >> (i * 8)) & 0xFF;
    colour += ('00' + value.toString(16)).substr(-2);
  }
  return colour;
}

Stosowanie:

stringToColour("greenish");
// -> #9bc63b

Przykład:

http://jsfiddle.net/sUK45/

(Alternatywne / prostsze rozwiązanie może obejmować zwrócenie kodu koloru w stylu „rgb (...)”).

Joe Freeman
źródło
3
Ten kod działa świetnie w połączeniu z automatycznie generowanymi identyfikatorami NoSQL, Twój kolor będzie zawsze taki sam dla tego samego użytkownika.
deviavir
Potrzebowałem również kanału alfa do przezroczystości w moich kodach szesnastkowych. To pomogło (dodanie dwóch cyfr dla kanału alfa na końcu mojego kodu szesnastkowego): gist.github.com/lopspower/03fb1cc0ac9f32ef38f4
Husterknupp
@Tjorriemorrie Upvoted za wskazanie, że to kolor, a nie kolor. Tak, tak, to nie jest tak naprawdę na temat, ale jest to dla mnie coś ważnego (tak naprawdę podczas pisania tego oryginalnie przeliterowałem to „kolor” dwa razy!). Dziękuję Ci.
Pryftan
Ciekawe, że kolor jest inny dla tego samego ciągu na różnych przeglądarkach / systemach operacyjnych - np. Chrome + Windows i Chrome + Android - mój e-mail => kolor jest niebieski na jednej, a zielony na drugiej. Każdy pomysł, dlaczego?
avenmore
43

Chciałem podobnego bogactwa kolorów dla elementów HTML, byłem zaskoczony, że CSS obsługuje teraz kolory hsl (), więc pełne rozwiązanie dla mnie jest poniżej:

Zobacz także Jak automatycznie wygenerować N „odrębnych” kolorów? więcej alternatyw bardziej podobnych do tego.

function colorByHashCode(value) {
    return "<span style='color:" + value.getHashCode().intToHSL() + "'>" + value + "</span>";
}
String.prototype.getHashCode = function() {
    var hash = 0;
    if (this.length == 0) return hash;
    for (var i = 0; i < this.length; i++) {
        hash = this.charCodeAt(i) + ((hash << 5) - hash);
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
};
Number.prototype.intToHSL = function() {
    var shortened = this % 360;
    return "hsl(" + shortened + ",100%,30%)";
};

document.body.innerHTML = [
  "javascript",
  "is",
  "nice",
].map(colorByHashCode).join("<br/>");
span {
  font-size: 50px;
  font-weight: 800;
}

W HSL jego odcień, nasycenie, jasność. Tak więc odcień między 0-359 będzie miał wszystkie kolory, nasycenie określa, jak bogaty chcesz kolor, 100% działa dla mnie. Jasność określa głębię, 50% to norma, 25% to ciemne kolory, 75% to pastel. Mam 30%, ponieważ najlepiej pasuje do mojej kolorystyki.

Tymina
źródło
3
Bardzo wszechstronne rozwiązanie.
MastaBaba
2
Dzięki za udostępnienie rozwiązania, w którym możesz zdecydować, jak kolorowe powinny być kolory!
Florian Bauer
@haykam Dzięki za utworzenie fragmentu!
Tymine
Takie podejście jest naprawdę przydatne, aby nadać pożądaną wibrację / subtelność, której potrzebowała moja aplikacja. Losowy Hex różni się zbytnio nasyceniem i jasnością, aby był przydatny w większości sytuacji. Dzięki za to!
simey.me
To rozwiązanie zwraca zbyt mało kolorów, nie wystarczy.
katamfetamina
9

Uważam, że generowanie przypadkowych kolorów ma tendencję do tworzenia kolorów, które nie mają wystarczającego kontrastu dla mojego gustu. Najłatwiejszym sposobem obejścia tego problemu jest wstępne wypełnienie listy bardzo różnych kolorów. Do każdego nowego ciągu przypisz kolejny kolor na liście:

// Takes any string and converts it into a #RRGGBB color.
var StringToColor = (function(){
    var instance = null;

    return {
    next: function stringToColor(str) {
        if(instance === null) {
            instance = {};
            instance.stringToColorHash = {};
            instance.nextVeryDifferntColorIdx = 0;
            instance.veryDifferentColors = ["#000000","#00FF00","#0000FF","#FF0000","#01FFFE","#FFA6FE","#FFDB66","#006401","#010067","#95003A","#007DB5","#FF00F6","#FFEEE8","#774D00","#90FB92","#0076FF","#D5FF00","#FF937E","#6A826C","#FF029D","#FE8900","#7A4782","#7E2DD2","#85A900","#FF0056","#A42400","#00AE7E","#683D3B","#BDC6FF","#263400","#BDD393","#00B917","#9E008E","#001544","#C28C9F","#FF74A3","#01D0FF","#004754","#E56FFE","#788231","#0E4CA1","#91D0CB","#BE9970","#968AE8","#BB8800","#43002C","#DEFF74","#00FFC6","#FFE502","#620E00","#008F9C","#98FF52","#7544B1","#B500FF","#00FF78","#FF6E41","#005F39","#6B6882","#5FAD4E","#A75740","#A5FFD2","#FFB167","#009BFF","#E85EBE"];
        }

        if(!instance.stringToColorHash[str])
            instance.stringToColorHash[str] = instance.veryDifferentColors[instance.nextVeryDifferntColorIdx++];

            return instance.stringToColorHash[str];
        }
    }
})();

// Get a new color for each string
StringToColor.next("get first color");
StringToColor.next("get second color");

// Will return the same color as the first time
StringToColor.next("get first color");

Chociaż ma to limit tylko do 64 kolorów, uważam, że większość ludzi i tak nie jest w stanie odróżnić różnicy po tym. Przypuszczam, że zawsze możesz dodać więcej kolorów.

Podczas gdy ten kod używa kolorów zakodowanych na stałe, masz przynajmniej gwarancję, że podczas programowania dokładnie wiesz, jaki dokładnie kontrast zobaczysz między kolorami podczas produkcji.

Lista kolorów została usunięta z tej odpowiedzi SO , istnieją inne listy z większą liczbą kolorów.

Rick Smith
źródło
Fwiw, istnieje algorytm do określania kontrastu. Napisałem coś z nim lata temu (ale w C). Zbyt wiele się dzieje, żeby się tym martwić, a i tak jest to stara odpowiedź, ale doszedłem do wniosku, że istnieje sposób na określenie kontrastu.
Pryftan
7

Otworzyłem żądanie ściągnięcia do Please.js, które umożliwia generowanie koloru z hasha.

Możesz odwzorować ciąg na taki kolor:

const color = Please.make_color({
    from_hash: "any string goes here"
});

Na przykład "any string goes here"zwróci jako "#47291b"
i "another!"zwróci jako"#1f0c3d"

Josue Alexander Ibarra
źródło
Naprawdę fajne dzięki za dodanie tego. Cześć, chcę wygenerować kręgi z literami na podstawie nazwy takiej jak skrzynka odbiorcza Google :)
marcus7777
kiedy zobaczyłem tę odpowiedź, pomyślałem, idealnie, teraz muszę pomyśleć o schemacie kolorów, aby nie generował bardzo przypadkowych kolorów, potem przeczytałem o opcjach make_color z Please.js i wywołało to piękny uśmiech na mojej twarzy.
panchicore
6

Jeśli dane wejściowe nie są wystarczająco różne, aby prosty skrót mógł wykorzystać całe spektrum kolorów, zamiast funkcji skrótu można użyć pierwotnego generatora liczb losowych.

Używam kodera kolorów z odpowiedzi Joe Freemana i generatora liczb losowych Davida Bau .

function stringToColour(str) {
    Math.seedrandom(str);
    var rand = Math.random() * Math.pow(255,3);
    Math.seedrandom(); // don't leave a non-random seed in the generator
    for (var i = 0, colour = "#"; i < 3; colour += ("00" + ((rand >> i++ * 8) & 0xFF).toString(16)).slice(-2));
    return colour;
}
Nathan
źródło
5

Jeszcze jedno rozwiązanie dla losowych kolorów:

function colorize(str) {
    for (var i = 0, hash = 0; i < str.length; hash = str.charCodeAt(i++) + ((hash << 5) - hash));
    color = Math.floor(Math.abs((Math.sin(hash) * 10000) % 1 * 16777216)).toString(16);
    return '#' + Array(6 - color.length + 1).join('0') + color;
}

To mieszanka rzeczy, które działają za mnie. Użyłem funkcji JFreeman Hash (również odpowiedź w tym wątku) i funkcji pseudolosowej Asykäri stąd i trochę dopełnienia i matematyki ode mnie.

Wątpię, aby funkcja dawała równomiernie rozłożone kolory, chociaż ładnie wygląda i robi to, co powinna.

estani
źródło
'0'.repeat(...)nie jest poprawnym javascript
kikito
@kikito w porządku, prawdopodobnie miałem jakoś rozbudowany prototyp (JQuery?). W każdym razie, zredagowałem funkcję, więc jest to tylko javascript ... dzięki za wskazanie tego.
estani
@kikito to poprawna wersja ES6, chociaż używanie jej oznaczałoby zaniedbanie zgodności z różnymi przeglądarkami.
Patrick Roberts,
5

Używając hashCodejak w odpowiedzi Cristiana Sancheza hsli nowoczesnego javascript, możesz stworzyć próbnik kolorów z dobrym kontrastem:

function hashCode(str) {
  let hash = 0;
  for (var i = 0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 5) - hash);
  }
  return hash;
}

function pickColor(str) {
  return `hsl(${hashCode(str) % 360}, 100%, 80%)`;
}

one.style.backgroundColor = pickColor(one.innerText)
two.style.backgroundColor = pickColor(two.innerText)
div {
  padding: 10px;
}
<div id="one">One</div>
<div id="two">Two</div>

Ponieważ jest to HSL, możesz skalować luminancję, aby uzyskać kontrast, którego szukasz.

function hashCode(str) {
  let hash = 0;
  for (var i = 0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 5) - hash);
  }
  return hash;
}

function pickColor(str) {
  // Note the last value here is now 50% instead of 80%
  return `hsl(${hashCode(str) % 360}, 100%, 50%)`;
}

one.style.backgroundColor = pickColor(one.innerText)
two.style.backgroundColor = pickColor(two.innerText)
div {
  color: white;
  padding: 10px;
}
<div id="one">One</div>
<div id="two">Two</div>

Kyle Kelley
źródło
4

Oto rozwiązanie, które wymyśliłem, aby wygenerować estetyczne pastelowe kolory na podstawie ciągu wejściowego. Wykorzystuje pierwsze dwa znaki łańcucha jako losowe ziarno, a następnie generuje R / G / B na podstawie tego ziarna.

Można go łatwo rozszerzyć, tak aby ziarno było XOR wszystkich znaków w ciągu, a nie tylko pierwszych dwóch.

Zainspirowany odpowiedzią Davida Crow'a: Algorytm do losowego generowania estetycznej palety kolorów

//magic to convert strings to a nice pastel colour based on first two chars
//
// every string with the same first two chars will generate the same pastel colour
function pastel_colour(input_str) {

    //TODO: adjust base colour values below based on theme
    var baseRed = 128;
    var baseGreen = 128;
    var baseBlue = 128;

    //lazy seeded random hack to get values from 0 - 256
    //for seed just take bitwise XOR of first two chars
    var seed = input_str.charCodeAt(0) ^ input_str.charCodeAt(1);
    var rand_1 = Math.abs((Math.sin(seed++) * 10000)) % 256;
    var rand_2 = Math.abs((Math.sin(seed++) * 10000)) % 256;
    var rand_3 = Math.abs((Math.sin(seed++) * 10000)) % 256;

    //build colour
    var red = Math.round((rand_1 + baseRed) / 2);
    var green = Math.round((rand_2 + baseGreen) / 2);
    var blue = Math.round((rand_3 + baseBlue) / 2);

    return { red: red, green: green, blue: blue };
}

GIST jest tutaj: https://gist.github.com/ro-sharp/49fd46a071a267d9e5dd

Robert Sharp
źródło
Muszę powiedzieć, że jest to naprawdę dziwny sposób. Niby działa, ale nie ma zbyt wielu dostępnych kolorów. XOR pierwszych dwóch kolorów nie rozróżnia kolejności, więc są tylko kombinacje liter. Prosty dodatek, który dodałem, aby zwiększyć liczbę kolorów, to var seed = 0; for (var i in input_str) {seed ^ = i; }
Gussoh
Tak, to naprawdę zależy od tego, ile kolorów chcesz wygenerować. Pamiętam, że w tym przypadku tworzyłem różne panele w interfejsie użytkownika i chciałem mieć ograniczoną liczbę kolorów, a nie tęczę :)
Robert Sharp
1

Oto kolejna próba:

function stringToColor(str){
  var hash = 0;
  for(var i=0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 3) - hash);
  }
  var color = Math.abs(hash).toString(16).substring(0, 6);

  return "#" + '000000'.substring(0, 6 - color.length) + color;
}
kikito
źródło
1

Wszystko, czego naprawdę potrzebujesz, to dobra funkcja skrótu. W węźle po prostu używam

const crypto = require('crypto');
function strToColor(str) {
    return '#' + crypto.createHash('md5').update(str).digest('hex').substr(0, 6);
}
PulseJet
źródło
0

Konwertuję to na Javę.

Zbiorniki dla wszystkich.

public static int getColorFromText(String text)
    {
        if(text == null || text.length() < 1)
            return Color.BLACK;

        int hash = 0;

        for (int i = 0; i < text.length(); i++)
        {
            hash = text.charAt(i) + ((hash << 5) - hash);
        }

        int c = (hash & 0x00FFFFFF);
        c = c - 16777216;

        return c;
    }
Ali Bagheri
źródło
-1

Ta funkcja załatwia sprawę. To adaptacja tego, dość dłuższego wdrożenia tego repozytorium .

const color = (str) => {
    let rgb = [];
    // Changing non-hexadecimal characters to 0
    str = [...str].map(c => (/[0-9A-Fa-f]/g.test(c)) ? c : 0).join('');
    // Padding string with zeroes until it adds up to 3
    while (str.length % 3) str += '0';

    // Dividing string into 3 equally large arrays
    for (i = 0; i < str.length; i += str.length / 3)
        rgb.push(str.slice(i, i + str.length / 3));

    // Formatting a hex color from the first two letters of each portion
    return `#${rgb.map(string => string.slice(0, 2)).join('')}`;
}
Theódór Ágúst Magnússon
źródło
Generuje to wiele bardzo ciemnych wartości.
Langdon