Créer une couleur hexadécimale basée sur une chaîne avec JavaScript

141

Je veux créer une fonction qui accepte une ancienne chaîne (habituellement un seul mot) et de cette certaine façon de générer une valeur hexadécimale entre #000000et #FFFFFF, donc je peux l' utiliser comme une couleur pour un élément HTML.

Peut-être même une valeur hexadécimale abrégée (par exemple:) #FFFsi c'est moins compliqué. En fait, une couleur issue d'une palette «Web sécurisée» serait idéale.

Darragh Enright
la source
2
Pouvez-vous donner des exemples de commentaires et / ou des liens vers des questions similaires?
qw3n
2
Ce n'est pas une réponse, mais vous trouverez peut-être ce qui suit utile: Pour convertir un hexadécimal en entier, utilisez parseInt(hexstr, 10). Pour convertir un entier en hexadécimal, utilisez n.toString(16), où n est un entier.
Cristian Sanchez
@ qw3n - exemple d'entrée: juste des chaînes de texte brèves et simples ... comme «Médecine», «Chirurgie», «Neurologie», «Médecine générale», etc. Entre 3 et disons, 20 caractères ... impossible de trouver l'autre, mais voici la question java: stackoverflow.com/questions/2464745/… @Daniel - Merci. Je dois m'asseoir et avoir une autre tentative sérieuse à ce sujet. pourrait être utile.
Darragh Enright

Réponses:

176

Portage simplement sur Java du code de couleur hexadécimal Compute pour une chaîne arbitraire vers 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;
}

Pour convertir, vous feriez:

intToRGB(hashCode(your_string))
Cristian Sanchez
la source
1
génial! merci, cela fonctionne bien. Je ne sais pas grand-chose sur les opérateurs bit à bit et tout ça, donc votre aide pour le porter est appréciée.
Darragh Enright
Il doit remplir les chaînes hexadécimales, telles que:("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
Je convertis un tas d'étiquettes de genre musical en couleurs d'arrière-plan et cela m'a fait gagner beaucoup de temps.
Kyle Pennell
J'aimerais pouvoir le convertir en php.
Nimitz E.
6
J'ai quelques problèmes avec presque les mêmes couleurs pour des chaînes similaires, par exemple: intToRGB(hashCode('hello1')) -> "3A019F" intToRGB(hashCode('hello2')) -> "3A01A0" Et j'améliore votre code en ajoutant une multiplication pour la valeur de hachage finale:return 100 * hash;
SirWojtek
185

Voici une adaptation de la réponse de CD Sanchez qui renvoie systématiquement un code couleur à 6 chiffres:

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

Usage:

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

Exemple:

http://jsfiddle.net/sUK45/

(Une solution alternative / plus simple pourrait impliquer de renvoyer un code couleur de style 'rgb (...)'.)

Joe Freeman
la source
3
Ce code fonctionne très bien en conjonction avec les ID générés automatiquement par NoSQL, votre couleur sera la même à chaque fois pour le même utilisateur.
deviavir
J'avais également besoin du canal alpha pour la transparence de mes codes hexadécimaux. Cela a aidé (ajouter deux chiffres pour le canal alpha à la fin de mon code hexadécimal): gist.github.com/lopspower/03fb1cc0ac9f32ef38f4
Husterknupp
@Tjorriemorrie a voté pour avoir souligné que c'est la couleur et non la couleur. Oui, oui, ce n'est pas vraiment sur le sujet mais c'est quelque chose qui est important pour moi (en fait en le tapant à l'origine, je l'ai épelé «couleur» les deux fois!). Je vous remercie.
Pryftan
Intéressant que la couleur soit différente pour la même chaîne sur différents navigateurs / oss - par exemple Chrome + Windows et Chrome + Android - mon e-mail => la couleur est bleue sur l'un et verte sur l'autre. Une idée pourquoi?
avenmore
43

Je voulais une richesse de couleurs similaire pour les éléments HTML, j'ai été surpris de constater que CSS prend désormais en charge les couleurs hsl (), donc une solution complète pour moi est ci-dessous:

Voir aussi Comment générer automatiquement N couleurs "distinctes"? pour plus d'alternatives plus similaires à celle-ci.

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

En HSL sa teinte, sa saturation, sa légèreté. Ainsi, la teinte entre 0 et 359 obtiendra toutes les couleurs, la saturation est la richesse que vous voulez de la couleur, 100% fonctionne pour moi. Et la clarté détermine la profondeur, 50% est normal, 25% est des couleurs sombres, 75% est pastel. J'en ai 30% car il correspond le mieux à ma palette de couleurs.

Thymine
la source
3
Une solution très polyvalente.
MastaBaba
2
Merci de partager une solution, où vous pouvez décider de la couleur des couleurs!
Florian Bauer
@haykam Merci d'en avoir fait un extrait!
Thymine
Cette approche est vraiment utile pour donner la vibrance / subtilité souhaitée dont mon application avait besoin. Un hexagone aléatoire varie beaucoup trop en saturation et en luminosité pour être utile dans la plupart des situations. Merci pour cela!
simey.me
Cette solution renvoie trop peu de couleurs, ne fera pas l'affaire.
catamphétamine
9

Je trouve que générer des couleurs aléatoires a tendance à créer des couleurs qui n'ont pas assez de contraste à mon goût. Le moyen le plus simple que j'ai trouvé pour contourner ce problème est de pré-remplir une liste de couleurs très différentes. Pour chaque nouvelle chaîne, attribuez la couleur suivante dans la liste:

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

Bien que cela ait une limite à seulement 64 couleurs, je trouve que la plupart des humains ne peuvent pas vraiment faire la différence après cela de toute façon. Je suppose que vous pouvez toujours ajouter plus de couleurs.

Bien que ce code utilise des couleurs codées en dur, vous avez au moins la garantie de savoir pendant le développement exactement le contraste que vous verrez entre les couleurs en production.

La liste des couleurs a été retirée de cette réponse SO , il existe d'autres listes avec plus de couleurs.

Rick Smith
la source
Fwiw, il existe un algorithme pour déterminer le contraste. J'ai écrit quelque chose avec il y a des années (mais en C). Trop de soucis à ce sujet et c'est une vieille réponse de toute façon, mais je pensais qu'il y avait un moyen de déterminer le contraste.
Pryftan
7

J'ai ouvert une pull request vers Please.js qui permet de générer une couleur à partir d'un hachage.

Vous pouvez mapper la chaîne à une couleur comme ceci:

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

Par exemple, "any string goes here"retournera comme "#47291b"
et "another!"retourne comme"#1f0c3d"

Josue Alexander Ibarra
la source
Vraiment cool merci pour l'ajout. Bonjour,
je veux
quand j'ai vu cette réponse, j'ai pensé, parfait, maintenant je dois penser au schéma de couleur pour qu'il ne génère pas de couleurs très aléatoires, puis j'ai lu les options make_color de Please.js et cela m'a mis un beau sourire sur mon visage.
panchicore
6

Si vos entrées ne sont pas suffisamment différentes pour qu'un simple hachage utilise tout le spectre de couleurs, vous pouvez utiliser un générateur de nombres aléatoires prédéfini au lieu d'une fonction de hachage.

J'utilise le code couleur de la réponse de Joe Freeman et le générateur de nombres aléatoires prédéfini de 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;
}
Nathan
la source
5

Encore une autre solution pour les couleurs aléatoires:

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

C'est un mélange de choses qui fait le travail pour moi. J'ai utilisé la fonction JFreeman Hash (également une réponse dans ce fil) et la fonction pseudo aléatoire Asykäri d' ici et un peu de remplissage et de mathématiques de moi-même.

Je doute que la fonction produise des couleurs uniformément réparties, même si elle a l'air bien et fait ce qu'elle devrait faire.

estani
la source
'0'.repeat(...)n'est pas valide javascript
kikito
@kikito assez juste, j'ai probablement étendu le prototype (JQuery?). Quoi qu'il en soit, j'ai édité la fonction donc c'est du javascript seulement ... merci de l'avoir signalé.
estani
@kikito, c'est ES6 valide, mais l'utiliser reviendrait à négliger la compatibilité entre navigateurs.
Patrick Roberts
5

En utilisant la hashCoderéponse de Cristian Sanchez avec hslun javascript moderne, vous pouvez créer un sélecteur de couleurs avec un bon contraste comme celui-ci:

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>

Comme il s'agit de hsl, vous pouvez mettre à l'échelle la luminance pour obtenir le contraste que vous recherchez.

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
la source
4

Voici une solution que j'ai trouvée pour générer des couleurs pastel esthétiquement agréables à partir d'une chaîne d'entrée. Il utilise les deux premiers caractères de la chaîne comme une graine aléatoire, puis génère R / V / B en fonction de cette graine.

Il pourrait être facilement étendu pour que la graine soit le XOR de tous les caractères de la chaîne, plutôt que seulement les deux premiers.

Inspiré par la réponse de David Crow ici: Algorithme pour générer de manière aléatoire une palette de couleurs esthétiquement agréable

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

Robert Sharp
la source
Je dois dire que c'est une façon vraiment étrange de le faire. Cela fonctionne mais il n'y a pas beaucoup de couleurs disponibles. XOR des deux premières couleurs ne fait aucune distinction d'ordre, il n'y a donc que des combinaisons de lettres. Un simple ajout que j'ai fait pour augmenter le nombre de couleurs était var seed = 0; for (var i dans input_str) {seed ^ = i; }
Gussoh
Oui, cela dépend vraiment du nombre de couleurs que vous souhaitez générer. Je me souviens que dans cet exemple, je créais différents volets dans une interface utilisateur et je voulais un nombre limité de couleurs plutôt qu'un arc-en-ciel :)
Robert Sharp
1

Voici un autre essai:

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
la source
1

Tout ce dont vous avez vraiment besoin est une bonne fonction de hachage. Sur le nœud, j'utilise juste

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

Je convertis ceci pour Java.

Des chars pour tous.

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
la source
-1

Cette fonction fait l'affaire. C'est une adaptation de cette implémentation assez longue de ce dépôt .

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
la source
Cela génère beaucoup de valeurs très sombres.
Langdon le