mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-18 22:01:42 +08:00
feat: color methods
Should fill most needs and remove the need for external libs like tinycolor
This commit is contained in:
@ -37,6 +37,11 @@ export class Color implements definition.Color {
|
|||||||
// The parameter is a 32-bit unsigned integer where each 8 bits specify a color component
|
// The parameter is a 32-bit unsigned integer where each 8 bits specify a color component
|
||||||
// In case a 32-bit signed int (Android, Java has no unsigned types) was provided - convert to unsigned by applyint >>> 0
|
// In case a 32-bit signed int (Android, Java has no unsigned types) was provided - convert to unsigned by applyint >>> 0
|
||||||
this._argb = arg >>> 0;
|
this._argb = arg >>> 0;
|
||||||
|
} else if (arg && arg._argb) {
|
||||||
|
// we would go there if a color was passed as an argument (or an object which is why we dont do instanceof)
|
||||||
|
// The parameter is a 32-bit unsigned integer where each 8 bits specify a color component
|
||||||
|
// In case a 32-bit signed int (Android, Java has no unsigned types) was provided - convert to unsigned by applyint >>> 0
|
||||||
|
this._argb = arg._argb >>> 0;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Expected 1 or 4 constructor parameters.');
|
throw new Error('Expected 1 or 4 constructor parameters.');
|
||||||
}
|
}
|
||||||
@ -137,6 +142,10 @@ export class Color implements definition.Color {
|
|||||||
|
|
||||||
return HEX_REGEX.test(value) || isRgbOrRgba(value) || isHslOrHsla(value);
|
return HEX_REGEX.test(value) || isRgbOrRgba(value) || isHslOrHsla(value);
|
||||||
}
|
}
|
||||||
|
public static fromHSL(a, h, s, l) {
|
||||||
|
const rgb = hslToRgb(h, s, l);
|
||||||
|
return new Color(a, rgb.r, rgb.g, rgb.b);
|
||||||
|
}
|
||||||
|
|
||||||
private _componentToHex(component: number): string {
|
private _componentToHex(component: number): string {
|
||||||
let hex = component.toString(16);
|
let hex = component.toString(16);
|
||||||
@ -163,6 +172,205 @@ export class Color implements definition.Color {
|
|||||||
public static fromIosColor(value: UIColor): Color {
|
public static fromIosColor(value: UIColor): Color {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if brightenss < 128
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public isDark() {
|
||||||
|
return this.getBrightness() < 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if brightenss >= 128
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public isLight() {
|
||||||
|
return !this.isDark();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the [brightness](http://www.w3.org/TR/AERT#color-contrast)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public getBrightness() {
|
||||||
|
return (this.r * 299 + this.g * 587 + this.b * 114) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the [luminance](http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public getLuminance() {
|
||||||
|
let R, G, B;
|
||||||
|
const RsRGB = this.r / 255;
|
||||||
|
const GsRGB = this.g/255;
|
||||||
|
const BsRGB = this.b/255;
|
||||||
|
|
||||||
|
if (RsRGB <= 0.03928) {R = RsRGB / 12.92;} else {R = Math.pow(((RsRGB + 0.055) / 1.055), 2.4);}
|
||||||
|
if (GsRGB <= 0.03928) {G = GsRGB / 12.92;} else {G = Math.pow(((GsRGB + 0.055) / 1.055), 2.4);}
|
||||||
|
if (BsRGB <= 0.03928) {B = BsRGB / 12.92;} else {B = Math.pow(((BsRGB + 0.055) / 1.055), 2.4);}
|
||||||
|
return (0.2126 * R) + (0.7152 * G) + (0.0722 * B);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return this color (as a new Color instance) with the provided alpha
|
||||||
|
*
|
||||||
|
* @param alpha (between 0 and 255)
|
||||||
|
*/
|
||||||
|
public setAlpha(a: number) {
|
||||||
|
return new Color(a, this.r, this.g, this.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the hsl representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toHsl() {
|
||||||
|
const hsl = rgbToHsl(this.r, this.g, this.b);
|
||||||
|
return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this.a };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the [CSS hsv](https://www.w3schools.com/Css/css_colors_hsl.asp) representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toHslString() {
|
||||||
|
const hsl = rgbToHsl(this.r, this.g, this.b);
|
||||||
|
const h = Math.round(hsl.h * 360), s = Math.round(hsl.s * 100), l = Math.round(hsl.l * 100);
|
||||||
|
const a = this.a;
|
||||||
|
return (a == 255) ?
|
||||||
|
"hsl(" + h + ", " + s + "%, " + l + "%)" :
|
||||||
|
"hsla(" + h + ", " + s + "%, " + l + "%, "+ (a/255).toFixed(2) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the hsv representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toHsv() {
|
||||||
|
const hsv = rgbToHsv(this.r, this.g, this.b);
|
||||||
|
return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this.a };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the [CSS hsv](https://www.w3schools.com/Css/css_colors_rgb.asp) representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toHsvString() {
|
||||||
|
const hsv = rgbToHsv(this.r, this.g, this.b);
|
||||||
|
const h = Math.round(hsv.h * 360), s = Math.round(hsv.s * 100), v = Math.round(hsv.v * 100);
|
||||||
|
const a = this.a;
|
||||||
|
return (a == 255) ?
|
||||||
|
"hsv(" + h + ", " + s + "%, " + v + "%)" :
|
||||||
|
"hsva(" + h + ", " + s + "%, " + v + "%, "+ (a/255).toFixed(2) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the [CSS rgb](https://www.w3schools.com/Css/css_colors_rgb.asp) representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toRgbString() {
|
||||||
|
const a = this.a;
|
||||||
|
return (a == 1) ?
|
||||||
|
"rgb(" + Math.round(this.r) + ", " + Math.round(this.g) + ", " + Math.round(this.b) + ")" :
|
||||||
|
"rgba(" + Math.round(this.r) + ", " + Math.round(this.g) + ", " + Math.round(this.b) + ", " + (a/255).toFixed(2) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desaturate the color a given amount, from 0 to 100. Providing 100 will is the same as calling greyscale.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public desaturate(amount: number) {
|
||||||
|
amount = (amount === 0) ? 0 : (amount || 10);
|
||||||
|
const hsl = this.toHsl();
|
||||||
|
hsl.s -= amount / 100;
|
||||||
|
hsl.s = Math.min(1, Math.max(0, hsl.s))
|
||||||
|
return Color.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saturate the color a given amount, from 0 to 100.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public saturate(amount: number) {
|
||||||
|
amount = (amount === 0) ? 0 : (amount || 10);
|
||||||
|
const hsl = this.toHsl();
|
||||||
|
hsl.s += amount / 100;
|
||||||
|
hsl.s = Math.min(1, Math.max(0, hsl.s))
|
||||||
|
return Color.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completely desaturates a color into greyscale. Same as calling desaturate(100).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public greyscale() {
|
||||||
|
return this.desaturate(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lighten the color a given amount, from 0 to 100. Providing 100 will always return white.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public lighten (amount: number) {
|
||||||
|
amount = (amount === 0) ? 0 : (amount || 10);
|
||||||
|
const hsl = this.toHsl();
|
||||||
|
hsl.l += amount / 100;
|
||||||
|
hsl.l = Math.min(1, Math.max(0, hsl.l))
|
||||||
|
return Color.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Brighten the color a given amount, from 0 to 100.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public brighten(amount: number) {
|
||||||
|
amount = (amount === 0) ? 0 : (amount || 10);
|
||||||
|
const r = Math.max(0, Math.min(255, this.r - Math.round(255 * - (amount / 100))));
|
||||||
|
const g = Math.max(0, Math.min(255, this.g - Math.round(255 * - (amount / 100))));
|
||||||
|
const b = Math.max(0, Math.min(255, this.b - Math.round(255 * - (amount / 100))));
|
||||||
|
return new Color(this.a, r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Darken the color a given amount, from 0 to 100. Providing 100 will always return black.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public darken (amount: number) {
|
||||||
|
amount = (amount === 0) ? 0 : (amount || 10);
|
||||||
|
const hsl = this.toHsl();
|
||||||
|
hsl.l -= amount / 100;
|
||||||
|
hsl.l = Math.min(1, Math.max(0, hsl.l))
|
||||||
|
return Color.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spin the hue a given amount, from -360 to 360. Calling with 0, 360, or -360 will do nothing (since it sets the hue back to what it was before).
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public spin(amount: number) {
|
||||||
|
const hsl = this.toHsl();
|
||||||
|
const hue = (hsl.h + amount) % 360;
|
||||||
|
hsl.h = hue < 0 ? 360 + hue : hue;
|
||||||
|
return Color.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the color complement
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public complement() {
|
||||||
|
const hsl = this.toHsl();
|
||||||
|
hsl.h = (hsl.h + 180) % 360;
|
||||||
|
return Color.fromHSL(this.a, hsl.h, hsl.s, hsl.l);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRgbOrRgba(value: string): boolean {
|
function isRgbOrRgba(value: string): boolean {
|
||||||
@ -222,3 +430,86 @@ function argbFromHslOrHsla(value: string): number {
|
|||||||
|
|
||||||
return (a & 0xff) * 0x01000000 + (r & 0xff) * 0x00010000 + (g & 0xff) * 0x00000100 + (b & 0xff);
|
return (a & 0xff) * 0x01000000 + (r & 0xff) * 0x00010000 + (g & 0xff) * 0x00000100 + (b & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `rgbToHsl`
|
||||||
|
// Converts an RGB color value to HSL.
|
||||||
|
// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
|
||||||
|
// *Returns:* { h, s, l } in [0,1]
|
||||||
|
function rgbToHsl(r, g, b) {
|
||||||
|
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||||
|
let h, s;
|
||||||
|
const l = (max + min) / 2;
|
||||||
|
|
||||||
|
if(max == min) {
|
||||||
|
h = s = 0; // achromatic
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const d = max - min;
|
||||||
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||||
|
switch(max) {
|
||||||
|
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 { h: h, s: s, l: l };
|
||||||
|
}
|
||||||
|
|
||||||
|
function hue2rgb(p, q, t) {
|
||||||
|
if(t < 0) t += 1;
|
||||||
|
if(t > 1) t -= 1;
|
||||||
|
if(t < 1/6) return p + (q - p) * 6 * t;
|
||||||
|
if(t < 1/2) return q;
|
||||||
|
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `hslToRgb`
|
||||||
|
// Converts an HSL color value to RGB.
|
||||||
|
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
|
||||||
|
// *Returns:* { r, g, b } in the set [0, 255]
|
||||||
|
function hslToRgb(h, s, l) {
|
||||||
|
let r, g, b;
|
||||||
|
if(s === 0) {
|
||||||
|
r = g = b = l; // achromatic
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||||
|
const p = 2 * l - q;
|
||||||
|
r = hue2rgb(p, q, h + 1/3);
|
||||||
|
g = hue2rgb(p, q, h);
|
||||||
|
b = hue2rgb(p, q, h - 1/3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { r: r * 255, g: g * 255, b: b * 255 };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// `rgbToHsv`
|
||||||
|
// Converts an RGB color value to HSV
|
||||||
|
// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
|
||||||
|
// *Returns:* { h, s, v } in [0,1]
|
||||||
|
function rgbToHsv(r, g, b) {
|
||||||
|
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||||
|
let h;
|
||||||
|
const v = max;
|
||||||
|
|
||||||
|
const d = max - min;
|
||||||
|
const s = max === 0 ? 0 : d / max;
|
||||||
|
|
||||||
|
if(max == min) {
|
||||||
|
h = 0; // achromatic
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch(max) {
|
||||||
|
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 { h: h, s: s, v: v };
|
||||||
|
}
|
||||||
|
115
packages/core/color/index.d.ts
vendored
115
packages/core/color/index.d.ts
vendored
@ -75,4 +75,119 @@ export class Color {
|
|||||||
* Creates color from iOS-specific UIColor value representation.
|
* Creates color from iOS-specific UIColor value representation.
|
||||||
*/
|
*/
|
||||||
public static fromIosColor(value: any /* UIColor */): Color;
|
public static fromIosColor(value: any /* UIColor */): Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if brightenss < 128
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public isDark(): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if brightenss >= 128
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public isLight(): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the [brightness](http://www.w3.org/TR/AERT#color-contrast)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public getBrightness(): number;
|
||||||
|
/**
|
||||||
|
* return the [luminance](http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public getLuminance(): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return this color (as a new Color instance) with the provided alpha
|
||||||
|
*
|
||||||
|
* @param alpha (between 0 and 255)
|
||||||
|
*/
|
||||||
|
public setAlpha(a: number): Color;
|
||||||
|
/**
|
||||||
|
* return the hsl representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toHsl() : { h: number, s: number, l: number, a: number };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the [CSS hsv](https://www.w3schools.com/Css/css_colors_hsl.asp) representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toHslString(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the hsv representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toHsv(): { h: number, s: number, v: number, a: number };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the [CSS hsv](https://www.w3schools.com/Css/css_colors_rgb.asp) representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toHsvString(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the [CSS rgb](https://www.w3schools.com/Css/css_colors_rgb.asp) representation of the color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public toRgbString(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desaturate the color a given amount, from 0 to 100. Providing 100 will is the same as calling greyscale.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public desaturate(amount: number): Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saturate the color a given amount, from 0 to 100.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public saturate(amount: number): Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completely desaturates a color into greyscale. Same as calling desaturate(100).
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public greyscale(): Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lighten the color a given amount, from 0 to 100. Providing 100 will always return white.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
* @returns olor : Color
|
||||||
|
*/
|
||||||
|
public lighten (amount: number): Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Brighten the color a given amount, from 0 to 100.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public brighten(amount: number): Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Darken the color a given amount, from 0 to 100. Providing 100 will always return black.
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public darken (amount: number): Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spin the hue a given amount, from -360 to 360. Calling with 0, 360, or -360 will do nothing (since it sets the hue back to what it was before).
|
||||||
|
*
|
||||||
|
* @param amount (between 0 and 100)
|
||||||
|
*/
|
||||||
|
public spin(amount: number): Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the color complement
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public complement(): Color;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user