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