Skip to content

Commit 592cdb2

Browse files
authored
feat: support generating a color combination from a color palette (#1510)
* feat: support generating a color combination from color palette
1 parent ee0762a commit 592cdb2

File tree

5 files changed

+74
-0
lines changed

5 files changed

+74
-0
lines changed

projects/common/src/color/color-palette.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,30 @@ describe('Color palette', () => {
3131
expect(() => new ColorPalette(['black'])).toThrow();
3232
expect(() => new ColorPalette(['white', 'black'])).not.toThrow();
3333
});
34+
35+
test('should return color combinations correctly', () => {
36+
const palette = new ColorPalette(['#fffbeb', '#140300']);
37+
expect(palette.getColorCombinations(2)).toEqual([
38+
{
39+
background: 'rgb(255, 251, 235)',
40+
foreground: '#080909'
41+
},
42+
{
43+
background: 'rgb(20, 3, 0)',
44+
foreground: '#FFFFFF'
45+
}
46+
]);
47+
});
48+
49+
test('should generate color for a string as expected from a limited set', () => {
50+
const palette = new ColorPalette(['#fffbeb', '#140300', '#789ab7']);
51+
expect(palette.getColorCombinationForId('test', 2)).toEqual({
52+
background: 'rgb(255, 251, 235)',
53+
foreground: '#080909'
54+
});
55+
expect(palette.getColorCombinationForId('test')).toEqual({
56+
background: 'rgb(20, 3, 0)',
57+
foreground: '#FFFFFF'
58+
});
59+
});
3460
});

projects/common/src/color/color-palette.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { rgb } from 'd3-color';
22
import { interpolateRgbBasis, quantize } from 'd3-interpolate';
3+
import { hashCode } from '../utilities/math/math-utilities';
4+
import { Color, ColorCombination } from './color';
35

46
export class ColorPalette {
57
private readonly basisColors: string[];
@@ -10,6 +12,25 @@ export class ColorPalette {
1012
this.basisColors = basisColors.map(color => rgb(color).toString());
1113
}
1214

15+
public getColorCombinations(count: number): ColorCombination[] {
16+
return this.forNColors(count).map(color => ({ background: color, foreground: this.getContrast(color) }));
17+
}
18+
19+
public getColorCombinationForId(id: string, colorSetSize: number = this.basisColors.length): ColorCombination {
20+
return this.getColorCombinations(colorSetSize)[Math.abs(hashCode(id)) % colorSetSize];
21+
}
22+
23+
private getContrast(rgbColorString: string): string {
24+
// Convert to RGB value
25+
const rgbColor = rgb(rgbColorString);
26+
27+
// Get YIQ ratio
28+
const yiq = (rgbColor.r * 299 + rgbColor.g * 587 + rgbColor.b * 114) / 1000;
29+
30+
// Check contrast
31+
return yiq >= 128 ? Color.Gray9 : Color.White;
32+
}
33+
1334
public forNColors(count: number): string[] {
1435
if (count === this.basisColors.length) {
1536
// Use as is if palette size matches, don't interpolate

projects/common/src/color/color.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { hashCode } from '../utilities/math/math-utilities';
2+
13
export const enum Color {
24
Blue1 = '#f0f6ff',
35
Blue2 = '#b8d3ff',
@@ -58,3 +60,20 @@ export const enum Color {
5860
Yellow8 = '#6d5b00',
5961
Yellow9 = '#181400'
6062
}
63+
64+
export interface ColorCombination {
65+
background: string;
66+
foreground: string;
67+
}
68+
69+
export const getHexColorForString = (id: string): string => {
70+
const hash = hashCode(id);
71+
let rgb = '#';
72+
for (let i = 0; i < 3; i++) {
73+
// tslint:disable-next-line: no-bitwise
74+
const value = (hash >> (i * 8)) & 0xff;
75+
rgb += `00${value.toString(16)}`.substr(-2);
76+
}
77+
78+
return rgb;
79+
};

projects/common/src/public-api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,6 @@ export * from './time/page-time-range-preference.service';
124124

125125
// Validators
126126
export * from './utilities/validators';
127+
128+
// Color Palette
129+
export * from './color/color-palette';

projects/common/src/utilities/math/math-utilities.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ export const getPercentage = (numerator: number | undefined, denominator: number
110110
return (numerator / denominator) * 100;
111111
};
112112

113+
// Trying to recreate Java hashcode
114+
export const hashCode = (str: string): number =>
115+
// tslint:disable-next-line: no-bitwise
116+
Array.from(str).reduce((s, c) => (Math.imul(31, s) + c.charCodeAt(0)) | 0, 0);
117+
113118
export interface Point {
114119
x: number;
115120
y: number;

0 commit comments

Comments
 (0)