@etsoo/shared 1.1.15 → 1.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/__tests__/{EColor.ts → ColorUtils.ts} +10 -1
- package/lib/cjs/ColorUtils.d.ts +23 -0
- package/lib/cjs/ColorUtils.js +80 -0
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/types/EColor.d.ts +32 -20
- package/lib/cjs/types/EColor.js +94 -53
- package/lib/mjs/ColorUtils.d.ts +23 -0
- package/lib/mjs/ColorUtils.js +77 -0
- package/lib/mjs/index.d.ts +1 -0
- package/lib/mjs/index.js +1 -0
- package/lib/mjs/types/EColor.d.ts +32 -20
- package/lib/mjs/types/EColor.js +94 -53
- package/package.json +6 -6
- package/src/ColorUtils.ts +99 -0
- package/src/index.ts +1 -0
- package/src/types/EColor.ts +104 -58
package/README.md
CHANGED
|
@@ -26,7 +26,12 @@ Etsoo implmented Color
|
|
|
26
26
|
|static getColors|Get HEX or RGB colors|
|
|
27
27
|
|static getEColors|Get EColors|
|
|
28
28
|
|static parse|Parse HTML color to EColor|
|
|
29
|
+
|clone|Clone color with adjustments|
|
|
30
|
+
|getContrastRatio|Get contrast ratio, a value between 0 and 1|
|
|
31
|
+
|getDeltaValue|Get Delta value (perceptible by human eyes)|
|
|
32
|
+
|getLuminance|Get luminance|
|
|
29
33
|
|toHEXColor|To HEX color string|
|
|
34
|
+
|toLabValue|To Lab value|
|
|
30
35
|
|toRGBColor|To RGB color string|
|
|
31
36
|
|
|
32
37
|
## Keyboard
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EColor } from '../src/types/EColor';
|
|
2
|
+
import { ColorUtils } from '../src/ColorUtils';
|
|
2
3
|
|
|
3
4
|
test('Tests for parse', () => {
|
|
4
5
|
// Arrange & act
|
|
@@ -13,5 +14,13 @@ test('Tests for parse', () => {
|
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
test('Tests for getColors', () => {
|
|
16
|
-
|
|
17
|
+
const colors = ColorUtils.getColors(undefined, 128);
|
|
18
|
+
expect(colors.length).toBe(8);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('Tests for toRGBColor', () => {
|
|
22
|
+
const color = new EColor(0, 0, 0);
|
|
23
|
+
expect(color.toRGBColor()).toBe('RGB(0, 0, 0)');
|
|
24
|
+
expect(color.toRGBColor(0.1)).toBe('RGBA(0, 0, 0, 0.1)');
|
|
25
|
+
expect(color.alpha).toBeUndefined();
|
|
17
26
|
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { EColor } from './types/EColor';
|
|
2
|
+
/**
|
|
3
|
+
* Color utils
|
|
4
|
+
*/
|
|
5
|
+
export declare namespace ColorUtils {
|
|
6
|
+
/**
|
|
7
|
+
* Get HEX or RGB colors
|
|
8
|
+
* @param init Initial color
|
|
9
|
+
* @param factor Increase factor
|
|
10
|
+
* @param adjustOrder Adjust order to increase difference
|
|
11
|
+
* @param hex to HEX or not
|
|
12
|
+
* @returns Result
|
|
13
|
+
*/
|
|
14
|
+
function getColors(init?: string, factor?: number, adjustOrder?: boolean, hex?: boolean): string[];
|
|
15
|
+
/**
|
|
16
|
+
* Get EColors
|
|
17
|
+
* @param init Initial color
|
|
18
|
+
* @param factor Increase factor
|
|
19
|
+
* @param adjustOrder Adjust order to increase difference
|
|
20
|
+
* @returns Result
|
|
21
|
+
*/
|
|
22
|
+
function getEColors(init?: string, factor?: number, adjustOrder?: boolean): EColor[];
|
|
23
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ColorUtils = void 0;
|
|
4
|
+
const EColor_1 = require("./types/EColor");
|
|
5
|
+
/**
|
|
6
|
+
* Color utils
|
|
7
|
+
*/
|
|
8
|
+
var ColorUtils;
|
|
9
|
+
(function (ColorUtils) {
|
|
10
|
+
/**
|
|
11
|
+
* Get HEX or RGB colors
|
|
12
|
+
* @param init Initial color
|
|
13
|
+
* @param factor Increase factor
|
|
14
|
+
* @param adjustOrder Adjust order to increase difference
|
|
15
|
+
* @param hex to HEX or not
|
|
16
|
+
* @returns Result
|
|
17
|
+
*/
|
|
18
|
+
function getColors(init = '#000', factor = 51, adjustOrder = true, hex = true) {
|
|
19
|
+
return getEColors(init, factor, adjustOrder).map((c) => hex ? c.toHEXColor() : c.toRGBColor());
|
|
20
|
+
}
|
|
21
|
+
ColorUtils.getColors = getColors;
|
|
22
|
+
/**
|
|
23
|
+
* Get EColors
|
|
24
|
+
* @param init Initial color
|
|
25
|
+
* @param factor Increase factor
|
|
26
|
+
* @param adjustOrder Adjust order to increase difference
|
|
27
|
+
* @returns Result
|
|
28
|
+
*/
|
|
29
|
+
function getEColors(init = '#000', factor = 51, adjustOrder = true) {
|
|
30
|
+
var _a;
|
|
31
|
+
// Init color
|
|
32
|
+
const initColor = (_a = EColor_1.EColor.parse(init)) !== null && _a !== void 0 ? _a : new EColor_1.EColor(0, 0, 0);
|
|
33
|
+
// Factors elements
|
|
34
|
+
// 51 = '00', '33', '66', '99', 'cc', 'ff'
|
|
35
|
+
const factors = [];
|
|
36
|
+
let f = 0;
|
|
37
|
+
while (f <= 255) {
|
|
38
|
+
factors.push(f);
|
|
39
|
+
f += factor;
|
|
40
|
+
}
|
|
41
|
+
// RGB loop
|
|
42
|
+
const colors = [initColor];
|
|
43
|
+
for (const r of factors) {
|
|
44
|
+
for (const g of factors) {
|
|
45
|
+
for (const b of factors) {
|
|
46
|
+
colors.push(initColor.clone(r, g, b));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Non-nullable colors
|
|
51
|
+
const nColors = colors.filter((color) => color != null);
|
|
52
|
+
// Adjust order
|
|
53
|
+
if (adjustOrder) {
|
|
54
|
+
const firstColor = nColors.shift();
|
|
55
|
+
if (firstColor) {
|
|
56
|
+
let color = firstColor;
|
|
57
|
+
const newColors = [color];
|
|
58
|
+
while (nColors.length > 0) {
|
|
59
|
+
const result = nColors.reduce((p, c, index) => {
|
|
60
|
+
const delta = color.getDeltaValue(c);
|
|
61
|
+
if (delta != null && delta > p.delta) {
|
|
62
|
+
p.delta = delta;
|
|
63
|
+
p.color = c;
|
|
64
|
+
p.index = index;
|
|
65
|
+
}
|
|
66
|
+
return p;
|
|
67
|
+
}, { delta: 0, color, index: -1 });
|
|
68
|
+
if (result.delta > 0) {
|
|
69
|
+
color = result.color;
|
|
70
|
+
newColors.push(color);
|
|
71
|
+
nColors.splice(result.index, 1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return newColors;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return nColors;
|
|
78
|
+
}
|
|
79
|
+
ColorUtils.getEColors = getEColors;
|
|
80
|
+
})(ColorUtils = exports.ColorUtils || (exports.ColorUtils = {}));
|
package/lib/cjs/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './types/FormData';
|
|
|
4
4
|
export * from './storage/IStorage';
|
|
5
5
|
export * from './storage/WindowStorage';
|
|
6
6
|
export * from './DataTypes';
|
|
7
|
+
export * from './ColorUtils';
|
|
7
8
|
export * from './DateUtils';
|
|
8
9
|
export * from './DomUtils';
|
|
9
10
|
export * from './ExtendUtils';
|
package/lib/cjs/index.js
CHANGED
|
@@ -20,6 +20,7 @@ __exportStar(require("./types/FormData"), exports);
|
|
|
20
20
|
__exportStar(require("./storage/IStorage"), exports);
|
|
21
21
|
__exportStar(require("./storage/WindowStorage"), exports);
|
|
22
22
|
__exportStar(require("./DataTypes"), exports);
|
|
23
|
+
__exportStar(require("./ColorUtils"), exports);
|
|
23
24
|
__exportStar(require("./DateUtils"), exports);
|
|
24
25
|
__exportStar(require("./DomUtils"), exports);
|
|
25
26
|
__exportStar(require("./ExtendUtils"), exports);
|
|
@@ -13,21 +13,6 @@ export declare class EColor {
|
|
|
13
13
|
* @returns Adjusted value
|
|
14
14
|
*/
|
|
15
15
|
static adjust(value: number, adjust?: number): number;
|
|
16
|
-
/**
|
|
17
|
-
* Get HEX or RGB colors
|
|
18
|
-
* @param init Initial color
|
|
19
|
-
* @param factor Increase factor
|
|
20
|
-
* @param hex to HEX or not
|
|
21
|
-
* @returns Result
|
|
22
|
-
*/
|
|
23
|
-
static getColors(init?: string, factor?: number, hex?: boolean): string[];
|
|
24
|
-
/**
|
|
25
|
-
* Get EColors
|
|
26
|
-
* @param init Initial color
|
|
27
|
-
* @param factor Increase factor
|
|
28
|
-
* @returns Result
|
|
29
|
-
*/
|
|
30
|
-
static getEColors(init?: string, factor?: number): EColor[];
|
|
31
16
|
/**
|
|
32
17
|
* HEX string to integer value
|
|
33
18
|
* @param hex HEX string
|
|
@@ -55,7 +40,7 @@ export declare class EColor {
|
|
|
55
40
|
*/
|
|
56
41
|
constructor(r: number, g: number, b: number, alpha?: number | undefined);
|
|
57
42
|
/**
|
|
58
|
-
* Clone color with
|
|
43
|
+
* Clone color with adjustments
|
|
59
44
|
* @param adjustR Adjust R value
|
|
60
45
|
* @param adjustG Adjust G value
|
|
61
46
|
* @param adjustB Adjust B value
|
|
@@ -63,14 +48,41 @@ export declare class EColor {
|
|
|
63
48
|
*/
|
|
64
49
|
clone(adjustR?: number, adjustG?: number, adjustB?: number, alpha?: number): EColor | undefined;
|
|
65
50
|
/**
|
|
66
|
-
*
|
|
67
|
-
* @param
|
|
68
|
-
|
|
51
|
+
* Get contrast ratio, a value between 0 and 1
|
|
52
|
+
* @param color Contrast color
|
|
53
|
+
*/
|
|
54
|
+
getContrastRatio(color: EColor): number;
|
|
55
|
+
/**
|
|
56
|
+
* Get Delta value (perceptible by human eyes)
|
|
57
|
+
* <= 1, Not perceptible by human eyes
|
|
58
|
+
* 1 - 2, Perceptible through close observation
|
|
59
|
+
* 2 - 10, Perceptible at a glance
|
|
60
|
+
* 11 - 49, Colors are more similar than opposite
|
|
61
|
+
* 100+, Colors are exact opposite
|
|
62
|
+
* @param color Contrast color
|
|
63
|
+
* @returns Value
|
|
64
|
+
*/
|
|
65
|
+
getDeltaValue(color: EColor): number;
|
|
66
|
+
/**
|
|
67
|
+
* Get luminance
|
|
68
|
+
* Darker one has higher luminance
|
|
69
|
+
* https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
|
|
69
70
|
*/
|
|
70
|
-
|
|
71
|
+
getLuminance(): number;
|
|
71
72
|
/**
|
|
72
73
|
* To HEX color string
|
|
73
74
|
* @returns HEX color string
|
|
74
75
|
*/
|
|
75
76
|
toHEXColor(): string;
|
|
77
|
+
/**
|
|
78
|
+
* To Lab value
|
|
79
|
+
* @returns Lab value
|
|
80
|
+
*/
|
|
81
|
+
toLabValue(): [number, number, number];
|
|
82
|
+
/**
|
|
83
|
+
* To RGB color string
|
|
84
|
+
* @param alpha Alpha value, false means ignore it
|
|
85
|
+
* @returns RGB color string
|
|
86
|
+
*/
|
|
87
|
+
toRGBColor(alpha?: boolean | number): string;
|
|
76
88
|
}
|
package/lib/cjs/types/EColor.js
CHANGED
|
@@ -32,47 +32,6 @@ class EColor {
|
|
|
32
32
|
return value % 255;
|
|
33
33
|
return value;
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Get HEX or RGB colors
|
|
37
|
-
* @param init Initial color
|
|
38
|
-
* @param factor Increase factor
|
|
39
|
-
* @param hex to HEX or not
|
|
40
|
-
* @returns Result
|
|
41
|
-
*/
|
|
42
|
-
static getColors(init = '#000', factor = 51, hex = true) {
|
|
43
|
-
return EColor.getEColors(init, factor).map((c) => hex ? c.toHEXColor() : c.toRGBColor());
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Get EColors
|
|
47
|
-
* @param init Initial color
|
|
48
|
-
* @param factor Increase factor
|
|
49
|
-
* @returns Result
|
|
50
|
-
*/
|
|
51
|
-
static getEColors(init = '#000', factor = 51) {
|
|
52
|
-
var _a;
|
|
53
|
-
// Init color
|
|
54
|
-
const initColor = (_a = EColor.parse(init)) !== null && _a !== void 0 ? _a : new EColor(0, 0, 0);
|
|
55
|
-
// Factors elements
|
|
56
|
-
// 51 = '00', '33', '66', '99', 'cc', 'ff'
|
|
57
|
-
const factors = [];
|
|
58
|
-
let f = 0;
|
|
59
|
-
while (f <= 255) {
|
|
60
|
-
factors.push(f);
|
|
61
|
-
f += factor;
|
|
62
|
-
}
|
|
63
|
-
// RGB loop
|
|
64
|
-
const colors = [initColor];
|
|
65
|
-
for (const r of factors) {
|
|
66
|
-
for (const g of factors) {
|
|
67
|
-
for (const b of factors) {
|
|
68
|
-
const newColor = initColor.clone(r, g, b);
|
|
69
|
-
if (newColor)
|
|
70
|
-
colors.push(newColor);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return colors;
|
|
75
|
-
}
|
|
76
35
|
/**
|
|
77
36
|
* HEX string to integer value
|
|
78
37
|
* @param hex HEX string
|
|
@@ -98,7 +57,7 @@ class EColor {
|
|
|
98
57
|
// Null
|
|
99
58
|
if (htmlColor == null)
|
|
100
59
|
return undefined;
|
|
101
|
-
htmlColor = htmlColor.toUpperCase();
|
|
60
|
+
htmlColor = htmlColor.trim().toUpperCase();
|
|
102
61
|
// HEX color
|
|
103
62
|
if (htmlColor.startsWith('#')) {
|
|
104
63
|
htmlColor = htmlColor.substring(1);
|
|
@@ -124,7 +83,7 @@ class EColor {
|
|
|
124
83
|
return undefined;
|
|
125
84
|
}
|
|
126
85
|
/**
|
|
127
|
-
* Clone color with
|
|
86
|
+
* Clone color with adjustments
|
|
128
87
|
* @param adjustR Adjust R value
|
|
129
88
|
* @param adjustG Adjust G value
|
|
130
89
|
* @param adjustB Adjust B value
|
|
@@ -142,17 +101,60 @@ class EColor {
|
|
|
142
101
|
return new EColor(r, g, b, alpha);
|
|
143
102
|
}
|
|
144
103
|
/**
|
|
145
|
-
*
|
|
146
|
-
* @param
|
|
147
|
-
* @returns RGB color string
|
|
104
|
+
* Get contrast ratio, a value between 0 and 1
|
|
105
|
+
* @param color Contrast color
|
|
148
106
|
*/
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
107
|
+
getContrastRatio(color) {
|
|
108
|
+
const lum1 = this.getLuminance();
|
|
109
|
+
const lum2 = color.getLuminance();
|
|
110
|
+
const brightest = Math.max(lum1, lum2);
|
|
111
|
+
const darkest = Math.min(lum1, lum2);
|
|
112
|
+
return (brightest + 0.05) / (darkest + 0.05);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get Delta value (perceptible by human eyes)
|
|
116
|
+
* <= 1, Not perceptible by human eyes
|
|
117
|
+
* 1 - 2, Perceptible through close observation
|
|
118
|
+
* 2 - 10, Perceptible at a glance
|
|
119
|
+
* 11 - 49, Colors are more similar than opposite
|
|
120
|
+
* 100+, Colors are exact opposite
|
|
121
|
+
* @param color Contrast color
|
|
122
|
+
* @returns Value
|
|
123
|
+
*/
|
|
124
|
+
getDeltaValue(color) {
|
|
125
|
+
const labA = this.toLabValue();
|
|
126
|
+
const labB = color.toLabValue();
|
|
127
|
+
const deltaL = labA[0] - labB[0];
|
|
128
|
+
const deltaA = labA[1] - labB[1];
|
|
129
|
+
const deltaB = labA[2] - labB[2];
|
|
130
|
+
const c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
|
|
131
|
+
const c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
|
|
132
|
+
const deltaC = c1 - c2;
|
|
133
|
+
let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
|
|
134
|
+
deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
|
|
135
|
+
const sc = 1.0 + 0.045 * c1;
|
|
136
|
+
const sh = 1.0 + 0.015 * c1;
|
|
137
|
+
const deltaLKlsl = deltaL / 1.0;
|
|
138
|
+
const deltaCkcsc = deltaC / sc;
|
|
139
|
+
const deltaHkhsh = deltaH / sh;
|
|
140
|
+
const i = deltaLKlsl * deltaLKlsl +
|
|
141
|
+
deltaCkcsc * deltaCkcsc +
|
|
142
|
+
deltaHkhsh * deltaHkhsh;
|
|
143
|
+
return i < 0 ? 0 : Math.sqrt(i);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get luminance
|
|
147
|
+
* Darker one has higher luminance
|
|
148
|
+
* https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
|
|
149
|
+
*/
|
|
150
|
+
getLuminance() {
|
|
151
|
+
const a = [this.r, this.g, this.b].map((v) => {
|
|
152
|
+
v /= 255;
|
|
153
|
+
return v <= 0.03928
|
|
154
|
+
? v / 12.92
|
|
155
|
+
: Math.pow((v + 0.055) / 1.055, 2.4);
|
|
156
|
+
});
|
|
157
|
+
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
|
156
158
|
}
|
|
157
159
|
/**
|
|
158
160
|
* To HEX color string
|
|
@@ -161,5 +163,44 @@ class EColor {
|
|
|
161
163
|
toHEXColor() {
|
|
162
164
|
return `#${EColor.toHex(this.r)}${EColor.toHex(this.g)}${EColor.toHex(this.b)}`;
|
|
163
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* To Lab value
|
|
168
|
+
* @returns Lab value
|
|
169
|
+
*/
|
|
170
|
+
toLabValue() {
|
|
171
|
+
let r = this.r / 255, g = this.g / 255, b = this.b / 255, x, y, z;
|
|
172
|
+
r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
|
|
173
|
+
g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
|
|
174
|
+
b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
|
|
175
|
+
x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
|
|
176
|
+
y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.0;
|
|
177
|
+
z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
|
|
178
|
+
x = x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116;
|
|
179
|
+
y = y > 0.008856 ? Math.pow(y, 1 / 3) : 7.787 * y + 16 / 116;
|
|
180
|
+
z = z > 0.008856 ? Math.pow(z, 1 / 3) : 7.787 * z + 16 / 116;
|
|
181
|
+
return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* To RGB color string
|
|
185
|
+
* @param alpha Alpha value, false means ignore it
|
|
186
|
+
* @returns RGB color string
|
|
187
|
+
*/
|
|
188
|
+
toRGBColor(alpha) {
|
|
189
|
+
// Decide
|
|
190
|
+
let includeAlpha, alphaValue = this.alpha;
|
|
191
|
+
if (typeof alpha === 'number') {
|
|
192
|
+
alphaValue = alpha;
|
|
193
|
+
includeAlpha = true;
|
|
194
|
+
}
|
|
195
|
+
else if (alpha == null) {
|
|
196
|
+
includeAlpha = this.alpha != null;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
includeAlpha = alpha;
|
|
200
|
+
}
|
|
201
|
+
if (includeAlpha)
|
|
202
|
+
return `RGBA(${this.r}, ${this.g}, ${this.b}, ${alphaValue !== null && alphaValue !== void 0 ? alphaValue : 1})`;
|
|
203
|
+
return `RGB(${this.r}, ${this.g}, ${this.b})`;
|
|
204
|
+
}
|
|
164
205
|
}
|
|
165
206
|
exports.EColor = EColor;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { EColor } from './types/EColor';
|
|
2
|
+
/**
|
|
3
|
+
* Color utils
|
|
4
|
+
*/
|
|
5
|
+
export declare namespace ColorUtils {
|
|
6
|
+
/**
|
|
7
|
+
* Get HEX or RGB colors
|
|
8
|
+
* @param init Initial color
|
|
9
|
+
* @param factor Increase factor
|
|
10
|
+
* @param adjustOrder Adjust order to increase difference
|
|
11
|
+
* @param hex to HEX or not
|
|
12
|
+
* @returns Result
|
|
13
|
+
*/
|
|
14
|
+
function getColors(init?: string, factor?: number, adjustOrder?: boolean, hex?: boolean): string[];
|
|
15
|
+
/**
|
|
16
|
+
* Get EColors
|
|
17
|
+
* @param init Initial color
|
|
18
|
+
* @param factor Increase factor
|
|
19
|
+
* @param adjustOrder Adjust order to increase difference
|
|
20
|
+
* @returns Result
|
|
21
|
+
*/
|
|
22
|
+
function getEColors(init?: string, factor?: number, adjustOrder?: boolean): EColor[];
|
|
23
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { EColor } from './types/EColor';
|
|
2
|
+
/**
|
|
3
|
+
* Color utils
|
|
4
|
+
*/
|
|
5
|
+
export var ColorUtils;
|
|
6
|
+
(function (ColorUtils) {
|
|
7
|
+
/**
|
|
8
|
+
* Get HEX or RGB colors
|
|
9
|
+
* @param init Initial color
|
|
10
|
+
* @param factor Increase factor
|
|
11
|
+
* @param adjustOrder Adjust order to increase difference
|
|
12
|
+
* @param hex to HEX or not
|
|
13
|
+
* @returns Result
|
|
14
|
+
*/
|
|
15
|
+
function getColors(init = '#000', factor = 51, adjustOrder = true, hex = true) {
|
|
16
|
+
return getEColors(init, factor, adjustOrder).map((c) => hex ? c.toHEXColor() : c.toRGBColor());
|
|
17
|
+
}
|
|
18
|
+
ColorUtils.getColors = getColors;
|
|
19
|
+
/**
|
|
20
|
+
* Get EColors
|
|
21
|
+
* @param init Initial color
|
|
22
|
+
* @param factor Increase factor
|
|
23
|
+
* @param adjustOrder Adjust order to increase difference
|
|
24
|
+
* @returns Result
|
|
25
|
+
*/
|
|
26
|
+
function getEColors(init = '#000', factor = 51, adjustOrder = true) {
|
|
27
|
+
var _a;
|
|
28
|
+
// Init color
|
|
29
|
+
const initColor = (_a = EColor.parse(init)) !== null && _a !== void 0 ? _a : new EColor(0, 0, 0);
|
|
30
|
+
// Factors elements
|
|
31
|
+
// 51 = '00', '33', '66', '99', 'cc', 'ff'
|
|
32
|
+
const factors = [];
|
|
33
|
+
let f = 0;
|
|
34
|
+
while (f <= 255) {
|
|
35
|
+
factors.push(f);
|
|
36
|
+
f += factor;
|
|
37
|
+
}
|
|
38
|
+
// RGB loop
|
|
39
|
+
const colors = [initColor];
|
|
40
|
+
for (const r of factors) {
|
|
41
|
+
for (const g of factors) {
|
|
42
|
+
for (const b of factors) {
|
|
43
|
+
colors.push(initColor.clone(r, g, b));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Non-nullable colors
|
|
48
|
+
const nColors = colors.filter((color) => color != null);
|
|
49
|
+
// Adjust order
|
|
50
|
+
if (adjustOrder) {
|
|
51
|
+
const firstColor = nColors.shift();
|
|
52
|
+
if (firstColor) {
|
|
53
|
+
let color = firstColor;
|
|
54
|
+
const newColors = [color];
|
|
55
|
+
while (nColors.length > 0) {
|
|
56
|
+
const result = nColors.reduce((p, c, index) => {
|
|
57
|
+
const delta = color.getDeltaValue(c);
|
|
58
|
+
if (delta != null && delta > p.delta) {
|
|
59
|
+
p.delta = delta;
|
|
60
|
+
p.color = c;
|
|
61
|
+
p.index = index;
|
|
62
|
+
}
|
|
63
|
+
return p;
|
|
64
|
+
}, { delta: 0, color, index: -1 });
|
|
65
|
+
if (result.delta > 0) {
|
|
66
|
+
color = result.color;
|
|
67
|
+
newColors.push(color);
|
|
68
|
+
nColors.splice(result.index, 1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return newColors;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return nColors;
|
|
75
|
+
}
|
|
76
|
+
ColorUtils.getEColors = getEColors;
|
|
77
|
+
})(ColorUtils || (ColorUtils = {}));
|
package/lib/mjs/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './types/FormData';
|
|
|
4
4
|
export * from './storage/IStorage';
|
|
5
5
|
export * from './storage/WindowStorage';
|
|
6
6
|
export * from './DataTypes';
|
|
7
|
+
export * from './ColorUtils';
|
|
7
8
|
export * from './DateUtils';
|
|
8
9
|
export * from './DomUtils';
|
|
9
10
|
export * from './ExtendUtils';
|
package/lib/mjs/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './types/FormData';
|
|
|
4
4
|
export * from './storage/IStorage';
|
|
5
5
|
export * from './storage/WindowStorage';
|
|
6
6
|
export * from './DataTypes';
|
|
7
|
+
export * from './ColorUtils';
|
|
7
8
|
export * from './DateUtils';
|
|
8
9
|
export * from './DomUtils';
|
|
9
10
|
export * from './ExtendUtils';
|
|
@@ -13,21 +13,6 @@ export declare class EColor {
|
|
|
13
13
|
* @returns Adjusted value
|
|
14
14
|
*/
|
|
15
15
|
static adjust(value: number, adjust?: number): number;
|
|
16
|
-
/**
|
|
17
|
-
* Get HEX or RGB colors
|
|
18
|
-
* @param init Initial color
|
|
19
|
-
* @param factor Increase factor
|
|
20
|
-
* @param hex to HEX or not
|
|
21
|
-
* @returns Result
|
|
22
|
-
*/
|
|
23
|
-
static getColors(init?: string, factor?: number, hex?: boolean): string[];
|
|
24
|
-
/**
|
|
25
|
-
* Get EColors
|
|
26
|
-
* @param init Initial color
|
|
27
|
-
* @param factor Increase factor
|
|
28
|
-
* @returns Result
|
|
29
|
-
*/
|
|
30
|
-
static getEColors(init?: string, factor?: number): EColor[];
|
|
31
16
|
/**
|
|
32
17
|
* HEX string to integer value
|
|
33
18
|
* @param hex HEX string
|
|
@@ -55,7 +40,7 @@ export declare class EColor {
|
|
|
55
40
|
*/
|
|
56
41
|
constructor(r: number, g: number, b: number, alpha?: number | undefined);
|
|
57
42
|
/**
|
|
58
|
-
* Clone color with
|
|
43
|
+
* Clone color with adjustments
|
|
59
44
|
* @param adjustR Adjust R value
|
|
60
45
|
* @param adjustG Adjust G value
|
|
61
46
|
* @param adjustB Adjust B value
|
|
@@ -63,14 +48,41 @@ export declare class EColor {
|
|
|
63
48
|
*/
|
|
64
49
|
clone(adjustR?: number, adjustG?: number, adjustB?: number, alpha?: number): EColor | undefined;
|
|
65
50
|
/**
|
|
66
|
-
*
|
|
67
|
-
* @param
|
|
68
|
-
|
|
51
|
+
* Get contrast ratio, a value between 0 and 1
|
|
52
|
+
* @param color Contrast color
|
|
53
|
+
*/
|
|
54
|
+
getContrastRatio(color: EColor): number;
|
|
55
|
+
/**
|
|
56
|
+
* Get Delta value (perceptible by human eyes)
|
|
57
|
+
* <= 1, Not perceptible by human eyes
|
|
58
|
+
* 1 - 2, Perceptible through close observation
|
|
59
|
+
* 2 - 10, Perceptible at a glance
|
|
60
|
+
* 11 - 49, Colors are more similar than opposite
|
|
61
|
+
* 100+, Colors are exact opposite
|
|
62
|
+
* @param color Contrast color
|
|
63
|
+
* @returns Value
|
|
64
|
+
*/
|
|
65
|
+
getDeltaValue(color: EColor): number;
|
|
66
|
+
/**
|
|
67
|
+
* Get luminance
|
|
68
|
+
* Darker one has higher luminance
|
|
69
|
+
* https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
|
|
69
70
|
*/
|
|
70
|
-
|
|
71
|
+
getLuminance(): number;
|
|
71
72
|
/**
|
|
72
73
|
* To HEX color string
|
|
73
74
|
* @returns HEX color string
|
|
74
75
|
*/
|
|
75
76
|
toHEXColor(): string;
|
|
77
|
+
/**
|
|
78
|
+
* To Lab value
|
|
79
|
+
* @returns Lab value
|
|
80
|
+
*/
|
|
81
|
+
toLabValue(): [number, number, number];
|
|
82
|
+
/**
|
|
83
|
+
* To RGB color string
|
|
84
|
+
* @param alpha Alpha value, false means ignore it
|
|
85
|
+
* @returns RGB color string
|
|
86
|
+
*/
|
|
87
|
+
toRGBColor(alpha?: boolean | number): string;
|
|
76
88
|
}
|
package/lib/mjs/types/EColor.js
CHANGED
|
@@ -29,47 +29,6 @@ export class EColor {
|
|
|
29
29
|
return value % 255;
|
|
30
30
|
return value;
|
|
31
31
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Get HEX or RGB colors
|
|
34
|
-
* @param init Initial color
|
|
35
|
-
* @param factor Increase factor
|
|
36
|
-
* @param hex to HEX or not
|
|
37
|
-
* @returns Result
|
|
38
|
-
*/
|
|
39
|
-
static getColors(init = '#000', factor = 51, hex = true) {
|
|
40
|
-
return EColor.getEColors(init, factor).map((c) => hex ? c.toHEXColor() : c.toRGBColor());
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Get EColors
|
|
44
|
-
* @param init Initial color
|
|
45
|
-
* @param factor Increase factor
|
|
46
|
-
* @returns Result
|
|
47
|
-
*/
|
|
48
|
-
static getEColors(init = '#000', factor = 51) {
|
|
49
|
-
var _a;
|
|
50
|
-
// Init color
|
|
51
|
-
const initColor = (_a = EColor.parse(init)) !== null && _a !== void 0 ? _a : new EColor(0, 0, 0);
|
|
52
|
-
// Factors elements
|
|
53
|
-
// 51 = '00', '33', '66', '99', 'cc', 'ff'
|
|
54
|
-
const factors = [];
|
|
55
|
-
let f = 0;
|
|
56
|
-
while (f <= 255) {
|
|
57
|
-
factors.push(f);
|
|
58
|
-
f += factor;
|
|
59
|
-
}
|
|
60
|
-
// RGB loop
|
|
61
|
-
const colors = [initColor];
|
|
62
|
-
for (const r of factors) {
|
|
63
|
-
for (const g of factors) {
|
|
64
|
-
for (const b of factors) {
|
|
65
|
-
const newColor = initColor.clone(r, g, b);
|
|
66
|
-
if (newColor)
|
|
67
|
-
colors.push(newColor);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return colors;
|
|
72
|
-
}
|
|
73
32
|
/**
|
|
74
33
|
* HEX string to integer value
|
|
75
34
|
* @param hex HEX string
|
|
@@ -95,7 +54,7 @@ export class EColor {
|
|
|
95
54
|
// Null
|
|
96
55
|
if (htmlColor == null)
|
|
97
56
|
return undefined;
|
|
98
|
-
htmlColor = htmlColor.toUpperCase();
|
|
57
|
+
htmlColor = htmlColor.trim().toUpperCase();
|
|
99
58
|
// HEX color
|
|
100
59
|
if (htmlColor.startsWith('#')) {
|
|
101
60
|
htmlColor = htmlColor.substring(1);
|
|
@@ -121,7 +80,7 @@ export class EColor {
|
|
|
121
80
|
return undefined;
|
|
122
81
|
}
|
|
123
82
|
/**
|
|
124
|
-
* Clone color with
|
|
83
|
+
* Clone color with adjustments
|
|
125
84
|
* @param adjustR Adjust R value
|
|
126
85
|
* @param adjustG Adjust G value
|
|
127
86
|
* @param adjustB Adjust B value
|
|
@@ -139,17 +98,60 @@ export class EColor {
|
|
|
139
98
|
return new EColor(r, g, b, alpha);
|
|
140
99
|
}
|
|
141
100
|
/**
|
|
142
|
-
*
|
|
143
|
-
* @param
|
|
144
|
-
* @returns RGB color string
|
|
101
|
+
* Get contrast ratio, a value between 0 and 1
|
|
102
|
+
* @param color Contrast color
|
|
145
103
|
*/
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
104
|
+
getContrastRatio(color) {
|
|
105
|
+
const lum1 = this.getLuminance();
|
|
106
|
+
const lum2 = color.getLuminance();
|
|
107
|
+
const brightest = Math.max(lum1, lum2);
|
|
108
|
+
const darkest = Math.min(lum1, lum2);
|
|
109
|
+
return (brightest + 0.05) / (darkest + 0.05);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get Delta value (perceptible by human eyes)
|
|
113
|
+
* <= 1, Not perceptible by human eyes
|
|
114
|
+
* 1 - 2, Perceptible through close observation
|
|
115
|
+
* 2 - 10, Perceptible at a glance
|
|
116
|
+
* 11 - 49, Colors are more similar than opposite
|
|
117
|
+
* 100+, Colors are exact opposite
|
|
118
|
+
* @param color Contrast color
|
|
119
|
+
* @returns Value
|
|
120
|
+
*/
|
|
121
|
+
getDeltaValue(color) {
|
|
122
|
+
const labA = this.toLabValue();
|
|
123
|
+
const labB = color.toLabValue();
|
|
124
|
+
const deltaL = labA[0] - labB[0];
|
|
125
|
+
const deltaA = labA[1] - labB[1];
|
|
126
|
+
const deltaB = labA[2] - labB[2];
|
|
127
|
+
const c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
|
|
128
|
+
const c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
|
|
129
|
+
const deltaC = c1 - c2;
|
|
130
|
+
let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
|
|
131
|
+
deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
|
|
132
|
+
const sc = 1.0 + 0.045 * c1;
|
|
133
|
+
const sh = 1.0 + 0.015 * c1;
|
|
134
|
+
const deltaLKlsl = deltaL / 1.0;
|
|
135
|
+
const deltaCkcsc = deltaC / sc;
|
|
136
|
+
const deltaHkhsh = deltaH / sh;
|
|
137
|
+
const i = deltaLKlsl * deltaLKlsl +
|
|
138
|
+
deltaCkcsc * deltaCkcsc +
|
|
139
|
+
deltaHkhsh * deltaHkhsh;
|
|
140
|
+
return i < 0 ? 0 : Math.sqrt(i);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Get luminance
|
|
144
|
+
* Darker one has higher luminance
|
|
145
|
+
* https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
|
|
146
|
+
*/
|
|
147
|
+
getLuminance() {
|
|
148
|
+
const a = [this.r, this.g, this.b].map((v) => {
|
|
149
|
+
v /= 255;
|
|
150
|
+
return v <= 0.03928
|
|
151
|
+
? v / 12.92
|
|
152
|
+
: Math.pow((v + 0.055) / 1.055, 2.4);
|
|
153
|
+
});
|
|
154
|
+
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
|
153
155
|
}
|
|
154
156
|
/**
|
|
155
157
|
* To HEX color string
|
|
@@ -158,4 +160,43 @@ export class EColor {
|
|
|
158
160
|
toHEXColor() {
|
|
159
161
|
return `#${EColor.toHex(this.r)}${EColor.toHex(this.g)}${EColor.toHex(this.b)}`;
|
|
160
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* To Lab value
|
|
165
|
+
* @returns Lab value
|
|
166
|
+
*/
|
|
167
|
+
toLabValue() {
|
|
168
|
+
let r = this.r / 255, g = this.g / 255, b = this.b / 255, x, y, z;
|
|
169
|
+
r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
|
|
170
|
+
g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
|
|
171
|
+
b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
|
|
172
|
+
x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
|
|
173
|
+
y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.0;
|
|
174
|
+
z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
|
|
175
|
+
x = x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116;
|
|
176
|
+
y = y > 0.008856 ? Math.pow(y, 1 / 3) : 7.787 * y + 16 / 116;
|
|
177
|
+
z = z > 0.008856 ? Math.pow(z, 1 / 3) : 7.787 * z + 16 / 116;
|
|
178
|
+
return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* To RGB color string
|
|
182
|
+
* @param alpha Alpha value, false means ignore it
|
|
183
|
+
* @returns RGB color string
|
|
184
|
+
*/
|
|
185
|
+
toRGBColor(alpha) {
|
|
186
|
+
// Decide
|
|
187
|
+
let includeAlpha, alphaValue = this.alpha;
|
|
188
|
+
if (typeof alpha === 'number') {
|
|
189
|
+
alphaValue = alpha;
|
|
190
|
+
includeAlpha = true;
|
|
191
|
+
}
|
|
192
|
+
else if (alpha == null) {
|
|
193
|
+
includeAlpha = this.alpha != null;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
includeAlpha = alpha;
|
|
197
|
+
}
|
|
198
|
+
if (includeAlpha)
|
|
199
|
+
return `RGBA(${this.r}, ${this.g}, ${this.b}, ${alphaValue !== null && alphaValue !== void 0 ? alphaValue : 1})`;
|
|
200
|
+
return `RGB(${this.r}, ${this.g}, ${this.b})`;
|
|
201
|
+
}
|
|
161
202
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/shared",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.18",
|
|
4
4
|
"description": "TypeScript shared utilities and functions",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/mjs/index.js",
|
|
@@ -55,13 +55,13 @@
|
|
|
55
55
|
"dependencies": {},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/jest": "^27.4.1",
|
|
58
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
59
|
-
"@typescript-eslint/parser": "^5.
|
|
60
|
-
"eslint": "^8.
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^5.16.0",
|
|
59
|
+
"@typescript-eslint/parser": "^5.16.0",
|
|
60
|
+
"eslint": "^8.11.0",
|
|
61
61
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
62
62
|
"eslint-plugin-import": "^2.25.4",
|
|
63
63
|
"jest": "^27.5.1",
|
|
64
|
-
"ts-jest": "^27.1.
|
|
65
|
-
"typescript": "^4.6.
|
|
64
|
+
"ts-jest": "^27.1.4",
|
|
65
|
+
"typescript": "^4.6.3"
|
|
66
66
|
}
|
|
67
67
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { EColor } from './types/EColor';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Color utils
|
|
5
|
+
*/
|
|
6
|
+
export namespace ColorUtils {
|
|
7
|
+
/**
|
|
8
|
+
* Get HEX or RGB colors
|
|
9
|
+
* @param init Initial color
|
|
10
|
+
* @param factor Increase factor
|
|
11
|
+
* @param adjustOrder Adjust order to increase difference
|
|
12
|
+
* @param hex to HEX or not
|
|
13
|
+
* @returns Result
|
|
14
|
+
*/
|
|
15
|
+
export function getColors(
|
|
16
|
+
init: string = '#000',
|
|
17
|
+
factor: number = 51,
|
|
18
|
+
adjustOrder: boolean = true,
|
|
19
|
+
hex: boolean = true
|
|
20
|
+
) {
|
|
21
|
+
return getEColors(init, factor, adjustOrder).map((c) =>
|
|
22
|
+
hex ? c.toHEXColor() : c.toRGBColor()
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get EColors
|
|
28
|
+
* @param init Initial color
|
|
29
|
+
* @param factor Increase factor
|
|
30
|
+
* @param adjustOrder Adjust order to increase difference
|
|
31
|
+
* @returns Result
|
|
32
|
+
*/
|
|
33
|
+
export function getEColors(
|
|
34
|
+
init: string = '#000',
|
|
35
|
+
factor: number = 51,
|
|
36
|
+
adjustOrder: boolean = true
|
|
37
|
+
): EColor[] {
|
|
38
|
+
// Init color
|
|
39
|
+
const initColor = EColor.parse(init) ?? new EColor(0, 0, 0);
|
|
40
|
+
|
|
41
|
+
// Factors elements
|
|
42
|
+
// 51 = '00', '33', '66', '99', 'cc', 'ff'
|
|
43
|
+
const factors: number[] = [];
|
|
44
|
+
let f = 0;
|
|
45
|
+
while (f <= 255) {
|
|
46
|
+
factors.push(f);
|
|
47
|
+
f += factor;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// RGB loop
|
|
51
|
+
const colors: (EColor | undefined)[] = [initColor];
|
|
52
|
+
for (const r of factors) {
|
|
53
|
+
for (const g of factors) {
|
|
54
|
+
for (const b of factors) {
|
|
55
|
+
colors.push(initColor.clone(r, g, b));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Non-nullable colors
|
|
61
|
+
const nColors = colors.filter(
|
|
62
|
+
(color): color is EColor => color != null
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Adjust order
|
|
66
|
+
if (adjustOrder) {
|
|
67
|
+
const firstColor = nColors.shift();
|
|
68
|
+
if (firstColor) {
|
|
69
|
+
let color = firstColor;
|
|
70
|
+
const newColors: EColor[] = [color];
|
|
71
|
+
|
|
72
|
+
while (nColors.length > 0) {
|
|
73
|
+
const result = nColors.reduce(
|
|
74
|
+
(p, c, index) => {
|
|
75
|
+
const delta = color.getDeltaValue(c);
|
|
76
|
+
if (delta != null && delta > p.delta) {
|
|
77
|
+
p.delta = delta;
|
|
78
|
+
p.color = c;
|
|
79
|
+
p.index = index;
|
|
80
|
+
}
|
|
81
|
+
return p;
|
|
82
|
+
},
|
|
83
|
+
{ delta: 0, color, index: -1 }
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
if (result.delta > 0) {
|
|
87
|
+
color = result.color;
|
|
88
|
+
newColors.push(color);
|
|
89
|
+
nColors.splice(result.index, 1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return newColors;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return nColors;
|
|
98
|
+
}
|
|
99
|
+
}
|
package/src/index.ts
CHANGED
package/src/types/EColor.ts
CHANGED
|
@@ -15,53 +15,6 @@ export class EColor {
|
|
|
15
15
|
return value;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* Get HEX or RGB colors
|
|
20
|
-
* @param init Initial color
|
|
21
|
-
* @param factor Increase factor
|
|
22
|
-
* @param hex to HEX or not
|
|
23
|
-
* @returns Result
|
|
24
|
-
*/
|
|
25
|
-
static getColors(init = '#000', factor: number = 51, hex: boolean = true) {
|
|
26
|
-
return EColor.getEColors(init, factor).map((c) =>
|
|
27
|
-
hex ? c.toHEXColor() : c.toRGBColor()
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Get EColors
|
|
33
|
-
* @param init Initial color
|
|
34
|
-
* @param factor Increase factor
|
|
35
|
-
* @returns Result
|
|
36
|
-
*/
|
|
37
|
-
static getEColors(init = '#000', factor: number = 51): EColor[] {
|
|
38
|
-
// Init color
|
|
39
|
-
const initColor = EColor.parse(init) ?? new EColor(0, 0, 0);
|
|
40
|
-
|
|
41
|
-
// Factors elements
|
|
42
|
-
// 51 = '00', '33', '66', '99', 'cc', 'ff'
|
|
43
|
-
const factors: number[] = [];
|
|
44
|
-
let f = 0;
|
|
45
|
-
while (f <= 255) {
|
|
46
|
-
factors.push(f);
|
|
47
|
-
f += factor;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// RGB loop
|
|
51
|
-
const colors: EColor[] = [initColor];
|
|
52
|
-
|
|
53
|
-
for (const r of factors) {
|
|
54
|
-
for (const g of factors) {
|
|
55
|
-
for (const b of factors) {
|
|
56
|
-
const newColor = initColor.clone(r, g, b);
|
|
57
|
-
if (newColor) colors.push(newColor);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return colors;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
18
|
/**
|
|
66
19
|
* HEX string to integer value
|
|
67
20
|
* @param hex HEX string
|
|
@@ -88,7 +41,7 @@ export class EColor {
|
|
|
88
41
|
static parse(htmlColor?: string | null): EColor | undefined {
|
|
89
42
|
// Null
|
|
90
43
|
if (htmlColor == null) return undefined;
|
|
91
|
-
htmlColor = htmlColor.toUpperCase();
|
|
44
|
+
htmlColor = htmlColor.trim().toUpperCase();
|
|
92
45
|
|
|
93
46
|
// HEX color
|
|
94
47
|
if (htmlColor.startsWith('#')) {
|
|
@@ -143,7 +96,7 @@ export class EColor {
|
|
|
143
96
|
) {}
|
|
144
97
|
|
|
145
98
|
/**
|
|
146
|
-
* Clone color with
|
|
99
|
+
* Clone color with adjustments
|
|
147
100
|
* @param adjustR Adjust R value
|
|
148
101
|
* @param adjustG Adjust G value
|
|
149
102
|
* @param adjustB Adjust B value
|
|
@@ -169,18 +122,63 @@ export class EColor {
|
|
|
169
122
|
}
|
|
170
123
|
|
|
171
124
|
/**
|
|
172
|
-
*
|
|
173
|
-
* @param
|
|
174
|
-
* @returns RGB color string
|
|
125
|
+
* Get contrast ratio, a value between 0 and 1
|
|
126
|
+
* @param color Contrast color
|
|
175
127
|
*/
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
128
|
+
getContrastRatio(color: EColor) {
|
|
129
|
+
const lum1 = this.getLuminance();
|
|
130
|
+
const lum2 = color.getLuminance();
|
|
131
|
+
const brightest = Math.max(lum1, lum2);
|
|
132
|
+
const darkest = Math.min(lum1, lum2);
|
|
133
|
+
return (brightest + 0.05) / (darkest + 0.05);
|
|
134
|
+
}
|
|
179
135
|
|
|
180
|
-
|
|
181
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Get Delta value (perceptible by human eyes)
|
|
138
|
+
* <= 1, Not perceptible by human eyes
|
|
139
|
+
* 1 - 2, Perceptible through close observation
|
|
140
|
+
* 2 - 10, Perceptible at a glance
|
|
141
|
+
* 11 - 49, Colors are more similar than opposite
|
|
142
|
+
* 100+, Colors are exact opposite
|
|
143
|
+
* @param color Contrast color
|
|
144
|
+
* @returns Value
|
|
145
|
+
*/
|
|
146
|
+
getDeltaValue(color: EColor) {
|
|
147
|
+
const labA = this.toLabValue();
|
|
148
|
+
const labB = color.toLabValue();
|
|
149
|
+
const deltaL = labA[0] - labB[0];
|
|
150
|
+
const deltaA = labA[1] - labB[1];
|
|
151
|
+
const deltaB = labA[2] - labB[2];
|
|
152
|
+
const c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
|
|
153
|
+
const c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
|
|
154
|
+
const deltaC = c1 - c2;
|
|
155
|
+
let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
|
|
156
|
+
deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
|
|
157
|
+
const sc = 1.0 + 0.045 * c1;
|
|
158
|
+
const sh = 1.0 + 0.015 * c1;
|
|
159
|
+
const deltaLKlsl = deltaL / 1.0;
|
|
160
|
+
const deltaCkcsc = deltaC / sc;
|
|
161
|
+
const deltaHkhsh = deltaH / sh;
|
|
162
|
+
const i =
|
|
163
|
+
deltaLKlsl * deltaLKlsl +
|
|
164
|
+
deltaCkcsc * deltaCkcsc +
|
|
165
|
+
deltaHkhsh * deltaHkhsh;
|
|
166
|
+
return i < 0 ? 0 : Math.sqrt(i);
|
|
167
|
+
}
|
|
182
168
|
|
|
183
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Get luminance
|
|
171
|
+
* Darker one has higher luminance
|
|
172
|
+
* https://dev.to/alvaromontoro/building-your-own-color-contrast-checker-4j7o
|
|
173
|
+
*/
|
|
174
|
+
getLuminance() {
|
|
175
|
+
const a = [this.r, this.g, this.b].map((v) => {
|
|
176
|
+
v /= 255;
|
|
177
|
+
return v <= 0.03928
|
|
178
|
+
? v / 12.92
|
|
179
|
+
: Math.pow((v + 0.055) / 1.055, 2.4);
|
|
180
|
+
});
|
|
181
|
+
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
|
184
182
|
}
|
|
185
183
|
|
|
186
184
|
/**
|
|
@@ -192,4 +190,52 @@ export class EColor {
|
|
|
192
190
|
this.b
|
|
193
191
|
)}`;
|
|
194
192
|
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* To Lab value
|
|
196
|
+
* @returns Lab value
|
|
197
|
+
*/
|
|
198
|
+
toLabValue(): [number, number, number] {
|
|
199
|
+
let r = this.r / 255,
|
|
200
|
+
g = this.g / 255,
|
|
201
|
+
b = this.b / 255,
|
|
202
|
+
x,
|
|
203
|
+
y,
|
|
204
|
+
z;
|
|
205
|
+
r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
|
|
206
|
+
g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
|
|
207
|
+
b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
|
|
208
|
+
x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
|
|
209
|
+
y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.0;
|
|
210
|
+
z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
|
|
211
|
+
x = x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787 * x + 16 / 116;
|
|
212
|
+
y = y > 0.008856 ? Math.pow(y, 1 / 3) : 7.787 * y + 16 / 116;
|
|
213
|
+
z = z > 0.008856 ? Math.pow(z, 1 / 3) : 7.787 * z + 16 / 116;
|
|
214
|
+
return [116 * y - 16, 500 * (x - y), 200 * (y - z)];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* To RGB color string
|
|
219
|
+
* @param alpha Alpha value, false means ignore it
|
|
220
|
+
* @returns RGB color string
|
|
221
|
+
*/
|
|
222
|
+
toRGBColor(alpha?: boolean | number) {
|
|
223
|
+
// Decide
|
|
224
|
+
let includeAlpha: boolean,
|
|
225
|
+
alphaValue: number | undefined = this.alpha;
|
|
226
|
+
|
|
227
|
+
if (typeof alpha === 'number') {
|
|
228
|
+
alphaValue = alpha;
|
|
229
|
+
includeAlpha = true;
|
|
230
|
+
} else if (alpha == null) {
|
|
231
|
+
includeAlpha = this.alpha != null;
|
|
232
|
+
} else {
|
|
233
|
+
includeAlpha = alpha;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (includeAlpha)
|
|
237
|
+
return `RGBA(${this.r}, ${this.g}, ${this.b}, ${alphaValue ?? 1})`;
|
|
238
|
+
|
|
239
|
+
return `RGB(${this.r}, ${this.g}, ${this.b})`;
|
|
240
|
+
}
|
|
195
241
|
}
|