aboutsummaryrefslogtreecommitdiff
path: root/node_modules/stylus/lib/functions/contrast.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/stylus/lib/functions/contrast.js')
-rw-r--r--node_modules/stylus/lib/functions/contrast.js75
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;
+}