Buat warna heksadesimal berdasarkan string dengan JavaScript

141

Saya ingin membuat fungsi yang akan menerima string lama (biasanya akan menjadi satu kata) dan dari yang entah bagaimana menghasilkan nilai heksadesimal antara #000000dan #FFFFFF, jadi saya bisa menggunakannya sebagai warna untuk elemen HTML.

Mungkin bahkan nilai hex steno (misalnya:) #FFFjika itu kurang rumit. Bahkan, warna dari palet 'web-safe' akan ideal.

Darragh Enright
sumber
2
Bisakah memberikan beberapa input sampel dan / atau tautan ke pertanyaan serupa?
qw3n
2
Bukan jawaban, tetapi Anda mungkin menemukan yang berikut berguna: Untuk mengonversi heksadesimal menjadi bilangan bulat, gunakan parseInt(hexstr, 10). Untuk mengonversi bilangan bulat menjadi heksadesimal, gunakan n.toString(16), di mana n adalah bilangan bulat.
Cristian Sanchez
@ qw3n - input sampel: hanya string teks pendek dan sederhana ... seperti 'Obat', 'Bedah', 'Neurologi', 'Praktik Umum', dll. Mulai antara 3 dan katakanlah, 20 karakter ... tidak dapat menemukan yang lain tapi inilah pertanyaan java: stackoverflow.com/questions/2464745/... @aniel - Terima kasih. Saya perlu duduk dan serius lagi dalam hal ini. bisa bermanfaat.
Darragh Enright

Jawaban:

176

Cukup porting di atas Java dari Compute hex color code untuk string arbitrer ke 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;
}

Untuk mengkonversi Anda akan lakukan:

intToRGB(hashCode(your_string))
Cristian Sanchez
sumber
1
Bagus! terima kasih, ini bekerja dengan baik. Saya tidak tahu banyak tentang operator bitwise dan hal-hal lain sehingga bantuan Anda untuk memindahkannya sangat dihargai.
Darragh Enright
Perlu mengisi string hex, seperti:("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
Saya mengonversi banyak tag genre musik ke warna latar belakang dan ini menghemat banyak waktu saya.
Kyle Pennell
Saya berharap saya bisa mengonversikan ini ke php.
Nimitz E.
6
Saya memiliki beberapa masalah dengan warna yang hampir sama untuk string yang sama, misalnya: intToRGB(hashCode('hello1')) -> "3A019F" intToRGB(hashCode('hello2')) -> "3A01A0" Dan saya meningkatkan kode Anda dengan menambahkan perkalian untuk nilai hash akhir:return 100 * hash;
SirWojtek
185

Berikut ini adalah adaptasi dari jawaban CD Sanchez yang secara konsisten mengembalikan kode warna 6 digit:

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

Pemakaian:

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

Contoh:

http://jsfiddle.net/sUK45/

(Solusi alternatif / sederhana mungkin melibatkan pengembalian kode warna gaya 'rgb (...)'.)

Joe Freeman
sumber
3
Kode ini berfungsi luar biasa bersama dengan ID yang dihasilkan secara otomatis NoSQL, warna Anda akan sama setiap kali untuk pengguna yang sama.
deviavir
Saya membutuhkan saluran alfa untuk transparansi dalam kode hex saya juga. Ini membantu (menambahkan dua digit untuk saluran alfa di akhir kode hex saya): gist.github.com/lopspower/03fb1cc0ac9f32ef38f4
Husterknupp
@Tjorriemorrie Upvoted untuk menunjukkan bahwa itu warna dan bukan warna. Ya, ya, itu tidak benar-benar pada topik tetapi itu adalah sesuatu yang penting bagi saya (bahkan ketika mengetiknya awalnya saya mengeja 'warna' di kedua kali!). Terima kasih.
Pryftan
Menarik bahwa warnanya berbeda untuk string yang sama pada browser / oss yang berbeda - mis. Chrome + Windows dan Chrome + Android - email saya => warnanya biru di satu dan hijau di yang lain. Ada yang tahu kenapa?
lanjut
43

Saya ingin kekayaan warna yang serupa untuk elemen HTML, saya terkejut menemukan bahwa CSS sekarang mendukung warna hsl (), jadi solusi lengkap untuk saya adalah di bawah ini:

Lihat juga Cara membuat warna N "berbeda" secara otomatis? untuk lebih banyak alternatif lebih mirip dengan ini.

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

Dalam HSL, Hue, Saturation, Lightness. Jadi rona antara 0-359 akan mendapatkan semua warna, saturasi adalah seberapa kaya warna yang Anda inginkan, 100% bekerja untuk saya. Dan Lightness menentukan kedalaman, 50% normal, 25% warna gelap, 75% pastel. Saya memiliki 30% karena paling sesuai dengan skema warna saya.

Timin
sumber
3
Solusi yang sangat serbaguna.
MastaBaba
2
Terima kasih untuk berbagi solusi, di mana Anda dapat memutuskan bagaimana warna-warni warna seharusnya!
Florian Bauer
@haykam Terima kasih telah membuatnya menjadi cuplikan!
Thymine
Pendekatan ini sangat berguna untuk memberikan getaran / kehalusan yang diinginkan aplikasi saya. Hex acak sangat bervariasi dalam saturasi dan kecerahannya sehingga tidak berguna untuk sebagian besar situasi. Terima kasih untuk ini!
simey.me
Solusi ini mengembalikan terlalu sedikit warna, tidak akan berhasil.
catamphetamine
9

Saya menemukan bahwa menghasilkan warna acak cenderung membuat warna yang tidak memiliki kontras yang cukup untuk seleraku. Cara termudah yang saya temukan untuk menyiasatinya adalah dengan mempopulasikan daftar warna yang sangat berbeda. Untuk setiap string baru , tetapkan warna berikutnya dalam daftar:

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

Meskipun ini memiliki batas hanya 64 warna, saya menemukan kebanyakan manusia tidak bisa membedakannya setelah itu. Saya kira Anda selalu bisa menambahkan lebih banyak warna.

Walaupun kode ini menggunakan warna-warna yang dikodekan, Anda setidaknya dijamin mengetahui selama pengembangan dengan tepat seberapa besar kontras yang akan Anda lihat di antara warna-warna yang diproduksi.

Daftar warna telah diangkat dari jawaban SO ini , ada daftar lain dengan lebih banyak warna.

Rick Smith
sumber
Namun ada algoritma di luar sana untuk menentukan kontras. Saya menulis sesuatu dengannya bertahun-tahun yang lalu (tetapi dalam C). Terlalu banyak yang perlu dikhawatirkan dan ini merupakan jawaban lama, tetapi saya pikir saya akan menunjukkan bahwa ada cara untuk menentukan kontras.
Pryftan
7

Saya telah membuka permintaan tarik ke Please.js yang memungkinkan menghasilkan warna dari hash.

Anda dapat memetakan string ke warna seperti ini:

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

Misalnya, "any string goes here"akan kembali sebagai "#47291b"
dan "another!"mengembalikan sebagai"#1f0c3d"

Josue Alexander Ibarra
sumber
Sangat keren terima kasih telah menambahkan itu. Hai, ingin membuat lingkaran dengan huruf-huruf berdasarkan nama seperti Google inbox :)
marcus7777
ketika saya melihat jawaban ini, saya pikir, sempurna, sekarang saya harus berpikir tentang skema warna sehingga tidak menghasilkan warna yang sangat acak, kemudian saya membaca tentang opsi make_color Please.js dan meletakkan senyum indah di wajah saya.
panchicore
6

Jika input Anda tidak cukup berbeda untuk hash sederhana untuk menggunakan seluruh spektrum warna, Anda dapat menggunakan generator nomor acak yang diunggah alih-alih fungsi hash.

Saya menggunakan kode warna dari jawaban Joe Freeman, dan pembuat nomor acak unggulan 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
sumber
5

Solusi lain untuk warna acak:

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

Ini adalah campuran dari hal-hal yang bermanfaat bagi saya. Saya menggunakan fungsi JFreeman Hash (juga jawaban di utas ini) dan fungsi acak pseudo Asykäri dari sini dan beberapa padding dan matematika dari diri saya.

Saya ragu fungsi menghasilkan warna yang terdistribusi secara merata, meskipun terlihat bagus dan melakukan apa yang seharusnya dilakukan.

estani
sumber
'0'.repeat(...)tidak valid javascript
kikito
@kikito cukup adil, mungkin prototipe saya diperpanjang entah bagaimana (JQuery?). Pokoknya, saya sudah mengedit fungsi jadi hanya javascript ... terima kasih sudah menunjukkan itu.
estani
@kikito ini ES6 yang valid, meskipun menggunakannya akan mengabaikan kompatibilitas lintas-browser.
Patrick Roberts
5

Dengan menggunakan hashCodeseperti pada jawaban Cristian Sanchez dengan hsldan javascript modern, Anda dapat membuat pemilih warna dengan kontras yang baik seperti ini:

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>

Karena ini hsl, Anda dapat mengukur pencahayaan untuk mendapatkan kontras yang Anda cari.

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
sumber
4

Inilah solusi yang saya buat untuk menghasilkan warna pastel yang estetis berdasarkan string input. Ia menggunakan dua karakter pertama dari string sebagai seed acak, kemudian menghasilkan R / G / B berdasarkan pada seed itu.

Ini bisa dengan mudah diperpanjang sehingga seed adalah XOR dari semua karakter dalam string, bukan hanya dua yang pertama.

Terinspirasi oleh jawaban David Crow di sini: Algoritma untuk secara acak menghasilkan palet warna yang menyenangkan secara estetika

//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 ada di sini: https://gist.github.com/ro-sharp/49fd46a071a267d9e5dd

Robert Sharp
sumber
Saya harus mengatakan bahwa ini adalah cara yang sangat aneh untuk melakukannya. Ini jenis pekerjaan tetapi tidak ada banyak warna yang tersedia. XOR dari dua warna pertama tidak membuat perbedaan urutan sehingga hanya ada kombinasi huruf. Tambahan sederhana yang saya lakukan untuk menambah jumlah warna adalah var seed = 0; for (var i in input_str) {seed ^ = i; }
Gussoh
Ya, itu benar-benar tergantung pada berapa banyak warna yang ingin Anda hasilkan. Saya ingat dalam contoh ini saya sedang membuat panel yang berbeda di UI dan ingin sejumlah warna daripada pelangi :)
Robert Sharp
1

Ini adalah percobaan lain:

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
sumber
1

Yang Anda butuhkan adalah fungsi hash yang baik. Pada node, saya hanya menggunakan

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

Saya mengonversi ini untuk Java.

Tank untuk semua.

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
sumber
-1

Fungsi ini berfungsi. Ini adaptasi dari ini, implementasi yang cukup lama dari repo ini ..

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
sumber
Ini menghasilkan banyak nilai yang sangat gelap.
Langdon