├── .gitignore ├── .zuul.yml ├── .travis.yml ├── index.html ├── style.css ├── test ├── house.js └── fixtures │ ├── house_expected_eventstream.json │ └── house.json ├── package.json ├── LICENSE ├── event_stream.js ├── readme.markdown ├── index.js └── svg-sketch.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.zuul.yml: -------------------------------------------------------------------------------- 1 | ui: tape 2 | capabilities: 3 | record-video: false 4 | video-upload-on-pass: false 5 | record-screenshots: false 6 | tunnel: 7 | type: ngrok 8 | bind_tls: true 9 | browsers: 10 | - name: microsoftedge 11 | version: latest 12 | - name: firefox 13 | version: latest 14 | - name: safari 15 | version: latest 16 | - name: chrome 17 | version: latest 18 | - name: iphone 19 | version: latest 20 | - name: android 21 | version: latest 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | bundler_args: --retry 4 4 | node_js: 5 | - '5.5.0' 6 | script: 7 | travis_retry npm run test-browsers 8 | env: 9 | global: 10 | - secure: WBPZcGHOX0dp0KSDgOdYhm0peisSB1A0QAEv2juykSjJV8wOy9LoS9TxdpjZHVMAGY5ybIGpb+0EKcMcHQZjE4k2SrAmMaE87Oqiwf1uaWeEZaiV+OrSH2CzVyLTLAIHhVld3F4BpV0FWPoFfABgmxFC0Qdr4WdfuchCJ7X9ru4= 11 | - secure: V+wQdTNbTBv1qkynGPsserTL1WLIcqHiCffV1zcHrBzWS6oSH9gYUS5I7w2iXiQTFLotcVshm4+EwfAUCZtfMTv2ZkeTT1arPPQJL+P1EbLlyXrXaBIkY3ZYegJqmsDN4EO0+i60KEvdFwi9HH8fdgZYUiJWs23a6TqupRX3Zpk= 12 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | .svg-widget { 2 | height: 100%; 3 | } 4 | 5 | .svg-widget .grid { 6 | border: solid 2px #F7F8A6; 7 | } 8 | 9 | .svg-widget svg *:not(.grid):not(text):not(tspan) { 10 | stroke-width: 1px; 11 | } 12 | 13 | .svg-widget svg text { 14 | stroke-width: 0; 15 | fill: none; 16 | margin: 0; 17 | padding: 0; 18 | } 19 | 20 | .svg-widget svg[data-control=move] *:not(.grid):hover, 21 | .svg-widget svg[data-control=rubber] *:not(.grid):hover { 22 | cursor: move; 23 | stroke-width: 2px; 24 | } 25 | 26 | .svg-widget svg[data-control=text] text:hover { 27 | cursor: pointer; 28 | } 29 | 30 | .svg-widget .anchor { 31 | display: none; 32 | } 33 | 34 | .svg-widget svg[data-control=move] .anchor, 35 | .svg-widget svg[data-control=text] .anchor, 36 | .svg-widget svg[data-control=rubber] .anchor { 37 | fill: rgba(213, 236, 24, 0.2); 38 | stroke: rgb(14, 14, 14); 39 | display: block; 40 | } 41 | -------------------------------------------------------------------------------- /test/house.js: -------------------------------------------------------------------------------- 1 | // phantomjs it's 2014 and still no bind :( 2 | var fp = Function.prototype 3 | fp.bind = fp.bind || require('function-bind') 4 | 5 | // setup svg dom 6 | var svg = require('../')() 7 | var controls = require('svg-sketch-controls') 8 | var test = require('tape') 9 | 10 | svg.appendTo(document.body) 11 | svg.el.setAttribute('height', '600px') 12 | svg.el.setAttribute('width', '600px') 13 | 14 | Object.keys(controls).forEach(registerControl) 15 | 16 | function registerControl (key) { 17 | svg.registerControl(key, controls[key](svg.el)) 18 | } 19 | 20 | // allow running test in all screen sizes with predefined xy 21 | controls.control.prototype.xy = function fixedXy (e) { 22 | return [e.pageX, e.pageY] 23 | } 24 | 25 | test('draw a house', function (t) { 26 | var moves = require('./fixtures/house') 27 | var expected = require('./fixtures/house_expected_eventstream') 28 | window.prompt = function () { return 'maison' } 29 | 30 | moves.forEach(draw) 31 | 32 | function draw (item) { 33 | svg.setControl(item[1]) 34 | svg[item[0]]({preventDefault: Function, pageX: item[2], pageY: item[3]}) 35 | } 36 | 37 | process.nextTick(function () { 38 | t.deepEqual(svg.eventStream.toJSON(), expected) 39 | t.end() 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svg-sketch", 3 | "description": "svg widget", 4 | "keywords": "svg sketch json", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/jameskyburz/svg-sketch" 8 | }, 9 | "author": { 10 | "name": "James Kyburz", 11 | "email": "james.kyburz@gmail.com" 12 | }, 13 | "browserify": { 14 | "transform": [ 15 | "brfs" 16 | ] 17 | }, 18 | "main": "index.js", 19 | "version": "1.4.32", 20 | "scripts": { 21 | "test": "zuul test/*.js --phantom | faucet", 22 | "test-browsers": "remove-saucelabs-jobs-by-build && zuul test/*.js", 23 | "build": "browserify -s SvgSketch -e ./ | uglifyjs -c warnings=false -m > svg-sketch.min.js", 24 | "prepublish": "standard" 25 | }, 26 | "files": [ 27 | "event_stream.js", 28 | "index.html", 29 | "index.js", 30 | "style.css" 31 | ], 32 | "dependencies": { 33 | "brfs": "1.4.3", 34 | "color": "0.11.4", 35 | "hyperglue": "2.0.1", 36 | "inherits": "2.0.3", 37 | "insert-css": "0.1.0", 38 | "shallow-copy": "0.0.1", 39 | "xtend": "4.0.1" 40 | }, 41 | "devDependencies": { 42 | "faucet": "0.0.1", 43 | "function-bind": "1.1.0", 44 | "remove-saucelabs-jobs-by-build": "1.0.19", 45 | "standard": "10.0.2", 46 | "svg-sketch-controls": "1.0.15", 47 | "tape": "4.6.3", 48 | "zuul": "3.11.1", 49 | "zuul-ngrok": "4.0.0" 50 | }, 51 | "license": "MIT" 52 | } 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014, James Kyburz (the "Original Author") 2 | All rights reserved. 3 | 4 | MIT +no-false-attribs License 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the "Software"), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | Distributions of all or part of the Software intended to be used 19 | by the recipients as they would use the unmodified Software, 20 | containing modifications that substantially alter, remove, or 21 | disable functionality of the Software, outside of the documented 22 | configuration mechanisms provided by the Software, shall be 23 | modified such that the Original Author's bug reporting email 24 | addresses and urls are either replaced with the contact information 25 | of the parties responsible for the changes, or removed entirely. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 28 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 29 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 30 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 31 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 32 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 33 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 34 | OTHER DEALINGS IN THE SOFTWARE. 35 | 36 | 37 | Except where noted, this license applies to any and all software 38 | programs and associated documentation files created by the 39 | Original Author, when distributed with the Software. 40 | -------------------------------------------------------------------------------- /event_stream.js: -------------------------------------------------------------------------------- 1 | var copy = require('shallow-copy') 2 | var xtend = require('xtend') 3 | var Color = require('color') 4 | 5 | module.exports = EventStream 6 | 7 | EventStream.validEvent = validEvent 8 | 9 | function EventStream () { 10 | if (!(this instanceof EventStream)) return new EventStream() 11 | this.events = [] 12 | } 13 | 14 | EventStream.prototype.push = function push (event) { 15 | var value = this.events.push(event) 16 | return value 17 | } 18 | 19 | EventStream.prototype.pop = function pop () { 20 | var value = this.events.pop() 21 | return value 22 | } 23 | 24 | EventStream.prototype.toJSON = function toJSON () { 25 | var self = this 26 | var lastType 27 | this.normalized = this.events.map(createEvent) 28 | this.normalized.forEach(processPath) 29 | 30 | return this.normalized.reduce( 31 | reduce, 32 | [] 33 | ) 34 | 35 | function createEvent (event) { 36 | var args = copy(event.args) 37 | if (args) { 38 | ;['stroke', 'fill'].forEach(function setRgb (key) { 39 | if (args[key]) args[key] = Color(args[key]).rgbaString() 40 | }) 41 | } 42 | return { 43 | type: event.type, 44 | id: event.id, 45 | args: args, 46 | layout: event.layout, 47 | pathId: event.path ? event.path.id : undefined 48 | } 49 | } 50 | 51 | function processPath (event) { 52 | if (event.pathId) { 53 | var path = self.normalized.filter(findById)[0] 54 | if (path) { 55 | event.deleted = true 56 | path.args = xtend(path.args, event.args) 57 | path.deleted = event.type === 'delete' 58 | } 59 | } 60 | 61 | function findById (e) { 62 | return e.id === event.pathId 63 | } 64 | } 65 | 66 | function reduce (result, event) { 67 | if (event.type === 'style' && lastType === 'style') result.pop() 68 | if (validEvent(event)) { 69 | lastType = event.type 70 | result.push( 71 | ['type', 'args', 'layout'].reduce(copyEvent, {}) 72 | ) 73 | return result 74 | } 75 | 76 | function copyEvent (result, key) { 77 | if (event[key]) { 78 | result[key] = event[key] 79 | } 80 | return result 81 | } 82 | return result 83 | } 84 | } 85 | 86 | function validEvent (event) { 87 | if (event.deleted) return false 88 | 89 | if (event.type === 'text') { 90 | return !!event.args.value 91 | } 92 | 93 | if (event.type === 'path') { 94 | return !!event.args.d.match(/a|l/i) 95 | } 96 | 97 | return Object.keys(event.args || {}).length + 98 | Object.keys(event.layout || {}).length > 0 99 | } 100 | -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | # svg-sketch 2 | 3 | svg widget with built in json eventstream 4 | 5 | svg -> json -> what ever FTW 6 | 7 | [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) 8 | 9 | [![build status](https://api.travis-ci.org/JamesKyburz/svg-sketch.svg)](http://travis-ci.org/JamesKyburz/svg-sketch) 10 | 11 | [![Sauce Test Status](https://saucelabs.com/browser-matrix/svg-sketch.svg)](https://saucelabs.com/u/svg-sketch) 12 | 13 | Try it out! [![view on requirebin](http://requirebin.com/badge.png)](http://requirebin.com/?gist=0dc5356985194d0b8466) 14 | 15 | use with [browserify](http://browserify.org) 16 | 17 | # methods 18 | 19 | ``` js 20 | var sketch = require('svg-sketch') 21 | ``` 22 | 23 | ## `sketch([opts={}])` 24 | 25 | Returns a new sketch instance. 26 | 27 | `opts` is optional 28 | 29 | `opts.anchor` is used for move, delete operations and to easily click on 30 | text elements 31 | 32 | If you want anchors to appear then there are the options (they help with deleting and moving elements) :- 33 | 34 | * `opts.anchor.size` size of anchor (default is 14px) 35 | 36 | * `opts.anchor.exclude` regex checked for a falsy value, used to determine when to remove anchor elements. (default is `/undo|redo|grid/`) 37 | 38 | * `opts.anchor.include` regex checked for a truthy value, used to determine when to show anchor elements. (default is `/rubber|move|text/`) 39 | 40 | * `opts.anchor.position` optional function to determine the xy position of a svg shape. 41 | 42 | ## sketch.appendTo(el) 43 | 44 | append svg element to element 45 | 46 | ## sketch.registerControl() 47 | 48 | register drawing control 49 | 50 | ## sketch.remove() 51 | 52 | remove svg element and event listeners 53 | 54 | ## sketch.setEvents(events) 55 | 56 | set drawing events data 57 | 58 | ## sketch.setControl(control) 59 | 60 | set which control is currently being used 61 | 62 | ## sketch.resize(width, height) 63 | 64 | set viewport to width and height 65 | 66 | ## sketch.setColor(color) 67 | 68 | set current drawing color in hex or rgb 69 | 70 | ## sketch.setStyle(style) 71 | 72 | ## sketch.setGridStyle(style) 73 | 74 | override grid style used 75 | 76 | ## svg.setClipboard(json) 77 | 78 | clipboard context for widget used by paste. 79 | 80 | ## svg.copy() 81 | 82 | save eventStream json and emit `copy` event 83 | 84 | ## svg.cut 85 | 86 | save eventStream json, remove drawing and emit `copy` event 87 | 88 | ## svg.paste(e) 89 | 90 | paste copied eventStream to drawing 91 | if `e` contains clipboard data used that instead of local copied eventStream. 92 | 93 | # events 94 | 95 | ## svg.changeControl(name) 96 | 97 | ## svg.changeColor(color) 98 | 99 | ## svg.changeStyle(style) 100 | 101 | ## svg.eventStream(events) 102 | 103 | complete json structure for drawing 104 | 105 | ## svg.copy 106 | 107 | emitted when drawing copied 108 | 109 | ## svg.drawing 110 | 111 | emitted when interacting with drawing 112 | 113 | # install 114 | 115 | With [npm](https://npmjs.org) do: 116 | 117 | ``` 118 | npm install svg-sketch 119 | ``` 120 | 121 | # test 122 | 123 | ``` 124 | npm test 125 | ``` 126 | 127 | # license 128 | 129 | MIT 130 | -------------------------------------------------------------------------------- /test/fixtures/house_expected_eventstream.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "args": { 4 | "x": 219, 5 | "y": 162, 6 | "width": 151, 7 | "height": 101 8 | }, 9 | "type": "rect" 10 | }, 11 | { 12 | "args": { 13 | "d": "M 296,100 L 218,163" 14 | }, 15 | "type": "path" 16 | }, 17 | { 18 | "args": { 19 | "d": "M 296,101 L 370,162" 20 | }, 21 | "type": "path" 22 | }, 23 | { 24 | "args": { 25 | "d": "M 150,341 L 150,340 L 151,340 L 151,339 L 151,339 L 151,338 L 152,337 L 153,337 L 153,336 L 154,336 L 154,335 L 155,335 L 155,334 L 156,334 L 157,334 L 158,334 L 158,333 L 159,333 L 160,333 L 161,333 L 162,333 L 163,333 L 163,332 L 164,332 L 165,332 L 165,331 L 166,331 L 166,330 L 167,329 L 168,329 L 168,328 L 169,328 L 170,328 L 171,328 L 171,327 L 172,327 L 173,327 L 174,327 L 174,327 L 175,327 L 176,327 L 177,327 L 178,326 L 179,326 L 179,326 L 180,326 L 181,326 L 181,325 L 182,325 L 183,325 L 183,324 L 187,322 L 188,322 L 189,321 L 190,320 L 191,320 L 191,319 L 192,319 L 192,318 L 193,318 L 194,317 L 195,317 L 195,316 L 196,316 L 197,316 L 198,316 L 199,316 L 199,315 L 200,315 L 201,315 L 202,315 L 202,314 L 203,314 L 204,314 L 205,313 L 206,313 L 206,312 L 207,312 L 208,312 L 208,311 L 209,311 L 209,310 L 210,310 L 211,310 L 211,309 L 212,308 L 216,306 L 220,305 L 221,304 L 222,304 L 223,304 L 223,303 L 224,303 L 225,303 L 226,303 L 227,303 L 227,302 L 228,302 L 229,302 L 229,301 L 230,301 L 230,300 L 231,300 L 231,299 L 232,299 L 232,298 L 233,298 L 233,297 L 234,297 L 235,297 L 235,296 L 236,296 L 237,296 L 237,295 L 238,295 L 238,294 L 239,294 L 240,294 L 240,293 L 241,293 L 241,292 L 242,292 L 242,291 L 243,291 L 243,290 L 244,290 L 244,289 L 245,289 L 246,289 L 246,288 L 246,288 L 247,288 L 247,287 L 249,287 L 249,286 L 250,286 L 251,286 L 251,286 L 252,286 L 252,286 L 252,284 L 253,284 L 254,284 L 254,283 L 255,283 L 255,282 L 256,282 L 256,282 L 257,282 L 257,281 L 258,281 L 259,281 L 259,280 L 260,280 L 261,280 L 261,280 L 262,280 L 263,280 L 263,279 L 264,279 L 264,278 L 265,278 L 265,277 L 266,277 L 267,276 L 268,276 L 268,275 L 269,275 L 269,274 L 270,274 L 270,273 L 271,273 L 271,272 L 272,272 L 273,272 L 273,271 L 274,271 L 274,270 L 275,270 L 275,269 L 275,268 L 276,268 L 276,267 L 277,267 L 277,266 L 278,266 L 278,265 L 279,265 L 280,265 L 280,264" 26 | }, 27 | "type": "path" 28 | }, 29 | { 30 | "args": { 31 | "d": "M 197,347 L 198,346 L 199,346 L 200,346 L 200,345 L 201,345 L 201,344 L 202,344 L 203,342 L 203,342 L 204,341 L 205,341 L 206,341 L 207,341 L 207,340 L 208,340 L 209,340 L 210,340 L 210,339 L 210,339 L 211,339 L 211,338 L 212,338 L 213,338 L 217,337 L 218,336 L 219,336 L 219,336 L 220,336 L 221,336 L 222,335 L 223,335 L 224,335 L 225,335 L 225,334 L 226,334 L 226,334 L 228,334 L 231,332 L 235,331 L 239,330 L 240,329 L 241,329 L 241,328 L 242,328 L 243,328 L 244,327 L 245,327 L 245,326 L 246,326 L 246,325 L 247,325 L 248,324 L 249,324 L 249,323 L 250,323 L 251,323 L 252,323 L 252,322 L 253,322 L 253,321 L 253,321 L 253,320 L 254,320 L 254,319 L 255,319 L 256,318 L 257,318 L 258,317 L 259,317 L 259,316 L 260,316 L 260,315 L 261,315 L 262,315 L 262,314 L 263,314 L 263,314 L 264,314 L 264,313 L 265,313 L 265,312 L 266,312 L 267,311 L 267,310 L 268,310 L 268,310 L 269,310 L 269,309 L 270,309 L 271,307 L 272,306 L 273,306 L 273,305 L 274,305 L 274,304 L 275,304 L 275,303 L 276,303 L 276,303 L 277,303 L 277,302 L 278,302 L 278,301 L 279,301 L 280,300 L 281,299 L 282,299 L 282,298 L 283,298 L 284,297 L 285,297 L 285,296 L 285,296 L 285,295 L 286,295 L 286,294 L 287,294 L 287,293 L 289,293 L 289,292 L 289,292 L 289,291 L 289,290 L 290,290 L 290,289 L 291,289 L 291,288 L 292,287 L 292,286 L 293,286 L 294,285 L 295,284 L 296,284 L 296,283 L 297,283 L 297,283 L 298,283 L 298,282 L 299,282 L 299,280 L 300,280 L 300,280 L 300,280 L 300,279 L 301,279 L 301,278 L 302,278 L 302,278 L 303,278 L 303,277 L 304,277 L 304,276 L 305,276 L 305,275 L 306,275 L 306,274 L 307,274 L 307,273 L 308,272 L 308,271 L 309,271 L 309,270 L 309,269 L 310,269 L 310,268 L 310,267 L 310,266 L 311,266 L 311,265 L 312,265 L 312,264" 32 | }, 33 | "type": "path" 34 | }, 35 | { 36 | "args": { 37 | "x": 285, 38 | "y": 233, 39 | "width": 23, 40 | "height": 30 41 | }, 42 | "type": "rect" 43 | }, 44 | { 45 | "args": { 46 | "x": 228, 47 | "y": 170, 48 | "width": 28, 49 | "height": 27 50 | }, 51 | "type": "rect" 52 | }, 53 | { 54 | "args": { 55 | "x": 337, 56 | "y": 169, 57 | "width": 27, 58 | "height": 28 59 | }, 60 | "type": "rect" 61 | }, 62 | { 63 | "args": { 64 | "d": "M 407,130 L 407,131 L 408,131 L 408,132 L 409,132 L 410,132 L 410,133 L 411,133 L 412,133 L 412,134 L 413,134 L 414,134 L 415,134 L 416,134 L 417,134 L 418,134 L 419,134 L 420,134 L 421,134 L 422,134 L 422,133 L 423,133 L 424,133 L 424,132 L 425,132 L 425,131 L 426,131 L 426,130 L 427,130 L 427,129 L 427,128 L 428,128 L 428,129 L 428,129 L 429,130 L 430,130 L 431,130 L 431,131 L 432,131 L 433,131 L 434,131 L 435,131 L 436,131 L 437,131 L 438,131 L 439,131 L 440,131 L 441,131 L 442,131 L 443,131 L 444,131 L 445,131 L 446,130 L 447,130 L 447,129 L 447,128 L 448,127" 65 | }, 66 | "type": "path" 67 | }, 68 | { 69 | "args": { 70 | "d": "M 101,132 L 102,132 L 103,132 L 104,132 L 104,133 L 105,133 L 106,133 L 107,133 L 108,133 L 108,133 L 109,133 L 110,133 L 111,133 L 112,133 L 113,133 L 114,133 L 115,133 L 116,133 L 116,132 L 116,132 L 117,131 L 118,130 L 119,130 L 119,129 L 120,128 L 121,127 L 122,127 L 123,127 L 123,128 L 124,128 L 125,128 L 126,128 L 128,128 L 128,128 L 129,128 L 130,128 L 130,128 L 131,128 L 132,128 L 132,128 L 133,128 L 134,128 L 135,128 L 136,128 L 137,128 L 138,128 L 139,127 L 139,127 L 139,126 L 141,125 L 142,125 L 142,124 L 143,124 L 143,124 L 143,123 L 144,123 L 144,122" 71 | }, 72 | "type": "path" 73 | }, 74 | { 75 | "args": { 76 | "cx": 296, 77 | "cy": 243, 78 | "rx": 8, 79 | "ry": 7 80 | }, 81 | "type": "ellipse" 82 | }, 83 | { 84 | "args": { 85 | "value": "maison", 86 | "x": 264, 87 | "y": 226 88 | }, 89 | "layout": { 90 | "font": { 91 | "name": "default", 92 | "size": 20 93 | }, 94 | "style": { 95 | "characterSpacing": 3 96 | } 97 | }, 98 | "type": "text" 99 | } 100 | ] 101 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var hyperglue = require('hyperglue') 2 | var EventEmitter = require('events').EventEmitter 3 | var inherits = require('inherits') 4 | var EventStream = require('./event_stream') 5 | var copy = require('shallow-copy') 6 | var xtend = require('xtend') 7 | var fs = require('fs') 8 | var insertCss = require('insert-css') 9 | var Color = require('color') 10 | var path = require('path') 11 | 12 | var validEvent = EventStream.validEvent 13 | 14 | var idSequence = 0 15 | 16 | module.exports = Svg 17 | inherits(Svg, EventEmitter) 18 | 19 | function Svg (opt) { 20 | if (!(this instanceof Svg)) return new Svg(opt) 21 | 22 | this.idSequence = ++idSequence 23 | 24 | insertCss(fs.readFileSync(path.join(__dirname, '/style.css'), 'utf-8')) 25 | this.html = fs.readFileSync(path.join(__dirname, '/index.html'), 'utf-8') 26 | 27 | this.DEFAULT_STYLE = { 28 | fill: 'rgba(0, 0, 0, 0)', 29 | stroke: 'rgba(0, 0, 0, 1)' 30 | } 31 | 32 | this.opt = opt || {} 33 | 34 | this._resetStyle() 35 | 36 | this.fonts = { 37 | 'default': { 38 | 'font-family': 'Arial', 39 | 'letter-spacing': 0, 40 | 'font-weight': 'normal' 41 | } 42 | } 43 | 44 | this.fonts.Normal = xtend(this.fonts.default, { 45 | 'font-size': 11, 46 | 'letter-spacing': 0 47 | }) 48 | 49 | this.fonts.Heading = xtend(this.fonts.default, { 50 | 'font-size': 22, 51 | 'font-weight': 'bold', 52 | 'letter-spacing': 0 53 | }) 54 | 55 | this.font = copy(this.fonts.default) 56 | 57 | this.deleted = [] 58 | 59 | this.listeners = { 60 | 'mousedown': this._down.bind(this), 61 | 'touchstart': this._down.bind(this), 62 | 'mouseup': this._up.bind(this), 63 | 'touchend': this._up.bind(this), 64 | 'mousemove': this._move.bind(this), 65 | 'touchmove': this._move.bind(this), 66 | 'anchorselect': this._anchorSelect.bind(this) 67 | } 68 | 69 | this.eventStream = new EventStream() 70 | } 71 | 72 | Svg.prototype.appendTo = function appendTo (el) { 73 | if (this.el) return this 74 | 75 | this.el = el.appendChild(hyperglue(this.html, { 76 | '#grid': { 77 | 'id': 'grid-' + this.idSequence 78 | }, 79 | '.grid': { 80 | 'fill': 'url(#grid-' + this.idSequence + ')' 81 | }, 82 | '#smallGrid': { 83 | 'id': 'smallGrid-' + this.idSequence 84 | }, 85 | '.smallGrid': { 86 | 'fill': 'url(#smallGrid-' + this.idSequence + ')' 87 | } 88 | })).children[0] 89 | 90 | this.controls = {} 91 | 92 | this._eventListeners('addEventListener') 93 | 94 | return this 95 | } 96 | 97 | Svg.prototype.registerControl = function (name, instance) { 98 | var self = this 99 | 100 | if (!instance || typeof instance.emit === 'undefined') return 101 | 102 | self.controls[name] = instance 103 | 104 | var control = self.controls[name] 105 | 106 | if (!control.on) return 107 | 108 | control.on('createEvent', createEvent) 109 | control.on('updateEvent', updateEvent) 110 | control.on('deletePath', deletePath) 111 | control.on('closeToPath', self._pathSelected.bind(self)) 112 | 113 | function createEvent (event) { 114 | self.eventStream.push(event) 115 | self._redraw([event]) 116 | } 117 | 118 | function updateEvent (event) { 119 | self._redraw([event]) 120 | } 121 | 122 | function deletePath (opt) { 123 | self.eventStream.push({ 124 | type: 'delete', 125 | target: opt.target, 126 | args: {}, 127 | path: opt.path 128 | }) 129 | self._redraw(self.eventStream.events.slice(-1)) 130 | } 131 | } 132 | 133 | Svg.prototype.remove = function remove () { 134 | if (!this.el) return 135 | var el = this.el.parentNode 136 | this._eventListeners('removeEventListener') 137 | el.parentNode.removeChild(el) 138 | this.el = null 139 | } 140 | 141 | Svg.prototype._triggerEventsChanged = function trigger () { 142 | if (trigger.timer) { 143 | clearTimeout(trigger.timer) 144 | trigger.timer = null 145 | } 146 | trigger.timer = setTimeout(function () { 147 | this.emit('eventStream', this.eventStream.toJSON()) 148 | }.bind(this), 300) 149 | } 150 | 151 | Svg.prototype.setEvents = function setEvents (events) { 152 | this._resetStyle() 153 | while (this.eventStream.events.length) this._deleteEvent() 154 | this.eventStream.events = events 155 | this._redraw() 156 | this._init(events) 157 | } 158 | 159 | Svg.prototype._deleteEvent = function deleteEvent () { 160 | var event = this.eventStream.events.pop() 161 | if (event.el && event.el.parentNode) { 162 | event.el.parentNode.removeChild(event.el) 163 | event.el = null 164 | } 165 | } 166 | 167 | Svg.prototype._resetEvents = function resetEvents () { 168 | this._resetStyle() 169 | this._redraw() 170 | this._init(this.eventStream.events) 171 | } 172 | 173 | Svg.prototype.setControl = function setControl (control) { 174 | if (control === 'grid') return this._grid() 175 | if (control === 'undo') return this.undo() 176 | if (control === 'redo') return this.redo() 177 | this.el.setAttribute('data-control', control) 178 | this.control = this.controls[control] 179 | this.emit('changeControl', control) 180 | if (!this.control) throw new Error('control ' + control + ' not supported') 181 | if (this.opt.anchor) { 182 | if (!(this.opt.anchor.exclude || /undo|redo|grid/).test(control)) this._removeAnchorElements() 183 | if ((this.opt.anchor.include || /rubber|move|text/).test(control)) this._addAnchorElements(control) 184 | } 185 | } 186 | 187 | Svg.prototype._init = function init (events) { 188 | var self = this 189 | var color, style, controlName 190 | 191 | this.silent = true 192 | events.forEach(setDefaults) 193 | this.emit('changeStyle', style || self.style) 194 | this.emit('changeColor', color || self.DEFAULT_STYLE.stroke) 195 | if (controlName) self.setControl(controlName) 196 | 197 | this.silent = false 198 | 199 | function setDefaults (event) { 200 | if (event.type === 'style') { 201 | style = event.args 202 | if (event.args.stroke) { 203 | color = event.args.stroke 204 | } 205 | return 206 | } 207 | controls().forEach(setControl) 208 | function setControl (opt) { 209 | var control = opt.control 210 | if (control.matchEvent && control.matchEvent(event)) { 211 | controlName = opt.controlName 212 | } 213 | } 214 | } 215 | 216 | function controls () { 217 | return Object.keys(self.controls).map(function mapControl (name) { 218 | return { 219 | controlName: name, 220 | control: self.controls[name] 221 | } 222 | }) 223 | } 224 | } 225 | 226 | Svg.prototype._eventListeners = function (method) { 227 | var self = this 228 | Object.keys(this.listeners).forEach(function event (name) { 229 | self.el[method](name, self.listeners[name]) 230 | }) 231 | } 232 | 233 | Svg.prototype._down = function down (e) { 234 | this.emit('drawing') 235 | if (this.control && this.control.ondown) this.control.ondown(e) 236 | } 237 | 238 | Svg.prototype._move = function move (e) { 239 | if (this.control && this.control.onmove) this.control.onmove(e) 240 | } 241 | 242 | Svg.prototype._up = function up (e) { 243 | if (this.control && this.control.onup) this.control.onup(e) 244 | } 245 | 246 | Svg.prototype._pathSelected = function pathSelected (e) { 247 | this.emit('drawing') 248 | if (!this.control || !this.control.onpathselected) return 249 | var target = e.target 250 | var id = +target.getAttribute('data-id') 251 | var path = this.eventStream.events.filter(findId) 252 | if (!path.length) return 253 | return this.control.onpathselected({path: path[0], e: e}) 254 | function findId (event) { 255 | return event.id === id 256 | } 257 | } 258 | 259 | Svg.prototype._resetStyle = function resetStyle () { 260 | this.style = copy(this.DEFAULT_STYLE) 261 | } 262 | 263 | Svg.prototype._redraw = function redraw (events) { 264 | if (!this.el) return 265 | var self = this 266 | events = events || self.eventStream.events 267 | redraw.id = redraw.id || 0 268 | self._triggerEventsChanged() 269 | events.forEach(create) 270 | 271 | this._addAnchorElements() 272 | 273 | function create (event) { 274 | if (event.type === 'style') { 275 | self.style = xtend(self.DEFAULT_STYLE, event.args) 276 | return 277 | } 278 | var el = event.el || (function () { 279 | if (event.target) return event.target 280 | var el = self.el.appendChild(createElement(event.type)) 281 | event.el = el 282 | el.setAttribute('data-id', ++redraw.id) 283 | event.id = redraw.id 284 | el.addEventListener('mousedown', self._pathSelected.bind(self)) 285 | el.addEventListener('touchstart', self._pathSelected.bind(self)) 286 | return el 287 | })() 288 | for (var key in event.args) { 289 | if (key !== 'value') { 290 | el.setAttribute(key, event.args[key]) 291 | } 292 | } 293 | 294 | if (event.type !== 'move') { 295 | if (event.args.value) { 296 | el.innerHTML = '' 297 | if (event.layout && event.layout.style && event.layout.style.width) { 298 | var match = new RegExp('.{0,' + (event.layout.style.width / 5 | 0) + '}', 'g') 299 | event.args.value.match(match).forEach(function wrap (text, i) { 300 | if (i === 0) { 301 | el.textContent = text 302 | } else { 303 | var tspan = createElement('tspan') 304 | tspan.setAttribute('dy', '1.1em') 305 | tspan.setAttribute('x', event.args.x) 306 | tspan.textContent = text 307 | el.appendChild(tspan) 308 | } 309 | }) 310 | } else { 311 | el.textContent = event.args.value 312 | } 313 | } 314 | } 315 | 316 | if (event.type === 'delete') { 317 | el.style.display = 'none' 318 | } else { 319 | if (!event.target) { 320 | var style = copy(self.style) 321 | if (event.type === 'text') style.fill = style.stroke 322 | applyStyle(el, style) 323 | applyLayout(event, el) 324 | } 325 | } 326 | } 327 | 328 | function applyLayout (event, el) { 329 | if (event.layout && event.layout.class) { 330 | el.setAttribute('class', event.layout.class) 331 | } 332 | if (event.layout && event.layout.font) { 333 | if (self.fonts[event.layout.font.name]) { 334 | self.font = copy(self.fonts[event.layout.font.name]) 335 | if (event.layout.font.size) { 336 | self.font['font-size'] = event.layout.font.size 337 | } 338 | } 339 | } 340 | 341 | for (var key in self.font) el.setAttribute(key, self.font[key]) 342 | if (event.layout && event.layout.rotate) { 343 | el.setAttribute('transform', 344 | 'rotate(' + event.layout.rotate.deg + ' ' + event.args.x + ' ' + event.args.y + ')' 345 | ) 346 | } 347 | } 348 | 349 | function applyStyle (el, style) { 350 | el.setAttribute('style', Object.keys(style).reduce(reduce, '')) 351 | function reduce (result, key) { 352 | return result + key + ':' + style[key] + ';' 353 | } 354 | } 355 | } 356 | 357 | function createElement (name) { 358 | return document.createElementNS('http://www.w3.org/2000/svg', name) 359 | } 360 | 361 | Svg.prototype.resize = function resize (width, height) { 362 | if (this.el) { 363 | this.el.setAttribute('viewBox', '0 0 ' + width + ' ' + height) 364 | } 365 | } 366 | 367 | Svg.prototype.setColor = function setColor (color) { 368 | if (Color(this.style.stroke).rgbaString() === Color(color).rgbaString()) return 369 | this.setStyle({stroke: Color(color).rgbaString()}) 370 | } 371 | 372 | Svg.prototype.setStyle = function setStyle (opt) { 373 | var style = xtend(this.DEFAULT_STYLE, opt) 374 | var event = { 375 | type: 'style', 376 | args: style 377 | } 378 | if (!this.silent) this.eventStream.push(event) 379 | this._redraw([event]) 380 | } 381 | 382 | Svg.prototype.undo = function undo () { 383 | var event = this.eventStream.pop() 384 | if (event) { 385 | this.deleted.push(event) 386 | if (event.el) { 387 | event.el.style.display = 'none' 388 | } 389 | } 390 | this._resetEvents() 391 | } 392 | 393 | Svg.prototype.redo = function redo () { 394 | var event = this.deleted.pop() 395 | if (event) { 396 | this.eventStream.push(event) 397 | if (event.el) { 398 | event.el.style.display = 'block' 399 | } 400 | } 401 | this._resetEvents() 402 | } 403 | 404 | Svg.prototype.setGridStyle = function setGridStyle (style) { 405 | style = style || this.gridStyle 406 | if (style) { 407 | this.gridStyle = style 408 | var grid = this.el.querySelector('.grid') 409 | Object.keys(style).forEach(function setStyle (key) { 410 | grid.setAttribute(key, style[key]) 411 | }) 412 | } 413 | } 414 | 415 | Svg.prototype._grid = function toggleGrid () { 416 | var grid = this.el.querySelector('.grid') 417 | var gridUrl = 'url(#grid-' + this.idSequence + ')' 418 | 419 | var gridDisplay = grid.getAttribute('fill') 420 | gridDisplay = gridDisplay === 'transparent' ? gridUrl : 'transparent' 421 | grid.setAttribute('fill', gridDisplay) 422 | this.el.setAttribute('data-grid', gridDisplay === gridUrl) 423 | this.setGridStyle() 424 | } 425 | 426 | Svg.prototype._anchorSelect = function anchorSelect (e) { 427 | var id = e.target.getAttribute('data-anchor-id') 428 | var target = this.el.querySelector('[data-id="' + id + '"]') 429 | e.stopPropagation() 430 | this._pathSelected({target: target, stopPropagation: e.stopPropagation.bind(e)}) 431 | } 432 | 433 | Svg.prototype._removeAnchorElements = function removeAnchorElements () { 434 | var self = this 435 | ;[].forEach.call(this.el.querySelectorAll('.anchor'), removeAnchor) 436 | this.eventStream.events.forEach(resetAnchorEl) 437 | function removeAnchor (el) { 438 | el.removeEventListener('mousedown', self.listeners.anchorselect) 439 | el.removeEventListener('touchstart', self.listeners.anchorselect) 440 | el.parentNode.removeChild(el) 441 | } 442 | function resetAnchorEl (event) { 443 | delete event.anchorEl 444 | } 445 | } 446 | 447 | Svg.prototype._addAnchorElements = function addAnchorElements (control) { 448 | if (control) addAnchorElements.control = control 449 | control = addAnchorElements.control 450 | if (!control) return 451 | if (!this.opt.anchor) return 452 | this.eventStream.events.forEach(add.bind(this)) 453 | function add (event) { 454 | if (!event.el) return 455 | var position = (this.opt.anchor.position || xy)(event) 456 | if (!position.filter(Boolean).length) return 457 | if (control === 'text' && !(event.target || event.el).nodeName.match(/text/i)) return 458 | var el = event.anchorEl 459 | if (!el) { 460 | el = createElement('ellipse') 461 | el.addEventListener('mousedown', this.listeners.anchorselect) 462 | el.addEventListener('touchstart', this.listeners.anchorselect) 463 | event.anchorEl = el 464 | this.el.appendChild(el) 465 | } 466 | var id = (event.target || event.el).getAttribute('data-id') 467 | el.style.display = (event.target || event.el).style.display 468 | el.setAttribute('cx', position[0]) 469 | el.setAttribute('cy', position[1]) 470 | el.setAttribute('rx', this.opt.anchor.size || 14) 471 | el.setAttribute('ry', this.opt.anchor.size || 14) 472 | el.setAttribute('data-anchor-id', id) 473 | el.setAttribute('class', 'anchor') 474 | } 475 | 476 | function xy (event) { 477 | var el = (event.target || event.el) 478 | var attributes = el.attributes 479 | var args = [].reduce.call(attributes, function (sum, item) { sum[item.name] = item.value; return sum }, {}) 480 | if (event.type === 'text') args.value = el.textContent 481 | if (!validEvent({args: args, type: event.type})) return [] 482 | if (event.type === 'ellipse') return [args.cx - args.rx, args.cy] 483 | if (event.type === 'path') return path() 484 | return [args.x, args.y] 485 | function path () { 486 | var POINT = /\d+\.?\d*\s*,\s*\d+\.?\d*/g 487 | var d = args.d.match(POINT)[0].split(',').map(Number) 488 | return [d[0], d[1]] 489 | } 490 | } 491 | } 492 | 493 | Svg.prototype.setClipboard = function setClipboard (copied) { 494 | this.copied = copied 495 | } 496 | 497 | Svg.prototype.copy = function copy () { 498 | this.copied = this.eventStream.toJSON() 499 | this.emit('copy', this.copied) 500 | } 501 | 502 | Svg.prototype.cut = function cut () { 503 | this.copy() 504 | this._removeAllEvents() 505 | this._resetEvents() 506 | } 507 | 508 | Svg.prototype._removeAllEvents = function removeAllEvents () { 509 | var self = this 510 | this.eventStream.events.forEach(remove) 511 | function remove (event) { 512 | if (!event.el || event.type === 'delete') return 513 | self.eventStream.push({ 514 | type: 'delete', 515 | target: event.el, 516 | args: {}, 517 | path: event 518 | }) 519 | } 520 | this._removeAnchorElements() 521 | } 522 | 523 | Svg.prototype.paste = function paste (e) { 524 | var pasteData 525 | try { 526 | var data = e.clipboardData.getData('text') 527 | pasteData = JSON.parse(data) 528 | } catch (x) {} 529 | if (!pasteData && !this.copied) return 530 | this._removeAllEvents() 531 | Array.prototype.push.apply(this.eventStream.events, (pasteData || this.copied)) 532 | this._resetEvents() 533 | } 534 | -------------------------------------------------------------------------------- /svg-sketch.min.js: -------------------------------------------------------------------------------- 1 | !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.SvgSketch=t()}}(function(){return function t(e,r,n){function o(s,a){if(!r[s]){if(!e[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(i)return i(s,!0);var h=new Error("Cannot find module '"+s+"'");throw h.code="MODULE_NOT_FOUND",h}var u=r[s]={exports:{}};e[s][0].call(u.exports,function(t){var r=e[s][1][t];return o(r?r:t)},u,u.exports,t,e,r,n)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s0}var o=t("shallow-copy"),i=t("xtend"),s=t("color");e.exports=r,r.validEvent=n,r.prototype.push=function(t){var e=this.events.push(t);return e},r.prototype.pop=function(){var t=this.events.pop();return t},r.prototype.toJSON=function(){function t(t){var e=o(t.args);return e&&["stroke","fill"].forEach(function(t){e[t]&&(e[t]=s(e[t]).rgbaString())}),{type:t.type,id:t.id,args:e,layout:t.layout,pathId:t.path?t.path.id:void 0}}function e(t){function e(e){return e.id===t.pathId}if(t.pathId){var r=l.normalized.filter(e)[0];r&&(t.deleted=!0,r.args=i(r.args,t.args),r.deleted="delete"===t.type)}}function r(t,e){function r(t,r){return e[r]&&(t[r]=e[r]),t}return"style"===e.type&&"style"===a&&t.pop(),n(e)?(a=e.type,t.push(["type","args","layout"].reduce(r,{})),t):t}var a,l=this;return this.normalized=this.events.map(t),this.normalized.forEach(e),this.normalized.reduce(r,[])}},{color:7,"shallow-copy":16,xtend:18}],2:[function(t,e){function r(t,e){return Math.pow(t[0]-e[0],2)+Math.pow(t[1]-e[1],2)+Math.pow(t[2]-e[2],2)}var n=t("color-name"),o={};for(var i in n)n.hasOwnProperty(i)&&(o[n[i]]=i);var s=e.exports={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};for(var a in s)if(s.hasOwnProperty(a)){if(!("channels"in s[a]))throw new Error("missing channels property: "+a);if(!("labels"in s[a]))throw new Error("missing channel labels property: "+a);if(s[a].labels.length!==s[a].channels)throw new Error("channel and label counts mismatch: "+a);var l=s[a].channels,h=s[a].labels;delete s[a].channels,delete s[a].labels,Object.defineProperty(s[a],"channels",{value:l}),Object.defineProperty(s[a],"labels",{value:h})}s.rgb.hsl=function(t){var e,r,n,o=t[0]/255,i=t[1]/255,s=t[2]/255,a=Math.min(o,i,s),l=Math.max(o,i,s),h=l-a;return l===a?e=0:o===l?e=(i-s)/h:i===l?e=2+(s-o)/h:s===l&&(e=4+(o-i)/h),e=Math.min(60*e,360),0>e&&(e+=360),n=(a+l)/2,r=l===a?0:.5>=n?h/(l+a):h/(2-l-a),[e,100*r,100*n]},s.rgb.hsv=function(t){var e,r,n,o=t[0],i=t[1],s=t[2],a=Math.min(o,i,s),l=Math.max(o,i,s),h=l-a;return r=0===l?0:1e3*(h/l)/10,l===a?e=0:o===l?e=(i-s)/h:i===l?e=2+(s-o)/h:s===l&&(e=4+(o-i)/h),e=Math.min(60*e,360),0>e&&(e+=360),n=1e3*(l/255)/10,[e,r,n]},s.rgb.hwb=function(t){var e=t[0],r=t[1],n=t[2],o=s.rgb.hsl(t)[0],i=1/255*Math.min(e,Math.min(r,n));return n=1-1/255*Math.max(e,Math.max(r,n)),[o,100*i,100*n]},s.rgb.cmyk=function(t){var e,r,n,o,i=t[0]/255,s=t[1]/255,a=t[2]/255;return o=Math.min(1-i,1-s,1-a),e=(1-i-o)/(1-o)||0,r=(1-s-o)/(1-o)||0,n=(1-a-o)/(1-o)||0,[100*e,100*r,100*n,100*o]},s.rgb.keyword=function(t){var e=o[t];if(e)return e;var i,s=1/0;for(var a in n)if(n.hasOwnProperty(a)){var l=n[a],h=r(t,l);s>h&&(s=h,i=a)}return i},s.keyword.rgb=function(t){return n[t]},s.rgb.xyz=function(t){var e=t[0]/255,r=t[1]/255,n=t[2]/255;e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92,r=r>.04045?Math.pow((r+.055)/1.055,2.4):r/12.92,n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92;var o=.4124*e+.3576*r+.1805*n,i=.2126*e+.7152*r+.0722*n,s=.0193*e+.1192*r+.9505*n;return[100*o,100*i,100*s]},s.rgb.lab=function(t){var e,r,n,o=s.rgb.xyz(t),i=o[0],a=o[1],l=o[2];return i/=95.047,a/=100,l/=108.883,i=i>.008856?Math.pow(i,1/3):7.787*i+16/116,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,l=l>.008856?Math.pow(l,1/3):7.787*l+16/116,e=116*a-16,r=500*(i-a),n=200*(a-l),[e,r,n]},s.hsl.rgb=function(t){var e,r,n,o,i,s=t[0]/360,a=t[1]/100,l=t[2]/100;if(0===a)return i=255*l,[i,i,i];r=.5>l?l*(1+a):l+a-l*a,e=2*l-r,o=[0,0,0];for(var h=0;3>h;h++)n=s+1/3*-(h-1),0>n&&n++,n>1&&n--,i=1>6*n?e+6*(r-e)*n:1>2*n?r:2>3*n?e+6*(r-e)*(2/3-n):e,o[h]=255*i;return o},s.hsl.hsv=function(t){var e,r,n=t[0],o=t[1]/100,i=t[2]/100,s=o,a=Math.max(i,.01);return i*=2,o*=1>=i?i:2-i,s*=1>=a?a:2-a,r=(i+o)/2,e=0===i?2*s/(a+s):2*o/(i+o),[n,100*e,100*r]},s.hsv.rgb=function(t){var e=t[0]/60,r=t[1]/100,n=t[2]/100,o=Math.floor(e)%6,i=e-Math.floor(e),s=255*n*(1-r),a=255*n*(1-r*i),l=255*n*(1-r*(1-i));switch(n*=255,o){case 0:return[n,l,s];case 1:return[a,n,s];case 2:return[s,n,l];case 3:return[s,a,n];case 4:return[l,s,n];case 5:return[n,s,a]}},s.hsv.hsl=function(t){var e,r,n,o=t[0],i=t[1]/100,s=t[2]/100,a=Math.max(s,.01);return n=(2-i)*s,e=(2-i)*a,r=i*a,r/=1>=e?e:2-e,r=r||0,n/=2,[o,100*r,100*n]},s.hwb.rgb=function(t){var e,r,n,o,i=t[0]/360,s=t[1]/100,a=t[2]/100,l=s+a;l>1&&(s/=l,a/=l),e=Math.floor(6*i),r=1-a,n=6*i-e,0!==(1&e)&&(n=1-n),o=s+n*(r-s);var h,u,c;switch(e){default:case 6:case 0:h=r,u=o,c=s;break;case 1:h=o,u=r,c=s;break;case 2:h=s,u=r,c=o;break;case 3:h=s,u=o,c=r;break;case 4:h=o,u=s,c=r;break;case 5:h=r,u=s,c=o}return[255*h,255*u,255*c]},s.cmyk.rgb=function(t){var e,r,n,o=t[0]/100,i=t[1]/100,s=t[2]/100,a=t[3]/100;return e=1-Math.min(1,o*(1-a)+a),r=1-Math.min(1,i*(1-a)+a),n=1-Math.min(1,s*(1-a)+a),[255*e,255*r,255*n]},s.xyz.rgb=function(t){var e,r,n,o=t[0]/100,i=t[1]/100,s=t[2]/100;return e=3.2406*o+-1.5372*i+s*-.4986,r=o*-.9689+1.8758*i+.0415*s,n=.0557*o+i*-.204+1.057*s,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:12.92*e,r=r>.0031308?1.055*Math.pow(r,1/2.4)-.055:12.92*r,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:12.92*n,e=Math.min(Math.max(0,e),1),r=Math.min(Math.max(0,r),1),n=Math.min(Math.max(0,n),1),[255*e,255*r,255*n]},s.xyz.lab=function(t){var e,r,n,o=t[0],i=t[1],s=t[2];return o/=95.047,i/=100,s/=108.883,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,i=i>.008856?Math.pow(i,1/3):7.787*i+16/116,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116,e=116*i-16,r=500*(o-i),n=200*(i-s),[e,r,n]},s.lab.xyz=function(t){var e,r,n,o=t[0],i=t[1],s=t[2];r=(o+16)/116,e=i/500+r,n=r-s/200;var a=Math.pow(r,3),l=Math.pow(e,3),h=Math.pow(n,3);return r=a>.008856?a:(r-16/116)/7.787,e=l>.008856?l:(e-16/116)/7.787,n=h>.008856?h:(n-16/116)/7.787,e*=95.047,r*=100,n*=108.883,[e,r,n]},s.lab.lch=function(t){var e,r,n,o=t[0],i=t[1],s=t[2];return e=Math.atan2(s,i),r=360*e/2/Math.PI,0>r&&(r+=360),n=Math.sqrt(i*i+s*s),[o,n,r]},s.lch.lab=function(t){var e,r,n,o=t[0],i=t[1],s=t[2];return n=2*(s/360)*Math.PI,e=i*Math.cos(n),r=i*Math.sin(n),[o,e,r]},s.rgb.ansi16=function(t){var e=t[0],r=t[1],n=t[2],o=1 in arguments?arguments[1]:s.rgb.hsv(t)[2];if(o=Math.round(o/50),0===o)return 30;var i=30+(Math.round(n/255)<<2|Math.round(r/255)<<1|Math.round(e/255));return 2===o&&(i+=60),i},s.hsv.ansi16=function(t){return s.rgb.ansi16(s.hsv.rgb(t),t[2])},s.rgb.ansi256=function(t){var e=t[0],r=t[1],n=t[2];if(e===r&&r===n)return 8>e?16:e>248?231:Math.round(24*((e-8)/247))+232;var o=16+36*Math.round(5*(e/255))+6*Math.round(5*(r/255))+Math.round(5*(n/255));return o},s.ansi16.rgb=function(t){var e=t%10;if(0===e||7===e)return t>50&&(e+=3.5),e=255*(e/10.5),[e,e,e];var r=.5*(~~(t>50)+1),n=255*(1&e)*r,o=255*(1&e>>1)*r,i=255*(1&e>>2)*r;return[n,o,i]},s.ansi256.rgb=function(t){if(t>=232){var e=10*(t-232)+8;return[e,e,e]}t-=16;var r,n=255*(Math.floor(t/36)/5),o=255*(Math.floor((r=t%36)/6)/5),i=255*(r%6/5);return[n,o,i]},s.rgb.hex=function(t){var e=((255&Math.round(t[0]))<<16)+((255&Math.round(t[1]))<<8)+(255&Math.round(t[2])),r=e.toString(16).toUpperCase();return"000000".substring(r.length)+r},s.hex.rgb=function(t){var e=t.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!e)return[0,0,0];var r=e[0];3===e[0].length&&(r=r.split("").map(function(t){return t+t}).join(""));var n=parseInt(r,16),o=255&n>>16,i=255&n>>8,s=255&n;return[o,i,s]},s.rgb.hcg=function(t){var e,r,n=t[0]/255,o=t[1]/255,i=t[2]/255,s=Math.max(Math.max(n,o),i),a=Math.min(Math.min(n,o),i),l=s-a;return e=1>l?a/(1-l):0,r=0>=l?0:s===n?(o-i)/l%6:s===o?2+(i-n)/l:4+(n-o)/l+4,r/=6,r%=1,[360*r,100*l,100*e]},s.hsl.hcg=function(t){var e=t[1]/100,r=t[2]/100,n=1,o=0;return n=.5>r?2*e*r:2*e*(1-r),1>n&&(o=(r-.5*n)/(1-n)),[t[0],100*n,100*o]},s.hsv.hcg=function(t){var e=t[1]/100,r=t[2]/100,n=e*r,o=0;return 1>n&&(o=(r-n)/(1-n)),[t[0],100*n,100*o]},s.hcg.rgb=function(t){var e=t[0]/360,r=t[1]/100,n=t[2]/100;if(0===r)return[255*n,255*n,255*n];var o=[0,0,0],i=6*(e%1),s=i%1,a=1-s,l=0;switch(Math.floor(i)){case 0:o[0]=1,o[1]=s,o[2]=0;break;case 1:o[0]=a,o[1]=1,o[2]=0;break;case 2:o[0]=0,o[1]=1,o[2]=s;break;case 3:o[0]=0,o[1]=a,o[2]=1;break;case 4:o[0]=s,o[1]=0,o[2]=1;break;default:o[0]=1,o[1]=0,o[2]=a}return l=(1-r)*n,[255*(r*o[0]+l),255*(r*o[1]+l),255*(r*o[2]+l)]},s.hcg.hsv=function(t){var e=t[1]/100,r=t[2]/100,n=e+r*(1-e),o=0;return n>0&&(o=e/n),[t[0],100*o,100*n]},s.hcg.hsl=function(t){var e=t[1]/100,r=t[2]/100,n=r*(1-e)+.5*e,o=0;return n>0&&.5>n?o=e/(2*n):n>=.5&&1>n&&(o=e/(2*(1-n))),[t[0],100*o,100*n]},s.hcg.hwb=function(t){var e=t[1]/100,r=t[2]/100,n=e+r*(1-e);return[t[0],100*(n-e),100*(1-n)]},s.hwb.hcg=function(t){var e=t[1]/100,r=t[2]/100,n=1-r,o=n-e,i=0;return 1>o&&(i=(n-o)/(1-o)),[t[0],100*o,100*i]},s.apple.rgb=function(t){return[255*(t[0]/65535),255*(t[1]/65535),255*(t[2]/65535)]},s.rgb.apple=function(t){return[65535*(t[0]/255),65535*(t[1]/255),65535*(t[2]/255)]},s.gray.rgb=function(t){return[255*(t[0]/100),255*(t[0]/100),255*(t[0]/100)]},s.gray.hsl=s.gray.hsv=function(t){return[0,0,t[0]]},s.gray.hwb=function(t){return[0,100,t[0]]},s.gray.cmyk=function(t){return[0,0,0,t[0]]},s.gray.lab=function(t){return[t[0],0,0]},s.gray.hex=function(t){var e=255&Math.round(255*(t[0]/100)),r=(e<<16)+(e<<8)+e,n=r.toString(16).toUpperCase();return"000000".substring(n.length)+n},s.rgb.gray=function(t){var e=(t[0]+t[1]+t[2])/3;return[100*(e/255)]}},{"color-name":5}],3:[function(t,e){function r(t){var e=function(e){return void 0===e||null===e?e:(arguments.length>1&&(e=Array.prototype.slice.call(arguments)),t(e))};return"conversion"in t&&(e.conversion=t.conversion),e}function n(t){var e=function(e){if(void 0===e||null===e)return e;arguments.length>1&&(e=Array.prototype.slice.call(arguments));var r=t(e);if("object"==typeof r)for(var n=r.length,o=0;n>o;o++)r[o]=Math.round(r[o]);return r};return"conversion"in t&&(e.conversion=t.conversion),e}var o=t("./conversions"),i=t("./route"),s={},a=Object.keys(o);a.forEach(function(t){s[t]={},Object.defineProperty(s[t],"channels",{value:o[t].channels}),Object.defineProperty(s[t],"labels",{value:o[t].labels});var e=i(t),a=Object.keys(e);a.forEach(function(o){var i=e[o];s[t][o]=n(i),s[t][o].raw=r(i)})}),e.exports=s},{"./conversions":2,"./route":4}],4:[function(t,e){function r(){for(var t={},e=a.length,r=0;e>r;r++)t[a[r]]={distance:-1,parent:null};return t}function n(t){var e=r(),n=[t];for(e[t].distance=0;n.length;)for(var o=n.pop(),i=Object.keys(s[o]),a=i.length,l=0;a>l;l++){var h=i[l],u=e[h];-1===u.distance&&(u.distance=e[o].distance+1,u.parent=o,n.unshift(h))}return e}function o(t,e){return function(r){return e(t(r))}}function i(t,e){for(var r=[e[t].parent,t],n=s[e[t].parent][t],i=e[t].parent;e[i].parent;)r.unshift(e[i].parent),n=o(s[e[i].parent][i],n),i=e[i].parent;return n.conversion=r,n}var s=t("./conversions"),a=Object.keys(s);e.exports=function(t){for(var e=n(t),r={},o=Object.keys(e),s=o.length,a=0;s>a;a++){var l=o[a],h=e[l];null!==h.parent&&(r[l]=i(l,e))}return r}},{"./conversions":2}],5:[function(t,e){e.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},{}],6:[function(t,e){function r(t,e,r){return Math.min(Math.max(e,t),r)}function n(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var o=t("color-name"),i=t("simple-swizzle"),s={};for(var a in o)o.hasOwnProperty(a)&&(s[o[a]]=a);var l=e.exports={to:{}};l.get=function(t){var e,r,n=t.substring(0,3).toLowerCase();switch(n){case"hsl":e=l.get.hsl(t),r="hsl";break;case"hwb":e=l.get.hwb(t),r="hwb";break;default:e=l.get.rgb(t),r="rgb"}return e?{model:r,value:e}:null},l.get.rgb=function(t){if(!t)return null;var e,n,i=/^#([a-fA-F0-9]{3})$/,s=/^#([a-fA-F0-9]{6})$/,a=/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,l=/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,h=/(\D+)/,u=[0,0,0,1];if(e=t.match(i))for(e=e[1],n=0;3>n;n++)u[n]=parseInt(e[n]+e[n],16);else if(e=t.match(s))for(e=e[1],n=0;3>n;n++){var c=2*n;u[n]=parseInt(e.slice(c,c+2),16)}else if(e=t.match(a)){for(n=0;3>n;n++)u[n]=parseInt(e[n+1],0);e[4]&&(u[3]=parseFloat(e[4]))}else if(e=t.match(l)){for(n=0;3>n;n++)u[n]=Math.round(2.55*parseFloat(e[n+1]));e[4]&&(u[3]=parseFloat(e[4]))}else if(e=t.match(h))return"transparent"===e[1]?[0,0,0,0]:(u=o[e[1]])?(u[3]=1,u):null;for(n=0;n=4&&1!==t[3]&&(e=", "+t[3]),"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+e+")"},l.to.keyword=function(t){return s[t.slice(0,3)]}},{"color-name":5,"simple-swizzle":17}],7:[function(t,e){"use strict";function r(t,e){if(!(this instanceof r))return new r(t,e);if(e&&e in f&&(e=null),e&&!(e in u))throw new Error("Unknown model: "+e);var n,o;if(t)if(t instanceof r)this.model=t.model,this.color=t.color.slice(),this.valpha=t.valpha;else if("string"==typeof t){var i=h.get(t);if(null===i)throw new Error("Unable to parse color from string: "+t);this.model=i.model,o=u[this.model].channels,this.color=i.value.slice(0,o),this.valpha="number"==typeof i.value[o]?i.value[o]:1}else if(t.length){this.model=e||"rgb",o=u[this.model].channels;var s=c.call(t,0,o);this.color=l(s,o),this.valpha="number"==typeof t[o]?t[o]:1}else if("number"==typeof t)t&=16777215,this.model="rgb",this.color=[255&t>>16,255&t>>8,255&t],this.valpha=1;else{this.valpha=1;var a=Object.keys(t);"alpha"in t&&(a.splice(a.indexOf("alpha"),1),this.valpha="number"==typeof t.alpha?t.alpha:0);var v=a.sort().join("");if(!(v in p))throw new Error("Unable to parse color from object: "+JSON.stringify(t));this.model=p[v];var g=u[this.model].labels,m=[];for(n=0;nn;n++){var y=d[this.model][n];y&&(this.color[n]=y(this.color[n]))}this.valpha=Math.max(0,Math.min(1,this.valpha)),Object.freeze&&Object.freeze(this)}function n(t,e){return Number(t.toFixed(e))}function o(t){return function(e){return n(e,t)}}function i(t,e,r){return t=Array.isArray(t)?t:[t],t.forEach(function(t){(d[t]||(d[t]=[]))[e]=r}),t=t[0],function(n){var o;return arguments.length?(r&&(n=r(n)),o=this[t](),o.color[e]=n,o):(o=this[t]().color[e],r&&(o=r(o)),o)}}function s(t){return function(e){return Math.max(0,Math.min(t,e))}}function a(t){return Array.isArray(t)?t:[t]}function l(t,e){for(var r=0;e>r;r++)"number"!=typeof t[r]&&(t[r]=0);return t}var h=t("color-string"),u=t("color-convert"),c=[].slice,f=["keyword","gray","hex"],p={};Object.keys(u).forEach(function(t){p[c.call(u[t].labels).sort().join("")]=t});var d={};r.prototype={toString:function(){return this.string()},toJSON:function(){return this[this.model]()},string:function(t){var e=this.model in h.to?this:this.rgb();e=e.round("number"==typeof t?t:1);var r=1===e.valpha?e.color:e.color.concat(this.valpha);return h.to[e.model](r)},percentString:function(t){var e=this.rgb().round("number"==typeof t?t:1),r=1===e.valpha?e.color:e.color.concat(this.valpha);return h.to.rgb.percent(r)},array:function(){return 1===this.valpha?this.color.slice():this.color.concat(this.valpha)},object:function(){for(var t={},e=u[this.model].channels,r=u[this.model].labels,n=0;e>n;n++)t[r[n]]=this.color[n];return 1!==this.valpha&&(t.alpha=this.valpha),t},unitArray:function(){var t=this.rgb().color;return t[0]/=255,t[1]/=255,t[2]/=255,1!==this.valpha&&t.push(this.valpha),t},unitObject:function(){var t=this.rgb().object();return t.r/=255,t.g/=255,t.b/=255,1!==this.valpha&&(t.alpha=this.valpha),t},round:function(t){return t=Math.max(t||0,0),new r(this.color.map(o(t)).concat(this.valpha),this.model)},alpha:function(t){return arguments.length?new r(this.color.concat(Math.max(0,Math.min(1,t))),this.model):this.valpha},red:i("rgb",0,s(255)),green:i("rgb",1,s(255)),blue:i("rgb",2,s(255)),hue:i(["hsl","hsv","hsl","hwb","hcg"],0,function(t){return(t%360+360)%360}),saturationl:i("hsl",1,s(100)),lightness:i("hsl",2,s(100)),saturationv:i("hsv",1,s(100)),value:i("hsv",2,s(100)),chroma:i("hcg",1,s(100)),gray:i("hcg",2,s(100)),white:i("hwb",1,s(100)),wblack:i("hwb",2,s(100)),cyan:i("cmyk",0,s(100)),magenta:i("cmyk",1,s(100)),yellow:i("cmyk",2,s(100)),black:i("cmyk",3,s(100)),x:i("xyz",0,s(100)),y:i("xyz",1,s(100)),z:i("xyz",2,s(100)),l:i("lab",0,s(100)),a:i("lab",1),b:i("lab",2),keyword:function(t){return arguments.length?new r(t):u[this.model].keyword(this.color)},hex:function(t){return arguments.length?new r(t):h.to.hex(this.rgb().round().color)},rgbNumber:function(){var t=this.rgb().color;return(255&t[0])<<16|(255&t[1])<<8|255&t[2]},luminosity:function(){for(var t=this.rgb().color,e=[],r=0;r=n?n/12.92:Math.pow((n+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),r=t.luminosity();return e>r?(e+.05)/(r+.05):(r+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.rgb().color,e=(299*t[0]+587*t[1]+114*t[2])/1e3;return 128>e},light:function(){return!this.dark()},negate:function(){for(var t=this.rgb(),e=0;3>e;e++)t.color[e]=255-t.color[e];return t},lighten:function(t){var e=this.hsl();return e.color[2]+=e.color[2]*t,e},darken:function(t){var e=this.hsl();return e.color[2]-=e.color[2]*t,e},saturate:function(t){var e=this.hsl();return e.color[1]+=e.color[1]*t,e},desaturate:function(t){var e=this.hsl();return e.color[1]-=e.color[1]*t,e},whiten:function(t){var e=this.hwb();return e.color[1]+=e.color[1]*t,e},blacken:function(t){var e=this.hwb();return e.color[2]+=e.color[2]*t,e},grayscale:function(){var t=this.rgb().color,e=.3*t[0]+.59*t[1]+.11*t[2];return r.rgb(e,e,e)},fade:function(t){return this.alpha(this.valpha-this.valpha*t)},opaquer:function(t){return this.alpha(this.valpha+this.valpha*t)},rotate:function(t){var e=this.hsl(),r=e.color[0];return r=(r+t)%360,r=0>r?360+r:r,e.color[0]=r,e},mix:function(t,e){var n=this.rgb(),o=t.rgb(),i=void 0===e?.5:e,s=2*i-1,a=n.alpha()-o.alpha(),l=((-1===s*a?s:(s+a)/(1+s*a))+1)/2,h=1-l;return r.rgb(l*n.red()+h*o.red(),l*n.green()+h*o.green(),l*n.blue()+h*o.blue(),n.alpha()*i+o.alpha()*(1-i))}},Object.keys(u).forEach(function(t){if(-1===f.indexOf(t)){var e=u[t].channels;r.prototype[t]=function(){if(this.model===t)return new r(this);if(arguments.length)return new r(arguments,t);var n="number"==typeof arguments[e]?e:this.valpha;return new r(a(u[this.model][t].raw(this.color)).concat(n),t)},r[t]=function(n){return"number"==typeof n&&(n=l(c.call(arguments),e)),new r(n,t)}}}),e.exports=r},{"color-convert":3,"color-string":6}],8:[function(t,e){function r(t){if("string"!=typeof t)throw new TypeError("String expected");var e=/<([\w:]+)/.exec(t);if(!e)throw new Error("No elements were generated.");var r=e[1];if("body"==r){var i=document.createElement("html");return i.innerHTML=t,[i.removeChild(i.lastChild)]}var s=o[r]||o._default,a=s[0],l=s[1],h=s[2],i=document.createElement("div");for(i.innerHTML=l+t+h;a--;)i=i.lastChild;return n(i.children)}function n(t){for(var e=[];t.length;)e.push(t[0].parentNode.removeChild(t[0]));return e}e.exports=r;var o={option:[1,'"],optgroup:[1,'"],legend:[1,"
","
"],thead:[1,"","
"],tbody:[1,"","
"],tfoot:[1,"","
"],colgroup:[1,"","
"],caption:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],th:[3,"","
"],col:[2,"","
"],_default:[0,"",""]}},{}],9:[function(t,e){function r(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function n(t){return"function"==typeof t}function o(t){return"number"==typeof t}function i(t){return"object"==typeof t&&null!==t}function s(t){return void 0===t}e.exports=r,r.EventEmitter=r,r.prototype._events=void 0,r.prototype._maxListeners=void 0,r.defaultMaxListeners=10,r.prototype.setMaxListeners=function(t){if(!o(t)||0>t||isNaN(t))throw TypeError("n must be a positive number");return this._maxListeners=t,this},r.prototype.emit=function(t){var e,r,o,a,l,h;if(this._events||(this._events={}),"error"===t&&(!this._events.error||i(this._events.error)&&!this._events.error.length)){if(e=arguments[1],e instanceof Error)throw e;var u=new Error('Uncaught, unspecified "error" event. ('+e+")");throw u.context=e,u}if(r=this._events[t],s(r))return!1;if(n(r))switch(arguments.length){case 1:r.call(this);break;case 2:r.call(this,arguments[1]);break;case 3:r.call(this,arguments[1],arguments[2]);break;default:a=Array.prototype.slice.call(arguments,1),r.apply(this,a)}else if(i(r))for(a=Array.prototype.slice.call(arguments,1),h=r.slice(),o=h.length,l=0;o>l;l++)h[l].apply(this,a);return!0},r.prototype.addListener=function(t,e){var o;if(!n(e))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",t,n(e.listener)?e.listener:e),this._events[t]?i(this._events[t])?this._events[t].push(e):this._events[t]=[this._events[t],e]:this._events[t]=e,i(this._events[t])&&!this._events[t].warned&&(o=s(this._maxListeners)?r.defaultMaxListeners:this._maxListeners,o&&o>0&&this._events[t].length>o&&(this._events[t].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[t].length),"function"==typeof console.trace&&console.trace())),this},r.prototype.on=r.prototype.addListener,r.prototype.once=function(t,e){function r(){this.removeListener(t,r),o||(o=!0,e.apply(this,arguments))}if(!n(e))throw TypeError("listener must be a function");var o=!1;return r.listener=e,this.on(t,r),this},r.prototype.removeListener=function(t,e){var r,o,s,a;if(!n(e))throw TypeError("listener must be a function");if(!this._events||!this._events[t])return this;if(r=this._events[t],s=r.length,o=-1,r===e||n(r.listener)&&r.listener===e)delete this._events[t],this._events.removeListener&&this.emit("removeListener",t,e);else if(i(r)){for(a=s;a-->0;)if(r[a]===e||r[a].listener&&r[a].listener===e){o=a;break}if(0>o)return this;1===r.length?(r.length=0,delete this._events[t]):r.splice(o,1),this._events.removeListener&&this.emit("removeListener",t,e)}return this},r.prototype.removeAllListeners=function(t){var e,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[t]&&delete this._events[t],this;if(0===arguments.length){for(e in this._events)"removeListener"!==e&&this.removeAllListeners(e);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[t],n(r))this.removeListener(t,r);else if(r)for(;r.length;)this.removeListener(t,r[r.length-1]);return delete this._events[t],this},r.prototype.listeners=function(t){var e;return e=this._events&&this._events[t]?n(this._events[t])?[this._events[t]]:this._events[t].slice():[]},r.prototype.listenerCount=function(t){if(this._events){var e=this._events[t];if(n(e))return 1;if(e)return e.length}return 0},r.listenerCount=function(t,e){return t.listenerCount(e)}},{}],10:[function(t,e){function r(t,e){e||(e={});var r="object"==typeof t?[t]:a(t);return l||(l=document.createElement("div")),o(h(e),function(t){var i=e[t];o(r,function(e){var r=e.parentNode;if(":first"===t)n(e,i);else if(/:first$/.test(t)){var o=t.replace(/:first$/,"");r&&r.removeChild(e),l.appendChild(e);var s=l.querySelector(o);l.removeChild(e),r&&r.appendChild(e),s&&n(s,i)}else{r&&r.removeChild(e),l.appendChild(e);var a=e.parentNode.querySelectorAll(t);if(l.removeChild(e),r&&r.appendChild(e),0===a.length)return;for(var h=0;h=0&&(t.splice instanceof Function||Object.getOwnPropertyDescriptor(t,t.length-1)&&"String"!==t.constructor.name):!1 2 | }},{}],14:[function(t,e,r){!function(t){function e(t,e){for(var r=0,n=t.length-1;n>=0;n--){var o=t[n];"."===o?t.splice(n,1):".."===o?(t.splice(n,1),r++):r&&(t.splice(n,1),r--)}if(e)for(;r--;r)t.unshift("..");return t}function n(t,e){if(t.filter)return t.filter(e);for(var r=[],n=0;n=-1&&!o;i--){var s=i>=0?arguments[i]:t.cwd();if("string"!=typeof s)throw new TypeError("Arguments to path.resolve must be strings");s&&(r=s+"/"+r,o="/"===s.charAt(0))}return r=e(n(r.split("/"),function(t){return!!t}),!o).join("/"),(o?"/":"")+r||"."},r.normalize=function(t){var o=r.isAbsolute(t),i="/"===s(t,-1);return t=e(n(t.split("/"),function(t){return!!t}),!o).join("/"),t||o||(t="."),t&&i&&(t+="/"),(o?"/":"")+t},r.isAbsolute=function(t){return"/"===t.charAt(0)},r.join=function(){var t=Array.prototype.slice.call(arguments,0);return r.normalize(n(t,function(t){if("string"!=typeof t)throw new TypeError("Arguments to path.join must be strings");return t}).join("/"))},r.relative=function(t,e){function n(t){for(var e=0;e=0&&""===t[r];r--);return e>r?[]:t.slice(e,r-e+1)}t=r.resolve(t).substr(1),e=r.resolve(e).substr(1);for(var o=n(t.split("/")),i=n(e.split("/")),s=Math.min(o.length,i.length),a=s,l=0;s>l;l++)if(o[l]!==i[l]){a=l;break}for(var h=[],l=a;le&&(e=t.length+e),t.substr(e,r)}}.call(this,t("_process"))},{_process:15}],15:[function(t,e){function r(){throw new Error("setTimeout has not been defined")}function n(){throw new Error("clearTimeout has not been defined")}function o(t){if(u===setTimeout)return setTimeout(t,0);if((u===r||!u)&&setTimeout)return u=setTimeout,setTimeout(t,0);try{return u(t,0)}catch(e){try{return u.call(null,t,0)}catch(e){return u.call(this,t,0)}}}function i(t){if(c===clearTimeout)return clearTimeout(t);if((c===n||!c)&&clearTimeout)return c=clearTimeout,clearTimeout(t);try{return c(t)}catch(e){try{return c.call(null,t)}catch(e){return c.call(this,t)}}}function s(){v&&p&&(v=!1,p.length?d=p.concat(d):g=-1,d.length&&a())}function a(){if(!v){var t=o(s);v=!0;for(var e=d.length;e;){for(p=d,d=[];++g1)for(var r=1;ri;i++)e[i]=t[i]}else{var s=r(t);e={};for(var i=0,a=s.length;a>i;i++){var l=s[i];e[l]=t[l]}}return e};var r=Object.keys||function(t){var e=[];for(var r in t)({}).hasOwnProperty.call(t,r)&&e.push(r);return e},n=Array.isArray||function(t){return"[object Array]"==={}.toString.call(t)}},{}],17:[function(t,e){"use strict";var r=t("is-arrayish"),n=Array.prototype.concat,o=Array.prototype.slice,i=e.exports=function(t){for(var e=[],i=0,s=t.length;s>i;i++){var a=t[i];r(a)?e=n.call(e,o.call(a)):e.push(a)}return e};i.wrap=function(t){return function(){return t(i(arguments))}}},{"is-arrayish":13}],18:[function(t,e){function r(){for(var t={},e=0;e