diff options
Diffstat (limited to 'node_modules/stylus/lib/functions/contrast.js')
| -rw-r--r-- | node_modules/stylus/lib/functions/contrast.js | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/node_modules/stylus/lib/functions/contrast.js b/node_modules/stylus/lib/functions/contrast.js new file mode 100644 index 00000000..7e59c891 --- /dev/null +++ b/node_modules/stylus/lib/functions/contrast.js @@ -0,0 +1,75 @@ +var utils = require('../utils') + , nodes = require('../nodes') + , blend = require('./blend') + , luminosity = require('./luminosity'); + +/** + * Returns the contrast ratio object between `top` and `bottom` colors, + * based on http://leaverou.github.io/contrast-ratio/ + * and https://github.com/LeaVerou/contrast-ratio/blob/gh-pages/color.js#L108 + * + * Examples: + * + * contrast(#000, #fff).ratio + * => 21 + * + * contrast(#000, rgba(#FFF, 0.5)) + * => { "ratio": "13.15;", "error": "7.85", "min": "5.3", "max": "21" } + * + * @param {RGBA|HSLA} top + * @param {RGBA|HSLA} [bottom=#fff] + * @return {Object} + * @api public + */ + +module.exports = function contrast(top, bottom){ + if ('rgba' != top.nodeName && 'hsla' != top.nodeName) { + return new nodes.Literal('contrast(' + (top.isNull ? '' : top.toString()) + ')'); + } + var result = new nodes.Object(); + top = top.rgba; + bottom = bottom || new nodes.RGBA(255, 255, 255, 1); + utils.assertColor(bottom); + bottom = bottom.rgba; + function contrast(top, bottom) { + if (1 > top.a) { + top = blend(top, bottom); + } + var l1 = luminosity(bottom).val + 0.05 + , l2 = luminosity(top).val + 0.05 + , ratio = l1 / l2; + + if (l2 > l1) { + ratio = 1 / ratio; + } + return Math.round(ratio * 10) / 10; + } + + if (1 <= bottom.a) { + var resultRatio = new nodes.Unit(contrast(top, bottom)); + result.set('ratio', resultRatio); + result.set('error', new nodes.Unit(0)); + result.set('min', resultRatio); + result.set('max', resultRatio); + } else { + var onBlack = contrast(top, blend(bottom, new nodes.RGBA(0, 0, 0, 1))) + , onWhite = contrast(top, blend(bottom, new nodes.RGBA(255, 255, 255, 1))) + , max = Math.max(onBlack, onWhite); + function processChannel(topChannel, bottomChannel) { + return Math.min(Math.max(0, (topChannel - bottomChannel * bottom.a) / (1 - bottom.a)), 255); + } + var closest = new nodes.RGBA( + processChannel(top.r, bottom.r), + processChannel(top.g, bottom.g), + processChannel(top.b, bottom.b), + 1 + ); + var min = contrast(top, blend(bottom, closest)); + + result.set('ratio', new nodes.Unit(Math.round((min + max) * 50) / 100)); + result.set('error', new nodes.Unit(Math.round((max - min) * 50) / 100)); + result.set('min', new nodes.Unit(min)); + result.set('max', new nodes.Unit(max)); + } + return result; +} |
