tinycolor2
Advanced tools
Comparing version 1.1.1 to 1.1.2
{ | ||
"name": "tinycolor", | ||
"repository": "bgrins/TinyColor", | ||
"version": "1.1.1", | ||
"version": "1.1.2", | ||
"main": "tinycolor.js", | ||
@@ -6,0 +6,0 @@ "scripts": ["tinycolor.js"], |
{ | ||
"version": "1.1.1", | ||
"version": "1.1.2", | ||
"name": "tinycolor2", | ||
@@ -4,0 +4,0 @@ "description": "Fast Color Parsing and Manipulation", |
110
README.md
@@ -74,2 +74,4 @@ # TinyColor | ||
tinycolor({ h: 0, s: 1, l: .5 }); | ||
tinycolor.fromRatio({ h: 1, s: 0, l: 0 }); | ||
tinycolor.fromRatio({ h: .5, s: .5, l: .5 }); | ||
@@ -83,2 +85,4 @@ ### HSV, HSVA | ||
tinycolor({ h: 0, s: 100, v: 100 }); | ||
tinycolor.fromRatio({ h: 1, s: 0, v: 0 }); | ||
tinycolor.fromRatio({ h: .5, s: .5, v: .5 }); | ||
@@ -102,2 +106,22 @@ ### Named | ||
### getFormat | ||
Returns the format used to create the tinycolor instance | ||
```js | ||
var color = tinycolor("red"); | ||
color.getFormat(); // "name" | ||
color = tinycolor({r:255, g:255, b:255}); | ||
color.getFormat; // "rgb" | ||
``` | ||
### getOriginalInput | ||
Returns the input passed into the constructer used to create the tinycolor instance | ||
```js | ||
var color = tinycolor("red"); | ||
color.getOriginalInput(); // "red" | ||
color = tinycolor({r:255, g:255, b:255}); | ||
color.getOriginalInput; // "{r: 255, g: 255, b: 255}" | ||
``` | ||
### isValid | ||
@@ -115,2 +139,12 @@ | ||
### getBrightness | ||
Returns the perceived brightness of a color, from `0-255`, as defined by [Web Content Accessibility Guidelines (Version 1.0)](http://www.w3.org/TR/AERT#color-contrast). | ||
var color1 = tinycolor("#fff"); | ||
color1.getBrightness(); // 255 | ||
var color2 = tinycolor("#000"); | ||
color2.getBrightness(); // 0 | ||
### isLight | ||
@@ -136,2 +170,12 @@ | ||
### getLuminance | ||
Returns the perceived luminance of a color, from `0-1` as defined by [Web Content Accessibility Guidelines (Version 2.0).](http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef) | ||
var color1 = tinycolor("#fff"); | ||
color1.getLuminance(); // 1 | ||
var color2 = tinycolor("#000"); | ||
color2.getLuminance(); // 0 | ||
### getAlpha | ||
@@ -150,12 +194,2 @@ | ||
### getBrightness | ||
Returns the perceived brightness of a color, from `0-255`. | ||
var color1 = tinycolor("#fff"); | ||
color1.getBrightness(); // 255 | ||
var color2 = tinycolor("#000"); | ||
color2.getBrightness(); // 0 | ||
### setAlpha | ||
@@ -171,2 +205,6 @@ | ||
### String Representations | ||
The following methods will return a property for the `alpha` value, which can be ignored: `toHsv`, `toHsl`, `toRgb` | ||
### toHsv | ||
@@ -181,2 +219,4 @@ | ||
color.toHsvString(); // "hsv(0, 100%, 100%)" | ||
color.setAlpha(0.5); | ||
color.toHsvString(); // "hsva(0, 100%, 100%, 0.5)" | ||
@@ -192,2 +232,4 @@ ### toHsl | ||
color.toHslString(); // "hsl(0, 100%, 50%)" | ||
color.setAlpha(0.5); | ||
color.toHslString(); // "hsla(0, 100%, 50%, 0.5)" | ||
@@ -223,2 +265,4 @@ ### toHex | ||
color.toRgbString(); // "rgb(255, 0, 0)" | ||
color.setAlpha(0.5); | ||
color.toRgbString(); // "rgba(255, 0, 0, 0.5)" | ||
@@ -234,2 +278,4 @@ ### toPercentageRgb | ||
color.toPercentageRgbString(); // "rgb(100%, 0%, 0%)" | ||
color.setAlpha(0.5); | ||
color.toPercentageRgbString(); // "rgba(100%, 0%, 0%, 0.5)" | ||
@@ -252,3 +298,3 @@ ### toName | ||
color1.toString(); // "red" | ||
color1.toString("hsv"); // ""hsv(0, 100%, 100%)" | ||
color1.toString("hsv"); // "hsv(0, 100%, 100%)" | ||
@@ -373,21 +419,47 @@ var color2 = tinycolor("rgb(255, 0, 0)"); | ||
### readability | ||
### random | ||
`readable: function(TinyColor, TinyColor) -> Object`. Analyze 2 colors and returns an object with the following properties. `brightness` is difference in brightness between the two colors. `color`: difference in color/hue between the two colors. | ||
Returns a random color. | ||
```js | ||
var color = tinycolor.random(); | ||
color.toRgb(); // "{r: 145, g: 40, b: 198, a: 1}" | ||
``` | ||
tinycolor.readability("#000", "#111"); // {brightness: 17, color: 51} | ||
tinycolor.readability("#000", "#fff"); // {brightness: 255, color: 765} | ||
### Readability | ||
### isReadable | ||
TinyColor assesses readability based on the [Web Content Accessibility Guidelines (Version 2.0)](http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef). | ||
`isReadable: function(TinyColor, TinyColor) -> Boolean`. Ensure that foreground and background color combinations provide sufficient contrast. | ||
#### readability | ||
tinycolor.isReadable("#000", "#111"); // false | ||
`readability: function(TinyColor, TinyColor) -> Object`. | ||
Returns the contrast ratio between two colors. | ||
### mostReadable | ||
tinycolor.readability("#000", "#000"); // 1 | ||
tinycolor.readability("#000", "#111"); // 1.1121078324840545 | ||
tinycolor.readability("#000", "#fff"); // 21 | ||
Use the values in your own calculations, or use one of the convenience functions below. | ||
#### isReadable | ||
`isReadable: function(TinyColor, TinyColor, Object) -> Boolean`. Ensure that foreground and background color combinations meet WCAG guidelines. `Object` is optional, defaulting to `{level: "AA",size: "small"}`. `level` can be `"AA"` or "AAA" and `size` can be `"small"` or `"large"`. | ||
Here are links to read more about the [AA](http://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html) and [AAA](http://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast7.html) requirements. | ||
tinycolor.isReadable("#000", "#111", {}); // false | ||
tinycolor.isReadable("#ff0088", "#5c1a72",{level:"AA",size:"small"}); //false | ||
tinycolor.isReadable("#ff0088", "#5c1a72",{level:"AA",size:"large"}), //true | ||
#### mostReadable | ||
`mostReadable: function(TinyColor, [TinyColor, Tinycolor ...], Object) -> Boolean`. | ||
Given a base color and a list of possible foreground or background colors for that base, returns the most readable color. | ||
If none of the colors in the list is readable, `mostReadable` will return the better of black or white if `includeFallbackColors:true`. | ||
tinycolor.mostReadable("#000", ["#f00", "#0f0", "#00f"]).toHexString(); // "#00ff00" | ||
tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255" | ||
tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff" | ||
tinycolor.mostReadable("#ff0088", ["#2e0c3a"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString() // "#2e0c3a", | ||
tinycolor.mostReadable("#ff0088", ["#2e0c3a"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString() // "#000000", | ||
See [index.html](https://github.com/bgrins/TinyColor/blob/master/index.html) in the project for a demo. |
@@ -399,2 +399,7 @@ | ||
test("getLuminance", function() { | ||
equal(tinycolor('#000').getLuminance(), 0, 'returns 0 for #000'); | ||
equal(tinycolor('#fff').getLuminance(), 1, 'returns 1 for #fff'); | ||
}); | ||
test("isDark returns true/false for dark/light colors", function() { | ||
@@ -550,15 +555,60 @@ equal(tinycolor('#000').isDark(), true, '#000 is dark'); | ||
test("isReadable", function() { | ||
ok (tinycolor.isReadable("#000000", "#ffffff"), "white/black is readable"); | ||
ok (!tinycolor.isReadable("#FF0088", "#8822AA"), "pink on pink is not readable"); | ||
// "#ff0088", "#8822aa" (values used in old WCAG1 tests) | ||
ok (tinycolor.isReadable("#000000", "#ffffff",{level:"AA",size:"small"}), "white/black is readable"); | ||
ok (!tinycolor.isReadable("#ff0088", "#5c1a72",{}), "not readable - empty wcag2 object"); | ||
ok (!tinycolor.isReadable("#ff0088", "#8822aa",{level:"AA",size:"small"}), "not readable - AA small"); | ||
ok (!tinycolor.isReadable("#ff0088", "#8822aa",{level:"AA",size:"large"}), "not readable - AA large"); | ||
ok (!tinycolor.isReadable("#ff0088", "#8822aa",{level:"AAA",size:"small"}), "not readable - AAA small"); | ||
ok (!tinycolor.isReadable("#ff0088", "#8822aa",{level:"AAA",size:"large"}), "not readable - AAA large"); | ||
// values derived from and validated using the calculators at http://www.dasplankton.de/ContrastA/ | ||
// and http://webaim.org/resources/contrastchecker/ | ||
// "#ff0088", "#5c1a72": contrast ratio 3.04 | ||
ok (!tinycolor.isReadable("#ff0088", "#5c1a72",{level:"AA",size:"small"}), "not readable - AA small"); | ||
ok (tinycolor.isReadable("#ff0088", "#5c1a72",{level:"AA",size:"large"}), "readable - AA large"); | ||
ok (!tinycolor.isReadable("#ff0088", "#5c1a72",{level:"AAA",size:"small"}), "not readable - AAA small"); | ||
ok (!tinycolor.isReadable("#ff0088", "#5c1a72",{level:"AAA",size:"large"}), "not readable - AAA large"); | ||
// "#ff0088", "#2e0c3a": contrast ratio 4.56 | ||
ok (tinycolor.isReadable("#ff0088", "#2e0c3a",{level:"AA",size:"small"}), "readable - AA small"); | ||
ok (tinycolor.isReadable("#ff0088", "#2e0c3a",{level:"AA",size:"large"}), "readable - AA large"); | ||
ok (!tinycolor.isReadable("#ff0088", "#2e0c3a",{level:"AAA",size:"small"}), "not readable - AAA small"); | ||
ok (tinycolor.isReadable("#ff0088", "#2e0c3a",{level:"AAA",size:"large"}), "readable - AAA large"); | ||
// "#db91b8", "#2e0c3a": contrast ratio 7.12 | ||
ok (tinycolor.isReadable("#db91b8", "#2e0c3a",{level:"AA",size:"small"}), "readable - AA small"); | ||
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"); | ||
}); | ||
test("readability", function() { | ||
// XXX: Need tests for readability | ||
deepEqual(tinycolor.readability("#000", "#111"), {brightness: 17, color: 51}, "Readability 1"); | ||
deepEqual(tinycolor.readability("#000", "#fff"), {brightness: 255, color: 765}, "Readability 2"); | ||
// check return values from readability function. See isReadable above for standards tests. | ||
equal(tinycolor.readability("#000", "#000"), 1, "Readability function test 0"); | ||
deepEqual(tinycolor.readability("#000", "#111"), 1.1121078324840545, "Readability function test 1"); | ||
deepEqual(tinycolor.readability("#000", "#fff"), 21, "Readability function test 2"); | ||
}); | ||
test("mostReadable", function () { | ||
equal (tinycolor.mostReadable("#000", ["#111", "#222"]).toHexString(), "#222222", "pick most readable color"); | ||
equal (tinycolor.mostReadable("#f00", ["#d00", "#0d0"]).toHexString(), "#00dd00", "pick most readable color"); | ||
equal (tinycolor.mostReadable("#000", ["#111", "#222",{wcag2:{}}]).toHexString(), "#222222", "readable color present"); | ||
equal (tinycolor.mostReadable("#f00", ["#d00", "#0d0"],{wcag2:{}}).toHexString(), "#00dd00", "readable color present"); | ||
equal (tinycolor.mostReadable("#fff", ["#fff", "#fff"],{wcag2:{}}).toHexString(), "#ffffff", "no different color in list"); | ||
//includeFallbackColors | ||
equal (tinycolor.mostReadable("#fff", ["#fff", "#fff"],{includeFallbackColors:true}).toHexString(), "#000000", "no different color in list"); | ||
equal (tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(), "#112255", "no readable color in list"); | ||
equal (tinycolor.mostReadable("#123", ["#000", "#fff"],{includeFallbackColors:false}).toHexString(), "#ffffff", "verify assumption"); | ||
equal (tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(), "#ffffff", "no readable color in list"); | ||
equal (tinycolor.mostReadable("#ff0088", ["#000", "#fff"],{includeFallbackColors:false}).toHexString(), "#000000", "verify assumption"); | ||
equal (tinycolor.mostReadable("#ff0088", ["#2e0c3a"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(), "#2e0c3a", "readable color present"); | ||
equal (tinycolor.mostReadable("#ff0088", ["#2e0c3a"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(), "#000000", "no readable color in list"); | ||
equal (tinycolor.mostReadable("#371b2c", ["#000", "#fff"],{includeFallbackColors:false}).toHexString(), "#ffffff", "verify assumption"); | ||
equal (tinycolor.mostReadable("#371b2c", ["#a9acb6"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(), "#a9acb6", "readable color present"); | ||
equal (tinycolor.mostReadable("#371b2c", ["#a9acb6"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(), "#ffffff", "no readable color in list"); | ||
}); | ||
test("Filters", function () { | ||
@@ -565,0 +615,0 @@ |
135
tinycolor.js
@@ -1,2 +0,2 @@ | ||
// TinyColor v1.1.1 | ||
// TinyColor v1.1.2 | ||
// https://github.com/bgrins/TinyColor | ||
@@ -16,3 +16,3 @@ // Brian Grinstead, MIT License | ||
var tinycolor = function tinycolor (color, opts) { | ||
function tinycolor (color, opts) { | ||
@@ -51,3 +51,3 @@ color = (color) ? color : ''; | ||
this._tc_id = tinyCounter++; | ||
}; | ||
} | ||
@@ -74,5 +74,19 @@ tinycolor.prototype = { | ||
getBrightness: function() { | ||
//http://www.w3.org/TR/AERT#color-contrast | ||
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) { | ||
@@ -695,35 +709,44 @@ this._a = boundAlpha(value); | ||
// --------------------- | ||
// <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 | ||
// `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); | ||
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; | ||
}; | ||
@@ -734,26 +757,35 @@ | ||
// 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; | ||
for (var i=0; i < colorList.length; i++) { | ||
var readability; | ||
var includeFallbackColors, level, size ; | ||
args = args || {}; | ||
includeFallbackColors = args.includeFallbackColors ; | ||
level = args.level; | ||
size = args.size; | ||
// 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; | ||
for (var i= 0; i < colorList.length ; i++) { | ||
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); | ||
} | ||
}; | ||
@@ -1108,2 +1140,17 @@ | ||
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}; | ||
} | ||
// Node: Export function | ||
@@ -1110,0 +1157,0 @@ if (typeof module !== "undefined" && module.exports) { |
Sorry, the diff of this file is not supported yet
668256
12080
453