UNPKG

fabric

Version:

Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.

1 lines 13.6 kB
{"version":3,"file":"Color.mjs","names":[],"sources":["../../../src/color/Color.ts"],"sourcesContent":["import { normalizeWs } from '../util/internals/normalizeWhiteSpace';\nimport { radiansToDegrees } from '../util/misc/radiansDegreesConversion';\nimport { ColorNameMap } from './color_map';\nimport { reHSLa, reHex, reRGBa } from './constants';\nimport type { TRGBAColorSource, TColorArg } from './typedefs';\nimport {\n hue2rgb,\n hexify,\n rgb2Hsl,\n fromAlphaToFloat,\n greyAverage,\n} from './util';\n\n/**\n * @class Color common color operations\n * @see {@link http://fabric5.fabricjs.com/fabric-intro-part-2#colors colors}\n */\nexport class Color {\n declare private _source: TRGBAColorSource;\n isUnrecognised = false;\n\n /**\n *\n * @param {string} [color] optional in hex or rgb(a) or hsl format or from known color list\n */\n constructor(color?: TColorArg) {\n if (!color) {\n // we default to black as canvas does\n this.setSource([0, 0, 0, 1]);\n } else if (color instanceof Color) {\n this.setSource([...color._source]);\n } else if (Array.isArray(color)) {\n const [r, g, b, a = 1] = color;\n this.setSource([r, g, b, a]);\n } else {\n this.setSource(this._tryParsingColor(color));\n }\n }\n\n /**\n * @private\n * @param {string} [color] Color value to parse\n * @returns {TRGBAColorSource}\n */\n protected _tryParsingColor(color: string) {\n color = color.toLowerCase();\n if (color in ColorNameMap) {\n color = ColorNameMap[color as keyof typeof ColorNameMap];\n }\n return color === 'transparent'\n ? ([255, 255, 255, 0] as TRGBAColorSource)\n : Color.sourceFromHex(color) ||\n Color.sourceFromRgb(color) ||\n Color.sourceFromHsl(color) ||\n // color is not recognized\n // we default to black as canvas does\n // eslint-disable-next-line no-constant-binary-expression\n ((this.isUnrecognised = true) && ([0, 0, 0, 1] as TRGBAColorSource));\n }\n\n /**\n * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n * @return {TRGBAColorSource}\n */\n getSource() {\n return this._source;\n }\n\n /**\n * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n * @param {TRGBAColorSource} source\n */\n setSource(source: TRGBAColorSource) {\n this._source = source;\n }\n\n /**\n * Returns color representation in RGB format\n * @return {String} ex: rgb(0-255,0-255,0-255)\n */\n toRgb() {\n const [r, g, b] = this.getSource();\n return `rgb(${r},${g},${b})`;\n }\n\n /**\n * Returns color representation in RGBA format\n * @return {String} ex: rgba(0-255,0-255,0-255,0-1)\n */\n toRgba() {\n return `rgba(${this.getSource().join(',')})`;\n }\n\n /**\n * Returns color representation in HSL format\n * @return {String} ex: hsl(0-360,0%-100%,0%-100%)\n */\n toHsl() {\n const [h, s, l] = rgb2Hsl(...this.getSource());\n return `hsl(${h},${s}%,${l}%)`;\n }\n\n /**\n * Returns color representation in HSLA format\n * @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1)\n */\n toHsla() {\n const [h, s, l, a] = rgb2Hsl(...this.getSource());\n return `hsla(${h},${s}%,${l}%,${a})`;\n }\n\n /**\n * Returns color representation in HEX format\n * @return {String} ex: FF5555\n */\n toHex() {\n const fullHex = this.toHexa();\n return fullHex.slice(0, 6);\n }\n\n /**\n * Returns color representation in HEXA format\n * @return {String} ex: FF5555CC\n */\n toHexa() {\n const [r, g, b, a] = this.getSource();\n return `${hexify(r)}${hexify(g)}${hexify(b)}${hexify(Math.round(a * 255))}`;\n }\n\n /**\n * Gets value of alpha channel for this color\n * @return {Number} 0-1\n */\n getAlpha() {\n return this.getSource()[3];\n }\n\n /**\n * Sets value of alpha channel for this color\n * @param {Number} alpha Alpha value 0-1\n * @return {Color} thisArg\n */\n setAlpha(alpha: number) {\n this._source[3] = alpha;\n return this;\n }\n\n /**\n * Transforms color to its grayscale representation\n * @return {Color} thisArg\n */\n toGrayscale() {\n this.setSource(greyAverage(this.getSource()));\n return this;\n }\n\n /**\n * Transforms color to its black and white representation\n * @param {Number} threshold\n * @return {Color} thisArg\n */\n toBlackWhite(threshold: number) {\n const [average, , , a] = greyAverage(this.getSource()),\n bOrW = average < (threshold || 127) ? 0 : 255;\n this.setSource([bOrW, bOrW, bOrW, a]);\n return this;\n }\n\n /**\n * Overlays color with another color\n * @param {String|Color} otherColor\n * @return {Color} thisArg\n */\n overlayWith(otherColor: string | Color) {\n if (!(otherColor instanceof Color)) {\n otherColor = new Color(otherColor);\n }\n\n const source = this.getSource(),\n otherAlpha = 0.5,\n otherSource = otherColor.getSource(),\n [R, G, B] = source.map((value, index) =>\n Math.round(value * (1 - otherAlpha) + otherSource[index] * otherAlpha),\n );\n\n this.setSource([R, G, B, source[3]]);\n return this;\n }\n\n /**\n * Returns new color object, when given a color in RGB format\n * @param {String} color Color value ex: rgb(0-255,0-255,0-255)\n * @return {Color}\n */\n static fromRgb(color: string): Color {\n return Color.fromRgba(color);\n }\n\n /**\n * Returns new color object, when given a color in RGBA format\n * @param {String} color\n * @return {Color}\n */\n static fromRgba(color: string): Color {\n return new Color(Color.sourceFromRgb(color));\n }\n\n /**\n * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format\n * @param {String} color Color value ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%)\n * @return {TRGBAColorSource | undefined} source\n */\n static sourceFromRgb(color: string): TRGBAColorSource | undefined {\n const match = normalizeWs(color).match(reRGBa());\n if (match) {\n const [r, g, b] = match.slice(1, 4).map((value) => {\n const parsedValue = parseFloat(value);\n return value.endsWith('%')\n ? Math.round(parsedValue * 2.55)\n : parsedValue;\n });\n return [r, g, b, fromAlphaToFloat(match[4])];\n }\n }\n\n /**\n * Returns new color object, when given a color in HSL format\n * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%)\n * @return {Color}\n */\n static fromHsl(color: string): Color {\n return Color.fromHsla(color);\n }\n\n /**\n * Returns new color object, when given a color in HSLA format\n * @param {String} color\n * @return {Color}\n */\n static fromHsla(color: string): Color {\n return new Color(Color.sourceFromHsl(color));\n }\n\n /**\n * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format.\n * Adapted from <a href=\"https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html\">https://github.com/mjijackson</a>\n * @param {String} color Color value ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1)\n * @return {TRGBAColorSource | undefined} source\n * @see http://http://www.w3.org/TR/css3-color/#hsl-color\n */\n static sourceFromHsl(color: string): TRGBAColorSource | undefined {\n const match = normalizeWs(color).match(reHSLa());\n if (!match) {\n return;\n }\n const match1degrees = Color.parseAngletoDegrees(match[1]);\n\n const h = (((match1degrees % 360) + 360) % 360) / 360,\n s = parseFloat(match[2]) / 100,\n l = parseFloat(match[3]) / 100;\n let r: number, g: number, b: number;\n\n if (s === 0) {\n r = g = b = l;\n } else {\n const q = l <= 0.5 ? l * (s + 1) : l + s - l * s,\n p = l * 2 - q;\n\n r = hue2rgb(p, q, h + 1 / 3);\n g = hue2rgb(p, q, h);\n b = hue2rgb(p, q, h - 1 / 3);\n }\n\n return [\n Math.round(r * 255),\n Math.round(g * 255),\n Math.round(b * 255),\n fromAlphaToFloat(match[4]),\n ];\n }\n\n /**\n * Returns new color object, when given a color in HEX format\n * @param {String} color Color value ex: FF5555\n * @return {Color}\n */\n static fromHex(color: string): Color {\n return new Color(Color.sourceFromHex(color));\n }\n\n /**\n * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HEX format\n * @param {String} color ex: FF5555 or FF5544CC (RGBa)\n * @return {TRGBAColorSource | undefined} source\n */\n static sourceFromHex(color: string): TRGBAColorSource | undefined {\n if (color.match(reHex())) {\n const value = color.slice(color.indexOf('#') + 1),\n isShortNotation = value.length <= 4;\n let expandedValue: string[];\n if (isShortNotation) {\n expandedValue = value.split('').map((hex) => hex + hex);\n } else {\n expandedValue = value.match(/.{2}/g)!;\n }\n const [r, g, b, a = 255] = expandedValue.map((hexCouple) =>\n parseInt(hexCouple, 16),\n );\n return [r, g, b, a / 255];\n }\n }\n\n /**\n * Converts a string that could be any angle notation (50deg, 0.5turn, 2rad)\n * into degrees without the 'deg' suffix\n * @param {String} value ex: 0deg, 0.5turn, 2rad\n * @return {Number} number in degrees or NaN if inputs are invalid\n */\n static parseAngletoDegrees(value: string): number {\n const lowercase = value.toLowerCase();\n const numeric = parseFloat(lowercase);\n\n if (lowercase.includes('rad')) {\n return radiansToDegrees(numeric);\n }\n\n if (lowercase.includes('turn')) {\n return numeric * 360;\n }\n\n // Value is probably just a number already in degrees eg '50'\n return numeric;\n }\n}\n"],"mappings":"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"}