UNPKG

pixi.js

Version:

PixiJS — The HTML5 Creation Engine =============

395 lines (392 loc) 12.5 kB
import { extend, colord } from '@pixi/colord'; import namesPlugin from '@pixi/colord/plugins/names'; "use strict"; extend([namesPlugin]); const _Color = class _Color { /** * @param {ColorSource} value - Optional value to use, if not provided, white is used. */ constructor(value = 16777215) { this._value = null; this._components = new Float32Array(4); this._components.fill(1); this._int = 16777215; this.value = value; } /** Get red component (0 - 1) */ get red() { return this._components[0]; } /** Get green component (0 - 1) */ get green() { return this._components[1]; } /** Get blue component (0 - 1) */ get blue() { return this._components[2]; } /** Get alpha component (0 - 1) */ get alpha() { return this._components[3]; } /** * Set the value, suitable for chaining * @param value * @see Color.value */ setValue(value) { this.value = value; return this; } /** * The current color source. * * When setting: * - Setting to an instance of `Color` will copy its color source and components. * - Otherwise, `Color` will try to normalize the color source and set the components. * If the color source is invalid, an `Error` will be thrown and the `Color` will left unchanged. * * Note: The `null` in the setter's parameter type is added to match the TypeScript rule: return type of getter * must be assignable to its setter's parameter type. Setting `value` to `null` will throw an `Error`. * * When getting: * - A return value of `null` means the previous value was overridden (e.g., {@link Color.multiply multiply}, * {@link Color.premultiply premultiply} or {@link Color.round round}). * - Otherwise, the color source used when setting is returned. */ set value(value) { if (value instanceof _Color) { this._value = this._cloneSource(value._value); this._int = value._int; this._components.set(value._components); } else if (value === null) { throw new Error("Cannot set Color#value to null"); } else if (this._value === null || !this._isSourceEqual(this._value, value)) { this._normalize(value); this._value = this._cloneSource(value); } } get value() { return this._value; } /** * Copy a color source internally. * @param value - Color source */ _cloneSource(value) { if (typeof value === "string" || typeof value === "number" || value instanceof Number || value === null) { return value; } else if (Array.isArray(value) || ArrayBuffer.isView(value)) { return value.slice(0); } else if (typeof value === "object" && value !== null) { return { ...value }; } return value; } /** * Equality check for color sources. * @param value1 - First color source * @param value2 - Second color source * @returns `true` if the color sources are equal, `false` otherwise. */ _isSourceEqual(value1, value2) { const type1 = typeof value1; const type2 = typeof value2; if (type1 !== type2) { return false; } else if (type1 === "number" || type1 === "string" || value1 instanceof Number) { return value1 === value2; } else if (Array.isArray(value1) && Array.isArray(value2) || ArrayBuffer.isView(value1) && ArrayBuffer.isView(value2)) { if (value1.length !== value2.length) { return false; } return value1.every((v, i) => v === value2[i]); } else if (value1 !== null && value2 !== null) { const keys1 = Object.keys(value1); const keys2 = Object.keys(value2); if (keys1.length !== keys2.length) { return false; } return keys1.every((key) => value1[key] === value2[key]); } return value1 === value2; } /** * Convert to a RGBA color object. * @example * import { Color } from 'pixi.js'; * new Color('white').toRgb(); // returns { r: 1, g: 1, b: 1, a: 1 } */ toRgba() { const [r, g, b, a] = this._components; return { r, g, b, a }; } /** * Convert to a RGB color object. * @example * import { Color } from 'pixi.js'; * new Color('white').toRgb(); // returns { r: 1, g: 1, b: 1 } */ toRgb() { const [r, g, b] = this._components; return { r, g, b }; } /** Convert to a CSS-style rgba string: `rgba(255,255,255,1.0)`. */ toRgbaString() { const [r, g, b] = this.toUint8RgbArray(); return `rgba(${r},${g},${b},${this.alpha})`; } toUint8RgbArray(out) { const [r, g, b] = this._components; if (!this._arrayRgb) { this._arrayRgb = []; } out = out || this._arrayRgb; out[0] = Math.round(r * 255); out[1] = Math.round(g * 255); out[2] = Math.round(b * 255); return out; } toArray(out) { if (!this._arrayRgba) { this._arrayRgba = []; } out = out || this._arrayRgba; const [r, g, b, a] = this._components; out[0] = r; out[1] = g; out[2] = b; out[3] = a; return out; } toRgbArray(out) { if (!this._arrayRgb) { this._arrayRgb = []; } out = out || this._arrayRgb; const [r, g, b] = this._components; out[0] = r; out[1] = g; out[2] = b; return out; } /** * Convert to a hexadecimal number. * @example * import { Color } from 'pixi.js'; * new Color('white').toNumber(); // returns 16777215 */ toNumber() { return this._int; } /** * Convert to a BGR number * @example * import { Color } from 'pixi.js'; * new Color(0xffcc99).toBgrNumber(); // returns 0x99ccff */ toBgrNumber() { const [r, g, b] = this.toUint8RgbArray(); return (b << 16) + (g << 8) + r; } /** * Convert to a hexadecimal number in little endian format (e.g., BBGGRR). * @example * import { Color } from 'pixi.js'; * new Color(0xffcc99).toLittleEndianNumber(); // returns 0x99ccff * @returns {number} - The color as a number in little endian format. */ toLittleEndianNumber() { const value = this._int; return (value >> 16) + (value & 65280) + ((value & 255) << 16); } /** * Multiply with another color. This action is destructive, and will * override the previous `value` property to be `null`. * @param {ColorSource} value - The color to multiply by. */ multiply(value) { const [r, g, b, a] = _Color._temp.setValue(value)._components; this._components[0] *= r; this._components[1] *= g; this._components[2] *= b; this._components[3] *= a; this._refreshInt(); this._value = null; return this; } /** * Converts color to a premultiplied alpha format. This action is destructive, and will * override the previous `value` property to be `null`. * @param alpha - The alpha to multiply by. * @param {boolean} [applyToRGB=true] - Whether to premultiply RGB channels. * @returns {Color} - Itself. */ premultiply(alpha, applyToRGB = true) { if (applyToRGB) { this._components[0] *= alpha; this._components[1] *= alpha; this._components[2] *= alpha; } this._components[3] = alpha; this._refreshInt(); this._value = null; return this; } /** * Premultiplies alpha with current color. * @param {number} alpha - The alpha to multiply by. * @param {boolean} [applyToRGB=true] - Whether to premultiply RGB channels. * @returns {number} tint multiplied by alpha */ toPremultiplied(alpha, applyToRGB = true) { if (alpha === 1) { return (255 << 24) + this._int; } if (alpha === 0) { return applyToRGB ? 0 : this._int; } let r = this._int >> 16 & 255; let g = this._int >> 8 & 255; let b = this._int & 255; if (applyToRGB) { r = r * alpha + 0.5 | 0; g = g * alpha + 0.5 | 0; b = b * alpha + 0.5 | 0; } return (alpha * 255 << 24) + (r << 16) + (g << 8) + b; } /** * Convert to a hexadecimal string. * @example * import { Color } from 'pixi.js'; * new Color('white').toHex(); // returns "#ffffff" */ toHex() { const hexString = this._int.toString(16); return `#${"000000".substring(0, 6 - hexString.length) + hexString}`; } /** * Convert to a hexadecimal string with alpha. * @example * import { Color } from 'pixi.js'; * new Color('white').toHexa(); // returns "#ffffffff" */ toHexa() { const alphaValue = Math.round(this._components[3] * 255); const alphaString = alphaValue.toString(16); return this.toHex() + "00".substring(0, 2 - alphaString.length) + alphaString; } /** * Set alpha, suitable for chaining. * @param alpha */ setAlpha(alpha) { this._components[3] = this._clamp(alpha); return this; } /** * Normalize the input value into rgba * @param value - Input value */ _normalize(value) { let r; let g; let b; let a; if ((typeof value === "number" || value instanceof Number) && value >= 0 && value <= 16777215) { const int = value; r = (int >> 16 & 255) / 255; g = (int >> 8 & 255) / 255; b = (int & 255) / 255; a = 1; } else if ((Array.isArray(value) || value instanceof Float32Array) && value.length >= 3 && value.length <= 4) { value = this._clamp(value); [r, g, b, a = 1] = value; } else if ((value instanceof Uint8Array || value instanceof Uint8ClampedArray) && value.length >= 3 && value.length <= 4) { value = this._clamp(value, 0, 255); [r, g, b, a = 255] = value; r /= 255; g /= 255; b /= 255; a /= 255; } else if (typeof value === "string" || typeof value === "object") { if (typeof value === "string") { const match = _Color.HEX_PATTERN.exec(value); if (match) { value = `#${match[2]}`; } } const color = colord(value); if (color.isValid()) { ({ r, g, b, a } = color.rgba); r /= 255; g /= 255; b /= 255; } } if (r !== void 0) { this._components[0] = r; this._components[1] = g; this._components[2] = b; this._components[3] = a; this._refreshInt(); } else { throw new Error(`Unable to convert color ${value}`); } } /** Refresh the internal color rgb number */ _refreshInt() { this._clamp(this._components); const [r, g, b] = this._components; this._int = (r * 255 << 16) + (g * 255 << 8) + (b * 255 | 0); } /** * Clamps values to a range. Will override original values * @param value - Value(s) to clamp * @param min - Minimum value * @param max - Maximum value */ _clamp(value, min = 0, max = 1) { if (typeof value === "number") { return Math.min(Math.max(value, min), max); } value.forEach((v, i) => { value[i] = Math.min(Math.max(v, min), max); }); return value; } /** * Check if the value is a color-like object * @param value - Value to check * @returns True if the value is a color-like object * @static * @example * import { Color } from 'pixi.js'; * Color.isColorLike('white'); // returns true * Color.isColorLike(0xffffff); // returns true * Color.isColorLike([1, 1, 1]); // returns true */ static isColorLike(value) { return typeof value === "number" || typeof value === "string" || value instanceof Number || value instanceof _Color || Array.isArray(value) || value instanceof Uint8Array || value instanceof Uint8ClampedArray || value instanceof Float32Array || value.r !== void 0 && value.g !== void 0 && value.b !== void 0 || value.r !== void 0 && value.g !== void 0 && value.b !== void 0 && value.a !== void 0 || value.h !== void 0 && value.s !== void 0 && value.l !== void 0 || value.h !== void 0 && value.s !== void 0 && value.l !== void 0 && value.a !== void 0 || value.h !== void 0 && value.s !== void 0 && value.v !== void 0 || value.h !== void 0 && value.s !== void 0 && value.v !== void 0 && value.a !== void 0; } }; /** * Default Color object for static uses * @example * import { Color } from 'pixi.js'; * Color.shared.setValue(0xffffff).toHex(); // '#ffffff' */ _Color.shared = new _Color(); /** * Temporary Color object for static uses internally. * As to not conflict with Color.shared. * @ignore */ _Color._temp = new _Color(); /** Pattern for hex strings */ // eslint-disable-next-line @typescript-eslint/naming-convention _Color.HEX_PATTERN = /^(#|0x)?(([a-f0-9]{3}){1,2}([a-f0-9]{2})?)$/i; let Color = _Color; export { Color }; //# sourceMappingURL=Color.mjs.map