UNPKG

faded

Version:

Standalone Javascript Plugin for creating visually hinted scroll views.

1,949 lines (1,693 loc) 78.7 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Fog = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ "use strict"; /*!***************************************************************************** * nelsoncash/fog * * @typedef {String|HTMLElement} container - Reference for plugin application * * @typedef {Number} midrange - Center percentage which remains style(s) max * * @typedef {Object.Number} Offset - Adjust (top/bottom) min influence * @property {Number} top - <Offset> top (min/max) influence * @property {Number} bottom - <Offset> bottom (min/max) influence * * @typedef {Object.(String|Number)} Style - Assign css style property to affect * @property {String|Number} [min] - List edge styling * @property {String|Number} [max] - List middle range styling * * * @copyright 2015 Nelson Cash * @URL https://github.com/nelsoncash/fog ******************************************************************************/ var ArgsHandler = _dereq_(2); var raf = _dereq_(34); var helper = _dereq_(5); // FIXME: Percentages are not correctly rendered. Check calc values. function Fog(element, opts){ // Variable ================================================================== var _element = element; var _oldOpts = {}; var _opts = opts; var _rafFogHandle = 0; var _isRunning = false; // Function: Private ========================================================= // Event Handler ------------------------------------------------------------- function _rafFog(){ _rafFogHandle = raf(_render); return _rafFogHandle; } function _onScrollHandler(){ if (!_isRunning) { _rafFog(); } return true; } // Calculate ----------------------------------------------------------------- function _calcRangeRelPos(pos, min, max){ return (pos - min)/(max - min); } function _calcColorMix(start, end, percent){ if (percent >= 1.0) { return start; } else if (percent <= 0) { return end; } else { var clone = start.clone(); return clone.mix(end, percent); } } /** * _calcPortionScrollStyleMin * * @param {Number} scrollPosition - Child relative position in list * @param {Number} min - Minimum percent of style influence on list * @param {Number} max - Maximum percent of style influence on list * @param {Boolean} isListBottom - Is calculation for list bottom * @return {Number} - Percent of style minimum influence */ function _calcScrollStyleMin(scrollPosition, min, max, isListTop){ var result = (max * scrollPosition); result = isListTop ? (max - result) : result; return (result < min) ? min : result; } function _render(){ _isRunning = true; // START var allChild = [].slice.call(_element.children); var allStyle = _opts.style; var listRange = _opts.range; var allChildStyle = []; var allStyleMin = {}; // All Dimension var elementHeight = _element.clientHeight; var scrollHeight = _element.scrollHeight; // Scroll Position Range var scrollTop = _element.scrollTop; var scrollBottom = scrollTop + elementHeight; scrollBottom = (scrollBottom > scrollHeight ? scrollHeight : scrollBottom); // First Child var firstChild = allChild[0]; var firstChildTop = firstChild.offsetTop; var firstChildBottom = firstChildTop + firstChild.clientHeight; // Last Child var lastChild = allChild[allChild.length - 1]; var lastChildTop = lastChild.offsetTop; var lastChildBottom = lastChildTop + lastChild.clientHeight; // List Center Range var edgeRange = (1 - listRange) / 2; var edgeRangeHeight = edgeRange * elementHeight; var edgeRangeTop = scrollTop + edgeRangeHeight; var edgeRangeBottom = scrollBottom - edgeRangeHeight; function calcListTopEdgeStyleMin(min, max){ if (scrollTop < firstChildTop) { return max; } else if (scrollTop < firstChildBottom) { return _calcScrollStyleMin( _calcRangeRelPos(scrollTop, firstChildTop, firstChildBottom), min, max, true ); } else { return min; } } function calcListBottomEdgeStyleMin(min, max){ if (scrollBottom > lastChildBottom) { return max; } else if (scrollBottom > lastChildTop) { return _calcScrollStyleMin( _calcRangeRelPos(scrollBottom, lastChildTop, lastChildBottom), min, max, false ); } else { return min; } } function calcChildStyleMin(style, min, max){ var result = {}; result.top = calcListTopEdgeStyleMin(min, max); result.bottom = calcListBottomEdgeStyleMin(min, max); return result; } // Calculate Layout allChild.forEach(function(child, index){ var childTop = child.offsetTop; var childBottom = childTop + child.offsetHeight; allChildStyle[index] = allChildStyle[index] || {}; for (var style in allStyle) { if (!allStyle.hasOwnProperty(style)) { continue; } var styleMin = allStyle[style].isColor ? 0 : allStyle[style].min; var styleMax = allStyle[style].isColor ? 1.0 : allStyle[style].max; var childStyleValue = styleMin; // Find Scroll Edges if (!allStyleMin[style]) { allStyleMin[style] = calcChildStyleMin(style, styleMin, styleMax); } // Only calculate viewable children if ((childBottom >= scrollTop) && (childTop <= scrollBottom)) { if (childTop < edgeRangeTop) { childStyleValue = styleMax * _calcRangeRelPos(childTop, scrollTop, edgeRangeTop); childStyleValue = childStyleValue < allStyleMin[style].top ? allStyleMin[style].top : childStyleValue; } else if (childBottom > edgeRangeBottom) { childStyleValue = styleMax - (styleMax * _calcRangeRelPos(childBottom, edgeRangeBottom, scrollBottom)); childStyleValue = childStyleValue < allStyleMin[style].bottom ? allStyleMin[style].bottom : childStyleValue; } else { childStyleValue = styleMax; } } if (allStyle[style].isColor) { childStyleValue = _calcColorMix( allStyle[style].max, allStyle[style].min, childStyleValue ).rgbaString(); } allChildStyle[index][style] = childStyleValue; } }); // Render Layout allChild.forEach(function(child, index){ var childStyle = allChildStyle[index]; for (var style in childStyle) { if (childStyle.hasOwnProperty(style)) { child.style[style] = childStyle[style]; } } }); _isRunning = false; // END } function _clearOpts(){ var oldAllStyle = Object.keys(_oldOpts.style); var allStyle = Object.keys(_opts.style); var allStyleToClear = helper.arrayDifference(oldAllStyle, allStyle) if (!oldAllStyle.length || !allStyleToClear.length) { return; } var allChild = [].slice.call(_element.children); allChild.forEach(function(child){ allStyleToClear.forEach(function(style){ child.style[style] = ""; }); }); } // Function: Public ========================================================== this.remove = function remove(){ var isSuccess = false; if (_onScrollHandler) { _element.removeEventListener("scroll", _onScrollHandler); isSuccess = true; } if (_isRunning && _rafFogHandle) { raf.cancel(_rafFogHandle); _rafFogHandle = 0; isSuccess = true; } return isSuccess; }; // setOpts onScroll is a NOOP because performance. // TODO: test with es6 promise this.setOpts = function setOpts(allOption){ var isSuccess = false; _oldOpts = _opts; _opts = ArgsHandler.resolveAllOption(allOption); _rafFog(); _clearOpts(); isSuccess = true; return isSuccess; }; // Initialize ---------------------------------------------------------------------- function _init(){ _element.addEventListener("scroll", _onScrollHandler); _onScrollHandler(); } _init(); } module.exports = function(element, opts){ element = ArgsHandler.resolveList(element); opts = ArgsHandler.resolveAllOption(opts); return new Fog(element, opts); }; },{"2":2,"34":34,"5":5}],2:[function(_dereq_,module,exports){ "use strict"; /* =========================================================================== * * @module ArgsHandler * * @typedef {Object} AllOption * @property {Range} * @property {AllStyle} * * @typedef {Number} Range - Center percentage which remains style(s) max * * @typedef {Object.<Style>} AllStyle - Collection of <Style> which modify element Children * * @typedef {Object} Style * @property {?(String|Number)} [min] - List edge styling * @property {?(String|Number)} [max] - List middle range styling * * @TODO: Add <Offset> to <Opts> * @typedef {Object} Offset - Adjust (top/bottom) min influence * @property {Number} top - <Offset> top (min/max) influence * @property {Number} bottom - <Offset> bottom (min/max) influence * * @copyright 2015 Nelson Cash * ========================================================================== */ var isElement = _dereq_(24); var isPlainObject = _dereq_(29); var isString = _dereq_(30); var isNumber = _dereq_(27); var Color = _dereq_(10); var config = _dereq_(3); var eLog = _dereq_(4).error; // PRIVATE ===================================================================== // Create ---------------------------------------------------------------------- /** * _createDefaultStyle * * @return {!Style} - Default Style Configuration */ function _createDefaultStyle(){ var style = {}; var prop = config.default.style; var min = config.default.min; var max = config.default.max; style[prop] = { isColor: false, min: min, max: max }; return style; } /** * _createCSSQueryString * * @param {String} str - Value to Prepare * @return {String} getElementByClassName friendly value */ function _createCSSQueryString(str){ return str.split(".").join(" ").trim(); } // Retrieve -------------------------------------------------------------------- /** * _getListElementByString * * @param {String} str - Element CSS class(s) or HTMLElement id * @return {?HTMLElement} First HTMLElement matching criteria */ function _getListElementByString(str){ var identifier = str.trim()[0]; var element = null; if (identifier === "#") { var queryString = str.slice(1); element = document.getElementById(queryString); } else if (identifier === ".") { var queryString = _createCSSQueryString(str); var allElement = document.getElementsByClassName(queryString); if (allElement.length !== 1) { eLog("Argument 'element' MUST reference single unique <HTMLElement>."); } element = allElement[0]; } else { eLog("Argument 'element' MUST reference single unique <HTMLElement>."); } return element; } // Validate -------------------------------------------------------------------- /** * _hasPropertySupported * * @param {String} prop - CSS property to query * @return {Boolean} Property Support Status */ function _hasPropertySupported(prop){ return prop in document.body.style; } // Resolve --------------------------------------------------------------------- /** * _resolveColor * * @param {String} str - Color to Construct * @return {Color} Color Object */ function _resolveColor(str){ var color; try { color = new Color(str); } catch (e) { eLog("Invalid Color " + str); } return color; } /** * _resolveStyle * * @param {String} prop - CSS property to modify * @param {Object} obj - Configuration for specifed CSS Property * @return {Style} Resolved <Style> */ function _resolveStyle(prop, obj){ var style = {}; if (prop.indexOf("color") >= 0) { if (!(obj.min || obj.max)) { eLog("One <String> (min/max) color is REQUIRED for '" + prop + "'"); } style.min = _resolveColor(obj.min || config.default.color); style.max = _resolveColor(obj.max || config.default.color); style.isColor = true; } else { style.min = (obj.min && isNumber(obj.min) ? obj.min : config.default.min); style.max = (obj.max && isNumber(obj.max) ? obj.max : config.default.max); style.isColor = false; } return style; } /** * _resolveAllStyle * * @param {!AllStyle} allStyle - <AllStyle> with resolved <Style>(s) * @return {AllStyle} Resolved <AllStyle> */ function _resolveAllStyle(allStyle){ var result = {}; for (var prop in allStyle) { if (allStyle.hasOwnProperty(prop)) { prop = prop.toLowerCase(); if (!_hasPropertySupported(prop)) { eLog("'" + prop + "' is not supported. Check README."); } result[prop] = _resolveStyle(prop, allStyle[prop]); } } return result; } // PUBLIC ====================================================================== // Resolve --------------------------------------------------------------------- /** * resolveList * * @param {!(String|HTMLElement)} arg - List Element to apply affect */ exports.resolveList = function resolveList(arg){ if (arg && isElement(arg)) { return arg; } else if (arg && isString(arg)) { return _getListElementByString(arg); } else { eLog("Argument 'element' typeof <HTMLElement> or <String> REQUIRED!"); } }; /** * resolveAllOption * * @param {AllOption} opts Plugin Configuration * @return {AllOption} Consuption Ready Plugin Configuration */ exports.resolveAllOption = function resolveAllOption(opts){ var allOpt = opts && isPlainObject(opts) ? opts : {}; if (isPlainObject(allOpt.style) && Object.keys(allOpt.style).length > 0) { // resolve opts allOpt.style = _resolveAllStyle(allOpt.style); } else { allOpt.style = _createDefaultStyle(); } var range = allOpt.range; allOpt.range = (range && isNumber(range) && range <= 1 ? range : config.default.range); return allOpt; }; },{"10":10,"24":24,"27":27,"29":29,"3":3,"30":30,"4":4}],3:[function(_dereq_,module,exports){ "use strict"; /*! =========================================================================== * * PlugConfig.js * * @summary Fog Plugin Configuration * * @copyright 2015 Nelson Cash * * https://github.com/nelsoncash/fog * ========================================================================== */ module.exports = { title: "Fog", file: "fog.js", default: { style: "opacity", min: 0.1, max: 1, color: "#FFF", range: 0.6 } }; },{}],4:[function(_dereq_,module,exports){ "use strict"; /*!***************************************************************************** * Log.js * * @copyright 2015 Nelson Cash * https://github.com/nelsoncash/fog ******************************************************************************/ var config = _dereq_(3); exports.error = function error(){ var header = config.title + ":"; var args = Array.prototype.slice.call(arguments); args.unshift(header); //console.error.apply(console, args); var message = args.join(" "); throw new Error(message, config.file); }; },{"3":3}],5:[function(_dereq_,module,exports){ "use strict"; /*!***************************************************************************** * Helper.js * * @copyright 2015 Nelson Cash * @URL https://github.com/nelsoncash/fog ******************************************************************************/ var eLog = _dereq_(4); /** * arrayDifference * * @param {Array} first * @param {Array} second * @return {Array} <Array> with difference between arguments */ exports.arrayDifference = function arrayDifference(first, second){ if (!Boolean(Array.isArray(first) && Array.isArray(second))) { eLog("(Helper.arrayExclusiveIntersect): two array arguments required.") } return first.filter(function(itemFirst){ return !second.some(function(itemSecond){ return Boolean(itemFirst === itemSecond); }); }); }; },{"4":4}],6:[function(_dereq_,module,exports){ /* MIT license */ module.exports = { rgb2hsl: rgb2hsl, rgb2hsv: rgb2hsv, rgb2hwb: rgb2hwb, rgb2cmyk: rgb2cmyk, rgb2keyword: rgb2keyword, rgb2xyz: rgb2xyz, rgb2lab: rgb2lab, rgb2lch: rgb2lch, hsl2rgb: hsl2rgb, hsl2hsv: hsl2hsv, hsl2hwb: hsl2hwb, hsl2cmyk: hsl2cmyk, hsl2keyword: hsl2keyword, hsv2rgb: hsv2rgb, hsv2hsl: hsv2hsl, hsv2hwb: hsv2hwb, hsv2cmyk: hsv2cmyk, hsv2keyword: hsv2keyword, hwb2rgb: hwb2rgb, hwb2hsl: hwb2hsl, hwb2hsv: hwb2hsv, hwb2cmyk: hwb2cmyk, hwb2keyword: hwb2keyword, cmyk2rgb: cmyk2rgb, cmyk2hsl: cmyk2hsl, cmyk2hsv: cmyk2hsv, cmyk2hwb: cmyk2hwb, cmyk2keyword: cmyk2keyword, keyword2rgb: keyword2rgb, keyword2hsl: keyword2hsl, keyword2hsv: keyword2hsv, keyword2hwb: keyword2hwb, keyword2cmyk: keyword2cmyk, keyword2lab: keyword2lab, keyword2xyz: keyword2xyz, xyz2rgb: xyz2rgb, xyz2lab: xyz2lab, xyz2lch: xyz2lch, lab2xyz: lab2xyz, lab2rgb: lab2rgb, lab2lch: lab2lch, lch2lab: lch2lab, lch2xyz: lch2xyz, lch2rgb: lch2rgb } function rgb2hsl(rgb) { var r = rgb[0]/255, g = rgb[1]/255, b = rgb[2]/255, min = Math.min(r, g, b), max = Math.max(r, g, b), delta = max - min, h, s, l; if (max == min) h = 0; else if (r == max) h = (g - b) / delta; else if (g == max) h = 2 + (b - r) / delta; else if (b == max) h = 4 + (r - g)/ delta; h = Math.min(h * 60, 360); if (h < 0) h += 360; l = (min + max) / 2; if (max == min) s = 0; else if (l <= 0.5) s = delta / (max + min); else s = delta / (2 - max - min); return [h, s * 100, l * 100]; } function rgb2hsv(rgb) { var r = rgb[0], g = rgb[1], b = rgb[2], min = Math.min(r, g, b), max = Math.max(r, g, b), delta = max - min, h, s, v; if (max == 0) s = 0; else s = (delta/max * 1000)/10; if (max == min) h = 0; else if (r == max) h = (g - b) / delta; else if (g == max) h = 2 + (b - r) / delta; else if (b == max) h = 4 + (r - g) / delta; h = Math.min(h * 60, 360); if (h < 0) h += 360; v = ((max / 255) * 1000) / 10; return [h, s, v]; } function rgb2hwb(rgb) { var r = rgb[0], g = rgb[1], b = rgb[2], h = rgb2hsl(rgb)[0], w = 1/255 * Math.min(r, Math.min(g, b)), b = 1 - 1/255 * Math.max(r, Math.max(g, b)); return [h, w * 100, b * 100]; } function rgb2cmyk(rgb) { var r = rgb[0] / 255, g = rgb[1] / 255, b = rgb[2] / 255, c, m, y, k; k = Math.min(1 - r, 1 - g, 1 - b); c = (1 - r - k) / (1 - k) || 0; m = (1 - g - k) / (1 - k) || 0; y = (1 - b - k) / (1 - k) || 0; return [c * 100, m * 100, y * 100, k * 100]; } function rgb2keyword(rgb) { return reverseKeywords[JSON.stringify(rgb)]; } function rgb2xyz(rgb) { var r = rgb[0] / 255, g = rgb[1] / 255, b = rgb[2] / 255; // assume sRGB r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92); g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92); b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92); var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805); var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722); var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505); return [x * 100, y *100, z * 100]; } function rgb2lab(rgb) { var xyz = rgb2xyz(rgb), x = xyz[0], y = xyz[1], z = xyz[2], l, a, b; x /= 95.047; y /= 100; z /= 108.883; x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116); y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116); z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116); l = (116 * y) - 16; a = 500 * (x - y); b = 200 * (y - z); return [l, a, b]; } function rgb2lch(args) { return lab2lch(rgb2lab(args)); } function hsl2rgb(hsl) { var h = hsl[0] / 360, s = hsl[1] / 100, l = hsl[2] / 100, t1, t2, t3, rgb, val; if (s == 0) { val = l * 255; return [val, val, val]; } if (l < 0.5) t2 = l * (1 + s); else t2 = l + s - l * s; t1 = 2 * l - t2; rgb = [0, 0, 0]; for (var i = 0; i < 3; i++) { t3 = h + 1 / 3 * - (i - 1); t3 < 0 && t3++; t3 > 1 && t3--; if (6 * t3 < 1) val = t1 + (t2 - t1) * 6 * t3; else if (2 * t3 < 1) val = t2; else if (3 * t3 < 2) val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; else val = t1; rgb[i] = val * 255; } return rgb; } function hsl2hsv(hsl) { var h = hsl[0], s = hsl[1] / 100, l = hsl[2] / 100, sv, v; if(l === 0) { // no need to do calc on black // also avoids divide by 0 error return [0, 0, 0]; } l *= 2; s *= (l <= 1) ? l : 2 - l; v = (l + s) / 2; sv = (2 * s) / (l + s); return [h, sv * 100, v * 100]; } function hsl2hwb(args) { return rgb2hwb(hsl2rgb(args)); } function hsl2cmyk(args) { return rgb2cmyk(hsl2rgb(args)); } function hsl2keyword(args) { return rgb2keyword(hsl2rgb(args)); } function hsv2rgb(hsv) { var h = hsv[0] / 60, s = hsv[1] / 100, v = hsv[2] / 100, hi = Math.floor(h) % 6; var f = h - Math.floor(h), p = 255 * v * (1 - s), q = 255 * v * (1 - (s * f)), t = 255 * v * (1 - (s * (1 - f))), v = 255 * v; switch(hi) { case 0: return [v, t, p]; case 1: return [q, v, p]; case 2: return [p, v, t]; case 3: return [p, q, v]; case 4: return [t, p, v]; case 5: return [v, p, q]; } } function hsv2hsl(hsv) { var h = hsv[0], s = hsv[1] / 100, v = hsv[2] / 100, sl, l; l = (2 - s) * v; sl = s * v; sl /= (l <= 1) ? l : 2 - l; sl = sl || 0; l /= 2; return [h, sl * 100, l * 100]; } function hsv2hwb(args) { return rgb2hwb(hsv2rgb(args)) } function hsv2cmyk(args) { return rgb2cmyk(hsv2rgb(args)); } function hsv2keyword(args) { return rgb2keyword(hsv2rgb(args)); } // http://dev.w3.org/csswg/css-color/#hwb-to-rgb function hwb2rgb(hwb) { var h = hwb[0] / 360, wh = hwb[1] / 100, bl = hwb[2] / 100, ratio = wh + bl, i, v, f, n; // wh + bl cant be > 1 if (ratio > 1) { wh /= ratio; bl /= ratio; } i = Math.floor(6 * h); v = 1 - bl; f = 6 * h - i; if ((i & 0x01) != 0) { f = 1 - f; } n = wh + f * (v - wh); // linear interpolation switch (i) { default: case 6: case 0: r = v; g = n; b = wh; break; case 1: r = n; g = v; b = wh; break; case 2: r = wh; g = v; b = n; break; case 3: r = wh; g = n; b = v; break; case 4: r = n; g = wh; b = v; break; case 5: r = v; g = wh; b = n; break; } return [r * 255, g * 255, b * 255]; } function hwb2hsl(args) { return rgb2hsl(hwb2rgb(args)); } function hwb2hsv(args) { return rgb2hsv(hwb2rgb(args)); } function hwb2cmyk(args) { return rgb2cmyk(hwb2rgb(args)); } function hwb2keyword(args) { return rgb2keyword(hwb2rgb(args)); } function cmyk2rgb(cmyk) { var c = cmyk[0] / 100, m = cmyk[1] / 100, y = cmyk[2] / 100, k = cmyk[3] / 100, r, g, b; r = 1 - Math.min(1, c * (1 - k) + k); g = 1 - Math.min(1, m * (1 - k) + k); b = 1 - Math.min(1, y * (1 - k) + k); return [r * 255, g * 255, b * 255]; } function cmyk2hsl(args) { return rgb2hsl(cmyk2rgb(args)); } function cmyk2hsv(args) { return rgb2hsv(cmyk2rgb(args)); } function cmyk2hwb(args) { return rgb2hwb(cmyk2rgb(args)); } function cmyk2keyword(args) { return rgb2keyword(cmyk2rgb(args)); } function xyz2rgb(xyz) { var x = xyz[0] / 100, y = xyz[1] / 100, z = xyz[2] / 100, r, g, b; r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986); g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415); b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570); // assume sRGB r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055) : r = (r * 12.92); g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055) : g = (g * 12.92); b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055) : b = (b * 12.92); r = Math.min(Math.max(0, r), 1); g = Math.min(Math.max(0, g), 1); b = Math.min(Math.max(0, b), 1); return [r * 255, g * 255, b * 255]; } function xyz2lab(xyz) { var x = xyz[0], y = xyz[1], z = xyz[2], l, a, b; x /= 95.047; y /= 100; z /= 108.883; x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116); y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116); z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116); l = (116 * y) - 16; a = 500 * (x - y); b = 200 * (y - z); return [l, a, b]; } function xyz2lch(args) { return lab2lch(xyz2lab(args)); } function lab2xyz(lab) { var l = lab[0], a = lab[1], b = lab[2], x, y, z, y2; if (l <= 8) { y = (l * 100) / 903.3; y2 = (7.787 * (y / 100)) + (16 / 116); } else { y = 100 * Math.pow((l + 16) / 116, 3); y2 = Math.pow(y / 100, 1/3); } x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3); z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3); return [x, y, z]; } function lab2lch(lab) { var l = lab[0], a = lab[1], b = lab[2], hr, h, c; hr = Math.atan2(b, a); h = hr * 360 / 2 / Math.PI; if (h < 0) { h += 360; } c = Math.sqrt(a * a + b * b); return [l, c, h]; } function lab2rgb(args) { return xyz2rgb(lab2xyz(args)); } function lch2lab(lch) { var l = lch[0], c = lch[1], h = lch[2], a, b, hr; hr = h / 360 * 2 * Math.PI; a = c * Math.cos(hr); b = c * Math.sin(hr); return [l, a, b]; } function lch2xyz(args) { return lab2xyz(lch2lab(args)); } function lch2rgb(args) { return lab2rgb(lch2lab(args)); } function keyword2rgb(keyword) { return cssKeywords[keyword]; } function keyword2hsl(args) { return rgb2hsl(keyword2rgb(args)); } function keyword2hsv(args) { return rgb2hsv(keyword2rgb(args)); } function keyword2hwb(args) { return rgb2hwb(keyword2rgb(args)); } function keyword2cmyk(args) { return rgb2cmyk(keyword2rgb(args)); } function keyword2lab(args) { return rgb2lab(keyword2rgb(args)); } function keyword2xyz(args) { return rgb2xyz(keyword2rgb(args)); } var cssKeywords = { aliceblue: [240,248,255], antiquewhite: [250,235,215], aqua: [0,255,255], aquamarine: [127,255,212], azure: [240,255,255], beige: [245,245,220], bisque: [255,228,196], black: [0,0,0], blanchedalmond: [255,235,205], blue: [0,0,255], blueviolet: [138,43,226], brown: [165,42,42], burlywood: [222,184,135], cadetblue: [95,158,160], chartreuse: [127,255,0], chocolate: [210,105,30], coral: [255,127,80], cornflowerblue: [100,149,237], cornsilk: [255,248,220], crimson: [220,20,60], cyan: [0,255,255], darkblue: [0,0,139], darkcyan: [0,139,139], darkgoldenrod: [184,134,11], darkgray: [169,169,169], darkgreen: [0,100,0], darkgrey: [169,169,169], darkkhaki: [189,183,107], darkmagenta: [139,0,139], darkolivegreen: [85,107,47], darkorange: [255,140,0], darkorchid: [153,50,204], darkred: [139,0,0], darksalmon: [233,150,122], darkseagreen: [143,188,143], darkslateblue: [72,61,139], darkslategray: [47,79,79], darkslategrey: [47,79,79], darkturquoise: [0,206,209], darkviolet: [148,0,211], deeppink: [255,20,147], deepskyblue: [0,191,255], dimgray: [105,105,105], dimgrey: [105,105,105], dodgerblue: [30,144,255], firebrick: [178,34,34], floralwhite: [255,250,240], forestgreen: [34,139,34], fuchsia: [255,0,255], gainsboro: [220,220,220], ghostwhite: [248,248,255], gold: [255,215,0], goldenrod: [218,165,32], gray: [128,128,128], green: [0,128,0], greenyellow: [173,255,47], grey: [128,128,128], honeydew: [240,255,240], hotpink: [255,105,180], indianred: [205,92,92], indigo: [75,0,130], ivory: [255,255,240], khaki: [240,230,140], lavender: [230,230,250], lavenderblush: [255,240,245], lawngreen: [124,252,0], lemonchiffon: [255,250,205], lightblue: [173,216,230], lightcoral: [240,128,128], lightcyan: [224,255,255], lightgoldenrodyellow: [250,250,210], lightgray: [211,211,211], lightgreen: [144,238,144], lightgrey: [211,211,211], lightpink: [255,182,193], lightsalmon: [255,160,122], lightseagreen: [32,178,170], lightskyblue: [135,206,250], lightslategray: [119,136,153], lightslategrey: [119,136,153], lightsteelblue: [176,196,222], lightyellow: [255,255,224], lime: [0,255,0], limegreen: [50,205,50], linen: [250,240,230], magenta: [255,0,255], maroon: [128,0,0], mediumaquamarine: [102,205,170], mediumblue: [0,0,205], mediumorchid: [186,85,211], mediumpurple: [147,112,219], mediumseagreen: [60,179,113], mediumslateblue: [123,104,238], mediumspringgreen: [0,250,154], mediumturquoise: [72,209,204], mediumvioletred: [199,21,133], midnightblue: [25,25,112], mintcream: [245,255,250], mistyrose: [255,228,225], moccasin: [255,228,181], navajowhite: [255,222,173], navy: [0,0,128], oldlace: [253,245,230], olive: [128,128,0], olivedrab: [107,142,35], orange: [255,165,0], orangered: [255,69,0], orchid: [218,112,214], palegoldenrod: [238,232,170], palegreen: [152,251,152], paleturquoise: [175,238,238], palevioletred: [219,112,147], papayawhip: [255,239,213], peachpuff: [255,218,185], peru: [205,133,63], pink: [255,192,203], plum: [221,160,221], powderblue: [176,224,230], purple: [128,0,128], rebeccapurple: [102, 51, 153], red: [255,0,0], rosybrown: [188,143,143], royalblue: [65,105,225], saddlebrown: [139,69,19], salmon: [250,128,114], sandybrown: [244,164,96], seagreen: [46,139,87], seashell: [255,245,238], sienna: [160,82,45], silver: [192,192,192], skyblue: [135,206,235], slateblue: [106,90,205], slategray: [112,128,144], slategrey: [112,128,144], snow: [255,250,250], springgreen: [0,255,127], steelblue: [70,130,180], tan: [210,180,140], teal: [0,128,128], thistle: [216,191,216], tomato: [255,99,71], turquoise: [64,224,208], violet: [238,130,238], wheat: [245,222,179], white: [255,255,255], whitesmoke: [245,245,245], yellow: [255,255,0], yellowgreen: [154,205,50] }; var reverseKeywords = {}; for (var key in cssKeywords) { reverseKeywords[JSON.stringify(cssKeywords[key])] = key; } },{}],7:[function(_dereq_,module,exports){ var conversions = _dereq_(6); var convert = function() { return new Converter(); } for (var func in conversions) { // export Raw versions convert[func + "Raw"] = (function(func) { // accept array or plain args return function(arg) { if (typeof arg == "number") arg = Array.prototype.slice.call(arguments); return conversions[func](arg); } })(func); var pair = /(\w+)2(\w+)/.exec(func), from = pair[1], to = pair[2]; // export rgb2hsl and ["rgb"]["hsl"] convert[from] = convert[from] || {}; convert[from][to] = convert[func] = (function(func) { return function(arg) { if (typeof arg == "number") arg = Array.prototype.slice.call(arguments); var val = conversions[func](arg); if (typeof val == "string" || val === undefined) return val; // keyword for (var i = 0; i < val.length; i++) val[i] = Math.round(val[i]); return val; } })(func); } /* Converter does lazy conversion and caching */ var Converter = function() { this.convs = {}; }; /* Either get the values for a space or set the values for a space, depending on args */ Converter.prototype.routeSpace = function(space, args) { var values = args[0]; if (values === undefined) { // color.rgb() return this.getValues(space); } // color.rgb(10, 10, 10) if (typeof values == "number") { values = Array.prototype.slice.call(args); } return this.setValues(space, values); }; /* Set the values for a space, invalidating cache */ Converter.prototype.setValues = function(space, values) { this.space = space; this.convs = {}; this.convs[space] = values; return this; }; /* Get the values for a space. If there's already a conversion for the space, fetch it, otherwise compute it */ Converter.prototype.getValues = function(space) { var vals = this.convs[space]; if (!vals) { var fspace = this.space, from = this.convs[fspace]; vals = convert[fspace][space](from); this.convs[space] = vals; } return vals; }; ["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) { Converter.prototype[space] = function(vals) { return this.routeSpace(space, arguments); } }); module.exports = convert; },{"6":6}],8:[function(_dereq_,module,exports){ module.exports={ "aliceblue": [240, 248, 255], "antiquewhite": [250, 235, 215], "aqua": [0, 255, 255], "aquamarine": [127, 255, 212], "azure": [240, 255, 255], "beige": [245, 245, 220], "bisque": [255, 228, 196], "black": [0, 0, 0], "blanchedalmond": [255, 235, 205], "blue": [0, 0, 255], "blueviolet": [138, 43, 226], "brown": [165, 42, 42], "burlywood": [222, 184, 135], "cadetblue": [95, 158, 160], "chartreuse": [127, 255, 0], "chocolate": [210, 105, 30], "coral": [255, 127, 80], "cornflowerblue": [100, 149, 237], "cornsilk": [255, 248, 220], "crimson": [220, 20, 60], "cyan": [0, 255, 255], "darkblue": [0, 0, 139], "darkcyan": [0, 139, 139], "darkgoldenrod": [184, 134, 11], "darkgray": [169, 169, 169], "darkgreen": [0, 100, 0], "darkgrey": [169, 169, 169], "darkkhaki": [189, 183, 107], "darkmagenta": [139, 0, 139], "darkolivegreen": [85, 107, 47], "darkorange": [255, 140, 0], "darkorchid": [153, 50, 204], "darkred": [139, 0, 0], "darksalmon": [233, 150, 122], "darkseagreen": [143, 188, 143], "darkslateblue": [72, 61, 139], "darkslategray": [47, 79, 79], "darkslategrey": [47, 79, 79], "darkturquoise": [0, 206, 209], "darkviolet": [148, 0, 211], "deeppink": [255, 20, 147], "deepskyblue": [0, 191, 255], "dimgray": [105, 105, 105], "dimgrey": [105, 105, 105], "dodgerblue": [30, 144, 255], "firebrick": [178, 34, 34], "floralwhite": [255, 250, 240], "forestgreen": [34, 139, 34], "fuchsia": [255, 0, 255], "gainsboro": [220, 220, 220], "ghostwhite": [248, 248, 255], "gold": [255, 215, 0], "goldenrod": [218, 165, 32], "gray": [128, 128, 128], "green": [0, 128, 0], "greenyellow": [173, 255, 47], "grey": [128, 128, 128], "honeydew": [240, 255, 240], "hotpink": [255, 105, 180], "indianred": [205, 92, 92], "indigo": [75, 0, 130], "ivory": [255, 255, 240], "khaki": [240, 230, 140], "lavender": [230, 230, 250], "lavenderblush": [255, 240, 245], "lawngreen": [124, 252, 0], "lemonchiffon": [255, 250, 205], "lightblue": [173, 216, 230], "lightcoral": [240, 128, 128], "lightcyan": [224, 255, 255], "lightgoldenrodyellow": [250, 250, 210], "lightgray": [211, 211, 211], "lightgreen": [144, 238, 144], "lightgrey": [211, 211, 211], "lightpink": [255, 182, 193], "lightsalmon": [255, 160, 122], "lightseagreen": [32, 178, 170], "lightskyblue": [135, 206, 250], "lightslategray": [119, 136, 153], "lightslategrey": [119, 136, 153], "lightsteelblue": [176, 196, 222], "lightyellow": [255, 255, 224], "lime": [0, 255, 0], "limegreen": [50, 205, 50], "linen": [250, 240, 230], "magenta": [255, 0, 255], "maroon": [128, 0, 0], "mediumaquamarine": [102, 205, 170], "mediumblue": [0, 0, 205], "mediumorchid": [186, 85, 211], "mediumpurple": [147, 112, 219], "mediumseagreen": [60, 179, 113], "mediumslateblue": [123, 104, 238], "mediumspringgreen": [0, 250, 154], "mediumturquoise": [72, 209, 204], "mediumvioletred": [199, 21, 133], "midnightblue": [25, 25, 112], "mintcream": [245, 255, 250], "mistyrose": [255, 228, 225], "moccasin": [255, 228, 181], "navajowhite": [255, 222, 173], "navy": [0, 0, 128], "oldlace": [253, 245, 230], "olive": [128, 128, 0], "olivedrab": [107, 142, 35], "orange": [255, 165, 0], "orangered": [255, 69, 0], "orchid": [218, 112, 214], "palegoldenrod": [238, 232, 170], "palegreen": [152, 251, 152], "paleturquoise": [175, 238, 238], "palevioletred": [219, 112, 147], "papayawhip": [255, 239, 213], "peachpuff": [255, 218, 185], "peru": [205, 133, 63], "pink": [255, 192, 203], "plum": [221, 160, 221], "powderblue": [176, 224, 230], "purple": [128, 0, 128], "rebeccapurple": [102, 51, 153], "red": [255, 0, 0], "rosybrown": [188, 143, 143], "royalblue": [65, 105, 225], "saddlebrown": [139, 69, 19], "salmon": [250, 128, 114], "sandybrown": [244, 164, 96], "seagreen": [46, 139, 87], "seashell": [255, 245, 238], "sienna": [160, 82, 45], "silver": [192, 192, 192], "skyblue": [135, 206, 235], "slateblue": [106, 90, 205], "slategray": [112, 128, 144], "slategrey": [112, 128, 144], "snow": [255, 250, 250], "springgreen": [0, 255, 127], "steelblue": [70, 130, 180], "tan": [210, 180, 140], "teal": [0, 128, 128], "thistle": [216, 191, 216], "tomato": [255, 99, 71], "turquoise": [64, 224, 208], "violet": [238, 130, 238], "wheat": [245, 222, 179], "white": [255, 255, 255], "whitesmoke": [245, 245, 245], "yellow": [255, 255, 0], "yellowgreen": [154, 205, 50] } },{}],9:[function(_dereq_,module,exports){ /* MIT license */ var colorNames = _dereq_(8); module.exports = { getRgba: getRgba, getHsla: getHsla, getRgb: getRgb, getHsl: getHsl, getHwb: getHwb, getAlpha: getAlpha, hexString: hexString, rgbString: rgbString, rgbaString: rgbaString, percentString: percentString, percentaString: percentaString, hslString: hslString, hslaString: hslaString, hwbString: hwbString, keyword: keyword } function getRgba(string) { if (!string) { return; } var abbr = /^#([a-fA-F0-9]{3})$/, hex = /^#([a-fA-F0-9]{6})$/, rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/, per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/, keyword = /(\D+)/; var rgb = [0, 0, 0], a = 1, match = string.match(abbr); if (match) { match = match[1]; for (var i = 0; i < rgb.length; i++) { rgb[i] = parseInt(match[i] + match[i], 16); } } else if (match = string.match(hex)) { match = match[1]; for (var i = 0; i < rgb.length; i++) { rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16); } } else if (match = string.match(rgba)) { for (var i = 0; i < rgb.length; i++) { rgb[i] = parseInt(match[i + 1]); } a = parseFloat(match[4]); } else if (match = string.match(per)) { for (var i = 0; i < rgb.length; i++) { rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55); } a = parseFloat(match[4]); } else if (match = string.match(keyword)) { if (match[1] == "transparent") { return [0, 0, 0, 0]; } rgb = colorNames[match[1]]; if (!rgb) { return; } } for (var i = 0; i < rgb.length; i++) { rgb[i] = scale(rgb[i], 0, 255); } if (!a && a != 0) { a = 1; } else { a = scale(a, 0, 1); } rgb[3] = a; return rgb; } function getHsla(string) { if (!string) { return; } var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/; var match = string.match(hsl); if (match) { var alpha = parseFloat(match[4]); var h = scale(parseInt(match[1]), 0, 360), s = scale(parseFloat(match[2]), 0, 100), l = scale(parseFloat(match[3]), 0, 100), a = scale(isNaN(alpha) ? 1 : alpha, 0, 1); return [h, s, l, a]; } } function getHwb(string) { if (!string) { return; } var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/; var match = string.match(hwb); if (match) { var alpha = parseFloat(match[4]); var h = scale(parseInt(match[1]), 0, 360), w = scale(parseFloat(match[2]), 0, 100), b = scale(parseFloat(match[3]), 0, 100), a = scale(isNaN(alpha) ? 1 : alpha, 0, 1); return [h, w, b, a]; } } function getRgb(string) { var rgba = getRgba(string); return rgba && rgba.slice(0, 3); } function getHsl(string) { var hsla = getHsla(string); return hsla && hsla.slice(0, 3); } function getAlpha(string) { var vals = getRgba(string); if (vals) { return vals[3]; } else if (vals = getHsla(string)) { return vals[3]; } else if (vals = getHwb(string)) { return vals[3]; } } // generators function hexString(rgb) { return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1]) + hexDouble(rgb[2]); } function rgbString(rgba, alpha) { if (alpha < 1 || (rgba[3] && rgba[3] < 1)) { return rgbaString(rgba, alpha); } return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")"; } function rgbaString(rgba, alpha) { if (alpha === undefined) { alpha = (rgba[3] !== undefined ? rgba[3] : 1); } return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ", " + alpha + ")"; } function percentString(rgba, alpha) { if (alpha < 1 || (rgba[3] && rgba[3] < 1)) { return percentaString(rgba, alpha); } var r = Math.round(rgba[0]/255 * 100), g = Math.round(rgba[1]/255 * 100), b = Math.round(rgba[2]/255 * 100); return "rgb(" + r + "%, " + g + "%, " + b + "%)"; } function percentaString(rgba, alpha) { var r = Math.round(rgba[0]/255 * 100), g = Math.round(rgba[1]/255 * 100), b = Math.round(rgba[2]/255 * 100); return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")"; } function hslString(hsla, alpha) { if (alpha < 1 || (hsla[3] && hsla[3] < 1)) { return hslaString(hsla, alpha); } return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)"; } function hslaString(hsla, alpha) { if (alpha === undefined) { alpha = (hsla[3] !== undefined ? hsla[3] : 1); } return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " + alpha + ")"; } // hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax // (hwb have alpha optional & 1 is default value) function hwbString(hwb, alpha) { if (alpha === undefined) { alpha = (hwb[3] !== undefined ? hwb[3] : 1); } return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%" + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")"; } function keyword(rgb) { return reverseNames[rgb.slice(0, 3)]; } // helpers function scale(num, min, max) { return Math.min(Math.max(min, num), max); } function hexDouble(num) { var str = num.toString(16).toUpperCase(); return (str.length < 2) ? "0" + str : str; } //create a list of reverse color names var reverseNames = {}; for (var name in colorNames) { reverseNames[colorNames[name]] = name; } },{"8":8}],10:[function(_dereq_,module,exports){ /* MIT license */ var convert = _dereq_(7), string = _dereq_(9); var Color = function(obj) { if (obj instanceof Color) return obj; if (! (this instanceof Color)) return new Color(obj); this.values = { rgb: [0, 0, 0], hsl: [0, 0, 0], hsv: [0, 0, 0], hwb: [0, 0, 0], cmyk: [0, 0, 0, 0], alpha: 1 } // parse Color() argument if (typeof obj == "string") { var vals = string.getRgba(obj); if (vals) { this.setValues("rgb", vals); } else if(vals = string.getHsla(obj)) { this.setValues("hsl", vals); } else if(vals = string.getHwb(obj)) { this.setValues("hwb", vals); } else { throw new Error("Unable to parse color from string \"" + obj + "\""); } } else if (typeof obj == "object") { var vals = obj; if(vals["r"] !== undefined || vals["red"] !== undefined) { this.setValues("rgb", vals) } else if(vals["l"] !== undefined || vals["lightness"] !== undefined) { this.setValues("hsl", vals) } else if(vals["v"] !== undefined || vals["value"] !== undefined) { this.setValues("hsv", vals) } else if(vals["w"] !== undefined || vals["whiteness"] !== undefined) { this.setValues("hwb", vals) } else if(vals["c"] !== undefined || vals["cyan"] !== undefined) { this.setValues("cmyk", vals) } else { throw new Error("Unable to parse color from object " + JSON.stringify(obj)); } } } Color.prototype = { rgb: function (vals) { return this.setSpace("rgb", arguments); }, hsl: function(vals) { return this.setSpace("hsl", arguments); }, hsv: function(vals) { return this.setSpace("hsv", arguments); }, hwb: function(vals) { return this.setSpace("hwb", arguments); }, cmyk: function(vals) { return this.setSpace("cmyk", arguments); }, rgbArray: function() { return this.values.rgb; }, hslArray: function() { return this.values.hsl; }, hsvArray: function() { return this.values.hsv; }, hwbArray: function() { if (this.values.alpha !== 1) { return this.values.hwb.concat([this.values.alpha]) } return this.values.hwb; }, cmykArray: function() { return this.values.cmyk; }, rgbaArray: function() { var rgb = this.values.rgb; return rgb.concat([this.values.alpha]); }, hslaArray: function() { var hsl = this.values.hsl; return hsl.concat([this.values.alpha]); }, alpha: function(val) { if (val === undefined) { return this.values.alpha; } this.setValues("alpha", val); return this; }, red: function(val) { return this.setChannel("rgb", 0, val); }, green: function(val) { return this.setChannel("rgb", 1, val); }, blue: function(val) { return this.setChannel("rgb", 2, val); }, hue: function(val) { return this.setChannel("hsl", 0, val); }, saturation: function(val) { return this.setChannel("hsl", 1, val); }, lightness: function(val) { return this.setChannel("hsl", 2, val); }, saturationv: function(val) { return this.setChannel("hsv", 1, val); }, whiteness: function(val) { return this.setChannel("hwb", 1, val); }, blackness: function(val) { return this.setChannel("hwb", 2, val); }, value: function(val) { return this.setChannel("hsv", 2, val); }, cyan: function(val) { return this.setChannel("cmyk", 0, val); }, magenta: function(val) { return this.setChannel("cmyk", 1, val); }, yellow: function(val) { return this.setChannel("cmyk", 2, val); }, black: function(val) { return this.setChannel("cmyk", 3, val); }, hexString: function() { return string.hexString(this.values.rgb); }, rgbString: function() { return string.rgbString(this.values.rgb, this.values.alpha); }, rgbaString: function() { return string.rgbaString(this.values.rgb, this.values.alpha); }, percentString: function() { return string.percentString(this.values.rgb, this.values.alpha); }, hslString: function() { return string.hslString(this.values.hsl, this.values.alpha); }, hslaString: function() { return string.hslaString(this.values.hsl, this.values.alpha); }, hwbString: function() { return string.hwbString(this.values.hwb, this.values.alpha); }, keyword: function() { return string.keyword(this.values.rgb, this.values.alpha); }, rgbNumber: function() { return (this.values.rgb[0] << 16) | (this.values.rgb[1] << 8) | this.values.rgb[2]; }, luminosity: function() { // http://www.w3.org/TR/WCAG20/#relativeluminancedef var rgb = this.values.rgb; var lum = []; for (var i = 0; i < rgb.length; i++) { var chan = rgb[i] / 255; lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4) } return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2]; }, contrast: function(color2) { // http://www.w3.org/TR/WCAG20/#contrast-ratiodef var lum1 = this.luminosity(); var lum2 = color2.luminosity(); if (lum1 > lum2) { return (lum1 + 0.05) / (lum2 + 0.05) }; return (lum2 + 0.05) / (lum1 + 0.05); }, level: function(color2) { var contrastRatio = this.contrast(color2); return (contrastRatio >= 7.1) ? 'AA