github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/ui/dashboard/src/utils/color.ts (about)

     1  import colorConvert from "color-convert";
     2  import { getColorOverride } from "../components/dashboards/common";
     3  
     4  const minColumn = 16;
     5  const maxColumn = 51;
     6  const minRow = 0;
     7  const maxRow = 5;
     8  
     9  type Color = {
    10    ansi256: number;
    11    hex: string;
    12  };
    13  
    14  type ColorDictionary = {
    15    [key: number]: boolean;
    16  };
    17  
    18  export class ColorGenerator {
    19    private readonly startingColumn: number;
    20    private readonly startingRow: number;
    21    private currentColumn!: number;
    22    private currentRow!: number;
    23    private allocatedColorCodes!: ColorDictionary;
    24    private forbiddenColumns: ColorDictionary;
    25  
    26    constructor(startingColumn: number, startingRow: number) {
    27      if (startingColumn < minColumn || startingColumn > maxColumn) {
    28        throw new Error("starting column must be between 16 and 51");
    29      }
    30      if (startingRow < minRow || startingRow > maxRow) {
    31        throw new Error("starting row must be between 0 and 5");
    32      }
    33  
    34      this.forbiddenColumns = {
    35        16: true, // red
    36        17: true, // red
    37        18: true, // red
    38        19: true, // red
    39        20: true, // red
    40        22: true, // orange
    41        23: true, // orange
    42        27: true, // orange
    43        28: true, // orange
    44        29: true, // orange
    45        34: true, // green/orange
    46        35: true, // green/orange
    47        36: true, // green/orange
    48        40: true, // green/orange
    49        41: true, // green/orange
    50        42: true, // green/orange
    51        46: true, // green
    52        47: true, // green
    53        48: true, // green
    54        49: true, // green
    55        50: true, // yellow
    56        51: true, // yellow
    57        52: true, // black
    58        53: true, // black
    59        54: true, // black
    60        55: true, // black
    61      };
    62  
    63      this.startingColumn = startingColumn;
    64      this.startingRow = startingRow;
    65  
    66      this.reset();
    67    }
    68  
    69    reset() {
    70      this.currentColumn = this.startingColumn;
    71      this.currentRow = this.startingRow;
    72      this.allocatedColorCodes = {};
    73    }
    74  
    75    incrementColumn(increment: number) {
    76      this.currentColumn += increment;
    77      if (this.currentColumn > maxColumn) {
    78        // reset and maintain offset
    79        this.currentColumn -= maxColumn - minColumn + 1;
    80      }
    81      while (this.forbiddenColumns[this.currentColumn]) {
    82        this.currentColumn++;
    83        if (this.currentColumn > maxColumn) {
    84          // reset and maintain offset
    85          this.currentColumn -= maxColumn - minColumn + 1;
    86        }
    87      }
    88    }
    89  
    90    incrementRow(increment: number) {
    91      this.currentRow += increment;
    92      if (this.currentRow > maxRow) {
    93        // reset and maintain offset
    94        this.currentRow -= maxRow;
    95      }
    96    }
    97  
    98    colorClashes(color: number) {
    99      return this.allocatedColorCodes[color];
   100    }
   101  
   102    currentColor() {
   103      return this.currentColumn + this.currentRow * 36;
   104    }
   105  
   106    nextColor(): Color {
   107      this.incrementColumn(2);
   108      this.incrementRow(2);
   109  
   110      // does this color clash, or is it forbidden
   111      let color = this.currentColor();
   112      const origColor = color;
   113      while (this.colorClashes(color)) {
   114        this.incrementColumn(1);
   115        this.incrementRow(1);
   116        color = this.currentColor();
   117        if (color === origColor) {
   118          // we have tried them all reset and start from the first color
   119          this.reset();
   120          return this.nextColor();
   121        }
   122      }
   123  
   124      // store this color code
   125      this.allocatedColorCodes[color] = true;
   126      return this.toColorObject(color);
   127    }
   128  
   129    toColorObject(ansi256ColorCode: number): Color {
   130      return {
   131        ansi256: ansi256ColorCode,
   132        hex: `#${colorConvert.ansi256.hex(ansi256ColorCode)}`,
   133      };
   134    }
   135  }
   136  
   137  const stringColorMap = {};
   138  const colorGenerator = new ColorGenerator(16, 0);
   139  
   140  export const stringToColor = (str: string): string => {
   141    if (stringColorMap[str]) {
   142      return stringColorMap[str];
   143    }
   144    const color = colorGenerator.nextColor().hex;
   145    stringColorMap[str] = color;
   146    return color;
   147  };
   148  
   149  export const hexToRgb = (hex: string) => {
   150    return colorConvert.hex.rgb(hex);
   151  };
   152  
   153  export const colorToRgb = (input: string, themeColors: any) => {
   154    const convertedColor = getColorOverride(input, themeColors);
   155    if (convertedColor.startsWith("#")) {
   156      return colorConvert.hex.rgb(convertedColor);
   157    }
   158    return colorConvert.keyword.rgb(convertedColor);
   159  };