UNPKG

lml-main

Version:

This is now a mono repository published into many standalone packages.

205 lines (175 loc) 4.81 kB
var Color = require('color'); /** * Basic RGBA adjusters. */ exports.red = rgbaAdjuster('red'); exports.blue = rgbaAdjuster('blue'); exports.green = rgbaAdjuster('green'); exports.alpha = exports.a = rgbaAdjuster('alpha'); /** * RGB adjuster. */ exports.rgb = function () { // TODO }; /** * Basic HSLWB adjusters. */ exports.hue = exports.h = hslwbAdjuster('hue'); exports.saturation = exports.s = hslwbAdjuster('saturation'); exports.lightness = exports.l = hslwbAdjuster('lightness'); exports.whiteness = exports.w = hslwbAdjuster('whiteness'); exports.blackness = exports.b = hslwbAdjuster('blackness'); /** * Blend adjuster. * * @param {Color} color * @param {Object} args */ exports.blend = function (color, args) { var targetAlpha = color.alpha(); // Reset the alpha value to one. This is required because color.mix mixes // the alpha value as well as rgb values. For blend() purposes, that's not // what we want. color.alpha(1); var other = new Color(args[0].value); var percentage = 1 - parseInt(args[1].value, 10) / 100; // Finally set the alpha value of the mixed color to the target value. color.mix(other, percentage).alpha(targetAlpha); }; /** * Tint adjuster. * * @param {Color} color * @param {Object} args */ exports.tint = function (color, args) { args.unshift({ type: 'argument', value: 'white' }); exports.blend(color, args); }; /** * Share adjuster. * * @param {Color} color * @param {Object} args */ exports.shade = function (color, args) { args.unshift({ type: 'argument', value: 'black' }); exports.blend(color, args); }; /** * Contrast adjuster. * * @param {Color} color * @param {Object} args */ exports.contrast = function (color, args) { if (args.length == 0) args.push({ type: 'argument', value: '100%' }); var percentage = 1 - parseInt(args[0].value, 10) / 100; var max = color.luminosity() < .5 ? new Color({ h:color.hue(), w:100, b:0 }) : new Color({ h:color.hue(), w:0, b:100 }); var min = max; var minRatio = 4.5; if (color.contrast(max) > minRatio) { var min = binarySearchBWContrast(minRatio, color, max); var targetMinAlpha = min.alpha(); // Set the alpha to 1 to avoid mix()-ing the alpha value. min.alpha(1); // mixes the colors then sets the alpha back to the target alpha. min.mix(max, percentage).alpha(targetMinAlpha); } color.hwb(min.hwb()); }; /** * Generate a value or percentage of modifier. * * @param {String} prop * @return {Function} */ function rgbaAdjuster (prop) { return function (color, args) { var mod; if (args[0].type == 'modifier') mod = args.shift().value; var val = args[0].value; if (val.indexOf('%') != -1) { val = parseInt(val, 10) / 100; if (!mod) { val = val * (prop == 'alpha' ? 1 : 255); } else if (mod != '*') { val = color[prop]() * val; } } else { val = Number(val); } color[prop](modify(color[prop](), val, mod)); }; } /** * Generate a basic HSLWB adjuster. * * @param {String} prop * @return {Function} */ function hslwbAdjuster (prop) { return function (color, args) { var mod; if (args[0].type == 'modifier') mod = args.shift().value; var val = parseFloat(args[0].value, 10); color[prop](modify(color[prop](), val, mod)); }; } /** * Return the percentage of a `number` for a given percentage `string`. * * @param {Number} number * @param {String} string * @return {Number} */ function percentageOf (number, string) { var percent = parseInt(string, 10) / 100; return number * percent; } /** * Modify a `val` by an `amount` with an optional `modifier`. * * @param {Number} val * @param {Number} amount * @param {String} modifier (optional) */ function modify (val, amount, modifier) { switch (modifier) { case '+': return val + amount; case '-': return val - amount; case '*': return val * amount; default: return amount; } } /** * Return the color closest to `color` between `color` and `max` that has a contrast ratio higher than `minRatio` * assumes `color` and `max` have identical hue * * @param {Number} minRatio * @param {Color} color * @param {Color} max **/ function binarySearchBWContrast (minRatio, color, max) { var hue = color.hue(); var min = color.clone(); var minW = color.whiteness(); var minB = color.blackness(); var maxW = max.whiteness(); var maxB = max.blackness(); while (Math.abs(minW - maxW) > 1 || Math.abs(minB - maxB) > 1) { var midW = Math.round((maxW + minW) / 2); var midB = Math.round((maxB + minB) / 2); min.whiteness(midW); min.blackness(midB); if (min.contrast(color) > minRatio) { maxW = midW; maxB = midB; } else { minW = midW; minB = midB; } } return min }