Crea un colore esadecimale basato su una stringa con JavaScript


141

Voglio creare una funzione che accetti qualsiasi vecchia stringa (di solito sarà una singola parola) e da quella in qualche modo generare un valore esadecimale tra #000000e #FFFFFF, quindi posso usarlo come colore per un elemento HTML.

Forse anche un valore esadecimale abbreviato (ad esempio:) #FFFse è meno complicato. In effetti, un colore da una tavolozza "sicura per il web" sarebbe l'ideale.


2
Potresti dare alcuni esempi di input e / o collegamenti a domande simili?
qw3n,

2
Non è una risposta, ma potresti trovare utile quanto segue: Per convertire un esadecimale in un numero intero, usa parseInt(hexstr, 10). Per convertire un numero intero in esadecimale, utilizzare n.toString(16), dove n è un numero intero.
Cristian Sanchez,

@ qw3n - input di esempio: stringhe di testo semplici e brevi ... come "Medicina", "Chirurgia", "Neurologia", "Medicina generale" ecc. Intervallo tra 3 e dire, 20 caratteri ... impossibile trovare l'altra, ma ecco la domanda java: stackoverflow.com/questions/2464745/... @ Daniel - Grazie. Devo sedermi e fare un'altra cosa seria. potrebbe essere utile.
Darragh Enright,

Risposte:


176

Basta eseguire il porting su Java dal codice colore esadecimale di calcolo per una stringa arbitraria su 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;
}

Per convertire dovresti fare:

intToRGB(hashCode(your_string))

1
grande! grazie, funziona bene. Non so molto sugli operatori bit a bit e roba del genere quindi il tuo aiuto per portarlo è apprezzato.
Darragh Enright,

Deve riempire le stringhe esadecimali, come ad esempio:("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
Sto convertendo un sacco di tag di genere musicale in colori di sfondo e questo mi ha fatto risparmiare un sacco di tempo.
Kyle Pennell,

Vorrei poterlo convertire in php.
Nimitz E.

6
Ho alcuni problemi con quasi gli stessi colori per stringhe simili, ad esempio: intToRGB(hashCode('hello1')) -> "3A019F" intToRGB(hashCode('hello2')) -> "3A01A0" E ottimizzo il tuo codice aggiungendo la moltiplicazione per il valore di hash finale:return 100 * hash;
SirWojtek

185

Ecco un adattamento della risposta di CD Sanchez che restituisce costantemente un codice colore a 6 cifre:

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;
}

Uso:

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

Esempio:

http://jsfiddle.net/sUK45/

(Una soluzione alternativa / più semplice potrebbe comportare la restituzione di un codice colore in stile 'rgb (...)'.)


3
Questo codice funziona alla grande insieme agli ID generati automaticamente NoSQL, il tuo colore sarà lo stesso ogni volta per lo stesso utente.
deviavir,

Avevo bisogno del canale alfa per la trasparenza anche nei miei codici esadecimali. Questo mi ha aiutato (aggiungendo due cifre per il canale alfa alla fine del mio codice esadecimale): gist.github.com/lopspower/03fb1cc0ac9f32ef38f4
Husterknupp,

@Tjorriemorrie È stato votato per sottolineare che è colore e non colore. Sì, sì, non è proprio in tema, ma è qualcosa che è importante per me (infatti durante la digitazione in origine l'ho scritto "colore" entrambe le volte!). Grazie.
Pryftan,

È interessante notare che il colore è diverso per la stessa stringa su browser / oss diversi - ad es. Chrome + Windows e Chrome + Android - la mia e-mail => il colore è blu su uno e verde sull'altro. Qualche idea sul perché?
avenmore,

43

Volevo una simile ricchezza di colori per gli elementi HTML, sono stato sorpreso di scoprire che CSS ora supporta i colori hsl (), quindi una soluzione completa per me è di seguito:

Vedi anche Come generare automaticamente N colori "distinti"? per più alternative più simili a questo.

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;
}

In HSL la sua tonalità, saturazione, leggerezza. Quindi la tonalità tra 0-359 otterrà tutti i colori, la saturazione è quanto vuoi il colore, il 100% funziona per me. E la leggerezza determina la profondità, il 50% è normale, il 25% è colori scuri, il 75% è pastello. Ho il 30% perché si adatta meglio alla mia combinazione di colori.


3
Una soluzione molto versatile.
MastaBaba,

2
Grazie per aver condiviso una soluzione, dove puoi decidere quanto devono essere colorati i colori!
Florian Bauer,

@haykam Grazie per averlo reso uno snippet!
Thymine,

Questo approccio è davvero utile per fornire la vibrazione / sottigliezza desiderata di cui la mia app aveva bisogno. Un esagono casuale varia troppo in saturazione e luminosità per essere utile nella maggior parte delle situazioni. Grazie per questo!
simey.me

Questa soluzione restituisce colori troppo piccoli, non lo farà.
catamphetamine,

9

Trovo che la generazione di colori casuali tende a creare colori che non hanno abbastanza contrasto per i miei gusti. Il modo più semplice che ho trovato per aggirare è quello di precompilare un elenco di colori molto diversi. Per ogni nuova stringa, assegnare il colore successivo nell'elenco:

// 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");

Anche se questo ha un limite di soli 64 colori, trovo che la maggior parte degli umani non riesca a distinguere comunque dopo. Suppongo che potresti sempre aggiungere più colori.

Sebbene questo codice utilizzi colori hardcoded, durante lo sviluppo si garantisce almeno quanto esattamente si vedrà il contrasto tra i colori nella produzione.

La lista dei colori è stata sollevata da questa risposta SO , ci sono altre liste con più colori.


In seguito c'è un algoritmo là fuori per determinare il contrasto. Ho scritto qualcosa con esso anni fa (ma in C). Ci si preoccupa troppo ed è comunque una vecchia risposta, ma ho pensato che avrei sottolineato che esiste un modo per determinare il contrasto.
Pryftan,

7

Ho aperto una richiesta pull su Please.js che consente di generare un colore da un hash.

Puoi associare la stringa a un colore in questo modo:

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

Ad esempio, "any string goes here"restituirà come "#47291b"
e "another!"restituirà come"#1f0c3d"


Davvero fantastico grazie per averlo aggiunto. Ciao, voglio generare cerchie con lettere basate su un nome come fa la casella di posta in arrivo di Google :)
marcus7777,

quando ho visto questa risposta, ho pensato, perfetto, ora devo pensare allo schema dei colori in modo che non generi colori molto casuali, quindi ho letto le opzioni make_color di Please.js e mi ha messo un bel sorriso in faccia.
Panchicore,

6

Se i tuoi input non sono abbastanza diversi da consentire a un hash semplice di utilizzare l'intero spettro dei colori, puoi utilizzare un generatore di numeri casuali con seeding anziché una funzione di hash.

Sto usando il codice colore dalla risposta di Joe Freeman e il generatore di numeri casuali seminato di David 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;
}

5

Ancora un'altra soluzione per colori casuali:

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;
}

È un misto di cose che fa il lavoro per me. Ho usato la funzione Hash di JFreeman (anche una risposta in questo thread) e la funzione pseudo casuale di Asykäri da qui e qualche imbottitura e matematica da me stesso.

Dubito che la funzione produca colori uniformemente distribuiti, anche se sembra carina e fa quello che dovrebbe fare.


'0'.repeat(...)non è valido JavaScript
kikito

@kikito abbastanza giusto, probabilmente ho avuto il prototipo esteso in qualche modo (JQuery?). Ad ogni modo, ho modificato la funzione in modo che sia solo javascript ... grazie per averlo sottolineato.
estani,

@kikito è valido ES6, sebbene utilizzarlo significherebbe trascurare la compatibilità tra browser.
Patrick Roberts,

5

Usando il hashCodecome nella risposta di Cristian Sanchez con hsle javascript moderno, puoi creare un selettore di colori con un buon contrasto come questo:

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>

Dato che è hsl, puoi ridimensionare la luminanza per ottenere il contrasto che stai cercando.

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>


4

Ecco una soluzione che ho trovato per generare colori pastello esteticamente gradevoli basati su una stringa di input. Utilizza i primi due caratteri della stringa come seme casuale, quindi genera R / G / B in base a quel seme.

Potrebbe essere facilmente esteso in modo che il seme sia lo XOR di tutti i caratteri nella stringa, piuttosto che solo i primi due.

Ispirato dalla risposta di David Crow qui: Algoritmo per generare casualmente una tavolozza di colori esteticamente gradevole

//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 è qui: https://gist.github.com/ro-sharp/49fd46a071a267d9e5dd


Devo dire che questo è un modo davvero strano di farlo. Funziona in qualche modo ma non ci sono molti colori disponibili. XOR dei primi due colori non fa alcuna distinzione di ordine, quindi ci sono solo combinazioni di lettere. Una semplice aggiunta che ho fatto per aumentare il numero di colori è stata var seed = 0; per (var i in input_str) {seed ^ = i; }
Gussoh,

Sì, dipende davvero da quanti colori desideri generare. Ricordo in questo caso che stavo creando diversi riquadri in un'interfaccia utente e volevo un numero limitato di colori anziché un arcobaleno :)
Robert Sharp

1

Ecco un altro tentativo:

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;
}

1

Tutto ciò di cui hai veramente bisogno è una buona funzione hash. Sul nodo, ho appena usato

const crypto = require('crypto');
function strToColor(str) {
    return '#' + crypto.createHash('md5').update(str).digest('hex').substr(0, 6);
}

0

Lo converto per Java.

Carri armati per tutti.

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;
    }

-1

Questa funzione fa il trucco. È un adattamento di questo, implementazione abbastanza più lunga di questo repository .

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('')}`;
}

Questo genera molti valori molto scuri.
Langdon
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.