├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .gitmodules ├── .npmrc ├── .prettierignore ├── .prettierrc ├── .travis.yml ├── LICENSE ├── README.md ├── bower.json ├── demo ├── demo.css ├── demo.js └── index.html ├── index.js ├── lib ├── CMYK.js ├── HSL.js ├── HSV.js ├── LAB.js ├── XYZ.js ├── color.js └── plugins │ ├── clearer.js │ ├── contrast.js │ ├── darken.js │ ├── desaturate.js │ ├── grayscale.js │ ├── isDark.js │ ├── isLight.js │ ├── lighten.js │ ├── luminance.js │ ├── mix.js │ ├── namedColors.js │ ├── negate.js │ ├── opaquer.js │ ├── rotate.js │ ├── saturate.js │ └── toAlpha.js ├── minimal.js ├── one-color-all.js ├── one-color-all.js.map ├── one-color.js ├── one-color.js.map ├── package.json ├── rollup.config.js ├── slides └── CPHJS-Oct2011 │ ├── colorcat │ ├── css │ │ ├── colorcat.css │ │ └── demo.css │ ├── images │ │ └── transparent.gif │ └── js │ │ ├── colorcat.js │ │ └── one-color-debug.js │ ├── images │ ├── 1024px-HSV_color_solid_cylinder_alpha_lowgamma.png │ ├── ExtJS.png │ ├── HSL.png │ ├── HSV.png │ ├── Hsl-hsv_models_b.svg │ ├── Pixels.jpg │ ├── PullingHair.png │ ├── RGB.png │ ├── RGB_HSL_HSV_comparison.png │ ├── Space_Rainbow_desktop_background_pictures.jpg │ ├── blog.png │ ├── calendar.png │ └── colorSpace.jpg │ ├── index.html │ ├── talk.css │ └── theme.css └── test ├── color.js ├── contrast.js ├── conversion.js ├── grayscale.js ├── isDark.js ├── isLight.js ├── luminance.js ├── mix.js ├── parse.js └── samples.js /.editorconfig: -------------------------------------------------------------------------------- 1 | ; EditorConfig is awesome: http://EditorConfig.org 2 | 3 | ; top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | 9 | trim_trailing_whitespace = true 10 | 11 | ; Unix style line endings 12 | end_of_line = lf 13 | 14 | ; Always end file on newline 15 | insert_final_newline = true 16 | 17 | ; Indentation 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [Makefile] 22 | indent_style = tab 23 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /demo/ 3 | /slides/ 4 | /one-color-all.js 5 | /one-color.js 6 | /coverage/ 7 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["standard", "prettier", "prettier/standard"], 3 | "plugins": ["import", "mocha"], 4 | "env": { 5 | "mocha": true 6 | }, 7 | "rules": { 8 | "mocha/no-exclusive-tests": "error", 9 | "mocha/no-nested-tests": "error", 10 | "mocha/no-identical-title": "error" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /doc/ 3 | coverage 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "slides/3rdparty/CSSS"] 2 | path = slides/3rdparty/CSSS 3 | url = https://github.com/LeaVerou/csss.git 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock = false 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /demo/ 3 | /slides/ 4 | /one-color-all.js 5 | /one-color.js 6 | /coverage/ 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | services: 2 | - docker 3 | language: node_js 4 | cache: 5 | directories: 6 | - node_modules 7 | node_js: 8 | - '0.12' 9 | - '1' 10 | - '2' 11 | - '3' 12 | - '4' 13 | - '6' 14 | - '8' 15 | - '10' 16 | - '12' 17 | - '14' 18 | - node 19 | 20 | matrix: 21 | include: 22 | - name: Lint 23 | node_js: 14 24 | script: npm run lint 25 | - name: Documentation 26 | node_js: 14 27 | script: npm run test:documentation 28 | 29 | script: '(nvm i 14 && npm run build) && npm run ci:test' 30 | after_success: 'one-color.js to one-color-all.js to gain 41 | named color support): 42 | 43 | ```html 44 | 45 | 50 | ``` 51 | 52 | In the browser, the parser is exposed as a global named `onecolor`. 53 | In node.js, it is returned directly with a require of the module 54 | (after `npm install onecolor`): 55 | 56 | ```javascript 57 | var color = require('onecolor'); 58 | console.warn(color('rgba(100%, 0%, 0%, .5)').alpha(0.4).cssa()); 59 | ``` 60 | 61 | ```output 62 | rgba(255,0,0,0.4) 63 | ``` 64 | 65 | All of the above return color instances in the relevant color space 66 | with the channel values (0..1) as instance variables: 67 | 68 | ```javascript 69 | var myColor = color('#a9d91d'); 70 | myColor instanceof color.RGB; // true 71 | myColor.red(); // 0.6627450980392157 72 | ``` 73 | 74 | You can also parse named CSS colors (works out of the box in node.js, 75 | but the requires the slightly bigger one-color-all.js build in the 76 | browser): 77 | 78 | ```javascript 79 | color('maroon').lightness(0.3).hex(); // '#990000' 80 | ``` 81 | 82 | To turn a color instance back into a string, use the `hex()`, `css()`, 83 | and `cssa()` methods: 84 | 85 | ```javascript 86 | color('rgb(124, 96, 200)').hex(); // '#7c60c8' 87 | color('#bb7b81').cssa(); // 'rgba(187,123,129,1)' 88 | ``` 89 | 90 | Color instances have getters/setters for all channels in all supported 91 | colorspaces (`red()`, `green()`, `blue()`, `hue()`, `saturation()`, `lightness()`, 92 | `value()`, `alpha()`, etc.). Thus you don't need to think about which colorspace 93 | you're in. All the necessary conversions happen automatically: 94 | 95 | ```javascript 96 | color('#ff0000') // Red in RGB 97 | .green(1) // Set green to the max value, producing yellow (still RGB) 98 | .hue(0.5, true) // Add 180 degrees to the hue, implicitly converting to HSV 99 | .hex(); // Dump as RGB hex syntax: '#2222ff' 100 | ``` 101 | 102 | When called without any arguments, they return the current value of 103 | the channel (0..1): 104 | 105 | ```javascript 106 | color('#09ffdd').green(); // 1 107 | color('#09ffdd').saturation(); // 0.9647058823529412 108 | ``` 109 | 110 | When called with a single numerical argument (0..1), a new color 111 | object is returned with that channel replaced: 112 | 113 | ```javascript 114 | var myColor = color('#00ddff'); 115 | myColor.red(0.5).red(); // .5 116 | 117 | // ... but as the objects are immutable, the original object retains its value: 118 | myColor.red(); // 0 119 | ``` 120 | 121 | When called with a single numerical argument (0..1) and `true` as 122 | the second argument, a new value is returned with that channel 123 | adjusted: 124 | 125 | ```javascript 126 | color('#ff0000') // Red 127 | .red(-0.1, true) // Adjust red channel by -0.1 128 | .hex(); // '#e60000' 129 | ``` 130 | 131 | ## Alpha channel 132 | 133 | All color instances have an alpha channel (0..1), defaulting to 1 134 | (opaque). You can simply ignore it if you don't need it. 135 | 136 | It's preserved when converting between colorspaces: 137 | 138 | ```javascript 139 | color('rgba(10, 20, 30, .8)').green(0.4).saturation(0.2).alpha(); // 0.8 140 | ``` 141 | 142 | ## Comparing color objects 143 | 144 | If you need to know whether two colors represent the same 8 bit color, regardless 145 | of colorspace, compare their `hex()` values: 146 | 147 | ```javascript 148 | color('#f00').hex() === color('#e00').red(1).hex(); // true 149 | ``` 150 | 151 | Use the `equals` method to compare two color instances within a certain 152 | epsilon (defaults to `1e-9`). 153 | 154 | ```javascript 155 | color('#e00').lightness(0.00001, true).equals(color('#e00'), 1e-5); // false 156 | color('#e00').lightness(0.000001, true).equals(color('#e00'), 1e-5); // true 157 | ``` 158 | 159 | Before comparing the `equals` method converts the other color to the right colorspace, 160 | so you don't need to convert explicitly in this case either: 161 | 162 | ```javascript 163 | color('#e00').hsv().equals(color('#e00')); // true 164 | ``` 165 | 166 | # API overview 167 | 168 | Color parser function, the recommended way to create a color instance: 169 | 170 | ```javascript 171 | color('#a9d91d'); // Regular hex syntax 172 | color('a9d91d'); // hex syntax, # is optional 173 | color('#eee'); // Short hex syntax 174 | color('rgb(124, 96, 200)'); // CSS rgb syntax 175 | color('rgb(99%, 40%, 0%)'); // CSS rgb syntax with percentages 176 | color('rgba(124, 96, 200, .4)'); // CSS rgba syntax 177 | color('hsl(120, 75%, 75%)'); // CSS hsl syntax 178 | color('hsla(120, 75%, 75%, .1)'); // CSS hsla syntax 179 | color('hsv(220, 47%, 12%)'); // CSS hsv syntax (non-standard) 180 | color('hsva(120, 75%, 75%, 0)'); // CSS hsva syntax (non-standard) 181 | color([0, 4, 255, 120]); // CanvasPixelArray entry, RGBA 182 | color(['RGB', 0.5, 0.1, 0.6, 0.9]); // The output format of color.toJSON() 183 | ``` 184 | 185 | The slightly bigger one-color-all.js build adds support for 186 | the standard suite of named CSS colors: 187 | 188 | ```javascript 189 | color('maroon'); 190 | color('darkolivegreen'); 191 | ``` 192 | 193 | Existing onecolor instances pass through unchanged, which is useful 194 | in APIs where you want to accept either a string or a color instance: 195 | 196 | ```javascript 197 | color(color('#fff')); // Same as color('#fff') 198 | ``` 199 | 200 | Serialization methods: 201 | 202 | ```javascript 203 | var myColor = color('#bda65b'); 204 | 205 | myColor.hex(); // 6-digit hex string: '#bda65b' 206 | myColor.css(); // CSS rgb syntax: 'rgb(10,128,220)' 207 | myColor.cssa(); // CSS rgba syntax: 'rgba(10,128,220,0.8)' 208 | myColor.toString(); // For debugging: '[onecolor.RGB: Red=0.3 Green=0.8 Blue=0 Alpha=1]' 209 | myColor.toJSON(); // ["RGB"|"HSV"|"HSL", , , , ] 210 | ``` 211 | 212 | Getters -- return the value of the channel (converts to other colorspaces as needed): 213 | 214 | ```javascript 215 | var myColor = color('#bda65b'); 216 | 217 | myColor.red(); 218 | myColor.green(); 219 | myColor.blue(); 220 | myColor.hue(); 221 | myColor.saturation(); 222 | myColor.value(); 223 | myColor.lightness(); 224 | myColor.alpha(); 225 | myColor.cyan(); // one-color-all.js and node.js only 226 | myColor.magenta(); // one-color-all.js and node.js only 227 | myColor.yellow(); // one-color-all.js and node.js only 228 | myColor.black(); // one-color-all.js and node.js only 229 | ``` 230 | 231 | Setters -- return new color instances with one channel changed: 232 | 233 | 234 | 235 | ```javascript 236 | color.red() 237 | color.green() 238 | color.blue() 239 | color.hue() 240 | color.saturation() 241 | color.value() 242 | color.lightness() 243 | color.alpha() 244 | color.cyan() // one-color-all.js and node.js only 245 | color.magenta() // one-color-all.js and node.js only 246 | color.yellow() // one-color-all.js and node.js only 247 | color.black() // one-color-all.js and node.js only 248 | ``` 249 | 250 | Adjusters -- return new color instances with the channel adjusted by 251 | the specified delta (0..1): 252 | 253 | 254 | 255 | ```javascript 256 | color.red(, true) 257 | color.green(, true) 258 | color.blue(, true) 259 | color.hue(, true) 260 | color.saturation(, true) 261 | color.value(, true) 262 | color.lightness(, true) 263 | color.alpha(, true) 264 | color.cyan(, true) // one-color-all.js and node.js only 265 | color.magenta(, true) // one-color-all.js and node.js only 266 | color.yellow(, true) // one-color-all.js and node.js only 267 | color.black(, true) // one-color-all.js and node.js only 268 | ``` 269 | 270 | Comparison with other color objects, returns `true` or `false` (epsilon defaults to `1e-9`): 271 | 272 | 273 | 274 | ```javascript 275 | color.equals(otherColor[, ]) 276 | ``` 277 | 278 | ## Mostly for internal (and plugin) use: 279 | 280 | "Low level" constructors, accept 3 or 4 numerical arguments (0..1): 281 | 282 | ```javascript 283 | new onecolor.RGB(, , [, ]) 284 | new onecolor.HSL(, , [, ]) 285 | new onecolor.HSV(, , [, ]) 286 | ``` 287 | 288 | The one-color-all.js build includes CMYK support: 289 | 290 | ```javascript 291 | new onecolor.CMYK(, , , [, ]) 292 | ``` 293 | 294 | All color instances have `rgb()`, `hsv()`, and `hsl()` methods for 295 | explicitly converting to another color space. Like the setter and 296 | adjuster methods they return a new color object representing the same 297 | color in another color space. 298 | 299 | If for some reason you need to get all the channel values in a 300 | specific colorspace, do an explicit conversion first to cut down on 301 | the number of implicit conversions: 302 | 303 | ```javascript 304 | var myColor = color('#0620ff').lightness(+0.3).rgb(); 305 | 306 | console.log(myColor.red() + ' ' + myColor.green() + ' ' + myColor.blue()); 307 | ``` 308 | 309 | ```output 310 | 0 0.06265060240963878 0.5999999999999999 311 | ``` 312 | 313 | # Building 314 | 315 | ``` 316 | git clone https://github.com/One-com/one-color.git 317 | cd one-color 318 | npm install 319 | npm run build 320 | ``` 321 | 322 | If you aren't up for a complete installation, there are pre-built 323 | packages in the repository as well as the npm package: 324 | 325 | - Basic library: one-color.js 326 | - Full library including named color support: one-color-all.js 327 | 328 | # License 329 | 330 | onecolor is licensed under a standard 2-clause BSD license -- see the `LICENSE` file for details. 331 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "color", 3 | "main": "one-color-all.js", 4 | "licence": "2-clause BSD", 5 | "ignore": [ 6 | "demo", 7 | "lib", 8 | "slides", 9 | "test", 10 | ".gitignore", 11 | ".gitmodules", 12 | "LICENSE", 13 | "package.json" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /demo/demo.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #2D1B06; 3 | } 4 | 5 | * { 6 | font-family: Palatino Linotype, Book Antiqua, Palatino, serif; 7 | } 8 | 9 | h1 { 10 | color: #FFD49E; 11 | } 12 | 13 | h2 { 14 | color: #BE9765; 15 | } 16 | 17 | h3 { 18 | color: #BE9765; 19 | } 20 | 21 | h1 { 22 | font-size: 300%; 23 | } 24 | 25 | hr { 26 | border: 1px inset #AC7D46; 27 | } 28 | 29 | #site { 30 | position: relative; 31 | max-width: 700px; 32 | margin: 0 auto; 33 | background: #623B0D; 34 | padding: 20px 40px 100px; 35 | } 36 | 37 | a { 38 | padding: 5px 10px; 39 | background: #258826; 40 | color: white; 41 | font-weight: bold; 42 | } 43 | 44 | p { 45 | color: #FFECD4; 46 | } 47 | 48 | pre { 49 | padding: 20px; 50 | background: #482B09; 51 | border: 1px solid #AC7D46; 52 | color: #FFECD4; 53 | } 54 | 55 | #disqus_thread a { 56 | padding: 0; 57 | background-color: transparent; 58 | } 59 | -------------------------------------------------------------------------------- /demo/demo.js: -------------------------------------------------------------------------------- 1 | window.onload = function () { 2 | var demo = { 3 | rainbow: function (el) { 4 | el.innerHTML = '' + el.innerHTML.split('').join('') + ''; 5 | 6 | var collection = el.getElementsByTagName('span'), 7 | len = collection.length, 8 | frac = 1 / (len + 1); 9 | 10 | window.setInterval(function () { 11 | var date = new Date().getTime(); 12 | for (var i = 0; i < len; i += 1) { 13 | collection[i].style.color = new one.color.HSV( 14 | i * frac + date / 10000, 15 | (1 + Math.cos(date/1000)) / 3 + 0.2, 16 | 1, 17 | (1 + Math.sin(date/1000)) / 3 + 0.5 18 | ).cssa(); 19 | 20 | } 21 | }, 100); 22 | } 23 | }; 24 | 25 | document.getElementById('demo').onclick = function () { 26 | demo.rainbow(document.getElementsByTagName('h1')[0]); 27 | demo.rainbow(document.getElementsByTagName('h2')[0]); 28 | 29 | document.getElementById('demo').onclick = function () { 30 | return false; 31 | } 32 | 33 | return false; 34 | } 35 | } -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | one-color demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

One-color.js

15 |

A color object with implicit color space conversion and methods for setting, getting and adjusting any channel in RGB, HSV, HSL and CMYK including alpha

16 | 17 | Click me for demo! 18 | 19 |

We made this color object because we were tired of color conversion functions that required you to serialize to strings all the time. When you want to to a lot of color manipulation in different color spaces, you shouldn't need to serialize to a string representation at intermediary steps.

20 |

So this is when we came up with the idea og making Color an object that has manipulation methods for all channels in all installed color spaces, with implicit conversion to the color space that you are manipulating.

21 |

This means that you can chain any manipulation of any channel without ever having to think about serialization. When you are done you just run one of the serialization methods depending on the output you want.

22 | 23 |

Example

24 |
new one.color.RGB(.4, .3, .9).
25 |     adjustLightness(+.2). // Implicit conversion to HSL
26 |     setRed(-.1). // Implicit conversion back to RGB
27 |     toHex(); // "#00a6f2"
28 | 29 |

The code is fully documented, and you can use JSdoc to build the documentation.

30 | Link to documenation (TODO) 31 |

This color object runs in your browser and in NodeJS.

32 | 33 | Fork me on GitHub 34 | 35 |
36 | 37 |
38 | 49 | 50 | 51 |
52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/color') 2 | .use(require('./lib/XYZ')) 3 | .use(require('./lib/LAB')) 4 | .use(require('./lib/HSV')) 5 | .use(require('./lib/HSL')) 6 | .use(require('./lib/CMYK')) 7 | 8 | // Convenience functions 9 | .use(require('./lib/plugins/namedColors')) 10 | .use(require('./lib/plugins/clearer.js')) 11 | .use(require('./lib/plugins/contrast.js')) 12 | .use(require('./lib/plugins/darken.js')) 13 | .use(require('./lib/plugins/desaturate.js')) 14 | .use(require('./lib/plugins/grayscale.js')) 15 | .use(require('./lib/plugins/isDark.js')) 16 | .use(require('./lib/plugins/isLight.js')) 17 | .use(require('./lib/plugins/lighten.js')) 18 | .use(require('./lib/plugins/luminance.js')) 19 | .use(require('./lib/plugins/mix.js')) 20 | .use(require('./lib/plugins/negate.js')) 21 | .use(require('./lib/plugins/opaquer.js')) 22 | .use(require('./lib/plugins/rotate.js')) 23 | .use(require('./lib/plugins/saturate.js')) 24 | .use(require('./lib/plugins/toAlpha.js')); 25 | -------------------------------------------------------------------------------- /lib/CMYK.js: -------------------------------------------------------------------------------- 1 | module.exports = function CMYK(color) { 2 | color.installColorSpace( 3 | 'CMYK', 4 | ['cyan', 'magenta', 'yellow', 'black', 'alpha'], 5 | { 6 | rgb: function () { 7 | return new color.RGB( 8 | 1 - this._cyan * (1 - this._black) - this._black, 9 | 1 - this._magenta * (1 - this._black) - this._black, 10 | 1 - this._yellow * (1 - this._black) - this._black, 11 | this._alpha 12 | ); 13 | }, 14 | 15 | fromRgb: function () { 16 | // Becomes one.color.RGB.prototype.cmyk 17 | // Adapted from http://www.javascripter.net/faq/rgb2cmyk.htm 18 | var red = this._red; 19 | var green = this._green; 20 | var blue = this._blue; 21 | var cyan = 1 - red; 22 | var magenta = 1 - green; 23 | var yellow = 1 - blue; 24 | var black = 1; 25 | if (red || green || blue) { 26 | black = Math.min(cyan, Math.min(magenta, yellow)); 27 | cyan = (cyan - black) / (1 - black); 28 | magenta = (magenta - black) / (1 - black); 29 | yellow = (yellow - black) / (1 - black); 30 | } else { 31 | black = 1; 32 | } 33 | return new color.CMYK(cyan, magenta, yellow, black, this._alpha); 34 | }, 35 | } 36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /lib/HSL.js: -------------------------------------------------------------------------------- 1 | module.exports = function HSL(color) { 2 | color.use(require('./HSV')); 3 | 4 | color.installColorSpace('HSL', ['hue', 'saturation', 'lightness', 'alpha'], { 5 | hsv: function () { 6 | // Algorithm adapted from http://wiki.secondlife.com/wiki/Color_conversion_scripts 7 | var l = this._lightness * 2; 8 | var s = this._saturation * (l <= 1 ? l : 2 - l); 9 | var saturation; 10 | 11 | // Avoid division by zero when l + s is very small (approaching black): 12 | if (l + s < 1e-9) { 13 | saturation = 0; 14 | } else { 15 | saturation = (2 * s) / (l + s); 16 | } 17 | 18 | return new color.HSV(this._hue, saturation, (l + s) / 2, this._alpha); 19 | }, 20 | 21 | rgb: function () { 22 | return this.hsv().rgb(); 23 | }, 24 | 25 | fromRgb: function () { 26 | // Becomes one.color.RGB.prototype.hsv 27 | return this.hsv().hsl(); 28 | }, 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /lib/HSV.js: -------------------------------------------------------------------------------- 1 | module.exports = function HSV(color) { 2 | color.installColorSpace('HSV', ['hue', 'saturation', 'value', 'alpha'], { 3 | rgb: function () { 4 | var hue = this._hue; 5 | var saturation = this._saturation; 6 | var value = this._value; 7 | var i = Math.min(5, Math.floor(hue * 6)); 8 | var f = hue * 6 - i; 9 | var p = value * (1 - saturation); 10 | var q = value * (1 - f * saturation); 11 | var t = value * (1 - (1 - f) * saturation); 12 | var red; 13 | var green; 14 | var blue; 15 | switch (i) { 16 | case 0: 17 | red = value; 18 | green = t; 19 | blue = p; 20 | break; 21 | case 1: 22 | red = q; 23 | green = value; 24 | blue = p; 25 | break; 26 | case 2: 27 | red = p; 28 | green = value; 29 | blue = t; 30 | break; 31 | case 3: 32 | red = p; 33 | green = q; 34 | blue = value; 35 | break; 36 | case 4: 37 | red = t; 38 | green = p; 39 | blue = value; 40 | break; 41 | case 5: 42 | red = value; 43 | green = p; 44 | blue = q; 45 | break; 46 | } 47 | return new color.RGB(red, green, blue, this._alpha); 48 | }, 49 | 50 | hsl: function () { 51 | var l = (2 - this._saturation) * this._value; 52 | var sv = this._saturation * this._value; 53 | var svDivisor = l <= 1 ? l : 2 - l; 54 | var saturation; 55 | 56 | // Avoid division by zero when lightness approaches zero: 57 | if (svDivisor < 1e-9) { 58 | saturation = 0; 59 | } else { 60 | saturation = sv / svDivisor; 61 | } 62 | return new color.HSL(this._hue, saturation, l / 2, this._alpha); 63 | }, 64 | 65 | fromRgb: function () { 66 | // Becomes one.color.RGB.prototype.hsv 67 | var red = this._red; 68 | var green = this._green; 69 | var blue = this._blue; 70 | var max = Math.max(red, green, blue); 71 | var min = Math.min(red, green, blue); 72 | var delta = max - min; 73 | var hue; 74 | var saturation = max === 0 ? 0 : delta / max; 75 | var value = max; 76 | if (delta === 0) { 77 | hue = 0; 78 | } else { 79 | switch (max) { 80 | case red: 81 | hue = (green - blue) / delta / 6 + (green < blue ? 1 : 0); 82 | break; 83 | case green: 84 | hue = (blue - red) / delta / 6 + 1 / 3; 85 | break; 86 | case blue: 87 | hue = (red - green) / delta / 6 + 2 / 3; 88 | break; 89 | } 90 | } 91 | return new color.HSV(hue, saturation, value, this._alpha); 92 | }, 93 | }); 94 | }; 95 | -------------------------------------------------------------------------------- /lib/LAB.js: -------------------------------------------------------------------------------- 1 | module.exports = function LAB(color) { 2 | color.use(require('./XYZ.js')); 3 | 4 | color.installColorSpace('LAB', ['l', 'a', 'b', 'alpha'], { 5 | fromRgb: function () { 6 | return this.xyz().lab(); 7 | }, 8 | 9 | rgb: function () { 10 | return this.xyz().rgb(); 11 | }, 12 | 13 | xyz: function () { 14 | // http://www.easyrgb.com/index.php?X=MATH&H=08#text8 15 | var convert = function (channel) { 16 | var pow = Math.pow(channel, 3); 17 | return pow > 0.008856 ? pow : (channel - 16 / 116) / 7.87; 18 | }; 19 | var y = (this._l + 16) / 116; 20 | var x = this._a / 500 + y; 21 | var z = y - this._b / 200; 22 | 23 | return new color.XYZ( 24 | convert(x) * 95.047, 25 | convert(y) * 100.0, 26 | convert(z) * 108.883, 27 | this._alpha 28 | ); 29 | }, 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /lib/XYZ.js: -------------------------------------------------------------------------------- 1 | module.exports = function XYZ(color) { 2 | color.installColorSpace('XYZ', ['x', 'y', 'z', 'alpha'], { 3 | fromRgb: function () { 4 | // http://www.easyrgb.com/index.php?X=MATH&H=02#text2 5 | var convert = function (channel) { 6 | return channel > 0.04045 7 | ? Math.pow((channel + 0.055) / 1.055, 2.4) 8 | : channel / 12.92; 9 | }; 10 | var r = convert(this._red); 11 | var g = convert(this._green); 12 | var b = convert(this._blue); 13 | 14 | // Reference white point sRGB D65: 15 | // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html 16 | return new color.XYZ( 17 | r * 0.4124564 + g * 0.3575761 + b * 0.1804375, 18 | r * 0.2126729 + g * 0.7151522 + b * 0.072175, 19 | r * 0.0193339 + g * 0.119192 + b * 0.9503041, 20 | this._alpha 21 | ); 22 | }, 23 | 24 | rgb: function () { 25 | // http://www.easyrgb.com/index.php?X=MATH&H=01#text1 26 | var x = this._x; 27 | var y = this._y; 28 | var z = this._z; 29 | var convert = function (channel) { 30 | return channel > 0.0031308 31 | ? 1.055 * Math.pow(channel, 1 / 2.4) - 0.055 32 | : 12.92 * channel; 33 | }; 34 | 35 | // Reference white point sRGB D65: 36 | // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html 37 | return new color.RGB( 38 | convert(x * 3.2404542 + y * -1.5371385 + z * -0.4985314), 39 | convert(x * -0.969266 + y * 1.8760108 + z * 0.041556), 40 | convert(x * 0.0556434 + y * -0.2040259 + z * 1.0572252), 41 | this._alpha 42 | ); 43 | }, 44 | 45 | lab: function () { 46 | // http://www.easyrgb.com/index.php?X=MATH&H=07#text7 47 | var convert = function (channel) { 48 | return channel > 0.008856 49 | ? Math.pow(channel, 1 / 3) 50 | : 7.787037 * channel + 4 / 29; 51 | }; 52 | var x = convert(this._x / 95.047); 53 | var y = convert(this._y / 100.0); 54 | var z = convert(this._z / 108.883); 55 | 56 | return new color.LAB( 57 | 116 * y - 16, 58 | 500 * (x - y), 59 | 200 * (y - z), 60 | this._alpha 61 | ); 62 | }, 63 | }); 64 | }; 65 | -------------------------------------------------------------------------------- /lib/color.js: -------------------------------------------------------------------------------- 1 | var installedColorSpaces = []; 2 | var undef = function (obj) { 3 | return typeof obj === 'undefined'; 4 | }; 5 | var channelRegExp = /\s*(\.\d+|\d+(?:\.\d+)?)(%|deg)?\s*/; 6 | var percentageChannelRegExp = /\s*(\.\d+|100|\d?\d(?:\.\d+)?)%\s*/; 7 | var cssColorRegExp = new RegExp( 8 | '^(rgb|hsl|hsv)a?' + 9 | '\\(' + 10 | channelRegExp.source + 11 | '[, ]' + 12 | channelRegExp.source + 13 | '[, ]' + 14 | channelRegExp.source + 15 | '(?:[,/]' + 16 | channelRegExp.source + 17 | ')?' + 18 | '\\)$', 19 | 'i' 20 | ); 21 | 22 | function divisor(unit, channelNumber, hasHue) { 23 | if (unit === '%') { 24 | return 100; 25 | } else if (unit === 'deg' || (hasHue && channelNumber === 0)) { 26 | return 360; 27 | } else if (!unit) { 28 | return 255; 29 | } 30 | } 31 | 32 | function color(obj) { 33 | if (Array.isArray(obj)) { 34 | if (typeof obj[0] === 'string' && typeof color[obj[0]] === 'function') { 35 | // Assumed array from .toJSON() 36 | return new color[obj[0]](obj.slice(1, obj.length)); 37 | } else if (obj.length === 4) { 38 | // Assumed 4 element int RGB array from canvas with all channels [0;255] 39 | return new color.RGB( 40 | obj[0] / 255, 41 | obj[1] / 255, 42 | obj[2] / 255, 43 | obj[3] / 255 44 | ); 45 | } 46 | } else if (typeof obj === 'string') { 47 | var lowerCased = obj.toLowerCase(); 48 | if (color.namedColors[lowerCased]) { 49 | obj = '#' + color.namedColors[lowerCased]; 50 | } 51 | if (lowerCased === 'transparent') { 52 | obj = 'rgba(0,0,0,0)'; 53 | } 54 | // Test for CSS rgb(....) string 55 | var matchCssSyntax = obj.match(cssColorRegExp); 56 | if (matchCssSyntax) { 57 | var colorSpaceName = matchCssSyntax[1].toUpperCase(); 58 | var hasHue = colorSpaceName[0] === 'H'; 59 | if (undef(color[colorSpaceName])) { 60 | throw new Error('color.' + colorSpaceName + ' is not installed.'); 61 | } 62 | 63 | let alpha = undef(matchCssSyntax[8]) ? 1 : undefined; 64 | if (alpha === undefined) { 65 | if (matchCssSyntax[9] === '%') { 66 | alpha = parseFloat(matchCssSyntax[8]) / 100; 67 | } else { 68 | alpha = parseFloat(matchCssSyntax[8]); 69 | } 70 | } 71 | return new color[colorSpaceName]( 72 | parseFloat(matchCssSyntax[2]) / divisor(matchCssSyntax[3], 0, hasHue), 73 | parseFloat(matchCssSyntax[4]) / divisor(matchCssSyntax[5], 1, hasHue), 74 | parseFloat(matchCssSyntax[6]) / divisor(matchCssSyntax[7], 2, hasHue), 75 | alpha 76 | ); 77 | } 78 | // Assume hex syntax 79 | if (obj.length < 6) { 80 | // Allow CSS shorthand 81 | obj = obj.replace( 82 | /^#?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/i, 83 | '$1$1$2$2$3$3$4$4' 84 | ); 85 | } 86 | // Split obj into the red, green, blue, and optionally alpha component 87 | var hexMatch = obj.match( 88 | /^#?([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])?$/i 89 | ); 90 | 91 | if (hexMatch) { 92 | return new color.RGB( 93 | parseInt(hexMatch[1], 16) / 255, 94 | parseInt(hexMatch[2], 16) / 255, 95 | parseInt(hexMatch[3], 16) / 255, 96 | hexMatch[4] ? parseInt(hexMatch[4], 16) / 255 : 1 97 | ); 98 | } 99 | 100 | // No match so far. Lets try the less likely ones 101 | if (color.CMYK) { 102 | var cmykMatch = obj.match( 103 | new RegExp( 104 | '^cmyk' + 105 | '\\(' + 106 | percentageChannelRegExp.source + 107 | ',' + 108 | percentageChannelRegExp.source + 109 | ',' + 110 | percentageChannelRegExp.source + 111 | ',' + 112 | percentageChannelRegExp.source + 113 | '\\)$', 114 | 'i' 115 | ) 116 | ); 117 | if (cmykMatch) { 118 | return new color.CMYK( 119 | parseFloat(cmykMatch[1]) / 100, 120 | parseFloat(cmykMatch[2]) / 100, 121 | parseFloat(cmykMatch[3]) / 100, 122 | parseFloat(cmykMatch[4]) / 100 123 | ); 124 | } 125 | } 126 | } else if (typeof obj === 'object' && obj.isColor) { 127 | return obj; 128 | } 129 | return false; 130 | } 131 | 132 | color.namedColors = {}; 133 | 134 | color.installColorSpace = function (colorSpaceName, propertyNames, config) { 135 | color[colorSpaceName] = function (a1) { 136 | // ... 137 | var args = Array.isArray(a1) ? a1 : arguments; 138 | propertyNames.forEach(function (propertyName, i) { 139 | var propertyValue = args[i]; 140 | if (propertyName === 'alpha') { 141 | this._alpha = 142 | isNaN(propertyValue) || propertyValue > 1 143 | ? 1 144 | : propertyValue < 0 145 | ? 0 146 | : propertyValue; 147 | } else { 148 | if (isNaN(propertyValue)) { 149 | throw new Error( 150 | '[' + 151 | colorSpaceName + 152 | ']: Invalid color: (' + 153 | propertyNames.join(',') + 154 | ')' 155 | ); 156 | } 157 | if (propertyName === 'hue') { 158 | this._hue = 159 | propertyValue < 0 160 | ? propertyValue - Math.floor(propertyValue) 161 | : propertyValue % 1; 162 | } else { 163 | this['_' + propertyName] = 164 | propertyValue < 0 ? 0 : propertyValue > 1 ? 1 : propertyValue; 165 | } 166 | } 167 | }, this); 168 | }; 169 | color[colorSpaceName].propertyNames = propertyNames; 170 | 171 | var prototype = color[colorSpaceName].prototype; 172 | 173 | ['valueOf', 'hex', 'hexa', 'css', 'cssa'].forEach(function (methodName) { 174 | prototype[methodName] = 175 | prototype[methodName] || 176 | (colorSpaceName === 'RGB' 177 | ? prototype.hex 178 | : function () { 179 | return this.rgb()[methodName](); 180 | }); 181 | }); 182 | 183 | prototype.isColor = true; 184 | 185 | prototype.equals = function (otherColor, epsilon) { 186 | if (undef(epsilon)) { 187 | epsilon = 1e-10; 188 | } 189 | 190 | otherColor = otherColor[colorSpaceName.toLowerCase()](); 191 | 192 | for (var i = 0; i < propertyNames.length; i = i + 1) { 193 | if ( 194 | Math.abs( 195 | this['_' + propertyNames[i]] - otherColor['_' + propertyNames[i]] 196 | ) > epsilon 197 | ) { 198 | return false; 199 | } 200 | } 201 | 202 | return true; 203 | }; 204 | 205 | prototype.toJSON = function () { 206 | return [colorSpaceName].concat( 207 | propertyNames.map(function (propertyName) { 208 | return this['_' + propertyName]; 209 | }, this) 210 | ); 211 | }; 212 | 213 | for (var propertyName in config) { 214 | if (Object.prototype.hasOwnProperty.call(config, propertyName)) { 215 | var matchFromColorSpace = propertyName.match(/^from(.*)$/); 216 | if (matchFromColorSpace) { 217 | color[matchFromColorSpace[1].toUpperCase()].prototype[ 218 | colorSpaceName.toLowerCase() 219 | ] = config[propertyName]; 220 | } else { 221 | prototype[propertyName] = config[propertyName]; 222 | } 223 | } 224 | } 225 | 226 | // It is pretty easy to implement the conversion to the same color space: 227 | prototype[colorSpaceName.toLowerCase()] = function () { 228 | return this; 229 | }; 230 | prototype.toString = function () { 231 | return ( 232 | '[' + 233 | colorSpaceName + 234 | ' ' + 235 | propertyNames 236 | .map(function (propertyName) { 237 | return this['_' + propertyName]; 238 | }, this) 239 | .join(', ') + 240 | ']' 241 | ); 242 | }; 243 | 244 | // Generate getters and setters 245 | propertyNames.forEach(function (propertyName) { 246 | var shortName = propertyName === 'black' ? 'k' : propertyName.charAt(0); 247 | prototype[propertyName] = prototype[shortName] = function (value, isDelta) { 248 | // Simple getter mode: color.red() 249 | if (typeof value === 'undefined') { 250 | return this['_' + propertyName]; 251 | } else if (isDelta) { 252 | // Adjuster: color.red(+.2, true) 253 | return new this.constructor( 254 | propertyNames.map(function (otherPropertyName) { 255 | return ( 256 | this['_' + otherPropertyName] + 257 | (propertyName === otherPropertyName ? value : 0) 258 | ); 259 | }, this) 260 | ); 261 | } else { 262 | // Setter: color.red(.2); 263 | return new this.constructor( 264 | propertyNames.map(function (otherPropertyName) { 265 | return propertyName === otherPropertyName 266 | ? value 267 | : this['_' + otherPropertyName]; 268 | }, this) 269 | ); 270 | } 271 | }; 272 | }); 273 | 274 | function installForeignMethods(targetColorSpaceName, sourceColorSpaceName) { 275 | var obj = {}; 276 | obj[sourceColorSpaceName.toLowerCase()] = function () { 277 | return this.rgb()[sourceColorSpaceName.toLowerCase()](); 278 | }; 279 | color[sourceColorSpaceName].propertyNames.forEach(function (propertyName) { 280 | var shortName = propertyName === 'black' ? 'k' : propertyName.charAt(0); 281 | obj[propertyName] = obj[shortName] = function (value, isDelta) { 282 | return this[sourceColorSpaceName.toLowerCase()]()[propertyName]( 283 | value, 284 | isDelta 285 | ); 286 | }; 287 | }); 288 | for (var prop in obj) { 289 | if ( 290 | Object.prototype.hasOwnProperty.call(obj, prop) && 291 | color[targetColorSpaceName].prototype[prop] === undefined 292 | ) { 293 | color[targetColorSpaceName].prototype[prop] = obj[prop]; 294 | } 295 | } 296 | } 297 | 298 | installedColorSpaces.forEach(function (otherColorSpaceName) { 299 | installForeignMethods(colorSpaceName, otherColorSpaceName); 300 | installForeignMethods(otherColorSpaceName, colorSpaceName); 301 | }); 302 | 303 | installedColorSpaces.push(colorSpaceName); 304 | return color; 305 | }; 306 | 307 | color.pluginList = []; 308 | 309 | color.use = function (plugin) { 310 | if (color.pluginList.indexOf(plugin) === -1) { 311 | this.pluginList.push(plugin); 312 | plugin(color); 313 | } 314 | return color; 315 | }; 316 | 317 | color.installMethod = function (name, fn) { 318 | installedColorSpaces.forEach(function (colorSpace) { 319 | color[colorSpace].prototype[name] = fn; 320 | }); 321 | return this; 322 | }; 323 | 324 | color.installColorSpace('RGB', ['red', 'green', 'blue', 'alpha'], { 325 | hex: function () { 326 | var hexString = ( 327 | Math.round(255 * this._red) * 0x10000 + 328 | Math.round(255 * this._green) * 0x100 + 329 | Math.round(255 * this._blue) 330 | ).toString(16); 331 | return '#' + '00000'.substr(0, 6 - hexString.length) + hexString; 332 | }, 333 | 334 | hexa: function () { 335 | var alphaString = Math.round(this._alpha * 255).toString(16); 336 | return this.hex() + '00'.substr(0, 2 - alphaString.length) + alphaString; 337 | }, 338 | 339 | css: function () { 340 | return ( 341 | 'rgb(' + 342 | Math.round(255 * this._red) + 343 | ',' + 344 | Math.round(255 * this._green) + 345 | ',' + 346 | Math.round(255 * this._blue) + 347 | ')' 348 | ); 349 | }, 350 | 351 | cssa: function () { 352 | return ( 353 | 'rgba(' + 354 | Math.round(255 * this._red) + 355 | ',' + 356 | Math.round(255 * this._green) + 357 | ',' + 358 | Math.round(255 * this._blue) + 359 | ',' + 360 | this._alpha + 361 | ')' 362 | ); 363 | }, 364 | }); 365 | 366 | module.exports = color; 367 | -------------------------------------------------------------------------------- /lib/plugins/clearer.js: -------------------------------------------------------------------------------- 1 | module.exports = function clearer(color) { 2 | color.installMethod('clearer', function (amount) { 3 | return this.alpha(isNaN(amount) ? -0.1 : -amount, true); 4 | }); 5 | }; 6 | -------------------------------------------------------------------------------- /lib/plugins/contrast.js: -------------------------------------------------------------------------------- 1 | module.exports = function contrast(color) { 2 | // http://www.w3.org/TR/WCAG20/#contrast-ratiodef 3 | 4 | color.use(require('./luminance')); 5 | 6 | color.installMethod('contrast', function (color2) { 7 | var lum1 = this.luminance(); 8 | var lum2 = color2.luminance(); 9 | if (lum1 > lum2) { 10 | return (lum1 + 0.05) / (lum2 + 0.05); 11 | } 12 | 13 | return (lum2 + 0.05) / (lum1 + 0.05); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /lib/plugins/darken.js: -------------------------------------------------------------------------------- 1 | module.exports = function darken(color) { 2 | color.use(require('../HSL')); 3 | 4 | color.installMethod('darken', function (amount) { 5 | return this.lightness(isNaN(amount) ? -0.1 : -amount, true); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /lib/plugins/desaturate.js: -------------------------------------------------------------------------------- 1 | module.exports = function desaturate(color) { 2 | color.use(require('../HSL')); 3 | 4 | color.installMethod('desaturate', function (amount) { 5 | return this.saturation(isNaN(amount) ? -0.1 : -amount, true); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /lib/plugins/grayscale.js: -------------------------------------------------------------------------------- 1 | module.exports = function grayscale(color) { 2 | function gs() { 3 | /* jslint strict:false */ 4 | var rgb = this.rgb(); 5 | var val = rgb._red * 0.3 + rgb._green * 0.59 + rgb._blue * 0.11; 6 | 7 | return new color.RGB(val, val, val, rgb._alpha); 8 | } 9 | 10 | color.installMethod('greyscale', gs).installMethod('grayscale', gs); 11 | }; 12 | -------------------------------------------------------------------------------- /lib/plugins/isDark.js: -------------------------------------------------------------------------------- 1 | module.exports = function isDark(color) { 2 | color.installMethod('isDark', function () { 3 | var rgb = this.rgb(); 4 | 5 | // YIQ equation from http://24ways.org/2010/calculating-color-contrast 6 | var yiq = 7 | (rgb._red * 255 * 299 + rgb._green * 255 * 587 + rgb._blue * 255 * 114) / 8 | 1000; 9 | return yiq < 128; 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /lib/plugins/isLight.js: -------------------------------------------------------------------------------- 1 | module.exports = function isLight(color) { 2 | color.use(require('./isDark')); 3 | 4 | color.installMethod('isLight', function () { 5 | return !this.isDark(); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /lib/plugins/lighten.js: -------------------------------------------------------------------------------- 1 | module.exports = function lighten(color) { 2 | color.use(require('../HSL')); 3 | 4 | color.installMethod('lighten', function (amount) { 5 | return this.lightness(isNaN(amount) ? 0.1 : amount, true); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /lib/plugins/luminance.js: -------------------------------------------------------------------------------- 1 | module.exports = function luminance(color) { 2 | // http://www.w3.org/TR/WCAG20/#relativeluminancedef 3 | 4 | function channelLuminance(value) { 5 | return value <= 0.03928 6 | ? value / 12.92 7 | : Math.pow((value + 0.055) / 1.055, 2.4); 8 | } 9 | 10 | color.installMethod('luminance', function () { 11 | var rgb = this.rgb(); 12 | return ( 13 | 0.2126 * channelLuminance(rgb._red) + 14 | 0.7152 * channelLuminance(rgb._green) + 15 | 0.0722 * channelLuminance(rgb._blue) 16 | ); 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /lib/plugins/mix.js: -------------------------------------------------------------------------------- 1 | module.exports = function mix(color) { 2 | color.installMethod('mix', function (otherColor, weight) { 3 | otherColor = color(otherColor).rgb(); 4 | weight = 1 - (isNaN(weight) ? 0.5 : weight); 5 | 6 | var w = weight * 2 - 1; 7 | var a = this._alpha - otherColor._alpha; 8 | var weight1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2; 9 | var weight2 = 1 - weight1; 10 | var rgb = this.rgb(); 11 | 12 | return new color.RGB( 13 | rgb._red * weight1 + otherColor._red * weight2, 14 | rgb._green * weight1 + otherColor._green * weight2, 15 | rgb._blue * weight1 + otherColor._blue * weight2, 16 | rgb._alpha * weight + otherColor._alpha * (1 - weight) 17 | ); 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /lib/plugins/namedColors.js: -------------------------------------------------------------------------------- 1 | module.exports = function namedColors(color) { 2 | color.namedColors = { 3 | aliceblue: 'f0f8ff', 4 | antiquewhite: 'faebd7', 5 | aqua: '0ff', 6 | aquamarine: '7fffd4', 7 | azure: 'f0ffff', 8 | beige: 'f5f5dc', 9 | bisque: 'ffe4c4', 10 | black: '000', 11 | blanchedalmond: 'ffebcd', 12 | blue: '00f', 13 | blueviolet: '8a2be2', 14 | brown: 'a52a2a', 15 | burlywood: 'deb887', 16 | cadetblue: '5f9ea0', 17 | chartreuse: '7fff00', 18 | chocolate: 'd2691e', 19 | coral: 'ff7f50', 20 | cornflowerblue: '6495ed', 21 | cornsilk: 'fff8dc', 22 | crimson: 'dc143c', 23 | cyan: '0ff', 24 | darkblue: '00008b', 25 | darkcyan: '008b8b', 26 | darkgoldenrod: 'b8860b', 27 | darkgray: 'a9a9a9', 28 | darkgrey: 'a9a9a9', 29 | darkgreen: '006400', 30 | darkkhaki: 'bdb76b', 31 | darkmagenta: '8b008b', 32 | darkolivegreen: '556b2f', 33 | darkorange: 'ff8c00', 34 | darkorchid: '9932cc', 35 | darkred: '8b0000', 36 | darksalmon: 'e9967a', 37 | darkseagreen: '8fbc8f', 38 | darkslateblue: '483d8b', 39 | darkslategray: '2f4f4f', 40 | darkslategrey: '2f4f4f', 41 | darkturquoise: '00ced1', 42 | darkviolet: '9400d3', 43 | deeppink: 'ff1493', 44 | deepskyblue: '00bfff', 45 | dimgray: '696969', 46 | dimgrey: '696969', 47 | dodgerblue: '1e90ff', 48 | firebrick: 'b22222', 49 | floralwhite: 'fffaf0', 50 | forestgreen: '228b22', 51 | fuchsia: 'f0f', 52 | gainsboro: 'dcdcdc', 53 | ghostwhite: 'f8f8ff', 54 | gold: 'ffd700', 55 | goldenrod: 'daa520', 56 | gray: '808080', 57 | grey: '808080', 58 | green: '008000', 59 | greenyellow: 'adff2f', 60 | honeydew: 'f0fff0', 61 | hotpink: 'ff69b4', 62 | indianred: 'cd5c5c', 63 | indigo: '4b0082', 64 | ivory: 'fffff0', 65 | khaki: 'f0e68c', 66 | lavender: 'e6e6fa', 67 | lavenderblush: 'fff0f5', 68 | lawngreen: '7cfc00', 69 | lemonchiffon: 'fffacd', 70 | lightblue: 'add8e6', 71 | lightcoral: 'f08080', 72 | lightcyan: 'e0ffff', 73 | lightgoldenrodyellow: 'fafad2', 74 | lightgray: 'd3d3d3', 75 | lightgrey: 'd3d3d3', 76 | lightgreen: '90ee90', 77 | lightpink: 'ffb6c1', 78 | lightsalmon: 'ffa07a', 79 | lightseagreen: '20b2aa', 80 | lightskyblue: '87cefa', 81 | lightslategray: '789', 82 | lightslategrey: '789', 83 | lightsteelblue: 'b0c4de', 84 | lightyellow: 'ffffe0', 85 | lime: '0f0', 86 | limegreen: '32cd32', 87 | linen: 'faf0e6', 88 | magenta: 'f0f', 89 | maroon: '800000', 90 | mediumaquamarine: '66cdaa', 91 | mediumblue: '0000cd', 92 | mediumorchid: 'ba55d3', 93 | mediumpurple: '9370d8', 94 | mediumseagreen: '3cb371', 95 | mediumslateblue: '7b68ee', 96 | mediumspringgreen: '00fa9a', 97 | mediumturquoise: '48d1cc', 98 | mediumvioletred: 'c71585', 99 | midnightblue: '191970', 100 | mintcream: 'f5fffa', 101 | mistyrose: 'ffe4e1', 102 | moccasin: 'ffe4b5', 103 | navajowhite: 'ffdead', 104 | navy: '000080', 105 | oldlace: 'fdf5e6', 106 | olive: '808000', 107 | olivedrab: '6b8e23', 108 | orange: 'ffa500', 109 | orangered: 'ff4500', 110 | orchid: 'da70d6', 111 | palegoldenrod: 'eee8aa', 112 | palegreen: '98fb98', 113 | paleturquoise: 'afeeee', 114 | palevioletred: 'd87093', 115 | papayawhip: 'ffefd5', 116 | peachpuff: 'ffdab9', 117 | peru: 'cd853f', 118 | pink: 'ffc0cb', 119 | plum: 'dda0dd', 120 | powderblue: 'b0e0e6', 121 | purple: '800080', 122 | rebeccapurple: '639', 123 | red: 'f00', 124 | rosybrown: 'bc8f8f', 125 | royalblue: '4169e1', 126 | saddlebrown: '8b4513', 127 | salmon: 'fa8072', 128 | sandybrown: 'f4a460', 129 | seagreen: '2e8b57', 130 | seashell: 'fff5ee', 131 | sienna: 'a0522d', 132 | silver: 'c0c0c0', 133 | skyblue: '87ceeb', 134 | slateblue: '6a5acd', 135 | slategray: '708090', 136 | slategrey: '708090', 137 | snow: 'fffafa', 138 | springgreen: '00ff7f', 139 | steelblue: '4682b4', 140 | tan: 'd2b48c', 141 | teal: '008080', 142 | thistle: 'd8bfd8', 143 | tomato: 'ff6347', 144 | turquoise: '40e0d0', 145 | violet: 'ee82ee', 146 | wheat: 'f5deb3', 147 | white: 'fff', 148 | whitesmoke: 'f5f5f5', 149 | yellow: 'ff0', 150 | yellowgreen: '9acd32', 151 | }; 152 | }; 153 | -------------------------------------------------------------------------------- /lib/plugins/negate.js: -------------------------------------------------------------------------------- 1 | module.exports = function negate(color) { 2 | color.installMethod('negate', function () { 3 | var rgb = this.rgb(); 4 | return new color.RGB( 5 | 1 - rgb._red, 6 | 1 - rgb._green, 7 | 1 - rgb._blue, 8 | this._alpha 9 | ); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /lib/plugins/opaquer.js: -------------------------------------------------------------------------------- 1 | module.exports = function opaquer(color) { 2 | color.installMethod('opaquer', function (amount) { 3 | return this.alpha(isNaN(amount) ? 0.1 : amount, true); 4 | }); 5 | }; 6 | -------------------------------------------------------------------------------- /lib/plugins/rotate.js: -------------------------------------------------------------------------------- 1 | module.exports = function rotate(color) { 2 | color.use(require('../HSL')); 3 | 4 | color.installMethod('rotate', function (degrees) { 5 | return this.hue((degrees || 0) / 360, true); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /lib/plugins/saturate.js: -------------------------------------------------------------------------------- 1 | module.exports = function saturate(color) { 2 | color.use(require('../HSL')); 3 | 4 | color.installMethod('saturate', function (amount) { 5 | return this.saturation(isNaN(amount) ? 0.1 : amount, true); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /lib/plugins/toAlpha.js: -------------------------------------------------------------------------------- 1 | // Adapted from http://gimp.sourcearchive.com/documentation/2.6.6-1ubuntu1/color-to-alpha_8c-source.html 2 | // toAlpha returns a color where the values of the argument have been converted to alpha 3 | module.exports = function toAlpha(color) { 4 | color.installMethod('toAlpha', function (color) { 5 | var me = this.rgb(); 6 | var other = color(color).rgb(); 7 | var epsilon = 1e-10; 8 | var a = new color.RGB(0, 0, 0, me._alpha); 9 | var channels = ['_red', '_green', '_blue']; 10 | 11 | channels.forEach(function (channel) { 12 | if (me[channel] < epsilon) { 13 | a[channel] = me[channel]; 14 | } else if (me[channel] > other[channel]) { 15 | a[channel] = (me[channel] - other[channel]) / (1 - other[channel]); 16 | } else if (me[channel] > other[channel]) { 17 | a[channel] = (other[channel] - me[channel]) / other[channel]; 18 | } else { 19 | a[channel] = 0; 20 | } 21 | }); 22 | 23 | if (a._red > a._green) { 24 | if (a._red > a._blue) { 25 | me._alpha = a._red; 26 | } else { 27 | me._alpha = a._blue; 28 | } 29 | } else if (a._green > a._blue) { 30 | me._alpha = a._green; 31 | } else { 32 | me._alpha = a._blue; 33 | } 34 | 35 | if (me._alpha < epsilon) { 36 | return me; 37 | } 38 | 39 | channels.forEach(function (channel) { 40 | me[channel] = (me[channel] - other[channel]) / me._alpha + other[channel]; 41 | }); 42 | me._alpha *= a._alpha; 43 | 44 | return me; 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /minimal.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/color') 2 | .use(require('./lib/HSV')) 3 | .use(require('./lib/HSL')); 4 | -------------------------------------------------------------------------------- /one-color-all.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):((e=e||self).one=e.one||{},e.one.color=t())}(this,(function(){"use strict";var e=[],t=function(e){return void 0===e},a=/\s*(\.\d+|\d+(?:\.\d+)?)(%|deg)?\s*/,r=/\s*(\.\d+|100|\d?\d(?:\.\d+)?)%\s*/,n=new RegExp("^(rgb|hsl|hsv)a?\\("+a.source+"[, ]"+a.source+"[, ]"+a.source+"(?:[,/]"+a.source+")?\\)$","i");function i(e,t,a){return"%"===e?100:"deg"===e||a&&0===t?360:e?void 0:255}function o(e){if(Array.isArray(e)){if("string"==typeof e[0]&&"function"==typeof o[e[0]])return new o[e[0]](e.slice(1,e.length));if(4===e.length)return new o.RGB(e[0]/255,e[1]/255,e[2]/255,e[3]/255)}else if("string"==typeof e){var a=e.toLowerCase();o.namedColors[a]&&(e="#"+o.namedColors[a]),"transparent"===a&&(e="rgba(0,0,0,0)");var s=e.match(n);if(s){var f=s[1].toUpperCase(),u="H"===f[0];if(t(o[f]))throw new Error("color."+f+" is not installed.");let e=t(s[8])?1:void 0;return void 0===e&&(e="%"===s[9]?parseFloat(s[8])/100:parseFloat(s[8])),new o[f](parseFloat(s[2])/i(s[3],0,u),parseFloat(s[4])/i(s[5],1,u),parseFloat(s[6])/i(s[7],2,u),e)}e.length<6&&(e=e.replace(/^#?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/i,"$1$1$2$2$3$3$4$4"));var l=e.match(/^#?([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])?$/i);if(l)return new o.RGB(parseInt(l[1],16)/255,parseInt(l[2],16)/255,parseInt(l[3],16)/255,l[4]?parseInt(l[4],16)/255:1);if(o.CMYK){var h=e.match(new RegExp("^cmyk\\("+r.source+","+r.source+","+r.source+","+r.source+"\\)$","i"));if(h)return new o.CMYK(parseFloat(h[1])/100,parseFloat(h[2])/100,parseFloat(h[3])/100,parseFloat(h[4])/100)}}else if("object"==typeof e&&e.isColor)return e;return!1}o.namedColors={},o.installColorSpace=function(a,r,n){o[a]=function(e){var t=Array.isArray(e)?e:arguments;r.forEach((function(e,n){var i=t[n];if("alpha"===e)this._alpha=isNaN(i)||i>1?1:i<0?0:i;else{if(isNaN(i))throw new Error("["+a+"]: Invalid color: ("+r.join(",")+")");"hue"===e?this._hue=i<0?i-Math.floor(i):i%1:this["_"+e]=i<0?0:i>1?1:i}}),this)},o[a].propertyNames=r;var i=o[a].prototype;for(var s in["valueOf","hex","hexa","css","cssa"].forEach((function(e){i[e]=i[e]||("RGB"===a?i.hex:function(){return this.rgb()[e]()})})),i.isColor=!0,i.equals=function(e,n){t(n)&&(n=1e-10),e=e[a.toLowerCase()]();for(var i=0;in)return!1;return!0},i.toJSON=function(){return[a].concat(r.map((function(e){return this["_"+e]}),this))},n)if(Object.prototype.hasOwnProperty.call(n,s)){var f=s.match(/^from(.*)$/);f?o[f[1].toUpperCase()].prototype[a.toLowerCase()]=n[s]:i[s]=n[s]}function u(e,t){var a={};for(var r in a[t.toLowerCase()]=function(){return this.rgb()[t.toLowerCase()]()},o[t].propertyNames.forEach((function(e){var r="black"===e?"k":e.charAt(0);a[e]=a[r]=function(a,r){return this[t.toLowerCase()]()[e](a,r)}})),a)Object.prototype.hasOwnProperty.call(a,r)&&void 0===o[e].prototype[r]&&(o[e].prototype[r]=a[r])}return i[a.toLowerCase()]=function(){return this},i.toString=function(){return"["+a+" "+r.map((function(e){return this["_"+e]}),this).join(", ")+"]"},r.forEach((function(e){var t="black"===e?"k":e.charAt(0);i[e]=i[t]=function(t,a){return void 0===t?this["_"+e]:a?new this.constructor(r.map((function(a){return this["_"+a]+(e===a?t:0)}),this)):new this.constructor(r.map((function(a){return e===a?t:this["_"+a]}),this))}})),e.forEach((function(e){u(a,e),u(e,a)})),e.push(a),o},o.pluginList=[],o.use=function(e){return-1===o.pluginList.indexOf(e)&&(this.pluginList.push(e),e(o)),o},o.installMethod=function(t,a){return e.forEach((function(e){o[e].prototype[t]=a})),this},o.installColorSpace("RGB",["red","green","blue","alpha"],{hex:function(){var e=(65536*Math.round(255*this._red)+256*Math.round(255*this._green)+Math.round(255*this._blue)).toString(16);return"#"+"00000".substr(0,6-e.length)+e},hexa:function(){var e=Math.round(255*this._alpha).toString(16);return this.hex()+"00".substr(0,2-e.length)+e},css:function(){return"rgb("+Math.round(255*this._red)+","+Math.round(255*this._green)+","+Math.round(255*this._blue)+")"},cssa:function(){return"rgba("+Math.round(255*this._red)+","+Math.round(255*this._green)+","+Math.round(255*this._blue)+","+this._alpha+")"}});var s=function(e){e.installColorSpace("XYZ",["x","y","z","alpha"],{fromRgb:function(){var t=function(e){return e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92},a=t(this._red),r=t(this._green),n=t(this._blue);return new e.XYZ(.4124564*a+.3575761*r+.1804375*n,.2126729*a+.7151522*r+.072175*n,.0193339*a+.119192*r+.9503041*n,this._alpha)},rgb:function(){var t=this._x,a=this._y,r=this._z,n=function(e){return e>.0031308?1.055*Math.pow(e,1/2.4)-.055:12.92*e};return new e.RGB(n(3.2404542*t+-1.5371385*a+-.4985314*r),n(-.969266*t+1.8760108*a+.041556*r),n(.0556434*t+-.2040259*a+1.0572252*r),this._alpha)},lab:function(){var t=function(e){return e>.008856?Math.pow(e,1/3):7.787037*e+4/29},a=t(this._x/95.047),r=t(this._y/100),n=t(this._z/108.883);return new e.LAB(116*r-16,500*(a-r),200*(r-n),this._alpha)}})},f=function(e){e.installColorSpace("HSV",["hue","saturation","value","alpha"],{rgb:function(){var t,a,r,n=this._hue,i=this._saturation,o=this._value,s=Math.min(5,Math.floor(6*n)),f=6*n-s,u=o*(1-i),l=o*(1-f*i),h=o*(1-(1-f)*i);switch(s){case 0:t=o,a=h,r=u;break;case 1:t=l,a=o,r=u;break;case 2:t=u,a=o,r=h;break;case 3:t=u,a=l,r=o;break;case 4:t=h,a=u,r=o;break;case 5:t=o,a=u,r=l}return new e.RGB(t,a,r,this._alpha)},hsl:function(){var t,a=(2-this._saturation)*this._value,r=this._saturation*this._value,n=a<=1?a:2-a;return t=n<1e-9?0:r/n,new e.HSL(this._hue,t,a/2,this._alpha)},fromRgb:function(){var t,a=this._red,r=this._green,n=this._blue,i=Math.max(a,r,n),o=i-Math.min(a,r,n),s=0===i?0:o/i,f=i;if(0===o)t=0;else switch(i){case a:t=(r-n)/o/6+(r.008856?t:(e-16/116)/7.87},a=(this._l+16)/116,r=this._a/500+a,n=a-this._b/200;return new e.XYZ(95.047*t(r),100*t(a),108.883*t(n),this._alpha)}})})).use(f).use(u).use((function(e){e.installColorSpace("CMYK",["cyan","magenta","yellow","black","alpha"],{rgb:function(){return new e.RGB(1-this._cyan*(1-this._black)-this._black,1-this._magenta*(1-this._black)-this._black,1-this._yellow*(1-this._black)-this._black,this._alpha)},fromRgb:function(){var t=this._red,a=this._green,r=this._blue,n=1-t,i=1-a,o=1-r,s=1;return t||a||r?(n=(n-(s=Math.min(n,Math.min(i,o))))/(1-s),i=(i-s)/(1-s),o=(o-s)/(1-s)):s=1,new e.CMYK(n,i,o,s,this._alpha)}})})).use((function(e){e.namedColors={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"0ff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000",blanchedalmond:"ffebcd",blue:"00f",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"0ff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgrey:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkslategrey:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dimgrey:"696969",dodgerblue:"1e90ff",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"f0f",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",grey:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgray:"d3d3d3",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslategray:"789",lightslategrey:"789",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"0f0",limegreen:"32cd32",linen:"faf0e6",magenta:"f0f",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",rebeccapurple:"639",red:"f00",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",slategrey:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",wheat:"f5deb3",white:"fff",whitesmoke:"f5f5f5",yellow:"ff0",yellowgreen:"9acd32"}})).use((function(e){e.installMethod("clearer",(function(e){return this.alpha(isNaN(e)?-.1:-e,!0)}))})).use((function(e){e.use(l),e.installMethod("contrast",(function(e){var t=this.luminance(),a=e.luminance();return t>a?(t+.05)/(a+.05):(a+.05)/(t+.05)}))})).use((function(e){e.use(u),e.installMethod("darken",(function(e){return this.lightness(isNaN(e)?-.1:-e,!0)}))})).use((function(e){e.use(u),e.installMethod("desaturate",(function(e){return this.saturation(isNaN(e)?-.1:-e,!0)}))})).use((function(e){function t(){var t=this.rgb(),a=.3*t._red+.59*t._green+.11*t._blue;return new e.RGB(a,a,a,t._alpha)}e.installMethod("greyscale",t).installMethod("grayscale",t)})).use(h).use((function(e){e.use(h),e.installMethod("isLight",(function(){return!this.isDark()}))})).use((function(e){e.use(u),e.installMethod("lighten",(function(e){return this.lightness(isNaN(e)?.1:e,!0)}))})).use(l).use((function(e){e.installMethod("mix",(function(t,a){t=e(t).rgb();var r=2*(a=1-(isNaN(a)?.5:a))-1,n=this._alpha-t._alpha,i=((r*n==-1?r:(r+n)/(1+r*n))+1)/2,o=1-i,s=this.rgb();return new e.RGB(s._red*i+t._red*o,s._green*i+t._green*o,s._blue*i+t._blue*o,s._alpha*a+t._alpha*(1-a))}))})).use((function(e){e.installMethod("negate",(function(){var t=this.rgb();return new e.RGB(1-t._red,1-t._green,1-t._blue,this._alpha)}))})).use((function(e){e.installMethod("opaquer",(function(e){return this.alpha(isNaN(e)?.1:e,!0)}))})).use((function(e){e.use(u),e.installMethod("rotate",(function(e){return this.hue((e||0)/360,!0)}))})).use((function(e){e.use(u),e.installMethod("saturate",(function(e){return this.saturation(isNaN(e)?.1:e,!0)}))})).use((function(e){e.installMethod("toAlpha",(function(e){var t=this.rgb(),a=e(e).rgb(),r=new e.RGB(0,0,0,t._alpha),n=["_red","_green","_blue"];return n.forEach((function(e){t[e]<1e-10?r[e]=t[e]:t[e]>a[e]?r[e]=(t[e]-a[e])/(1-a[e]):t[e]>a[e]?r[e]=(a[e]-t[e])/a[e]:r[e]=0})),r._red>r._green?r._red>r._blue?t._alpha=r._red:t._alpha=r._blue:r._green>r._blue?t._alpha=r._green:t._alpha=r._blue,t._alpha<1e-10||(n.forEach((function(e){t[e]=(t[e]-a[e])/t._alpha+a[e]})),t._alpha*=r._alpha),t}))}))})); 2 | //# sourceMappingURL=one-color-all.js.map 3 | -------------------------------------------------------------------------------- /one-color.js: -------------------------------------------------------------------------------- 1 | !function(t,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):((t=t||self).one=t.one||{},t.one.color=r())}(this,(function(){"use strict";var t=[],r=function(t){return void 0===t},e=/\s*(\.\d+|\d+(?:\.\d+)?)(%|deg)?\s*/,n=/\s*(\.\d+|100|\d?\d(?:\.\d+)?)%\s*/,a=new RegExp("^(rgb|hsl|hsv)a?\\("+e.source+"[, ]"+e.source+"[, ]"+e.source+"(?:[,/]"+e.source+")?\\)$","i");function o(t,r,e){return"%"===t?100:"deg"===t||e&&0===r?360:t?void 0:255}function s(t){if(Array.isArray(t)){if("string"==typeof t[0]&&"function"==typeof s[t[0]])return new s[t[0]](t.slice(1,t.length));if(4===t.length)return new s.RGB(t[0]/255,t[1]/255,t[2]/255,t[3]/255)}else if("string"==typeof t){var e=t.toLowerCase();s.namedColors[e]&&(t="#"+s.namedColors[e]),"transparent"===e&&(t="rgba(0,0,0,0)");var i=t.match(a);if(i){var u=i[1].toUpperCase(),h="H"===u[0];if(r(s[u]))throw new Error("color."+u+" is not installed.");let t=r(i[8])?1:void 0;return void 0===t&&(t="%"===i[9]?parseFloat(i[8])/100:parseFloat(i[8])),new s[u](parseFloat(i[2])/o(i[3],0,h),parseFloat(i[4])/o(i[5],1,h),parseFloat(i[6])/o(i[7],2,h),t)}t.length<6&&(t=t.replace(/^#?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/i,"$1$1$2$2$3$3$4$4"));var c=t.match(/^#?([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])?$/i);if(c)return new s.RGB(parseInt(c[1],16)/255,parseInt(c[2],16)/255,parseInt(c[3],16)/255,c[4]?parseInt(c[4],16)/255:1);if(s.CMYK){var f=t.match(new RegExp("^cmyk\\("+n.source+","+n.source+","+n.source+","+n.source+"\\)$","i"));if(f)return new s.CMYK(parseFloat(f[1])/100,parseFloat(f[2])/100,parseFloat(f[3])/100,parseFloat(f[4])/100)}}else if("object"==typeof t&&t.isColor)return t;return!1}s.namedColors={},s.installColorSpace=function(e,n,a){s[e]=function(t){var r=Array.isArray(t)?t:arguments;n.forEach((function(t,a){var o=r[a];if("alpha"===t)this._alpha=isNaN(o)||o>1?1:o<0?0:o;else{if(isNaN(o))throw new Error("["+e+"]: Invalid color: ("+n.join(",")+")");"hue"===t?this._hue=o<0?o-Math.floor(o):o%1:this["_"+t]=o<0?0:o>1?1:o}}),this)},s[e].propertyNames=n;var o=s[e].prototype;for(var i in["valueOf","hex","hexa","css","cssa"].forEach((function(t){o[t]=o[t]||("RGB"===e?o.hex:function(){return this.rgb()[t]()})})),o.isColor=!0,o.equals=function(t,a){r(a)&&(a=1e-10),t=t[e.toLowerCase()]();for(var o=0;oa)return!1;return!0},o.toJSON=function(){return[e].concat(n.map((function(t){return this["_"+t]}),this))},a)if(Object.prototype.hasOwnProperty.call(a,i)){var u=i.match(/^from(.*)$/);u?s[u[1].toUpperCase()].prototype[e.toLowerCase()]=a[i]:o[i]=a[i]}function h(t,r){var e={};for(var n in e[r.toLowerCase()]=function(){return this.rgb()[r.toLowerCase()]()},s[r].propertyNames.forEach((function(t){var n="black"===t?"k":t.charAt(0);e[t]=e[n]=function(e,n){return this[r.toLowerCase()]()[t](e,n)}})),e)Object.prototype.hasOwnProperty.call(e,n)&&void 0===s[t].prototype[n]&&(s[t].prototype[n]=e[n])}return o[e.toLowerCase()]=function(){return this},o.toString=function(){return"["+e+" "+n.map((function(t){return this["_"+t]}),this).join(", ")+"]"},n.forEach((function(t){var r="black"===t?"k":t.charAt(0);o[t]=o[r]=function(r,e){return void 0===r?this["_"+t]:e?new this.constructor(n.map((function(e){return this["_"+e]+(t===e?r:0)}),this)):new this.constructor(n.map((function(e){return t===e?r:this["_"+e]}),this))}})),t.forEach((function(t){h(e,t),h(t,e)})),t.push(e),s},s.pluginList=[],s.use=function(t){return-1===s.pluginList.indexOf(t)&&(this.pluginList.push(t),t(s)),s},s.installMethod=function(r,e){return t.forEach((function(t){s[t].prototype[r]=e})),this},s.installColorSpace("RGB",["red","green","blue","alpha"],{hex:function(){var t=(65536*Math.round(255*this._red)+256*Math.round(255*this._green)+Math.round(255*this._blue)).toString(16);return"#"+"00000".substr(0,6-t.length)+t},hexa:function(){var t=Math.round(255*this._alpha).toString(16);return this.hex()+"00".substr(0,2-t.length)+t},css:function(){return"rgb("+Math.round(255*this._red)+","+Math.round(255*this._green)+","+Math.round(255*this._blue)+")"},cssa:function(){return"rgba("+Math.round(255*this._red)+","+Math.round(255*this._green)+","+Math.round(255*this._blue)+","+this._alpha+")"}});var i=function(t){t.installColorSpace("HSV",["hue","saturation","value","alpha"],{rgb:function(){var r,e,n,a=this._hue,o=this._saturation,s=this._value,i=Math.min(5,Math.floor(6*a)),u=6*a-i,h=s*(1-o),c=s*(1-u*o),f=s*(1-(1-u)*o);switch(i){case 0:r=s,e=f,n=h;break;case 1:r=c,e=s,n=h;break;case 2:r=h,e=s,n=f;break;case 3:r=h,e=c,n=s;break;case 4:r=f,e=h,n=s;break;case 5:r=s,e=h,n=c}return new t.RGB(r,e,n,this._alpha)},hsl:function(){var r,e=(2-this._saturation)*this._value,n=this._saturation*this._value,a=e<=1?e:2-e;return r=a<1e-9?0:n/a,new t.HSL(this._hue,r,e/2,this._alpha)},fromRgb:function(){var r,e=this._red,n=this._green,a=this._blue,o=Math.max(e,n,a),s=o-Math.min(e,n,a),i=0===o?0:s/o,u=o;if(0===s)r=0;else switch(o){case e:r=(n-a)/s/6+(n 1\n ? 1\n : propertyValue < 0\n ? 0\n : propertyValue;\n } else {\n if (isNaN(propertyValue)) {\n throw new Error(\n '[' +\n colorSpaceName +\n ']: Invalid color: (' +\n propertyNames.join(',') +\n ')'\n );\n }\n if (propertyName === 'hue') {\n this._hue =\n propertyValue < 0\n ? propertyValue - Math.floor(propertyValue)\n : propertyValue % 1;\n } else {\n this['_' + propertyName] =\n propertyValue < 0 ? 0 : propertyValue > 1 ? 1 : propertyValue;\n }\n }\n }, this);\n };\n color[colorSpaceName].propertyNames = propertyNames;\n\n var prototype = color[colorSpaceName].prototype;\n\n ['valueOf', 'hex', 'hexa', 'css', 'cssa'].forEach(function (methodName) {\n prototype[methodName] =\n prototype[methodName] ||\n (colorSpaceName === 'RGB'\n ? prototype.hex\n : function () {\n return this.rgb()[methodName]();\n });\n });\n\n prototype.isColor = true;\n\n prototype.equals = function (otherColor, epsilon) {\n if (undef(epsilon)) {\n epsilon = 1e-10;\n }\n\n otherColor = otherColor[colorSpaceName.toLowerCase()]();\n\n for (var i = 0; i < propertyNames.length; i = i + 1) {\n if (\n Math.abs(\n this['_' + propertyNames[i]] - otherColor['_' + propertyNames[i]]\n ) > epsilon\n ) {\n return false;\n }\n }\n\n return true;\n };\n\n prototype.toJSON = function () {\n return [colorSpaceName].concat(\n propertyNames.map(function (propertyName) {\n return this['_' + propertyName];\n }, this)\n );\n };\n\n for (var propertyName in config) {\n if (Object.prototype.hasOwnProperty.call(config, propertyName)) {\n var matchFromColorSpace = propertyName.match(/^from(.*)$/);\n if (matchFromColorSpace) {\n color[matchFromColorSpace[1].toUpperCase()].prototype[\n colorSpaceName.toLowerCase()\n ] = config[propertyName];\n } else {\n prototype[propertyName] = config[propertyName];\n }\n }\n }\n\n // It is pretty easy to implement the conversion to the same color space:\n prototype[colorSpaceName.toLowerCase()] = function () {\n return this;\n };\n prototype.toString = function () {\n return (\n '[' +\n colorSpaceName +\n ' ' +\n propertyNames\n .map(function (propertyName) {\n return this['_' + propertyName];\n }, this)\n .join(', ') +\n ']'\n );\n };\n\n // Generate getters and setters\n propertyNames.forEach(function (propertyName) {\n var shortName = propertyName === 'black' ? 'k' : propertyName.charAt(0);\n prototype[propertyName] = prototype[shortName] = function (value, isDelta) {\n // Simple getter mode: color.red()\n if (typeof value === 'undefined') {\n return this['_' + propertyName];\n } else if (isDelta) {\n // Adjuster: color.red(+.2, true)\n return new this.constructor(\n propertyNames.map(function (otherPropertyName) {\n return (\n this['_' + otherPropertyName] +\n (propertyName === otherPropertyName ? value : 0)\n );\n }, this)\n );\n } else {\n // Setter: color.red(.2);\n return new this.constructor(\n propertyNames.map(function (otherPropertyName) {\n return propertyName === otherPropertyName\n ? value\n : this['_' + otherPropertyName];\n }, this)\n );\n }\n };\n });\n\n function installForeignMethods(targetColorSpaceName, sourceColorSpaceName) {\n var obj = {};\n obj[sourceColorSpaceName.toLowerCase()] = function () {\n return this.rgb()[sourceColorSpaceName.toLowerCase()]();\n };\n color[sourceColorSpaceName].propertyNames.forEach(function (propertyName) {\n var shortName = propertyName === 'black' ? 'k' : propertyName.charAt(0);\n obj[propertyName] = obj[shortName] = function (value, isDelta) {\n return this[sourceColorSpaceName.toLowerCase()]()[propertyName](\n value,\n isDelta\n );\n };\n });\n for (var prop in obj) {\n if (\n Object.prototype.hasOwnProperty.call(obj, prop) &&\n color[targetColorSpaceName].prototype[prop] === undefined\n ) {\n color[targetColorSpaceName].prototype[prop] = obj[prop];\n }\n }\n }\n\n installedColorSpaces.forEach(function (otherColorSpaceName) {\n installForeignMethods(colorSpaceName, otherColorSpaceName);\n installForeignMethods(otherColorSpaceName, colorSpaceName);\n });\n\n installedColorSpaces.push(colorSpaceName);\n return color;\n};\n\ncolor.pluginList = [];\n\ncolor.use = function (plugin) {\n if (color.pluginList.indexOf(plugin) === -1) {\n this.pluginList.push(plugin);\n plugin(color);\n }\n return color;\n};\n\ncolor.installMethod = function (name, fn) {\n installedColorSpaces.forEach(function (colorSpace) {\n color[colorSpace].prototype[name] = fn;\n });\n return this;\n};\n\ncolor.installColorSpace('RGB', ['red', 'green', 'blue', 'alpha'], {\n hex: function () {\n var hexString = (\n Math.round(255 * this._red) * 0x10000 +\n Math.round(255 * this._green) * 0x100 +\n Math.round(255 * this._blue)\n ).toString(16);\n return '#' + '00000'.substr(0, 6 - hexString.length) + hexString;\n },\n\n hexa: function () {\n var alphaString = Math.round(this._alpha * 255).toString(16);\n return this.hex() + '00'.substr(0, 2 - alphaString.length) + alphaString;\n },\n\n css: function () {\n return (\n 'rgb(' +\n Math.round(255 * this._red) +\n ',' +\n Math.round(255 * this._green) +\n ',' +\n Math.round(255 * this._blue) +\n ')'\n );\n },\n\n cssa: function () {\n return (\n 'rgba(' +\n Math.round(255 * this._red) +\n ',' +\n Math.round(255 * this._green) +\n ',' +\n Math.round(255 * this._blue) +\n ',' +\n this._alpha +\n ')'\n );\n },\n});\n\nmodule.exports = color;\n","module.exports = function HSV(color) {\n color.installColorSpace('HSV', ['hue', 'saturation', 'value', 'alpha'], {\n rgb: function () {\n var hue = this._hue;\n var saturation = this._saturation;\n var value = this._value;\n var i = Math.min(5, Math.floor(hue * 6));\n var f = hue * 6 - i;\n var p = value * (1 - saturation);\n var q = value * (1 - f * saturation);\n var t = value * (1 - (1 - f) * saturation);\n var red;\n var green;\n var blue;\n switch (i) {\n case 0:\n red = value;\n green = t;\n blue = p;\n break;\n case 1:\n red = q;\n green = value;\n blue = p;\n break;\n case 2:\n red = p;\n green = value;\n blue = t;\n break;\n case 3:\n red = p;\n green = q;\n blue = value;\n break;\n case 4:\n red = t;\n green = p;\n blue = value;\n break;\n case 5:\n red = value;\n green = p;\n blue = q;\n break;\n }\n return new color.RGB(red, green, blue, this._alpha);\n },\n\n hsl: function () {\n var l = (2 - this._saturation) * this._value;\n var sv = this._saturation * this._value;\n var svDivisor = l <= 1 ? l : 2 - l;\n var saturation;\n\n // Avoid division by zero when lightness approaches zero:\n if (svDivisor < 1e-9) {\n saturation = 0;\n } else {\n saturation = sv / svDivisor;\n }\n return new color.HSL(this._hue, saturation, l / 2, this._alpha);\n },\n\n fromRgb: function () {\n // Becomes one.color.RGB.prototype.hsv\n var red = this._red;\n var green = this._green;\n var blue = this._blue;\n var max = Math.max(red, green, blue);\n var min = Math.min(red, green, blue);\n var delta = max - min;\n var hue;\n var saturation = max === 0 ? 0 : delta / max;\n var value = max;\n if (delta === 0) {\n hue = 0;\n } else {\n switch (max) {\n case red:\n hue = (green - blue) / delta / 6 + (green < blue ? 1 : 0);\n break;\n case green:\n hue = (blue - red) / delta / 6 + 1 / 3;\n break;\n case blue:\n hue = (red - green) / delta / 6 + 2 / 3;\n break;\n }\n }\n return new color.HSV(hue, saturation, value, this._alpha);\n },\n });\n};\n","module.exports = require('./lib/color')\n .use(require('./lib/HSV'))\n .use(require('./lib/HSL'));\n","module.exports = function HSL(color) {\n color.use(require('./HSV'));\n\n color.installColorSpace('HSL', ['hue', 'saturation', 'lightness', 'alpha'], {\n hsv: function () {\n // Algorithm adapted from http://wiki.secondlife.com/wiki/Color_conversion_scripts\n var l = this._lightness * 2;\n var s = this._saturation * (l <= 1 ? l : 2 - l);\n var saturation;\n\n // Avoid division by zero when l + s is very small (approaching black):\n if (l + s < 1e-9) {\n saturation = 0;\n } else {\n saturation = (2 * s) / (l + s);\n }\n\n return new color.HSV(this._hue, saturation, (l + s) / 2, this._alpha);\n },\n\n rgb: function () {\n return this.hsv().rgb();\n },\n\n fromRgb: function () {\n // Becomes one.color.RGB.prototype.hsv\n return this.hsv().hsl();\n },\n });\n};\n"],"names":["installedColorSpaces","undef","obj","channelRegExp","percentageChannelRegExp","cssColorRegExp","RegExp","source","divisor","unit","channelNumber","hasHue","color","Array","isArray","slice","length","RGB","lowerCased","toLowerCase","namedColors","matchCssSyntax","match","colorSpaceName","toUpperCase","Error","alpha","undefined","parseFloat","replace","hexMatch","parseInt","CMYK","cmykMatch","isColor","installColorSpace","propertyNames","config","a1","args","arguments","forEach","propertyName","i","propertyValue","this","_alpha","isNaN","join","_hue","Math","floor","prototype","methodName","hex","rgb","equals","otherColor","epsilon","abs","toJSON","concat","map","Object","hasOwnProperty","call","matchFromColorSpace","installForeignMethods","targetColorSpaceName","sourceColorSpaceName","prop","shortName","charAt","value","isDelta","toString","constructor","otherPropertyName","otherColorSpaceName","push","pluginList","use","plugin","indexOf","installMethod","name","fn","colorSpace","hexString","round","_red","_green","_blue","substr","hexa","alphaString","css","cssa","red","green","blue","hue","saturation","_saturation","_value","min","f","p","q","t","hsl","l","sv","svDivisor","HSL","fromRgb","max","delta","HSV","require$$1","require$$0","hsv","_lightness","s"],"mappings":"kNAAA,IAAIA,EAAuB,GACvBC,EAAQ,SAAUC,GACpB,YAAsB,IAARA,GAEZC,EAAgB,sCAChBC,EAA0B,qCAC1BC,EAAiB,IAAIC,OACvB,sBAEEH,EAAcI,OACd,OACAJ,EAAcI,OACd,OACAJ,EAAcI,OACd,UACAJ,EAAcI,OARhB,SAWA,KAGF,SAASC,EAAQC,EAAMC,EAAeC,GACpC,MAAa,MAATF,EACK,IACW,QAATA,GAAmBE,GAA4B,IAAlBD,EAC/B,IACGD,OAAL,EACE,IAIX,SAASG,EAAMV,GACb,GAAIW,MAAMC,QAAQZ,GAAM,CACtB,GAAsB,iBAAXA,EAAI,IAA4C,mBAAlBU,EAAMV,EAAI,IAEjD,OAAO,IAAIU,EAAMV,EAAI,IAAIA,EAAIa,MAAM,EAAGb,EAAIc,SACrC,GAAmB,IAAfd,EAAIc,OAEb,OAAO,IAAIJ,EAAMK,IACff,EAAI,GAAK,IACTA,EAAI,GAAK,IACTA,EAAI,GAAK,IACTA,EAAI,GAAK,UAGR,GAAmB,iBAARA,EAAkB,CAClC,IAAIgB,EAAahB,EAAIiB,cACjBP,EAAMQ,YAAYF,KACpBhB,EAAM,IAAMU,EAAMQ,YAAYF,IAEb,gBAAfA,IACFhB,EAAM,iBAGR,IAAImB,EAAiBnB,EAAIoB,MAAMjB,GAC/B,GAAIgB,EAAgB,CAClB,IAAIE,EAAiBF,EAAe,GAAGG,cACnCb,EAA+B,MAAtBY,EAAe,GAC5B,GAAItB,EAAMW,EAAMW,IACd,MAAM,IAAIE,MAAM,SAAWF,EAAiB,sBAG9C,IAAIG,EAAQzB,EAAMoB,EAAe,IAAM,OAAIM,EAQ3C,YAPcA,IAAVD,IAEAA,EADwB,MAAtBL,EAAe,GACTO,WAAWP,EAAe,IAAM,IAEhCO,WAAWP,EAAe,KAG/B,IAAIT,EAAMW,GACfK,WAAWP,EAAe,IAAMb,EAAQa,EAAe,GAAI,EAAGV,GAC9DiB,WAAWP,EAAe,IAAMb,EAAQa,EAAe,GAAI,EAAGV,GAC9DiB,WAAWP,EAAe,IAAMb,EAAQa,EAAe,GAAI,EAAGV,GAC9De,GAIAxB,EAAIc,OAAS,IAEfd,EAAMA,EAAI2B,QACR,iDACA,qBAIJ,IAAIC,EAAW5B,EAAIoB,MACjB,kFAGF,GAAIQ,EACF,OAAO,IAAIlB,EAAMK,IACfc,SAASD,EAAS,GAAI,IAAM,IAC5BC,SAASD,EAAS,GAAI,IAAM,IAC5BC,SAASD,EAAS,GAAI,IAAM,IAC5BA,EAAS,GAAKC,SAASD,EAAS,GAAI,IAAM,IAAM,GAKpD,GAAIlB,EAAMoB,KAAM,CACd,IAAIC,EAAY/B,EAAIoB,MAClB,IAAIhB,OACF,WAEEF,EAAwBG,OACxB,IACAH,EAAwBG,OACxB,IACAH,EAAwBG,OACxB,IACAH,EAAwBG,OACxB,OACF,MAGJ,GAAI0B,EACF,OAAO,IAAIrB,EAAMoB,KACfJ,WAAWK,EAAU,IAAM,IAC3BL,WAAWK,EAAU,IAAM,IAC3BL,WAAWK,EAAU,IAAM,IAC3BL,WAAWK,EAAU,IAAM,WAI5B,GAAmB,iBAAR/B,GAAoBA,EAAIgC,QACxC,OAAOhC,EAET,OAAO,EAGTU,EAAMQ,YAAc,GAEpBR,EAAMuB,kBAAoB,SAAUZ,EAAgBa,EAAeC,GACjEzB,EAAMW,GAAkB,SAAUe,GAEhC,IAAIC,EAAO1B,MAAMC,QAAQwB,GAAMA,EAAKE,UACpCJ,EAAcK,SAAQ,SAAUC,EAAcC,GAC5C,IAAIC,EAAgBL,EAAKI,GACzB,GAAqB,UAAjBD,EACFG,KAAKC,OACHC,MAAMH,IAAkBA,EAAgB,EACpC,EACAA,EAAgB,EAChB,EACAA,MACD,CACL,GAAIG,MAAMH,GACR,MAAM,IAAInB,MACR,IACEF,EACA,sBACAa,EAAcY,KAAK,KACnB,KAGe,QAAjBN,EACFG,KAAKI,KACHL,EAAgB,EACZA,EAAgBM,KAAKC,MAAMP,GAC3BA,EAAgB,EAEtBC,KAAK,IAAMH,GACTE,EAAgB,EAAI,EAAIA,EAAgB,EAAI,EAAIA,KAGrDC,OAELjC,EAAMW,GAAgBa,cAAgBA,EAEtC,IAAIgB,EAAYxC,EAAMW,GAAgB6B,UA0CtC,IAAK,IAAIV,IAxCT,CAAC,UAAW,MAAO,OAAQ,MAAO,QAAQD,SAAQ,SAAUY,GAC1DD,EAAUC,GACRD,EAAUC,KACU,QAAnB9B,EACG6B,EAAUE,IACV,WACE,OAAOT,KAAKU,MAAMF,UAI5BD,EAAUlB,SAAU,EAEpBkB,EAAUI,OAAS,SAAUC,EAAYC,GACnCzD,EAAMyD,KACRA,EAAU,OAGZD,EAAaA,EAAWlC,EAAeJ,iBAEvC,IAAK,IAAIwB,EAAI,EAAGA,EAAIP,EAAcpB,OAAQ2B,GAAQ,EAChD,GACEO,KAAKS,IACHd,KAAK,IAAMT,EAAcO,IAAMc,EAAW,IAAMrB,EAAcO,KAC5De,EAEJ,OAAO,EAIX,OAAO,GAGTN,EAAUQ,OAAS,WACjB,MAAO,CAACrC,GAAgBsC,OACtBzB,EAAc0B,KAAI,SAAUpB,GAC1B,OAAOG,KAAK,IAAMH,KACjBG,QAIkBR,EACvB,GAAI0B,OAAOX,UAAUY,eAAeC,KAAK5B,EAAQK,GAAe,CAC9D,IAAIwB,EAAsBxB,EAAapB,MAAM,cACzC4C,EACFtD,EAAMsD,EAAoB,GAAG1C,eAAe4B,UAC1C7B,EAAeJ,eACbkB,EAAOK,GAEXU,EAAUV,GAAgBL,EAAOK,GAqDvC,SAASyB,EAAsBC,EAAsBC,GACnD,IAAInE,EAAM,GAaV,IAAK,IAAIoE,KAZTpE,EAAImE,EAAqBlD,eAAiB,WACxC,OAAO0B,KAAKU,MAAMc,EAAqBlD,kBAEzCP,EAAMyD,GAAsBjC,cAAcK,SAAQ,SAAUC,GAC1D,IAAI6B,EAA6B,UAAjB7B,EAA2B,IAAMA,EAAa8B,OAAO,GACrEtE,EAAIwC,GAAgBxC,EAAIqE,GAAa,SAAUE,EAAOC,GACpD,OAAO7B,KAAKwB,EAAqBlD,iBAAiBuB,GAChD+B,EACAC,OAIWxE,EAEb6D,OAAOX,UAAUY,eAAeC,KAAK/D,EAAKoE,SACM3C,IAAhDf,EAAMwD,GAAsBhB,UAAUkB,KAEtC1D,EAAMwD,GAAsBhB,UAAUkB,GAAQpE,EAAIoE,IAWxD,OA7EAlB,EAAU7B,EAAeJ,eAAiB,WACxC,OAAO0B,MAETO,EAAUuB,SAAW,WACnB,MACE,IACApD,EACA,IACAa,EACG0B,KAAI,SAAUpB,GACb,OAAOG,KAAK,IAAMH,KACjBG,MACFG,KAAK,MACR,KAKJZ,EAAcK,SAAQ,SAAUC,GAC9B,IAAI6B,EAA6B,UAAjB7B,EAA2B,IAAMA,EAAa8B,OAAO,GACrEpB,EAAUV,GAAgBU,EAAUmB,GAAa,SAAUE,EAAOC,GAEhE,YAAqB,IAAVD,EACF5B,KAAK,IAAMH,GACTgC,EAEF,IAAI7B,KAAK+B,YACdxC,EAAc0B,KAAI,SAAUe,GAC1B,OACEhC,KAAK,IAAMgC,IACVnC,IAAiBmC,EAAoBJ,EAAQ,KAE/C5B,OAIE,IAAIA,KAAK+B,YACdxC,EAAc0B,KAAI,SAAUe,GAC1B,OAAOnC,IAAiBmC,EACpBJ,EACA5B,KAAK,IAAMgC,KACdhC,WA8BX7C,EAAqByC,SAAQ,SAAUqC,GACrCX,EAAsB5C,EAAgBuD,GACtCX,EAAsBW,EAAqBvD,MAG7CvB,EAAqB+E,KAAKxD,GACnBX,GAGTA,EAAMoE,WAAa,GAEnBpE,EAAMqE,IAAM,SAAUC,GAKpB,OAJ0C,IAAtCtE,EAAMoE,WAAWG,QAAQD,KAC3BrC,KAAKmC,WAAWD,KAAKG,GACrBA,EAAOtE,IAEFA,GAGTA,EAAMwE,cAAgB,SAAUC,EAAMC,GAIpC,OAHAtF,EAAqByC,SAAQ,SAAU8C,GACrC3E,EAAM2E,GAAYnC,UAAUiC,GAAQC,KAE/BzC,MAGTjC,EAAMuB,kBAAkB,MAAO,CAAC,MAAO,QAAS,OAAQ,SAAU,CAChEmB,IAAK,WACH,IAAIkC,GAC4B,MAA9BtC,KAAKuC,MAAM,IAAM5C,KAAK6C,MACU,IAAhCxC,KAAKuC,MAAM,IAAM5C,KAAK8C,QACtBzC,KAAKuC,MAAM,IAAM5C,KAAK+C,QACtBjB,SAAS,IACX,MAAO,IAAM,QAAQkB,OAAO,EAAG,EAAIL,EAAUxE,QAAUwE,GAGzDM,KAAM,WACJ,IAAIC,EAAc7C,KAAKuC,MAAoB,IAAd5C,KAAKC,QAAc6B,SAAS,IACzD,OAAO9B,KAAKS,MAAQ,KAAKuC,OAAO,EAAG,EAAIE,EAAY/E,QAAU+E,GAG/DC,IAAK,WACH,MACE,OACA9C,KAAKuC,MAAM,IAAM5C,KAAK6C,MACtB,IACAxC,KAAKuC,MAAM,IAAM5C,KAAK8C,QACtB,IACAzC,KAAKuC,MAAM,IAAM5C,KAAK+C,OACtB,KAIJK,KAAM,WACJ,MACE,QACA/C,KAAKuC,MAAM,IAAM5C,KAAK6C,MACtB,IACAxC,KAAKuC,MAAM,IAAM5C,KAAK8C,QACtB,IACAzC,KAAKuC,MAAM,IAAM5C,KAAK+C,OACtB,IACA/C,KAAKC,OACL,OAKN,MC7WiB,SAAalC,GAC5BA,EAAMuB,kBAAkB,MAAO,CAAC,MAAO,aAAc,QAAS,SAAU,CACtEoB,IAAK,WACH,IAQI2C,EACAC,EACAC,EAVAC,EAAMxD,KAAKI,KACXqD,EAAazD,KAAK0D,YAClB9B,EAAQ5B,KAAK2D,OACb7D,EAAIO,KAAKuD,IAAI,EAAGvD,KAAKC,MAAY,EAANkD,IAC3BK,EAAU,EAANL,EAAU1D,EACdgE,EAAIlC,GAAS,EAAI6B,GACjBM,EAAInC,GAAS,EAAIiC,EAAIJ,GACrBO,EAAIpC,GAAS,GAAK,EAAIiC,GAAKJ,GAI/B,OAAQ3D,GACN,KAAK,EACHuD,EAAMzB,EACN0B,EAAQU,EACRT,EAAOO,EACP,MACF,KAAK,EACHT,EAAMU,EACNT,EAAQ1B,EACR2B,EAAOO,EACP,MACF,KAAK,EACHT,EAAMS,EACNR,EAAQ1B,EACR2B,EAAOS,EACP,MACF,KAAK,EACHX,EAAMS,EACNR,EAAQS,EACRR,EAAO3B,EACP,MACF,KAAK,EACHyB,EAAMW,EACNV,EAAQQ,EACRP,EAAO3B,EACP,MACF,KAAK,EACHyB,EAAMzB,EACN0B,EAAQQ,EACRP,EAAOQ,EAGX,OAAO,IAAIhG,EAAMK,IAAIiF,EAAKC,EAAOC,EAAMvD,KAAKC,SAG9CgE,IAAK,WACH,IAGIR,EAHAS,GAAK,EAAIlE,KAAK0D,aAAe1D,KAAK2D,OAClCQ,EAAKnE,KAAK0D,YAAc1D,KAAK2D,OAC7BS,EAAYF,GAAK,EAAIA,EAAI,EAAIA,EASjC,OAJET,EADEW,EAAY,KACD,EAEAD,EAAKC,EAEb,IAAIrG,EAAMsG,IAAIrE,KAAKI,KAAMqD,EAAYS,EAAI,EAAGlE,KAAKC,SAG1DqE,QAAS,WAEP,IAMId,EANAH,EAAMrD,KAAK6C,KACXS,EAAQtD,KAAK8C,OACbS,EAAOvD,KAAK+C,MACZwB,EAAMlE,KAAKkE,IAAIlB,EAAKC,EAAOC,GAE3BiB,EAAQD,EADFlE,KAAKuD,IAAIP,EAAKC,EAAOC,GAG3BE,EAAqB,IAARc,EAAY,EAAIC,EAAQD,EACrC3C,EAAQ2C,EACZ,GAAc,IAAVC,EACFhB,EAAM,OAEN,OAAQe,GACN,KAAKlB,EACHG,GAAOF,EAAQC,GAAQiB,EAAQ,GAAKlB,EAAQC,EAAO,EAAI,GACvD,MACF,KAAKD,EACHE,GAAOD,EAAOF,GAAOmB,EAAQ,EAAI,EAAI,EACrC,MACF,KAAKjB,EACHC,GAAOH,EAAMC,GAASkB,EAAQ,EAAI,EAAI,EAI5C,OAAO,IAAIzG,EAAM0G,IAAIjB,EAAKC,EAAY7B,EAAO5B,KAAKC,mBDmRvClC,EE5WdqE,IAAIsC,GACJtC,KCFc,SAAarE,GAC5BA,EAAMqE,IAAIuC,GAEV5G,EAAMuB,kBAAkB,MAAO,CAAC,MAAO,aAAc,YAAa,SAAU,CAC1EsF,IAAK,WAEH,IAEInB,EAFAS,EAAsB,EAAlBlE,KAAK6E,WACTC,EAAI9E,KAAK0D,aAAeQ,GAAK,EAAIA,EAAI,EAAIA,GAU7C,OALET,EADES,EAAIY,EAAI,KACG,EAEC,EAAIA,GAAMZ,EAAIY,GAGvB,IAAI/G,EAAM0G,IAAIzE,KAAKI,KAAMqD,GAAaS,EAAIY,GAAK,EAAG9E,KAAKC,SAGhES,IAAK,WACH,OAAOV,KAAK4E,MAAMlE,OAGpB4D,QAAS,WAEP,OAAOtE,KAAK4E,MAAMX"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "onecolor", 3 | "description": "Javascript color object with implicit color space conversions. Supports RGB, HSV, HSL and CMYK with alpha channel.", 4 | "repository": "git@github.com:One-com/one-color.git", 5 | "version": "4.1.0", 6 | "license": "BSD-2-Clause", 7 | "keywords": [ 8 | "color", 9 | "colour", 10 | "conversion", 11 | "rgb", 12 | "hsv", 13 | "hsl", 14 | "cmyk" 15 | ], 16 | "maintainers": [ 17 | { 18 | "name": "Peter Müller", 19 | "email": "munter@fumle.dk" 20 | }, 21 | { 22 | "name": "Andreas Lind", 23 | "email": "andreaslindpetersen@gmail.com" 24 | } 25 | ], 26 | "devDependencies": { 27 | "@rollup/plugin-commonjs": "^14.0.0", 28 | "coveralls": "2.11.9", 29 | "eslint": "^7.4.0", 30 | "eslint-config-prettier": "^6.11.0", 31 | "eslint-config-standard": "^14.1.1", 32 | "eslint-plugin-import": "^2.22.0", 33 | "eslint-plugin-mocha": "^7.0.1", 34 | "eslint-plugin-node": "^11.1.0", 35 | "eslint-plugin-promise": "^4.2.1", 36 | "eslint-plugin-standard": "^4.0.1", 37 | "evaldown": "^1.2.2", 38 | "istanbul": "0.4.2", 39 | "mocha": "2.4.5", 40 | "mocha-lcov-reporter": "1.2.0", 41 | "onecolor": "file:./", 42 | "prettier": "~2.8.0", 43 | "rollup": "^2.21.0", 44 | "rollup-plugin-terser": "^6.1.0", 45 | "unexpected": "10.11.1" 46 | }, 47 | "engines": { 48 | "node": ">=0.4.8" 49 | }, 50 | "files": [ 51 | "one-color.js", 52 | "one-color.js.map", 53 | "one-color-all.js", 54 | "one-color-all.js.map", 55 | "index.js", 56 | "minimal.js", 57 | "lib" 58 | ], 59 | "scripts": { 60 | "one-color-all": "rollup -c rollup.config.js index.js -o one-color-all.js", 61 | "one-color": "rollup -c rollup.config.js minimal.js -o one-color.js", 62 | "build": "npm run one-color && npm run one-color-all", 63 | "preversion": "npm run lint && npm run build && TEST_BUNDLES=true npm test && bash -c 'git add one-color{-all,}.js{,.map}'", 64 | "lint": "eslint . && prettier --check '**/*.{js,md}'", 65 | "test": "npm run lint && mocha", 66 | "test:documentation": "evaldown --validate --capture=console ./README.md", 67 | "coverage": "istanbul cover _mocha -- --reporter dot", 68 | "ci:test": "TEST_BUNDLES=true npm run coverage" 69 | }, 70 | "jspm": { 71 | "dependencies": {}, 72 | "main": "one-color-all.js", 73 | "jspmPackage": true 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // entry: 'index.js', 3 | 4 | plugins: [ 5 | require('@rollup/plugin-commonjs')(), 6 | require('rollup-plugin-terser').terser(), 7 | ], 8 | 9 | output: { 10 | format: 'umd', 11 | name: 'one.color', 12 | sourcemap: true, 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/colorcat/css/colorcat.css: -------------------------------------------------------------------------------- 1 | #colorCat { 2 | margin: 20px auto; 3 | width: 506px; 4 | background: url(../images/transparent.gif); 5 | } 6 | 7 | .colorcat { 8 | padding-bottom: 0 !important; 9 | } 10 | 11 | .colorcat fieldset { 12 | float: left; 13 | margin: 0 10px; 14 | padding: 0px 20px; 15 | } 16 | 17 | .colorcat label { 18 | text-align: right; 19 | padding-right: 20px; 20 | } 21 | 22 | .colorcat label:after { 23 | content: ':'; 24 | } 25 | 26 | .colorcat input { 27 | float: right; 28 | width: 200px; 29 | margin-top: 5px; 30 | } 31 | 32 | .colorcat .credits { 33 | text-align: center; 34 | clear: both; 35 | padding-top: 20px; 36 | } 37 | -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/colorcat/css/demo.css: -------------------------------------------------------------------------------- 1 | #colorCat { 2 | text-shadow: none; 3 | } 4 | 5 | #colorCat .skin { 6 | background-color: #a7a5aa; 7 | border: 5px solid #000000; 8 | } 9 | 10 | @-moz-keyframes toastBody { 11 | 0% { top: 0; } 12 | 89.99% { top: 0; } 13 | 90% { top: -5px; } 14 | 99.99% { top: -5px; } 15 | 100% { top: 0; } 16 | } 17 | 18 | @-webkit-keyframes toastBody { 19 | 0% { top: 0; } 20 | 89.99% { top: 0; } 21 | 90% { top: -5px; } 22 | 99.99% { top: -5px; } 23 | 100% { top: 0; } 24 | } 25 | 26 | #colorCat #toastBody { 27 | background-color:#fad695; 28 | width:100px; 29 | height: 70px; 30 | border: solid #000 5px; 31 | border-radius: 15px; 32 | padding: 2px; 33 | position:absolute; 34 | z-index:19; 35 | -moz-animation: toastBody 0.8s linear 0s infinite; 36 | -webkit-animation: toastBody 0.8s linear 0s infinite; 37 | } 38 | 39 | #colorCat #toastBody > div { 40 | width:100px; 41 | height:70px; 42 | border-radius: 30px; 43 | background-color: #fc9dff; 44 | display:block; 45 | color: #da3eb9; 46 | font-size: 40px; 47 | line-height: 10px; 48 | } 49 | 50 | /* -- head -- */ 51 | 52 | @-moz-keyframes wholeHead { 53 | 0% { top: -15px; left: 0;} 54 | 24.99% { top: -15px; left: 0;} 55 | 25% { top: -10px; left: 5px; } 56 | 49.99% { top: -10px; left:5px; } 57 | 50% { top: -5px; left: 0; } 58 | 74.99% { top: -5px; left: 0; } 59 | 75% { top: -10px; left: -5px; } 60 | 99.99% { top: -10px; left: -5px;} 61 | 100% { top: -15px; left: 0;} 62 | } 63 | 64 | @-webkit-keyframes wholeHead { 65 | 0% { top: -15px; left: 0;} 66 | 24.99% { top: -15px; left: 0;} 67 | 25% { top: -10px; left: 5px; } 68 | 49.99% { top: -10px; left:5px; } 69 | 50% { top: -5px; left: 0; } 70 | 74.99% { top: -5px; left: 0; } 71 | 75% { top: -10px; left: -5px; } 72 | 99.99% { top: -10px; left: -5px;} 73 | 100% { top: -15px; left: 0;} 74 | } 75 | 76 | #colorCat #wholeHead{ 77 | position:absolute; 78 | top: -15px; 79 | -moz-animation: wholeHead 0.4s linear 0s infinite; 80 | -webkit-animation: wholeHead 0.4s linear 0s infinite; 81 | } 82 | #colorCat #mainHead { 83 | width: 80px; 84 | height: 35px; 85 | border-bottom-right-radius: 15px; 86 | border-bottom-left-radius: 15px; 87 | position:absolute; 88 | z-index: 20; 89 | top: 48px; 90 | left: 60px; 91 | } 92 | 93 | #colorCat .ear { 94 | width: 30px; 95 | height: 20px; 96 | position: absolute; 97 | z-index: 21; 98 | left: 65px; 99 | top: 28px; 100 | border-bottom: none; 101 | border-top-right-radius: 25px; 102 | } 103 | 104 | #colorCat .rightEar { 105 | border-top-right-radius: 0; 106 | border-top-left-radius: 25px; 107 | left: 106px; 108 | } 109 | 110 | #colorCat .eye { 111 | width: 5px; 112 | height:5px; 113 | background-color: #fff; 114 | position: absolute; 115 | top:4px; 116 | left: 17px; 117 | z-index: 22; 118 | border-right: 5px solid #000; 119 | border-bottom: 5px solid #000; 120 | } 121 | 122 | #colorCat .rightEye { 123 | left: 56px; 124 | } 125 | 126 | #colorCat .nose { 127 | width:5px; 128 | height: 5px; 129 | background-color:#000; 130 | position:absolute; 131 | top:9px; 132 | left: 45px; 133 | } 134 | 135 | #colorCat .chick { 136 | width: 10px; 137 | height: 10px; 138 | background-color: #f7a4a3; 139 | position: absolute; 140 | top: 15px; 141 | left: 5px; 142 | } 143 | 144 | #colorCat .rightChick { 145 | left: 70px; 146 | } 147 | 148 | #colorCat .mouth { 149 | position: absolute; 150 | -moz-transform: scale(2, 0.7) rotate(-90deg); 151 | -webkit-transform: scale(2, 0.7) rotate(-90deg); 152 | font-family: Arial; 153 | font-size: 25px; 154 | font-weight: bold; 155 | top:5px; 156 | left:37px; 157 | color: #000; 158 | } 159 | 160 | /* -- tail -- */ 161 | 162 | @-moz-keyframes midTail { 163 | 0% { top: 52px;} 164 | 24.99% { top: 52px; } 165 | 25% { top: 56px;} 166 | 49.99% { top: 56px;} 167 | 50% { top: 60px;} 168 | 74.99% { top: 60px;} 169 | 75% { top: 56px;} 170 | 99.99% { top: 56px;} 171 | 100% { top: 52px;} 172 | } 173 | 174 | @-webkit-keyframes midTail { 175 | 0% { top: 52px;} 176 | 24.99% { top: 52px; } 177 | 25% { top: 56px;} 178 | 49.99% { top: 56px;} 179 | 50% { top: 60px;} 180 | 74.99% { top: 60px;} 181 | 75% { top: 56px;} 182 | 99.99% { top: 56px;} 183 | 100% { top: 52px;} 184 | } 185 | 186 | @-moz-keyframes backTail { 187 | 0% { top: 48px;} 188 | 12.49% { top: 48px; } 189 | 12.50% { top: 52px;} 190 | 24.99% { top: 52px;} 191 | 25% { top: 56px;} 192 | 37.49% { top: 56px;} 193 | 37.5% { top: 60px; } 194 | 49.99% { top: 60px; } 195 | 50% { top: 64px; } 196 | 62.49% { top: 64px; } 197 | 62.5% { top: 60px; } 198 | 74.99% { top: 60px; } 199 | 75% { top: 56px;} 200 | 87.49% { top: 56px;} 201 | 87.5% { top: 52px;} 202 | 99.99% { top: 52px;} 203 | 100% { top: 48px;} 204 | } 205 | 206 | @-webkit-keyframes backTail { 207 | 0% { top: 48px;} 208 | 12.49% { top: 48px; } 209 | 12.50% { top: 52px;} 210 | 24.99% { top: 52px;} 211 | 25% { top: 56px;} 212 | 37.49% { top: 56px;} 213 | 37.5% { top: 60px; } 214 | 49.99% { top: 60px; } 215 | 50% { top: 64px; } 216 | 62.49% { top: 64px; } 217 | 62.5% { top: 60px; } 218 | 74.99% { top: 60px; } 219 | 75% { top: 56px;} 220 | 87.49% { top: 56px;} 221 | 87.5% { top: 52px;} 222 | 99.99% { top: 52px;} 223 | 100% { top: 48px;} 224 | } 225 | 226 | #colorCat #wholeTail { 227 | top: -15px; 228 | position:absolute; 229 | } 230 | 231 | #colorCat .tail { 232 | width: 10px; 233 | height: 10px; 234 | position: absolute; 235 | left: -15px; 236 | top: 56px; 237 | z-index: 18; 238 | } 239 | 240 | #colorCat .middleTail { 241 | left: -25px; 242 | z-index:19; 243 | border-right: none; 244 | top: 52px; 245 | -moz-animation: midTail 0.4s linear 0s infinite; 246 | -webkit-animation: midTail 0.4s linear 0s infinite; 247 | } 248 | 249 | #colorCat .backTail { 250 | left: -35px; 251 | z-index:19; 252 | border-right: none; 253 | top: 48px; 254 | -moz-animation: backTail 0.4s linear 0s infinite; 255 | -webkit-animation: backTail 0.4s linear 0s infinite; 256 | } 257 | 258 | /* -- legs -- */ 259 | @-moz-keyframes letsDanceBeeAch { 260 | 0% { top: 0px; left: 0;} 261 | 24.99% { top: 0px; left: 0;} 262 | 25% { top: 5px; left: 5px; } 263 | 49.99% { top: 5px; left:5px; } 264 | 50% { top: 10px; left: 0; } 265 | 74.99% { top: 10px; left: 0; } 266 | 75% { top: 5px; left: -5px; } 267 | 99.99% { top: 5px; left: -5px;} 268 | 100% { top: 0px; left: 0;} 269 | } 270 | 271 | @-webkit-keyframes letsDanceBeeAch { 272 | 0% { top: 0px; left: 0;} 273 | 24.99% { top: 0px; left: 0;} 274 | 25% { top: 5px; left: 5px; } 275 | 49.99% { top: 5px; left:5px; } 276 | 50% { top: 10px; left: 0; } 277 | 74.99% { top: 10px; left: 0; } 278 | 75% { top: 5px; left: -5px; } 279 | 99.99% { top: 5px; left: -5px;} 280 | 100% { top: 0px; left: 0;} 281 | } 282 | 283 | #colorCat #allYourLegAreBelongToUs { 284 | position: absolute; 285 | top: 10px; 286 | -moz-animation: letsDanceBeeAch 0.2s linear 0s infinite; 287 | -webkit-animation: letsDanceBeeAch 0.2s linear 0s infinite; 288 | } 289 | #colorCat .leg { 290 | width:10px; 291 | height:20px; 292 | position:absolute; 293 | z-index: 18; 294 | top: 64px; 295 | left:5px; 296 | } 297 | 298 | #colorCat .back { 299 | -moz-transform: rotate(40deg); 300 | -webkit-transform: rotate(40deg); 301 | } 302 | 303 | #colorCat .leftBack { 304 | left: 35px; 305 | } 306 | 307 | #colorCat .front { 308 | -moz-transform: rotate(-40deg); 309 | -webkit-transform: rotate(-40deg); 310 | left:100px; 311 | } 312 | 313 | #colorCat .leftFront { 314 | left: 70px; 315 | } 316 | 317 | /* -- RAINBOW -- */ 318 | @-moz-keyframes rainbow1 { 319 | 0% { top: 0; } 320 | 49.99% { top: 0; } 321 | 50% { top: 5px; } 322 | 99.99% { top: 5px; } 323 | 100% { top: 0; } 324 | } 325 | 326 | @-webkit-keyframes rainbow1 { 327 | 0% { top: 0; } 328 | 49.99% { top: 0; } 329 | 50% { top: 5px; } 330 | 99.99% { top: 5px; } 331 | 100% { top: 0; } 332 | } 333 | 334 | @-moz-keyframes rainbow2 { 335 | 0% { top: 5px; } 336 | 49.99% { top: 5px; } 337 | 50% { top: 0; } 338 | 99.99% { top: 0; } 339 | 100% { top: 5px; } 340 | } 341 | 342 | @-webkit-keyframes rainbow2 { 343 | 0% { top: 5px; } 344 | 49.99% { top: 5px; } 345 | 50% { top: 0; } 346 | 99.99% { top: 0; } 347 | 100% { top: 5px; } 348 | } 349 | 350 | #colorCat .rainbow { 351 | position:absolute; 352 | width:45px; 353 | height:90px; 354 | background: -moz-linear-gradient(top, #d91a12 15%, #e13300 15%, #ff7f14 16%, #f2ab03 32%, #ebc000 32%, #fade00 33%, #efff03 48%, #56fc02 49%, #52ff01 66%, #4ade7e 67%, #3baaf2 67%, #3baaf2 84%, #7337f7 84%, #6b40f2 100%); /* FF3.6+ */ 355 | background: -webkit-gradient(linear, left top, left bottom, color-stop(15%,#d91a12), color-stop(15%,#e13300), color-stop(16%,#ff7f14), color-stop(32%,#f2ab03), color-stop(32%,#ebc000), color-stop(33%,#fade00), color-stop(48%,#efff03), color-stop(49%,#56fc02), color-stop(66%,#52ff01), color-stop(67%,#4ade7e), color-stop(67%,#3baaf2), color-stop(84%,#3baaf2), color-stop(84%,#7337f7), color-stop(100%,#6b40f2)); /* Chrome,Safari4+ */ 356 | background: -webkit-linear-gradient(top, #d91a12 15%,#e13300 15%,#ff7f14 16%,#f2ab03 32%,#ebc000 32%,#fade00 33%,#efff03 48%,#56fc02 49%,#52ff01 66%,#4ade7e 67%,#3baaf2 67%,#3baaf2 84%,#7337f7 84%,#6b40f2 100%); /* Chrome10+,Safari5.1+ */ 357 | left: -40px; 358 | -moz-animation: rainbow1 0.3s linear 0s infinite; 359 | -webkit-animation: rainbow1 0.3s linear 0s infinite; 360 | z-index: 15; 361 | } 362 | #colorCat .r2 { 363 | left: -85px; 364 | top: 5px; 365 | -moz-animation-name: rainbow2; 366 | -webkit-animation-name: rainbow2; 367 | } 368 | 369 | #colorCat .r3 { 370 | left: -130px; 371 | } 372 | 373 | #colorCat .r4 { 374 | left: -175px; 375 | top: 5px; 376 | -moz-animation-name: rainbow2; 377 | -webkit-animation-name: rainbow2; 378 | } 379 | 380 | /* -- stars -- */ 381 | 382 | @-moz-keyframes star1 { 383 | 0% { top: 0; height: 5px;} 384 | 33.19% { top: 0; height: 5px; } 385 | 33.2% { height:10px; top:0; } 386 | 49.79% { height:10px; top:0; } 387 | 49.8% { height:10px; top:5px; } 388 | 66.39% {height:10px; top:5px; } 389 | 66.4% { height:5px; top:10px;} 390 | 82.99% { height:5px; top:10px;} 391 | 83% { height: 5px; top: 15px; } 392 | 99.99% { height: 5px; top: 15px; } 393 | 100% { top: 0; height: 5px; } 394 | } 395 | 396 | @-webkit-keyframes star1{ 397 | 0% { top: 0; height: 5px;} 398 | 33.19% { top: 0; height: 5px; } 399 | 33.2% { height:10px; top:0; } 400 | 49.79% { height:10px; top:0; } 401 | 49.8% { height:10px; top:5px; } 402 | 66.39% {height:10px; top:5px; } 403 | 66.4% { height:5px; top:10px;} 404 | 82.99% { height:5px; top:10px;} 405 | 83% { height: 5px; top: 15px; } 406 | 99.99% { height: 5px; top: 15px; } 407 | 100% { top: 0; height: 5px; } 408 | } 409 | 410 | @-moz-keyframes star2-3-6-7 { 411 | 0% { visibility: hidden; } 412 | 16.59% { visibility: hidden; } 413 | 16.6% { visibility: visible; } 414 | 33.19% { visibility: visible; } 415 | 33.2% { visibility: hidden; } 416 | 100% { visibility: hidden; } 417 | } 418 | 419 | @-webkit-keyframes star2-3-6-7{ 420 | 0% { visibility: hidden; } 421 | 16.59% { visibility: hidden; } 422 | 16.6% { visibility: visible; } 423 | 33.19% { visibility: visible; } 424 | 33.2% { visibility: hidden; } 425 | 100% { visibility: hidden; } 426 | } 427 | 428 | @-moz-keyframes star4 { 429 | 0% { left: 0; width: 5px; visibility: visible;} 430 | 33.19% { left: 0; width: 5px; } 431 | 33.2% { width:10px; left:0; } 432 | 49.79% { width:10px; left:0; } 433 | 49.8% { width:10px; left:5px; } 434 | 66.39% {width:10px; left:5px; } 435 | 66.4% { width:5px; left:10px;} 436 | 82.99% { width:5px; left:10px;} 437 | 83% { width: 5px; left: 15px; visibility:hidden;} 438 | 99.99% { width: 5px; left: 15px; visibility:hidden;} 439 | 100% { left: 0; width: 5px; visibility:hidden;} 440 | } 441 | 442 | @-webkit-keyframes star4 { 443 | 0% { left: 0; width: 5px; visibility: visible;} 444 | 33.19% { left: 0; width: 5px; } 445 | 33.2% { width:10px; left:0; } 446 | 49.79% { width:10px; left:0; } 447 | 49.8% { width:10px; left:5px; } 448 | 66.39% {width:10px; left:5px; } 449 | 66.4% { width:5px; left:10px;} 450 | 82.99% { width:5px; left:10px;} 451 | 83% { width: 5px; left: 15px; visibility:hidden;} 452 | 99.99% { width: 5px; left: 15px; visibility:hidden;} 453 | 100% { left: 0; width: 5px; visibility:hidden;} 454 | } 455 | 456 | @-moz-keyframes star5 { 457 | 0% { left: 38px; width: 5px; visibility: visible;} 458 | 33.19% { left: 38px; width: 5px; } 459 | 33.2% { width:10px; left:33px; } 460 | 49.79% { width:10px; left:33px; } 461 | 49.8% { width:10px; left:28px; } 462 | 66.39% {width:10px; left:28px; } 463 | 66.4% { width:5px; left:28px;} 464 | 82.99% { width:5px; left:28px;} 465 | 83% { width: 5px; left: 15px; visibility:hidden;} 466 | 99.99% { width: 5px; left: 15px; visibility:hidden;} 467 | 100% { left: 0; width: 5px; visibility:hidden;} 468 | } 469 | 470 | @-webkit-keyframes star5 { 471 | 0% { left: 38px; width: 5px; visibility: visible;} 472 | 33.19% { left: 38px; width: 5px; } 473 | 33.2% { width:10px; left:33px; } 474 | 49.79% { width:10px; left:33px; } 475 | 49.8% { width:10px; left:28px; } 476 | 66.39% {width:10px; left:28px; } 477 | 66.4% { width:5px; left:28px;} 478 | 82.99% { width:5px; left:28px;} 479 | 83% { width: 5px; left: 15px; visibility:hidden;} 480 | 99.99% { width: 5px; left: 15px; visibility:hidden;} 481 | 100% { left: 0; width: 5px; visibility:hidden;} 482 | } 483 | 484 | @-moz-keyframes star8 { 485 | 0% { top: 32px; height: 5px; visibility:visible;} 486 | 33.19% { top: 32px; height: 5px; } 487 | 33.2% { height:10px; top:28px; } 488 | 49.79% { height:10px; top:28px; } 489 | 49.8% { height:10px; top:23px; } 490 | 66.39% {height:10px; top:23px; } 491 | 66.4% { height:5px; top:18px;} 492 | 82.99% { height:5px; top:18px;} 493 | 83% { height: 5px; top: 15px; visibility:hidden;} 494 | 99.99% { height: 5px; top: 15px; visibility:hidden;} 495 | 100% { top: 0; height: 5px; visibility:hidden;} 496 | } 497 | 498 | @-webkit-keyframes star8 { 499 | 0% { top: 32px; height: 5px; visibility:visible;} 500 | 33.19% { top: 32px; height: 5px; } 501 | 33.2% { height:10px; top:28px; } 502 | 49.79% { height:10px; top:28px; } 503 | 49.8% { height:10px; top:23px; } 504 | 66.39% {height:10px; top:23px; } 505 | 66.4% { height:5px; top:18px;} 506 | 82.99% { height:5px; top:18px;} 507 | 83% { height: 5px; top: 15px; visibility:hidden;} 508 | 99.99% { height: 5px; top: 15px; visibility:hidden;} 509 | 100% { top: 0; height: 5px; visibility:hidden;} 510 | } 511 | 512 | 513 | #colorCat .star { 514 | position: absolute; 515 | width: 40px; 516 | height: 40px; 517 | z-index: 10; 518 | } 519 | 520 | #colorCat .star div { 521 | width: 5px; 522 | height: 5px; 523 | background-color: #fff; 524 | position: absolute; 525 | -moz-animation: star1 0.4s linear 0s infinite; 526 | -webkit-animation: star1 0.4s linear 0s infinite; 527 | } 528 | 529 | #colorCat .star div[number="1"] { 530 | left: 18px; 531 | top: 0; 532 | } 533 | 534 | #colorCat .star div[number="2"] { 535 | left: 8px; 536 | top: 6px; 537 | visibility: hidden; 538 | -moz-animation-name: star2-3-6-7; 539 | -webkit-animation-name: star2-3-6-7; 540 | } 541 | 542 | #colorCat .star div[number="3"] { 543 | left: 30px; 544 | top: 6px; 545 | visibility: hidden; 546 | -moz-animation-name: star2-3-6-7; 547 | -webkit-animation-name: star2-3-6-7; 548 | } 549 | 550 | #colorCat .star div[number="4"] { 551 | left: 0px; 552 | top: 16px; 553 | -moz-animation-name: star4; 554 | -webkit-animation-name: star4; 555 | } 556 | 557 | #colorCat .star div[number="5"] { 558 | left: 38px; 559 | top: 16px; 560 | -moz-animation-name: star5; 561 | -webkit-animation-name: star5; 562 | } 563 | 564 | #colorCat .star div[number="6"] { 565 | left: 8px; 566 | top: 26px; 567 | visibility: hidden; 568 | -moz-animation-name: star2-3-6-7; 569 | -webkit-animation-name: star2-3-6-7; 570 | } 571 | 572 | #colorCat .star div[number="7"] { 573 | left: 30px; 574 | top: 26px; 575 | visibility: hidden; 576 | -moz-animation-name: star2-3-6-7; 577 | -webkit-animation-name: star2-3-6-7; 578 | } 579 | 580 | #colorCat .star div[number="8"] { 581 | left: 18px; 582 | top: 32px; 583 | -moz-animation-name: star8; 584 | -webkit-animation-name: star8; 585 | } 586 | 587 | @-moz-keyframes starMovement1 { 588 | 0% { top: 80px; left: 600px} 589 | 100% { top: 80px; left: 0px;} 590 | } 591 | 592 | @-webkit-keyframes starMovement1 { 593 | 0% { top: 80px; left: 600px} 594 | 100% { top: 80px; left: 0px;} 595 | } 596 | 597 | #colorCat .starMovement1 { 598 | -moz-animation: starMovement1 3s linear 0s infinite; 599 | -webkit-animation: starMovement1 3s linear 0s infinite; 600 | } 601 | 602 | @-moz-keyframes starMovement2 { 603 | 0% { top: -10px; left: 800px} 604 | 100% { top: -10px; left: -100px;} 605 | } 606 | 607 | @-webkit-keyframes starMovement2{ 608 | 0% { top: -10px; left: 800px} 609 | 100% { top: -10px; left: -100px;} 610 | } 611 | 612 | #colorCat .starMovement2 { 613 | -moz-animation: starMovement2 4.5s linear 0s infinite; 614 | -webkit-animation: starMovement2 4.5s linear 0s infinite; 615 | } 616 | 617 | @-moz-keyframes starMovement3 { 618 | 0% { top: 270px; left: 728px} 619 | 100% { top: 270px; left: -172px;} 620 | } 621 | 622 | @-webkit-keyframes starMovement3 { 623 | 0% { top: 270px; left: 728px} 624 | 100% { top: 270px; left: -172px;} 625 | } 626 | 627 | #colorCat .starMovement3 { 628 | -moz-animation: starMovement3 4.5s linear 0s infinite; 629 | -webkit-animation: starMovement3 4.5s linear 0s infinite; 630 | } 631 | 632 | @-moz-keyframes starMovement4 { 633 | 0% { top: 160px; left: 2300px} 634 | 100% { top: 160px; left: -100px;} 635 | } 636 | 637 | @-webkit-keyframes starMovement4 { 638 | 0% { top: 160px; left: 2300px} 639 | 100% { top: 160px; left: -100px;} 640 | } 641 | 642 | .starMovement4 { 643 | -moz-animation: starMovement4 12s linear 0s infinite; 644 | -webkit-animation: starMovement4 12s linear 0s infinite; 645 | } 646 | 647 | @-moz-keyframes starMovement5 { 648 | 0% { top: 130px; left: 1100px} 649 | 100% { top: 130px; left: -100px;} 650 | } 651 | 652 | @-webkit-keyframes starMovement5 { 653 | 0% { top: 130px; left: 1100px} 654 | 100% { top: 130px; left: -100px;} 655 | } 656 | 657 | #colorCat .starMovement5 { 658 | -moz-animation: starMovement5 6s linear 0s infinite; 659 | -webkit-animation: starMovement5 6s linear 0s infinite; 660 | } 661 | /* -- rest -- */ 662 | 663 | #colorCat #nyanCat { 664 | position:absolute; 665 | left:150px; 666 | top: 100px; 667 | } 668 | 669 | #colorCat #mainContainer { 670 | position:relative; 671 | width:500px; 672 | height:300px; 673 | border: solid #fff 3px; 674 | overflow:hidden; 675 | background-color: #1C4170; 676 | margin: 0 auto; 677 | } 678 | -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/colorcat/images/transparent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/colorcat/images/transparent.gif -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/colorcat/js/colorcat.js: -------------------------------------------------------------------------------- 1 | window.onload = function () { 2 | var backgrounds = [ 3 | 'background-color', 4 | 'background-image' 5 | ]; 6 | var directions = [ 7 | 'top', 8 | 'right', 9 | 'bottom', 10 | 'left' 11 | ]; 12 | var colorElements = []; 13 | var traverse = function (el, fn) { 14 | fn(el); 15 | for (var i = 0; i < el.childNodes.length; i += 1) { 16 | if (el.childNodes[i].nodeType === 1) { 17 | traverse(el.childNodes[i], fn); 18 | } 19 | } 20 | }; 21 | var registerColor = function (el) { 22 | var cs = getComputedStyle(el), 23 | styles = [], 24 | match = false; 25 | 26 | var color = cs.getPropertyCSSValue('color').cssText; 27 | if (color !== 'rgb(255, 255, 255)') { 28 | styles.push({ 29 | property: 'color', 30 | value: one.color.parse(color) 31 | }); 32 | } 33 | 34 | backgrounds.forEach(function (prop) { 35 | var val = cs.getPropertyCSSValue(prop).cssText; 36 | if (val !== 'none' && val !== 'rgba(0, 0, 0, 0)') { 37 | var color = one.color.parse(val); 38 | if (color) { 39 | styles.push({ 40 | property: prop, 41 | value: one.color.parse(val) 42 | }); 43 | } else { 44 | var colorStrings = val.match(/rgba?\([^\(]+?\)/g), 45 | colors = colorStrings.map(function (rgbaStr) { 46 | return one.color.parse(rgbaStr); 47 | }); 48 | 49 | for (var i = 0; i < colorStrings.length; i+=1) { 50 | val = val.replace(colorStrings[i], '[' + i + ']'); 51 | } 52 | 53 | styles.push({ 54 | property: prop, 55 | value: { 56 | tpl: val, 57 | colors: colors 58 | } 59 | }); 60 | } 61 | } 62 | }); 63 | directions.forEach(function (dir) { 64 | var val = cs.getPropertyCSSValue('border-' + dir + '-width').cssText; 65 | if (val !== '0px') { 66 | styles.push({ 67 | property: 'border-' + dir + '-color', 68 | value: one.color.parse(cs.getPropertyCSSValue('border-' + dir + '-color').cssText) 69 | }); 70 | } 71 | }); 72 | 73 | if (styles.length) { 74 | colorElements.push({ 75 | el: el, 76 | styles: styles 77 | }); 78 | } 79 | }; 80 | 81 | var colorize = function (fn) { 82 | colorElements.forEach(function (item) { 83 | item.styles.forEach(function (style) { 84 | if (style.value.isColor) { 85 | item.el.style[style.property] = fn(style.value).toCSSWithAlpha(); 86 | } else if (style.value.colors) { 87 | var val = style.value.tpl; 88 | style.value.colors.forEach(function (color, idx) { 89 | val = val.replace('[' + idx + ']', fn(color).toCSSWithAlpha()); 90 | }); 91 | item.el.style[style.property] = val; 92 | } 93 | }); 94 | }); 95 | }; 96 | 97 | traverse(document.getElementById('mainContainer'), registerColor); 98 | colorElements.forEach(function (item) { 99 | item.styles.map(function (style) { 100 | style.property = style.property.replace(/-(\w)/g, function (str, p1) { 101 | return p1.toUpperCase(); 102 | }); 103 | return style; 104 | }); 105 | }); 106 | 107 | var channels = [ 108 | 'Red', 109 | 'Green', 110 | 'Blue', 111 | 'Hue', 112 | 'Saturation', 113 | 'Value', 114 | 'Cyan', 115 | 'Magenta', 116 | 'Yellow', 117 | 'Black', 118 | 'Alpha' 119 | ]; 120 | var handler = function (e) { 121 | colorize(function (color) { 122 | inputs.forEach(function (input) { 123 | var val = parseFloat(input.value); 124 | 125 | color = color[(input.name === 'Alpha' ? 'set' : 'adjust') + input.name](val); 126 | }); 127 | return color; 128 | }); 129 | }; 130 | var inputs = channels.map(function (channel) { 131 | var input = document.getElementById(channel); 132 | input.onchange = handler; 133 | return input; 134 | }); 135 | }; -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/colorcat/js/one-color-debug.js: -------------------------------------------------------------------------------- 1 | /*global window*/ 2 | 3 | /** 4 | * @namespace one One.com global JavaScript namespace. 5 | * @exports window.one as one 6 | */ 7 | if (typeof window !== 'undefined') { 8 | window.one = window.one || {}; 9 | } else { 10 | var one = {}; 11 | } 12 | 13 | one.include = one.exclude = function () {}; // Ignore these in development mode 14 | 15 | /*global one*/ 16 | 17 | /** 18 | * @namespace one.color 19 | */ 20 | one.color = one.color || {}; 21 | 22 | (function () { 23 | /** @exports stringPrototype as String.prototype*/ 24 | var stringPrototype = String.prototype; 25 | 26 | /** 27 | *

Returns this string with the char at first position in uppercase.

28 | *

Example of use:


  29 |     "the brown Fox jumped over the lazy Dog".capitalize(); // = "The brown Fox jumped over the lazy Dog"
  30 |     
31 | * @return capitalized string. 32 | * @memberOf String.prototype 33 | */ 34 | stringPrototype.capitalize = function () { 35 | return this.charAt(0).toUpperCase() + this.substring(1); 36 | }; 37 | }()); 38 | 39 | /*global one*/ 40 | 41 | /*jslint evil:true*/ 42 | 43 | one.color.installedColorSpaces = []; 44 | 45 | one.color.installColorSpace = function (colorSpaceName, propertyDefinitions, config) { 46 | var propertyNames = propertyDefinitions.map(function (propertyDefinition) { 47 | return propertyDefinition.match(/[A-Z]/)[0].toLowerCase(); 48 | }), 49 | longPropertyNames = propertyDefinitions.map(function (propertyDefinition) { 50 | return propertyDefinition.toLowerCase().capitalize(); 51 | }), 52 | Constructor = one.color[colorSpaceName] = new Function(propertyNames.join(","), 53 | // Allow passing an array to the constructor: 54 | "if (Object.prototype.toString.apply(" + propertyNames[0] + ") === '[object Array]') {" + 55 | propertyNames.map(function (propertyName, i) { 56 | return propertyName + "=" + propertyNames[0] + "[" + i + "];"; 57 | }).reverse().join("") + 58 | "}" + 59 | "if (" + propertyNames.filter(function (propertyName) { 60 | return propertyName !== 'a'; 61 | }).map(function (propertyName) { 62 | return "isNaN(" + propertyName + ")"; 63 | }).join("||") + "){" + "throw \"[one.color." + colorSpaceName + "]: Invalid color: (\"+" + propertyNames.join("+\",\"+") + "+\")\";}" + 64 | propertyNames.map(function (propertyName) { 65 | if (propertyName === 'h') { 66 | return "this.h=h<0?h-Math.floor(h):h%1"; // Wrap 67 | } else if (propertyName === 'a') { 68 | return "this.a=(isNaN(a)||a>1)?1:(a<0?0:a);"; 69 | } else { 70 | return "this." + propertyName + "=" + propertyName + "<0?0:(" + propertyName + ">1?1:" + propertyName + ")"; 71 | } 72 | }).join(";") + ";" 73 | ), 74 | prototype = Constructor.prototype; 75 | 76 | Constructor.propertyNames = propertyNames; 77 | Constructor.longPropertyNames = longPropertyNames; 78 | 79 | ['valueOf', 'toHex', 'toCSS', 'toCSSWithAlpha'].forEach(function (methodName) { 80 | prototype[methodName] = prototype[methodName] || (colorSpaceName === 'RGB' ? prototype.toHex : new Function("return this.toRGB()." + methodName + "();")); 81 | }); 82 | 83 | prototype.isColor = true; 84 | 85 | prototype.equals = function (otherColor, epsilon) { 86 | if (typeof epsilon === 'undefined') { 87 | epsilon = 1e-10; 88 | } 89 | 90 | otherColor = otherColor['to' + colorSpaceName](); 91 | 92 | for (var i = 0; i < propertyNames.length; i = i + 1) { 93 | if (Math.abs(this[propertyNames[i]] - otherColor[propertyNames[i]]) > epsilon) { 94 | return false; 95 | } 96 | } 97 | 98 | return true; 99 | }; 100 | 101 | prototype.toJSON = new Function( 102 | "return ['" + colorSpaceName + "', " + 103 | propertyNames.map(function (propertyName) { 104 | return "this." + propertyName; 105 | }, this).join(", ") + 106 | "];" 107 | ); 108 | 109 | if (config.fromRGB) { 110 | one.color.RGB.prototype['to' + colorSpaceName] = config.fromRGB; 111 | delete config.fromRGB; 112 | } 113 | for (var prop in config) { 114 | if (config.hasOwnProperty(prop)) { 115 | prototype[prop] = config[prop]; 116 | } 117 | } 118 | 119 | // It is pretty easy to implement the conversion to the same color space: 120 | prototype['to' + colorSpaceName] = function () { 121 | return this; 122 | }; 123 | prototype.toString = new Function("return \"[one.color." + colorSpaceName + ":\"+" + propertyNames.map(function (propertyName, i) { 124 | return "\" " + longPropertyNames[i] + "=\"+this." + propertyName; 125 | }).join("+") + "+\"]\";"); 126 | 127 | // Generate getters and setters 128 | propertyNames.forEach(function (propertyName, i) { 129 | var longPropertyName = longPropertyNames[i]; 130 | prototype['get' + longPropertyName] = new Function("return this." + propertyName + ";"); 131 | prototype['set' + longPropertyName] = new Function("newValue", "return new this.constructor(" + propertyNames.map(function (otherPropertyName, i) { 132 | return propertyName === otherPropertyName ? "newValue" : "this." + otherPropertyName; 133 | }).join(", ") + ");"); 134 | prototype['adjust' + longPropertyName] = new Function("delta", "return new this.constructor(" + propertyNames.map(function (otherPropertyName, i) { 135 | return "this." + otherPropertyName + (propertyName === otherPropertyName ? "+delta" : ""); 136 | }).join(", ") + ");"); 137 | }); 138 | 139 | function installForeignMethods(targetColorSpaceName, sourceColorSpaceName) { 140 | var obj = {}; 141 | obj['to' + sourceColorSpaceName] = new Function("return this.toRGB().to" + sourceColorSpaceName + "();"); // Fallback 142 | one.color[sourceColorSpaceName].propertyNames.forEach(function (property, i) { 143 | var longPropertyName = one.color[sourceColorSpaceName].longPropertyNames[i]; 144 | obj['get' + longPropertyName] = new Function("return this.to" + sourceColorSpaceName + "().get" + longPropertyName + "();"); 145 | obj['set' + longPropertyName] = new Function("newValue", "return this.to" + sourceColorSpaceName + "().set" + longPropertyName + "(newValue);"); 146 | obj['adjust' + longPropertyName] = new Function("delta", "return this.to" + sourceColorSpaceName + "().adjust" + longPropertyName + "(delta);"); 147 | }); 148 | for (var prop in obj) { 149 | if (obj.hasOwnProperty(prop) && one.color[targetColorSpaceName].prototype[prop] === undefined) { 150 | one.color[targetColorSpaceName].prototype[prop] = obj[prop]; 151 | } 152 | } 153 | } 154 | 155 | one.color.installedColorSpaces.forEach(function (otherColorSpaceName) { 156 | installForeignMethods(colorSpaceName, otherColorSpaceName); 157 | installForeignMethods(otherColorSpaceName, colorSpaceName); 158 | }); 159 | 160 | one.color.installedColorSpaces.push(colorSpaceName); 161 | }; 162 | 163 | /*global one*/ 164 | 165 | 166 | /** 167 | * @name one.color.RGB 168 | * @class 169 | *

A color in the RGB colorspace with an optional alpha value.

170 | *

one.color.(RGB|HSL|HSV|CMYK) objects are designed to be 171 | * immutable; all the conversion, set, and adjust methods return new 172 | * objects.

173 | *

one.color.(RGB|HSL|HSV|CMYK) objects automatically get the set 174 | * and adjust methods from all other installed colorspaces, so 175 | * although you can use the explicit conversion methods ({@link 176 | * one.color.RGB#toHSL}, {@link one.color.RGB#toCMYK}...), the below 177 | * will work just fine:


 178 | 
 179 | new one.color.RGB(.4, .3, .9).
 180 |     adjustLightness(+.2). // Implicit conversion to HSL
 181 |     setRed(-.1). // Implicit conversion back to RGB
 182 |     toHex(); // "#00a6f2"
 183 | 
184 | * 185 | * @constructor 186 | * Create a new one.color.RGB object. Values outside the supported 187 | * range, [0..1], will be adjusted automatically. 188 | * @param {Number} r The red component, range: [0..1] 189 | * @param {Number} g The green component, range: [0..1] 190 | * @param {Number} b The blue component, range: [0..1] 191 | * @param {Number} [a] The alpha value, range: [0..1], 192 | * defaults to 1 193 | */ 194 | 195 | one.color.installColorSpace('RGB', ['Red', 'Green', 'Blue', 'Alpha'], { 196 | /** 197 | * Get the standard RGB hex representation of the color. 198 | * @return {String} The hex string, e.g. "#f681df" 199 | */ 200 | toHex: function () { 201 | var hexString = (Math.round(255 * this.r) * 0x10000 + Math.round(255 * this.g) * 0x100 + Math.round(255 * this.b)).toString(16); 202 | return '#' + ('00000'.substr(0, 6 - hexString.length)) + hexString; 203 | }, 204 | 205 | /** 206 | * Get a valid CSS color representation of the color without an 207 | * alpha value. 208 | * @return {String} The CSS color string, e.g. "rgb(123, 2, 202)" 209 | */ 210 | toCSS: function () { 211 | return "rgb(" + Math.round(255 * this.r) + "," + Math.round(255 * this.g) + "," + Math.round(255 * this.b) + ")"; 212 | }, 213 | 214 | /** 215 | * Get a valid CSS color representation of the color, including 216 | * the alpha value. 217 | * @return {String} The CSS color string, e.g. "rgba(123, 2, 202, 0.253)" 218 | */ 219 | toCSSWithAlpha: function () { 220 | return "rgba(" + Math.round(255 * this.r) + "," + Math.round(255 * this.g) + "," + Math.round(255 * this.b) + "," + this.a + ")"; 221 | } 222 | }); 223 | 224 | /** 225 | * @name one.color.RGB.prototype.r 226 | * @property 227 | * @type Number 228 | * @description The red component, range: [0..1] 229 | */ 230 | 231 | /** 232 | * @name one.color.RGB.prototype.g 233 | * @property 234 | * @type Number 235 | * @description The green component, range: [0..1] 236 | */ 237 | 238 | /** 239 | * @name one.color.RGB.prototype.b 240 | * @property 241 | * @type Number 242 | * @description The blue component, range: [0..1] 243 | */ 244 | 245 | /** 246 | * @name one.color.RGB.prototype.a 247 | * @property 248 | * @type Number 249 | * @description The alpha value, range: [0..1] 250 | */ 251 | 252 | /** 253 | * @name one.color.RGB.prototype.setRed 254 | * @function 255 | * @param {Number} r The new red component, range: [0..1] 256 | * @return {one.color.RGB} New color object with the changed value. 257 | */ 258 | 259 | /** 260 | * @name one.color.RGB.prototype.setGreen 261 | * @function 262 | * @param {Number} g The new green component, range: [0..1] 263 | * @return {one.color.RGB} New color object with the changed value. 264 | */ 265 | 266 | /** 267 | * @name one.color.RGB.prototype.setBlue 268 | * @function 269 | * @param {Number} b The new blue component, range: [0..1] 270 | * @return {one.color.RGB} New color object with the changed value. 271 | */ 272 | 273 | /** 274 | * @name one.color.RGB.prototype.setAlpha 275 | * @function 276 | * @param {Number} a The new alpha value, range: [0..1] 277 | * @return {one.color.RGB} New color object with the changed value. 278 | */ 279 | 280 | /** 281 | * @name one.color.RGB.prototype.adjustRed 282 | * @function 283 | * @param {Number} r The value to add to the red component. If the resulting 284 | * value falls outside the supported range, [0..1], it will be 285 | * adjusted automatically. 286 | * @return {one.color.RGB} New color object with the changed value. 287 | */ 288 | 289 | /** 290 | * @name one.color.RGB.prototype.adjustGreen 291 | * @function 292 | * @param {Number} g The value to add to the green component. If the resulting 293 | * value falls outside the supported range, [0..1], it will be 294 | * adjusted automatically. 295 | * @return {one.color.RGB} New color object with the changed value. 296 | */ 297 | 298 | /** 299 | * @name one.color.RGB.prototype.adjustBlue 300 | * @function 301 | * @param {Number} b The value to add to the blue component. If the resulting 302 | * value falls outside the supported range, [0..1], it will be 303 | * adjusted automatically. 304 | * @return {one.color.RGB} New color object with the changed value. 305 | */ 306 | 307 | /** 308 | * @name one.color.RGB.prototype.adjustAlpha 309 | * @function 310 | * @param {Number} a The value to add to the alpha value. If the resulting 311 | * value falls outside the supported range, [0..1], it will be 312 | * adjusted automatically. 313 | * @return {one.color.RGB} New color object with the changed value. 314 | */ 315 | 316 | /** 317 | * @name one.color.RGB.prototype.toJSON 318 | * @description Convert the color to a JSON representation. 319 | * @function 320 | * @return {Array} 321 | */ 322 | 323 | /** 324 | * @name one.color.RGB.prototype.toRGB 325 | * @description Convert the color to a {@link one.color.RGB} object, ie. return the 326 | * object itself. 327 | * @function 328 | * @return {one.color.RGB} 329 | */ 330 | 331 | /** 332 | * @name one.color.RGB.prototype.toHSV 333 | * @description Convert the color to a {@link one.color.HSV} object. 334 | * @function 335 | * @requires one.color.HSV 336 | * @return {one.color.HSV} 337 | */ 338 | 339 | /** 340 | * @name one.color.RGB.prototype.toHSL 341 | * @description Convert the color to a {@link one.color.HSL} object. 342 | * @function 343 | * @requires one.color.HSL 344 | * @return {one.color.HSL} 345 | */ 346 | 347 | /** 348 | * @name one.color.RGB.prototype.toCMYK 349 | * @description Convert the color to a {@link one.color.CMYK} object. 350 | * @function 351 | * @requires one.color.CMYK 352 | * @return {one.color.CMYK} 353 | */ 354 | 355 | /*jslint bitwise:false*/ 356 | /*global one*/ 357 | 358 | /** 359 | * Parse a hex string. Please use {@link one.color#parse} instead. 360 | * @param strHex The hex string, e.g. "#abc", 361 | * "123abc".... 362 | * @return {one.color.RGB} Color object representing the parsed 363 | * color, or false if the string couldn't be parsed. 364 | * @private 365 | */ 366 | one.color.fromHex = function (strHex) { 367 | if (strHex.length < 6) { 368 | // Allow CSS shorthand 369 | strHex = strHex.replace(/^#?([0-9a-f])([0-9a-f])([0-9a-f])$/i, '$1$1$2$2$3$3'); 370 | } 371 | // Split strHex into red, green, and blue components 372 | var hexMatch = strHex.match(/^#?([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])$/i); 373 | if (hexMatch) { 374 | return new one.color.RGB( 375 | parseInt(hexMatch[1], 16) / 255, 376 | parseInt(hexMatch[2], 16) / 255, 377 | parseInt(hexMatch[3], 16) / 255 378 | ); 379 | } 380 | }; 381 | 382 | /** 383 | * Regex for matching CSS RGBA color strings 384 | * @private 385 | */ 386 | one.color.rgbaRegex =/^rgba?\(\s*(\.\d+|\d+(?:\.\d+)?)(%)?\s*,\s*(\.\d+|\d+(?:\.\d+)?)(%)?\s*,\s*(\.\d+|\d+(?:\.\d+)?)(%)?\s*(?:,\s*(\.\d+|\d+(?:\.\d+))\s*)?\)/i; 387 | 388 | /** 389 | * Parse a CSS RGBA string. Please use {@link one.color#parse} instead. 390 | * @param strCSS The CSS RGBA string, e.g. "rgb(100, 255, 100)", 391 | * "rgba(0, 0, 255, 0.5)", "rgb(0%, 100%, 0%)".... 392 | * @return {one.color.RGB} Color object representing the parsed 393 | * color, or false if the string couldn't be parsed. 394 | * @private 395 | */ 396 | one.color.fromCSSRGBA = function (strCSS) { 397 | var match = strCSS.match(one.color.rgbaRegex); 398 | 399 | if (match) { 400 | return new one.color.RGB( 401 | parseFloat(match[1]) / (match[2] ? 100 : 255), 402 | parseFloat(match[3]) / (match[4] ? 100 : 255), 403 | parseFloat(match[5]) / (match[6] ? 100 : 255), 404 | parseFloat(match[7]) 405 | ); 406 | } 407 | }; 408 | 409 | /** 410 | * Parse a hex string, 24-bit integer or object representing a color. 411 | * If a one.color.(RGB|HSL|HSV|CMYK) object is provided, it will be returned 412 | * as-is, so in library code you can use {@link one.color.parse} to be flexible 413 | * about how colors are provided to you: 414 | *

 415 | function foo (color) {
 416 | color = color.parse(color);
 417 | // Now we are sure that color is a one.color.(RGB|CMYK|HSL|HSV) object, even if it was provided as a hex string.
 418 | }
 419 |  * 
420 | * @param {String|Object} obj A hex string, integer value, or 421 | * object to parse. 422 | * @return {one.color.RGB|one.color.HSL|one.color.HSV|one.color.CMYK} Color object representing the 423 | * parsed color, or false if the input couldn't be parsed. 424 | */ 425 | one.color.parse = function (obj) { 426 | if (obj.charCodeAt) { 427 | return one.color.fromCSSRGBA(obj) || one.color.fromHex(obj); 428 | } else if (typeof obj === 'object' && obj.isColor) { 429 | return obj; 430 | } else if (Object.prototype.toString.apply(obj) === '[object Array]') { 431 | return new one.color[obj[0]](obj.slice(1, obj.length)); 432 | } else if (!isNaN(obj)) { 433 | // Strange integer representation sometimes returned by document.queryCommandValue in some browser... 434 | return new one.color.RGB((obj & 0xFF) / 255, ((obj & 0xFF00) >> 8) / 255, ((obj & 0xFF0000) >> 16) / 255); 435 | } 436 | return false; 437 | }; 438 | 439 | /*global one*/ 440 | 441 | 442 | /** 443 | * @name one.color.HSV 444 | * @class 445 | *

A color in the HSV colorspace, with an optional alpha value.

446 | *

one.color.(RGB|HSL|HSV|CMYK) objects are designed to be 447 | * immutable; all the conversion, set, and adjust methods return new 448 | * objects.

449 | *

one.color.(RGB|HSL|HSV|CMYK) objects automatically get the set 450 | * and adjust methods from all other installed colorspaces, so 451 | * although you can use the explicit conversion methods ({@link 452 | * one.color.HSV#toRGB}, {@link one.color.HSV#toHSL}...), the below 453 | * will work just fine:


 454 | 
 455 | new one.color.HSV(.9, .2, .4).
 456 |     adjustBlue(-.4). // Implicit conversion to RGB
 457 |     setCyan(-.1). // Implicit conversion to CMYK
 458 |     toHex(); // "#665200"
 459 | 
460 | * 461 | * @constructor 462 | * Create a new one.color.HSV object. Component values outside the 463 | * supported range, [0..1], will be adjusted automatically. 464 | * @param {Number} h The hue component, range: [0..1] 465 | * @param {Number} s The saturation component, range: [0..1] 466 | * @param {Number} v The value component, range: [0..1] 467 | * @param {Number} [a] The alpha value, range: [0..1], 468 | * defaults to 1 469 | */ 470 | 471 | /** 472 | * @name one.color.HSV.prototype.h 473 | * @property 474 | * @type Number 475 | * @description The hue component, range: [0..1] 476 | */ 477 | 478 | /** 479 | * @name one.color.HSV.prototype.s 480 | * @property 481 | * @type Number 482 | * @description The saturation component, range: [0..1] 483 | */ 484 | 485 | /** 486 | * @name one.color.HSV.prototype.v 487 | * @property 488 | * @type Number 489 | * @description The value component, range: [0..1] 490 | */ 491 | 492 | /** 493 | * @name one.color.HSV.prototype.a 494 | * @property 495 | * @type Number 496 | * @description The alpha value, range: [0..1] 497 | */ 498 | 499 | /** 500 | * @name one.color.HSV.prototype.setHue 501 | * @function 502 | * @param {Number} h The new hue component, range: [0..1] 503 | * @return {one.color.HSV} New color object with the changed value. 504 | */ 505 | 506 | /** 507 | * @name one.color.HSV.prototype.setSaturation 508 | * @function 509 | * @param {Number} s The new saturation component, range: [0..1] 510 | * @return {one.color.HSV} New color object with the changed value. 511 | */ 512 | 513 | /** 514 | * @name one.color.HSV.prototype.setValue 515 | * @function 516 | * @param {Number} l The new value component, range: [0..1] 517 | * @return {one.color.HSV} New color object with the changed value. 518 | */ 519 | 520 | /** 521 | * @name one.color.HSV.prototype.setAlpha 522 | * @function 523 | * @param {Number} a The new alpha value, range: [0..1] 524 | * @return {one.color.HSV} New color object with the changed value. 525 | */ 526 | 527 | /** 528 | * @name one.color.HSV.prototype.adjustHue 529 | * @function 530 | * @param {Number} h The value to add to the hue component. If the resulting 531 | * value falls outside the supported range, [0..1], it will be 532 | * adjusted automatically. 533 | * @return {one.color.HSV} New color object with the changed value. 534 | */ 535 | 536 | /** 537 | * @name one.color.HSV.prototype.adjustSaturation 538 | * @function 539 | * @param {Number} s The value to add to the saturation component. If the 540 | * resulting value falls outside the supported range, [0..1], it will 541 | * be adjusted automatically. 542 | * @return {one.color.HSV} New color object with the changed value. 543 | */ 544 | 545 | /** 546 | * @name one.color.HSV.prototype.adjustValue 547 | * @function 548 | * @param {Number} v The value to add to the value component. If the resulting 549 | * value falls outside the supported range, [0..1], it will be 550 | * adjusted automatically. 551 | * @return {one.color.HSV} New color object with the changed value. 552 | */ 553 | 554 | /** 555 | * @name one.color.HSV.prototype.adjustAlpha 556 | * @function 557 | * @param {Number} a The value to add to the alpha value. If the resulting 558 | * value falls outside the supported range, [0..1], it will be 559 | * adjusted automatically. 560 | * @return {one.color.HSV} New color object with the changed value. 561 | */ 562 | 563 | /** 564 | * @name one.color.HSV.prototype.toJSON 565 | * @description Convert the color to a JSON representation. 566 | * @function 567 | * @return {Array} 568 | */ 569 | 570 | /** 571 | * @name one.color.HSV.prototype.toRGB 572 | * @description Convert the color to a {@link one.color.RGB} object. 573 | * @function 574 | * @return {one.color.RGB} 575 | */ 576 | 577 | /** 578 | * @name one.color.HSV.prototype.toHSV 579 | * @description Convert the color to a {@link one.color.HSV} object, ie. return the object itself. 580 | * @function 581 | * @return {one.color.HSV} 582 | */ 583 | 584 | /** 585 | * @name one.color.HSV.prototype.toHSL 586 | * @description Convert the color to a {@link one.color.HSL} object. 587 | * @function 588 | * @requires one.color.HSL 589 | * @return {one.color.HSL} 590 | */ 591 | 592 | /** 593 | * @name one.color.HSV.prototype.toCMYK 594 | * @description Convert the color to a {@link one.color.CMYK} object. 595 | * @function 596 | * @include one.color.CMYK 597 | * @return {one.color.CMYK} 598 | */ 599 | 600 | /** 601 | * @name one.color.HSV.prototype.toHex 602 | * @description Get the standard RGB hex representation of the color. 603 | * @function 604 | * @return {String} The hex string, e.g. "#f681df" 605 | */ 606 | 607 | /** 608 | * @name one.color.HSV.prototype.toCSS 609 | * @description Get a valid CSS color representation of the color without an alpha value. 610 | * @function 611 | * @return {String} The CSS color string, e.g. "rgb(123, 2, 202)" 612 | */ 613 | 614 | /** 615 | * @name one.color.HSV.prototype.toCSSWithAlpha 616 | * @description Get a valid CSS color representation of the color, including the alpha value. 617 | * @function 618 | * @return {String} The CSS color string, e.g. "rgba(123, 2, 202, 0.253)" 619 | */ 620 | one.color.installColorSpace('HSV', ['Hue', 'Saturation', 'Value', 'Alpha'], { 621 | toRGB: function () { 622 | var r, g, b, 623 | i = Math.min(5, Math.floor(this.h * 6)), 624 | f = this.h * 6 - i, 625 | p = this.v * (1 - this.s), 626 | q = this.v * (1 - f * this.s), 627 | t = this.v * (1 - (1 - f) * this.s); 628 | switch (i) { 629 | case 0: 630 | r = this.v; 631 | g = t; 632 | b = p; 633 | break; 634 | case 1: 635 | r = q; 636 | g = this.v; 637 | b = p; 638 | break; 639 | case 2: 640 | r = p; 641 | g = this.v; 642 | b = t; 643 | break; 644 | case 3: 645 | r = p; 646 | g = q; 647 | b = this.v; 648 | break; 649 | case 4: 650 | r = t; 651 | g = p; 652 | b = this.v; 653 | break; 654 | case 5: 655 | r = this.v; 656 | g = p; 657 | b = q; 658 | break; 659 | } 660 | return new one.color.RGB(r, g, b, this.a); 661 | }, 662 | 663 | toHSL: function () { 664 | // Algorithm adapted from http://wiki.secondlife.com/wiki/Color_conversion_scripts 665 | var s = this.s * this.v, 666 | l = (2 - this.s) * this.v; 667 | return new one.color.HSL(this.h, s / (l <= 1 ? l : (2 - l)), l / 2, this.a); 668 | }, 669 | 670 | fromRGB: function () { // Becomes one.color.RGB.prototype.toHSV 671 | var max = Math.max(this.r, this.g, this.b), 672 | min = Math.min(this.r, this.g, this.b), 673 | delta = max - min, 674 | h, 675 | s = (max === 0) ? 0 : (delta / max), 676 | v = max; 677 | if (delta === 0) { 678 | h = 0; 679 | } else { 680 | switch (max) { 681 | case this.r: 682 | h = (this.g - this.b) / delta / 6 + (this.g < this.b ? 1 : 0); 683 | break; 684 | case this.g: 685 | h = (this.b - this.r) / delta / 6 + 1 / 3; 686 | break; 687 | case this.b: 688 | h = (this.r - this.g) / delta / 6 + 2 / 3; 689 | break; 690 | } 691 | } 692 | return new one.color.HSV(h, s, v, this.a); 693 | } 694 | }); 695 | 696 | /*global one*/ 697 | 698 | 699 | /** 700 | * @name one.color.HSL 701 | * @class 702 | *

A color in the HSL colorspace, with an optional alpha value.

703 | *

one.color.(RGB|HSL|HSV|CMYK) objects are designed to be 704 | * immutable; all the conversion, set, and adjust methods return new 705 | * objects.

706 | *

one.color.(RGB|HSL|HSV|CMYK) objects automatically get the set 707 | * and adjust methods from all other installed colorspaces, so 708 | * although you can use the explicit conversion methods ({@link 709 | * one.color.HSL#toRGB}, {@link one.color.HSL#toHSV}...), the below 710 | * will work just fine:


 711 | 
 712 | new one.color.HSL(.4, .3, .9, .9). // HSL with alpha
 713 |     adjustBlack(+.1). // Implicit conversion to CMYK (with alpha)
 714 |     setGreen(-.1). // Implicit conversion to RGB (with alpha)
 715 |     toCSSWithAlpha(); // "rgba(198,0,203,0.9)"
 716 | 
717 | * 718 | * @constructor 719 | * Create a new one.color.HSL object. Component values outside the 720 | * supported range, [0..1], will be adjusted automatically. 721 | * @param {Number} h The hue component, range: [0..1] 722 | * @param {Number} s The saturation component, range: [0..1] 723 | * @param {Number} l The lightness component, range: [0..1] 724 | * @param {Number} [a] The alpha value, range: [0..1], 725 | * defaults to 1 726 | */ 727 | 728 | one.color.installColorSpace('HSL', ['Hue', 'Saturation', 'Lightness', 'Alpha'], { 729 | toHSV: function () { 730 | // Algorithm adapted from http://wiki.secondlife.com/wiki/Color_conversion_scripts 731 | var s = this.s, 732 | l = this.l * 2; 733 | if (l <= 1) { 734 | s *= l; 735 | } else { 736 | s *= (2 - l); 737 | } 738 | return new one.color.HSV(this.h, (2 * s) / (l + s), (l + s) / 2, this.a); 739 | }, 740 | 741 | toRGB: function () { 742 | return this.toHSV().toRGB(); 743 | }, 744 | 745 | fromRGB: function () { // Becomes one.color.RGB.prototype.toHSV 746 | return this.toHSV().toHSL(); 747 | } 748 | }); 749 | 750 | /** 751 | * @name one.color.HSL.prototype.h 752 | * @property 753 | * @type Number 754 | * @description The hue component, range: [0..1] 755 | */ 756 | 757 | /** 758 | * @name one.color.HSL.prototype.s 759 | * @property 760 | * @type Number 761 | * @description The saturation component, range: [0..1] 762 | */ 763 | 764 | /** 765 | * @name one.color.HSL.prototype.l 766 | * @property 767 | * @type Number 768 | * @description The lightness component, range: [0..1] 769 | */ 770 | 771 | /** 772 | * @name one.color.HSL.prototype.a 773 | * @property 774 | * @type Number 775 | * @description The alpha value, range: [0..1] 776 | */ 777 | 778 | /** 779 | * @name one.color.HSL.prototype.setHue 780 | * @function 781 | * @param {Number} h The new hue component, range: [0..1] 782 | * @return {one.color.HSL} New color object with the changed value. 783 | */ 784 | 785 | /** 786 | * @name one.color.HSL.prototype.setSaturation 787 | * @function 788 | * @param {Number} s The new saturation component, range: [0..1] 789 | * @return {one.color.HSL} New color object with the changed value. 790 | */ 791 | 792 | /** 793 | * @name one.color.HSL.prototype 794 | * @function setLightness 795 | * @param {Number} l The new lightness component, range: [0..1] 796 | * @return {one.color.HSL} New color object with the changed value. 797 | */ 798 | 799 | /** 800 | * @name one.color.HSL.prototype.setAlpha 801 | * @function 802 | * @param {Number} a The new alpha value, range: [0..1] 803 | * @return {one.color.HSL} New color object with the changed value. 804 | */ 805 | 806 | /** 807 | * @name one.color.HSL.prototype.adjustHue 808 | * @function 809 | * @param {Number} h The value to add to the hue component. If the resulting 810 | * value falls outside the supported range, [0..1], it will be 811 | * adjusted automatically. 812 | * @return {one.color.HSL} New color object with the changed value. 813 | */ 814 | 815 | /** 816 | * @name one.color.HSL.prototype.adjustSaturation 817 | * @function 818 | * @param {Number} s The value to add to the saturation component. If the 819 | * resulting value falls outside the supported range, [0..1], it will 820 | * be adjusted automatically. 821 | * @return {one.color.HSL} New color object with the changed value. 822 | */ 823 | 824 | /** 825 | * @name one.color.HSL.prototype.adjustLightness 826 | * @function 827 | * @param {Number} l The value to add to the lightness component. If the 828 | * resulting value falls outside the supported range, [0..1], it will 829 | * be adjusted automatically. 830 | * @return {one.color.HSL} New color object with the changed value. 831 | */ 832 | 833 | /** 834 | * @name one.color.HSL.prototype.adjustAlpha 835 | * @function 836 | * @param {Number} a The value to add to the alpha value. If the resulting 837 | * value falls outside the supported range, [0..1], it will be 838 | * adjusted automatically. 839 | * @return {one.color.HSL} New color object with the changed value. 840 | */ 841 | 842 | /** 843 | * @name one.color.HSL.prototype.toJSON 844 | * @description Convert the color to a JSON representation. 845 | * @function 846 | * @return {Array} 847 | */ 848 | 849 | /** 850 | * @name one.color.HSL.prototype.toRGB 851 | * @description Convert the color to a {@link one.color.RGB} object. 852 | * @function 853 | * @return {one.color.RGB} 854 | */ 855 | 856 | /** 857 | * @name one.color.HSL.prototype.toHSV 858 | * @description Convert the color to a {@link one.color.HSV} object. 859 | * @function 860 | * @return {one.color.HSV} 861 | * @requires one.color.HSV 862 | */ 863 | 864 | /** 865 | * @name one.color.HSL.prototype.toHSL 866 | * @description Convert the color to a {@link one.color.HSL} object, ie. return the object itself. 867 | * @function 868 | * @return {one.color.HSL} 869 | */ 870 | 871 | /** 872 | * @name one.color.HSL.prototype.toCMYK 873 | * @description Convert the color to a {@link one.color.CMYK} object. 874 | * @function 875 | * @requires one.color.CMYK 876 | * @return {one.color.CMYK} 877 | */ 878 | 879 | /** 880 | * @name one.color.HSL.prototype.toHex 881 | * @description Get the standard RGB hex representation of the color. 882 | * @function 883 | * @return {String} The hex string, e.g. "#f681df" 884 | */ 885 | 886 | /** 887 | * @name one.color.HSL.prototype.toCSS 888 | * @description Get a valid CSS color representation of the color without an alpha value. 889 | * @function 890 | * @return {String} The CSS color string, e.g. "rgb(123, 2, 202)" 891 | */ 892 | 893 | /** 894 | * @name one.color.HSL.prototype.toCSSWithAlpha 895 | * @description Get a valid CSS color representation of the color, including the alpha value. 896 | * @function 897 | * @return {String} The CSS color string, e.g. "rgba(123, 2, 202, 0.253)" 898 | */ 899 | 900 | /*global one*/ 901 | 902 | /** 903 | * @name one.color.CMYK 904 | * @class 905 | *

A color in the CMYK colorspace, with an optional alpha value.

906 | *

one.color.(RGB|HSL|HSV|CMYK) objects are designed to be 907 | * immutable; all the conversion, set, and adjust methods return new 908 | * objects.

909 | *

one.color.(RGB|HSL|HSV|CMYK) objects automatically get the set 910 | * and adjust methods from all other installed colorspaces, so 911 | * although you can use the explicit conversion methods ({@link one.color.CMYK#toRGB}, 912 | * {@link one.color.CMYK#toHSL}...), the below 913 | * will work just fine:


 914 | 
 915 | new one.color.CMYK(.4, .2, .4, .9, .2). // CMYK with alpha
 916 |     setBlue(-.2). // Implicit conversion to RGB (with alpha)
 917 |     adjustHue(-.1). // Implicit conversion to HSL(/HSV) (with alpha)
 918 |     toCSSWithAlpha(); // "rgba(20,13,0,0.2)"
 919 | 
920 | * @static 921 | * 922 | * @constructor 923 | * Create a new one.color.CMYK object. Component values outside the 924 | * supported range, [0..1], will be adjusted automatically. 925 | * @param {Number} c The cyan component, range: [0..1] 926 | * @param {Number} m The magenta component, range: [0..1] 927 | * @param {Number} y The yellow component, range: [0..1] 928 | * @param {Number} k The black component, range: [0..1] 929 | * @param {Number} [a] The alpha value, range: [0..1], 930 | * defaults to 1 931 | */ 932 | 933 | /** 934 | * @name one.color.CMYK.prototype.c 935 | * @property 936 | * @type Number 937 | * @description The cyan component, range: [0..1] 938 | */ 939 | 940 | /** 941 | * @name one.color.CMYK.prototype.m 942 | * @property 943 | * @type Number 944 | * @description The magenta component, range: [0..1] 945 | */ 946 | 947 | /** 948 | * @name one.color.CMYK.prototype.y 949 | * @property 950 | * @type Number 951 | * @description The yellow component, range: [0..1] 952 | */ 953 | 954 | /** 955 | * @name one.color.CMYK.prototype.k 956 | * @property 957 | * @type Number 958 | * @description The black component, range: [0..1] 959 | */ 960 | 961 | /** 962 | * @name one.color.CMYK.prototype.a 963 | * @property 964 | * @type Number 965 | * @description The alpha value, range: [0..1] 966 | */ 967 | 968 | /** 969 | * @name one.color.CMYK.prototype.setCyan 970 | * @function 971 | * @param {Number} c The new cyan component, range: [0..1] 972 | * @return {one.color.CMYK} New color object with the changed value. 973 | */ 974 | 975 | /** 976 | * @name one.color.CMYK.prototype.setMagenta 977 | * @function 978 | * @param {Number} m The new magenta component, range: [0..1] 979 | * @return {one.color.CMYK} New color object with the changed value. 980 | */ 981 | 982 | /** 983 | * @name one.color.CMYK.prototype.setYellow 984 | * @function 985 | * @param {Number} y The new yellow component, range: [0..1] 986 | * @return {one.color.CMYK} New color object with the changed value. 987 | */ 988 | 989 | /** 990 | * @name one.color.CMYK.prototype.setBlack 991 | * @function 992 | * @param {Number} k The new black component, range: [0..1] 993 | * @return {one.color.CMYK} New color object with the changed value. 994 | */ 995 | 996 | /** 997 | * @name one.color.CMYK.prototype.setAlpha 998 | * @function 999 | * @param {Number} a The new alpha value, range: [0..1] 1000 | * @return {one.color.CMYK} New color object with the changed value. 1001 | */ 1002 | 1003 | /** 1004 | * @name one.color.CMYK.prototype.adjustCyan 1005 | * @function 1006 | * @param {Number} c The value to add to the cyan component. If the resulting 1007 | * value falls outside the supported range, [0..1], it will be 1008 | * adjusted automatically. 1009 | * @return {one.color.CMYK} New color object with the changed value. 1010 | */ 1011 | 1012 | /** 1013 | * @name one.color.CMYK.prototype.adjustMagenta 1014 | * @function 1015 | * @param {Number} m The value to add to the magenta component. If the 1016 | * resulting value falls outside the supported range, [0..1], it will 1017 | * be adjusted automatically. 1018 | * @return {one.color.CMYK} New color object with the changed value. 1019 | */ 1020 | 1021 | /** 1022 | * @name one.color.CMYK.prototype.adjustYellow 1023 | * @function 1024 | * @param {Number} y The value to add to the yellow component. If the resulting 1025 | * value falls outside the supported range, [0..1], it will be 1026 | * adjusted automatically. 1027 | * @return {one.color.CMYK} New color object with the changed value. 1028 | */ 1029 | 1030 | /** 1031 | * @name one.color.CMYK.prototype.adjustBlack 1032 | * @function 1033 | * @param {Number} k The value to add to the black component. If the resulting 1034 | * value falls outside the supported range, [0..1], it will be 1035 | * adjusted automatically. 1036 | * @return {one.color.CMYK} New color object with the changed value. 1037 | */ 1038 | 1039 | /** 1040 | * @name one.color.CMYK.prototype.adjustAlpha 1041 | * @function 1042 | * @param {Number} a The value to add to the alpha value. If the resulting 1043 | * value falls outside the supported range, [0..1], it will be 1044 | * adjusted automatically. 1045 | * @return {one.color.CMYK} New color object with the changed value. 1046 | */ 1047 | 1048 | /** 1049 | * @name one.color.CMYK.prototype.toJSON 1050 | * @description Convert the color to a JSON representation. 1051 | * @function 1052 | * @return {Array} 1053 | */ 1054 | 1055 | /** 1056 | * @name one.color.CMYK.prototype.toRGB 1057 | * @description Convert the color to a {@link one.color.RGB} object. 1058 | * @function 1059 | * @return {one.color.RGB} 1060 | */ 1061 | 1062 | /** 1063 | * @name one.color.CMYK.prototype.toHSV 1064 | * @description Convert the color to a {@link one.color.HSV} object. 1065 | * @function 1066 | * @requires one.color.HSV 1067 | * @return {one.color.HSV} 1068 | */ 1069 | 1070 | /** 1071 | * @name one.color.CMYK.prototype.toHSL 1072 | * @description Convert the color to a {@link one.color.HSL} object. 1073 | * @function 1074 | * @requires one.color.HSL 1075 | * @return {one.color.HSL} 1076 | */ 1077 | 1078 | /** 1079 | * @name one.color.CMYK.prototype.toCMYK 1080 | * @description Convert the color to a {@link one.color.CMYK} object, ie. return the object itself. 1081 | * @function 1082 | * @return {one.color.CMYK} 1083 | */ 1084 | 1085 | /** 1086 | * @name one.color.CMYK.prototype.toHex 1087 | * @description Get the standard RGB hex representation of the color. 1088 | * @function 1089 | * @return {String} The hex string, e.g. "#f681df" 1090 | */ 1091 | 1092 | /** 1093 | * @name one.color.CMYK.prototype.toCSS 1094 | * @description Get a valid CSS color representation of the color without an alpha value. 1095 | * @function 1096 | * @return {String} The CSS color string, e.g. "rgb(123, 2, 202)" 1097 | */ 1098 | 1099 | /** 1100 | * @name one.color.CMYK.prototype.toCSSWithAlpha 1101 | * @description Get a valid CSS color representation of the color, including the alpha value. 1102 | * @function 1103 | * @return {String} The CSS color string, e.g. "rgba(123, 2, 202, 0.253)" 1104 | */ 1105 | 1106 | one.color.installColorSpace('CMYK', ['Cyan', 'Magenta', 'Yellow', 'blacK', 'Alpha'], { 1107 | toRGB: function () { 1108 | return new one.color.RGB((1 - this.c * (1 - this.k) - this.k), 1109 | (1 - this.m * (1 - this.k) - this.k), 1110 | (1 - this.y * (1 - this.k) - this.k), 1111 | this.a); 1112 | }, 1113 | 1114 | fromRGB: function () { // Becomes one.color.RGB.prototype.toCMYK 1115 | // Adapted from http://www.javascripter.net/faq/rgb2cmyk.htm 1116 | var c = 1 - this.r, 1117 | m = 1 - this.g, 1118 | y = 1 - this.b, 1119 | k = 1; 1120 | if (this.r || this.g || this.b) { 1121 | k = Math.min(c, Math.min(m, y)); 1122 | c = (c - k) / (1 - k); 1123 | m = (m - k) / (1 - k); 1124 | y = (y - k) / (1 - k); 1125 | } else { 1126 | k = 1; 1127 | } 1128 | return new one.color.CMYK(c, m, y, k, this.a); 1129 | } 1130 | }); 1131 | 1132 | // This file is purely for the build system 1133 | try { 1134 | if (module) { 1135 | module.exports = one.color; 1136 | } 1137 | } catch(e) {} 1138 | -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/1024px-HSV_color_solid_cylinder_alpha_lowgamma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/1024px-HSV_color_solid_cylinder_alpha_lowgamma.png -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/ExtJS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/ExtJS.png -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/HSL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/HSL.png -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/HSV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/HSV.png -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/Pixels.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/Pixels.jpg -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/PullingHair.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/PullingHair.png -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/RGB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/RGB.png -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/RGB_HSL_HSV_comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/RGB_HSL_HSV_comparison.png -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/Space_Rainbow_desktop_background_pictures.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/Space_Rainbow_desktop_background_pictures.jpg -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/blog.png -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/calendar.png -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/images/colorSpace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-com/one-color/fa36a832c597f94247e68797f9ef15016f9cb43c/slides/CPHJS-Oct2011/images/colorSpace.jpg -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | One-color.js - JS color manipulation made easy 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

One-color.js

19 |

JS colors made easy

20 |

Peter Müller, Web developer @onecom

21 |
22 | 23 |
24 |

Introduction

25 |
    26 |
  • One.com, shared hosting webspaces
  • 27 |
  • 8 frontend webdevs adding value to product
  • 28 |
  • Webmail, Abook, Calendar, Filemanager, Blog, Gallery, Webcreator etc...
  • 29 |
  • All partially or completely JS → Huge toolchain → Modular libs
  • 30 |
31 |
32 |
33 | 34 |
35 |
36 |

Why do we need it?

37 | 38 |
    39 |
  • Administration for blog, gallery etc
  • 40 |
  • User choice
  • 41 |
  • Webpages should look different than the other customers's
  • 42 |
43 |
44 |
45 |

Why do we need it?

46 | 47 |
    48 |
  • Alternate colors hues
  • 49 |
  • Color variants based on a user choice
  • 50 |
  • Text legibility on random background color
  • 51 |
52 |
53 |
54 |

?

55 |
    56 |
  • Custom color picker components
  • 57 |
  • Automatic colorization of maps etc
  • 58 |
  • Animation
  • 59 |
  • Canvas manipulation
  • 60 |
61 |
62 |
63 | 64 |
65 |
66 |

But first...

67 |

68 | A little domain knowledge 69 |

70 |
71 |
72 |

Displays

73 | 74 |
75 |
76 |

RGB

77 | 78 |
79 |
80 |

HSV

81 | 82 |
    83 |
  • Hue: 360 degrees pure color
  • 84 |
  • Saturation: colorfullness
  • 85 |
  • Value: amount of light
  • 86 |
  • More intuitive than RGB
  • 87 |
88 |
89 |
90 |

HSL

91 | 92 |
    93 |
  • Lightness vs value
  • 94 |
95 |
96 |
97 | 98 |
    99 |
  • Conversion to RGB looses information
  • 100 |
  • Uniquely defined in RGB
  • 101 |
  • White and black ambiguous in HSV, HSL
  • 102 |
  • Bonusinfo: There are a lot more color spaces
  • 103 |
104 |
105 |
106 |

CSS syntaxes

107 |
    108 |
  • #123456
  • 109 |
  • rgb (100, 100, 100)
  • 110 |
  • rgba(100, 100, 100, 0.5)
  • 111 |
  • hsl (100, 100, 100)
  • 112 |
  • hsla(100, 100, 100, 0.5)
  • 113 |
114 |
115 |
116 |

No Javascript syntax :'(

117 |
118 |
119 | 120 |
121 |
122 |

Specifications

123 |
    124 |
  • RGB, HSL and HSV
  • 125 |
  • Colorspace conversions
  • 126 |
  • A 'datatype'
  • 127 |
  • Pluggable architecture
  • 128 |
  • Chainable modifiers
  • 129 |
  • SMALL!
  • 130 |
131 |
132 | 133 |
134 |

Options

135 |
    136 |
  • Ext JS
  • 137 |
  • Micro library
  • 138 |
  • Roll your own
  • 139 |
140 |
141 | 142 |
143 |

Ext JS

144 | 145 |
    146 |
  • Seriously?
  • 147 |
148 |
    149 |
  • Representation: Hex-string
  • 150 |
  • Color spaces
  • 151 |
  • Color conversion
  • 152 |
153 |
154 | 155 |
156 |

Micro library

157 |
    158 |
  • Lots to choose from
  • 159 |
  • Lots to choose from!
  • 160 |
  • Math is well documented
  • 161 |
  • Architecture is difficult
  • 162 |
163 |
164 | 165 |
166 |
167 |

Lack of data model

168 |
    169 |
  • "#000000"
  • 170 |
  • [0, 0, 0]
  • 171 |
  • { R: 0, G: 0, B: 0 }
  • 172 |
  • { space: 'rgb', R: 0, G: 0, B: 0 }
  • 173 |
174 |
175 | 176 |
177 |

Conversion methods

178 |
    179 |
  • fromHexToRGB()
  • 180 |
  • fromRGBToHex()
  • 181 |
182 |
    183 |
  • fromHexToHSV()
  • 184 |
  • fromRGBToHSV()
  • 185 |
  • fromHSVToHex()
  • 186 |
  • fromHSVToRGB()
  • 187 |
188 |
    189 |
  • fromHexToHSL()
  • 190 |
  • fromRGBToHSL()
  • 191 |
  • fromHSVToHSL()
  • 192 |
  • fromHSLToHex()
  • 193 |
  • fromHSLToRGB()
  • 194 |
  • fromHSLToHSV()
  • 195 |
196 | 197 |
    198 |
  • RGB and HEX. Simple
  • 199 |
  • Lets add HSV
  • 200 |
  • Now HSL... You see where this is going
  • 201 |
  • Lots of methods, lots of bytes, lots of mental maintenance
  • 202 |
203 |
204 | 205 |
206 |

Chained modifiers

207 |
    208 |
  • Object with conversion methods
  • 209 |
  • Object with channel modifier methods
  • 210 |
211 |
212 | 213 |
214 |

Color representation

215 |
    216 |
  • Red: [0;255]
  • 217 |
  • Green: [0;255]
  • 218 |
  • Blue: [0;255]
  • 219 |
220 |
    221 |
  • Hue: [0;360]
  • 222 |
  • Saturation: [0;100]
  • 223 |
  • Value: [0;100]
  • 224 |
  • Lightness: [0;100]
  • 225 |
226 |

Color math: [0;1]

227 |
    228 |
  • RGB: Integers
  • 229 |
  • HSL/HSVL: Floating point? Browsers don't get it
  • 230 |
  • Math: Infinetly precise → Aproximate by using floating point
  • 231 |
  • Other libs only think one conversion at a time
  • 232 |
233 |
234 | 235 |
236 |

And the winner is...

237 |
    238 |
  • None :(
  • 239 |
240 |

... but take a look at https://github.com/harthur/color, lots of good ideas!

241 |
242 |
243 |
244 | 245 |
246 |
247 |

One-color.js

248 |
249 | 250 |
251 |

Specifications

252 |
    253 |
  • RGB, HSL and HSV
  • 254 |
  • Colorspace conversions
  • 255 |
  • A 'datatype'
  • 256 |
  • Pluggable architecture
  • 257 |
  • Chainable modifiers
  • 258 |
  • SMALL!
  • 259 |
260 |
    261 |
  • Parse once
  • 262 |
  • Round once
  • 263 |
  • Avoid loss of precision
  • 264 |
265 |
266 | 267 |
268 |

Base

269 |
one.color = { // General namespace for One.com libs
270 |     color = function( one.color.* | Array | String | Int ), // Parser
271 | };
272 | one.color.installColorSpace: function ( str space, [str channelNames], obj methods )
273 | one.color.installColorSpace("RGB", "Red", "Green", "Blue", "Alpha", {...});
274 |
one.color.RGB  = function ( [0;1], [0;1], [0;1], [0;1] ) // Constructor
275 |

And with plugins:

276 |
one.color.HSV  = function ( [0;1], [0;1], [0;1], [0;1] ) // Constructor
277 |
one.color.HSL  = function ( [0;1], [0;1], [0;1], [0;1] ) // Constructor
278 |
one.color.CMYK = function ( [0;1], [0;1], [0;1], [0;1] ) // Constructor
279 |
    280 |
  • This is the new API
  • 281 |
  • Array: toJSON and back!
  • 282 |
  • String: Hex, RGB, HSL, HSV
  • 283 |
  • Notice the normalization to [0;1]
  • 284 |
285 | 286 |
287 |

installColorSpace

288 |

Metaprogramming FTW!

289 |

Methods added to all installed one.color.* prototypes:

290 |
    291 |
  • toString() → "[one.color.RGB: Red=0 Green=0 Blue=0 Alpha=1]"
  • 292 |
  • hex() → "#RRGGBB"
  • 293 |
  • css() → "rgb([0;255], [0;255], [0;255])"
  • 294 |
  • cssa() → "rgb([0;255], [0;255], [0;255], [0;1])"
  • 295 |
  • toJSON() → ["RGB", [0;1], [0;1], [0;1], [0;1]]
  • 296 |
  • equals(otherColor, ε = 10-9) → Boolean
  • 297 |
  • [colorSpace] → one.color[colorSpace]
  • 298 |
  • [channelName] → Number [0;1]
  • 299 |
  • [channelName]([0;1]) → new one.color[colorSpace], channelName = [0;1]
  • 300 |
  • [channelName](±[0;1], true) → new one.color[colorSpace], channelName ±= [0;1]
  • 301 |
302 |
303 | 304 |
305 |

installColorSpace

306 |

How to write a colorSpace plugin

307 |
one.color.installColorSpace('HSV', ['Hue', 'Saturation', 'Value', 'Alpha'], {
308 |     fromRgb: function () { // Becomes one.color.RGB.prototype.toHSV
309 |         // SNIP! Colormath is boring, lets go shopping!
310 |         return new one.color.HSV(h, s, v, this.alpha);
311 |     },
312 | 
313 |     rgb: function () {
314 |         // SNIP! Colormath... Go read wikipedia
315 |         return new one.color.RGB(r, g, b, this.alpha);
316 |     },
317 | 
318 |     hsl: function () {
319 |         // SNIP! Colormath... Just copy/paste from someone else
320 |         return new one.color.HSL(this.h, s, l, this.alpha);
321 |     }
322 | });
323 |
324 | 325 |
326 |

API usage

327 |

Color space conversions

328 |
one.color("#99FFFF")
329 |     .hsv()
330 |     .hsl()
331 |     .cmyk()
332 |     .hex(); → "#99FFFF"
333 |

Conversions are implicit, why bother...

334 |
335 | 336 |
337 |

API usage

338 |

Channel manipulation methods

339 |
one.color("#99FFFF")
340 |     .red(0.5)
341 |     .hue(-0.2, true)
342 |     .magenta(0)
343 |     .hex(); → "#99ff80"
344 |
345 | 346 |
347 |

Future possibilities

348 |
    349 |
  • More color spaces
  • 350 |
  • Text contrast method
  • 351 |
  • Intuitive adjustment methods
  • 352 |
  • Photoshop blending modes
  • 353 |
  • To/from canvas array
  • 354 |
  • Color picker components
  • 355 |
356 |
357 | 358 |
359 |

FAQ

360 |

Based on the rewritten API version on the 'newapi' branch

361 | 368 |
369 |
370 | 371 |
372 |
373 |

DEMOTIME!

374 |
375 | 376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
E
390 |
391 |
392 |
393 |
     .  .     ..     . .        ..     .  .
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 | RGB 466 |

467 | 468 | 469 |

470 | 471 |

472 | 473 | 474 |

475 | 476 |

477 | 478 | 479 |

480 |
481 | 482 |
483 | HSV 484 |

485 | 486 | 487 |

488 | 489 |

490 | 491 | 492 |

493 | 494 |

495 | 496 | 497 |

498 |
499 | 500 |
501 | CMYK 502 |

503 | 504 | 505 |

506 | 507 |

508 | 509 | 510 |

511 | 512 |

513 | 514 | 515 |

516 | 517 |

518 | 519 | 520 |

521 |
522 | 523 |
524 |

525 | 526 | 527 |

528 |
529 |
530 |
531 |

The CSS NYAN CAT was created by Michal Budzynski for Mozilla Demo Party in Helsinki June 2011

532 |

Sound was disabled for the audiences/visitors pleasure...

533 |
534 |
535 |
536 | 537 |
538 |
539 |

Questions?

540 |
541 |
542 | 543 | 553 | 554 | 555 | 556 | 557 | 560 | 561 | 562 | 563 | -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/talk.css: -------------------------------------------------------------------------------- 1 | html { 2 | background-image: url(images/Space_Rainbow_desktop_background_pictures.jpg); 3 | background-size: cover; 4 | } 5 | 6 | h2 { 7 | text-align: center; 8 | } 9 | 10 | code { 11 | white-space: pre; 12 | } 13 | 14 | .slide, 15 | .delayed, 16 | .delayed-children > * { 17 | -webkit-transition:1s; 18 | -ms-transition:1s; 19 | -moz-transition:1s; 20 | -o-transition:1s; 21 | transition:1s; 22 | -moz-transition-property: -webkit-transform, opacity, left, top, right, bottom; 23 | -ms-transition-property: -webkit-transform, opacity, left, top, right, bottom; 24 | -o-transition-property: -webkit-transform, opacity, left, top, right, bottom; 25 | -webkit-transition-property: -webkit-transform, opacity, left, top, right, bottom; 26 | transition-property: -webkit-transform, opacity, left, top, right, bottom; 27 | } 28 | 29 | .delayed.displayed, .delayed-children > .displayed { 30 | opacity: .5; 31 | } 32 | 33 | .nofade .delayed.displayed, 34 | pre .delayed.displayed, 35 | pre.delayed.displayed, 36 | .delayed-children > .displayed { 37 | opacity: 1; 38 | 39 | } 40 | 41 | section > footer.slide > h1 { 42 | position: absolute; 43 | top: 50%; 44 | left: 0; 45 | right: 0; 46 | margin-top: -.6em; 47 | font-size: 400%; 48 | line-height: 1; 49 | text-align: center; 50 | } 51 | 52 | #intro h1 { 53 | font-size: 2in; 54 | text-align: center; 55 | } 56 | 57 | #intro h2 { 58 | text-align: center; 59 | position: relative; 60 | z-index: 1; 61 | } 62 | 63 | #intro object { 64 | display: block; 65 | margin: -100px auto; 66 | } 67 | 68 | #intro .attribution { 69 | font-family: Helvetica, sans-serif; 70 | font-weight: bold; 71 | text-align: center; 72 | font-size: 100%; 73 | color: rgba(255,255,255,.7); 74 | background: rgba(0,0,0,0.4); 75 | padding:.4em 0; 76 | } 77 | 78 | .slide img { 79 | display: block; 80 | margin: 0 auto; 81 | } 82 | 83 | .slide > ul > li::before { 84 | content: '\25BA'; 85 | color: #c1bf2c; 86 | } 87 | 88 | .slide > ul > li.good::before { 89 | content: '\2714'; 90 | color: #A0C12C; 91 | } 92 | 93 | .slide > ul > li.bad::before { 94 | content: '\2717'; 95 | color: #c12c2c; 96 | } 97 | 98 | .comment { 99 | color: #6CC; 100 | } 101 | 102 | /* Conversion methods slide */ 103 | .conversion ul.delayed { 104 | float: left; 105 | width: 33.33%; 106 | } 107 | .conversion > ul > li::before { 108 | content: ''; 109 | } 110 | .conversion img { 111 | position: absolute; 112 | top: 50%; 113 | left: 50%; 114 | margin-left: -115px; 115 | margin-top: -220px; 116 | } 117 | 118 | #reps ul.delayed { 119 | float: left; 120 | width: 33%; 121 | margin-left: 11%; 122 | } 123 | #reps > ul > li::before { 124 | content: ''; 125 | } 126 | #reps p { 127 | clear: both; 128 | padding-top: 50px; 129 | text-align: center; 130 | font-size: 150%; 131 | } 132 | 133 | /* Specs slide */ 134 | #specs ul { 135 | float: left; 136 | width: 50%; 137 | } 138 | -------------------------------------------------------------------------------- /slides/CPHJS-Oct2011/theme.css: -------------------------------------------------------------------------------- 1 | /** 2 | CSSS basic slideshow theme 3 | 4 | @author Lea Verou 5 | @version 1.0 6 | */ 7 | 8 | /** 9 | * Variables 10 | */ 11 | .slide h2, 12 | section > header.slide > h1 { 13 | font-family: 'Helvetica Neue', Helvetica, sans-serif; 14 | font-weight: 100; 15 | } 16 | 17 | /** 18 | * Styles 19 | */ 20 | 21 | * { 22 | padding:0; 23 | margin:0; 24 | font:inherit; 25 | color:inherit; 26 | } 27 | 28 | html { 29 | background: black url(img/rainbow-wood.jpg) bottom center; 30 | background-size: cover; 31 | } 32 | 33 | body { 34 | font-family: sans-serif; 35 | } 36 | 37 | button { 38 | padding:.2em .5em; 39 | } 40 | 41 | a:hover { 42 | text-shadow: 0 0 .5em white, 0 0 1em white; 43 | } 44 | 45 | select { 46 | color: black; 47 | } 48 | 49 | code, pre, style, textarea, input { 50 | font-family: Consolas, 'Andale Mono', 'Courier New', monospace; 51 | background:rgba(0,0,0,.4); 52 | } 53 | 54 | code { 55 | padding:.2em .2em .1em; 56 | white-space: nowrap; 57 | 58 | -moz-border-radius:.2em; 59 | -webkit-border-radius:.2em; 60 | border-radius:.2em; 61 | 62 | -moz-box-shadow:.05em .05em .3em black; 63 | -webkit-box-shadow:.05em .05em .3em black; 64 | box-shadow:.05em .05em .3em black; 65 | 66 | border: 1px solid rgba(0,0,0,0.5); 67 | background: rgba(0,0,0,0.25); 68 | 69 | -webkit-box-shadow: 0 2px 6px rgba(0,0,0,0.5), inset 0 1px rgba(255,255,255,0.3), inset 0 12px rgba(255,255,255,0.15), inset 0 10px 20px rgba(255,255,255,0.25), inset 0 -15px 30px rgba(0,0,0,0.3); 70 | -moz-box-shadow: 0 2px 6px rgba(0,0,0,0.5), inset 0 1px rgba(255,255,255,0.3), inset 0 12px rgba(255,255,255,0.15), inset 0 10px 20px rgba(255,255,255,0.25), inset 0 -15px 30px rgba(0,0,0,0.3); 71 | box-shadow: 0 2px 6px rgba(0,0,0,0.5), inset 0 1px rgba(255,255,255,0.3), inset 0 12px rgba(255,255,255,0.15), inset 0 10px 20px rgba(255,255,255,0.25), inset 0 -15px 30px rgba(0,0,0,0.3); 72 | } 73 | 74 | pre, style, textarea { 75 | padding:.3em .5em; 76 | margin-left: -.1em; 77 | border:2px solid rgba(255, 255, 255, .1); 78 | 79 | -webkit-box-shadow:.1em .1em .5em black inset; 80 | -moz-box-shadow:.1em .1em .5em black inset; 81 | box-shadow:.1em .1em .5em black inset; 82 | } 83 | 84 | textarea { 85 | width: 100%; 86 | 87 | -moz-box-sizing: border-box; 88 | box-sizing: border-box; 89 | } 90 | 91 | strong, b { 92 | font-weight:bold; 93 | } 94 | 95 | pre strong { 96 | text-shadow: 0 0 .6em white; 97 | } 98 | 99 | .slide { 100 | padding:0 2.5% 2%; 101 | background: rgba(0,0,0,.5); 102 | background-clip: padding-box; 103 | -moz-background-clip: padding-box; 104 | text-shadow:.05em .05em .1em rgba(0,0,0,.4); 105 | color: white; 106 | border:30px solid transparent; 107 | } 108 | 109 | .slide:target::before { 110 | background: rgba(255, 255, 255, .6); 111 | color: black; 112 | text-shadow: .03em .03em .1em white; 113 | } 114 | 115 | .slide h2 { 116 | font-family: 'Helvetica Neue', Helvetica, sans-serif; 117 | font-weight: 100; 118 | font-size: 1.2in; 119 | } 120 | 121 | .slide p, 122 | .slide li { 123 | font-weight: bold; 124 | letter-spacing: -.03em; 125 | } 126 | 127 | .slide > ul { 128 | list-style:none; 129 | } 130 | 131 | .slide ol { 132 | margin-left:2em; 133 | } 134 | 135 | .slide > ul ul { 136 | margin-left:2em; 137 | list-style: none; 138 | } 139 | 140 | .slide li li { 141 | font-size:80%; 142 | } 143 | 144 | .slide li { 145 | margin:.2em 0; 146 | } 147 | 148 | .slide > ul > li:before { 149 | content:'\2714'; 150 | color: #a0c12c; 151 | padding-right: .2em; 152 | } 153 | 154 | .slide li li:before { 155 | content: '\279C'; 156 | color: #28bcbc; 157 | padding-right: .2em; 158 | } 159 | 160 | section > header.slide { 161 | background-color: rgba(0,0,0,.8); 162 | } 163 | 164 | section > header.slide > h1 { 165 | position: absolute; 166 | top: 50%; 167 | left: 0; 168 | right: 0; 169 | margin-top: -.6em; 170 | font-size: 400%; 171 | line-height: 1; 172 | text-align: center; 173 | } 174 | 175 | .slide .emphasis { 176 | padding: .4em .5em .3em; 177 | margin: .3em 0; 178 | background: #f80; 179 | background: -webkit-gradient(linear, left top, left bottom, from(#fa0), to(#f80)); 180 | background: -moz-linear-gradient(#fa0, #f80); 181 | color: white; 182 | font-weight: bold; 183 | letter-spacing: -.05em; 184 | line-height: .85; 185 | text-shadow: .05em .05em .1em rgba(0,0,0,.4); 186 | 187 | -moz-border-radius: .3em; 188 | -webkit-border-radius: .3em; 189 | border-radius: .3em; 190 | 191 | -moz-box-shadow:.1em .1em .5em black; 192 | -webkit-box-shadow:.1em .1em .5em black; 193 | box-shadow:.1em .1em .5em black; 194 | } 195 | 196 | .light.slide .emphasis { 197 | -moz-box-shadow:.1em .1em .5em rgba(0,0,0,.4); 198 | -webkit-box-shadow:.1em .1em .5em rgba(0,0,0,.4); 199 | box-shadow:.1em .1em .5em rgba(0,0,0,.4); 200 | } 201 | 202 | .slide .emphasis::before { 203 | content: '\279C'; 204 | color: rgba(255,255,255,.5); 205 | float: left; 206 | width: .75em; 207 | height: 0; 208 | padding: .45em 0 .3em; 209 | margin: -.2em .2em 0 -.25em; 210 | border: .12em solid; 211 | text-align: center; 212 | line-height: 0; 213 | font-size: 120%; 214 | font-family: inherit; 215 | text-shadow: none; 216 | 217 | -moz-border-radius:999px; 218 | -webkit-border-radius:999px; 219 | border-radius:999px; 220 | 221 | -moz-transform: rotate(45deg); 222 | -o-transform: rotate(45deg); 223 | -webkit-transform: rotate(45deg); 224 | transform: rotate(45deg); 225 | } 226 | 227 | .attribution { 228 | background: rgba(0,0,0,.8); 229 | color: white; 230 | display: block; 231 | position: absolute; 232 | left: 0; 233 | right: 0; 234 | bottom: 1em; 235 | padding: .5em 1em; 236 | font-size: 30%; 237 | text-shadow: .05em .05em .1em black; 238 | } 239 | 240 | .attribution a { 241 | text-decoration: none; 242 | } 243 | 244 | .attribution a::after { 245 | content: ' (' attr(href) ')'; 246 | } 247 | 248 | -------------------------------------------------------------------------------- /test/color.js: -------------------------------------------------------------------------------- 1 | var expect = require('unexpected'); 2 | var libs = [ 3 | { 4 | name: 'index.js', 5 | lib: require('../'), 6 | }, 7 | ]; 8 | 9 | if (process.env.TEST_BUNDLES) { 10 | libs.push({ 11 | name: 'Bundle: one-color-all.js', 12 | lib: require('../one-color-all'), 13 | }); 14 | } 15 | 16 | var namedColorSamples = require('./samples'); 17 | 18 | var spaces = [ 19 | { 20 | name: 'RGB', 21 | channels: ['red', 'green', 'blue', 'alpha'], 22 | }, 23 | { 24 | name: 'HSV', 25 | channels: ['hue', 'saturation', 'value', 'alpha'], 26 | }, 27 | { 28 | name: 'HSL', 29 | channels: ['hue', 'saturation', 'lightness', 'alpha'], 30 | }, 31 | { 32 | name: 'CMYK', 33 | channels: ['cyan', 'magenta', 'yellow', 'black', 'alpha'], 34 | }, 35 | // { 36 | // name: 'XYZ', 37 | // channels: ['x', 'y', 'z', 'alpha'] 38 | // }, 39 | // { 40 | // name: 'LAB', 41 | // channels: ['l', 'a', 'b', 'alpha'] 42 | // } 43 | ]; 44 | 45 | function testLib(libConfig) { 46 | var color = libConfig.lib; 47 | 48 | describe(libConfig.name, function () { 49 | describe('Named colors', function () { 50 | Object.keys(namedColorSamples).forEach(function (namedColor) { 51 | var hex = namedColorSamples[namedColor].toLowerCase(); 52 | it('should parse ' + namedColor + ' as ' + hex, function () { 53 | return expect(color(namedColor).hex(), 'to be', hex); 54 | }); 55 | }); 56 | }); 57 | 58 | spaces.forEach(function (colorSpace) { 59 | describe(colorSpace.name, function () { 60 | var spaceName = colorSpace.name; 61 | 62 | it('should have a constructor function', function () { 63 | expect(color[spaceName], 'to be a function'); 64 | }); 65 | 66 | var clr = 67 | colorSpace.name === 'CMYK' 68 | ? new color[spaceName](1, 1, 1, 1, 1) 69 | : new color[spaceName](0, 0, 0, 1); 70 | 71 | it('should be constructed correctly', function () { 72 | expect(clr, 'to satisfy', { 73 | isColor: true, 74 | }); 75 | }); 76 | 77 | describe('color space conversion', function () { 78 | spaces.forEach(function (otherSpace) { 79 | it( 80 | 'should have a ' + otherSpace.name + ' conversion method', 81 | function () { 82 | var expected = {}; 83 | 84 | expected[otherSpace.name.toLowerCase()] = 85 | expect.it('to be a function'); 86 | 87 | expect(clr, 'to satisfy', expected); 88 | } 89 | ); 90 | 91 | it('should convert to ' + otherSpace.name, function () { 92 | var expected = { 93 | isColor: true, 94 | }; 95 | 96 | otherSpace.channels.forEach(function (channelName) { 97 | expected['_' + channelName] = expect.it('to be a number'); 98 | }); 99 | 100 | expect( 101 | clr[otherSpace.name.toLowerCase()](), 102 | 'to satisfy', 103 | expected 104 | ); 105 | 106 | // Awaiting unexpected patch 107 | // expect(clr[otherSpace.name.toLowerCase()](), 'to exhaustively satisfy', expected); 108 | }); 109 | }); 110 | }); 111 | 112 | describe('equality', function () { 113 | it('should have an equals method', function () { 114 | expect(clr, 'to satisfy', { 115 | equals: expect.it('to be a function').and('to have arity', 2), 116 | }); 117 | }); 118 | 119 | spaces.forEach(function (otherSpace) { 120 | it('should equal same color in ' + otherSpace.name, function () { 121 | if (otherSpace.name === 'CMYK') { 122 | expect( 123 | clr.equals(new color[otherSpace.name](1, 1, 1, 1, 1)), 124 | 'to be true' 125 | ); 126 | } else { 127 | expect( 128 | clr.equals(new color[otherSpace.name](0, 0, 0, 1)), 129 | 'to be true' 130 | ); 131 | } 132 | }); 133 | }); 134 | }); 135 | 136 | it('should convert to JSON', function () { 137 | var clr = new color[colorSpace.name]( 138 | Math.random(), 139 | Math.random(), 140 | Math.random(), 141 | Math.random(), 142 | Math.random() 143 | ); 144 | 145 | expect(clr.equals(color(clr.toJSON())), 'to be true'); 146 | }); 147 | 148 | describe('color channels', function () { 149 | colorSpace.channels.forEach(function (channel) { 150 | var shortHand = channel === 'black' ? 'k' : channel.charAt(0); 151 | 152 | describe(channel, function () { 153 | it('should have a "' + channel + '" method', function () { 154 | var expected = {}; 155 | 156 | expected[channel] = expect 157 | .it('to be a function') 158 | .and('to have arity', 2); 159 | 160 | expect(clr, 'to satisfy', expected); 161 | }); 162 | 163 | it( 164 | 'should have a "' + shortHand + '" shorthand method', 165 | function () { 166 | var expected = {}; 167 | 168 | expected[shortHand] = expect 169 | .it('to be a function') 170 | .and('to have arity', 2); 171 | 172 | expect(clr, 'to satisfy', expected); 173 | } 174 | ); 175 | 176 | it('should get the "' + channel + '" value', function () { 177 | expect( 178 | new color[colorSpace.name](0, 0, 0, 0, 0)[channel](), 179 | 'to be', 180 | 0 181 | ); 182 | }); 183 | 184 | it( 185 | 'should get the "' + 186 | channel + 187 | '" shorthand "' + 188 | shortHand + 189 | '" value', 190 | function () { 191 | expect( 192 | new color[colorSpace.name](0, 0, 0, 0, 0)[channel](), 193 | 'to be', 194 | 0 195 | ); 196 | } 197 | ); 198 | 199 | it('should set the "' + channel + '" value', function () { 200 | expect(clr[channel](0)[channel](), 'to be', 0); 201 | expect(clr[channel](0.5)[channel](), 'to be', 0.5); 202 | 203 | if (channel === 'hue') { 204 | // Hue is considered a circle, and thus has periodic boundary conditions 205 | expect(clr[channel](1)[channel](), 'to be', 0); 206 | expect(clr[channel](-0.1)[channel](), 'to be', 0.9); 207 | expect(clr[channel](1.5)[channel](), 'to be', 0.5); 208 | } else { 209 | expect(clr[channel](1)[channel](), 'to be', 1); 210 | expect(clr[channel](-0.1)[channel](), 'to be', 0); 211 | expect(clr[channel](1.1)[channel](), 'to be', 1); 212 | } 213 | }); 214 | 215 | it( 216 | 'should set the "' + 217 | channel + 218 | '" shorthand "' + 219 | shortHand + 220 | '" value', 221 | function () { 222 | expect(clr[shortHand](0)[channel](), 'to be', 0); 223 | expect(clr[shortHand](0.5)[channel](), 'to be', 0.5); 224 | 225 | if (channel === 'hue') { 226 | // Hue is considered a circle, and thus has periodic boundary conditions 227 | expect(clr[shortHand](1)[channel](), 'to be', 0); 228 | expect(clr[shortHand](-0.1)[channel](), 'to be', 0.9); 229 | expect(clr[shortHand](1.5)[channel](), 'to be', 0.5); 230 | } else { 231 | expect(clr[shortHand](1)[channel](), 'to be', 1); 232 | expect(clr[shortHand](-0.1)[channel](), 'to be', 0); 233 | expect(clr[shortHand](1.1)[channel](), 'to be', 1); 234 | } 235 | } 236 | ); 237 | 238 | it('should adjust the "' + channel + '" value', function () { 239 | expect( 240 | clr[channel](0)[channel](0.5, true)[channel](), 241 | 'to be', 242 | 0.5 243 | ); 244 | }); 245 | 246 | it( 247 | 'should adjust the "' + 248 | channel + 249 | '", shorthand "' + 250 | shortHand + 251 | '" value', 252 | function () { 253 | expect( 254 | clr[channel](0)[shortHand](0.5, true)[channel](), 255 | 'to be', 256 | 0.5 257 | ); 258 | } 259 | ); 260 | }); 261 | }); 262 | }); 263 | }); 264 | }); 265 | }); 266 | } 267 | 268 | libs.forEach(testLib); 269 | -------------------------------------------------------------------------------- /test/contrast.js: -------------------------------------------------------------------------------- 1 | var color = require('../'); 2 | 3 | var expect = require('unexpected').clone(); 4 | 5 | function contrast(color1, color2) { 6 | var contrast = color(color1).contrast(color(color2)); 7 | return Math.round(contrast * 100) / 100; 8 | } 9 | 10 | describe('contrast', function () { 11 | it('should return the contrast for colors', function () { 12 | expect(contrast('white', 'black'), 'to equal', 21); 13 | expect(contrast('white', 'red'), 'to equal', 4); 14 | expect(contrast('red', 'white'), 'to equal', 4); 15 | expect(contrast('005aff', 'eeeeee'), 'to equal', 4.63); 16 | expect(contrast('blue', 'blue'), 'to equal', 1); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/conversion.js: -------------------------------------------------------------------------------- 1 | var expect = require('unexpected'); 2 | var namedColorSamples = require('./samples'); 3 | var color = require('../'); 4 | var spaces = ['rgb', 'hsl', 'hsv', 'cmyk']; 5 | 6 | describe('conversion', function () { 7 | Object.keys(namedColorSamples).forEach(function (namedColor) { 8 | describe('with named color sample ' + namedColor, function () { 9 | var instance = color(namedColorSamples[namedColor]); 10 | spaces.forEach(function (space) { 11 | it('should convert to ' + space, function () { 12 | expect(instance[space]().hex(), 'to equal', instance.hex()); 13 | }); 14 | }); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/grayscale.js: -------------------------------------------------------------------------------- 1 | var color = require('../'); 2 | 3 | var expect = require('unexpected').clone(); 4 | 5 | describe('grayscale', function () { 6 | it('should convert a non-gray to a shade of gray', function () { 7 | expect(color('#550022').grayscale().hex(), 'to equal', '#1d1d1d'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /test/isDark.js: -------------------------------------------------------------------------------- 1 | var color = require('../'); 2 | 3 | var expect = require('unexpected').clone(); 4 | 5 | describe('isDark', function () { 6 | it('should return true, if the color is dark', function () { 7 | expect(color('black').isDark(), 'to equal', true); 8 | expect(color('white').isDark(), 'to equal', false); 9 | expect(color('blue').isDark(), 'to equal', true); 10 | expect(color('darkgreen').isDark(), 'to equal', true); 11 | expect(color('pink').isDark(), 'to equal', false); 12 | expect(color('goldenrod').isDark(), 'to equal', false); 13 | expect(color('red').isDark(), 'to equal', true); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/isLight.js: -------------------------------------------------------------------------------- 1 | var color = require('../'); 2 | 3 | var expect = require('unexpected').clone(); 4 | 5 | describe('isLight', function () { 6 | it('should return true, if the color is light', function () { 7 | expect(color('black').isLight(), 'to equal', false); 8 | expect(color('white').isLight(), 'to equal', true); 9 | expect(color('blue').isLight(), 'to equal', false); 10 | expect(color('darkgreen').isLight(), 'to equal', false); 11 | expect(color('pink').isLight(), 'to equal', true); 12 | expect(color('goldenrod').isLight(), 'to equal', true); 13 | expect(color('red').isLight(), 'to equal', false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/luminance.js: -------------------------------------------------------------------------------- 1 | var color = require('../'); 2 | 3 | var expect = require('unexpected').clone(); 4 | 5 | describe('luminance', function () { 6 | it('should return the luminance for colors', function () { 7 | expect(color('white').luminance(), 'to equal', 1); 8 | expect(color('black').luminance(), 'to equal', 0); 9 | expect(color('ff0000').luminance(), 'to equal', 0.2126); 10 | expect(color('00ff00').luminance(), 'to equal', 0.7152); 11 | expect(color('0000ff').luminance(), 'to equal', 0.0722); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /test/mix.js: -------------------------------------------------------------------------------- 1 | var color = require('../'); 2 | 3 | var expect = require('unexpected').clone(); 4 | 5 | describe('mix', function () { 6 | it('black and white 50% mix should be gray', function () { 7 | expect(color('white').mix('black').hex(), 'to equal', '#808080'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /test/parse.js: -------------------------------------------------------------------------------- 1 | var color = require('../'); 2 | var expect = require('unexpected').clone(); 3 | 4 | expect.addAssertion( 5 | ' to be a color instance', 6 | function (expect, subject) { 7 | expect(subject, 'to satisfy', { isColor: true }); 8 | } 9 | ); 10 | 11 | describe('parsing', function () { 12 | describe('when parsing cmyk example from https://github.com/One-com/one-color/issues/25', function () { 13 | expect( 14 | color('cmyk(1.95468%,3.82086%,5.06294%,11.3802%)'), 15 | 'to be a color instance' 16 | ); 17 | }); 18 | 19 | describe('when parsing white cmyk', function () { 20 | var instance = color('cmyk(0%,0%,0%,0%)'); 21 | 22 | it('should return a color instance', function () { 23 | expect(instance, 'to be a color instance'); 24 | }); 25 | 26 | it('should be white', function () { 27 | expect(instance.hex(), 'to equal', '#ffffff'); 28 | }); 29 | }); 30 | 31 | describe('when parsing black cmyk', function () { 32 | var instance = color('cmyk(100%,100%,100%,100%)'); 33 | 34 | it('should return a color instance', function () { 35 | expect(instance, 'to be a color instance'); 36 | }); 37 | 38 | it('should be black', function () { 39 | expect(instance.hex(), 'to equal', '#000000'); 40 | }); 41 | }); 42 | 43 | describe('with invalid strings', function () { 44 | it('should refuse a percentage > 100', function () { 45 | expect(color('cmyk(100.1%,100%,100%,100%)'), 'to be false'); 46 | }); 47 | 48 | it('should refuse to parse a non-percentage', function () { 49 | expect(color('cmyk(100,100%,100%,100%)'), 'to be false'); 50 | }); 51 | 52 | it('should refuse to parse less than 4 channels', function () { 53 | expect(color('cmyk(100,100%,100%)'), 'to be false'); 54 | }); 55 | }); 56 | 57 | describe('with #rrggbbaa', function () { 58 | var instance = color('#00ff0080'); 59 | 60 | it('should return a color instance', function () { 61 | expect(instance, 'to be a color instance'); 62 | }); 63 | 64 | it('should be green', function () { 65 | expect(instance.hex(), 'to equal', '#00ff00'); 66 | }); 67 | 68 | it('should have its alpha channel set correctly', function () { 69 | expect(instance.alpha().toFixed(2), 'to equal', '0.50'); 70 | }); 71 | }); 72 | 73 | describe('with #rgba', function () { 74 | var instance = color('#0f08'); 75 | 76 | it('should return a color instance', function () { 77 | expect(instance, 'to be a color instance'); 78 | }); 79 | 80 | it('should be green', function () { 81 | expect(instance.hex(), 'to equal', '#00ff00'); 82 | }); 83 | 84 | it('should have its alpha channel set correctly', function () { 85 | expect(instance.alpha().toFixed(2), 'to equal', '0.53'); 86 | }); 87 | }); 88 | 89 | describe('with rgb(r, g, b)', function () { 90 | var instance = color('rgb(10, 20, 30)'); 91 | 92 | it('should return a color instance', function () { 93 | expect(instance, 'to be a color instance'); 94 | }); 95 | 96 | it('should be green', function () { 97 | expect(instance.hex(), 'to equal', '#0a141e'); 98 | }); 99 | }); 100 | 101 | describe('with rgb(r,g,b)', function () { 102 | var instance = color('rgb(10,20,30)'); 103 | 104 | it('should return a color instance', function () { 105 | expect(instance, 'to be a color instance'); 106 | }); 107 | 108 | it('should be green', function () { 109 | expect(instance.hex(), 'to equal', '#0a141e'); 110 | }); 111 | }); 112 | 113 | describe('with rgb(r g b)', function () { 114 | var instance = color('rgb(10 20 30)'); 115 | 116 | it('should return a color instance', function () { 117 | expect(instance, 'to be a color instance'); 118 | }); 119 | 120 | it('should be green', function () { 121 | expect(instance.hex(), 'to equal', '#0a141e'); 122 | }); 123 | }); 124 | 125 | describe('with rgba(r g b / a)', function () { 126 | var instance = color('rgba(10 20 30 / 50%)'); 127 | 128 | it('should return a color instance', function () { 129 | expect(instance, 'to be a color instance'); 130 | }); 131 | 132 | it('should be green', function () { 133 | expect(instance.hex(), 'to equal', '#0a141e'); 134 | }); 135 | 136 | it('should have its alpha channel set correctly', function () { 137 | expect(instance.alpha().toFixed(2), 'to equal', '0.50'); 138 | }); 139 | }); 140 | 141 | describe('with rgba(r g b/a)', function () { 142 | var instance = color('rgba(10 20 30/50%)'); 143 | 144 | it('should return a color instance', function () { 145 | expect(instance, 'to be a color instance'); 146 | }); 147 | 148 | it('should be green', function () { 149 | expect(instance.hex(), 'to equal', '#0a141e'); 150 | }); 151 | 152 | it('should have its alpha channel set correctly', function () { 153 | expect(instance.alpha().toFixed(2), 'to equal', '0.50'); 154 | }); 155 | }); 156 | 157 | describe('with rgba(r, g, b, a)', function () { 158 | var instance = color('rgba(10, 20, 30, 0.5)'); 159 | 160 | it('should return a color instance', function () { 161 | expect(instance, 'to be a color instance'); 162 | }); 163 | 164 | it('should be green', function () { 165 | expect(instance.hex(), 'to equal', '#0a141e'); 166 | }); 167 | 168 | it('should have its alpha channel set correctly', function () { 169 | expect(instance.alpha().toFixed(2), 'to equal', '0.50'); 170 | }); 171 | }); 172 | 173 | describe('with hsl(h s l) and the hue given as a percentage', function () { 174 | var instance = color('hsl(10% 20% 30%)'); 175 | 176 | it('should return a color instance', function () { 177 | expect(instance, 'to be a color instance'); 178 | }); 179 | 180 | it('should be green', function () { 181 | expect(instance.hex(), 'to equal', '#5c503d'); 182 | }); 183 | }); 184 | 185 | describe('with hsl(h s l) and the hue given as an angle', function () { 186 | var instance = color('hsl(10deg 20% 30%)'); 187 | 188 | it('should return a color instance', function () { 189 | expect(instance, 'to be a color instance'); 190 | }); 191 | 192 | it('should be green', function () { 193 | expect(instance.hex(), 'to equal', '#5c423d'); 194 | }); 195 | }); 196 | }); 197 | -------------------------------------------------------------------------------- /test/samples.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | AliceBlue: '#F0F8FF', 3 | AntiqueWhite: '#FAEBD7', 4 | Aqua: '#00FFFF', 5 | Aquamarine: '#7FFFD4', 6 | Azure: '#F0FFFF', 7 | Beige: '#F5F5DC', 8 | Bisque: '#FFE4C4', 9 | Black: '#000000', 10 | BlanchedAlmond: '#FFEBCD', 11 | Blue: '#0000FF', 12 | BlueViolet: '#8A2BE2', 13 | Brown: '#A52A2A', 14 | BurlyWood: '#DEB887', 15 | CadetBlue: '#5F9EA0', 16 | Chartreuse: '#7FFF00', 17 | Chocolate: '#D2691E', 18 | Coral: '#FF7F50', 19 | CornflowerBlue: '#6495ED', 20 | Cornsilk: '#FFF8DC', 21 | Crimson: '#DC143C', 22 | Cyan: '#00FFFF', 23 | DarkBlue: '#00008B', 24 | DarkCyan: '#008B8B', 25 | DarkGoldenRod: '#B8860B', 26 | DarkGray: '#A9A9A9', 27 | DarkGrey: '#A9A9A9', 28 | DarkGreen: '#006400', 29 | DarkKhaki: '#BDB76B', 30 | DarkMagenta: '#8B008B', 31 | DarkOliveGreen: '#556B2F', 32 | Darkorange: '#FF8C00', 33 | DarkOrchid: '#9932CC', 34 | DarkRed: '#8B0000', 35 | DarkSalmon: '#E9967A', 36 | DarkSeaGreen: '#8FBC8F', 37 | DarkSlateBlue: '#483D8B', 38 | DarkSlateGray: '#2F4F4F', 39 | DarkSlateGrey: '#2F4F4F', 40 | DarkTurquoise: '#00CED1', 41 | DarkViolet: '#9400D3', 42 | DeepPink: '#FF1493', 43 | DeepSkyBlue: '#00BFFF', 44 | DimGray: '#696969', 45 | DimGrey: '#696969', 46 | DodgerBlue: '#1E90FF', 47 | FireBrick: '#B22222', 48 | FloralWhite: '#FFFAF0', 49 | ForestGreen: '#228B22', 50 | Fuchsia: '#FF00FF', 51 | Gainsboro: '#DCDCDC', 52 | GhostWhite: '#F8F8FF', 53 | Gold: '#FFD700', 54 | GoldenRod: '#DAA520', 55 | Gray: '#808080', 56 | Grey: '#808080', 57 | Green: '#008000', 58 | GreenYellow: '#ADFF2F', 59 | HoneyDew: '#F0FFF0', 60 | HotPink: '#FF69B4', 61 | Ivory: '#FFFFF0', 62 | Khaki: '#F0E68C', 63 | Lavender: '#E6E6FA', 64 | LavenderBlush: '#FFF0F5', 65 | LawnGreen: '#7CFC00', 66 | LemonChiffon: '#FFFACD', 67 | LightBlue: '#ADD8E6', 68 | LightCoral: '#F08080', 69 | LightCyan: '#E0FFFF', 70 | LightGoldenRodYellow: '#FAFAD2', 71 | LightGray: '#D3D3D3', 72 | LightGrey: '#D3D3D3', 73 | LightGreen: '#90EE90', 74 | LightPink: '#FFB6C1', 75 | LightSalmon: '#FFA07A', 76 | LightSeaGreen: '#20B2AA', 77 | LightSkyBlue: '#87CEFA', 78 | LightSlateGray: '#778899', 79 | LightSlateGrey: '#778899', 80 | LightSteelBlue: '#B0C4DE', 81 | LightYellow: '#FFFFE0', 82 | Lime: '#00FF00', 83 | LimeGreen: '#32CD32', 84 | Linen: '#FAF0E6', 85 | Magenta: '#FF00FF', 86 | Maroon: '#800000', 87 | MediumAquaMarine: '#66CDAA', 88 | MediumBlue: '#0000CD', 89 | MediumOrchid: '#BA55D3', 90 | MediumPurple: '#9370D8', 91 | MediumSeaGreen: '#3CB371', 92 | MediumSlateBlue: '#7B68EE', 93 | MediumSpringGreen: '#00FA9A', 94 | MediumTurquoise: '#48D1CC', 95 | MediumVioletRed: '#C71585', 96 | MidnightBlue: '#191970', 97 | MintCream: '#F5FFFA', 98 | MistyRose: '#FFE4E1', 99 | Moccasin: '#FFE4B5', 100 | NavajoWhite: '#FFDEAD', 101 | Navy: '#000080', 102 | OldLace: '#FDF5E6', 103 | Olive: '#808000', 104 | OliveDrab: '#6B8E23', 105 | Orange: '#FFA500', 106 | OrangeRed: '#FF4500', 107 | Orchid: '#DA70D6', 108 | PaleGoldenRod: '#EEE8AA', 109 | PaleGreen: '#98FB98', 110 | PaleTurquoise: '#AFEEEE', 111 | PaleVioletRed: '#D87093', 112 | PapayaWhip: '#FFEFD5', 113 | PeachPuff: '#FFDAB9', 114 | Peru: '#CD853F', 115 | Pink: '#FFC0CB', 116 | Plum: '#DDA0DD', 117 | PowderBlue: '#B0E0E6', 118 | Purple: '#800080', 119 | Red: '#FF0000', 120 | RosyBrown: '#BC8F8F', 121 | RoyalBlue: '#4169E1', 122 | SaddleBrown: '#8B4513', 123 | Salmon: '#FA8072', 124 | SandyBrown: '#F4A460', 125 | SeaGreen: '#2E8B57', 126 | SeaShell: '#FFF5EE', 127 | Sienna: '#A0522D', 128 | Silver: '#C0C0C0', 129 | SkyBlue: '#87CEEB', 130 | SlateBlue: '#6A5ACD', 131 | SlateGray: '#708090', 132 | SlateGrey: '#708090', 133 | Snow: '#FFFAFA', 134 | SpringGreen: '#00FF7F', 135 | SteelBlue: '#4682B4', 136 | Tan: '#D2B48C', 137 | Teal: '#008080', 138 | Thistle: '#D8BFD8', 139 | Tomato: '#FF6347', 140 | Turquoise: '#40E0D0', 141 | Violet: '#EE82EE', 142 | Wheat: '#F5DEB3', 143 | White: '#FFFFFF', 144 | WhiteSmoke: '#F5F5F5', 145 | Yellow: '#FFFF00', 146 | YellowGreen: '#9ACD32', 147 | }; 148 | --------------------------------------------------------------------------------