使用JavaScript创建基于字符串的十六进制颜色

Create a hexadecimal colour based on a string with JavaScript

我想创建一个接受任何旧字符串(通常是一个单词)的函数,并从中以某种方式在#000000#FFFFFF之间生成十六进制值,因此我可以将其用作HTML元素的颜色。

如果不那么复杂,甚至可能是一个简短的十六进制值(例如:#FFF)。事实上,"网络安全"调色板的颜色是理想的。


以下是CD Sanchez的答案的改编版本,它始终返回6位颜色代码:

1
2
3
4
5
6
7
8
9
10
11
12
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;
}

用途:

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

例子:

http://jsfiddle.net/suk45/

(另一种/更简单的解决方案可能涉及返回"rgb(…)"样式的颜色代码。)


只需将Java从计算HEX颜色代码移植到任意字符串到JavaScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}

要转换,请执行以下操作:

1
intToRGB(hashCode(your_string))


我希望HTML元素的颜色具有类似的丰富性,我很惊讶地发现CSS现在支持hsl()颜色,因此我的完整解决方案如下:

另请参阅如何自动生成n种"不同"颜色?更多类似的替代品。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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/>");

1
2
3
4
span {
  font-size: 50px;
  font-weight: 800;
}

它的色调,饱和度,亮度。所以0-359之间的色调会得到所有的颜色,饱和度是你想要的颜色有多丰富,100%适合我。亮度决定深度,50%为正常,25%为深色,75%为柔和。我有30%,因为它最适合我的配色方案。


我发现生成随机颜色往往会产生没有足够对比度适合我口味的颜色。我找到的最简单的方法就是预先填充一个非常不同颜色的列表。对于每个新字符串,指定列表中的下一个颜色:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 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种颜色的限制,但我发现大多数人无论如何都不能分辨出颜色的不同。我想你总可以多加些颜色。

虽然这段代码使用硬编码的颜色,但至少可以保证您在开发过程中确切知道在生产中颜色之间的对比度。

颜色列表已从此处提升,因此答案是,还有其他具有更多颜色的列表。


我打开了一个pull请求please.js,它允许从哈希生成颜色。

您可以将字符串映射为这样的颜色:

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

例如,"any string goes here"将作为"#47291b"返回。和"another!"回报为"#1f0c3d"


如果您的输入不足以让一个简单的哈希使用整个色谱,那么您可以使用种子随机数生成器而不是哈希函数。

我使用的是JoeFreeman的答案中的颜色编码器,以及DavidBau的种子随机数生成器。

1
2
3
4
5
6
7
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;
}


这是我提出的一个解决方案,基于输入字符串生成美观的柔和颜色。它使用字符串的前两个字符作为随机种子,然后基于该种子生成r/g/b。

它可以很容易地扩展,以便种子是字符串中所有字符的XOR,而不仅仅是前两个字符。

灵感来源于大卫·克劳的回答:随机生成一个美观的调色板的算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//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/49fd46a07a26d9e5dd


另一种随机颜色的解决方案是:

1
2
3
4
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散列函数(也是这个线程中的一个答案)和asyk?这里的伪随机函数和我自己的一些填充和数学。

我怀疑函数是否能产生均匀分布的颜色,尽管它看起来很好,而且它应该做什么。


使用hashCode和cristian sanchez对hsl和modern javascript的回答,您可以创建一个具有良好对比度的颜色选择器,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)

1
2
3
div {
  padding: 10px;
}

1
2
One
Two

因为它是HSL,所以你可以缩放亮度以获得你想要的对比度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)

1
2
3
4
div {
  color: white;
  padding: 10px;
}

1
2
One
Two


下面是另一个尝试:

1
2
3
4
5
6
7
8
9
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;
}


我将此转换为Java。

所有人的坦克。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
2
3
4
5
6
7
8
9
10
11
12
13
14
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('')}`;
}