├── .gitignore ├── images └── background.jpg ├── package.json ├── scss ├── demo.scss └── normalize.scss ├── LICENSE ├── css ├── demo.css └── normalize.css ├── gulpfile.js ├── js ├── promise.min.js ├── demo.js ├── brushstroke.js └── rasterizeHTML.allinone.js ├── index.html ├── README.md └── dist ├── brushstroke.min.js └── brushstroke.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ -------------------------------------------------------------------------------- /images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmgonzalves/brushstroke/HEAD/images/background.jpg -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "brushstroke", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/brushstroke.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/lmgonzalves/brushstroke.git" 9 | }, 10 | "keywords": [ 11 | "brushstroke", 12 | "canvas", 13 | "animation" 14 | ], 15 | "author": "lmgonzalves", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/lmgonzalves/brushstroke/issues" 19 | }, 20 | "homepage": "http://lmgonzalves.github.io/brushstroke/", 21 | "engine": { 22 | "node": ">=6.0" 23 | }, 24 | "devDependencies": { 25 | "browser-sync": "^2.13.0", 26 | "gulp": "^3.9.1", 27 | "gulp-autoprefixer": "^3.1.0", 28 | "gulp-rename": "^1.2.2", 29 | "gulp-sass": "^2.3.1", 30 | "gulp-uglify": "^1.5.3" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /scss/demo.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | 6 | body { 7 | background-color: #000; 8 | text-align: center; 9 | } 10 | 11 | canvas { 12 | top: 50%; 13 | left: 50%; 14 | max-width: 100%; 15 | max-height: 100%; 16 | transform: translate(-50%, -50%); 17 | 18 | &:nth-of-type(1), &:nth-of-type(3) { 19 | width: 100%; 20 | height: 100%; 21 | } 22 | } 23 | 24 | button { 25 | position: relative; 26 | display: inline-block; 27 | top: 10%; 28 | color: #fff; 29 | background-color: #bc3a3a; 30 | border: none; 31 | text-transform: uppercase; 32 | padding: 10px 30px; 33 | border-radius: 2px; 34 | z-index: 1; 35 | transition: 0.3s; 36 | box-shadow: 0 0 10px 5px rgba(#bc3a3a, 0.5); 37 | 38 | &:hover { 39 | background-color: lighten(#bc3a3a, 5%); 40 | } 41 | 42 | &.hidden { 43 | transform: translateY(-150%); 44 | opacity: 0; 45 | pointer-events: none; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 lmgonzalves 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /css/demo.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | 6 | body { 7 | background-color: #000; 8 | text-align: center; 9 | } 10 | 11 | canvas { 12 | top: 50%; 13 | left: 50%; 14 | max-width: 100%; 15 | max-height: 100%; 16 | -webkit-transform: translate(-50%, -50%); 17 | -ms-transform: translate(-50%, -50%); 18 | transform: translate(-50%, -50%); 19 | } 20 | 21 | canvas:nth-of-type(1), canvas:nth-of-type(3) { 22 | width: 100%; 23 | height: 100%; 24 | } 25 | 26 | button { 27 | position: relative; 28 | display: inline-block; 29 | top: 10%; 30 | color: #fff; 31 | background-color: #bc3a3a; 32 | border: none; 33 | text-transform: uppercase; 34 | padding: 10px 30px; 35 | border-radius: 2px; 36 | z-index: 1; 37 | -webkit-transition: 0.3s; 38 | transition: 0.3s; 39 | -webkit-box-shadow: 0 0 10px 5px rgba(188, 58, 58, 0.5); 40 | box-shadow: 0 0 10px 5px rgba(188, 58, 58, 0.5); 41 | } 42 | 43 | button:hover { 44 | background-color: #c74949; 45 | } 46 | 47 | button.hidden { 48 | -webkit-transform: translateY(-150%); 49 | -ms-transform: translateY(-150%); 50 | transform: translateY(-150%); 51 | opacity: 0; 52 | pointer-events: none; 53 | } 54 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | browserSync = require('browser-sync'), 3 | sass = require('gulp-sass'), 4 | prefix = require('gulp-autoprefixer'), 5 | uglify = require('gulp-uglify'), 6 | rename = require('gulp-rename'); 7 | 8 | gulp.task('serve', ['sass', 'dist'], function() { 9 | browserSync.init({ 10 | server: { 11 | baseDir: "./" 12 | }, 13 | open: false, 14 | online: false, 15 | notify: false 16 | }); 17 | 18 | gulp.watch('scss/*.scss', ['sass']); 19 | gulp.watch('js/brushstroke.js', ['dist']); 20 | gulp.watch(['*.html', 'js/*']).on('change', browserSync.reload); 21 | }); 22 | 23 | gulp.task('sass', function () { 24 | return gulp.src('scss/*.scss') 25 | .pipe(sass({ 26 | outputStyle: 'expanded', 27 | includePaths: ['scss'] 28 | })) 29 | .pipe(prefix(['last 10 versions', '> 1%'], {cascade: true})) 30 | .pipe(gulp.dest('css')) 31 | .pipe(browserSync.reload({stream:true})); 32 | }); 33 | 34 | gulp.task('dist', function(){ 35 | return gulp.src('js/brushstroke.js') 36 | .pipe(gulp.dest('dist')) 37 | .pipe(uglify({preserveComments: 'some'})) 38 | .pipe(rename({suffix: '.min'})) 39 | .pipe(gulp.dest('dist')) 40 | .pipe(browserSync.reload({stream:true})); 41 | }); 42 | 43 | gulp.task('default', ['serve']); 44 | -------------------------------------------------------------------------------- /js/promise.min.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(){}function t(e,n){return function(){e.apply(n,arguments)}}function o(e){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],s(e,this)}function i(e,n){for(;3===e._state;)e=e._value;return 0===e._state?void e._deferreds.push(n):(e._handled=!0,void o._immediateFn(function(){var t=1===e._state?n.onFulfilled:n.onRejected;if(null===t)return void(1===e._state?r:u)(n.promise,e._value);var o;try{o=t(e._value)}catch(i){return void u(n.promise,i)}r(n.promise,o)}))}function r(e,n){try{if(n===e)throw new TypeError("A promise cannot be resolved with itself.");if(n&&("object"==typeof n||"function"==typeof n)){var i=n.then;if(n instanceof o)return e._state=3,e._value=n,void f(e);if("function"==typeof i)return void s(t(i,n),e)}e._state=1,e._value=n,f(e)}catch(r){u(e,r)}}function u(e,n){e._state=2,e._value=n,f(e)}function f(e){2===e._state&&0===e._deferreds.length&&o._immediateFn(function(){e._handled||o._unhandledRejectionFn(e._value)});for(var n=0,t=e._deferreds.length;n 2 | 3 | 4 | 5 | 6 | 7 | Brushstroke 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /js/demo.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // Declaring variables 4 | 5 | var paths = document.querySelectorAll('path'); 6 | var button = document.querySelector('button'); 7 | var animating = true; 8 | var width = window.innerWidth || document.body.clientWidth; 9 | var height = window.innerHeight || document.body.clientHeight; 10 | var optionsBackground, bsBackground, optionsPath, bsPath, optionsErase, bsErase; 11 | 12 | 13 | // Random curves for background 14 | 15 | optionsBackground = { 16 | animation: 'points', 17 | points: 10, 18 | inkAmount: 5, 19 | size: 300, 20 | frames: 10, 21 | frameAnimation: true, 22 | splashing: false, 23 | image: 'images/background.jpg', 24 | centered: true, 25 | queue: true, 26 | width: width, 27 | height: height 28 | }; 29 | bsBackground = new Brushstroke(optionsBackground); 30 | 31 | 32 | // Options for text (SVG paths) 33 | 34 | optionsPath = { 35 | animation: 'path', 36 | inkAmount: 2, 37 | frames: 20, 38 | frameAnimation: true, 39 | color: 'white', 40 | width: 1000, 41 | height: 300 42 | }; 43 | bsPath = new Brushstroke(optionsPath); 44 | 45 | 46 | // Function to start the animation 47 | 48 | function runAnimation() { 49 | // Draw a straight line 50 | bsBackground.draw({ 51 | points: [0, height / 2 - 40, width, height / 3] 52 | }); 53 | 54 | // Draw another straight line 55 | bsBackground.draw({ 56 | points: [width, height / 2, 0, height / 1.5 - 40] 57 | }); 58 | 59 | // Draw a curve generated using 20 random points 60 | bsBackground.draw({ 61 | inkAmount: 3, 62 | frames: 100, 63 | size: 200, 64 | splashing: true, 65 | points: 20, 66 | end: toggleButton 67 | }); 68 | 69 | // Draw each letter of the text, with a delay among them 70 | var delay = 0; 71 | for (var i = 0; i < paths.length; i++) { 72 | bsPath.draw({path: paths[i], delay: delay}); 73 | delay += 0.5; 74 | } 75 | } 76 | 77 | 78 | // Erase and run again 79 | 80 | optionsErase = { 81 | queue: true, 82 | size: 300, 83 | padding: 0, 84 | overlap: 100, 85 | inkAmount: 20, 86 | frames: 100, 87 | frameAnimation: true, 88 | color: '#000', 89 | width: width, 90 | height: height, 91 | end: function () { 92 | // Clear all canvas and run animation 93 | bsBackground.clear(); 94 | bsPath.clear(); 95 | bsErase.clear(); 96 | runAnimation(); 97 | } 98 | }; 99 | bsErase = new Brushstroke(optionsErase); 100 | 101 | 102 | // Run again button 103 | 104 | button.addEventListener('click', function () { 105 | if (!animating) { 106 | toggleButton(); 107 | bsErase.draw(); 108 | } 109 | }); 110 | 111 | function toggleButton() { 112 | button.classList.toggle('hidden'); 113 | animating = !animating; 114 | } 115 | 116 | 117 | // Start 118 | 119 | runAnimation(); 120 | 121 | })(); 122 | -------------------------------------------------------------------------------- /css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ 2 | html { 3 | font-family: sans-serif; 4 | -ms-text-size-adjust: 100%; 5 | -webkit-text-size-adjust: 100%; 6 | } 7 | 8 | body { 9 | margin: 0; 10 | } 11 | 12 | article, 13 | aside, 14 | details, 15 | figcaption, 16 | figure, 17 | footer, 18 | header, 19 | hgroup, 20 | main, 21 | menu, 22 | nav, 23 | section, 24 | summary { 25 | display: block; 26 | } 27 | 28 | audio, 29 | canvas, 30 | progress, 31 | video { 32 | display: inline-block; 33 | vertical-align: baseline; 34 | } 35 | 36 | audio:not([controls]) { 37 | display: none; 38 | height: 0; 39 | } 40 | 41 | [hidden], 42 | template { 43 | display: none; 44 | } 45 | 46 | a { 47 | background-color: transparent; 48 | } 49 | 50 | a:active, 51 | a:hover { 52 | outline: 0; 53 | } 54 | 55 | abbr[title] { 56 | border-bottom: 1px dotted; 57 | } 58 | 59 | b, 60 | strong { 61 | font-weight: bold; 62 | } 63 | 64 | dfn { 65 | font-style: italic; 66 | } 67 | 68 | h1 { 69 | font-size: 2em; 70 | margin: 0.67em 0; 71 | } 72 | 73 | mark { 74 | background: #ff0; 75 | color: #000; 76 | } 77 | 78 | small { 79 | font-size: 80%; 80 | } 81 | 82 | sub, 83 | sup { 84 | font-size: 75%; 85 | line-height: 0; 86 | position: relative; 87 | vertical-align: baseline; 88 | } 89 | 90 | sup { 91 | top: -0.5em; 92 | } 93 | 94 | sub { 95 | bottom: -0.25em; 96 | } 97 | 98 | img { 99 | border: 0; 100 | } 101 | 102 | svg:not(:root) { 103 | overflow: hidden; 104 | } 105 | 106 | figure { 107 | margin: 1em 40px; 108 | } 109 | 110 | hr { 111 | -webkit-box-sizing: content-box; 112 | box-sizing: content-box; 113 | height: 0; 114 | } 115 | 116 | pre { 117 | overflow: auto; 118 | } 119 | 120 | code, 121 | kbd, 122 | pre, 123 | samp { 124 | font-family: monospace, monospace; 125 | font-size: 1em; 126 | } 127 | 128 | button, 129 | input, 130 | optgroup, 131 | select, 132 | textarea { 133 | color: inherit; 134 | font: inherit; 135 | margin: 0; 136 | } 137 | 138 | button { 139 | overflow: visible; 140 | } 141 | 142 | button, 143 | select { 144 | text-transform: none; 145 | } 146 | 147 | button, 148 | html input[type="button"], 149 | input[type="reset"], 150 | input[type="submit"] { 151 | -webkit-appearance: button; 152 | cursor: pointer; 153 | } 154 | 155 | button[disabled], 156 | html input[disabled] { 157 | cursor: default; 158 | } 159 | 160 | button::-moz-focus-inner, 161 | input::-moz-focus-inner { 162 | border: 0; 163 | padding: 0; 164 | } 165 | 166 | input { 167 | line-height: normal; 168 | } 169 | 170 | input[type="checkbox"], 171 | input[type="radio"] { 172 | -webkit-box-sizing: border-box; 173 | box-sizing: border-box; 174 | padding: 0; 175 | } 176 | 177 | input[type="number"]::-webkit-inner-spin-button, 178 | input[type="number"]::-webkit-outer-spin-button { 179 | height: auto; 180 | } 181 | 182 | input[type="search"] { 183 | -webkit-appearance: textfield; 184 | -webkit-box-sizing: content-box; 185 | box-sizing: content-box; 186 | } 187 | 188 | input[type="search"]::-webkit-search-cancel-button, 189 | input[type="search"]::-webkit-search-decoration { 190 | -webkit-appearance: none; 191 | } 192 | 193 | fieldset { 194 | border: 1px solid #c0c0c0; 195 | margin: 0 2px; 196 | padding: 0.35em 0.625em 0.75em; 197 | } 198 | 199 | legend { 200 | border: 0; 201 | padding: 0; 202 | } 203 | 204 | textarea { 205 | overflow: auto; 206 | } 207 | 208 | optgroup { 209 | font-weight: bold; 210 | } 211 | 212 | table { 213 | border-collapse: collapse; 214 | border-spacing: 0; 215 | } 216 | 217 | td, 218 | th { 219 | padding: 0; 220 | } 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Brushstroke 2 | 3 | Brushstrokes on the web: draw solid colors, images, or even HTML! 4 | 5 | [**DEMO**](https://lmgonzalves.github.io/brushstroke/) 6 | 7 | [**TUTORIAL**](https://scotch.io/tutorials/drawing-creative-brushstrokes-with-javascript) 8 | 9 | ## Usage 10 | 11 | The `brushstroke` library has no mandatory dependencies, but: 12 | 13 | - It uses promises, so if you want to support IE or any other browser that does not support native promises, you need a polyfill. [This](https://github.com/taylorhakes/promise-polyfill) is a tiny one :) 14 | - To draw HTML, it uses [rasterizeHTML.js](https://github.com/cburgmer/rasterizeHTML.js). 15 | 16 | So, include the `brushstroke` script (and dependencies mentioned above, if you need them) and start drawing things: 17 | 18 | ```html 19 | 20 | 21 | 36 | ``` 37 | 38 | ## Options 39 | 40 | For customization, you can pass `options` (in object notation) to `Brushstroke` constructor. These options overrides defaults, and will be used for any operation (draw, erase, etc.). You can also override options for an specific operation. Here is the complete list, for reference: 41 | 42 | | Name | Type | Default | Description | 43 | |-------------------------|-------------------------|-----------------|-------------| 44 | |`animation` | String | 'to-bottom' | Type of animation. Possible values are: `to-bottom`, `to-top`, `to-right`, `to-left`, `path`, `points`. See details below. | 45 | |`path` | String or DOM Element | undefined | Path element (or `d` attribute as String) to perform a `path` animation. | 46 | |`points` | Array or Integer | undefined | Array of points (or a number indicating the amount of random points to generate an Array) to perform a `points` animation. | 47 | |`frameAnimation` | Boolean | false | If true, the animation will be frame-based instead time-based. This could be better to get a consistent drawing, but it can affect performance. | 48 | |`frames` | Integer | 0 | Number of frames to perform a frame-based animation. If `frameAnimation` is `false` and you define `frames > 0`, there will be no animation, but drawing will be calculated and showed ASAP, using the number of frames defined. | 49 | |`duration` | Float | 0 | Duration (in seconds) to perform a time-based animation. If `frameAnimation` is `true` and `frames` is not defined, duration will be translated to frames, considering `1 second = 60 frames`. | 50 | |`delay` | Float | 0 | Delay (in seconds) to begin the animation. | 51 | |`color` | String | '#ccc' | Valid color value to be used in drawing. | 52 | |`width` | Float | 300 | Width (in pixels) for the `canvas`. | 53 | |`height` | Float | 120 | Height (in pixels) for the `canvas`. | 54 | |`size` | Float | 40 | Size of the brush. | 55 | |`inkAmount` | Float | 1 | Amount of "ink" used. Higher values results in stronger drawings. | 56 | |`lifting` | Boolean | false | Determines if basic animations (`to-bottom`, `to-top`, `to-right`, `to-left`) must be performed without lifting the brush (continuous drawing), or as several separate drawings (straight lines). | 57 | |`dripping` | Boolean | false | Determines if it should drips in case there is to much ink. | 58 | |`splashing` | Boolean | true | Determines if the brush should splash in case of fast draw. | 59 | |`padding` | Float | 30 | Separation between border and drawing for basic animations (`to-bottom`, `to-top`, `to-right`, `to-left`). | 60 | |`overlap` | Float | 10 | Overlap among lines for basic animations (`to-bottom`, `to-top`, `to-right`, `to-left`). | 61 | |`tension` | Float | 0.5 | Used in `points` and basic animations (`to-bottom`, `to-top`, `to-right`, `to-left`) to customize curvature. Typically between [0.0, 1.0] but can be exceeded. | 62 | |`reduceOverflow` | Integer | 20 | This value decreases the overflow in generated curves for basic animations (`to-bottom`, `to-top`, `to-right`, `to-left`). | 63 | |`root` | String or DOM Element | body | DOM Element (or String selector to get it) to append `canvas`. | 64 | |`el` | String or DOM Element | undefined | DOM Element (or String selector to get it) to rasterize as image to draw. This require [rasterizeHTML.js](https://github.com/cburgmer/rasterizeHTML.js). | 65 | |`image` | String | undefined | Image `src` to draw. | 66 | |`repeat` | String | 'no-repeat' | Indicates how to repeat the image. Possible values are: `no-repeat`, `repeat`, `repeat-x`, `repeat-y`. | 67 | |`stretch` | Boolean | true | Indicates if the image should be stretched in canvas. | 68 | |`queue` | Boolean | false | Indicates if animations should be queued. | 69 | 70 | ### Possible animation values 71 | 72 | These are all the possible `animation` values: 73 | 74 | - Basic animations (`to-bottom`, `to-top`, `to-right`, `to-left`): This will perform the drawing in te specified direction. 75 | - Path animations (`path`): This will perform the drawing using a SVG path as reference. You must defined the `path` option to specify the path element (or `d` attribute as String). 76 | - Points animations (`points`): This will perform the drawing using a curve generated from an Array of points in format `[x1, y1, x2, y2, ...]`. You must defined the `points` option to specify the Array of points (or a number indicating the amount of random points to generate an Array). 77 | 78 | ## Operations 79 | 80 | These are all the possible operations can be performed with a `Brushstroke` instance: 81 | 82 | - `draw(options)`: Draw using the specified configuration. 83 | - `erase(options)`: Like draw, but instead it erase the canvas. 84 | - `fill(options)`: Fill the canvas with defined `el` (HTML) or `image` with no animation. 85 | - `clear()`: Clear the canvas with no animation. 86 | -------------------------------------------------------------------------------- /scss/normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | // 4 | // 1. Set default font family to sans-serif. 5 | // 2. Prevent iOS and IE text size adjust after device orientation change, 6 | // without disabling user zoom. 7 | // 8 | 9 | html { 10 | font-family: sans-serif; // 1 11 | -ms-text-size-adjust: 100%; // 2 12 | -webkit-text-size-adjust: 100%; // 2 13 | } 14 | 15 | // 16 | // Remove default margin. 17 | // 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | // HTML5 display definitions 24 | // ========================================================================== 25 | 26 | // 27 | // Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | // Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | // and Firefox. 30 | // Correct `block` display not defined for `main` in IE 11. 31 | // 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | // 50 | // 1. Correct `inline-block` display not defined in IE 8/9. 51 | // 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | // 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; // 1 59 | vertical-align: baseline; // 2 60 | } 61 | 62 | // 63 | // Prevent modern browsers from displaying `audio` without controls. 64 | // Remove excess height in iOS 5 devices. 65 | // 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | // 73 | // Address `[hidden]` styling not present in IE 8/9/10. 74 | // Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. 75 | // 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | // Links 83 | // ========================================================================== 84 | 85 | // 86 | // Remove the gray background color from active links in IE 10. 87 | // 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | // 94 | // Improve readability of focused elements when they are also in an 95 | // active/hover state. 96 | // 97 | 98 | a:active, 99 | a:hover { 100 | outline: 0; 101 | } 102 | 103 | // Text-level semantics 104 | // ========================================================================== 105 | 106 | // 107 | // Address styling not present in IE 8/9/10/11, Safari, and Chrome. 108 | // 109 | 110 | abbr[title] { 111 | border-bottom: 1px dotted; 112 | } 113 | 114 | // 115 | // Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 116 | // 117 | 118 | b, 119 | strong { 120 | font-weight: bold; 121 | } 122 | 123 | // 124 | // Address styling not present in Safari and Chrome. 125 | // 126 | 127 | dfn { 128 | font-style: italic; 129 | } 130 | 131 | // 132 | // Address variable `h1` font-size and margin within `section` and `article` 133 | // contexts in Firefox 4+, Safari, and Chrome. 134 | // 135 | 136 | h1 { 137 | font-size: 2em; 138 | margin: 0.67em 0; 139 | } 140 | 141 | // 142 | // Address styling not present in IE 8/9. 143 | // 144 | 145 | mark { 146 | background: #ff0; 147 | color: #000; 148 | } 149 | 150 | // 151 | // Address inconsistent and variable font size in all browsers. 152 | // 153 | 154 | small { 155 | font-size: 80%; 156 | } 157 | 158 | // 159 | // Prevent `sub` and `sup` affecting `line-height` in all browsers. 160 | // 161 | 162 | sub, 163 | sup { 164 | font-size: 75%; 165 | line-height: 0; 166 | position: relative; 167 | vertical-align: baseline; 168 | } 169 | 170 | sup { 171 | top: -0.5em; 172 | } 173 | 174 | sub { 175 | bottom: -0.25em; 176 | } 177 | 178 | // Embedded content 179 | // ========================================================================== 180 | 181 | // 182 | // Remove border when inside `a` element in IE 8/9/10. 183 | // 184 | 185 | img { 186 | border: 0; 187 | } 188 | 189 | // 190 | // Correct overflow not hidden in IE 9/10/11. 191 | // 192 | 193 | svg:not(:root) { 194 | overflow: hidden; 195 | } 196 | 197 | // Grouping content 198 | // ========================================================================== 199 | 200 | // 201 | // Address margin not present in IE 8/9 and Safari. 202 | // 203 | 204 | figure { 205 | margin: 1em 40px; 206 | } 207 | 208 | // 209 | // Address differences between Firefox and other browsers. 210 | // 211 | 212 | hr { 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | // 218 | // Contain overflow in all browsers. 219 | // 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | // 226 | // Address odd `em`-unit font size rendering in all browsers. 227 | // 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | // Forms 238 | // ========================================================================== 239 | 240 | // 241 | // Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | // styling of `select`, unless a `border` property is set. 243 | // 244 | 245 | // 246 | // 1. Correct color not being inherited. 247 | // Known issue: affects color of disabled elements. 248 | // 2. Correct font properties not being inherited. 249 | // 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | // 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; // 1 258 | font: inherit; // 2 259 | margin: 0; // 3 260 | } 261 | 262 | // 263 | // Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | // 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | // 271 | // Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | // All other form control elements do not inherit `text-transform` values. 273 | // Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | // Correct `select` style inheritance in Firefox. 275 | // 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | // 283 | // 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | // and `video` controls. 285 | // 2. Correct inability to style clickable `input` types in iOS. 286 | // 3. Improve usability and consistency of cursor style between image-type 287 | // `input` and others. 288 | // 289 | 290 | button, 291 | html input[type="button"], // 1 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; // 2 295 | cursor: pointer; // 3 296 | } 297 | 298 | // 299 | // Re-set default cursor for disabled elements. 300 | // 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | // 308 | // Remove inner padding and border in Firefox 4+. 309 | // 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | // 318 | // Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | // the UA stylesheet. 320 | // 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | // 327 | // It's recommended that you don't attempt to style these elements. 328 | // Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | // 330 | // 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | // 2. Remove excess padding in IE 8/9/10. 332 | // 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; // 1 337 | padding: 0; // 2 338 | } 339 | 340 | // 341 | // Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | // `font-size` values of the `input`, it causes the cursor style of the 343 | // decrement button to change from `default` to `text`. 344 | // 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | // 352 | // 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | // 2. Address `box-sizing` set to `border-box` in Safari and Chrome. 354 | // 355 | 356 | input[type="search"] { 357 | -webkit-appearance: textfield; // 1 358 | box-sizing: content-box; //2 359 | } 360 | 361 | // 362 | // Remove inner padding and search cancel button in Safari and Chrome on OS X. 363 | // Safari (but not Chrome) clips the cancel button when the search input has 364 | // padding (and `textfield` appearance). 365 | // 366 | 367 | input[type="search"]::-webkit-search-cancel-button, 368 | input[type="search"]::-webkit-search-decoration { 369 | -webkit-appearance: none; 370 | } 371 | 372 | // 373 | // Define consistent border, margin, and padding. 374 | // 375 | 376 | fieldset { 377 | border: 1px solid #c0c0c0; 378 | margin: 0 2px; 379 | padding: 0.35em 0.625em 0.75em; 380 | } 381 | 382 | // 383 | // 1. Correct `color` not being inherited in IE 8/9/10/11. 384 | // 2. Remove padding so people aren't caught out if they zero out fieldsets. 385 | // 386 | 387 | legend { 388 | border: 0; // 1 389 | padding: 0; // 2 390 | } 391 | 392 | // 393 | // Remove default vertical scrollbar in IE 8/9/10/11. 394 | // 395 | 396 | textarea { 397 | overflow: auto; 398 | } 399 | 400 | // 401 | // Don't inherit the `font-weight` (applied by a rule above). 402 | // NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 403 | // 404 | 405 | optgroup { 406 | font-weight: bold; 407 | } 408 | 409 | // Tables 410 | // ========================================================================== 411 | 412 | // 413 | // Remove most spacing between table cells. 414 | // 415 | 416 | table { 417 | border-collapse: collapse; 418 | border-spacing: 0; 419 | } 420 | 421 | td, 422 | th { 423 | padding: 0; 424 | } 425 | -------------------------------------------------------------------------------- /dist/brushstroke.min.js: -------------------------------------------------------------------------------- 1 | !function(t,i){"function"==typeof define&&define.amd?define([],i):"object"==typeof module&&module.exports?module.exports=i():t.Brushstroke=i()}(this,function(){function t(t,i,e,s){"use strict";function n(t,i,s,n){for(var o,r=2;r0&&i!=parseInt(i)&&t!=parseInt(t)}catch(e){return!1}}function o(t){var i=getComputedStyle(t),e="";for(var s in i)n(s,i[s])&&(e+=s+":"+i[s]+";");t.style.cssText+=e+";visibility:visible;"}function r(t,i){for(var e=t.children,s=0;sn*n+o*o&&this._strokeId!==l.strokeId||l.life<=0?(u.splice(r,1),a--,r--):l.render(t)}if(h){var c,f=this._tip;this._strokeId;if(n=this.x-this._latestPos.x,o=this.y-this._latestPos.y,c=Math.sqrt(n*n+o*o),this.splashing&&c>this._SPLASHING_BRUSH_SPEED){var p,m,g,x,v,y=.5*(c-this._SPLASHING_BRUSH_SPEED)|0;for(t.save(),t.fillStyle=this.color,t.beginPath(),r=0,a=y*Math.random()|0;rthis.maxHairs&&(u=this.maxHairs),l=0;l1?n=1:n<0&&(n=0),t.save(),t.lineCap=t.lineJoin="round",t.strokeStyle=this.color,t.lineWidth=this.inkAmount*n,t.beginPath(),t.moveTo(this._latestPos.x,this._latestPos.y),t.lineTo(this.x,this.y),t.stroke(),t.restore()}},e.prototype={x:0,y:0,size:7,color:"#000",strokeId:null,life:0,_latestPos:null,_xOffRatio:0,render:function(t){Math.random()<.03?this._xOffRatio+=.06*Math.random()-.03:Math.random()<.1&&(this._xOffRatio*=.003),this._latestPos.x=this.x,this._latestPos.y=this.y,this.x+=this.life*this._xOffRatio,this.y+=.5*this.life*Math.random(),this.life-=.04*Math.random()+.01,t.save(),t.lineCap=t.lineJoin="round",t.strokeStyle=this.color,t.lineWidth=this.size+.3*this.life,t.beginPath(),t.moveTo(this._latestPos.x,this._latestPos.y),t.lineTo(this.x,this.y),t.stroke(),t.restore(),t.restore()}},t}(),x={obj:function(t){return Object.prototype.toString.call(t).indexOf("Object")>-1},num:function(t){return"number"==typeof t},str:function(t){return"string"==typeof t},fnc:function(t){return"function"==typeof t},und:function(t){return"undefined"==typeof t}};return m.prototype={init:function(t){var i=s(this.defaults,t);x.str(i.root)&&(i.root=document.querySelector(i.root)),x.str(i.el)&&(i.el=document.querySelector(i.el)),p(i);var e=d();this.promise=e.promise,e.resolve()},run:function(t){function e(){t.canvas.style.visibility="visible",t.render?s.render(t):i(s.animations[t.animation],s,t)}var s=this;if(t.clear)t.ctx.clearRect(0,0,t.width,t.height),t.d.resolve();else if(t.el)if(t.pattern)e();else{var n=""+h(t.el);rasterizeHTML.drawHTML(n,null).then(function(i){t.fill?(t.ctx.drawImage(i.image,0,0,t.width,t.height),t.d.resolve()):(t.pattern=t.ctx.createPattern(i.image,t.repeat),e())},function(t){console.log("rasterizeHTMLError: "+t)})}else if(t.image){var o=new Image;o.onload=function(){(t.stretch||t.centered)&&(o=f(o,t)),t.fill?(t.ctx.drawImage(o,0,0,t.width,t.height),t.d.resolve()):(t.pattern=t.ctx.createPattern(o,t.repeat),e())},o.src=t.image}else e()},draw:function(t){var i=this,e=s({},this.defaults,t),n=function(){var t=d();return i.run(s(e,{d:t})),t.promise};e.queue?this.promise=this.promise.then(n):n()},erase:function(t){this.draw(s({},t,{erase:!0}))},fill:function(t){this.draw(s({},t,{fill:!0}))},clear:function(t){this.draw(s({},t,{clear:!0}))},setPath:function(t){var i=t.path;x.str(i)&&(i=document.createElementNS("http://www.w3.org/2000/svg","path"),i.setAttribute("d",t.path),t.path=i),t.pathLenght=i.getTotalLength()},pointAt:function(t,i){switch(i.animation){case"points":var e=i.points,s=e.length,n=2*Math.round(s*t/2);return n>=s&&(n=s-2),{x:e[n],y:e[n+1]};case"path":return i.path.getPointAtLength(i.pathLenght*t);default:return null}},setPos:function(t,i){var e=!i;switch(e&&(i={}),t.direction){case"bottom":i.startY=e?t.padding:i.startY+t.size-t.overlap,this.setPosBottomTop(t,i,e);break;case"top":i.startY=e?t.height-t.padding:i.startY-t.size+t.overlap,this.setPosBottomTop(t,i,e);break;case"right":i.startX=e?t.padding:i.startX+t.size-t.overlap,this.setPosRightLeft(t,i,e);break;case"left":i.startX=e?t.width-t.padding:i.startX-t.size+t.overlap,this.setPosRightLeft(t,i,e)}return i},setPosBottomTop:function(t,i,e){if(e)i.vertical=!0;else var s=i.startX;i.startX=e?t.padding:i.x,i.x=e?t.width-t.padding:s,i.y=i.startY},setPosRightLeft:function(t,i,e){if(e)i.vertical=!1;else var s=i.startY;i.x=i.startX,i.startY=e?t.padding:i.y,i.y=e?t.height-t.padding:s},render:function(t){if(!x.und(t.duration)||!x.und(t.frames)){var e=this;if(t.delay){var s=t.delay;return delete t.delay,void setTimeout(function(){e.render(t)},1e3*s)}t.erase&&(t.ctx.globalCompositeOperation="destination-out");var n,o,r,a,h=1,l=0,u=0,d=new Date;x.und(t.startX)||(l=t.startX),x.und(t.startY)||(u=t.startY);var c=new g(l,u,t.pattern||t.color,t.size,t.inkAmount,t.angle,t.dripping,t.splashing);c.startStroke(l,u),i(t.begin),t.frameAnimation&&t.duration&&(t.frames||(t.frames=60*parseFloat(t.duration)),delete t.duration),function f(){t.duration?(n=(new Date-d)/1e3,o=n/parseFloat(t.duration)):o=h/parseFloat(t.frames),r=o,x.fnc(t.easing)&&(r=t.easing(r)),o>1&&(r=1),a=e.pointAt(r,t),a||(a={x:l+(t.x-l)*r,y:u+(t.y-u)*r}),l=a.x,u=a.y,c.render(t.ctx,l,u),o>=1?(c.endStroke(),t.erase&&(t.ctx.globalCompositeOperation="source-over"),i(t.end),t.d.resolve()):t.duration?requestAnimationFrame(f):(h++,t.frameAnimation?requestAnimationFrame(f):f())}()}},animations:{"to-bottom":function(t){i(this.animations.basic,this,s(t,{direction:"bottom"}))},"to-top":function(t){i(this.animations.basic,this,s(t,{direction:"top"}))},"to-right":function(t){i(this.animations.basic,this,s(t,{direction:"right"}))},"to-left":function(t){i(this.animations.basic,this,s(t,{direction:"left"}))},basic:function(t){function e(t){0===m&&(a[t]=a[t]-p),1===m&&(a[t]=a[t]+p),m===h-1&&(a[t]=f?a[t]+p:a[t]-p)}for(var n,o,r,a=this.setPos(t),h=Math.ceil(((a.vertical?t.height:t.width)+t.size/2-2*t.padding)/(t.size-t.overlap)),l=a.vertical?.5*Math.PI:0,u=t.duration/h,d=t.frames/h,c=[],f=!0,p=t.reduceOverflow,m=0;m dx * dx + dy * dy && this._strokeId !== drop.strokeId) || 215 | drop.life <= 0 216 | ) { 217 | drops.splice(i, 1); 218 | len--; 219 | i--; 220 | continue; 221 | } 222 | 223 | drop.render(ctx); 224 | } 225 | } 226 | 227 | if (isStroke) { 228 | var tip = this._tip, 229 | strokeId = this._strokeId, 230 | dist; 231 | 232 | dx = this.x - this._latestPos.x; 233 | dy = this.y - this._latestPos.y; 234 | dist = Math.sqrt(dx * dx + dy * dy); 235 | 236 | if (this.splashing && dist > this._SPLASHING_BRUSH_SPEED) { 237 | var maxNum = (dist - this._SPLASHING_BRUSH_SPEED) * 0.5 | 0, 238 | r, a, sr, sx, sy; 239 | 240 | ctx.save(); 241 | ctx.fillStyle = this.color; 242 | ctx.beginPath(); 243 | for (i = 0, len = maxNum * Math.random() | 0; i < len; i++) { 244 | r = (dist - 1) * Math.random() + 1; 245 | a = Math.PI * 2 * Math.random(); 246 | sr = 5 * Math.random(); 247 | sx = this.x + r * Math.sin(a); 248 | sy = this.y + r * Math.cos(a); 249 | ctx.moveTo(sx + sr, sy); 250 | ctx.arc(sx, sy, sr, 0, Math.PI * 2, false); 251 | } 252 | ctx.fill(); 253 | ctx.restore(); 254 | 255 | } else if (this.dripping && dist < this.inkAmount * 2 && Math.random() < 0.05) { 256 | this._drops.push(new Drop( 257 | this.x, 258 | this.y, 259 | (this.size + this.inkAmount) * 0.5 * ((0.25 - 0.1) * Math.random() + 0.1), 260 | this.color, 261 | this._strokeId 262 | )); 263 | } 264 | 265 | for (i = 0, len = tip.length; i < len; i++) { 266 | tip[i].render(ctx, dx, dy, dist); 267 | } 268 | } 269 | }, 270 | 271 | dispose: function() { 272 | this._tip.length = this._drops.length = 0; 273 | }, 274 | 275 | _resetTip: function() { 276 | var tip = this._tip = [], 277 | rad = this.size * 0.5, 278 | x0, y0, a0, x1, y1, a1, cv, sv, 279 | i, len; 280 | 281 | //a1 = Math.PI * 2 * Math.random(); 282 | a1 = this.angle; 283 | len = rad * rad * Math.PI / this.inkAmount | 0; 284 | if (len < 1) len = 1; 285 | if (len > this.maxHairs) len = this.maxHairs; 286 | 287 | for (i = 0; i < len; i++) { 288 | x0 = rad * Math.random(); 289 | y0 = x0 * 0.5; 290 | a0 = Math.PI * 2 * Math.random(); 291 | x1 = x0 * Math.sin(a0); 292 | y1 = y0 * Math.cos(a0); 293 | cv = Math.cos(a1); 294 | sv = Math.sin(a1); 295 | 296 | tip.push(new Hair( 297 | this.x + x1 * cv - y1 * sv, 298 | this.y + x1 * sv + y1 * cv, 299 | this.inkAmount, 300 | this.color 301 | )); 302 | } 303 | } 304 | }; 305 | 306 | 307 | /** 308 | * Hair 309 | * @private 310 | */ 311 | function Hair(x, y, inkAmount, color) { 312 | this.x = x || 0; 313 | this.y = y || 0; 314 | this.inkAmount = inkAmount; 315 | this.color = color; 316 | 317 | this._latestPos = { x: this.x, y: this.y }; 318 | } 319 | 320 | Hair.prototype = { 321 | x: 0, 322 | y: 0, 323 | inkAmount: 7, 324 | color: '#000', 325 | _latestPos: null, 326 | 327 | render: function(ctx, offsetX, offsetY, offsetLength) { 328 | this._latestPos.x = this.x; 329 | this._latestPos.y = this.y; 330 | this.x += offsetX; 331 | this.y += offsetY; 332 | 333 | var per = offsetLength ? this.inkAmount / offsetLength : 0; 334 | if (per > 1) per = 1; 335 | else if (per < 0) per = 0; 336 | 337 | ctx.save(); 338 | ctx.lineCap = ctx.lineJoin = 'round'; 339 | ctx.strokeStyle = this.color; 340 | ctx.lineWidth = this.inkAmount * per; 341 | ctx.beginPath(); 342 | ctx.moveTo(this._latestPos.x, this._latestPos.y); 343 | ctx.lineTo(this.x, this.y); 344 | ctx.stroke(); 345 | ctx.restore(); 346 | } 347 | }; 348 | 349 | 350 | /** 351 | * Drop 352 | * @private 353 | */ 354 | function Drop(x, y, size, color, strokeId) { 355 | this.x = x || 0; 356 | this.y = y || 0; 357 | this.size = size; 358 | this.color = color; 359 | this.strokeId = strokeId; 360 | 361 | this.life = this.size * 1.5; 362 | this._latestPos = { x: this.x, y: this.y }; 363 | } 364 | 365 | Drop.prototype = { 366 | x: 0, 367 | y: 0, 368 | size: 7, 369 | color: '#000', 370 | strokeId: null, 371 | life: 0, 372 | _latestPos: null, 373 | _xOffRatio: 0, 374 | 375 | render: function(ctx) { 376 | if (Math.random() < 0.03) { 377 | this._xOffRatio += 0.06 * Math.random() - 0.03; 378 | } else if (Math.random() < 0.1) { 379 | this._xOffRatio *= 0.003; 380 | } 381 | 382 | this._latestPos.x = this.x; 383 | this._latestPos.y = this.y; 384 | this.x += this.life * this._xOffRatio; 385 | this.y += (this.life * 0.5) * Math.random(); 386 | 387 | this.life -= (0.05 - 0.01) * Math.random() + 0.01; 388 | 389 | ctx.save(); 390 | ctx.lineCap = ctx.lineJoin = 'round'; 391 | ctx.strokeStyle = this.color; 392 | ctx.lineWidth = this.size + this.life * 0.3; 393 | ctx.beginPath(); 394 | ctx.moveTo(this._latestPos.x, this._latestPos.y); 395 | ctx.lineTo(this.x, this.y); 396 | ctx.stroke(); 397 | ctx.restore(); 398 | ctx.restore(); 399 | } 400 | }; 401 | 402 | return Brush; 403 | 404 | })(); 405 | 406 | 407 | /******************** 408 | * Brushstroke utils 409 | ********************/ 410 | 411 | // Type of elements, most from anime.js 412 | 413 | var is = { 414 | obj: function(a) { return Object.prototype.toString.call(a).indexOf('Object') > -1 }, 415 | num: function(a) { return typeof a === 'number' }, 416 | str: function(a) { return typeof a === 'string' }, 417 | fnc: function(a) { return typeof a === 'function' }, 418 | und: function(a) { return typeof a === 'undefined' } 419 | }; 420 | 421 | // Functions 422 | 423 | function callFunction(fn, context, params) { 424 | if (is.fnc(fn)) fn.call(context, params); 425 | } 426 | 427 | // Objects 428 | 429 | function extendSingle(target, source) { 430 | for (var key in source) 431 | target[key] = source[key]; 432 | return target; 433 | } 434 | 435 | function extend(target, source) { 436 | if (!target) target = {}; 437 | for (var i = 1; i < arguments.length; i++) 438 | extendSingle(target, arguments[i]); 439 | return target; 440 | } 441 | 442 | // Styles 443 | 444 | function validProperty(property, value) { 445 | try { 446 | return !is.und(value) && 447 | !is.obj(value) && 448 | !is.fnc(value) && 449 | value.length > 0 && 450 | value != parseInt(value) && 451 | property != parseInt(property); 452 | } catch (e) { 453 | return false; 454 | } 455 | } 456 | 457 | function setStyle(el) { 458 | var computedStyle = getComputedStyle(el); 459 | var style = ''; 460 | for (var property in computedStyle) { 461 | if (validProperty(property, computedStyle[property])) { 462 | style += property + ':' + computedStyle[property] + ';'; 463 | } 464 | } 465 | el.style.cssText += style + ';visibility:visible;'; 466 | } 467 | 468 | function setStyleAll(el, list) { 469 | var children = el.children; 470 | for (var i = 0; i < children.length; i++) 471 | setStyleAll(children[i], list); 472 | list.push({el: el, style: el.style.cssText}); 473 | setStyle(el); 474 | } 475 | 476 | function restoreStyleAll(list) { 477 | var current; 478 | for (var i = 0; i < list.length; i++) { 479 | current = list[i]; 480 | if (current.style) { 481 | current.el.style.cssText = current.style; 482 | } else { 483 | current.el.removeAttribute('style'); 484 | } 485 | } 486 | } 487 | 488 | function getOuterHTML(el) { 489 | var list = []; 490 | setStyleAll(el, list); 491 | var html = el.outerHTML; 492 | restoreStyleAll(list); 493 | return html; 494 | } 495 | 496 | function fixRootPosition(root) { 497 | var style = getComputedStyle(root); 498 | var position = style.getPropertyValue('position'); 499 | if (position === 'static') { 500 | root.style.position = 'relative'; 501 | } 502 | } 503 | 504 | function setPosition(o) { 505 | var elRect = o.el.getBoundingClientRect(); 506 | var rootRect = o.root.getBoundingClientRect(); 507 | o.top = elRect.top - rootRect.top; 508 | o.left = elRect.left - rootRect.left; 509 | } 510 | 511 | // Promises 512 | 513 | function deferred() { 514 | return new function () { 515 | this.resolve = null; 516 | this.reject = null; 517 | 518 | this.promise = new Promise(function (resolve, reject) { 519 | this.resolve = resolve; 520 | this.reject = reject; 521 | }.bind(this)); 522 | }; 523 | } 524 | 525 | // Get random points in a 2d space 526 | 527 | function randomize(num, width, height) { 528 | var numPoints = num || 10; 529 | var points = []; 530 | for (var i = 0; i < numPoints; i++) { 531 | points.push( 532 | (width * Math.random() * 0.9 + width * 0.05) | 0, 533 | (height * Math.random() * 0.9 + height * 0.05) | 0 534 | ); 535 | } 536 | return points; 537 | } 538 | 539 | // Canvas 540 | 541 | function resizeImage(img, o) { 542 | var canvas = document.createElement('canvas'); 543 | canvas.width = o.width; 544 | canvas.height = o.height; 545 | var ctx = canvas.getContext("2d"); 546 | if (o.stretch) { 547 | ctx.drawImage(img, 0, 0, o.width, o.height); 548 | } else { 549 | var width = img.width; 550 | var height = img.height; 551 | var left = o.width / 2 - width / 2; 552 | var top = o.height / 2 - height / 2; 553 | ctx.drawImage(img, left, top, width, height); 554 | } 555 | return canvas; 556 | } 557 | 558 | function initCanvas(o) { 559 | if (o.el) { 560 | o.width = o.el.offsetWidth; 561 | o.height = o.el.offsetHeight; 562 | setPosition(o); 563 | } 564 | var canvas = document.createElement('canvas'); 565 | canvas.style.position = 'absolute'; 566 | canvas.style.top = o.top + 'px'; 567 | canvas.style.left = o.left + 'px'; 568 | canvas.width = o.width; 569 | canvas.height = o.height; 570 | canvas.style.visibility = 'hidden'; 571 | o.canvas = canvas; 572 | o.ctx = canvas.getContext('2d'); 573 | fixRootPosition(o.root); 574 | o.root.appendChild(o.canvas); 575 | } 576 | 577 | 578 | /************** 579 | * Brushstroke 580 | **************/ 581 | 582 | function Brushstroke(options) { 583 | 584 | // Default values 585 | 586 | this.defaults = { 587 | animation: 'to-bottom', 588 | path: undefined, 589 | points: undefined, 590 | frameAnimation: false, 591 | frames: 0, 592 | duration: 0, 593 | delay: 0, 594 | color: '#ccc', 595 | width: 300, 596 | height: 120, 597 | size: 40, 598 | inkAmount: 1, 599 | lifting: false, 600 | dripping: false, 601 | splashing: true, 602 | padding: 30, 603 | overlap: 10, 604 | tension: 0.5, 605 | reduceOverflow: 20, 606 | root: document.body, 607 | el: undefined, 608 | image: undefined, 609 | repeat: 'no-repeat', 610 | stretch: false, 611 | centered: false, 612 | queue: false 613 | }; 614 | 615 | this.init(options); 616 | } 617 | 618 | Brushstroke.prototype = { 619 | 620 | init: function (options) { 621 | var o = extend(this.defaults, options); 622 | if (is.str(o.root)) o.root = document.querySelector(o.root); 623 | if (is.str(o.el)) o.el = document.querySelector(o.el); 624 | initCanvas(o); 625 | 626 | var d = deferred(); 627 | this.promise = d.promise; 628 | d.resolve(); 629 | }, 630 | 631 | run: function (options) { 632 | var that = this; 633 | 634 | function start() { 635 | options.canvas.style.visibility = 'visible'; 636 | if (options.render) { 637 | that.render(options); 638 | } else { 639 | callFunction(that.animations[options.animation], that, options); 640 | } 641 | } 642 | 643 | if (options.clear) { 644 | options.ctx.clearRect(0, 0, options.width, options.height); 645 | options.d.resolve(); 646 | } else if (options.el) { 647 | if (options.pattern) { 648 | start(); 649 | } else { 650 | var html = '' + getOuterHTML(options.el); 651 | rasterizeHTML.drawHTML(html, null) 652 | .then(function success(renderResult) { 653 | if (options.fill) { 654 | options.ctx.drawImage(renderResult.image, 0, 0, options.width, options.height); 655 | options.d.resolve(); 656 | } else { 657 | options.pattern = options.ctx.createPattern(renderResult.image, options.repeat); 658 | start(); 659 | } 660 | }, function error(e) { 661 | console.log('rasterizeHTMLError: ' + e); 662 | }); 663 | } 664 | } else if (options.image) { 665 | var img = new Image(); 666 | img.onload = function() { 667 | if (options.stretch || options.centered) img = resizeImage(img, options); 668 | if (options.fill) { 669 | options.ctx.drawImage(img, 0, 0, options.width, options.height); 670 | options.d.resolve(); 671 | } else { 672 | options.pattern = options.ctx.createPattern(img, options.repeat); 673 | start(); 674 | } 675 | }; 676 | img.src = options.image; 677 | } else { 678 | start(); 679 | } 680 | }, 681 | 682 | draw: function (options) { 683 | var that = this; 684 | var o = extend({}, this.defaults, options); 685 | var _draw = function () { 686 | var d = deferred(); 687 | that.run(extend(o, {d: d})); 688 | return d.promise; 689 | }; 690 | if (o.queue) { 691 | this.promise = this.promise.then(_draw); 692 | } else { 693 | _draw(); 694 | } 695 | }, 696 | 697 | erase: function (options) { 698 | this.draw(extend({}, options, {erase: true})); 699 | }, 700 | 701 | fill: function (options) { 702 | this.draw(extend({}, options, {fill: true})); 703 | }, 704 | 705 | clear: function (options) { 706 | this.draw(extend({}, options, {clear: true})); 707 | }, 708 | 709 | setPath: function (o) { 710 | var path = o.path; 711 | if (is.str(path)) { 712 | path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 713 | path.setAttribute('d', o.path); 714 | o.path = path; 715 | } 716 | o.pathLenght = path.getTotalLength(); 717 | }, 718 | 719 | pointAt: function (t, o) { 720 | switch (o.animation) { 721 | case 'points': 722 | var points = o.points; 723 | var length = points.length; 724 | var i = Math.round((length * t) / 2) * 2; 725 | if (i >= length) i = length - 2; 726 | return {x: points[i], y: points[i + 1]}; 727 | case 'path': 728 | return o.path.getPointAtLength(o.pathLenght * t); 729 | default: 730 | return null; 731 | } 732 | }, 733 | 734 | setPos: function (o, pos) { 735 | var first = !pos; 736 | if (first) pos = {}; 737 | switch (o.direction) { 738 | case 'bottom': 739 | pos.startY = first ? o.padding : pos.startY + o.size - o.overlap; 740 | this.setPosBottomTop(o, pos, first); 741 | break; 742 | case 'top': 743 | pos.startY = first ? o.height - o.padding : pos.startY - o.size + o.overlap; 744 | this.setPosBottomTop(o, pos, first); 745 | break; 746 | case 'right': 747 | pos.startX = first ? o.padding : pos.startX + o.size - o.overlap; 748 | this.setPosRightLeft(o, pos, first); 749 | break; 750 | case 'left': 751 | pos.startX = first ? o.width - o.padding : pos.startX - o.size + o.overlap; 752 | this.setPosRightLeft(o, pos, first); 753 | break; 754 | } 755 | return pos; 756 | }, 757 | 758 | setPosBottomTop: function (o, pos, first) { 759 | if (first) { 760 | pos.vertical = true; 761 | } else { 762 | var aux = pos.startX; 763 | } 764 | pos.startX = first ? o.padding : pos.x; 765 | pos.x = first ? o.width - o.padding : aux; 766 | pos.y = pos.startY; 767 | }, 768 | 769 | setPosRightLeft: function (o, pos, first) { 770 | if (first) { 771 | pos.vertical = false; 772 | } else { 773 | var aux = pos.startY; 774 | } 775 | pos.x = pos.startX; 776 | pos.startY = first ? o.padding : pos.y; 777 | pos.y = first ? o.height - o.padding : aux; 778 | }, 779 | 780 | render: function (o) { 781 | if (!is.und(o.duration) || !is.und(o.frames)) { 782 | var that = this; 783 | 784 | if (o.delay) { 785 | var delay = o.delay; 786 | delete o.delay; 787 | setTimeout(function () { 788 | that.render(o); 789 | }, delay * 1000); 790 | return; 791 | } 792 | 793 | if (o.erase) o.ctx.globalCompositeOperation = 'destination-out'; 794 | 795 | var frame = 1, elapsed, time, t, point, x = 0, y = 0; 796 | var startTime = new Date(); 797 | 798 | if (!is.und(o.startX)) x = o.startX; 799 | if (!is.und(o.startY)) y = o.startY; 800 | 801 | var brush = new Brush(x, y, o.pattern || o.color, o.size, o.inkAmount, o.angle, o.dripping, o.splashing); 802 | brush.startStroke(x, y); 803 | callFunction(o.begin); 804 | 805 | if (o.frameAnimation && o.duration) { 806 | if (!o.frames) o.frames = parseFloat(o.duration) * 60; 807 | delete o.duration; 808 | } 809 | 810 | (function calc() { 811 | if (o.duration) { 812 | elapsed = (new Date() - startTime) / 1000; 813 | time = elapsed / parseFloat(o.duration); 814 | } else { 815 | time = frame / parseFloat(o.frames); 816 | } 817 | t = time; 818 | 819 | if (is.fnc(o.easing)) { 820 | t = o.easing(t); 821 | } 822 | 823 | if (time > 1) { 824 | t = 1; 825 | } 826 | 827 | point = that.pointAt(t, o); 828 | if (!point) { 829 | point = { 830 | x: x + (o.x - x) * t, 831 | y: y + (o.y - y) * t 832 | }; 833 | } 834 | 835 | x = point.x; 836 | y = point.y; 837 | brush.render(o.ctx, x, y); 838 | 839 | if (time >= 1) { 840 | brush.endStroke(); 841 | if (o.erase) o.ctx.globalCompositeOperation = 'source-over'; 842 | callFunction(o.end); 843 | o.d.resolve(); 844 | } else { 845 | if (o.duration) { 846 | requestAnimationFrame(calc); 847 | } else { 848 | frame++; 849 | o.frameAnimation ? requestAnimationFrame(calc) : calc(); 850 | } 851 | } 852 | })(); 853 | } 854 | }, 855 | 856 | animations: { 857 | 'to-bottom': function(o) { 858 | callFunction(this.animations.basic, this, extend(o, {direction: 'bottom'})); 859 | }, 860 | 'to-top': function(o) { 861 | callFunction(this.animations.basic, this, extend(o, {direction: 'top'})); 862 | }, 863 | 'to-right': function(o) { 864 | callFunction(this.animations.basic, this, extend(o, {direction: 'right'})); 865 | }, 866 | 'to-left': function(o) { 867 | callFunction(this.animations.basic, this, extend(o, {direction: 'left'})); 868 | }, 869 | 'basic': function(o) { 870 | var pos = this.setPos(o); 871 | var brushstrokes = Math.ceil(((pos.vertical ? o.height : o.width) + (o.size / 2) - (o.padding * 2)) / (o.size - o.overlap)); 872 | var angle = pos.vertical ? Math.PI * 0.5 : 0; 873 | var duration = o.duration / brushstrokes; 874 | var frames = o.frames / brushstrokes; 875 | var points = []; 876 | var alt = true; 877 | var overflow = o.reduceOverflow; 878 | var opts, first, last; 879 | 880 | function fixOverflow(axis) { 881 | if (i === 0) pos[axis] = pos[axis] - overflow; 882 | if (i === 1) pos[axis] = pos[axis] + overflow; 883 | if (i === brushstrokes - 1) pos[axis] = alt ? pos[axis] + overflow : pos[axis] - overflow; 884 | } 885 | 886 | for (var i = 0; i < brushstrokes; i++) { 887 | if (o.lifting) { 888 | first = i === 0; 889 | last = i === brushstrokes - 1; 890 | opts = extend({}, o, pos, {duration: duration, frames: frames, angle: angle, render: true, queue: true}); 891 | if (!first) opts.begin = null; 892 | if (!last) opts.end = null; 893 | this.draw(opts); 894 | } else { 895 | if (overflow) { 896 | pos.vertical ? fixOverflow('x') : fixOverflow('y'); 897 | } 898 | points.push(pos.startX, pos.startY, pos.x, pos.y); 899 | } 900 | this.setPos(o, pos); 901 | alt = !alt; 902 | } 903 | 904 | if (o.lifting) { 905 | o.d.resolve(); 906 | } else { 907 | callFunction(this.animations.points, this, extend(o, {animation: 'points', points: points, angle: angle})); 908 | } 909 | }, 910 | 'path': function(o) { 911 | this.setPath(o); 912 | var point = this.pointAt(0, o); 913 | this.render(extend(o, {startX: point.x, startY: point.y})); 914 | }, 915 | 'points': function(o) { 916 | var points = o.points || 0; 917 | points = is.num(points) ? randomize(points, o.width, o.height) : points; 918 | points = getCurvePoints(points, o.tension); 919 | this.render(extend(o, {points: points, startX: points[0], startY: points[1]})); 920 | } 921 | } 922 | }; 923 | 924 | return Brushstroke; 925 | 926 | })); 927 | -------------------------------------------------------------------------------- /js/brushstroke.js: -------------------------------------------------------------------------------- 1 | (function (root, factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | define([], factory); 4 | } else if (typeof module === 'object' && module.exports) { 5 | module.exports = factory(); 6 | } else { 7 | root.Brushstroke = factory(); 8 | } 9 | }(this, function () { 10 | 11 | /** 12 | * Curve calc function for canvas 2.3.4 - (c) Epistemex 2013-2016 - www.epistemex.com - MIT License 13 | */ 14 | 15 | /** 16 | * Calculates an array containing points representing a cardinal spline through given point array. 17 | * Points must be arranged as: [x1, y1, x2, y2, ..., xn, yn]. 18 | * 19 | * The points for the cardinal spline are returned as a new array. 20 | * 21 | * @param {Array} points - point array 22 | * @param {Number} [tension=0.5] - tension. Typically between [0.0, 1.0] but can be exceeded 23 | * @param {Number} [numOfSeg=25] - number of segments between two points (line resolution) 24 | * @param {Boolean} [close=false] - Close the ends making the line continuous 25 | * @returns {Float32Array} New array with the calculated points that was added to the path 26 | */ 27 | function getCurvePoints(points, tension, numOfSeg, close) { 28 | 29 | 'use strict'; 30 | 31 | // options or defaults 32 | tension = (typeof tension === 'number') ? tension : 0.5; 33 | numOfSeg = (typeof numOfSeg === 'number') ? numOfSeg : 25; 34 | 35 | var pts, // for cloning point array 36 | i = 1, 37 | l = points.length, 38 | rPos = 0, 39 | rLen = (l-2) * numOfSeg + 2 + (close ? 2 * numOfSeg: 0), 40 | res = new Float32Array(rLen), 41 | cache = new Float32Array((numOfSeg + 2) * 4), 42 | cachePtr = 4; 43 | 44 | pts = points.slice(0); 45 | 46 | if (close) { 47 | pts.unshift(points[l - 1]); // insert end point as first point 48 | pts.unshift(points[l - 2]); 49 | pts.push(points[0], points[1]); // first point as last point 50 | } 51 | else { 52 | pts.unshift(points[1]); // copy 1. point and insert at beginning 53 | pts.unshift(points[0]); 54 | pts.push(points[l - 2], points[l - 1]); // duplicate end-points 55 | } 56 | 57 | // cache inner-loop calculations as they are based on t alone 58 | cache[0] = 1; // 1,0,0,0 59 | 60 | for (; i < numOfSeg; i++) { 61 | 62 | var st = i / numOfSeg, 63 | st2 = st * st, 64 | st3 = st2 * st, 65 | st23 = st3 * 2, 66 | st32 = st2 * 3; 67 | 68 | cache[cachePtr++] = st23 - st32 + 1; // c1 69 | cache[cachePtr++] = st32 - st23; // c2 70 | cache[cachePtr++] = st3 - 2 * st2 + st; // c3 71 | cache[cachePtr++] = st3 - st2; // c4 72 | } 73 | 74 | cache[++cachePtr] = 1; // 0,1,0,0 75 | 76 | // calc. points 77 | parse(pts, cache, l, tension); 78 | 79 | if (close) { 80 | pts = []; 81 | pts.push(points[l - 4], points[l - 3], 82 | points[l - 2], points[l - 1], // second last and last 83 | points[0], points[1], 84 | points[2], points[3]); // first and second 85 | parse(pts, cache, 4, tension); 86 | } 87 | 88 | function parse(pts, cache, l, tension) { 89 | 90 | for (var i = 2, t; i < l; i += 2) { 91 | 92 | var pt1 = pts[i], 93 | pt2 = pts[i+1], 94 | pt3 = pts[i+2], 95 | pt4 = pts[i+3], 96 | 97 | t1x = (pt3 - pts[i-2]) * tension, 98 | t1y = (pt4 - pts[i-1]) * tension, 99 | t2x = (pts[i+4] - pt1) * tension, 100 | t2y = (pts[i+5] - pt2) * tension, 101 | c = 0, c1, c2, c3, c4; 102 | 103 | for (t = 0; t < numOfSeg; t++) { 104 | 105 | c1 = cache[c++]; 106 | c2 = cache[c++]; 107 | c3 = cache[c++]; 108 | c4 = cache[c++]; 109 | 110 | res[rPos++] = c1 * pt1 + c2 * pt3 + c3 * t1x + c4 * t2x; 111 | res[rPos++] = c1 * pt2 + c2 * pt4 + c3 * t1y + c4 * t2y; 112 | } 113 | } 114 | } 115 | 116 | // add last point 117 | l = close ? 0 : points.length - 2; 118 | res[rPos++] = points[l++]; 119 | res[rPos] = points[l]; 120 | 121 | return res; 122 | } 123 | 124 | 125 | /** 126 | * Brush by Akimitsu Hamamuro (http://codepen.io/akm2/pen/BonIh) - MIT License 127 | */ 128 | 129 | var Brush = (function() { 130 | 131 | /** 132 | * @constructor 133 | * @public 134 | */ 135 | function Brush(x, y, color, size, inkAmount, angle, dripping, splashing) { 136 | this.x = x || 0; 137 | this.y = y || 0; 138 | if (color !== undefined) this.color = color; 139 | if (size !== undefined) this.size = size; 140 | if (inkAmount !== undefined) this.inkAmount = inkAmount; 141 | if (angle !== undefined) this.angle = angle; 142 | if (dripping !== undefined) this.dripping = dripping; 143 | if (splashing !== undefined) this.splashing = splashing; 144 | 145 | this._drops = []; 146 | this._resetTip(); 147 | } 148 | 149 | Brush.prototype = { 150 | _SPLASHING_BRUSH_SPEED: 75, 151 | 152 | angle: 0, 153 | x: 0, 154 | y: 0, 155 | color: '#000', 156 | size: 35, 157 | inkAmount: 7, 158 | splashing: true, 159 | dripping: true, 160 | maxHairs: 1000, 161 | _latestPos: null, 162 | _strokeId: null, 163 | _drops: null, 164 | 165 | isStroke: function() { 166 | return Boolean(this._strokeId); 167 | }, 168 | 169 | startStroke: function() { 170 | if (this.isStroke()) return; 171 | 172 | this._resetTip(); 173 | 174 | // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript 175 | this._strokeId = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 176 | var r, v; 177 | r = Math.random() * 16 | 0; 178 | v = c === 'x' ? r : (r & 0x3 | 0x8); 179 | return v.toString(16); 180 | }); 181 | }, 182 | 183 | endStroke: function() { 184 | this._strokeId = this._latestPos = null; 185 | }, 186 | 187 | render: function(ctx, x, y) { 188 | var isStroke = this.isStroke(), 189 | dx, dy, 190 | i, len; 191 | 192 | if (!this._latestPos) this._latestPos = {}; 193 | this._latestPos.x = this.x; 194 | this._latestPos.y = this.y; 195 | this.x = x; 196 | this.y = y; 197 | 198 | if(this._latestPos.x === this.x && this._latestPos.y === this.y) { 199 | return; 200 | } 201 | 202 | if (this._drops.length) { 203 | var drops = this._drops, 204 | drop, 205 | sizeSq = this.size * this.size; 206 | 207 | for (i = 0, len = drops.length; i < len; i++) { 208 | drop = drops[i]; 209 | 210 | dx = this.x - drop.x; 211 | dy = this.y - drop.y; 212 | 213 | if ( 214 | (isStroke && sizeSq > dx * dx + dy * dy && this._strokeId !== drop.strokeId) || 215 | drop.life <= 0 216 | ) { 217 | drops.splice(i, 1); 218 | len--; 219 | i--; 220 | continue; 221 | } 222 | 223 | drop.render(ctx); 224 | } 225 | } 226 | 227 | if (isStroke) { 228 | var tip = this._tip, 229 | strokeId = this._strokeId, 230 | dist; 231 | 232 | dx = this.x - this._latestPos.x; 233 | dy = this.y - this._latestPos.y; 234 | dist = Math.sqrt(dx * dx + dy * dy); 235 | 236 | if (this.splashing && dist > this._SPLASHING_BRUSH_SPEED) { 237 | var maxNum = (dist - this._SPLASHING_BRUSH_SPEED) * 0.5 | 0, 238 | r, a, sr, sx, sy; 239 | 240 | ctx.save(); 241 | ctx.fillStyle = this.color; 242 | ctx.beginPath(); 243 | for (i = 0, len = maxNum * Math.random() | 0; i < len; i++) { 244 | r = (dist - 1) * Math.random() + 1; 245 | a = Math.PI * 2 * Math.random(); 246 | sr = 5 * Math.random(); 247 | sx = this.x + r * Math.sin(a); 248 | sy = this.y + r * Math.cos(a); 249 | ctx.moveTo(sx + sr, sy); 250 | ctx.arc(sx, sy, sr, 0, Math.PI * 2, false); 251 | } 252 | ctx.fill(); 253 | ctx.restore(); 254 | 255 | } else if (this.dripping && dist < this.inkAmount * 2 && Math.random() < 0.05) { 256 | this._drops.push(new Drop( 257 | this.x, 258 | this.y, 259 | (this.size + this.inkAmount) * 0.5 * ((0.25 - 0.1) * Math.random() + 0.1), 260 | this.color, 261 | this._strokeId 262 | )); 263 | } 264 | 265 | for (i = 0, len = tip.length; i < len; i++) { 266 | tip[i].render(ctx, dx, dy, dist); 267 | } 268 | } 269 | }, 270 | 271 | dispose: function() { 272 | this._tip.length = this._drops.length = 0; 273 | }, 274 | 275 | _resetTip: function() { 276 | var tip = this._tip = [], 277 | rad = this.size * 0.5, 278 | x0, y0, a0, x1, y1, a1, cv, sv, 279 | i, len; 280 | 281 | //a1 = Math.PI * 2 * Math.random(); 282 | a1 = this.angle; 283 | len = rad * rad * Math.PI / this.inkAmount | 0; 284 | if (len < 1) len = 1; 285 | if (len > this.maxHairs) len = this.maxHairs; 286 | 287 | for (i = 0; i < len; i++) { 288 | x0 = rad * Math.random(); 289 | y0 = x0 * 0.5; 290 | a0 = Math.PI * 2 * Math.random(); 291 | x1 = x0 * Math.sin(a0); 292 | y1 = y0 * Math.cos(a0); 293 | cv = Math.cos(a1); 294 | sv = Math.sin(a1); 295 | 296 | tip.push(new Hair( 297 | this.x + x1 * cv - y1 * sv, 298 | this.y + x1 * sv + y1 * cv, 299 | this.inkAmount, 300 | this.color 301 | )); 302 | } 303 | } 304 | }; 305 | 306 | 307 | /** 308 | * Hair 309 | * @private 310 | */ 311 | function Hair(x, y, inkAmount, color) { 312 | this.x = x || 0; 313 | this.y = y || 0; 314 | this.inkAmount = inkAmount; 315 | this.color = color; 316 | 317 | this._latestPos = { x: this.x, y: this.y }; 318 | } 319 | 320 | Hair.prototype = { 321 | x: 0, 322 | y: 0, 323 | inkAmount: 7, 324 | color: '#000', 325 | _latestPos: null, 326 | 327 | render: function(ctx, offsetX, offsetY, offsetLength) { 328 | this._latestPos.x = this.x; 329 | this._latestPos.y = this.y; 330 | this.x += offsetX; 331 | this.y += offsetY; 332 | 333 | var per = offsetLength ? this.inkAmount / offsetLength : 0; 334 | if (per > 1) per = 1; 335 | else if (per < 0) per = 0; 336 | 337 | ctx.save(); 338 | ctx.lineCap = ctx.lineJoin = 'round'; 339 | ctx.strokeStyle = this.color; 340 | ctx.lineWidth = this.inkAmount * per; 341 | ctx.beginPath(); 342 | ctx.moveTo(this._latestPos.x, this._latestPos.y); 343 | ctx.lineTo(this.x, this.y); 344 | ctx.stroke(); 345 | ctx.restore(); 346 | } 347 | }; 348 | 349 | 350 | /** 351 | * Drop 352 | * @private 353 | */ 354 | function Drop(x, y, size, color, strokeId) { 355 | this.x = x || 0; 356 | this.y = y || 0; 357 | this.size = size; 358 | this.color = color; 359 | this.strokeId = strokeId; 360 | 361 | this.life = this.size * 1.5; 362 | this._latestPos = { x: this.x, y: this.y }; 363 | } 364 | 365 | Drop.prototype = { 366 | x: 0, 367 | y: 0, 368 | size: 7, 369 | color: '#000', 370 | strokeId: null, 371 | life: 0, 372 | _latestPos: null, 373 | _xOffRatio: 0, 374 | 375 | render: function(ctx) { 376 | if (Math.random() < 0.03) { 377 | this._xOffRatio += 0.06 * Math.random() - 0.03; 378 | } else if (Math.random() < 0.1) { 379 | this._xOffRatio *= 0.003; 380 | } 381 | 382 | this._latestPos.x = this.x; 383 | this._latestPos.y = this.y; 384 | this.x += this.life * this._xOffRatio; 385 | this.y += (this.life * 0.5) * Math.random(); 386 | 387 | this.life -= (0.05 - 0.01) * Math.random() + 0.01; 388 | 389 | ctx.save(); 390 | ctx.lineCap = ctx.lineJoin = 'round'; 391 | ctx.strokeStyle = this.color; 392 | ctx.lineWidth = this.size + this.life * 0.3; 393 | ctx.beginPath(); 394 | ctx.moveTo(this._latestPos.x, this._latestPos.y); 395 | ctx.lineTo(this.x, this.y); 396 | ctx.stroke(); 397 | ctx.restore(); 398 | ctx.restore(); 399 | } 400 | }; 401 | 402 | return Brush; 403 | 404 | })(); 405 | 406 | 407 | /******************** 408 | * Brushstroke utils 409 | ********************/ 410 | 411 | // Type of elements, most from anime.js 412 | 413 | var is = { 414 | obj: function(a) { return Object.prototype.toString.call(a).indexOf('Object') > -1 }, 415 | num: function(a) { return typeof a === 'number' }, 416 | str: function(a) { return typeof a === 'string' }, 417 | fnc: function(a) { return typeof a === 'function' }, 418 | und: function(a) { return typeof a === 'undefined' } 419 | }; 420 | 421 | // Functions 422 | 423 | function callFunction(fn, context, params) { 424 | if (is.fnc(fn)) fn.call(context, params); 425 | } 426 | 427 | // Objects 428 | 429 | function extendSingle(target, source) { 430 | for (var key in source) 431 | target[key] = source[key]; 432 | return target; 433 | } 434 | 435 | function extend(target, source) { 436 | if (!target) target = {}; 437 | for (var i = 1; i < arguments.length; i++) 438 | extendSingle(target, arguments[i]); 439 | return target; 440 | } 441 | 442 | // Styles 443 | 444 | function validProperty(property, value) { 445 | try { 446 | return !is.und(value) && 447 | !is.obj(value) && 448 | !is.fnc(value) && 449 | value.length > 0 && 450 | value != parseInt(value) && 451 | property != parseInt(property); 452 | } catch (e) { 453 | return false; 454 | } 455 | } 456 | 457 | function setStyle(el) { 458 | var computedStyle = getComputedStyle(el); 459 | var style = ''; 460 | for (var property in computedStyle) { 461 | if (validProperty(property, computedStyle[property])) { 462 | style += property + ':' + computedStyle[property] + ';'; 463 | } 464 | } 465 | el.style.cssText += style + ';visibility:visible;'; 466 | } 467 | 468 | function setStyleAll(el, list) { 469 | var children = el.children; 470 | for (var i = 0; i < children.length; i++) 471 | setStyleAll(children[i], list); 472 | list.push({el: el, style: el.style.cssText}); 473 | setStyle(el); 474 | } 475 | 476 | function restoreStyleAll(list) { 477 | var current; 478 | for (var i = 0; i < list.length; i++) { 479 | current = list[i]; 480 | if (current.style) { 481 | current.el.style.cssText = current.style; 482 | } else { 483 | current.el.removeAttribute('style'); 484 | } 485 | } 486 | } 487 | 488 | function getOuterHTML(el) { 489 | var list = []; 490 | setStyleAll(el, list); 491 | var html = el.outerHTML; 492 | restoreStyleAll(list); 493 | return html; 494 | } 495 | 496 | function fixRootPosition(root) { 497 | var style = getComputedStyle(root); 498 | var position = style.getPropertyValue('position'); 499 | if (position === 'static') { 500 | root.style.position = 'relative'; 501 | } 502 | } 503 | 504 | function setPosition(o) { 505 | var elRect = o.el.getBoundingClientRect(); 506 | var rootRect = o.root.getBoundingClientRect(); 507 | o.top = elRect.top - rootRect.top; 508 | o.left = elRect.left - rootRect.left; 509 | } 510 | 511 | // Promises 512 | 513 | function deferred() { 514 | return new function () { 515 | this.resolve = null; 516 | this.reject = null; 517 | 518 | this.promise = new Promise(function (resolve, reject) { 519 | this.resolve = resolve; 520 | this.reject = reject; 521 | }.bind(this)); 522 | }; 523 | } 524 | 525 | // Get random points in a 2d space 526 | 527 | function randomize(num, width, height) { 528 | var numPoints = num || 10; 529 | var points = []; 530 | for (var i = 0; i < numPoints; i++) { 531 | points.push( 532 | (width * Math.random() * 0.9 + width * 0.05) | 0, 533 | (height * Math.random() * 0.9 + height * 0.05) | 0 534 | ); 535 | } 536 | return points; 537 | } 538 | 539 | // Canvas 540 | 541 | function resizeImage(img, o) { 542 | var canvas = document.createElement('canvas'); 543 | canvas.width = o.width; 544 | canvas.height = o.height; 545 | var ctx = canvas.getContext("2d"); 546 | if (o.stretch) { 547 | ctx.drawImage(img, 0, 0, o.width, o.height); 548 | } else { 549 | var width = img.width; 550 | var height = img.height; 551 | var left = o.width / 2 - width / 2; 552 | var top = o.height / 2 - height / 2; 553 | ctx.drawImage(img, left, top, width, height); 554 | } 555 | return canvas; 556 | } 557 | 558 | function initCanvas(o) { 559 | if (o.el) { 560 | o.width = o.el.offsetWidth; 561 | o.height = o.el.offsetHeight; 562 | setPosition(o); 563 | } 564 | var canvas = document.createElement('canvas'); 565 | canvas.style.position = 'absolute'; 566 | canvas.style.top = o.top + 'px'; 567 | canvas.style.left = o.left + 'px'; 568 | canvas.width = o.width; 569 | canvas.height = o.height; 570 | canvas.style.visibility = 'hidden'; 571 | o.canvas = canvas; 572 | o.ctx = canvas.getContext('2d'); 573 | fixRootPosition(o.root); 574 | o.root.appendChild(o.canvas); 575 | } 576 | 577 | 578 | /************** 579 | * Brushstroke 580 | **************/ 581 | 582 | function Brushstroke(options) { 583 | 584 | // Default values 585 | 586 | this.defaults = { 587 | animation: 'to-bottom', 588 | path: undefined, 589 | points: undefined, 590 | frameAnimation: false, 591 | frames: 0, 592 | duration: 0, 593 | delay: 0, 594 | color: '#ccc', 595 | width: 300, 596 | height: 120, 597 | size: 40, 598 | inkAmount: 1, 599 | lifting: false, 600 | dripping: false, 601 | splashing: true, 602 | padding: 30, 603 | overlap: 10, 604 | tension: 0.5, 605 | reduceOverflow: 20, 606 | root: document.body, 607 | el: undefined, 608 | image: undefined, 609 | repeat: 'no-repeat', 610 | stretch: false, 611 | centered: false, 612 | queue: false 613 | }; 614 | 615 | this.init(options); 616 | } 617 | 618 | Brushstroke.prototype = { 619 | 620 | init: function (options) { 621 | var o = extend(this.defaults, options); 622 | if (is.str(o.root)) o.root = document.querySelector(o.root); 623 | if (is.str(o.el)) o.el = document.querySelector(o.el); 624 | initCanvas(o); 625 | 626 | var d = deferred(); 627 | this.promise = d.promise; 628 | d.resolve(); 629 | }, 630 | 631 | run: function (options) { 632 | var that = this; 633 | 634 | function start() { 635 | options.canvas.style.visibility = 'visible'; 636 | if (options.render) { 637 | that.render(options); 638 | } else { 639 | callFunction(that.animations[options.animation], that, options); 640 | } 641 | } 642 | 643 | if (options.clear) { 644 | options.ctx.clearRect(0, 0, options.width, options.height); 645 | options.d.resolve(); 646 | } else if (options.el) { 647 | if (options.pattern) { 648 | start(); 649 | } else { 650 | var html = '' + getOuterHTML(options.el); 651 | rasterizeHTML.drawHTML(html, null) 652 | .then(function success(renderResult) { 653 | if (options.fill) { 654 | options.ctx.drawImage(renderResult.image, 0, 0, options.width, options.height); 655 | options.d.resolve(); 656 | } else { 657 | options.pattern = options.ctx.createPattern(renderResult.image, options.repeat); 658 | start(); 659 | } 660 | }, function error(e) { 661 | console.log('rasterizeHTMLError: ' + e); 662 | }); 663 | } 664 | } else if (options.image) { 665 | var img = new Image(); 666 | img.onload = function() { 667 | if (options.stretch || options.centered) img = resizeImage(img, options); 668 | if (options.fill) { 669 | options.ctx.drawImage(img, 0, 0, options.width, options.height); 670 | options.d.resolve(); 671 | } else { 672 | options.pattern = options.ctx.createPattern(img, options.repeat); 673 | start(); 674 | } 675 | }; 676 | img.src = options.image; 677 | } else { 678 | start(); 679 | } 680 | }, 681 | 682 | draw: function (options) { 683 | var that = this; 684 | var o = extend({}, this.defaults, options); 685 | var _draw = function () { 686 | var d = deferred(); 687 | that.run(extend(o, {d: d})); 688 | return d.promise; 689 | }; 690 | if (o.queue) { 691 | this.promise = this.promise.then(_draw); 692 | } else { 693 | _draw(); 694 | } 695 | }, 696 | 697 | erase: function (options) { 698 | this.draw(extend({}, options, {erase: true})); 699 | }, 700 | 701 | fill: function (options) { 702 | this.draw(extend({}, options, {fill: true})); 703 | }, 704 | 705 | clear: function (options) { 706 | this.draw(extend({}, options, {clear: true})); 707 | }, 708 | 709 | setPath: function (o) { 710 | var path = o.path; 711 | if (is.str(path)) { 712 | path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 713 | path.setAttribute('d', o.path); 714 | o.path = path; 715 | } 716 | o.pathLenght = path.getTotalLength(); 717 | }, 718 | 719 | pointAt: function (t, o) { 720 | switch (o.animation) { 721 | case 'points': 722 | var points = o.points; 723 | var length = points.length; 724 | var i = Math.round((length * t) / 2) * 2; 725 | if (i >= length) i = length - 2; 726 | return {x: points[i], y: points[i + 1]}; 727 | case 'path': 728 | return o.path.getPointAtLength(o.pathLenght * t); 729 | default: 730 | return null; 731 | } 732 | }, 733 | 734 | setPos: function (o, pos) { 735 | var first = !pos; 736 | if (first) pos = {}; 737 | switch (o.direction) { 738 | case 'bottom': 739 | pos.startY = first ? o.padding : pos.startY + o.size - o.overlap; 740 | this.setPosBottomTop(o, pos, first); 741 | break; 742 | case 'top': 743 | pos.startY = first ? o.height - o.padding : pos.startY - o.size + o.overlap; 744 | this.setPosBottomTop(o, pos, first); 745 | break; 746 | case 'right': 747 | pos.startX = first ? o.padding : pos.startX + o.size - o.overlap; 748 | this.setPosRightLeft(o, pos, first); 749 | break; 750 | case 'left': 751 | pos.startX = first ? o.width - o.padding : pos.startX - o.size + o.overlap; 752 | this.setPosRightLeft(o, pos, first); 753 | break; 754 | } 755 | return pos; 756 | }, 757 | 758 | setPosBottomTop: function (o, pos, first) { 759 | if (first) { 760 | pos.vertical = true; 761 | } else { 762 | var aux = pos.startX; 763 | } 764 | pos.startX = first ? o.padding : pos.x; 765 | pos.x = first ? o.width - o.padding : aux; 766 | pos.y = pos.startY; 767 | }, 768 | 769 | setPosRightLeft: function (o, pos, first) { 770 | if (first) { 771 | pos.vertical = false; 772 | } else { 773 | var aux = pos.startY; 774 | } 775 | pos.x = pos.startX; 776 | pos.startY = first ? o.padding : pos.y; 777 | pos.y = first ? o.height - o.padding : aux; 778 | }, 779 | 780 | render: function (o) { 781 | if (!is.und(o.duration) || !is.und(o.frames)) { 782 | var that = this; 783 | 784 | if (o.delay) { 785 | var delay = o.delay; 786 | delete o.delay; 787 | setTimeout(function () { 788 | that.render(o); 789 | }, delay * 1000); 790 | return; 791 | } 792 | 793 | if (o.erase) o.ctx.globalCompositeOperation = 'destination-out'; 794 | 795 | var frame = 1, elapsed, time, t, point, x = 0, y = 0; 796 | var startTime = new Date(); 797 | 798 | if (!is.und(o.startX)) x = o.startX; 799 | if (!is.und(o.startY)) y = o.startY; 800 | 801 | var brush = new Brush(x, y, o.pattern || o.color, o.size, o.inkAmount, o.angle, o.dripping, o.splashing); 802 | brush.startStroke(x, y); 803 | callFunction(o.begin); 804 | 805 | if (o.frameAnimation && o.duration) { 806 | if (!o.frames) o.frames = parseFloat(o.duration) * 60; 807 | delete o.duration; 808 | } 809 | 810 | (function calc() { 811 | if (o.duration) { 812 | elapsed = (new Date() - startTime) / 1000; 813 | time = elapsed / parseFloat(o.duration); 814 | } else { 815 | time = frame / parseFloat(o.frames); 816 | } 817 | t = time; 818 | 819 | if (is.fnc(o.easing)) { 820 | t = o.easing(t); 821 | } 822 | 823 | if (time > 1) { 824 | t = 1; 825 | } 826 | 827 | point = that.pointAt(t, o); 828 | if (!point) { 829 | point = { 830 | x: x + (o.x - x) * t, 831 | y: y + (o.y - y) * t 832 | }; 833 | } 834 | 835 | x = point.x; 836 | y = point.y; 837 | brush.render(o.ctx, x, y); 838 | 839 | if (time >= 1) { 840 | brush.endStroke(); 841 | if (o.erase) o.ctx.globalCompositeOperation = 'source-over'; 842 | callFunction(o.end); 843 | o.d.resolve(); 844 | } else { 845 | if (o.duration) { 846 | requestAnimationFrame(calc); 847 | } else { 848 | frame++; 849 | o.frameAnimation ? requestAnimationFrame(calc) : calc(); 850 | } 851 | } 852 | })(); 853 | } 854 | }, 855 | 856 | animations: { 857 | 'to-bottom': function(o) { 858 | callFunction(this.animations.basic, this, extend(o, {direction: 'bottom'})); 859 | }, 860 | 'to-top': function(o) { 861 | callFunction(this.animations.basic, this, extend(o, {direction: 'top'})); 862 | }, 863 | 'to-right': function(o) { 864 | callFunction(this.animations.basic, this, extend(o, {direction: 'right'})); 865 | }, 866 | 'to-left': function(o) { 867 | callFunction(this.animations.basic, this, extend(o, {direction: 'left'})); 868 | }, 869 | 'basic': function(o) { 870 | var pos = this.setPos(o); 871 | var brushstrokes = Math.ceil(((pos.vertical ? o.height : o.width) + (o.size / 2) - (o.padding * 2)) / (o.size - o.overlap)); 872 | var angle = pos.vertical ? Math.PI * 0.5 : 0; 873 | var duration = o.duration / brushstrokes; 874 | var frames = o.frames / brushstrokes; 875 | var points = []; 876 | var alt = true; 877 | var overflow = o.reduceOverflow; 878 | var opts, first, last; 879 | 880 | function fixOverflow(axis) { 881 | if (i === 0) pos[axis] = pos[axis] - overflow; 882 | if (i === 1) pos[axis] = pos[axis] + overflow; 883 | if (i === brushstrokes - 1) pos[axis] = alt ? pos[axis] + overflow : pos[axis] - overflow; 884 | } 885 | 886 | for (var i = 0; i < brushstrokes; i++) { 887 | if (o.lifting) { 888 | first = i === 0; 889 | last = i === brushstrokes - 1; 890 | opts = extend({}, o, pos, {duration: duration, frames: frames, angle: angle, render: true, queue: true}); 891 | if (!first) opts.begin = null; 892 | if (!last) opts.end = null; 893 | this.draw(opts); 894 | } else { 895 | if (overflow) { 896 | pos.vertical ? fixOverflow('x') : fixOverflow('y'); 897 | } 898 | points.push(pos.startX, pos.startY, pos.x, pos.y); 899 | } 900 | this.setPos(o, pos); 901 | alt = !alt; 902 | } 903 | 904 | if (o.lifting) { 905 | o.d.resolve(); 906 | } else { 907 | callFunction(this.animations.points, this, extend(o, {animation: 'points', points: points, angle: angle})); 908 | } 909 | }, 910 | 'path': function(o) { 911 | this.setPath(o); 912 | var point = this.pointAt(0, o); 913 | this.render(extend(o, {startX: point.x, startY: point.y})); 914 | }, 915 | 'points': function(o) { 916 | var points = o.points || 0; 917 | points = is.num(points) ? randomize(points, o.width, o.height) : points; 918 | points = getCurvePoints(points, o.tension); 919 | this.render(extend(o, {points: points, startX: points[0], startY: points[1]})); 920 | } 921 | } 922 | }; 923 | 924 | return Brushstroke; 925 | 926 | })); 927 | -------------------------------------------------------------------------------- /js/rasterizeHTML.allinone.js: -------------------------------------------------------------------------------- 1 | /*! rasterizeHTML.js - v1.0.0 - 2015-03-01 2 | * http://www.github.com/cburgmer/rasterizeHTML.js 3 | * Copyright (c) 2015 Christoph Burgmer; Licensed MIT */ 4 | /* Integrated dependencies: 5 | * url (MIT License), 6 | * CSSOM.js (MIT License), 7 | * ayepromise (BSD License & WTFPL), 8 | * xmlserializer (MIT License), 9 | * css-font-face-src (BSD License), 10 | * inlineresources (MIT License) */ 11 | !function(a){if("object"==typeof exports)module.exports=a();else if("function"==typeof define&&define.amd)define(a);else{var b;"undefined"!=typeof window?b=window:"undefined"!=typeof global?b=global:"undefined"!=typeof self&&(b=self),b.rasterizeHTML=a()}}(function(){var a;return function b(a,c,d){function e(g,h){if(!c[g]){if(!a[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};a[g][0].call(j.exports,function(b){var c=a[g][1][b];return e(c?c:b)},j,j.exports,b,a,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g=a&&f&&g.resolve({totalCount:c})},i=function(){var b=new a;return d(b,"send",function(a,b){return c+=1,b.apply(this,arguments)}),b.addEventListener("load",function(){e+=1,h()}),b};return i.waitForRequestsToFinish=function(){return f=!0,h(),g.promise},i},c}(e,c),g=function(){"use strict";var a={},b=function(a){return Array.prototype.slice.call(a)};a.addClassNameRecursively=function(b,c){b.className+=" "+c,b.parentNode!==b.ownerDocument&&a.addClassNameRecursively(b.parentNode,c)};var c=function(a,c){var d=a.parentStyleSheet,e=b(d.cssRules).indexOf(a);d.insertRule(c,e+1),d.deleteRule(e)},d=function(a,b){var d=a.cssText.replace(/^[^\{]+/,""),e=b+" "+d;c(a,e)},e=function(a){return b(a).reduce(function(a,b){return a+b.cssText},"")},f=function(a){a.textContent=e(a.sheet.cssRules)},g=function(a){return"((?:^|[^.#:\\w])|(?=\\W))("+a.join("|")+")(?=\\W|$)"},h=function(a,c,e){var h=g(c);b(a.querySelectorAll("style")).forEach(function(a){var c=b(a.sheet.cssRules).filter(function(a){return a.selectorText&&new RegExp(h,"i").test(a.selectorText)});c.length&&(c.forEach(function(a){var b=a.selectorText.replace(new RegExp(h,"gi"),function(a,b,c){return b+e(c)});b!==a.selectorText&&d(a,b)}),f(a))})};return a.rewriteCssSelectorWith=function(a,b,c){h(a,[b],function(){return c})},a.lowercaseCssTypeSelectors=function(a,b){h(a,b,function(a){return a.toLowerCase()})},a.findHtmlOnlyNodeNames=function(a){for(var b,c=a.createTreeWalker(a,NodeFilter.SHOW_ELEMENT),d={},e={};c.nextNode();)b=c.currentNode.tagName.toLowerCase(),"http://www.w3.org/1999/xhtml"===c.currentNode.namespaceURI?d[b]=!0:e[b]=!0;return Object.keys(d).filter(function(a){return!e[a]})},a}(),h=function(a){"use strict";var b={},c=function(a){return Array.prototype.slice.call(a)};return b.fakeHover=function(b,c){var d=b.querySelector(c),e="rasterizehtmlhover";d&&(a.addClassNameRecursively(d,e),a.rewriteCssSelectorWith(b,":hover","."+e))},b.fakeActive=function(b,c){var d=b.querySelector(c),e="rasterizehtmlactive";d&&(a.addClassNameRecursively(d,e),a.rewriteCssSelectorWith(b,":active","."+e))},b.fakeFocus=function(b,c){var d=b.querySelector(c),e="rasterizehtmlfocus";d&&(a.addClassNameRecursively(d,e),a.rewriteCssSelectorWith(b,":focus","."+e))},b.persistInputValues=function(a){var b=a.querySelectorAll("input"),d=a.querySelectorAll("textarea"),e=function(a){return"checkbox"===a.type||"radio"===a.type};c(b).filter(e).forEach(function(a){a.checked?a.setAttribute("checked",""):a.removeAttribute("checked")}),c(b).filter(function(a){return!e(a)}).forEach(function(a){a.setAttribute("value",a.value)}),c(d).forEach(function(a){a.textContent=a.value})},b.rewriteTagNameSelectorsToLowerCase=function(b){a.lowercaseCssTypeSelectors(b,a.findHtmlOnlyNodeNames(b))},b}(g),i=function(a,b,c,d){"use strict";var e={},f=function(a,b,c,d){var e=a.createElement(b);return e.style.visibility="hidden",e.style.width=c+"px",e.style.height=d+"px",e.style.position="absolute",e.style.top=-1e4-d+"px",e.style.left=-1e4-c+"px",a.getElementsByTagName("body")[0].appendChild(e),e};e.executeJavascript=function(a,e){var g=f(d.document,"iframe",e.width,e.height),h=a.documentElement.outerHTML,i=[],j=c.defer(),k=e.executeJsTimeout||0,l=function(){var a=g.contentDocument;d.document.getElementsByTagName("body")[0].removeChild(g),j.resolve({document:a,errors:i})},m=function(){var a=c.defer();return k>0?setTimeout(a.resolve,k):a.resolve(),a.promise};g.onload=function(){m().then(o.waitForRequestsToFinish).then(l)};var n=g.contentWindow.XMLHttpRequest,o=b.finishNotifyingXhr(n),p=b.baseUrlRespectingXhr(o,e.baseUrl);return g.contentDocument.open(),g.contentWindow.XMLHttpRequest=p,g.contentWindow.onerror=function(a){i.push({resourceType:"scriptExecution",msg:a})},g.contentDocument.write(""),g.contentDocument.write(h),g.contentDocument.close(),j.promise};var g=function(a,b,c){var d=a.createElement("iframe");return d.style.width=b+"px",d.style.height=c+"px",d.style.visibility="hidden",d.style.position="absolute",d.style.top=-1e4-c+"px",d.style.left=-1e4-b+"px",d.sandbox="allow-same-origin",d},h=function(a,b,c){var e=Math.floor(a/c),f=Math.floor(b/c);return g(d.document,e,f)},i=function(a,b,c,d){return{width:Math.max(a.width*d,b),height:Math.max(a.height*d,c)}},j=function(a,b,c,e,f){var g,h,j,k,l,m,n,o,p=Math.max(a.documentElement.scrollWidth,a.body.clientWidth),q=Math.max(a.documentElement.scrollHeight,a.body.scrollHeight,a.body.clientHeight);if(b){if(m=a.querySelector(b),!m)throw{message:"Clipping selector not found"};n=m.getBoundingClientRect(),g=n.top,h=n.left,j=n.width,k=n.height}else g=0,h=0,j=p,k=q;return o=i({width:j,height:k},c,e,f),l=d.getComputedStyle(a.documentElement).fontSize,{left:h,top:g,width:o.width,height:o.height,viewportWidth:p,viewportHeight:q,rootFontSize:l}};e.calculateDocumentContentSize=function(a,b){var e,f=a.documentElement.outerHTML,g=c.defer(),i=b.zoom||1;return e=h(b.width,b.height,i),d.document.getElementsByTagName("body")[0].appendChild(e),e.onload=function(){var a,c=e.contentDocument;try{a=j(c,b.clip,b.width,b.height,i),g.resolve(a)}catch(f){g.reject(f)}finally{d.document.getElementsByTagName("body")[0].removeChild(e)}},e.contentDocument.open(),e.contentDocument.write(""),e.contentDocument.write(f),e.contentDocument.close(),g.promise};var k=function(a,b){var c,e,f,g,h=/]*)?)>/im.exec(b),i=d.document.implementation.createHTMLDocument("");if(h)for(c="",i.documentElement.innerHTML=c,f=i.querySelector("div"),e=0;e0:a.getElementsByTagNameNS(d,"parsererror").length>0},m=function(a){if(null===a||l(a))throw{message:"Invalid source"}};e.validateXHTML=function(a){var b=new DOMParser,c=b.parseFromString(a,"application/xml");m(c)};var n=null,o=function(a,b){return"none"===b||"repeated"===b?((null===n||"repeated"!==b)&&(n=Date.now()),a+"?_="+n):a},p=function(b,d){var e=new window.XMLHttpRequest,f=a.joinUrl(d.baseUrl,b),g=o(f,d.cache),h=c.defer(),i=function(){h.reject({message:"Unable to load page"})};e.addEventListener("load",function(){200===e.status||0===e.status?h.resolve(e.responseXML):i()},!1),e.addEventListener("error",function(){i()},!1);try{e.open("GET",g,!0),e.responseType="document",e.send(null)}catch(j){i()}return h.promise};return e.loadDocument=function(a,b){return p(a,b).then(function(a){return m(a),a})},e}(e,f,c,window),j=function(a,b){"use strict";var c,d={},e=function(a,b){return b?URL.createObjectURL(new Blob([a],{type:"image/svg+xml"})):"data:image/svg+xml;charset=utf-8,"+encodeURIComponent(a)},f=function(a){a instanceof Blob&&URL.revokeObjectURL(a)},g='',h=function(b){var c=document.createElement("canvas"),d=new Image,e=a.defer();return d.onload=function(){var a=c.getContext("2d");try{a.drawImage(d,0,0),c.toDataURL("image/png"),e.resolve(!0)}catch(b){e.resolve(!1)}},d.onerror=e.reject,d.src=b,e.promise},i=function(){var a=e(g,!0);return h(a).then(function(b){return f(a),b?!1:h(e(g,!1)).then(function(a){return a})},function(){return!1})},j=function(){if(b.Blob)try{return new Blob([""],{type:"text/xml"}),!0}catch(a){}return!1},k=function(){var c=a.defer();return j&&b.URL?i().then(function(a){c.resolve(!a)},function(){c.reject()}):c.resolve(!1),c.promise},l=function(){return void 0===c&&(c=k()),c},m=function(a){return l().then(function(b){return e(a,b)})};return d.renderSvg=function(b){var c,d,e=a.defer(),g=function(){d.onload=null,d.onerror=null},h=function(){c&&f(c)};return d=new Image,d.onload=function(){g(),h(),e.resolve(d)},d.onerror=function(){h(),e.reject()},m(b).then(function(a){c=a,d.src=c},e.reject),e.promise},d}(c,window),k=function(a,b,c,d){"use strict";var e={},f=function(a,b){var c,d,e,f;b=b||1,c=Math.round(a.viewportWidth),d=Math.round(a.viewportHeight),e=-a.left,f=-a.top;var g={x:e,y:f,width:c,height:d};return 1!==b&&(g.style="-webkit-transform: scale("+b+"); -webkit-transform-origin: 0 0; transform: scale("+b+"); transform-origin: 0 0;"),g},g=function(a){var b=a.style||"";a.style=b+"float: left;"},h=function(a){a.externalResourcesRequired=!0},i=function(a){var b=Object.keys(a);return b.length?" "+b.map(function(b){return b+'="'+a[b]+'"'}).join(" "):""};return e.getSvgForDocument=function(a,e,j){c.rewriteTagNameSelectorsToLowerCase(a);var k=d.serializeToString(a);b.validateXHTML(k);var l=f(e,j);return g(l),h(l),'"+k+""},e.drawDocumentAsSvg=function(a,d){return d.hover&&c.fakeHover(a,d.hover),d.active&&c.fakeActive(a,d.active),d.focus&&c.fakeFocus(a,d.focus),b.calculateDocumentContentSize(a,d).then(function(b){return e.getSvgForDocument(a,b,d.zoom)})},e}(e,i,h,b),l=function(a,b,c,d,e,f){"use strict";var g={},h=function(){return{message:"Error rendering page"}},i=function(a){return e.renderSvg(a).then(function(b){return{image:b,svg:a}},function(){throw h()})},j=function(a,b){try{b.getContext("2d").drawImage(a,0,0)}catch(c){throw h()}},k=function(a,b,c){return d.drawDocumentAsSvg(a,c).then(i).then(function(a){return b&&j(a.image,b),a})},l=function(a,d){return b.executeJavascript(a,d).then(function(a){var b=a.document;return c.persistInputValues(b),{document:b,errors:a.errors}})};return g.rasterize=function(b,c,d){var e;return e=a.clone(d),e.inlineScripts=d.executeJs===!0,f.inlineReferences(b,e).then(function(a){return d.executeJs?l(b,d).then(function(b){return{document:b.document,errors:a.concat(b.errors)}}):{document:b,errors:a}}).then(function(a){return k(a.document,c,d).then(function(b){return{image:b.image,svg:b.svg,errors:a.errors}})})},g}(e,i,h,k,j,d),m=function(a,b,c){"use strict";var d={},e=function(a,b){var c=300,d=200,e=a?a.width:c,f=a?a.height:d,g=void 0!==b.width?b.width:e,h=void 0!==b.height?b.height:f;return{width:g,height:h}},f=function(b){var c,d=e(b.canvas,b.options);return c=a.clone(b.options),c.width=d.width,c.height=d.height,c};d.drawDocument=function(){var b=arguments[0],d=Array.prototype.slice.call(arguments,1),e=a.parseOptionalParameters(d);return c.rasterize(b,e.canvas,f(e))};var g=function(a,c,e){var f=b.parseHTML(a);return d.drawDocument(f,c,e)};d.drawHTML=function(){var b=arguments[0],c=Array.prototype.slice.call(arguments,1),d=a.parseOptionalParameters(c);return g(b,d.canvas,d.options)};var h=function(b,c,d){var e=document.implementation.createHTMLDocument("");e.replaceChild(b.documentElement,e.documentElement);var f=d?a.clone(d):{};return d.baseUrl||(f.baseUrl=c),{document:e,options:f}},i=function(a,c,e){return b.loadDocument(a,e).then(function(b){var f=h(b,a,e);return d.drawDocument(f.document,c,f.options)})};return d.drawURL=function(){var b=arguments[0],c=Array.prototype.slice.call(arguments,1),d=a.parseOptionalParameters(c);return i(b,d.canvas,d.options)},d}(e,i,l);return m})},{ayepromise:2,inlineresources:30,url:"j37I/u",xmlserializer:37}],2:[function(b,c,d){!function(b,e){"function"==typeof a&&a.amd?a(e):"object"==typeof d?c.exports=e():b.ayepromise=e()}(this,function(){"use strict";var a={},b=function(){var a=!1;return function(b){return function(){a||(a=!0,b.apply(null,arguments))}}},c=function(a){var b=a&&a.then;return"object"==typeof a&&"function"==typeof b?function(){return b.apply(a,arguments)}:void 0},d=function(b,c){var d=a.defer(),e=function(a,b){setTimeout(function(){var c;try{c=a(b)}catch(e){return void d.reject(e)}c===d.promise?d.reject(new TypeError("Cannot resolve promise with itself")):d.resolve(c)},1)},g=function(a){b&&b.call?e(b,a):d.resolve(a)},h=function(a){c&&c.call?e(c,a):d.reject(a)};return{promise:d.promise,handle:function(a,b){a===f?g(b):h(b)}}},e=0,f=1,g=2;return a.defer=function(){var a,h=e,i=[],j=function(b,c){h=b,a=c,i.forEach(function(b){b.handle(h,a)}),i=null},k=function(a){j(f,a)},l=function(a){j(g,a)},m=function(b,c){var f=d(b,c);return h===e?i.push(f):f.handle(h,a),f.promise},n=function(a){var c=b();try{a(c(o),c(l))}catch(d){c(l)(d)}},o=function(a){var b;try{b=c(a)}catch(d){return void l(d)}b?n(b):k(a)},p=b();return{resolve:p(o),reject:p(l),promise:{then:m,fail:function(a){return m(null,a)}}}},a})},{}],3:[function(b,c,d){(function(b){!function(e){function f(a){throw RangeError(I[a])}function g(a,b){for(var c=a.length;c--;)a[c]=b(a[c]);return a}function h(a,b){return g(a.split(H),b).join(".")}function i(a){for(var b,c,d=[],e=0,f=a.length;f>e;)b=a.charCodeAt(e++),b>=55296&&56319>=b&&f>e?(c=a.charCodeAt(e++),56320==(64512&c)?d.push(((1023&b)<<10)+(1023&c)+65536):(d.push(b),e--)):d.push(b);return d}function j(a){return g(a,function(a){var b="";return a>65535&&(a-=65536,b+=L(a>>>10&1023|55296),a=56320|1023&a),b+=L(a)}).join("")}function k(a){return 10>a-48?a-22:26>a-65?a-65:26>a-97?a-97:x}function l(a,b){return a+22+75*(26>a)-((0!=b)<<5)}function m(a,b,c){var d=0;for(a=c?K(a/B):a>>1,a+=K(a/b);a>J*z>>1;d+=x)a=K(a/J);return K(d+(J+1)*a/(a+A))}function n(a){var b,c,d,e,g,h,i,l,n,o,p=[],q=a.length,r=0,s=D,t=C;for(c=a.lastIndexOf(E),0>c&&(c=0),d=0;c>d;++d)a.charCodeAt(d)>=128&&f("not-basic"),p.push(a.charCodeAt(d));for(e=c>0?c+1:0;q>e;){for(g=r,h=1,i=x;e>=q&&f("invalid-input"),l=k(a.charCodeAt(e++)),(l>=x||l>K((w-r)/h))&&f("overflow"),r+=l*h,n=t>=i?y:i>=t+z?z:i-t,!(n>l);i+=x)o=x-n,h>K(w/o)&&f("overflow"),h*=o;b=p.length+1,t=m(r-g,b,0==g),K(r/b)>w-s&&f("overflow"),s+=K(r/b),r%=b,p.splice(r++,0,s)}return j(p)}function o(a){var b,c,d,e,g,h,j,k,n,o,p,q,r,s,t,u=[];for(a=i(a),q=a.length,b=D,c=0,g=C,h=0;q>h;++h)p=a[h],128>p&&u.push(L(p));for(d=e=u.length,e&&u.push(E);q>d;){for(j=w,h=0;q>h;++h)p=a[h],p>=b&&j>p&&(j=p);for(r=d+1,j-b>K((w-c)/r)&&f("overflow"),c+=(j-b)*r,b=j,h=0;q>h;++h)if(p=a[h],b>p&&++c>w&&f("overflow"),p==b){for(k=c,n=x;o=g>=n?y:n>=g+z?z:n-g,!(o>k);n+=x)t=k-o,s=x-o,u.push(L(l(o+t%s,0))),k=K(t/s);u.push(L(l(k,0))),g=m(c,r,d==e),c=0,++d}++c,++b}return u.join("")}function p(a){return h(a,function(a){return F.test(a)?n(a.slice(4).toLowerCase()):a})}function q(a){return h(a,function(a){return G.test(a)?"xn--"+o(a):a})}var r="object"==typeof d&&d,s="object"==typeof c&&c&&c.exports==r&&c,t="object"==typeof b&&b;(t.global===t||t.window===t)&&(e=t);var u,v,w=2147483647,x=36,y=1,z=26,A=38,B=700,C=72,D=128,E="-",F=/^xn--/,G=/[^ -~]/,H=/\x2E|\u3002|\uFF0E|\uFF61/g,I={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},J=x-y,K=Math.floor,L=String.fromCharCode;if(u={version:"1.2.4",ucs2:{decode:i,encode:j},decode:n,encode:o,toASCII:q,toUnicode:p},"function"==typeof a&&"object"==typeof a.amd&&a.amd)a("punycode",function(){return u});else if(r&&!r.nodeType)if(s)s.exports=u;else for(v in u)u.hasOwnProperty(v)&&(r[v]=u[v]);else e.punycode=u}(this)}).call(this,"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],4:[function(a,b){"use strict";function c(a,b){return Object.prototype.hasOwnProperty.call(a,b)}b.exports=function(a,b,e,f){b=b||"&",e=e||"=";var g={};if("string"!=typeof a||0===a.length)return g;var h=/\+/g;a=a.split(b);var i=1e3;f&&"number"==typeof f.maxKeys&&(i=f.maxKeys);var j=a.length;i>0&&j>i&&(j=i);for(var k=0;j>k;++k){var l,m,n,o,p=a[k].replace(h,"%20"),q=p.indexOf(e);q>=0?(l=p.substr(0,q),m=p.substr(q+1)):(l=p,m=""),n=decodeURIComponent(l),o=decodeURIComponent(m),c(g,n)?d(g[n])?g[n].push(o):g[n]=[g[n],o]:g[n]=o}return g};var d=Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)}},{}],5:[function(a,b){"use strict";function c(a,b){if(a.map)return a.map(b);for(var c=[],d=0;de;e++)f=b.charAt(e),"\n"===f?(a.seenCR||a.line++,a.column=1,a.seenCR=!1):"\r"===f||"\u2028"===f||"\u2029"===f?(a.line++,a.column=1,a.seenCR=!0):(a.column++,a.seenCR=!1)}return T!==a&&(T>a&&(T=0,U={line:1,column:1,seenCR:!1}),c(U,T,a),T=a),U}function e(a){V>R||(R>V&&(V=R,W=[]),W.push(a))}function f(a,e,f){function g(a){var b=1;for(a.sort(function(a,b){return a.descriptionb.description?1:0});b1?g.slice(0,-1).join(", ")+" or "+g[a.length-1]:g[0],e=b?'"'+c(b)+'"':"end of input","Expected "+d+" but "+e+" found."}var i=d(f),j=f1?arguments[1]:{},r={},s={start:g},t=g,u=function(){return[]},v=r,w=",",x={type:"literal",value:",",description:'","'},y=function(a,b){return[a].concat(b)},z=function(a){return[a]},A=function(a,b){return{url:a,format:b}},B=function(a){return{url:a}},C="url(",D={type:"literal",value:"url(",description:'"url("'},E=")",F={type:"literal",value:")",description:'")"'},G=function(a){return a},H="format(",I={type:"literal",value:"format(",description:'"format("'},J="local(",K={type:"literal",value:"local(",description:'"local("'},L=function(a){return{local:a}},M=/^[^)]/,N={type:"class",value:"[^)]",description:"[^)]"},O=function(a){return Y.extractValue(a.join(""))},P=/^[ \t\r\n\f]/,Q={type:"class",value:"[ \\t\\r\\n\\f]",description:"[ \\t\\r\\n\\f]"},R=0,S=0,T=0,U={line:1,column:1,seenCR:!1},V=0,W=[],X=0;if("startRule"in q){if(!(q.startRule in s))throw new Error("Can't start parsing from rule \""+q.startRule+'".');t=s[q.startRule]}var Y=a("../util");if(p=t(),p!==r&&R===b.length)return p;throw p!==r&&Rb;b++)a.push(this.cssRules[b].cssText);return"@-moz-document "+this.matcher.matcherText+" {"+a.join("")+"}"}}),c.CSSDocumentRule=d.CSSDocumentRule},{"./CSSRule":16,"./MatcherList":22}],11:[function(a,b,c){var d={CSSStyleDeclaration:a("./CSSStyleDeclaration").CSSStyleDeclaration,CSSRule:a("./CSSRule").CSSRule};d.CSSFontFaceRule=function(){d.CSSRule.call(this),this.style=new d.CSSStyleDeclaration,this.style.parentRule=this},d.CSSFontFaceRule.prototype=new d.CSSRule,d.CSSFontFaceRule.prototype.constructor=d.CSSFontFaceRule,d.CSSFontFaceRule.prototype.type=5,Object.defineProperty(d.CSSFontFaceRule.prototype,"cssText",{get:function(){return"@font-face {"+this.style.cssText+"}"}}),c.CSSFontFaceRule=d.CSSFontFaceRule},{"./CSSRule":16,"./CSSStyleDeclaration":17}],12:[function(a,b,c){var d={CSSRule:a("./CSSRule").CSSRule,CSSStyleSheet:a("./CSSStyleSheet").CSSStyleSheet,MediaList:a("./MediaList").MediaList};d.CSSImportRule=function(){d.CSSRule.call(this),this.href="",this.media=new d.MediaList,this.styleSheet=new d.CSSStyleSheet},d.CSSImportRule.prototype=new d.CSSRule,d.CSSImportRule.prototype.constructor=d.CSSImportRule,d.CSSImportRule.prototype.type=3,Object.defineProperty(d.CSSImportRule.prototype,"cssText",{get:function(){var a=this.media.mediaText;return"@import url("+this.href+")"+(a?" "+a:"")+";"},set:function(a){for(var b,c,d=0,e="",f="";c=a.charAt(d);d++)switch(c){case" ":case" ":case"\r":case"\n":case"\f":"after-import"===e?e="url":f+=c;break;case"@":e||a.indexOf("@import",d)!==d||(e="after-import",d+="import".length,f="");break;case"u":if("url"===e&&a.indexOf("url(",d)===d){if(b=a.indexOf(")",d+1),-1===b)throw d+': ")" not found';d+="url(".length;var g=a.slice(d,b);g[0]===g[g.length-1]&&('"'===g[0]||"'"===g[0])&&(g=g.slice(1,-1)),this.href=g,d=b,e="media"}break;case'"':if("url"===e){if(b=a.indexOf('"',d+1),!b)throw d+": '\"' not found";this.href=a.slice(d+1,b),d=b,e="media"}break;case"'":if("url"===e){if(b=a.indexOf("'",d+1),!b)throw d+': "\'" not found';this.href=a.slice(d+1,b),d=b,e="media"}break;case";":"media"===e&&f&&(this.media.mediaText=f.trim());break;default:"media"===e&&(f+=c)}}}),c.CSSImportRule=d.CSSImportRule},{"./CSSRule":16,"./CSSStyleSheet":19,"./MediaList":23}],13:[function(a,b,c){var d={CSSRule:a("./CSSRule").CSSRule,CSSStyleDeclaration:a("./CSSStyleDeclaration").CSSStyleDeclaration};d.CSSKeyframeRule=function(){d.CSSRule.call(this),this.keyText="",this.style=new d.CSSStyleDeclaration,this.style.parentRule=this},d.CSSKeyframeRule.prototype=new d.CSSRule,d.CSSKeyframeRule.prototype.constructor=d.CSSKeyframeRule,d.CSSKeyframeRule.prototype.type=9,Object.defineProperty(d.CSSKeyframeRule.prototype,"cssText",{get:function(){return this.keyText+" {"+this.style.cssText+"} "}}),c.CSSKeyframeRule=d.CSSKeyframeRule},{"./CSSRule":16,"./CSSStyleDeclaration":17}],14:[function(a,b,c){var d={CSSRule:a("./CSSRule").CSSRule};d.CSSKeyframesRule=function(){d.CSSRule.call(this),this.name="",this.cssRules=[]},d.CSSKeyframesRule.prototype=new d.CSSRule,d.CSSKeyframesRule.prototype.constructor=d.CSSKeyframesRule,d.CSSKeyframesRule.prototype.type=8,Object.defineProperty(d.CSSKeyframesRule.prototype,"cssText",{get:function(){for(var a=[],b=0,c=this.cssRules.length;c>b;b++)a.push(" "+this.cssRules[b].cssText);return"@"+(this._vendorPrefix||"")+"keyframes "+this.name+" { \n"+a.join("\n")+"\n}"}}),c.CSSKeyframesRule=d.CSSKeyframesRule},{"./CSSRule":16}],15:[function(a,b,c){var d={CSSRule:a("./CSSRule").CSSRule,MediaList:a("./MediaList").MediaList};d.CSSMediaRule=function(){d.CSSRule.call(this),this.media=new d.MediaList,this.cssRules=[]},d.CSSMediaRule.prototype=new d.CSSRule,d.CSSMediaRule.prototype.constructor=d.CSSMediaRule,d.CSSMediaRule.prototype.type=4,Object.defineProperty(d.CSSMediaRule.prototype,"cssText",{get:function(){for(var a=[],b=0,c=this.cssRules.length;c>b;b++)a.push(this.cssRules[b].cssText);return"@media "+this.media.mediaText+" {"+a.join("")+"}"}}),c.CSSMediaRule=d.CSSMediaRule},{"./CSSRule":16,"./MediaList":23}],16:[function(a,b,c){var d={};d.CSSRule=function(){this.parentRule=null,this.parentStyleSheet=null},d.CSSRule.STYLE_RULE=1,d.CSSRule.IMPORT_RULE=3,d.CSSRule.MEDIA_RULE=4,d.CSSRule.FONT_FACE_RULE=5,d.CSSRule.PAGE_RULE=6,d.CSSRule.WEBKIT_KEYFRAMES_RULE=8,d.CSSRule.WEBKIT_KEYFRAME_RULE=9,d.CSSRule.prototype={constructor:d.CSSRule},c.CSSRule=d.CSSRule},{}],17:[function(a,b,c){var d={};d.CSSStyleDeclaration=function(){this.length=0,this.parentRule=null,this._importants={}},d.CSSStyleDeclaration.prototype={constructor:d.CSSStyleDeclaration,getPropertyValue:function(a){return this[a]||""},setProperty:function(a,b,c){if(this[a]){var d=Array.prototype.indexOf.call(this,a);0>d&&(this[this.length]=a,this.length++)}else this[this.length]=a,this.length++;this[a]=b,this._importants[a]=c},removeProperty:function(a){if(!(a in this))return"";var b=Array.prototype.indexOf.call(this,a);if(0>b)return"";var c=this[a];return this[a]="",Array.prototype.splice.call(this,b,1),c},getPropertyCSSValue:function(){},getPropertyPriority:function(a){return this._importants[a]||""},getPropertyShorthand:function(){},isPropertyImplicit:function(){},get cssText(){for(var a=[],b=0,c=this.length;c>b;++b){var d=this[b],e=this.getPropertyValue(d),f=this.getPropertyPriority(d);f&&(f=" !"+f),a[b]=d+": "+e+f+";"}return a.join(" ")},set cssText(a){var b,c;for(b=this.length;b--;)c=this[b],this[c]="";Array.prototype.splice.call(this,0,this.length),this._importants={};var e=d.parse("#bogus{"+a+"}").cssRules[0].style,f=e.length;for(b=0;f>b;++b)c=e[b],this.setProperty(e[b],e.getPropertyValue(c),e.getPropertyPriority(c))}},c.CSSStyleDeclaration=d.CSSStyleDeclaration,d.parse=a("./parse").parse},{"./parse":27}],18:[function(a,b,c){var d={CSSStyleDeclaration:a("./CSSStyleDeclaration").CSSStyleDeclaration,CSSRule:a("./CSSRule").CSSRule};d.CSSStyleRule=function(){d.CSSRule.call(this),this.selectorText="",this.style=new d.CSSStyleDeclaration,this.style.parentRule=this},d.CSSStyleRule.prototype=new d.CSSRule,d.CSSStyleRule.prototype.constructor=d.CSSStyleRule,d.CSSStyleRule.prototype.type=1,Object.defineProperty(d.CSSStyleRule.prototype,"cssText",{get:function(){var a;return a=this.selectorText?this.selectorText+" {"+this.style.cssText+"}":""},set:function(a){var b=d.CSSStyleRule.parse(a);this.style=b.style,this.selectorText=b.selectorText}}),d.CSSStyleRule.parse=function(a){for(var b,c,e,f=0,g="selector",h=f,i="",j={selector:!0,value:!0},k=new d.CSSStyleRule,l="";e=a.charAt(f);f++)switch(e){case" ":case" ":case"\r":case"\n":case"\f":if(j[g])switch(a.charAt(f-1)){case" ":case" ":case"\r":case"\n":case"\f":break;default:i+=" "}break;case'"':if(h=f+1,b=a.indexOf('"',h)+1,!b)throw'" is missing';i+=a.slice(f,b),f=b-1;break;case"'":if(h=f+1,b=a.indexOf("'",h)+1,!b)throw"' is missing";i+=a.slice(f,b),f=b-1;break;case"/":if("*"===a.charAt(f+1)){if(f+=2,b=a.indexOf("*/",f),-1===b)throw new SyntaxError("Missing */");f=b+1}else i+=e;break;case"{":"selector"===g&&(k.selectorText=i.trim(),i="",g="name");break;case":":"name"===g?(c=i.trim(),i="",g="value"):i+=e;break;case"!":"value"===g&&a.indexOf("!important",f)===f?(l="important",f+="important".length):i+=e;break;case";":"value"===g?(k.style.setProperty(c,i.trim(),l),l="",i="",g="name"):i+=e;break;case"}":if("value"===g)k.style.setProperty(c,i.trim(),l),l="",i="";else{if("name"===g)break;i+=e}g="selector";break;default:i+=e}return k},c.CSSStyleRule=d.CSSStyleRule},{"./CSSRule":16,"./CSSStyleDeclaration":17}],19:[function(a,b,c){var d={StyleSheet:a("./StyleSheet").StyleSheet,CSSStyleRule:a("./CSSStyleRule").CSSStyleRule}; 12 | d.CSSStyleSheet=function(){d.StyleSheet.call(this),this.cssRules=[]},d.CSSStyleSheet.prototype=new d.StyleSheet,d.CSSStyleSheet.prototype.constructor=d.CSSStyleSheet,d.CSSStyleSheet.prototype.insertRule=function(a,b){if(0>b||b>this.cssRules.length)throw new RangeError("INDEX_SIZE_ERR");var c=d.parse(a).cssRules[0];return c.parentStyleSheet=this,this.cssRules.splice(b,0,c),b},d.CSSStyleSheet.prototype.deleteRule=function(a){if(0>a||a>=this.cssRules.length)throw new RangeError("INDEX_SIZE_ERR");this.cssRules.splice(a,1)},d.CSSStyleSheet.prototype.toString=function(){for(var a="",b=this.cssRules,c=0;c$/,/\<$/,/\&$/,/\|$/,/\^$/,/\~$/,/\?$/,/\,$/,/delete$/,/in$/,/instanceof$/,/new$/,/typeof$/,/void$/],e=d.some(function(a){return a.test(c)});if(e){var f="/";return this._parseJSString(a,b,f)}return!1},d.CSSValueExpression.prototype._findMatchedIdx=function(a,b,c){for(var d,e=b,f=-1;;){if(d=a.indexOf(c,e+1),-1===d){d=f;break}var g=a.substring(b+1,d),h=g.match(/\\+$/);if(!h||h[0]%2==0)break;e=d}var i=a.indexOf("\n",b+1);return d>i&&(d=f),d},c.CSSValueExpression=d.CSSValueExpression},{"./CSSValue":20}],22:[function(a,b,c){var d={};d.MatcherList=function(){this.length=0},d.MatcherList.prototype={constructor:d.MatcherList,get matcherText(){return Array.prototype.join.call(this,", ")},set matcherText(a){for(var b=a.split(","),c=this.length=b.length,d=0;c>d;d++)this[d]=b[d].trim()},appendMatcher:function(a){-1===Array.prototype.indexOf.call(this,a)&&(this[this.length]=a,this.length++)},deleteMatcher:function(a){var b=Array.prototype.indexOf.call(this,a);-1!==b&&Array.prototype.splice.call(this,b,1)}},c.MatcherList=d.MatcherList},{}],23:[function(a,b,c){var d={};d.MediaList=function(){this.length=0},d.MediaList.prototype={constructor:d.MediaList,get mediaText(){return Array.prototype.join.call(this,", ")},set mediaText(a){for(var b=a.split(","),c=this.length=b.length,d=0;c>d;d++)this[d]=b[d].trim()},appendMedium:function(a){-1===Array.prototype.indexOf.call(this,a)&&(this[this.length]=a,this.length++)},deleteMedium:function(a){var b=Array.prototype.indexOf.call(this,a);-1!==b&&Array.prototype.splice.call(this,b,1)}},c.MediaList=d.MediaList},{}],24:[function(a,b,c){var d={};d.StyleSheet=function(){this.parentStyleSheet=null},c.StyleSheet=d.StyleSheet},{}],25:[function(a,b,c){var d={CSSStyleSheet:a("./CSSStyleSheet").CSSStyleSheet,CSSStyleRule:a("./CSSStyleRule").CSSStyleRule,CSSMediaRule:a("./CSSMediaRule").CSSMediaRule,CSSStyleDeclaration:a("./CSSStyleDeclaration").CSSStyleDeclaration,CSSKeyframeRule:a("./CSSKeyframeRule").CSSKeyframeRule,CSSKeyframesRule:a("./CSSKeyframesRule").CSSKeyframesRule};d.clone=function e(a){var b=new d.CSSStyleSheet,c=a.cssRules;if(!c)return b;for(var f={1:d.CSSStyleRule,4:d.CSSMediaRule,8:d.CSSKeyframesRule,9:d.CSSKeyframeRule},g=0,h=c.length;h>g;g++){var i=c[g],j=b.cssRules[g]=new f[i.type],k=i.style;if(k){for(var l=j.style=new d.CSSStyleDeclaration,m=0,n=k.length;n>m;m++){var o=l[m]=k[m];l[o]=k[o],l._importants[o]=k.getPropertyPriority(o)}l.length=k.length}i.hasOwnProperty("keyText")&&(j.keyText=i.keyText),i.hasOwnProperty("selectorText")&&(j.selectorText=i.selectorText),i.hasOwnProperty("mediaText")&&(j.mediaText=i.mediaText),i.hasOwnProperty("cssRules")&&(j.cssRules=e(i).cssRules)}return b},c.clone=d.clone},{"./CSSKeyframeRule":13,"./CSSKeyframesRule":14,"./CSSMediaRule":15,"./CSSStyleDeclaration":17,"./CSSStyleRule":18,"./CSSStyleSheet":19}],26:[function(a,b,c){"use strict";c.CSSStyleDeclaration=a("./CSSStyleDeclaration").CSSStyleDeclaration,c.CSSRule=a("./CSSRule").CSSRule,c.CSSStyleRule=a("./CSSStyleRule").CSSStyleRule,c.MediaList=a("./MediaList").MediaList,c.CSSMediaRule=a("./CSSMediaRule").CSSMediaRule,c.CSSImportRule=a("./CSSImportRule").CSSImportRule,c.CSSFontFaceRule=a("./CSSFontFaceRule").CSSFontFaceRule,c.StyleSheet=a("./StyleSheet").StyleSheet,c.CSSStyleSheet=a("./CSSStyleSheet").CSSStyleSheet,c.CSSKeyframesRule=a("./CSSKeyframesRule").CSSKeyframesRule,c.CSSKeyframeRule=a("./CSSKeyframeRule").CSSKeyframeRule,c.MatcherList=a("./MatcherList").MatcherList,c.CSSDocumentRule=a("./CSSDocumentRule").CSSDocumentRule,c.CSSValue=a("./CSSValue").CSSValue,c.CSSValueExpression=a("./CSSValueExpression").CSSValueExpression,c.parse=a("./parse").parse,c.clone=a("./clone").clone},{"./CSSDocumentRule":10,"./CSSFontFaceRule":11,"./CSSImportRule":12,"./CSSKeyframeRule":13,"./CSSKeyframesRule":14,"./CSSMediaRule":15,"./CSSRule":16,"./CSSStyleDeclaration":17,"./CSSStyleRule":18,"./CSSStyleSheet":19,"./CSSValue":20,"./CSSValueExpression":21,"./MatcherList":22,"./MediaList":23,"./StyleSheet":24,"./clone":25,"./parse":27}],27:[function(a,b,c){var d={};d.parse=function(a){for(var b,c,e,f,g,h,i,j,k,l,m=0,n="before-selector",o="",p={selector:!0,value:!0,atRule:!0,"importRule-begin":!0,importRule:!0,atBlock:!0,"documentRule-begin":!0},q=new d.CSSStyleSheet,r=q,s="",t=/@(-(?:\w+-)+)?keyframes/g,u=function(b){var c=a.substring(0,m).split("\n"),d=c.length,e=c.pop().length+1,f=new Error(b+" (line "+d+", char "+e+")");throw f.line=d,f["char"]=e,f.styleSheet=q,f};l=a.charAt(m);m++)switch(l){case" ":case" ":case"\r":case"\n":case"\f":p[n]&&(o+=l);break;case'"':b=m+1;do b=a.indexOf('"',b)+1,b||u('Unmatched "');while("\\"===a[b-2]);switch(o+=a.slice(m,b),m=b-1,n){case"before-value":n="value";break;case"importRule-begin":n="importRule"}break;case"'":b=m+1;do b=a.indexOf("'",b)+1,b||u("Unmatched '");while("\\"===a[b-2]);switch(o+=a.slice(m,b),m=b-1,n){case"before-value":n="value";break;case"importRule-begin":n="importRule"}break;case"/":"*"===a.charAt(m+1)?(m+=2,b=a.indexOf("*/",m),-1===b?u("Missing */"):m=b+1):o+=l,"importRule-begin"===n&&(o+=" ",n="importRule");break;case"@":if(a.indexOf("@-moz-document",m)===m){n="documentRule-begin",k=new d.CSSDocumentRule,k.__starts=m,m+="-moz-document".length,o="";break}if(a.indexOf("@media",m)===m){n="atBlock",g=new d.CSSMediaRule,g.__starts=m,m+="media".length,o="";break}if(a.indexOf("@import",m)===m){n="importRule-begin",m+="import".length,o+="@import";break}if(a.indexOf("@font-face",m)===m){n="fontFaceRule-begin",m+="font-face".length,i=new d.CSSFontFaceRule,i.__starts=m,o="";break}t.lastIndex=m;var v=t.exec(a);if(v&&v.index===m){n="keyframesRule-begin",j=new d.CSSKeyframesRule,j.__starts=m,j._vendorPrefix=v[1],m+=v[0].length-1,o="";break}"selector"==n&&(n="atRule"),o+=l;break;case"{":"selector"===n||"atRule"===n?(f.selectorText=o.trim(),f.style.__starts=m,o="",n="before-name"):"atBlock"===n?(g.media.mediaText=o.trim(),r=c=g,g.parentStyleSheet=q,o="",n="before-selector"):"fontFaceRule-begin"===n?(c&&(i.parentRule=c),i.parentStyleSheet=q,f=i,o="",n="before-name"):"keyframesRule-begin"===n?(j.name=o.trim(),c&&(j.parentRule=c),j.parentStyleSheet=q,r=c=j,o="",n="keyframeRule-begin"):"keyframeRule-begin"===n?(f=new d.CSSKeyframeRule,f.keyText=o.trim(),f.__starts=m,o="",n="before-name"):"documentRule-begin"===n&&(k.matcher.matcherText=o.trim(),c&&(k.parentRule=c),r=c=k,k.parentStyleSheet=q,o="",n="before-selector");break;case":":"name"===n?(e=o.trim(),o="",n="before-value"):o+=l;break;case"(":if("value"===n)if("expression"==o.trim()){var w=new d.CSSValueExpression(a,m).parse();w.error?u(w.error):(o+=w.expression,m=w.idx)}else b=a.indexOf(")",m+1),-1===b&&u('Unmatched "("'),o+=a.slice(m,b+1),m=b;else o+=l;break;case"!":"value"===n&&a.indexOf("!important",m)===m?(s="important",m+="important".length):o+=l;break;case";":switch(n){case"value":f.style.setProperty(e,o.trim(),s),s="",o="",n="before-name";break;case"atRule":o="",n="before-selector";break;case"importRule":h=new d.CSSImportRule,h.parentStyleSheet=h.styleSheet.parentStyleSheet=q,h.cssText=o+l,q.cssRules.push(h),o="",n="before-selector";break;default:o+=l}break;case"}":switch(n){case"value":f.style.setProperty(e,o.trim(),s),s="";case"before-name":case"name":f.__ends=m+1,c&&(f.parentRule=c),f.parentStyleSheet=q,r.cssRules.push(f),o="",n=r.constructor===d.CSSKeyframesRule?"keyframeRule-begin":"before-selector";break;case"keyframeRule-begin":case"before-selector":case"selector":c||u("Unexpected }"),r.__ends=m+1,q.cssRules.push(r),r=q,c=null,o="",n="before-selector"}break;default:switch(n){case"before-selector":n="selector",f=new d.CSSStyleRule,f.__starts=m;break;case"before-name":n="name";break;case"before-value":n="value";break;case"importRule-begin":n="importRule"}o+=l}return q},c.parse=d.parse,d.CSSStyleSheet=a("./CSSStyleSheet").CSSStyleSheet,d.CSSStyleRule=a("./CSSStyleRule").CSSStyleRule,d.CSSImportRule=a("./CSSImportRule").CSSImportRule,d.CSSMediaRule=a("./CSSMediaRule").CSSMediaRule,d.CSSFontFaceRule=a("./CSSFontFaceRule").CSSFontFaceRule,d.CSSStyleDeclaration=a("./CSSStyleDeclaration").CSSStyleDeclaration,d.CSSKeyframeRule=a("./CSSKeyframeRule").CSSKeyframeRule,d.CSSKeyframesRule=a("./CSSKeyframesRule").CSSKeyframesRule,d.CSSValueExpression=a("./CSSValueExpression").CSSValueExpression,d.CSSDocumentRule=a("./CSSDocumentRule").CSSDocumentRule},{"./CSSDocumentRule":10,"./CSSFontFaceRule":11,"./CSSImportRule":12,"./CSSKeyframeRule":13,"./CSSKeyframesRule":14,"./CSSMediaRule":15,"./CSSStyleDeclaration":17,"./CSSStyleRule":18,"./CSSStyleSheet":19,"./CSSValueExpression":21}],28:[function(a,b,c){"use strict";var d=a("./cssSupport"),e=function(a){var b=/^[\t\r\f\n ]*(.+?)[\t\r\f\n ]*$/;return a.replace(b,"$1")};c.extractCssUrl=function(a){var b,c=/^url\(([^\)]+)\)/;if(!c.test(a))throw new Error("Invalid url");return b=c.exec(a)[1],d.unquoteString(e(b))};var f=function(a){var b,c="\\s*(?:\"[^\"]*\"|'[^']*'|[^\\(]+)\\s*",d="(url\\("+c+"\\)|[^,\\s]+)",e="(?:\\s*"+d+")+",f="^\\s*("+e+")(?:\\s*,\\s*("+e+"))*\\s*$",g=new RegExp(e,"g"),h=[],i=function(a){var b,c=new RegExp(d,"g"),e=[];for(b=c.exec(a);b;)e.push(b[1]),b=c.exec(a);return e};if(a.match(new RegExp(f))){for(b=g.exec(a);b;)h.push(i(b[0])),b=g.exec(a);return h}return[]},g=function(a){var b,d;for(b=0;b=0}();c.rulesForCssText=function(a){return f&&d.parse?d.parse(a).cssRules:e(a)},c.cssRulesToText=function(a){return a.reduce(function(a,b){return a+b.cssText},"")},c.exchangeRule=function(a,b,c){var d=a.indexOf(b),e=b.parentStyleSheet;e.insertRule(c,d+1),e.deleteRule(d),a[d]=e.cssRules[d]},c.changeFontFaceRuleSrc=function(a,b,d){var e="@font-face { font-family: "+b.style.getPropertyValue("font-family")+"; ";b.style.getPropertyValue("font-style")&&(e+="font-style: "+b.style.getPropertyValue("font-style")+"; "),b.style.getPropertyValue("font-weight")&&(e+="font-weight: "+b.style.getPropertyValue("font-weight")+"; "),e+="src: "+d+"}",c.exchangeRule(a,b,e)}},{cssom:26}],30:[function(a,b,c){"use strict";var d=a("./util"),e=a("./inlineImage"),f=a("./inlineScript"),g=a("./inlineCss"),h=a("./cssSupport"),i=function(a){return d.joinUrl(a,".")},j=function(a){var b=a.map(function(b,c){return c===a.length-1&&(b={baseUrl:i(b.baseUrl)}),JSON.stringify(b)});return b},k=function(a,b){return b.cache!==!1&&"none"!==b.cache&&b.cacheBucket?d.memoize(a,j,b.cacheBucket):a},l=function(a,b,c){var d=h.rulesForCssText(a);return g.loadCSSImportsForRules(d,b,c).then(function(b){return g.loadAndInlineCSSResourcesForRules(d,c).then(function(c){var e=b.errors.concat(c.errors),f=b.hasChanges||c.hasChanges;return f&&(a=h.cssRulesToText(d)),{hasChanges:f,content:a,errors:e}})})},m=function(a,b,c){var e=a.textContent,f=k(l,b);return f(e,c,b).then(function(b){return b.hasChanges&&(a.childNodes[0].nodeValue=b.content),d.cloneArray(b.errors)})},n=function(a){var b=a.getElementsByTagName("style");return Array.prototype.filter.call(b,function(a){return!a.attributes.type||"text/css"===a.attributes.type.nodeValue})};c.loadAndInlineStyles=function(a,b){var c,e=n(a),f=[],g=[];return c=d.clone(b),c.baseUrl=c.baseUrl||d.getDocumentBaseUrl(a),d.all(e.map(function(a){return m(a,c,g).then(function(a){f=f.concat(a)})})).then(function(){return f})};var o=function(a,b){var c,d=a.parentNode;b=b.trim(),b&&(c=a.ownerDocument.createElement("style"),c.type="text/css",c.appendChild(a.ownerDocument.createTextNode(b)),d.insertBefore(c,a)),d.removeChild(a)},p=function(a,b){return d.ajax(a,b).then(function(a){var b=h.rulesForCssText(a);return{content:a,cssRules:b}}).then(function(b){var c=g.adjustPathsOfCssResources(a,b.cssRules);return{content:b.content,cssRules:b.cssRules,hasChanges:c}}).then(function(a){return g.loadCSSImportsForRules(a.cssRules,[],b).then(function(b){return{content:a.content,cssRules:a.cssRules,hasChanges:a.hasChanges||b.hasChanges,errors:b.errors}})}).then(function(a){return g.loadAndInlineCSSResourcesForRules(a.cssRules,b).then(function(b){return{content:a.content,cssRules:a.cssRules,hasChanges:a.hasChanges||b.hasChanges,errors:a.errors.concat(b.errors)}})}).then(function(a){var b=a.content;return a.hasChanges&&(b=h.cssRulesToText(a.cssRules)),{content:b,errors:a.errors}})},q=function(a,b){var c=a.attributes.href.nodeValue,e=d.getDocumentBaseUrl(a.ownerDocument),f=d.clone(b);!f.baseUrl&&e&&(f.baseUrl=e);var g=k(p,b);return g(c,f).then(function(a){return{content:a.content,errors:d.cloneArray(a.errors)}})},r=function(a){var b=a.getElementsByTagName("link");return Array.prototype.filter.call(b,function(a){return a.attributes.rel&&"stylesheet"===a.attributes.rel.nodeValue&&(!a.attributes.type||"text/css"===a.attributes.type.nodeValue)})};c.loadAndInlineCssLinks=function(a,b){var c=r(a),e=[];return d.all(c.map(function(a){return q(a,b).then(function(b){o(a,b.content+"\n"),e=e.concat(b.errors)},function(a){e.push({resourceType:"stylesheet",url:a.url,msg:"Unable to load stylesheet "+a.url})})})).then(function(){return e})},c.loadAndInlineImages=e.inline,c.loadAndInlineScript=f.inline,c.inlineReferences=function(a,b){var e=[],f=[c.loadAndInlineImages,c.loadAndInlineStyles,c.loadAndInlineCssLinks];return b.inlineScripts!==!1&&f.push(c.loadAndInlineScript),d.all(f.map(function(c){return c(a,b).then(function(a){e=e.concat(a)})})).then(function(){return e})}},{"./cssSupport":29,"./inlineCss":31,"./inlineImage":32,"./inlineScript":33,"./util":34}],31:[function(a,b,c){"use strict";var d=a("ayepromise"),e=a("./util"),f=a("./cssSupport"),g=a("./backgroundValueParser"),h=a("css-font-face-src"),i=function(a,b,c){a.style.setProperty(b,c,a.style.getPropertyPriority(b))},j=function(a){return a.filter(function(a){return a.type===window.CSSRule.STYLE_RULE&&(a.style.getPropertyValue("background-image")||a.style.getPropertyValue("background"))})},k=function(a){var b=[];return a.forEach(function(a){a.style.getPropertyValue("background-image")?b.push({property:"background-image",value:a.style.getPropertyValue("background-image"),rule:a}):a.style.getPropertyValue("background")&&b.push({property:"background",value:a.style.getPropertyValue("background"),rule:a})}),b},l=function(a){return a.filter(function(a){return a.type===window.CSSRule.FONT_FACE_RULE&&a.style.getPropertyValue("src")})},m=function(a){return a.filter(function(a){return a.type===window.CSSRule.IMPORT_RULE&&a.href})},n=function(a){var b=[];return a.forEach(function(a,c){a.url&&!e.isDataUri(a.url)&&b.push(c)}),b},o=function(a){var b=[];return a.forEach(function(a,c){a.url&&!e.isDataUri(a.url)&&b.push(c)}),b};c.adjustPathsOfCssResources=function(a,b){var c=j(b),d=k(c),p=!1;return d.forEach(function(b){var c,d=g.parse(b.value),f=n(d);f.length>0&&(f.forEach(function(b){var c=d[b].url,f=e.joinUrl(a,c);d[b].url=f}),c=g.serialize(d),i(b.rule,b.property,c),p=!0)}),l(b).forEach(function(c){var d,g,i=c.style.getPropertyValue("src");try{d=h.parse(i)}catch(j){return}g=o(d),g.length>0&&(g.forEach(function(b){var c=d[b].url,f=e.joinUrl(a,c);d[b].url=f}),f.changeFontFaceRuleSrc(b,c,h.serialize(d)),p=!0)}),m(b).forEach(function(c){var d=c.href,g=e.joinUrl(a,d);f.exchangeRule(b,c,"@import url("+g+");"),p=!0}),p};var p=function(a,b,c){var d=a.indexOf(b);a.splice(d,1),c.forEach(function(b,c){a.splice(d+c,0,b)})},q=function(a){var b=d.defer();return b.resolve(a),b.promise},r=function(a,b,d,g){var h,i=b.href;return i=f.unquoteString(i),h=e.joinUrl(g.baseUrl,i),d.indexOf(h)>=0?(p(a,b,[]),q([])):(d.push(h),e.ajax(i,g).then(function(e){var h=f.rulesForCssText(e);return c.loadCSSImportsForRules(h,d,g).then(function(d){return c.adjustPathsOfCssResources(i,h),p(a,b,h),d.errors})},function(a){throw{resourceType:"stylesheet",url:a.url,msg:"Unable to load stylesheet "+a.url}}))};c.loadCSSImportsForRules=function(a,b,c){var d=m(a),f=[],g=!1;return e.all(d.map(function(d){return r(a,d,b,c).then(function(a){f=f.concat(a),g=!0},function(a){f.push(a)})})).then(function(){return{hasChanges:g,errors:f}})};var s=function(a,b){var c=g.parse(a),d=n(c),f=!1;return e.collectAndReportErrors(d.map(function(a){var d=c[a].url;return e.getDataURIForImageURL(d,b).then(function(b){c[a].url=b,f=!0},function(a){throw{resourceType:"backgroundImage",url:a.url,msg:"Unable to load background-image "+a.url}})})).then(function(a){return{backgroundValue:g.serialize(c),hasChanges:f,errors:a}})},t=function(a,b){var c=j(a),d=k(c),f=[],g=!1;return e.all(d.map(function(a){return s(a.value,b).then(function(b){b.hasChanges&&(i(a.rule,a.property,b.backgroundValue),g=!0),f=f.concat(b.errors)})})).then(function(){return{hasChanges:g,errors:f}})},u=function(a,b){var c,d,f=!1;try{c=h.parse(a)}catch(g){c=[]}return d=o(c),e.collectAndReportErrors(d.map(function(a){var d=c[a],g=d.format||"woff";return e.binaryAjax(d.url,b).then(function(a){var b=btoa(a);d.url="data:font/"+g+";base64,"+b,f=!0},function(a){throw{resourceType:"fontFace",url:a.url,msg:"Unable to load font-face "+a.url}})})).then(function(a){return{srcDeclarationValue:h.serialize(c),hasChanges:f,errors:a}})},v=function(a,b){var c=l(a),d=[],g=!1;return e.all(c.map(function(c){var e=c.style.getPropertyValue("src");return u(e,b).then(function(b){b.hasChanges&&(f.changeFontFaceRuleSrc(a,c,b.srcDeclarationValue),g=!0),d=d.concat(b.errors)})})).then(function(){return{hasChanges:g,errors:d}})};c.loadAndInlineCSSResourcesForRules=function(a,b){var c=!1,d=[];return e.all([t,v].map(function(e){return e(a,b).then(function(a){c=c||a.hasChanges,d=d.concat(a.errors)})})).then(function(){return{hasChanges:c,errors:d}})}},{"./backgroundValueParser":28,"./cssSupport":29,"./util":34,ayepromise:2,"css-font-face-src":8}],32:[function(a,b,c){"use strict";var d=a("./util"),e=function(a,b){var c=a.attributes.src?a.attributes.src.nodeValue:null,e=d.getDocumentBaseUrl(a.ownerDocument),f=d.clone(b);return!f.baseUrl&&e&&(f.baseUrl=e),d.getDataURIForImageURL(c,f).then(function(a){return a},function(a){throw{resourceType:"image",url:a.url,msg:"Unable to load image "+a.url}})},f=function(a){return a.filter(function(a){var b=a.attributes.src?a.attributes.src.nodeValue:null;return null!==b&&!d.isDataUri(b)})},g=function(a){return Array.prototype.filter.call(a,function(a){return"image"===a.type})},h=function(a){return Array.prototype.slice.call(a)};c.inline=function(a,b){var c=h(a.getElementsByTagName("img")),i=g(a.getElementsByTagName("input")),j=f(c.concat(i));return d.collectAndReportErrors(j.map(function(a){return e(a,b).then(function(b){a.attributes.src.nodeValue=b})}))}},{"./util":34}],33:[function(a,b,c){"use strict";var d=a("./util"),e=function(a,b){var c=a.attributes.src.nodeValue,e=d.getDocumentBaseUrl(a.ownerDocument),f=d.clone(b);return!f.baseUrl&&e&&(f.baseUrl=e),d.ajax(c,f).fail(function(a){throw{resourceType:"script",url:a.url,msg:"Unable to load script "+a.url}})},f=function(a){return a.replace(/<\//g,"<\\/")},g=function(a,b){a.attributes.removeNamedItem("src"),a.textContent=f(b)},h=function(a){var b=a.getElementsByTagName("script");return Array.prototype.filter.call(b,function(a){return!!a.attributes.src})};c.inline=function(a,b){var c=h(a);return d.collectAndReportErrors(c.map(function(a){return e(a,b).then(function(b){g(a,b)})}))}},{"./util":34}],34:[function(a,b,c){"use strict";var d=a("url"),e=a("ayepromise");c.getDocumentBaseUrl=function(a){return"about:blank"!==a.baseURI?a.baseURI:null},c.clone=function(a){var b,c={};for(b in a)a.hasOwnProperty(b)&&(c[b]=a[b]);return c},c.cloneArray=function(a){return Array.prototype.slice.apply(a,[0])},c.joinUrl=function(a,b){return a?d.resolve(a,b):b},c.isDataUri=function(a){return/^data:/.test(a)},c.all=function(a){var b=e.defer(),c=a.length,d=[];return 0===a.length?(b.resolve([]),b.promise):(a.forEach(function(a,e){a.then(function(a){c-=1,d[e]=a,0===c&&b.resolve(d)},function(a){b.reject(a)})}),b.promise)},c.collectAndReportErrors=function(a){var b=[];return c.all(a.map(function(a){return a.fail(function(a){b.push(a)})})).then(function(){return b})};var f=null,g=function(a,b){return b===!1||"none"===b||"repeated"===b?((null===f||"repeated"!==b)&&(f=Date.now()),a+"?_="+f):a};c.ajax=function(a,b){var d,f=new window.XMLHttpRequest,h=e.defer(),i=c.joinUrl(b.baseUrl,a),j=function(){h.reject({msg:"Unable to load url",url:i})};d=g(i,b.cache),f.addEventListener("load",function(){200===f.status||0===f.status?h.resolve(f.response):j()},!1),f.addEventListener("error",j,!1);try{f.open("GET",d,!0),f.overrideMimeType(b.mimeType),f.send(null)}catch(k){j()}return h.promise},c.binaryAjax=function(a,b){var d=c.clone(b);return d.mimeType="text/plain; charset=x-user-defined",c.ajax(a,d).then(function(a){for(var b="",c=0;c",'"',"`"," ","\r","\n"," "],q=["{","}","|","\\","^","`"].concat(p),r=["'"].concat(q),s=["%","/","?",";","#"].concat(r),t=["/","?","#"],u=255,v=/^[a-z0-9A-Z_-]{0,63}$/,w=/^([a-z0-9A-Z_-]{0,63})(.*)$/,x={javascript:!0,"javascript:":!0},y={javascript:!0,"javascript:":!0},z={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},A=a("querystring");d.prototype.parse=function(a,b,c){if(!i(a))throw new TypeError("Parameter 'url' must be a string, not "+typeof a);var d=a;d=d.trim();var e=n.exec(d);if(e){e=e[0];var f=e.toLowerCase();this.protocol=f,d=d.substr(e.length)}if(c||e||d.match(/^\/\/[^@\/]+@[^@\/]+/)){var g="//"===d.substr(0,2);!g||e&&y[e]||(d=d.substr(2),this.slashes=!0)}if(!y[e]&&(g||e&&!z[e])){for(var h=-1,j=0;jk)&&(h=k)}var l,o;o=-1===h?d.lastIndexOf("@"):d.lastIndexOf("@",h),-1!==o&&(l=d.slice(0,o),d=d.slice(o+1),this.auth=decodeURIComponent(l)),h=-1;for(var j=0;jk)&&(h=k)}-1===h&&(h=d.length),this.host=d.slice(0,h),d=d.slice(h),this.parseHost(),this.hostname=this.hostname||"";var p="["===this.hostname[0]&&"]"===this.hostname[this.hostname.length-1];if(!p)for(var q=this.hostname.split(/\./),j=0,B=q.length;B>j;j++){var C=q[j];if(C&&!C.match(v)){for(var D="",E=0,F=C.length;F>E;E++)D+=C.charCodeAt(E)>127?"x":C[E];if(!D.match(v)){var G=q.slice(0,j),H=q.slice(j+1),I=C.match(w);I&&(G.push(I[1]),H.unshift(I[2])),H.length&&(d="/"+H.join(".")+d),this.hostname=G.join(".");break}}}if(this.hostname=this.hostname.length>u?"":this.hostname.toLowerCase(),!p){for(var J=this.hostname.split("."),K=[],j=0;jj;j++){var O=r[j],P=encodeURIComponent(O);P===O&&(P=escape(O)),d=d.split(O).join(P)}var Q=d.indexOf("#");-1!==Q&&(this.hash=d.substr(Q),d=d.slice(0,Q));var R=d.indexOf("?");if(-1!==R?(this.search=d.substr(R),this.query=d.substr(R+1),b&&(this.query=A.parse(this.query)),d=d.slice(0,R)):b&&(this.search="",this.query={}),d&&(this.pathname=d),z[f]&&this.hostname&&!this.pathname&&(this.pathname="/"),this.pathname||this.search){var M=this.pathname||"",L=this.search||"";this.path=M+L}return this.href=this.format(),this},d.prototype.format=function(){var a=this.auth||"";a&&(a=encodeURIComponent(a),a=a.replace(/%3A/i,":"),a+="@");var b=this.protocol||"",c=this.pathname||"",d=this.hash||"",e=!1,f="";this.host?e=a+this.host:this.hostname&&(e=a+(-1===this.hostname.indexOf(":")?this.hostname:"["+this.hostname+"]"),this.port&&(e+=":"+this.port)),this.query&&j(this.query)&&Object.keys(this.query).length&&(f=A.stringify(this.query));var g=this.search||f&&"?"+f||"";return b&&":"!==b.substr(-1)&&(b+=":"),this.slashes||(!b||z[b])&&e!==!1?(e="//"+(e||""),c&&"/"!==c.charAt(0)&&(c="/"+c)):e||(e=""),d&&"#"!==d.charAt(0)&&(d="#"+d),g&&"?"!==g.charAt(0)&&(g="?"+g),c=c.replace(/[?#]/g,function(a){return encodeURIComponent(a)}),g=g.replace("#","%23"),b+e+c+g+d},d.prototype.resolve=function(a){return this.resolveObject(e(a,!1,!0)).format()},d.prototype.resolveObject=function(a){if(i(a)){var b=new d;b.parse(a,!1,!0),a=b}var c=new d;if(Object.keys(this).forEach(function(a){c[a]=this[a]},this),c.hash=a.hash,""===a.href)return c.href=c.format(),c;if(a.slashes&&!a.protocol)return Object.keys(a).forEach(function(b){"protocol"!==b&&(c[b]=a[b])}),z[c.protocol]&&c.hostname&&!c.pathname&&(c.path=c.pathname="/"),c.href=c.format(),c;if(a.protocol&&a.protocol!==c.protocol){if(!z[a.protocol])return Object.keys(a).forEach(function(b){c[b]=a[b]}),c.href=c.format(),c;if(c.protocol=a.protocol,a.host||y[a.protocol])c.pathname=a.pathname;else{for(var e=(a.pathname||"").split("/");e.length&&!(a.host=e.shift()););a.host||(a.host=""),a.hostname||(a.hostname=""),""!==e[0]&&e.unshift(""),e.length<2&&e.unshift(""),c.pathname=e.join("/")}if(c.search=a.search,c.query=a.query,c.host=a.host||"",c.auth=a.auth,c.hostname=a.hostname||a.host,c.port=a.port,c.pathname||c.search){var f=c.pathname||"",g=c.search||"";c.path=f+g}return c.slashes=c.slashes||a.slashes,c.href=c.format(),c}var h=c.pathname&&"/"===c.pathname.charAt(0),j=a.host||a.pathname&&"/"===a.pathname.charAt(0),m=j||h||c.host&&a.pathname,n=m,o=c.pathname&&c.pathname.split("/")||[],e=a.pathname&&a.pathname.split("/")||[],p=c.protocol&&!z[c.protocol];if(p&&(c.hostname="",c.port=null,c.host&&(""===o[0]?o[0]=c.host:o.unshift(c.host)),c.host="",a.protocol&&(a.hostname=null,a.port=null,a.host&&(""===e[0]?e[0]=a.host:e.unshift(a.host)),a.host=null),m=m&&(""===e[0]||""===o[0])),j)c.host=a.host||""===a.host?a.host:c.host,c.hostname=a.hostname||""===a.hostname?a.hostname:c.hostname,c.search=a.search,c.query=a.query,o=e;else if(e.length)o||(o=[]),o.pop(),o=o.concat(e),c.search=a.search,c.query=a.query;else if(!l(a.search)){if(p){c.hostname=c.host=o.shift();var q=c.host&&c.host.indexOf("@")>0?c.host.split("@"):!1;q&&(c.auth=q.shift(),c.host=c.hostname=q.shift())}return c.search=a.search,c.query=a.query,k(c.pathname)&&k(c.search)||(c.path=(c.pathname?c.pathname:"")+(c.search?c.search:"")),c.href=c.format(),c}if(!o.length)return c.pathname=null,c.path=c.search?"/"+c.search:null,c.href=c.format(),c;for(var r=o.slice(-1)[0],s=(c.host||a.host)&&("."===r||".."===r)||""===r,t=0,u=o.length;u>=0;u--)r=o[u],"."==r?o.splice(u,1):".."===r?(o.splice(u,1),t++):t&&(o.splice(u,1),t--);if(!m&&!n)for(;t--;t)o.unshift("..");!m||""===o[0]||o[0]&&"/"===o[0].charAt(0)||o.unshift(""),s&&"/"!==o.join("/").substr(-1)&&o.push("");var v=""===o[0]||o[0]&&"/"===o[0].charAt(0);if(p){c.hostname=c.host=v?"":o.length?o.shift():"";var q=c.host&&c.host.indexOf("@")>0?c.host.split("@"):!1;q&&(c.auth=q.shift(),c.host=c.hostname=q.shift())}return m=m||c.host&&o.length,m&&!v&&o.unshift(""),o.length?c.pathname=o.join("/"):(c.pathname=null,c.path=null),k(c.pathname)&&k(c.search)||(c.path=(c.pathname?c.pathname:"")+(c.search?c.search:"")),c.auth=a.auth||c.auth,c.slashes=c.slashes||a.slashes,c.href=c.format(),c},d.prototype.parseHost=function(){var a=this.host,b=o.exec(a);b&&(b=b[0],":"!==b&&(this.port=b.substr(1)),a=a.substr(0,a.length-b.length)),a&&(this.hostname=a)}},{punycode:3,querystring:6}],37:[function(a,b,c){var d=function(a){return a.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g,"") 13 | },e=function(a){return a.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},f=function(a){return a.replace(/&/g,"&").replace(//g,">")},g=function(a){var b=a.value;return" "+a.name+'="'+e(b)+'"'},h=function(a){var b=a.tagName;return"http://www.w3.org/1999/xhtml"===a.namespaceURI&&(b=b.toLowerCase()),b},i=function(a){var b=Array.prototype.map.call(a.attributes||a.attrs,function(a){return a.name}).indexOf("xmlns")>=0;return b||a.parentNode&&a.namespaceURI===a.parentNode.namespaceURI&&"html"!==h(a)?"":' xmlns="'+a.namespaceURI+'"'},j=function(a){return Array.prototype.map.call(a.childNodes,function(a){return o(a)}).join("")},k=function(a){var b="<"+h(a);return b+=i(a),Array.prototype.forEach.call(a.attributes||a.attrs,function(a){b+=g(a)}),a.childNodes.length>0?(b+=">",b+=j(a),b+=""):b+="/>",b},l=function(a){var b=a.nodeValue||a.value||"";return f(b)},m=function(a){return""},n=function(a){return""},o=function(a){return"#document"===a.nodeName||"#document-fragment"===a.nodeName?j(a):a.tagName?k(a):"#text"===a.nodeName?l(a):"#comment"===a.nodeName?m(a):"#cdata-section"===a.nodeName?n(a):void 0};c.serializeToString=function(a){return d(o(a))}},{}]},{},[1])(1)}); --------------------------------------------------------------------------------