Создайте шестнадцатеричный цвет на основе строки с помощью JavaScript

147

Я хочу создать функцию, которая будет принимать любую старую строку (обычно это одно слово) и из нее каким- то образом генерировать шестнадцатеричное значение между #000000и #FFFFFF, чтобы я мог использовать его как цвет для элемента HTML.

Может быть, даже сокращенное шестнадцатеричное значение (например:), #FFFесли это менее сложно. Фактически, цвет из палитры, пригодной для использования в Интернете, был бы идеальным.

Дарра Энрайт
источник
2
Не могли бы вы дать образец ввода и / или ссылки на похожие вопросы?
qw3n 06
2
Не ответ, но вы можете найти следующее полезным: Чтобы преобразовать шестнадцатеричное число в целое, используйте parseInt(hexstr, 10). Чтобы преобразовать целое число в шестнадцатеричное, используйте n.toString(16), где n - целое число.
Кристиан Санчес,
@ qw3n - пример ввода: только короткие простые старые текстовые строки ... например, «Медицина», «Хирургия», «Неврология», «Общая практика» и т. д. В диапазоне от 3 до 20 символов ... не могу найти другой, но вот вопрос java: stackoverflow.com/questions/2464745/… @Daniel - Спасибо. Мне нужно сесть и серьезно заняться этим. может быть полезно.
Дарра Энрайт

Ответы:

189

Просто перенесите Java из шестнадцатеричного цветового кода Compute для произвольной строки в 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;
}

Чтобы преобразовать, вам нужно сделать:

intToRGB(hashCode(your_string))
Кристиан Санчес
источник
1
большой! спасибо, это работает хорошо. Я не очень разбираюсь в побитовых операторах и т. Д., Поэтому приветствую вашу помощь в переносе.
Дарра Энрайт
Он должен заполнить шестнадцатеричные строки, например:("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
3
Я конвертирую кучу тегов музыкальных жанров в цвета фона, и это сэкономило мне много времени.
Кайл Пеннелл
Хотел бы я преобразовать это в php.
Nimitz E.
7
У меня есть некоторые проблемы с почти одинаковыми цветами для похожих строк, например: intToRGB(hashCode('hello1')) -> "3A019F" intToRGB(hashCode('hello2')) -> "3A01A0" И я улучшаю ваш код, добавляя умножение для окончательного хеш-значения:return 100 * hash;
SirWojtek
194

Вот адаптация ответа CD Санчеса, которая последовательно возвращает шестизначный цветовой код:

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

Применение:

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

Пример:

http://jsfiddle.net/sUK45/

(Альтернативное / более простое решение может включать возврат цветового кода в стиле rgb (...).)

Джо Фриман
источник
4
Этот код отлично работает в сочетании с автоматически сгенерированными идентификаторами NoSQL, ваш цвет будет каждый раз одинаковым для одного и того же пользователя.
deviavir
Мне также нужен альфа-канал для прозрачности моих шестнадцатеричных кодов. Это помогло (добавление двух цифр для альфа-канала в конце моего шестнадцатеричного кода): gist.github.com/lopspower/03fb1cc0ac9f32ef38f4
Husterknupp
@Tjorriemorrie Проголосовал за то, что указал, что это цвет, а не цвет. Да, да, это не совсем по теме, но для меня это важно (на самом деле, когда я набирал текст изначально, я оба раза писал «цвет»!). Спасибо.
Pryftan
Интересно, что цвет для одной и той же строки отличается в разных браузерах / oss - например, Chrome + Windows и Chrome + Android - моя электронная почта => цвет синий на одном и зеленый на другом. Есть идеи, почему?
avenmore
Благодарность! адаптация к этому для создания пастельных / ярких цветов только из строки stackoverflow.com/a/64490863/403372
Джовиано Диас
49

Мне нужно было такое же богатство цветов для элементов HTML, я был удивлен, обнаружив, что CSS теперь поддерживает цвета hsl (), поэтому полное решение для меня ниже:

Также см. Как автоматически генерировать N «различных» цветов? для большего количества альтернатив, более похожих на это.

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

В HSL это Оттенок, Насыщенность, Легкость. Таким образом, оттенок от 0 до 359 будет иметь все цвета, насыщенность - это то, насколько насыщенным вы хотите цвет, 100% мне подходит. А Lightness определяет глубину, 50% - это нормально, 25% - темные цвета, 75% - пастельные. У меня 30%, потому что это лучше всего подходит для моей цветовой схемы.

Тимин
источник
3
Очень универсальное решение.
MastaBaba
2
Спасибо за то, что поделились решением, где вы можете решить, насколько красочными должны быть цвета!
Флориан Бауэр
@haykam Спасибо, что превратили его в сниппет!
Тимин
Этот подход действительно полезен для придания желаемой яркости / тонкости, необходимой моему приложению. Случайный Hex слишком сильно различается по насыщенности и яркости, чтобы быть полезным в большинстве ситуаций. Спасибо за это!
simey.me
1
Это решение возвращает слишком мало цветов, не годится.
катамфетамин
9

Я считаю, что генерация случайных цветов имеет тенденцию создавать цвета, у которых нет достаточного контраста на мой вкус. Самый простой способ, который я нашел, - это предварительно заполнить список самых разных цветов. Для каждой новой строки назначайте следующий цвет в списке:

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

Хотя у этого есть ограничение только до 64 цветов, я считаю, что большинство людей все равно не заметят разницы после этого. Я полагаю, вы всегда можете добавить больше цветов.

Хотя в этом коде используются жестко запрограммированные цвета, вы, по крайней мере, гарантированно будете знать во время разработки, какой именно контраст вы увидите между цветами при производстве.

Список цветов был взят из этого SO-ответа , есть другие списки с большим количеством цветов.

Рик Смит
источник
Fwiw есть алгоритм для определения контраста. Я что-то писал с ним много лет назад (но на C). Слишком много всего, чтобы беспокоиться об этом, и в любом случае это старый ответ, но я решил, что укажу, что есть способ определить контраст.
Pryftan
Дополнение: чтобы вернуть цвет к первому после использования, замените второй, если на: if(!instance.stringToColorHash[str]) { instance.nextVeryDifferntColorIdx++; instance.nextVeryDifferntColorIdx %= instance.veryDifferentColors.length; instance.stringToColorHash[str] = instance.veryDifferentColors[instance.nextVeryDifferntColorIdx]; }
MoonLite
7

Я открыл запрос на перенос в Please.js, который позволяет генерировать цвет из хеша.

Вы можете сопоставить строку с цветом следующим образом:

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

Например, "any string goes here"вернется как "#47291b"
и "another!"вернется как"#1f0c3d"

Хосуэ Александр Ибарра
источник
Действительно здорово, спасибо, что добавили это. Привет, хочу создавать круги с буквами на основе имени, как это делает почтовый ящик Google :)
marcus7777
когда я увидел этот ответ, я подумал: отлично, теперь я должен подумать о цветовой схеме, чтобы она не генерировала очень случайные цвета, затем я прочитал о параметрах Make_color Please.js, и это вызвало у меня красивую улыбку.
panchicore
6

Если ваши входные данные недостаточно различаются, чтобы простой хеш использовал весь спектр цветов, вы можете использовать генератор случайных чисел с начальным значением вместо хеш-функции.

Я использую цветовой кодер из ответа Джо Фримена и генератор случайных чисел Дэвида Бау .

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

Еще одно решение для случайных цветов:

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

Это смесь вещей, которые делают работу за меня. Я использовал функцию JFreeman Hash (также ответ в этой теме) и псевдослучайную функцию Asykäri отсюда, а также некоторые отступы и математику от себя.

Я сомневаюсь, что функция воспроизводит равномерно распределенные цвета, хотя выглядит красиво и делает то, что должна.

Estani
источник
'0'.repeat(...)недопустимый javascript
kikito
@kikito честно, наверное, я как-то расширил прототип (JQuery?). В любом случае, я отредактировал функцию так, чтобы она была только javascript ... спасибо, что указали на это.
estani
@kikito - это действительный ES6, хотя при его использовании можно пренебречь кроссбраузерностью.
Патрик Робертс,
5

Используя hashCodeответ Кристиана Санчеса hslи современный javascript, вы можете создать средство выбора цвета с хорошим контрастом следующим образом:

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>

Поскольку это hsl, вы можете масштабировать яркость, чтобы получить желаемый контраст.

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

Вот решение, которое я придумал для создания эстетически приятных пастельных тонов на основе входной строки. Он использует первые два символа строки как случайное начальное число, а затем генерирует R / G / B на основе этого начального числа.

Его можно легко расширить так, чтобы семя было XOR всех символов в строке, а не только первых двух.

Вдохновленный ответом Дэвида Кроу здесь: Алгоритм случайного создания эстетически приятной цветовой палитры

//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 здесь: https://gist.github.com/ro-sharp/49fd46a071a267d9e5dd

Роберт Шарп
источник
Я должен сказать, что это действительно странный способ сделать это. Это вроде работает, но доступных цветов не так много. XOR первых двух цветов не делает различий в порядке, поэтому есть только комбинации букв. Простое добавление, которое я сделал для увеличения количества цветов, было var seed = 0; for (var i в input_str) {seed ^ = i; }
Gussoh
Да, это действительно зависит от того, сколько цветов вы хотите создать. Я помню, что в этом случае я создавал разные панели в пользовательском интерфейсе и хотел ограниченное количество цветов, а не радугу :)
Роберт Шарп
1

Вот еще одна попытка:

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

Все, что вам действительно нужно, это хорошая хеш-функция. На узле я просто использую

const crypto = require('crypto');
function strToColor(str) {
    return '#' + crypto.createHash('md5').update(str).digest('hex').substr(0, 6);
}
импульсный
источник
0

Я конвертировал это для Java.

Танки для всех.

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

Эта функция делает свое дело. Это адаптация этой, довольно продолжительной реализации этого репо ..

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('')}`;
}
Теодор Агуст Магнуссон
источник
Это порождает множество очень темных значений.
Лэнгдон,