diff --git a/README.md b/README.md index 165777a..9ae7763 100644 --- a/README.md +++ b/README.md @@ -405,6 +405,7 @@ tinycolor("#f00").complement().toHexString(); // "#00ffff" ```js tinycolor.equals(color1, color2) tinycolor.mix(color1, color2, amount = 50) +tinycolor.alphaBlend('#f008', '#0f08') // #ae5100 ``` ### random diff --git a/test/test.js b/test/test.js index d5bd787..0622807 100644 --- a/test/test.js +++ b/test/test.js @@ -634,6 +634,12 @@ test("isReadable", function() { ok(tinycolor.isReadable("#db91b8", "#2e0c3a",{level:"AA",size:"large"}), "readable - AA large"); ok(tinycolor.isReadable("#db91b8", "#2e0c3a",{level:"AAA",size:"small"}), "readable - AAA small"); ok(tinycolor.isReadable("#db91b8", "#2e0c3a",{level:"AAA",size:"large"}), "readable - AAA large"); + + // transparency + // "#0009" as foreground: contrast ratio 5.74 + // "#0009" as background: contrast ration between 5.74 and 21 + ok(!tinycolor.isReadable("#fff", "#0009",{level:"AAA",size:"small"}), "not readable - transparency"); + ok(tinycolor.isReadable("#fff", "#0009",{level:"AA",size:"small"}), "readable - transparency"); }); test("readability", function() { @@ -750,6 +756,14 @@ test("Mix", function () { } }); +test("AlphaBlend", function () { + equal(tinycolor.alphaBlend('#fff', '#000').toHex(), 'ffffff', "Blending with solid foreground returns foreground"); + equal(tinycolor.alphaBlend('#fff0', '#000').toHex(), '000000', "Blending with full transparent foreground returns background"); + equal(tinycolor.alphaBlend('#f008', '#0f0').toHex(), '887700', "Blending with solid background works"); + equal(tinycolor.alphaBlend('#f008', '#0f08').toHex(), 'ae5100', "Blending works"); + equal(tinycolor.alphaBlend('#fff0', '#0000').toHex(), '000000', "Blending returns background if both are fully transparent"); +}); + // The combination tests need to be expanded further module("Combinations"); diff --git a/tinycolor.js b/tinycolor.js index 9580299..0443d5d 100644 --- a/tinycolor.js +++ b/tinycolor.js @@ -716,17 +716,59 @@ tinycolor.mix = function(color1, color2, amount) { return tinycolor(rgba); }; +tinycolor.alphaBlend = function(foreground, background) { + var c1 = tinycolor(foreground); + var a1 = c1.getAlpha(); + var rgb1 = c1.toRgb(); + + var c2 = tinycolor(background); + var a2 = c2.getAlpha(); + var rgb2 = c2.toRgb(); + + if (a1 === 0 && a2 === 0) { + return c2; + } + + var alpha = a1 + (1 - a1) * a2; + + return tinycolor({ + r: (a1 * rgb1.r + (1 - a1) * a2 * rgb2.r) / alpha, + g: (a1 * rgb1.g + (1 - a1) * a2 * rgb2.g) / alpha, + b: (a1 * rgb1.b + (1 - a1) * a2 * rgb2.b) / alpha, + a: alpha + }); +}; // Readability Functions // --------------------- // fg.getLuminance()) { + return _readability(foreground, bgOnBlack); + } else { + return 1; + } +} + // `contrast` // Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2) tinycolor.readability = function(color1, color2) { - var c1 = tinycolor(color1); - var c2 = tinycolor(color2); - return (Math.max(c1.getLuminance(),c2.getLuminance())+0.05) / (Math.min(c1.getLuminance(),c2.getLuminance())+0.05); + var r1 = _readability_minimal(color1, color2); + var r2 = _readability_minimal(color2, color1); + return (r1 + r2) / 2; }; // `isReadable`