UNPKG

toloframework

Version:

Javascript/HTML/CSS compiler for Firefox OS or nodewebkit apps using modules in the nodejs style.

383 lines (326 loc) 8.54 kB
"use strict"; /** @module tfw.color */ require('tfw.color', function (require, module, exports) { var _ = function () { var D = { "en": {}, "fr": {} }, X = require("$").intl; function _() { return X(D, arguments); } _.all = D; return _; }(); "use strict"; /** * @class Color * Fast color manipulations. * Attributes R (red), G (green), B (blue), A (alpha), H (hue), S * (saturation), and L (luminance) are all floats between 0 and 1. */ module.exports = Color; /** * Uses R, G and B. * @return {float} The luminance of this color, to be used in * grayscale, for instance. */ Color.prototype.luminance = luminance; /** * Uses R, G, B and A. * @return {string} CSS color format. For instance: `#FE1795DD` */ Color.prototype.stringify = stringify; /** * @param {string} text - A CSS representation for this color. * @return {array} `[red, green, blue, alpha]` with every item between * 0 and 1. */ Color.prototype.parse = parse; /** * @return {Color} A clone of this object */ Color.prototype.copy = copy; /** * Read H,S,L and write R,G,B. */ Color.prototype.hsl2rgb = hsl2rgb; /** * Read R,G,B and write H,S,L. */ Color.prototype.rgb2hsl = rgb2hsl; var INSTANCE = new Color(); Color.instance = INSTANCE; Color.parse = staticParse; Color.luminance = staticLuminance; /** * @param {float} red - Red value between 0 and 1. * @param {float} green - Green value between 0 and 1. * @param {float} blue - Blue value between 0 and 1. * @return {Color} A new color. */ Color.newRGB = newRGB; /** * @param {float} red - Red value between 0 and 1. * @param {float} green - Green value between 0 and 1. * @param {float} blue - Blue value between 0 and 1. * @param {float} alpha - Alpha value between 0 and 1. * @return {Color} A new color. */ Color.newRGBA = newRGBA; /* * ################## * # Implementation # * ################## */ /** * @constructor * @param {string} code - CSS color code. */ function Color(code) { this.R = 0; this.G = 0; this.B = 0; this.A = 0; this.H = 0; this.S = 0; this.L = 0; if (typeof code === 'string') { this.parse(code); } } var INV6 = 1 / 6, INV15 = 1 / 15, INV99 = 1 / 99, INV255 = 1 / 255, INV359 = 1 / 359; /** * Read R,G,B and write H,S,L. * @returns {undefined} */ function rgb2hsl() { var R = this.R, G = this.G, B = this.B, min = Math.min(R, G, B), max = Math.max(R, G, B), delta = max - min; this.L = 0.5 * (max + min); if (delta < 0.000001) { this.H = 0; this.S = 0; } else { this.S = delta / (1 - Math.abs(2 * this.L - 1)); if (max === R) { if (G >= B) { this.H = INV6 * ((G - B) / delta); } else { this.H = 1 - INV6 * ((B - G) / delta); } } else if (max === G) { this.H = INV6 * (2 + (B - R) / delta); } else { this.H = INV6 * (4 + (R - G) / delta); } } } /** * @returns {undefined} * @see https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB */ function hsl2rgb() { var H = 6 * this.H, S = this.S, L = this.L, chroma = (1 - Math.abs(2 * L - 1)) * S, x = chroma * (1 - Math.abs(H % 2 - 1)); var R = 0, G = 0, B = 0; if (H < 3) { if (H < 1) { R = chroma; G = x; B = 0; } else if (H < 2) { R = x; G = chroma; B = 0; } else { // H == 2. R = 0; G = chroma; B = x; } } else if (H < 4) { R = 0; G = x; B = chroma; } else if (H < 5) { R = x; G = 0; B = chroma; } else { R = chroma; G = 0; B = x; } var shift = L - chroma * 0.5; this.R = R + shift; this.G = G + shift; this.B = B + shift; } /** * @returns {undefined} * @see https://en.wikipedia.org/wiki/Grayscale */ function luminance() { return 0.2126 * this.R + 0.7152 * this.G + 0.0722 * this.B; } /** * @returns {string} String value of the color. `#fd45a7`. */ function stringify() { var color = hexa2(this.R * 255) + hexa2(this.G * 255) + hexa2(this.B * 255); if (this.A < 1) { color += hexa2(this.A * 255); } return "#".concat(color); } /** * @param {string} _text - CSS color code. * @returns {boolean} Success? */ function parse(_text) { var text = typeof _text !== 'undefined' ? _text : '#000000', input = text.trim().toUpperCase(); if (parseHexa.call(this, input)) return true; if (parseRGB.call(this, input)) return true; if (parseRGBA.call(this, input)) return true; if (parseHSL.call(this, input)) return true; // @TODO hsl and hsla. return false; } /** * @param {string} text - CSS color code. * @returns {boolean} Success? */ function parseHexa(text) { if (text.charAt(0) !== '#') return false; var R = 0, G = 0, B = 0, A = 1; switch (text.length) { case 4: R = parseInt(text.charAt(1), 16) * INV15; G = parseInt(text.charAt(2), 16) * INV15; B = parseInt(text.charAt(3), 16) * INV15; break; case 5: R = parseInt(text.charAt(1), 16) * INV15; G = parseInt(text.charAt(2), 16) * INV15; B = parseInt(text.charAt(3), 16) * INV15; A = parseInt(text.charAt(4), 16) * INV15; break; case 7: R = parseInt(text.substr(1, 2), 16) * INV255; G = parseInt(text.substr(3, 2), 16) * INV255; B = parseInt(text.substr(5, 2), 16) * INV255; break; case 9: R = parseInt(text.substr(1, 2), 16) * INV255; G = parseInt(text.substr(3, 2), 16) * INV255; B = parseInt(text.substr(5, 2), 16) * INV255; A = parseInt(text.substr(7, 2), 16) * INV255; break; default: } if (isNaN(R) || isNaN(G) || isNaN(B) || isNaN(A)) { this.R = this.G = this.B = this.A = 0; } else { this.R = R; this.G = G; this.B = B; this.A = A; } return true; } var RX_RGB = /^RGB[\s\(]+([0-9]+)[^0-9]+([0-9]+)[^0-9]+([0-9]+)/; function parseRGB(text) { var m = RX_RGB.exec(text); if (!m) return false; this.R = clamp01(parseInt(m[1]) * INV255); this.G = clamp01(parseInt(m[2]) * INV255); this.B = clamp01(parseInt(m[3]) * INV255); this.A = 1; return true; } var RX_RGBA = /^RGBA[\s\(]+([0-9]+)[^0-9]+([0-9]+)[^0-9]+([0-9]+)[^0-9\.]+([0-9\.]+)/; function parseRGBA(text) { var m = RX_RGBA.exec(text); if (!m) return false; this.R = clamp01(parseInt(m[1]) * INV255); this.G = clamp01(parseInt(m[2]) * INV255); this.B = clamp01(parseInt(m[3]) * INV255); this.A = clamp01(parseFloat(m[4])); return true; } var RX_HSL = /^HSL[\s\(]+([0-9]+)[^0-9]+([0-9]+)[^0-9]+([0-9]+)/; function parseHSL(text) { var m = RX_HSL.exec(text); if (!m) return false; this.H = clamp01(parseInt(m[1]) * INV359); this.S = clamp01(parseInt(m[2]) * INV99); this.L = clamp01(parseInt(m[3]) * INV99); this.A = 1; this.hsl2rgb(); return true; } function hexa2(value) { var out = Math.floor(value).toString(16); if (out.length < 2) out = "0" + out; return out; } function copy() { var newColor = new Color(); newColor.R = this.R; newColor.G = this.G; newColor.B = this.B; newColor.A = this.A; newColor.H = this.H; newColor.S = this.S; newColor.L = this.L; return newColor; } function newRGB(red, green, blue) { var color = new Color(); color.R = red; color.G = red; color.B = red; return color; } function newRGBA(red, green, blue, alpha) { var color = new Color(); color.R = red; color.G = red; color.B = red; color.A = red; return color; } function clamp01(v) { if (v < 0) return 0; if (v > 1) return 1; return v; } function staticParse(text) { var color = new Color(); color.parse(text); return color; } function staticLuminance(text) { var color = staticParse(text); return color.luminance(); } module.exports._ = _; });