From 9cf4b17da0bbc03a7afd0abde5132c0167e1e473 Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Tue, 29 Mar 2022 16:56:32 +0530 Subject: [PATCH 01/11] feat: support generating a color combination from string id --- projects/common/src/color/color.ts | 110 ++++++++++++++++++ .../src/utilities/math/math-utilities.ts | 6 + 2 files changed, 116 insertions(+) diff --git a/projects/common/src/color/color.ts b/projects/common/src/color/color.ts index bcf86245d..2bc8cb8e7 100644 --- a/projects/common/src/color/color.ts +++ b/projects/common/src/color/color.ts @@ -1,3 +1,5 @@ +import { hashCode } from '../utilities/math/math-utilities'; + export const enum Color { Blue1 = '#f0f6ff', Blue2 = '#b8d3ff', @@ -58,3 +60,111 @@ export const enum Color { Yellow8 = '#6d5b00', Yellow9 = '#181400' } + +export interface ColorCombination { + background: string; + text: string; +} + +export const getColorCombinationForId = (id: string): ColorCombination => + predefinedColorCombinations[Math.abs(hashCode(id)) % predefinedColorCombinations.length]; + +// Predefined set of 25 compatible color combinations. +const predefinedColorCombinations: ColorCombination[] = [ + { + background: '#CD5C5C', + text: Color.White + }, + { + background: '#FFA07A', + text: Color.Gray9 + }, + { + background: '#F08080', + text: Color.Gray9 + }, + { + background: '#FFB6C1', + text: Color.Gray9 + }, + { + background: '#C71585', + text: Color.White + }, + { + background: '#DB7093', + text: Color.White + }, + { + background: '#FF6347', + text: Color.White + }, + { + background: '#FF8C00', + text: Color.White + }, + { + background: '#FFD700', + text: Color.Gray9 + }, + { + background: '#FFDAB9', + text: Color.Gray9 + }, + { + background: '#F0E68C', + text: Color.Gray9 + }, + { + background: '#BDB76B', + text: Color.White + }, + { + background: '#DDA0DD', + text: Color.White + }, + { + background: '#9370DB', + text: Color.White + }, + { + background: '#4B0082', + text: Color.White + }, + { + background: '#32CD32', + text: Color.White + }, + { + background: '#90EE90', + text: Color.Gray9 + }, + { + background: '#9ACD32', + text: Color.White + }, + { + background: '#66CDAA', + text: Color.White + }, + { + background: '#808000', + text: Color.White + }, + { + background: '#F4A460', + text: Color.White + }, + { + background: '#6B8E23', + text: Color.White + }, + { + background: '#D2691E', + text: Color.White + }, + { + background: Color.Yellow2, + text: Color.Gray9 + } +]; diff --git a/projects/common/src/utilities/math/math-utilities.ts b/projects/common/src/utilities/math/math-utilities.ts index 9a0963d04..1a1b165e3 100644 --- a/projects/common/src/utilities/math/math-utilities.ts +++ b/projects/common/src/utilities/math/math-utilities.ts @@ -110,6 +110,12 @@ export const getPercentage = (numerator: number | undefined, denominator: number return (numerator / denominator) * 100; }; + +// Trying to recreate Java hashcode +export const hashCode = (str: string): number => + // tslint:disable-next-line: no-bitwise + Array.from(str).reduce((s, c) => (Math.imul(31, s) + c.charCodeAt(0)) | 0, 0); + export interface Point { x: number; y: number; From a7d81746ef349187a68a29675d4160b9defb65dc Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Tue, 29 Mar 2022 17:22:49 +0530 Subject: [PATCH 02/11] fix: prettier fix --- projects/common/src/utilities/math/math-utilities.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/common/src/utilities/math/math-utilities.ts b/projects/common/src/utilities/math/math-utilities.ts index 1a1b165e3..2a0f3cbbc 100644 --- a/projects/common/src/utilities/math/math-utilities.ts +++ b/projects/common/src/utilities/math/math-utilities.ts @@ -110,7 +110,6 @@ export const getPercentage = (numerator: number | undefined, denominator: number return (numerator / denominator) * 100; }; - // Trying to recreate Java hashcode export const hashCode = (str: string): number => // tslint:disable-next-line: no-bitwise From c6d8cf0df496c1a53734f9fa6f58ed12d0bbd7ad Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Wed, 30 Mar 2022 09:12:36 +0530 Subject: [PATCH 03/11] fix: incorporate color combinations into color palette --- projects/common/src/color/color-palette.ts | 21 ++++ projects/common/src/color/color.ts | 113 ++------------------- projects/common/src/public-api.ts | 3 + 3 files changed, 35 insertions(+), 102 deletions(-) diff --git a/projects/common/src/color/color-palette.ts b/projects/common/src/color/color-palette.ts index 41c832c71..dc4ef0762 100644 --- a/projects/common/src/color/color-palette.ts +++ b/projects/common/src/color/color-palette.ts @@ -1,5 +1,7 @@ import { rgb } from 'd3-color'; import { interpolateRgbBasis, quantize } from 'd3-interpolate'; +import { hashCode } from '../utilities/math/math-utilities'; +import { Color, ColorCombination } from './color'; export class ColorPalette { private readonly basisColors: string[]; @@ -10,6 +12,25 @@ export class ColorPalette { this.basisColors = basisColors.map(color => rgb(color).toString()); } + public getColorCombinations(count: number): ColorCombination[] { + return this.forNColors(count).map(color => ({background: color, foreground: this.getContrast(color)})); + } + + public getColorCombinationForId(colorCount: number, id: string): ColorCombination { + return this.getColorCombinations(colorCount)[Math.abs(hashCode(id)) % colorCount]; + } + + private getContrast(rgbColorString: string): string { + // Convert to RGB value + const rgbColor = rgb(rgbColorString); + + // Get YIQ ratio + const yiq = ((rgbColor.r*299)+(rgbColor.g*587)+(rgbColor.b*114))/1000; + + // Check contrast + return (yiq >= 128) ? Color.Gray9 : Color.White; + }; + public forNColors(count: number): string[] { if (count === this.basisColors.length) { // Use as is if palette size matches, don't interpolate diff --git a/projects/common/src/color/color.ts b/projects/common/src/color/color.ts index 2bc8cb8e7..668ffa492 100644 --- a/projects/common/src/color/color.ts +++ b/projects/common/src/color/color.ts @@ -63,108 +63,17 @@ export const enum Color { export interface ColorCombination { background: string; - text: string; + foreground: string; } -export const getColorCombinationForId = (id: string): ColorCombination => - predefinedColorCombinations[Math.abs(hashCode(id)) % predefinedColorCombinations.length]; - -// Predefined set of 25 compatible color combinations. -const predefinedColorCombinations: ColorCombination[] = [ - { - background: '#CD5C5C', - text: Color.White - }, - { - background: '#FFA07A', - text: Color.Gray9 - }, - { - background: '#F08080', - text: Color.Gray9 - }, - { - background: '#FFB6C1', - text: Color.Gray9 - }, - { - background: '#C71585', - text: Color.White - }, - { - background: '#DB7093', - text: Color.White - }, - { - background: '#FF6347', - text: Color.White - }, - { - background: '#FF8C00', - text: Color.White - }, - { - background: '#FFD700', - text: Color.Gray9 - }, - { - background: '#FFDAB9', - text: Color.Gray9 - }, - { - background: '#F0E68C', - text: Color.Gray9 - }, - { - background: '#BDB76B', - text: Color.White - }, - { - background: '#DDA0DD', - text: Color.White - }, - { - background: '#9370DB', - text: Color.White - }, - { - background: '#4B0082', - text: Color.White - }, - { - background: '#32CD32', - text: Color.White - }, - { - background: '#90EE90', - text: Color.Gray9 - }, - { - background: '#9ACD32', - text: Color.White - }, - { - background: '#66CDAA', - text: Color.White - }, - { - background: '#808000', - text: Color.White - }, - { - background: '#F4A460', - text: Color.White - }, - { - background: '#6B8E23', - text: Color.White - }, - { - background: '#D2691E', - text: Color.White - }, - { - background: Color.Yellow2, - text: Color.Gray9 +export const getRgbColorForString = (id: string) => { + const hash = hashCode(id); + let rgb = '#'; + for (let i = 0; i < 3; i++) { + // tslint:disable-next-line: no-bitwise + const value = (hash >> (i * 8)) & 0xff; + rgb += `00${value.toString(16)}`.substr(-2); } -]; + + return rgb; +} diff --git a/projects/common/src/public-api.ts b/projects/common/src/public-api.ts index 0ea74530b..ebd7dd733 100644 --- a/projects/common/src/public-api.ts +++ b/projects/common/src/public-api.ts @@ -124,3 +124,6 @@ export * from './time/page-time-range-preference.service'; // Validators export * from './utilities/validators'; + +// Color Palette +export * from './color/color-palette'; From 49c37ca9f4b7fea8f50f3add4cc511869795a60e Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Wed, 30 Mar 2022 09:14:37 +0530 Subject: [PATCH 04/11] fix: renaming method --- projects/common/src/color/color.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/common/src/color/color.ts b/projects/common/src/color/color.ts index 668ffa492..1767efcad 100644 --- a/projects/common/src/color/color.ts +++ b/projects/common/src/color/color.ts @@ -66,7 +66,7 @@ export interface ColorCombination { foreground: string; } -export const getRgbColorForString = (id: string) => { +export const getHexColorForString = (id: string): string => { const hash = hashCode(id); let rgb = '#'; for (let i = 0; i < 3; i++) { From 4f0d6c4587347f899fdbc6c6d9caf3286370dc38 Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Wed, 30 Mar 2022 09:22:48 +0530 Subject: [PATCH 05/11] fix: prettier fix --- projects/common/src/color/color-palette.ts | 8 ++++---- projects/common/src/color/color.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/projects/common/src/color/color-palette.ts b/projects/common/src/color/color-palette.ts index dc4ef0762..af2ef88a7 100644 --- a/projects/common/src/color/color-palette.ts +++ b/projects/common/src/color/color-palette.ts @@ -13,7 +13,7 @@ export class ColorPalette { } public getColorCombinations(count: number): ColorCombination[] { - return this.forNColors(count).map(color => ({background: color, foreground: this.getContrast(color)})); + return this.forNColors(count).map(color => ({ background: color, foreground: this.getContrast(color) })); } public getColorCombinationForId(colorCount: number, id: string): ColorCombination { @@ -25,11 +25,11 @@ export class ColorPalette { const rgbColor = rgb(rgbColorString); // Get YIQ ratio - const yiq = ((rgbColor.r*299)+(rgbColor.g*587)+(rgbColor.b*114))/1000; + const yiq = (rgbColor.r * 299 + rgbColor.g * 587 + rgbColor.b * 114) / 1000; // Check contrast - return (yiq >= 128) ? Color.Gray9 : Color.White; - }; + return yiq >= 128 ? Color.Gray9 : Color.White; + } public forNColors(count: number): string[] { if (count === this.basisColors.length) { diff --git a/projects/common/src/color/color.ts b/projects/common/src/color/color.ts index 1767efcad..d5d8b3afd 100644 --- a/projects/common/src/color/color.ts +++ b/projects/common/src/color/color.ts @@ -76,4 +76,4 @@ export const getHexColorForString = (id: string): string => { } return rgb; -} +}; From c4625c5d36af8a96150f5e27080eaf72d85b11e4 Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Wed, 30 Mar 2022 18:53:15 +0530 Subject: [PATCH 06/11] fix: add test --- .../common/src/color/color-palette.test.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/projects/common/src/color/color-palette.test.ts b/projects/common/src/color/color-palette.test.ts index 37d713152..d329837e6 100644 --- a/projects/common/src/color/color-palette.test.ts +++ b/projects/common/src/color/color-palette.test.ts @@ -31,4 +31,26 @@ describe('Color palette', () => { expect(() => new ColorPalette(['black'])).toThrow(); expect(() => new ColorPalette(['white', 'black'])).not.toThrow(); }); + + test('should return color combinations correctly', () => { + const palette = new ColorPalette(['#fffbeb', '#140300']); + expect(palette.getColorCombinations(2)).toEqual([ + { + background: 'rgb(255, 251, 235)', + foreground: '#080909', + }, + { + background: 'rgb(20, 3, 0)', + foreground: '#FFFFFF', + } + ]); + }) + + test('should generate color for a string as expected from a limited set', () => { + const palette = new ColorPalette(['#fffbeb', '#140300', '#789ab7']); + expect(palette.getColorCombinationForId(2, 'test')).toEqual({ + background: 'rgb(255, 251, 235)', + foreground: '#080909', + }); + }) }); From 5f9293ff444f10e3dfb28da2f6a928f2b71d4f20 Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Wed, 30 Mar 2022 19:03:45 +0530 Subject: [PATCH 07/11] fix: lint fix --- projects/common/src/color/color-palette.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/projects/common/src/color/color-palette.test.ts b/projects/common/src/color/color-palette.test.ts index d329837e6..171722234 100644 --- a/projects/common/src/color/color-palette.test.ts +++ b/projects/common/src/color/color-palette.test.ts @@ -37,20 +37,20 @@ describe('Color palette', () => { expect(palette.getColorCombinations(2)).toEqual([ { background: 'rgb(255, 251, 235)', - foreground: '#080909', + foreground: '#080909' }, { background: 'rgb(20, 3, 0)', - foreground: '#FFFFFF', + foreground: '#FFFFFF' } ]); - }) + }); test('should generate color for a string as expected from a limited set', () => { const palette = new ColorPalette(['#fffbeb', '#140300', '#789ab7']); expect(palette.getColorCombinationForId(2, 'test')).toEqual({ background: 'rgb(255, 251, 235)', - foreground: '#080909', + foreground: '#080909' }); - }) + }); }); From 04fb98fcb76fab19ee2cfb098e36e24dcb83a35b Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Wed, 30 Mar 2022 20:55:28 +0530 Subject: [PATCH 08/11] fix: address comments --- projects/common/src/color/color-palette.test.ts | 7 ++++++- projects/common/src/color/color-palette.ts | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/projects/common/src/color/color-palette.test.ts b/projects/common/src/color/color-palette.test.ts index 171722234..b486605e7 100644 --- a/projects/common/src/color/color-palette.test.ts +++ b/projects/common/src/color/color-palette.test.ts @@ -48,9 +48,14 @@ describe('Color palette', () => { test('should generate color for a string as expected from a limited set', () => { const palette = new ColorPalette(['#fffbeb', '#140300', '#789ab7']); - expect(palette.getColorCombinationForId(2, 'test')).toEqual({ + expect(palette.getColorCombinationForId('test', 2)).toEqual({ background: 'rgb(255, 251, 235)', foreground: '#080909' }); + expect(palette.getColorCombinationForId('test')).toEqual({ + background: 'rgb(20, 3, 0)', + foreground: '#FFFFFF' + }); + }); }); diff --git a/projects/common/src/color/color-palette.ts b/projects/common/src/color/color-palette.ts index af2ef88a7..1b48df5d8 100644 --- a/projects/common/src/color/color-palette.ts +++ b/projects/common/src/color/color-palette.ts @@ -16,8 +16,10 @@ export class ColorPalette { return this.forNColors(count).map(color => ({ background: color, foreground: this.getContrast(color) })); } - public getColorCombinationForId(colorCount: number, id: string): ColorCombination { - return this.getColorCombinations(colorCount)[Math.abs(hashCode(id)) % colorCount]; + public getColorCombinationForId(id: string, colorPaletteSize?: number): ColorCombination { + const colorSetSize = colorPaletteSize ?? this.basisColors.length; + + return this.getColorCombinations(colorSetSize)[Math.abs(hashCode(id)) % colorSetSize]; } private getContrast(rgbColorString: string): string { From 925f82a5fcda224740a8bacfe40cdcd363d0aecb Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Wed, 30 Mar 2022 21:03:01 +0530 Subject: [PATCH 09/11] fix: prettier fix --- projects/common/src/color/color-palette.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/common/src/color/color-palette.test.ts b/projects/common/src/color/color-palette.test.ts index b486605e7..3d4d40db5 100644 --- a/projects/common/src/color/color-palette.test.ts +++ b/projects/common/src/color/color-palette.test.ts @@ -56,6 +56,5 @@ describe('Color palette', () => { background: 'rgb(20, 3, 0)', foreground: '#FFFFFF' }); - }); }); From f0ad954b871075fa0dc21e72f79220d88aa4cfec Mon Sep 17 00:00:00 2001 From: Arjunlal B <63222211+arjunlalb@users.noreply.github.com> Date: Wed, 30 Mar 2022 21:38:18 +0530 Subject: [PATCH 10/11] Update projects/common/src/color/color-palette.ts Co-authored-by: Aaron Steinfeld <45047841+aaron-steinfeld@users.noreply.github.com> --- projects/common/src/color/color-palette.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/projects/common/src/color/color-palette.ts b/projects/common/src/color/color-palette.ts index 1b48df5d8..ed4056c3d 100644 --- a/projects/common/src/color/color-palette.ts +++ b/projects/common/src/color/color-palette.ts @@ -16,8 +16,7 @@ export class ColorPalette { return this.forNColors(count).map(color => ({ background: color, foreground: this.getContrast(color) })); } - public getColorCombinationForId(id: string, colorPaletteSize?: number): ColorCombination { - const colorSetSize = colorPaletteSize ?? this.basisColors.length; + public getColorCombinationForId(id: string, colorSetSize: number = this.basisColors.length): ColorCombination { return this.getColorCombinations(colorSetSize)[Math.abs(hashCode(id)) % colorSetSize]; } From 36cd7740c19fe42717cef4c531a072944bbd329d Mon Sep 17 00:00:00 2001 From: Arjunlal B Date: Wed, 30 Mar 2022 21:44:06 +0530 Subject: [PATCH 11/11] fix: prettier fix --- projects/common/src/color/color-palette.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/common/src/color/color-palette.ts b/projects/common/src/color/color-palette.ts index ed4056c3d..2d1789984 100644 --- a/projects/common/src/color/color-palette.ts +++ b/projects/common/src/color/color-palette.ts @@ -17,7 +17,6 @@ export class ColorPalette { } public getColorCombinationForId(id: string, colorSetSize: number = this.basisColors.length): ColorCombination { - return this.getColorCombinations(colorSetSize)[Math.abs(hashCode(id)) % colorSetSize]; }