|
|
|
@ -1343,6 +1343,21 @@ export default function ($, undefined?: any) { |
|
|
|
var rgb = this.toRgb(); |
|
|
|
return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; |
|
|
|
}, |
|
|
|
getLuminance: function () { |
|
|
|
// http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
|
|
|
|
var rgb = this.toRgb(); |
|
|
|
var RsRGB, GsRGB, BsRGB, R, G, B; |
|
|
|
RsRGB = rgb.r / 255; |
|
|
|
GsRGB = rgb.g / 255; |
|
|
|
BsRGB = rgb.b / 255; |
|
|
|
if (RsRGB <= 0.03928) R = RsRGB / 12.92; |
|
|
|
else R = Math.pow((RsRGB + 0.055) / 1.055, 2.4); |
|
|
|
if (GsRGB <= 0.03928) G = GsRGB / 12.92; |
|
|
|
else G = Math.pow((GsRGB + 0.055) / 1.055, 2.4); |
|
|
|
if (BsRGB <= 0.03928) B = BsRGB / 12.92; |
|
|
|
else B = Math.pow((BsRGB + 0.055) / 1.055, 2.4); |
|
|
|
return 0.2126 * R + 0.7152 * G + 0.0722 * B; |
|
|
|
}, |
|
|
|
setAlpha: function (value) { |
|
|
|
this._a = boundAlpha(value); |
|
|
|
this._roundA = mathRound(100 * this._a) / 100; |
|
|
|
@ -2013,71 +2028,85 @@ export default function ($, undefined?: any) { |
|
|
|
|
|
|
|
// Readability Functions
|
|
|
|
// ---------------------
|
|
|
|
// <http://www.w3.org/TR/AERT#color-contrast>
|
|
|
|
// <http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
|
|
|
|
|
|
|
|
// `readability`
|
|
|
|
// Analyze the 2 colors and returns an object with the following properties:
|
|
|
|
// `brightness`: difference in brightness between the two colors
|
|
|
|
// `color`: difference in color/hue between the two colors
|
|
|
|
// `readibility`
|
|
|
|
// 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); |
|
|
|
var rgb1 = c1.toRgb(); |
|
|
|
var rgb2 = c2.toRgb(); |
|
|
|
var brightnessA = c1.getBrightness(); |
|
|
|
var brightnessB = c2.getBrightness(); |
|
|
|
var colorDiff = |
|
|
|
Math.max(rgb1.r, rgb2.r) - |
|
|
|
Math.min(rgb1.r, rgb2.r) + |
|
|
|
Math.max(rgb1.g, rgb2.g) - |
|
|
|
Math.min(rgb1.g, rgb2.g) + |
|
|
|
Math.max(rgb1.b, rgb2.b) - |
|
|
|
Math.min(rgb1.b, rgb2.b); |
|
|
|
|
|
|
|
return { |
|
|
|
brightness: Math.abs(brightnessA - brightnessB), |
|
|
|
color: colorDiff, |
|
|
|
}; |
|
|
|
return ( |
|
|
|
(Math.max(c1.getLuminance(), c2.getLuminance()) + 0.05) / (Math.min(c1.getLuminance(), c2.getLuminance()) + 0.05) |
|
|
|
); |
|
|
|
}; |
|
|
|
|
|
|
|
// `readable`
|
|
|
|
// http://www.w3.org/TR/AERT#color-contrast
|
|
|
|
// Ensure that foreground and background color combinations provide sufficient contrast.
|
|
|
|
// `isReadable`
|
|
|
|
// Ensure that foreground and background color combinations meet WCAG2 guidelines.
|
|
|
|
// The third argument is an optional Object.
|
|
|
|
// the 'level' property states 'AA' or 'AAA' - if missing or invalid, it defaults to 'AA';
|
|
|
|
// the 'size' property states 'large' or 'small' - if missing or invalid, it defaults to 'small'.
|
|
|
|
// If the entire object is absent, isReadable defaults to {level:"AA",size:"small"}.
|
|
|
|
|
|
|
|
// *Example*
|
|
|
|
// tinycolor.isReadable("#000", "#111") => false
|
|
|
|
tinycolor.isReadable = function (color1, color2) { |
|
|
|
// tinycolor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false
|
|
|
|
tinycolor.isReadable = function (color1, color2, wcag2) { |
|
|
|
var readability = tinycolor.readability(color1, color2); |
|
|
|
return readability.brightness > 125 && readability.color > 500; |
|
|
|
var wcag2Parms, out; |
|
|
|
out = false; |
|
|
|
wcag2Parms = validateWCAG2Parms(wcag2); |
|
|
|
switch (wcag2Parms.level + wcag2Parms.size) { |
|
|
|
case 'AAsmall': |
|
|
|
case 'AAAlarge': |
|
|
|
out = readability >= 4.5; |
|
|
|
break; |
|
|
|
case 'AAlarge': |
|
|
|
out = readability >= 3; |
|
|
|
break; |
|
|
|
case 'AAAsmall': |
|
|
|
out = readability >= 7; |
|
|
|
break; |
|
|
|
} |
|
|
|
return out; |
|
|
|
}; |
|
|
|
|
|
|
|
// `mostReadable`
|
|
|
|
// Given a base color and a list of possible foreground or background
|
|
|
|
// colors for that base, returns the most readable color.
|
|
|
|
// Optionally returns Black or White if the most readable color is unreadable.
|
|
|
|
// *Example*
|
|
|
|
// tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000"
|
|
|
|
tinycolor.mostReadable = function (baseColor, colorList) { |
|
|
|
// tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255"
|
|
|
|
// tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff"
|
|
|
|
// tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3"
|
|
|
|
// tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff"
|
|
|
|
tinycolor.mostReadable = function (baseColor, colorList, args) { |
|
|
|
var bestColor = null; |
|
|
|
var bestScore = 0; |
|
|
|
var bestIsReadable = false; |
|
|
|
var readability; |
|
|
|
var includeFallbackColors, level, size; |
|
|
|
args = args || {}; |
|
|
|
includeFallbackColors = args.includeFallbackColors; |
|
|
|
level = args.level; |
|
|
|
size = args.size; |
|
|
|
for (var i = 0; i < colorList.length; i++) { |
|
|
|
// We normalize both around the "acceptable" breaking point,
|
|
|
|
// but rank brightness constrast higher than hue.
|
|
|
|
|
|
|
|
var readability = tinycolor.readability(baseColor, colorList[i]); |
|
|
|
var readable = readability.brightness > 125 && readability.color > 500; |
|
|
|
var score = 3 * (readability.brightness / 125) + readability.color / 500; |
|
|
|
|
|
|
|
if ( |
|
|
|
(readable && !bestIsReadable) || |
|
|
|
(readable && bestIsReadable && score > bestScore) || |
|
|
|
(!readable && !bestIsReadable && score > bestScore) |
|
|
|
) { |
|
|
|
bestIsReadable = readable; |
|
|
|
bestScore = score; |
|
|
|
readability = tinycolor.readability(baseColor, colorList[i]); |
|
|
|
if (readability > bestScore) { |
|
|
|
bestScore = readability; |
|
|
|
bestColor = tinycolor(colorList[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
return bestColor; |
|
|
|
if ( |
|
|
|
tinycolor.isReadable(baseColor, bestColor, { |
|
|
|
level: level, |
|
|
|
size: size, |
|
|
|
}) || |
|
|
|
!includeFallbackColors |
|
|
|
) { |
|
|
|
return bestColor; |
|
|
|
} else { |
|
|
|
args.includeFallbackColors = false; |
|
|
|
return tinycolor.mostReadable(baseColor, ['#fff', '#000'], args); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// Big List of Colors
|
|
|
|
@ -2433,6 +2462,28 @@ export default function ($, undefined?: any) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
function validateWCAG2Parms(parms) { |
|
|
|
// return valid WCAG2 parms for isReadable.
|
|
|
|
// If input parms are invalid, return {'level':'AA', 'size':'small'}
|
|
|
|
var level, size; |
|
|
|
parms = parms || { |
|
|
|
level: 'AA', |
|
|
|
size: 'small', |
|
|
|
}; |
|
|
|
level = (parms.level || 'AA').toUpperCase(); |
|
|
|
size = (parms.size || 'small').toLowerCase(); |
|
|
|
if (level !== 'AA' && level !== 'AAA') { |
|
|
|
level = 'AA'; |
|
|
|
} |
|
|
|
if (size !== 'small' && size !== 'large') { |
|
|
|
size = 'small'; |
|
|
|
} |
|
|
|
return { |
|
|
|
level: level, |
|
|
|
size: size, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
window.tinycolor = tinycolor; |
|
|
|
//})();
|
|
|
|
|
|
|
|
|