-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(Color) Regex and color code cleanup and new color format support #8916
Changes from all commits
c26f998
9792c44
8db4286
048eb28
453248f
a962ce1
b3bca21
3eb2bf7
b445f9c
f17c216
979bfb3
29a5598
5a5c134
4d15b1c
89ccb5f
f3eadd8
ed671f0
77d2dbb
d4e98a5
649ba3c
02f0c5a
2406fa3
e3bfa4c
b648cb4
c78c568
43a2d1c
210a24a
fd75870
4b3693f
ed121bc
d90d07a
713a425
362879f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,7 +1,13 @@ | ||||||
import { ColorNameMap } from './color_map'; | ||||||
import { reHSLa, reHex, reRGBa } from './constants'; | ||||||
import type { TRGBAColorSource, TColorArg, TRGBColorSource } from './typedefs'; | ||||||
import { hue2rgb, hexify } from './util'; | ||||||
import type { TRGBAColorSource, TColorArg } from './typedefs'; | ||||||
import { | ||||||
hue2rgb, | ||||||
hexify, | ||||||
rgb2Hsl, | ||||||
fromAlphaToFloat, | ||||||
greyAverage, | ||||||
} from './util'; | ||||||
|
||||||
/** | ||||||
* @class Color common color operations | ||||||
|
@@ -47,46 +53,6 @@ export class Color { | |||||
([0, 0, 0, 1] as TRGBAColorSource); | ||||||
} | ||||||
|
||||||
/** | ||||||
* Adapted from {@link https://gist.github.com/mjackson/5311256 https://gist.github.com/mjackson} | ||||||
* @private | ||||||
* @param {Number} r Red color value | ||||||
* @param {Number} g Green color value | ||||||
* @param {Number} b Blue color value | ||||||
* @return {TRGBColorSource} Hsl color | ||||||
*/ | ||||||
_rgbToHsl(r: number, g: number, b: number): TRGBColorSource { | ||||||
r /= 255; | ||||||
g /= 255; | ||||||
b /= 255; | ||||||
const maxValue = Math.max(r, g, b), | ||||||
minValue = Math.min(r, g, b); | ||||||
|
||||||
let h!: number, s: number; | ||||||
const l = (maxValue + minValue) / 2; | ||||||
|
||||||
if (maxValue === minValue) { | ||||||
h = s = 0; // achromatic | ||||||
} else { | ||||||
const d = maxValue - minValue; | ||||||
s = l > 0.5 ? d / (2 - maxValue - minValue) : d / (maxValue + minValue); | ||||||
switch (maxValue) { | ||||||
case r: | ||||||
h = (g - b) / d + (g < b ? 6 : 0); | ||||||
break; | ||||||
case g: | ||||||
h = (b - r) / d + 2; | ||||||
break; | ||||||
case b: | ||||||
h = (r - g) / d + 4; | ||||||
break; | ||||||
} | ||||||
h /= 6; | ||||||
} | ||||||
|
||||||
return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)]; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1]) | ||||||
* @return {TRGBAColorSource} | ||||||
|
@@ -108,57 +74,52 @@ export class Color { | |||||
* @return {String} ex: rgb(0-255,0-255,0-255) | ||||||
*/ | ||||||
toRgb() { | ||||||
const source = this.getSource(); | ||||||
return `rgb(${source[0]},${source[1]},${source[2]})`; | ||||||
const [r, g, b] = this.getSource(); | ||||||
return `rgb(${r},${g},${b})`; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Returns color representation in RGBA format | ||||||
* @return {String} ex: rgba(0-255,0-255,0-255,0-1) | ||||||
*/ | ||||||
toRgba() { | ||||||
const source = this.getSource(); | ||||||
return `rgba(${source[0]},${source[1]},${source[2]},${source[3]})`; | ||||||
return `rgba(${this.getSource().join(',')})`; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Returns color representation in HSL format | ||||||
* @return {String} ex: hsl(0-360,0%-100%,0%-100%) | ||||||
*/ | ||||||
toHsl() { | ||||||
const source = this.getSource(), | ||||||
hsl = this._rgbToHsl(source[0], source[1], source[2]); | ||||||
|
||||||
return `hsl(${hsl[0]},${hsl[1]}%,${hsl[2]}%)`; | ||||||
const [h, s, l] = rgb2Hsl(...this.getSource()); | ||||||
return `hsl(${h},${s}%,${l}%)`; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Returns color representation in HSLA format | ||||||
* @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1) | ||||||
*/ | ||||||
toHsla() { | ||||||
const source = this.getSource(), | ||||||
hsl = this._rgbToHsl(source[0], source[1], source[2]); | ||||||
|
||||||
return `hsla(${hsl[0]},${hsl[1]}%,${hsl[2]}%,${source[3]})`; | ||||||
const [h, s, l, a] = rgb2Hsl(...this.getSource()); | ||||||
return `hsla(${h},${s}%,${l}%,${a})`; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Returns color representation in HEX format | ||||||
* @return {String} ex: FF5555 | ||||||
*/ | ||||||
toHex() { | ||||||
const [r, g, b] = this.getSource(); | ||||||
return `${hexify(r)}${hexify(g)}${hexify(b)}`; | ||||||
const fullHex = this.toHexa(); | ||||||
return fullHex.slice(0, 6); | ||||||
} | ||||||
|
||||||
/** | ||||||
* Returns color representation in HEXA format | ||||||
* @return {String} ex: FF5555CC | ||||||
*/ | ||||||
toHexa() { | ||||||
const source = this.getSource(); | ||||||
return `${this.toHex()}${hexify(Math.round(source[3] * 255))}`; | ||||||
const [r, g, b, a] = this.getSource(); | ||||||
return `${hexify(r)}${hexify(g)}${hexify(b)}${hexify(Math.round(a * 255))}`; | ||||||
} | ||||||
|
||||||
/** | ||||||
|
@@ -175,9 +136,7 @@ export class Color { | |||||
* @return {Color} thisArg | ||||||
*/ | ||||||
setAlpha(alpha: number) { | ||||||
const source = this.getSource(); | ||||||
source[3] = alpha; | ||||||
this.setSource(source); | ||||||
this._source[3] = alpha; | ||||||
return this; | ||||||
} | ||||||
|
||||||
|
@@ -186,13 +145,7 @@ export class Color { | |||||
* @return {Color} thisArg | ||||||
*/ | ||||||
toGrayscale() { | ||||||
const source = this.getSource(), | ||||||
average = parseInt( | ||||||
(source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), | ||||||
10 | ||||||
), | ||||||
currentAlpha = source[3]; | ||||||
this.setSource([average, average, average, currentAlpha]); | ||||||
this.setSource(greyAverage(this.getSource())); | ||||||
return this; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not very related, but since I am reviewing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this would be a possible change, and we can do that outside the cleanup/refactor scope. |
||||||
} | ||||||
|
||||||
|
@@ -202,14 +155,9 @@ export class Color { | |||||
* @return {Color} thisArg | ||||||
*/ | ||||||
toBlackWhite(threshold: number) { | ||||||
const source = this.getSource(), | ||||||
currentAlpha = source[3]; | ||||||
let average = Math.round( | ||||||
source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11 | ||||||
); | ||||||
|
||||||
average = average < (threshold || 127) ? 0 : 255; | ||||||
this.setSource([average, average, average, currentAlpha]); | ||||||
const [average, , , a] = greyAverage(this.getSource()), | ||||||
bOrW = average < (threshold || 127) ? 0 : 255; | ||||||
this.setSource([bOrW, bOrW, bOrW, a]); | ||||||
return this; | ||||||
} | ||||||
|
||||||
|
@@ -223,14 +171,14 @@ export class Color { | |||||
otherColor = new Color(otherColor); | ||||||
} | ||||||
|
||||||
const [r, g, b, alpha] = this.getSource(), | ||||||
const source = this.getSource(), | ||||||
otherAlpha = 0.5, | ||||||
otherSource = otherColor.getSource(), | ||||||
[R, G, B] = [r, g, b].map((value, index) => | ||||||
[R, G, B] = source.map((value, index) => | ||||||
Math.round(value * (1 - otherAlpha) + otherSource[index] * otherAlpha) | ||||||
); | ||||||
|
||||||
this.setSource([R, G, B, alpha]); | ||||||
this.setSource([R, G, B, source[3]]); | ||||||
return this; | ||||||
} | ||||||
|
||||||
|
@@ -263,19 +211,15 @@ export class Color { | |||||
* @return {TRGBAColorSource | undefined} source | ||||||
*/ | ||||||
static sourceFromRgb(color: string): TRGBAColorSource | undefined { | ||||||
const match = color.match(reRGBa); | ||||||
const match = color.match(reRGBa()); | ||||||
if (match) { | ||||||
const r = | ||||||
(parseInt(match[1], 10) / (/%$/.test(match[1]) ? 100 : 1)) * | ||||||
(/%$/.test(match[1]) ? 255 : 1), | ||||||
g = | ||||||
(parseInt(match[2], 10) / (/%$/.test(match[2]) ? 100 : 1)) * | ||||||
(/%$/.test(match[2]) ? 255 : 1), | ||||||
b = | ||||||
(parseInt(match[3], 10) / (/%$/.test(match[3]) ? 100 : 1)) * | ||||||
(/%$/.test(match[3]) ? 255 : 1); | ||||||
|
||||||
return [r, g, b, match[4] ? parseFloat(match[4]) : 1]; | ||||||
const [r, g, b] = match.slice(1, 4).map((value) => { | ||||||
const parsedValue = parseFloat(value); | ||||||
return value.endsWith('%') | ||||||
? Math.round(parsedValue * 2.55) | ||||||
: parsedValue; | ||||||
}); | ||||||
return [r, g, b, fromAlphaToFloat(match[4])]; | ||||||
} | ||||||
} | ||||||
|
||||||
|
@@ -310,14 +254,14 @@ export class Color { | |||||
* @see http://http://www.w3.org/TR/css3-color/#hsl-color | ||||||
*/ | ||||||
static sourceFromHsl(color: string): TRGBAColorSource | undefined { | ||||||
const match = color.match(reHSLa); | ||||||
const match = color.match(reHSLa()); | ||||||
if (!match) { | ||||||
return; | ||||||
} | ||||||
|
||||||
const h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i wonder... this seems correct and i noticed was off. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahhh I see. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that is fine, we discovered. |
||||||
s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1), | ||||||
l = parseFloat(match[3]) / (/%$/.test(match[3]) ? 100 : 1); | ||||||
s = parseFloat(match[2]) / 100, | ||||||
l = parseFloat(match[3]) / 100; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s and l are always percentages only. |
||||||
let r: number, g: number, b: number; | ||||||
|
||||||
if (s === 0) { | ||||||
|
@@ -335,7 +279,7 @@ export class Color { | |||||
Math.round(r * 255), | ||||||
Math.round(g * 255), | ||||||
Math.round(b * 255), | ||||||
match[4] ? parseFloat(match[4]) : 1, | ||||||
fromAlphaToFloat(match[4]), | ||||||
]; | ||||||
} | ||||||
|
||||||
|
@@ -358,31 +302,19 @@ export class Color { | |||||
* @return {TRGBAColorSource | undefined} source | ||||||
*/ | ||||||
static sourceFromHex(color: string): TRGBAColorSource | undefined { | ||||||
if (color.match(reHex)) { | ||||||
if (color.match(reHex())) { | ||||||
const value = color.slice(color.indexOf('#') + 1), | ||||||
isShortNotation = value.length === 3 || value.length === 4, | ||||||
isRGBa = value.length === 8 || value.length === 4, | ||||||
r = isShortNotation | ||||||
? value.charAt(0) + value.charAt(0) | ||||||
: value.substring(0, 2), | ||||||
g = isShortNotation | ||||||
? value.charAt(1) + value.charAt(1) | ||||||
: value.substring(2, 4), | ||||||
b = isShortNotation | ||||||
? value.charAt(2) + value.charAt(2) | ||||||
: value.substring(4, 6), | ||||||
a = isRGBa | ||||||
? isShortNotation | ||||||
? value.charAt(3) + value.charAt(3) | ||||||
: value.substring(6, 8) | ||||||
: 'FF'; | ||||||
|
||||||
return [ | ||||||
parseInt(r, 16), | ||||||
parseInt(g, 16), | ||||||
parseInt(b, 16), | ||||||
parseFloat((parseInt(a, 16) / 255).toFixed(2)), | ||||||
]; | ||||||
isShortNotation = value.length <= 4; | ||||||
let expandedValue: string[]; | ||||||
if (isShortNotation) { | ||||||
expandedValue = value.split('').map((hex) => hex + hex); | ||||||
asturur marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} else { | ||||||
expandedValue = value.match(/.{2}/g)!; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am guessing this split everything to couples |
||||||
} | ||||||
const [r, g, b, a = 255] = expandedValue.map((hexCouple) => | ||||||
parseInt(hexCouple, 16) | ||||||
); | ||||||
return [r, g, b, a / 255]; | ||||||
ShaMan123 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why isn't it prefixed with
#
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was like this before, trying to not change behaviour since it doesn't seems important.
I don't know the reasons, we should dig into git history