lml-main
Version:
This is now a mono repository published into many standalone packages.
205 lines (175 loc) • 4.81 kB
JavaScript
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
}