mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-19 06:10:56 +08:00
fix: color fixes for hsl / hsv
allow Color constructor to take hsl/hsv
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
import * as definition from '.';
|
||||
import * as types from '../utils/types';
|
||||
import * as knownColors from './known-colors';
|
||||
import { convertHSLToRGBColor } from '../css/parser';
|
||||
|
||||
const SHARP = '#';
|
||||
const HEX_REGEX = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)|(^#[0-9A-F]{8}$)/i;
|
||||
@ -12,18 +11,21 @@ export class Color implements definition.Color {
|
||||
|
||||
constructor(color: number);
|
||||
constructor(color: string);
|
||||
constructor(a: number, r: number, g: number, b: number);
|
||||
constructor(a: number, r: number, g: number, b: number, type?:'rbg' | 'hsl' | 'hsv');
|
||||
constructor(...args) {
|
||||
if (args.length === 1) {
|
||||
const arg = args[0];
|
||||
if (types.isString(arg)) {
|
||||
if (isRgbOrRgba(arg)) {
|
||||
this._argb = argbFromRgbOrRgba(arg);
|
||||
} else if (isHslOrHsla(arg)) {
|
||||
this._argb = argbFromHslOrHsla(arg);
|
||||
} else if (knownColors.isKnownName(arg)) {
|
||||
const lowered = arg.toLowerCase();
|
||||
if (isRgbOrRgba(lowered)) {
|
||||
this._argb = argbFromRgbOrRgba(lowered);
|
||||
} else if (isHslOrHsla(lowered)) {
|
||||
this._argb = argbFromHslOrHsla(lowered);
|
||||
} else if (isHsvOrHsva(lowered)) {
|
||||
this._argb = argbFromHsvOrHsva(lowered);
|
||||
} else if (knownColors.isKnownName(lowered)) {
|
||||
// The parameter is a known color name
|
||||
const argb = knownColors.getKnownColor(arg);
|
||||
const argb = knownColors.getKnownColor(lowered);
|
||||
this._name = arg;
|
||||
this._argb = argb;
|
||||
} else if (arg[0] === SHARP) {
|
||||
@ -44,8 +46,23 @@ export class Color implements definition.Color {
|
||||
} else {
|
||||
throw new Error('Expected 1 or 4 constructor parameters.');
|
||||
}
|
||||
} else if (args.length === 4) {
|
||||
this._argb = (args[0] & 0xff) * 0x01000000 + (args[1] & 0xff) * 0x00010000 + (args[2] & 0xff) * 0x00000100 + (args[3] & 0xff) * 0x00000001;
|
||||
} else if (args.length >= 4) {
|
||||
const a = args[0];
|
||||
switch(args[4]) {
|
||||
case 'hsl': {
|
||||
const { r, g, b } = hslToRgb(args[1], args[2], args[3]);
|
||||
this._argb = (a & 0xff) * 0x01000000 + (r & 0xff) * 0x00010000 + (g & 0xff) * 0x00000100 + (b & 0xff) * 0x00000001;
|
||||
break;
|
||||
}
|
||||
case 'hsv': {
|
||||
const { r, g, b } = hsvToRgb(args[1], args[2], args[3]);
|
||||
this._argb = (a & 0xff) * 0x01000000 + (r & 0xff) * 0x00010000 + (g & 0xff) * 0x00000100 + (b & 0xff) * 0x00000001;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this._argb = (a & 0xff) * 0x01000000 + (args[1] & 0xff) * 0x00010000 + (args[2] & 0xff) * 0x00000100 + (args[3] & 0xff) * 0x00000001;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
throw new Error('Expected 1 or 4 constructor parameters.');
|
||||
}
|
||||
@ -139,25 +156,19 @@ export class Color implements definition.Color {
|
||||
if (!types.isString(value)) {
|
||||
return false;
|
||||
}
|
||||
const lowered = value.toLowerCase();
|
||||
|
||||
if (knownColors.isKnownName(value)) {
|
||||
if (knownColors.isKnownName(lowered)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return HEX_REGEX.test(value) || isRgbOrRgba(value) || isHslOrHsla(value);
|
||||
return HEX_REGEX.test(value) || isRgbOrRgba(lowered) || isHslOrHsla(lowered);
|
||||
}
|
||||
public static fromHSL(a, h, s, l) {
|
||||
const rgb = hslToRgb(h, s, l);
|
||||
return new Color(a, rgb.r, rgb.g, rgb.b);
|
||||
return new Color(a, h, s, l, 'hsl');
|
||||
}
|
||||
|
||||
private _componentToHex(component: number): string {
|
||||
let hex = component.toString(16);
|
||||
if (hex.length === 1) {
|
||||
hex = '0' + hex;
|
||||
}
|
||||
|
||||
return hex;
|
||||
public static fromHSV(a, h, s, l) {
|
||||
return new Color(a, h, s, l, 'hsv');
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
@ -292,7 +303,7 @@ export class Color implements definition.Color {
|
||||
const hsl = rgbToHsl(this.r / 255, this.g / 255, this.b / 255);
|
||||
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);
|
||||
return Color.fromHSL(this.a, hsl.h * 360, hsl.s * 100, hsl.l * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -305,7 +316,7 @@ export class Color implements definition.Color {
|
||||
const hsl = rgbToHsl(this.r / 255, this.g / 255, this.b / 255);
|
||||
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);
|
||||
return Color.fromHSL(this.a, hsl.h * 360, hsl.s * 100, hsl.l * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -326,7 +337,7 @@ export class Color implements definition.Color {
|
||||
const hsl = rgbToHsl(this.r / 255, this.g / 255, this.b / 255);
|
||||
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);
|
||||
return Color.fromHSL(this.a, hsl.h * 360, hsl.s * 100, hsl.l * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -352,13 +363,13 @@ export class Color implements definition.Color {
|
||||
const hsl = rgbToHsl(this.r / 255, this.g / 255, this.b / 255);
|
||||
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);
|
||||
return Color.fromHSL(this.a, hsl.h * 360, hsl.s * 100, hsl.l * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @param amount (between -360 and 360)
|
||||
*/
|
||||
public spin(amount: number) {
|
||||
const hsl = this.toHsl();
|
||||
@ -392,20 +403,18 @@ export class Color implements definition.Color {
|
||||
}
|
||||
|
||||
function isRgbOrRgba(value: string): boolean {
|
||||
const toLower = value.toLowerCase();
|
||||
|
||||
return (toLower.indexOf('rgb(') === 0 || toLower.indexOf('rgba(') === 0) && toLower.indexOf(')') === toLower.length - 1;
|
||||
return (value.startsWith('rgb(') || value.startsWith('rgba(')) && value.endsWith(')');
|
||||
}
|
||||
|
||||
function isHslOrHsla(value: string): boolean {
|
||||
const toLower = value.toLowerCase();
|
||||
|
||||
return (toLower.indexOf('hsl(') === 0 || toLower.indexOf('hsla(') === 0) && toLower.indexOf(')') === toLower.length - 1;
|
||||
return (value.startsWith('hsl') || value.startsWith('hsla(')) && value.endsWith(')');
|
||||
}
|
||||
function isHsvOrHsva(value: string): boolean {
|
||||
return (value.startsWith('hsv') || value.startsWith('hsva(')) && value.endsWith(')');
|
||||
}
|
||||
|
||||
function parseColorWithAlpha(value: string): any {
|
||||
const toLower = value.toLowerCase();
|
||||
const parts = toLower
|
||||
const parts = value
|
||||
.replace(/(rgb|hsl)a?\(/, '')
|
||||
.replace(')', '')
|
||||
.trim()
|
||||
@ -444,7 +453,15 @@ function argbFromRgbOrRgba(value: string): number {
|
||||
function argbFromHslOrHsla(value: string): number {
|
||||
const { f: h, s: s, t: l, a } = parseColorWithAlpha(value);
|
||||
|
||||
const { r, g, b } = convertHSLToRGBColor(h, s, l);
|
||||
const { r, g, b } = hslToRgb(h, s, l);
|
||||
|
||||
return (a & 0xff) * 0x01000000 + (r & 0xff) * 0x00010000 + (g & 0xff) * 0x00000100 + (b & 0xff);
|
||||
}
|
||||
|
||||
function argbFromHsvOrHsva(value: string): number {
|
||||
const { f: h, s: s, t: v, a } = parseColorWithAlpha(value);
|
||||
|
||||
const { r, g, b } = hsvToRgb(h, s, v);
|
||||
|
||||
return (a & 0xff) * 0x01000000 + (r & 0xff) * 0x00010000 + (g & 0xff) * 0x00000100 + (b & 0xff);
|
||||
}
|
||||
@ -493,9 +510,13 @@ function hue2rgb(p, q, t) {
|
||||
|
||||
// `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]
|
||||
// *Assumes:* h is contained in [0, 360] and s and l are contained [0, 100]
|
||||
// *Returns:* { r, g, b } in the set [0, 255]
|
||||
function hslToRgb(h, s, l) {
|
||||
function hslToRgb(h1, s1, l1) {
|
||||
|
||||
const h = (h1 % 360) / 360 * 6;
|
||||
const s = s1 / 100;
|
||||
const l = l1 / 100;
|
||||
let r, g, b;
|
||||
if (s === 0) {
|
||||
r = g = b = l; // achromatic
|
||||
@ -512,7 +533,7 @@ function hslToRgb(h, s, l) {
|
||||
|
||||
// `rgbToHsv`
|
||||
// Converts an RGB color value to HSV
|
||||
// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
|
||||
// *Assumes:* r, g, and b are contained in the set [0, 1]
|
||||
// *Returns:* { h, s, v } in [0,1]
|
||||
function rgbToHsv(r, g, b) {
|
||||
const max = Math.max(r, g, b),
|
||||
@ -541,3 +562,26 @@ function rgbToHsv(r, g, b) {
|
||||
}
|
||||
return { h: h, s: s, v: v };
|
||||
}
|
||||
|
||||
// `hsvToRgb`
|
||||
// Converts an HSV color value to RGB.
|
||||
// *Assumes:* h is contained in [0, 360] and s and v are contained [0, 100]
|
||||
// *Returns:* { r, g, b } in the set [0, 255]
|
||||
function hsvToRgb(h1, s1, v1) {
|
||||
|
||||
const h = (h1 % 360) / 360 * 6;
|
||||
const s = s1 / 100;
|
||||
const v = v1 / 100;
|
||||
|
||||
var i = Math.floor(h),
|
||||
f = h - i,
|
||||
p = v * (1 - s),
|
||||
q = v * (1 - f * s),
|
||||
t = v * (1 - (1 - f) * s),
|
||||
mod = i % 6,
|
||||
r = [v, q, p, p, t, v][mod],
|
||||
g = [t, v, v, q, p, p][mod],
|
||||
b = [p, p, t, v, v, q][mod];
|
||||
|
||||
return { r: r * 255, g: g * 255, b: b * 255 };
|
||||
}
|
9
packages/core/color/index.d.ts
vendored
9
packages/core/color/index.d.ts
vendored
@ -5,7 +5,7 @@ export class Color {
|
||||
constructor(knownColor: string);
|
||||
constructor(hex: string);
|
||||
constructor(argb: number);
|
||||
constructor(alpha: number, red: number, green: number, blue: number);
|
||||
constructor(alpha: number, red: number, green: number, blue: number, type?: 'rgb' | 'hsl' | 'hsv');
|
||||
|
||||
/**
|
||||
* Gets the Alpha component (in the [0, 255] range) of this color. This is a read-only property.
|
||||
@ -196,4 +196,11 @@ export class Color {
|
||||
*
|
||||
*/
|
||||
public static mix(color1: Color, color2: Color, amount: number): Color;
|
||||
|
||||
/**
|
||||
* returns a new Color from HSL
|
||||
*
|
||||
*/
|
||||
public static fromHSL(a, h, s, l): Color;
|
||||
public static fromHSV(a, h, s, l): Color;
|
||||
}
|
||||
|
Reference in New Issue
Block a user