0

We have A-z chars and abcdef0-9 color.

I need get always same color on same word, (apple always red, car always green, cars - always orange) - even if word have 1 or 3 letter, I wanna see same color every time. In my function I have random function if no letters to Math color.

Please help me upgrade function and replace Math Random for something like get letter index in alphabet divide on colors char position or something else

export function MakeSenseColor(str) {
  if(!str && typeof str !== 'string') return '';

  const chars1 = 'abc6789';
  const chars2 = 'abcdef0123456789';

  const Digits = 'qйwцeуrкtеyнuгiшoщpзaхsъdфfыgвhаjпkрlоzлxдcжvэbяnчmсмитьбю1234567890';
  const splittedStr = str.split('').map((s,i,arr) => {
    const charPos = s && (Digits.split('')).indexOf(`${s}`.toLowerCase());

    if(!charPos || charPos === -1) return '0';

    if (charPos >= 0 ) {
      const char = (charPos * chars2.length) / Digits.length
      const charColor = (char * 6) / arr.length;

      return chars2[parseInt(charColor)];
    }

    return '0';
  });

  let color = '#';

  for (let i = 0; color.length < 7; i++) {
    const add = splittedStr[i%6] || chars1.charAt(Math.floor(Math.random() * chars1.length))

    color = color + add;
  }

  return color;
}
Alex Alex
  • 13
  • 3

1 Answers1

1

I'd just hash the string and use that to generate a hex string indicating the color. The hash implementation here https://stackoverflow.com/a/52171480/1358308 looks relatively nice to me.

// borrowed from https://stackoverflow.com/a/52171480/1358308
function cyrb53(str, seed = 0) {
    let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
    for (let i = 0, ch; i < str.length; i++) {
        ch = str.charCodeAt(i);
        h1 = Math.imul(h1 ^ ch, 2654435761);
        h2 = Math.imul(h2 ^ ch, 1597334677);
    }
    h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909);
    h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909);
    return 4294967296 * (2097151 & h2) + (h1>>>0);
};

function MakeSenseColor(str) {
    // hash the string and convert to hex
    let hash = cyrb53(str).toString(16);

    // just use the last 6 characters and prepend character to indicate color
    return '#' + hash.slice(-6);
}

this gives me unique and consistent results:

  • 'apple' = #002f86
  • 'car' = #684a21
  • 'cars' = #c10e83

these aren't the same colors as you pointed to in your question, but I suppose you could hard code a few that you care about.

Sam Mason
  • 15,216
  • 1
  • 41
  • 60
  • I dont need hardcode, because my words very different. And because this function only for fun/emotions in App. But, hash from word is what I need. And then I can use hash to convert to color. I think hash.slice give very repeated colors. But this is good answer. Thank you – Alex Alex Dec 07 '20 at 15:31