diff --git a/README.md b/README.md index 4f761f0..890e491 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ var steelblue = d3.rgb("steelblue"); # d3.color(specifier) [<>](https://github.com/d3/d3-color/blob/master/src/color.js "Source") -Parses the specified [CSS Color Module Level 3](http://www.w3.org/TR/css3-color/#colorunits) *specifier* string, returning an [RGB](#rgb) or [HSL](#hsl) color. If the specifier was not valid, null is returned. Some examples: +Parses the specified [CSS Color Module Level 3](http://www.w3.org/TR/css3-color/#colorunits) *specifier* string, returning an [RGB](#rgb) or [HSL](#hsl) color, along with [CSS Color Module Level 4 hex](https://www.w3.org/TR/css-color-4/#hex-notation) *specifier* strings. If the specifier was not valid, null is returned. Some examples: * `rgb(255, 255, 255)` * `rgb(10%, 20%, 30%)` @@ -73,6 +73,8 @@ Parses the specified [CSS Color Module Level 3](http://www.w3.org/TR/css3-color/ * `hsla(120, 50%, 20%, 0.4)` * `#ffeeaa` * `#fea` +* `#ffeeaa22` +* `#fea2` * `steelblue` The list of supported [named colors](http://www.w3.org/TR/SVG/types.html#ColorKeywords) is specified by CSS. diff --git a/src/color.js b/src/color.js index 6f133b1..7638c32 100644 --- a/src/color.js +++ b/src/color.js @@ -9,7 +9,9 @@ var reI = "\\s*([+-]?\\d+)\\s*", reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*", reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*", reHex3 = /^#([0-9a-f]{3})$/, + reHex4 = /^#([0-9a-f]{4})$/, reHex6 = /^#([0-9a-f]{6})$/, + reHex8 = /^#([0-9a-f]{8})$/, reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"), reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"), reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"), @@ -197,8 +199,10 @@ function color_formatRgb() { export default function color(format) { var m; format = (format + "").trim().toLowerCase(); - return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00 + return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00 + : (m = reHex4.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 12 & 0xf) | (m >> 8 & 0xf0), (m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), (((m & 0xf) << 4) | (m & 0xf)) / 0xff)) // #f000 : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000 + : (m = reHex8.exec(format)) ? rgbn8(parseInt(m[1], 16)) // #ff000000 : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0) : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%) : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1) @@ -214,6 +218,10 @@ function rgbn(n) { return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1); } +function rgbn8(n) { + return new Rgb(n >> 24 & 0xff, n >> 16 & 0xff, n >> 8 & 0xff, (n & 0xff) / 0xff); +} + function rgba(r, g, b, a) { if (a <= 0) r = g = b = NaN; return new Rgb(r, g, b, a); diff --git a/test/color-test.js b/test/color-test.js index a8e9825..99ed663 100644 --- a/test/color-test.js +++ b/test/color-test.js @@ -26,6 +26,16 @@ tape("color(format) parses 3-digit hexadecimal (e.g., \"#abc\")", function(test) test.end(); }); +tape("color(format) parses 8-digit hexadecimal (e.g., \"#abcdef33\")", function(test) { + test.rgbEqual(color.color("#abcdef33"), 171, 205, 239, 0.2); + test.end(); +}); + +tape("color(format) parses 4-digit hexadecimal (e.g., \"#abc3\")", function(test) { + test.rgbEqual(color.color("#abc3"), 170, 187, 204, 0.2); + test.end(); +}); + tape("color(format) parses RGB integer format (e.g., \"rgb(12,34,56)\")", function(test) { test.rgbEqual(color.color("rgb(12,34,56)"), 12, 34, 56, 1); test.end(); @@ -157,7 +167,6 @@ tape("color(format) returns undefined RGB channel values for unknown formats", f test.equal(color.color("hasOwnProperty"), null); test.equal(color.color("__proto__"), null); test.equal(color.color("#ab"), null); - test.equal(color.color("#abcd"), null); test.end(); });