Can I Ensure Consistent Colors Per Value Across Charts?

Vanilla Components do not currently support this option out of the box, but there are solutions available with a little development on your side. One option is to cache color on the browser side. Here’s an example of code that does this:


import { COLORS } from '../constants';

const CACHE_KEY = 'color-cache';

export function getComponentId(...identifiers: unknown[]): string {
  const ids: string[] = [];

  for (const identifier of identifiers) {
    // ignore undefined, null, function
    switch (typeof identifier) {
      case 'string':
        ids.push(identifier);
        break;
      case 'number':
      case 'boolean':
      case 'bigint':
      case 'symbol':
        ids.push(String(identifier));
        break;
      case 'object':
        ids.push(JSON.stringify(identifier));
        break;
      default:
        console.warn(`${typeof identifier} not supported as part of componentId`);
    }
  }

  return ids.join(':');
}

export function getCachedColorForLabel(componentId: string, label: string, index: number): string {
  const key = `${CACHE_KEY}:${componentId}`;

  const colorsJson = window.localStorage.getItem(key) ;

  // If no colors have been chosen for this component yet initialize the cache and give the Nth color.
  if (!colorsJson) {
    const color = COLORS[index % COLORS.length];
    window.localStorage.setItem(key, JSON.stringify({ [label]: color }));
    return color;
  }

  const colors = JSON.parse(colorsJson);

  // If a color has already been used for this component and this label use it again.
  if (label in colors) {
    return colors[label];
  }

  // Once we get to this point the cache has been instantiated but we have not seen this label before.
  // Sequentially go over the colors and check if it's been used before.
  // Once we find a suitable color store it in the cache and return it.
  const usedColors = Object.values(colors);
  for (const color of COLORS) {
    if (!usedColors.includes(color)) {
      window.localStorage.setItem(key, JSON.stringify({ [label]: color, ...colors }));
      return color;
    }
  }

  // If we get to this point all colors have been used. Just re-use a color based on the index.
  const color = COLORS[index % COLORS.length];
  window.localStorage.setItem(key, JSON.stringify({ [label]: color, ...colors }));
  return color;
}