Cree un color hexadecimal basado en una cadena con JavaScript


141

Quiero crear una función que acepte cualquier cadena de edad (por lo general será una sola palabra) y desde que de alguna manera generar un valor hexadecimal entre #000000y #FFFFFF, para que pueda utilizarlo como un color de un elemento HTML.

Tal vez incluso un valor hexadecimal abreviado (por ejemplo:) #FFFsi eso es menos complicado. De hecho, un color de una paleta 'segura para la web' sería ideal.


2
¿Podría dar alguna entrada de muestra y / o enlaces a preguntas similares?
qw3n

2
No es una respuesta, pero puede encontrar lo siguiente útil: Para convertir un hexadecimal en un entero, use parseInt(hexstr, 10). Para convertir un entero en un hexadecimal, use n.toString(16), donde n es un entero.
Cristian Sanchez

@ qw3n - entrada de muestra: solo cadenas de texto cortas y simples ... como 'Medicina', 'Cirugía', 'Neurología', 'Práctica general', etc. Entre 3 y 20 caracteres ... no se puede encontrar el otro pero aquí está la pregunta de Java: stackoverflow.com/questions/2464745/… @Daniel - Gracias. Necesito sentarme y tener otra oportunidad seria en esto. Podría ser útil.
Darragh Enright

Respuestas:


176

Simplemente portando sobre Java desde Compute hexadecimal código de color para una cadena arbitraria a 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;
}

Para convertir harías:

intToRGB(hashCode(your_string))

1
¡Excelente! gracias, esto funciona bien No sé mucho sobre operadores bit a bit y otras cosas, por lo que agradecemos su ayuda.
Darragh Enright

Necesita rellenar las cadenas hexadecimales, tales como:("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
Estoy convirtiendo un montón de etiquetas de género musical a colores de fondo y esto me ahorró mucho tiempo.
Kyle Pennell

Desearía poder convertir esto a php.
Nimitz E.

66
Tengo algunos problemas con casi los mismos colores para cadenas similares, por ejemplo: intToRGB(hashCode('hello1')) -> "3A019F" intToRGB(hashCode('hello2')) -> "3A01A0" y return 100 * hash;
mejoro

185

Aquí hay una adaptación de la respuesta de CD Sanchez que constantemente devuelve un código de color de 6 dígitos:

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

Ejemplo:

http://jsfiddle.net/sUK45/

(Una solución alternativa / más simple podría implicar devolver un código de color de estilo 'rgb (...)').


3
Este código funciona increíblemente junto con los ID generados automáticamente por NoSQL, su color será el mismo cada vez para el mismo usuario.
deviavir

También necesitaba el canal alfa para la transparencia en mis códigos hexadecimales. Esto ayudó (agregar dos dígitos para el canal alfa al final de mi código hexadecimal): gist.github.com/lopspower/03fb1cc0ac9f32ef38f4
Husterknupp

@Tjorriemorrie Upvoted por señalar que es color y no color. Sí, sí, no es realmente sobre el tema, pero es algo que es importante para mí (de hecho, al escribirlo originalmente, lo deletreé 'color' en ambas ocasiones). Gracias.
Pryftan

Es interesante que el color sea diferente para la misma cadena en diferentes navegadores / oss, por ejemplo, Chrome + Windows y Chrome + Android: mi correo electrónico => el color es azul en uno y verde en el otro. ¿Alguna idea de por qué?
avenmore

43

Quería una riqueza de colores similar para los elementos HTML, me sorprendió descubrir que CSS ahora admite colores hsl (), por lo que a continuación se muestra una solución completa para mí:

Consulte también ¿Cómo generar automáticamente N colores "distintos"? para más alternativas más similares a esto.

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 su tono, saturación, ligereza. Entonces, el tono entre 0-359 obtendrá todos los colores, la saturación es cuán rico quieres el color, 100% funciona para mí. Y la claridad determina la profundidad, el 50% es normal, el 25% son colores oscuros, el 75% es pastel. Tengo 30% porque encaja mejor con mi esquema de color.


3
Una solución muy versátil.
MastaBaba

2
Gracias por compartir una solución, donde puedes decidir qué tan coloridos deben ser los colores.
Florian Bauer

@haykam ¡Gracias por convertirlo en un fragmento!
Thymine

Este enfoque es realmente útil para dar la vitalidad / sutileza deseada que necesitaba mi aplicación. Un Hex aleatorio varía demasiado en saturación y brillo para ser útil en la mayoría de las situaciones. ¡Gracias por esto!
simey.me

Esta solución devuelve muy pocos colores, no funcionará.
Catamphetamine

9

Encuentro que generar colores aleatorios tiende a crear colores que no tienen suficiente contraste para mi gusto. La forma más fácil que he encontrado de evitarlo es rellenar previamente una lista de colores muy diferentes. Para cada nueva cadena, asigne el siguiente color en la lista:

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

Si bien esto tiene un límite de solo 64 colores, creo que la mayoría de los humanos realmente no pueden notar la diferencia después de eso de todos modos. Supongo que siempre puedes agregar más colores.

Si bien este código usa colores codificados, al menos se garantiza que sabrá durante el desarrollo exactamente cuánto contraste verá entre los colores en la producción.

La lista de colores se ha eliminado de esta respuesta SO , hay otras listas con más colores.


Ahora hay un algoritmo para determinar el contraste. Escribí algo con eso hace años (pero en C). Demasiado para preocuparse por eso y de todos modos es una respuesta antigua, pero pensé que señalaría que hay una manera de determinar el contraste.
Pryftan

7

He abierto una solicitud de extracción a Please.js que permite generar un color a partir de un hash.

Puede asignar la cadena a un color así:

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

Por ejemplo, "any string goes here"devolverá como "#47291b"
y "another!"devuelve como"#1f0c3d"


Realmente genial gracias por agregar eso. Hola, quiero generar círculos con letras basadas en un nombre como lo hace la bandeja de entrada de Google :)
marcus7777

Cuando vi esta respuesta, pensé, perfecto, ahora tengo que pensar en el esquema de color para que no genere colores muy aleatorios, luego leí sobre las opciones de Make.color de Please.js y me puso una hermosa sonrisa en la cara.
panchicore

6

Si sus entradas no son lo suficientemente diferentes para que un hash simple use el espectro de color completo, puede usar un generador de números aleatorios en lugar de una función hash.

Estoy usando el codificador de color de la respuesta de Joe Freeman y el generador de números aleatorios sembrados 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;
}

5

Otra solución más para colores aleatorios:

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

Es una mezcla de cosas que hace el trabajo por mí. Usé la función JFreeman Hash (también una respuesta en este hilo) y la función pseudoaleatoria Asykäri de aquí y algo de relleno y matemáticas de mí mismo.

Dudo que la función produzca colores distribuidos uniformemente, aunque se ve bien y hace lo que debería hacer.


'0'.repeat(...)no es válido javascript
kikito

@kikito bastante justo, probablemente tuve el prototipo extendido de alguna manera (JQuery?). De todos modos, he editado la función para que sea solo JavaScript ... gracias por señalarlo.
estani

@kikito es ES6 válido, aunque usarlo sería descuidar la compatibilidad entre navegadores.
Patrick Roberts

5

Usando hashCodecomo en la respuesta de Cristian Sanchez con hsljavascript moderno, puede crear un selector de color con un buen contraste como este:

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>

Como es hsl, puede escalar la luminancia para obtener el contraste que está buscando.

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

Aquí hay una solución que se me ocurrió para generar colores pastel estéticamente agradables basados ​​en una cadena de entrada. Utiliza los dos primeros caracteres de la cadena como una semilla aleatoria, luego genera R / G / B basado en esa semilla.

Se podría extender fácilmente para que la semilla sea el XOR de todos los caracteres en la cadena, en lugar de solo los dos primeros.

Inspirado por la respuesta de David Crow aquí: Algoritmo para generar aleatoriamente una paleta de colores estéticamente agradable

//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á aquí: https://gist.github.com/ro-sharp/49fd46a071a267d9e5dd


Debo decir que esta es una forma realmente extraña de hacerlo. Funciona un poco, pero no hay muchos colores disponibles. XOR de los dos primeros colores no hace distinción de orden, por lo que solo hay combinaciones de letras. Una simple adición que hice para aumentar el número de colores fue var seed = 0; para (var i en input_str) {seed ^ = i; }
Gussoh

Sí, realmente depende de cuántos colores le gustaría generar. Recuerdo que en este caso estaba creando diferentes paneles en una interfaz de usuario y quería un número limitado de colores en lugar de un arco iris :)
Robert Sharp

1

Aquí hay otro intento:

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

Todo lo que realmente necesita es una buena función hash. En el nodo, solo uso

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

0

Convierto esto para Java.

Tanques para todos.

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

Esta función hace el truco. Es una adaptación de esto, implementación bastante más larga este repositorio .

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

Esto genera muchos valores muy oscuros.
Langdon
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.