├── .gitattributes ├── bookmarklet.html ├── css ├── main.css ├── normalize.css └── normalize.min.css ├── index.html ├── js ├── main.js └── vendor │ ├── OrbitControls.js │ ├── dat.gui.min.js │ ├── jquery-1.11.2.js │ ├── modernizr-2.8.3.min.js │ └── three.min.js ├── pcb ├── b.cu.png ├── b.mask.png ├── b.silk.png ├── drl.png ├── edge.png ├── f.cu.png ├── f.mask.png └── f.silk.png ├── preview.gif ├── readme.md └── setup.gif /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /bookmarklet.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | OSHPark PCB Visualizer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

Drag the big purple button onto your bookmarks bar,
OR save the link as a bookmark.

18 | 19 | Purple Visualizer 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | /*! HTML5 Boilerplate v5.0 | MIT License | http://h5bp.com/ */ 2 | 3 | html { 4 | color: #222; 5 | font-size: 1em; 6 | line-height: 1.4; 7 | } 8 | 9 | ::-moz-selection { 10 | background: #b3d4fc; 11 | text-shadow: none; 12 | } 13 | 14 | ::selection { 15 | background: #b3d4fc; 16 | text-shadow: none; 17 | } 18 | 19 | hr { 20 | display: block; 21 | height: 1px; 22 | border: 0; 23 | border-top: 1px solid #ccc; 24 | margin: 1em 0; 25 | padding: 0; 26 | } 27 | 28 | audio, 29 | canvas, 30 | iframe, 31 | img, 32 | svg, 33 | video { 34 | vertical-align: middle; 35 | } 36 | 37 | fieldset { 38 | border: 0; 39 | margin: 0; 40 | padding: 0; 41 | } 42 | 43 | textarea { 44 | resize: vertical; 45 | } 46 | 47 | .browserupgrade { 48 | margin: 0.2em 0; 49 | background: #ccc; 50 | color: #000; 51 | padding: 0.2em 0; 52 | } 53 | 54 | 55 | /* ========================================================================== 56 | Author's custom styles 57 | ========================================================================== */ 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | /* ========================================================================== 74 | Media Queries 75 | ========================================================================== */ 76 | 77 | @media only screen and (min-width: 35em) { 78 | 79 | } 80 | 81 | @media print, 82 | (-o-min-device-pixel-ratio: 5/4), 83 | (-webkit-min-device-pixel-ratio: 1.25), 84 | (min-resolution: 120dpi) { 85 | 86 | } 87 | 88 | /* ========================================================================== 89 | Helper classes 90 | ========================================================================== */ 91 | 92 | .hidden { 93 | display: none !important; 94 | visibility: hidden; 95 | } 96 | 97 | .visuallyhidden { 98 | border: 0; 99 | clip: rect(0 0 0 0); 100 | height: 1px; 101 | margin: -1px; 102 | overflow: hidden; 103 | padding: 0; 104 | position: absolute; 105 | width: 1px; 106 | } 107 | 108 | .visuallyhidden.focusable:active, 109 | .visuallyhidden.focusable:focus { 110 | clip: auto; 111 | height: auto; 112 | margin: 0; 113 | overflow: visible; 114 | position: static; 115 | width: auto; 116 | } 117 | 118 | .invisible { 119 | visibility: hidden; 120 | } 121 | 122 | .clearfix:before, 123 | .clearfix:after { 124 | content: " "; 125 | display: table; 126 | } 127 | 128 | .clearfix:after { 129 | clear: both; 130 | } 131 | 132 | .clearfix { 133 | *zoom: 1; 134 | } 135 | 136 | /* ========================================================================== 137 | Print styles 138 | ========================================================================== */ 139 | 140 | @media print { 141 | *, 142 | *:before, 143 | *:after { 144 | background: transparent !important; 145 | color: #000 !important; 146 | box-shadow: none !important; 147 | text-shadow: none !important; 148 | } 149 | 150 | a, 151 | a:visited { 152 | text-decoration: underline; 153 | } 154 | 155 | a[href]:after { 156 | content: " (" attr(href) ")"; 157 | } 158 | 159 | abbr[title]:after { 160 | content: " (" attr(title) ")"; 161 | } 162 | 163 | a[href^="#"]:after, 164 | a[href^="javascript:"]:after { 165 | content: ""; 166 | } 167 | 168 | pre, 169 | blockquote { 170 | border: 1px solid #999; 171 | page-break-inside: avoid; 172 | } 173 | 174 | thead { 175 | display: table-header-group; 176 | } 177 | 178 | tr, 179 | img { 180 | page-break-inside: avoid; 181 | } 182 | 183 | img { 184 | max-width: 100% !important; 185 | } 186 | 187 | p, 188 | h2, 189 | h3 { 190 | orphans: 3; 191 | widows: 3; 192 | } 193 | 194 | h2, 195 | h3 { 196 | page-break-after: avoid; 197 | } 198 | } -------------------------------------------------------------------------------- /css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * 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/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 when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 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 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } 428 | -------------------------------------------------------------------------------- /css/normalize.min.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0} -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | OSHPark PCB Visualizer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | var key_color = [51, 0, 85]; 2 | var cu_color = [226, 188, 144]; 3 | var silk_color = [255, 255, 255]; 4 | var drl_color = [40, 40, 40]; 5 | var alpha_color = [0, 0, 0]; 6 | 7 | var pcb_image_urls = new Object(); 8 | 9 | var shared_alpha_channel; 10 | 11 | var camera, scene, renderer, controls, light, hemiLight; 12 | var mesh = new Object(); 13 | var material = new Object(); 14 | var default_opacity = 0.6; 15 | var default_z_spacing = 40; 16 | 17 | var controller, gui, onGUIChange; 18 | 19 | function main() 20 | { 21 | fillUrlFromQueryString(); 22 | // fillUrlForDebug(); // use for local testing 23 | 24 | three_init(); 25 | 26 | // creating the edge alpha channel will then process the other primary channels.. 27 | // ..which will then create their respective individual alpha channels (ugly) 28 | isolate("edge", alpha_color, true, false, 0); 29 | 30 | animate(); 31 | 32 | // GUI 33 | controller = 34 | { 35 | z_spacing: default_z_spacing, 36 | layer_opacity: default_opacity, 37 | auto_rotate: controls.autoRotate 38 | }; 39 | 40 | onGUIChange = function () 41 | { 42 | for (mesh_child in mesh) 43 | { 44 | mesh[mesh_child].material.opacity = controller.layer_opacity; 45 | mesh[mesh_child].position.set(0, mesh[mesh_child].position.y, controller.z_spacing * mesh[mesh_child].z_index); 46 | } 47 | controls.autoRotate = controller.auto_rotate; 48 | }; 49 | gui = new dat.GUI(); 50 | gui.add( controller, 'z_spacing', 1, 80 ).onChange ( onGUIChange ); 51 | gui.add( controller, 'layer_opacity', 0.1, 1 ).onChange ( onGUIChange ); 52 | gui.add( controller, 'auto_rotate' ).onChange( onGUIChange ); 53 | 54 | 55 | } 56 | 57 | function fillUrlForDebug() 58 | { 59 | pcb_image_urls["f.cu"] = "/pcb/f.cu.png"; 60 | pcb_image_urls["b.cu"] = "/pcb/b.cu.png"; 61 | pcb_image_urls["f.silk"] = "/pcb/f.silk.png"; 62 | pcb_image_urls["b.silk"] = "/pcb/b.silk.png"; 63 | pcb_image_urls["f.mask"] = "/pcb/f.mask.png"; 64 | pcb_image_urls["b.mask"] = "/pcb/b.mask.png"; 65 | pcb_image_urls["drl"] = "/pcb/drl.png"; 66 | pcb_image_urls["edge"] = "/pcb/edge.png"; 67 | } 68 | 69 | function fillUrlFromQueryString() 70 | { 71 | // doesn't check if it's really a URL 72 | params = getQueryParams(); 73 | //cors_proxy = "https://crossorigin.me/"; 74 | //cors_proxy = "https://cors.io/?"; 75 | cors_proxy = "https://cors-anywhere.herokuapp.com/"; 76 | 77 | if (params["f.cu"] === undefined) 78 | { 79 | alert("This page should be loaded from the bookmarklet on OSHPark - https://oshpark.com/uploads/xxxxxx/approval/new"); 80 | window.location = "https://github.com/jglim/PurpleVisualizer"; 81 | throw new Error("ugh!"); 82 | } 83 | 84 | pcb_image_urls["f.cu"] = cors_proxy + params["f.cu"]; 85 | pcb_image_urls["b.cu"] = cors_proxy + params["b.cu"]; 86 | pcb_image_urls["f.silk"] = cors_proxy + params["f.silk"]; 87 | pcb_image_urls["b.silk"] = cors_proxy + params["b.silk"]; 88 | pcb_image_urls["f.mask"] = cors_proxy + params["f.mask"]; 89 | pcb_image_urls["b.mask"] = cors_proxy + params["b.mask"]; 90 | pcb_image_urls["drl"] = cors_proxy + params["drl"]; 91 | pcb_image_urls["edge"] = cors_proxy + params["edge"]; 92 | } 93 | 94 | function getQueryParams(qs) { 95 | qs = document.location.search.split('+').join(' '); 96 | 97 | var params = {}, 98 | tokens, 99 | re = /[?&]?([^=]+)=([^&]*)/g; 100 | 101 | while (tokens = re.exec(qs)) { 102 | params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]); 103 | } 104 | 105 | return params; 106 | } 107 | 108 | 109 | function createKeyedImages() 110 | { 111 | isolate("f.cu", cu_color, true, false, 1); 112 | isolate("b.cu", cu_color, true, false, -1); 113 | isolate("f.silk", silk_color, true, false, 3); 114 | isolate("b.silk", silk_color, true, false, -3); 115 | isolate("f.mask", key_color, false, false, 2); 116 | isolate("b.mask", key_color, false, false, -2); 117 | isolate("drl", drl_color, false, false, 0); 118 | } 119 | 120 | // MDN: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas 121 | 122 | function isolate(output_id, new_color, invert_color, is_bump_map, z_index) 123 | { 124 | var hidden_canvas = document.createElement('canvas'); 125 | var img = new Image(); 126 | 127 | const src = pcb_image_urls[output_id]; 128 | const options = { 129 | headers: { 130 | 'Origin': 'http://localhost' // browser SHOULD fix this automatically 131 | } 132 | }; 133 | 134 | fetch(src, options) 135 | .then(res => res.blob()) 136 | .then(blob => { 137 | 138 | //img.src = pcb_image_urls[output_id]; 139 | img.src = URL.createObjectURL(blob); 140 | img.onload = function() { 141 | hidden_canvas.width = img.width; 142 | hidden_canvas.height = img.height; 143 | 144 | draw(this, hidden_canvas, new_color, invert_color, is_bump_map, output_id, z_index); 145 | }; 146 | }); 147 | 148 | } 149 | 150 | function color_match(channel_in, channel_base, tolerance = 30) 151 | { 152 | if ((channel_in <= channel_base + tolerance) && (channel_in >= channel_base - tolerance)) 153 | { 154 | return true; 155 | } 156 | return false; 157 | } 158 | 159 | function draw(img, canvas, new_color, invert_color, is_bump_map, output_id, z_index) 160 | { 161 | var ctx = canvas.getContext('2d'); 162 | ctx.drawImage(img, 0, 0); 163 | 164 | // if edge, flood fill first 165 | if (output_id == "edge") 166 | { 167 | // boards are usually radiused 168 | flood_fill(canvas, 0, 0); 169 | flood_fill(canvas, canvas.width - 1, 0); 170 | flood_fill(canvas, 0, canvas.height - 1); 171 | flood_fill(canvas, canvas.width - 1, canvas.height - 1); 172 | } 173 | 174 | img.style.display = 'none'; 175 | var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); 176 | var data = imageData.data; 177 | 178 | for (var i = 0; i < data.length; i += 4) 179 | { 180 | if (color_match(data[i], key_color[0]) && color_match(data[i + 1], key_color[1]) && color_match(data[i + 2], key_color[2])) 181 | { 182 | if (invert_color) 183 | { 184 | data[i + 3] = 0; 185 | } 186 | else 187 | { 188 | if (output_id != "edge") 189 | { 190 | data[i + 3] = 255 & shared_alpha_channel[i + 3]; 191 | } 192 | } 193 | } 194 | else 195 | { 196 | if (invert_color) 197 | { 198 | if (output_id != "edge") 199 | { 200 | data[i + 3] = 255 & shared_alpha_channel[i + 3]; 201 | } 202 | } 203 | else 204 | { 205 | data[i + 3] = 0; 206 | } 207 | } 208 | data[i] = new_color[0]; 209 | data[i + 1] = new_color[1]; 210 | data[i + 2] = new_color[2]; 211 | if (is_bump_map) 212 | { 213 | data[i] = data[i + 3]; 214 | data[i + 1] = data[i + 3]; 215 | data[i + 2] = data[i + 3]; 216 | data[i + 3] = 255; 217 | } 218 | } 219 | ctx.putImageData(imageData, 0, 0); 220 | 221 | // if we're working on alpha channel, store it (uint8clampedarray) for remaining ops 222 | if (output_id == "edge") 223 | { 224 | shared_alpha_channel = imageData.data; 225 | createKeyedImages(); 226 | return; 227 | } 228 | 229 | var new_image_url = canvas.toDataURL(); 230 | var new_img = document.createElement('img'); 231 | new_img.src = new_image_url; 232 | new_img.style = "display: none;"; 233 | if (is_bump_map) 234 | { 235 | new_img.id = "bump_" + output_id; 236 | new_img.onload = function() { 237 | mesh[output_id].material.alphaMap = THREE.ImageUtils.loadTexture( new_img.src ); 238 | }; 239 | } 240 | else 241 | { 242 | new_img.id = output_id; 243 | new_img.onload = function() { 244 | var temp_material = new THREE.MeshBasicMaterial(); 245 | temp_material.side = THREE.DoubleSide; 246 | temp_material.transparent = true; 247 | temp_material.opacity = default_opacity; 248 | temp_material.map = THREE.ImageUtils.loadTexture( new_img.src ); 249 | 250 | mesh[output_id] = new THREE.Mesh( new THREE.PlaneGeometry( canvas.width, canvas.height) , temp_material ); 251 | mesh[output_id].z_index = z_index; 252 | mesh[output_id].position.set(0, canvas.height / 2, default_z_spacing * mesh[output_id].z_index); 253 | scene.add( mesh[output_id] ); 254 | 255 | 256 | isolate(output_id, img.src, new_color, invert_color, true, z_index); 257 | }; 258 | } 259 | 260 | document.body.appendChild( new_img ); 261 | } 262 | 263 | // three.js 264 | 265 | function three_init() { 266 | camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 2000 ); 267 | camera.position.set( 0, 200, 800 ); 268 | 269 | scene = new THREE.Scene(); 270 | 271 | scene.background = new THREE.Color().setHSL( 0.6, 0, 0.95 ); 272 | scene.fog = new THREE.Fog( scene.background, 1, 5000 ); 273 | 274 | // ground 275 | /* 276 | var gnd_mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2000, 2000 ), new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } ) ); 277 | gnd_mesh.rotation.x = - Math.PI / 2; 278 | gnd_mesh.receiveShadow = true; 279 | scene.add( gnd_mesh ); 280 | */ 281 | var grid = new THREE.GridHelper( 2000, 20, 0x000000, 0x000000 ); 282 | grid.material.opacity = 0.2; 283 | grid.material.transparent = true; 284 | scene.add( grid ); 285 | 286 | 287 | light = new THREE.DirectionalLight( 0xffffff ); 288 | light.position.set( 0, 200, 100 ); 289 | light.castShadow = true; 290 | light.shadow.camera.top = 180; 291 | light.shadow.camera.bottom = -100; 292 | light.shadow.camera.left = -120; 293 | light.shadow.camera.right = 120; 294 | scene.add( light ); 295 | 296 | hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 ); 297 | hemiLight.color.setHSL( 0.6, 1, 0.6 ); 298 | hemiLight.groundColor.setHSL( 0.095, 1, 0.75 ); 299 | hemiLight.position.set( 0, 50, 0 ); 300 | scene.add( hemiLight ); 301 | 302 | 303 | controls = new THREE.OrbitControls( camera ); 304 | controls.target.set( 0, 100, 0 ); 305 | controls.autoRotate = true; 306 | //controls.enableDamping = true; 307 | //controls.autoRotateSpeed = 1.0; 308 | controls.update(); 309 | 310 | 311 | renderer = new THREE.WebGLRenderer( { antialias: true } ); 312 | renderer.setPixelRatio( window.devicePixelRatio ); 313 | renderer.setSize( window.innerWidth, window.innerHeight); 314 | document.body.appendChild( renderer.domElement ); 315 | window.addEventListener( 'resize', onWindowResize, false ); 316 | } 317 | 318 | function onWindowResize() { 319 | camera.aspect = window.innerWidth / window.innerHeight; 320 | camera.updateProjectionMatrix(); 321 | renderer.setSize( window.innerWidth, window.innerHeight ); 322 | } 323 | 324 | function animate() { 325 | requestAnimationFrame( animate ); 326 | controls.update(); 327 | renderer.render( scene, camera ); 328 | } 329 | 330 | // board edge: floodfill 331 | 332 | function flood_fill(the_canvas, x, y) { 333 | /* 334 | var x = 1; 335 | var y = 1; 336 | */ 337 | var color = {r:key_color[0], 338 | g:key_color[1], 339 | b:key_color[2], 340 | a:255}; 341 | 342 | 343 | var the_canvas_context = the_canvas.getContext( "2d" ) 344 | pixel_stack = [{x:x, y:y}] ; 345 | pixels = the_canvas_context.getImageData( 0, 0, the_canvas.width, the_canvas.height ) ; 346 | var linear_cords = ( y * the_canvas.width + x ) * 4 ; 347 | original_color = {r:pixels.data[linear_cords], 348 | g:pixels.data[linear_cords+1], 349 | b:pixels.data[linear_cords+2], 350 | a:pixels.data[linear_cords+3]} ; 351 | 352 | while( pixel_stack.length>0 ) { 353 | new_pixel = pixel_stack.shift() ; 354 | x = new_pixel.x ; 355 | y = new_pixel.y ; 356 | 357 | //console.log( x + ", " + y ) ; 358 | 359 | linear_cords = ( y * the_canvas.width + x ) * 4 ; 360 | while( y-->=0 && 361 | (pixels.data[linear_cords]==original_color.r && 362 | pixels.data[linear_cords+1]==original_color.g && 363 | pixels.data[linear_cords+2]==original_color.b && 364 | pixels.data[linear_cords+3]==original_color.a) ) { 365 | linear_cords -= the_canvas.width * 4 ; 366 | } 367 | linear_cords += the_canvas.width * 4 ; 368 | y++ ; 369 | 370 | var reached_left = false ; 371 | var reached_right = false ; 372 | while( y++0 ) { 382 | if( pixels.data[linear_cords-4]==original_color.r && 383 | pixels.data[linear_cords-4+1]==original_color.g && 384 | pixels.data[linear_cords-4+2]==original_color.b ) { 385 | if( !reached_left ) { 386 | pixel_stack.push( {x:x-1, y:y} ) ; 387 | reached_left = true ; 388 | } 389 | } else if( reached_left ) { 390 | reached_left = false ; 391 | } 392 | } 393 | 394 | if( x'); 464 | } 465 | } 466 | 467 | // bookmarklet edition 468 | // CWlmKGxvY2F0aW9uLmhvc3RuYW1lICE9ICJvc2hwYXJrLmNvbSIpCgl7CgkJYWxlcnQoIlRoaXMgb25seSBydW5zIG9uIG9zaHBhcmsuY29tIik7Cgl9CgllbHNlIAoJewoKCQljb25zb2xlLmxvZygib3NocGFya19sb2FkIGhlbGxvISIpOwoKCQl2YXIgbWFwcGluZ3MgPSBbCgkJCQkJWyJEcmlsbHMiLCAiZHJsIl0sCgkJCQkJWyJUb3AgU2lsayBTY3JlZW4iLCAiZi5zaWxrIl0sCgkJCQkJWyJCb2FyZCBPdXRsaW5lIiwgImVkZ2UiXSwKCQkJCQlbIkJvdHRvbSBTaWxrIFNjcmVlbiIsICJiLnNpbGsiXSwKCQkJCQlbIlRvcCBMYXllciIsICJmLmN1Il0sCgkJCQkJWyJCb3R0b20gTGF5ZXIiLCAiYi5jdSJdLAoJCQkJCVsiVG9wIFNvbGRlciBNYXNrIiwgImYubWFzayJdLAoJCQkJCVsiQm90dG9tIFNvbGRlciBNYXNrIiwgImIubWFzayJdCgkJCQldOwoJCXZhciBqZ19yZW1hcmtzID0gImFueSBodHRwcy1lbmFibGVkIHBhZ2UgaXMgb2theSwgcmV1c2luZyBvbmUgb2YgbXkgb2xkIHBhZ2VzIjsKCQl2YXIgZnVsbFVybCA9ICJodHRwczovL2VjZy5zbi5zZy9wdXJwbGUvPyI7CgoJCWZvciAodmFyIGkgPSAwOyBpIDwgbWFwcGluZ3MubGVuZ3RoOyBpKyspCgkJewoJCQl2YXIgZWwgPSBqUXVlcnkoICJpbWdbdGl0bGU9JyIgKyBtYXBwaW5nc1tpXVswXSArICInXSIgKVswXTsKCQkJaWYgKGVsID09PSB1bmRlZmluZWQpCgkJCXsKCQkJCWFsZXJ0KCJBYm9ydGluZyBkdWUgdG8gbWlzc2luZyBsYXllcjogIiArIG1hcHBpbmdzW2ldWzBdKTsKCQkJCXRocm93IG5ldyBFcnJvcigidWdoISIpOwoJCQl9CgkJCWVsc2UgCgkJCXsKCQkJCWZ1bGxVcmwgKz0gbWFwcGluZ3NbaV1bMV0gKyAiPSIgKyBlbmNvZGVVUklDb21wb25lbnQoZWwuc3JjKSArICImIjsKCQkJfQoJCX0KCQkkKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJoZWFkZXIiKSkuYXBwZW5kKCc8aWZyYW1lIGlkPSJqZ19mcmFtZSIgc3JjPSInICsgZnVsbFVybCArICciIGNsYXNzPSIiIHN0eWxlPSJib3JkZXI6IDA7IHdpZHRoOiAxMDAlOyBtaW4td2lkdGg6NTAwcHg7IG1pbi1oZWlnaHQ6NTAwcHg7IGJhY2tncm91bmQtY29sb3I6ICNlZWU7IGJvcmRlci1yYWRpdXM6IDE1cHg7IG1hcmdpbi10b3A6IDQwcHg7IG1hcmdpbi1ib3R0b206IDYwcHg7Ij48L2lmcmFtZT4nKTsKCX0= 469 | // javascript:eval(atob('')); 470 | // Purple Visualizer 471 | -------------------------------------------------------------------------------- /js/vendor/OrbitControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author qiao / https://github.com/qiao 3 | * @author mrdoob / http://mrdoob.com 4 | * @author alteredq / http://alteredqualia.com/ 5 | * @author WestLangley / http://github.com/WestLangley 6 | * @author erich666 / http://erichaines.com 7 | */ 8 | 9 | // This set of controls performs orbiting, dollying (zooming), and panning. 10 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). 11 | // 12 | // Orbit - left mouse / touch: one-finger move 13 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish 14 | // Pan - right mouse, or left mouse + ctrl/metaKey, or arrow keys / touch: two-finger move 15 | 16 | THREE.OrbitControls = function ( object, domElement ) { 17 | 18 | this.object = object; 19 | 20 | this.domElement = ( domElement !== undefined ) ? domElement : document; 21 | 22 | // Set to false to disable this control 23 | this.enabled = true; 24 | 25 | // "target" sets the location of focus, where the object orbits around 26 | this.target = new THREE.Vector3(); 27 | 28 | // How far you can dolly in and out ( PerspectiveCamera only ) 29 | this.minDistance = 0; 30 | this.maxDistance = Infinity; 31 | 32 | // How far you can zoom in and out ( OrthographicCamera only ) 33 | this.minZoom = 0; 34 | this.maxZoom = Infinity; 35 | 36 | // How far you can orbit vertically, upper and lower limits. 37 | // Range is 0 to Math.PI radians. 38 | this.minPolarAngle = 0; // radians 39 | this.maxPolarAngle = Math.PI; // radians 40 | 41 | // How far you can orbit horizontally, upper and lower limits. 42 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. 43 | this.minAzimuthAngle = - Infinity; // radians 44 | this.maxAzimuthAngle = Infinity; // radians 45 | 46 | // Set to true to enable damping (inertia) 47 | // If damping is enabled, you must call controls.update() in your animation loop 48 | this.enableDamping = false; 49 | this.dampingFactor = 0.25; 50 | 51 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. 52 | // Set to false to disable zooming 53 | this.enableZoom = true; 54 | this.zoomSpeed = 1.0; 55 | 56 | // Set to false to disable rotating 57 | this.enableRotate = true; 58 | this.rotateSpeed = 1.0; 59 | 60 | // Set to false to disable panning 61 | this.enablePan = true; 62 | this.panSpeed = 1.0; 63 | this.screenSpacePanning = false; // if true, pan in screen-space 64 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push 65 | 66 | // Set to true to automatically rotate around the target 67 | // If auto-rotate is enabled, you must call controls.update() in your animation loop 68 | this.autoRotate = false; 69 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 70 | 71 | // Set to false to disable use of the keys 72 | this.enableKeys = true; 73 | 74 | // The four arrow keys 75 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; 76 | 77 | // Mouse buttons 78 | this.mouseButtons = { LEFT: THREE.MOUSE.LEFT, MIDDLE: THREE.MOUSE.MIDDLE, RIGHT: THREE.MOUSE.RIGHT }; 79 | 80 | // for reset 81 | this.target0 = this.target.clone(); 82 | this.position0 = this.object.position.clone(); 83 | this.zoom0 = this.object.zoom; 84 | 85 | // 86 | // public methods 87 | // 88 | 89 | this.getPolarAngle = function () { 90 | 91 | return spherical.phi; 92 | 93 | }; 94 | 95 | this.getAzimuthalAngle = function () { 96 | 97 | return spherical.theta; 98 | 99 | }; 100 | 101 | this.saveState = function () { 102 | 103 | scope.target0.copy( scope.target ); 104 | scope.position0.copy( scope.object.position ); 105 | scope.zoom0 = scope.object.zoom; 106 | 107 | }; 108 | 109 | this.reset = function () { 110 | 111 | scope.target.copy( scope.target0 ); 112 | scope.object.position.copy( scope.position0 ); 113 | scope.object.zoom = scope.zoom0; 114 | 115 | scope.object.updateProjectionMatrix(); 116 | scope.dispatchEvent( changeEvent ); 117 | 118 | scope.update(); 119 | 120 | state = STATE.NONE; 121 | 122 | }; 123 | 124 | // this method is exposed, but perhaps it would be better if we can make it private... 125 | this.update = function () { 126 | 127 | var offset = new THREE.Vector3(); 128 | 129 | // so camera.up is the orbit axis 130 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); 131 | var quatInverse = quat.clone().inverse(); 132 | 133 | var lastPosition = new THREE.Vector3(); 134 | var lastQuaternion = new THREE.Quaternion(); 135 | 136 | return function update() { 137 | 138 | var position = scope.object.position; 139 | 140 | offset.copy( position ).sub( scope.target ); 141 | 142 | // rotate offset to "y-axis-is-up" space 143 | offset.applyQuaternion( quat ); 144 | 145 | // angle from z-axis around y-axis 146 | spherical.setFromVector3( offset ); 147 | 148 | if ( scope.autoRotate && state === STATE.NONE ) { 149 | 150 | rotateLeft( getAutoRotationAngle() ); 151 | 152 | } 153 | 154 | spherical.theta += sphericalDelta.theta; 155 | spherical.phi += sphericalDelta.phi; 156 | 157 | // restrict theta to be between desired limits 158 | spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) ); 159 | 160 | // restrict phi to be between desired limits 161 | spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); 162 | 163 | spherical.makeSafe(); 164 | 165 | 166 | spherical.radius *= scale; 167 | 168 | // restrict radius to be between desired limits 169 | spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); 170 | 171 | // move target to panned location 172 | scope.target.add( panOffset ); 173 | 174 | offset.setFromSpherical( spherical ); 175 | 176 | // rotate offset back to "camera-up-vector-is-up" space 177 | offset.applyQuaternion( quatInverse ); 178 | 179 | position.copy( scope.target ).add( offset ); 180 | 181 | scope.object.lookAt( scope.target ); 182 | 183 | if ( scope.enableDamping === true ) { 184 | 185 | sphericalDelta.theta *= ( 1 - scope.dampingFactor ); 186 | sphericalDelta.phi *= ( 1 - scope.dampingFactor ); 187 | 188 | panOffset.multiplyScalar( 1 - scope.dampingFactor ); 189 | 190 | } else { 191 | 192 | sphericalDelta.set( 0, 0, 0 ); 193 | 194 | panOffset.set( 0, 0, 0 ); 195 | 196 | } 197 | 198 | scale = 1; 199 | 200 | // update condition is: 201 | // min(camera displacement, camera rotation in radians)^2 > EPS 202 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8 203 | 204 | if ( zoomChanged || 205 | lastPosition.distanceToSquared( scope.object.position ) > EPS || 206 | 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { 207 | 208 | scope.dispatchEvent( changeEvent ); 209 | 210 | lastPosition.copy( scope.object.position ); 211 | lastQuaternion.copy( scope.object.quaternion ); 212 | zoomChanged = false; 213 | 214 | return true; 215 | 216 | } 217 | 218 | return false; 219 | 220 | }; 221 | 222 | }(); 223 | 224 | this.dispose = function () { 225 | 226 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false ); 227 | scope.domElement.removeEventListener( 'mousedown', onMouseDown, false ); 228 | scope.domElement.removeEventListener( 'wheel', onMouseWheel, false ); 229 | 230 | scope.domElement.removeEventListener( 'touchstart', onTouchStart, false ); 231 | scope.domElement.removeEventListener( 'touchend', onTouchEnd, false ); 232 | scope.domElement.removeEventListener( 'touchmove', onTouchMove, false ); 233 | 234 | document.removeEventListener( 'mousemove', onMouseMove, false ); 235 | document.removeEventListener( 'mouseup', onMouseUp, false ); 236 | 237 | window.removeEventListener( 'keydown', onKeyDown, false ); 238 | 239 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? 240 | 241 | }; 242 | 243 | // 244 | // internals 245 | // 246 | 247 | var scope = this; 248 | 249 | var changeEvent = { type: 'change' }; 250 | var startEvent = { type: 'start' }; 251 | var endEvent = { type: 'end' }; 252 | 253 | var STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY_PAN: 4 }; 254 | 255 | var state = STATE.NONE; 256 | 257 | var EPS = 0.000001; 258 | 259 | // current position in spherical coordinates 260 | var spherical = new THREE.Spherical(); 261 | var sphericalDelta = new THREE.Spherical(); 262 | 263 | var scale = 1; 264 | var panOffset = new THREE.Vector3(); 265 | var zoomChanged = false; 266 | 267 | var rotateStart = new THREE.Vector2(); 268 | var rotateEnd = new THREE.Vector2(); 269 | var rotateDelta = new THREE.Vector2(); 270 | 271 | var panStart = new THREE.Vector2(); 272 | var panEnd = new THREE.Vector2(); 273 | var panDelta = new THREE.Vector2(); 274 | 275 | var dollyStart = new THREE.Vector2(); 276 | var dollyEnd = new THREE.Vector2(); 277 | var dollyDelta = new THREE.Vector2(); 278 | 279 | function getAutoRotationAngle() { 280 | 281 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; 282 | 283 | } 284 | 285 | function getZoomScale() { 286 | 287 | return Math.pow( 0.95, scope.zoomSpeed ); 288 | 289 | } 290 | 291 | function rotateLeft( angle ) { 292 | 293 | sphericalDelta.theta -= angle; 294 | 295 | } 296 | 297 | function rotateUp( angle ) { 298 | 299 | sphericalDelta.phi -= angle; 300 | 301 | } 302 | 303 | var panLeft = function () { 304 | 305 | var v = new THREE.Vector3(); 306 | 307 | return function panLeft( distance, objectMatrix ) { 308 | 309 | v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix 310 | v.multiplyScalar( - distance ); 311 | 312 | panOffset.add( v ); 313 | 314 | }; 315 | 316 | }(); 317 | 318 | var panUp = function () { 319 | 320 | var v = new THREE.Vector3(); 321 | 322 | return function panUp( distance, objectMatrix ) { 323 | 324 | if ( scope.screenSpacePanning === true ) { 325 | 326 | v.setFromMatrixColumn( objectMatrix, 1 ); 327 | 328 | } else { 329 | 330 | v.setFromMatrixColumn( objectMatrix, 0 ); 331 | v.crossVectors( scope.object.up, v ); 332 | 333 | } 334 | 335 | v.multiplyScalar( distance ); 336 | 337 | panOffset.add( v ); 338 | 339 | }; 340 | 341 | }(); 342 | 343 | // deltaX and deltaY are in pixels; right and down are positive 344 | var pan = function () { 345 | 346 | var offset = new THREE.Vector3(); 347 | 348 | return function pan( deltaX, deltaY ) { 349 | 350 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 351 | 352 | if ( scope.object.isPerspectiveCamera ) { 353 | 354 | // perspective 355 | var position = scope.object.position; 356 | offset.copy( position ).sub( scope.target ); 357 | var targetDistance = offset.length(); 358 | 359 | // half of the fov is center to top of screen 360 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); 361 | 362 | // we use only clientHeight here so aspect ratio does not distort speed 363 | panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); 364 | panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); 365 | 366 | } else if ( scope.object.isOrthographicCamera ) { 367 | 368 | // orthographic 369 | panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); 370 | panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); 371 | 372 | } else { 373 | 374 | // camera neither orthographic nor perspective 375 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); 376 | scope.enablePan = false; 377 | 378 | } 379 | 380 | }; 381 | 382 | }(); 383 | 384 | function dollyIn( dollyScale ) { 385 | 386 | if ( scope.object.isPerspectiveCamera ) { 387 | 388 | scale /= dollyScale; 389 | 390 | } else if ( scope.object.isOrthographicCamera ) { 391 | 392 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); 393 | scope.object.updateProjectionMatrix(); 394 | zoomChanged = true; 395 | 396 | } else { 397 | 398 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 399 | scope.enableZoom = false; 400 | 401 | } 402 | 403 | } 404 | 405 | function dollyOut( dollyScale ) { 406 | 407 | if ( scope.object.isPerspectiveCamera ) { 408 | 409 | scale *= dollyScale; 410 | 411 | } else if ( scope.object.isOrthographicCamera ) { 412 | 413 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); 414 | scope.object.updateProjectionMatrix(); 415 | zoomChanged = true; 416 | 417 | } else { 418 | 419 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 420 | scope.enableZoom = false; 421 | 422 | } 423 | 424 | } 425 | 426 | // 427 | // event callbacks - update the object state 428 | // 429 | 430 | function handleMouseDownRotate( event ) { 431 | 432 | //console.log( 'handleMouseDownRotate' ); 433 | 434 | rotateStart.set( event.clientX, event.clientY ); 435 | 436 | } 437 | 438 | function handleMouseDownDolly( event ) { 439 | 440 | //console.log( 'handleMouseDownDolly' ); 441 | 442 | dollyStart.set( event.clientX, event.clientY ); 443 | 444 | } 445 | 446 | function handleMouseDownPan( event ) { 447 | 448 | //console.log( 'handleMouseDownPan' ); 449 | 450 | panStart.set( event.clientX, event.clientY ); 451 | 452 | } 453 | 454 | function handleMouseMoveRotate( event ) { 455 | 456 | //console.log( 'handleMouseMoveRotate' ); 457 | 458 | rotateEnd.set( event.clientX, event.clientY ); 459 | 460 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed ); 461 | 462 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 463 | 464 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height 465 | 466 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight ); 467 | 468 | rotateStart.copy( rotateEnd ); 469 | 470 | scope.update(); 471 | 472 | } 473 | 474 | function handleMouseMoveDolly( event ) { 475 | 476 | //console.log( 'handleMouseMoveDolly' ); 477 | 478 | dollyEnd.set( event.clientX, event.clientY ); 479 | 480 | dollyDelta.subVectors( dollyEnd, dollyStart ); 481 | 482 | if ( dollyDelta.y > 0 ) { 483 | 484 | dollyIn( getZoomScale() ); 485 | 486 | } else if ( dollyDelta.y < 0 ) { 487 | 488 | dollyOut( getZoomScale() ); 489 | 490 | } 491 | 492 | dollyStart.copy( dollyEnd ); 493 | 494 | scope.update(); 495 | 496 | } 497 | 498 | function handleMouseMovePan( event ) { 499 | 500 | //console.log( 'handleMouseMovePan' ); 501 | 502 | panEnd.set( event.clientX, event.clientY ); 503 | 504 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed ); 505 | 506 | pan( panDelta.x, panDelta.y ); 507 | 508 | panStart.copy( panEnd ); 509 | 510 | scope.update(); 511 | 512 | } 513 | 514 | function handleMouseUp( event ) { 515 | 516 | // console.log( 'handleMouseUp' ); 517 | 518 | } 519 | 520 | function handleMouseWheel( event ) { 521 | 522 | // console.log( 'handleMouseWheel' ); 523 | 524 | if ( event.deltaY < 0 ) { 525 | 526 | dollyOut( getZoomScale() ); 527 | 528 | } else if ( event.deltaY > 0 ) { 529 | 530 | dollyIn( getZoomScale() ); 531 | 532 | } 533 | 534 | scope.update(); 535 | 536 | } 537 | 538 | function handleKeyDown( event ) { 539 | 540 | //console.log( 'handleKeyDown' ); 541 | 542 | switch ( event.keyCode ) { 543 | 544 | case scope.keys.UP: 545 | pan( 0, scope.keyPanSpeed ); 546 | scope.update(); 547 | break; 548 | 549 | case scope.keys.BOTTOM: 550 | pan( 0, - scope.keyPanSpeed ); 551 | scope.update(); 552 | break; 553 | 554 | case scope.keys.LEFT: 555 | pan( scope.keyPanSpeed, 0 ); 556 | scope.update(); 557 | break; 558 | 559 | case scope.keys.RIGHT: 560 | pan( - scope.keyPanSpeed, 0 ); 561 | scope.update(); 562 | break; 563 | 564 | } 565 | 566 | } 567 | 568 | function handleTouchStartRotate( event ) { 569 | 570 | //console.log( 'handleTouchStartRotate' ); 571 | 572 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 573 | 574 | } 575 | 576 | function handleTouchStartDollyPan( event ) { 577 | 578 | //console.log( 'handleTouchStartDollyPan' ); 579 | 580 | if ( scope.enableZoom ) { 581 | 582 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 583 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 584 | 585 | var distance = Math.sqrt( dx * dx + dy * dy ); 586 | 587 | dollyStart.set( 0, distance ); 588 | 589 | } 590 | 591 | if ( scope.enablePan ) { 592 | 593 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ); 594 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ); 595 | 596 | panStart.set( x, y ); 597 | 598 | } 599 | 600 | } 601 | 602 | function handleTouchMoveRotate( event ) { 603 | 604 | //console.log( 'handleTouchMoveRotate' ); 605 | 606 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 607 | 608 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed ); 609 | 610 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 611 | 612 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height 613 | 614 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight ); 615 | 616 | rotateStart.copy( rotateEnd ); 617 | 618 | scope.update(); 619 | 620 | } 621 | 622 | function handleTouchMoveDollyPan( event ) { 623 | 624 | //console.log( 'handleTouchMoveDollyPan' ); 625 | 626 | if ( scope.enableZoom ) { 627 | 628 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 629 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 630 | 631 | var distance = Math.sqrt( dx * dx + dy * dy ); 632 | 633 | dollyEnd.set( 0, distance ); 634 | 635 | dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) ); 636 | 637 | dollyIn( dollyDelta.y ); 638 | 639 | dollyStart.copy( dollyEnd ); 640 | 641 | } 642 | 643 | if ( scope.enablePan ) { 644 | 645 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ); 646 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ); 647 | 648 | panEnd.set( x, y ); 649 | 650 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed ); 651 | 652 | pan( panDelta.x, panDelta.y ); 653 | 654 | panStart.copy( panEnd ); 655 | 656 | } 657 | 658 | scope.update(); 659 | 660 | } 661 | 662 | function handleTouchEnd( event ) { 663 | 664 | //console.log( 'handleTouchEnd' ); 665 | 666 | } 667 | 668 | // 669 | // event handlers - FSM: listen for events and reset state 670 | // 671 | 672 | function onMouseDown( event ) { 673 | 674 | if ( scope.enabled === false ) return; 675 | 676 | event.preventDefault(); 677 | 678 | switch ( event.button ) { 679 | 680 | case scope.mouseButtons.LEFT: 681 | 682 | if ( event.ctrlKey || event.metaKey ) { 683 | 684 | if ( scope.enablePan === false ) return; 685 | 686 | handleMouseDownPan( event ); 687 | 688 | state = STATE.PAN; 689 | 690 | } else { 691 | 692 | if ( scope.enableRotate === false ) return; 693 | 694 | handleMouseDownRotate( event ); 695 | 696 | state = STATE.ROTATE; 697 | 698 | } 699 | 700 | break; 701 | 702 | case scope.mouseButtons.MIDDLE: 703 | 704 | if ( scope.enableZoom === false ) return; 705 | 706 | handleMouseDownDolly( event ); 707 | 708 | state = STATE.DOLLY; 709 | 710 | break; 711 | 712 | case scope.mouseButtons.RIGHT: 713 | 714 | if ( scope.enablePan === false ) return; 715 | 716 | handleMouseDownPan( event ); 717 | 718 | state = STATE.PAN; 719 | 720 | break; 721 | 722 | } 723 | 724 | if ( state !== STATE.NONE ) { 725 | 726 | document.addEventListener( 'mousemove', onMouseMove, false ); 727 | document.addEventListener( 'mouseup', onMouseUp, false ); 728 | 729 | scope.dispatchEvent( startEvent ); 730 | 731 | } 732 | 733 | } 734 | 735 | function onMouseMove( event ) { 736 | 737 | if ( scope.enabled === false ) return; 738 | 739 | event.preventDefault(); 740 | 741 | switch ( state ) { 742 | 743 | case STATE.ROTATE: 744 | 745 | if ( scope.enableRotate === false ) return; 746 | 747 | handleMouseMoveRotate( event ); 748 | 749 | break; 750 | 751 | case STATE.DOLLY: 752 | 753 | if ( scope.enableZoom === false ) return; 754 | 755 | handleMouseMoveDolly( event ); 756 | 757 | break; 758 | 759 | case STATE.PAN: 760 | 761 | if ( scope.enablePan === false ) return; 762 | 763 | handleMouseMovePan( event ); 764 | 765 | break; 766 | 767 | } 768 | 769 | } 770 | 771 | function onMouseUp( event ) { 772 | 773 | if ( scope.enabled === false ) return; 774 | 775 | handleMouseUp( event ); 776 | 777 | document.removeEventListener( 'mousemove', onMouseMove, false ); 778 | document.removeEventListener( 'mouseup', onMouseUp, false ); 779 | 780 | scope.dispatchEvent( endEvent ); 781 | 782 | state = STATE.NONE; 783 | 784 | } 785 | 786 | function onMouseWheel( event ) { 787 | 788 | if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return; 789 | 790 | event.preventDefault(); 791 | event.stopPropagation(); 792 | 793 | scope.dispatchEvent( startEvent ); 794 | 795 | handleMouseWheel( event ); 796 | 797 | scope.dispatchEvent( endEvent ); 798 | 799 | } 800 | 801 | function onKeyDown( event ) { 802 | 803 | if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return; 804 | 805 | handleKeyDown( event ); 806 | 807 | } 808 | 809 | function onTouchStart( event ) { 810 | 811 | if ( scope.enabled === false ) return; 812 | 813 | event.preventDefault(); 814 | 815 | switch ( event.touches.length ) { 816 | 817 | case 1: // one-fingered touch: rotate 818 | 819 | if ( scope.enableRotate === false ) return; 820 | 821 | handleTouchStartRotate( event ); 822 | 823 | state = STATE.TOUCH_ROTATE; 824 | 825 | break; 826 | 827 | case 2: // two-fingered touch: dolly-pan 828 | 829 | if ( scope.enableZoom === false && scope.enablePan === false ) return; 830 | 831 | handleTouchStartDollyPan( event ); 832 | 833 | state = STATE.TOUCH_DOLLY_PAN; 834 | 835 | break; 836 | 837 | default: 838 | 839 | state = STATE.NONE; 840 | 841 | } 842 | 843 | if ( state !== STATE.NONE ) { 844 | 845 | scope.dispatchEvent( startEvent ); 846 | 847 | } 848 | 849 | } 850 | 851 | function onTouchMove( event ) { 852 | 853 | if ( scope.enabled === false ) return; 854 | 855 | event.preventDefault(); 856 | event.stopPropagation(); 857 | 858 | switch ( event.touches.length ) { 859 | 860 | case 1: // one-fingered touch: rotate 861 | 862 | if ( scope.enableRotate === false ) return; 863 | if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed? 864 | 865 | handleTouchMoveRotate( event ); 866 | 867 | break; 868 | 869 | case 2: // two-fingered touch: dolly-pan 870 | 871 | if ( scope.enableZoom === false && scope.enablePan === false ) return; 872 | if ( state !== STATE.TOUCH_DOLLY_PAN ) return; // is this needed? 873 | 874 | handleTouchMoveDollyPan( event ); 875 | 876 | break; 877 | 878 | default: 879 | 880 | state = STATE.NONE; 881 | 882 | } 883 | 884 | } 885 | 886 | function onTouchEnd( event ) { 887 | 888 | if ( scope.enabled === false ) return; 889 | 890 | handleTouchEnd( event ); 891 | 892 | scope.dispatchEvent( endEvent ); 893 | 894 | state = STATE.NONE; 895 | 896 | } 897 | 898 | function onContextMenu( event ) { 899 | 900 | if ( scope.enabled === false ) return; 901 | 902 | event.preventDefault(); 903 | 904 | } 905 | 906 | // 907 | 908 | scope.domElement.addEventListener( 'contextmenu', onContextMenu, false ); 909 | 910 | scope.domElement.addEventListener( 'mousedown', onMouseDown, false ); 911 | scope.domElement.addEventListener( 'wheel', onMouseWheel, false ); 912 | 913 | scope.domElement.addEventListener( 'touchstart', onTouchStart, false ); 914 | scope.domElement.addEventListener( 'touchend', onTouchEnd, false ); 915 | scope.domElement.addEventListener( 'touchmove', onTouchMove, false ); 916 | 917 | window.addEventListener( 'keydown', onKeyDown, false ); 918 | 919 | // force an update at start 920 | 921 | this.update(); 922 | 923 | }; 924 | 925 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 926 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; 927 | 928 | Object.defineProperties( THREE.OrbitControls.prototype, { 929 | 930 | center: { 931 | 932 | get: function () { 933 | 934 | console.warn( 'THREE.OrbitControls: .center has been renamed to .target' ); 935 | return this.target; 936 | 937 | } 938 | 939 | }, 940 | 941 | // backward compatibility 942 | 943 | noZoom: { 944 | 945 | get: function () { 946 | 947 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); 948 | return ! this.enableZoom; 949 | 950 | }, 951 | 952 | set: function ( value ) { 953 | 954 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' ); 955 | this.enableZoom = ! value; 956 | 957 | } 958 | 959 | }, 960 | 961 | noRotate: { 962 | 963 | get: function () { 964 | 965 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); 966 | return ! this.enableRotate; 967 | 968 | }, 969 | 970 | set: function ( value ) { 971 | 972 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' ); 973 | this.enableRotate = ! value; 974 | 975 | } 976 | 977 | }, 978 | 979 | noPan: { 980 | 981 | get: function () { 982 | 983 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); 984 | return ! this.enablePan; 985 | 986 | }, 987 | 988 | set: function ( value ) { 989 | 990 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' ); 991 | this.enablePan = ! value; 992 | 993 | } 994 | 995 | }, 996 | 997 | noKeys: { 998 | 999 | get: function () { 1000 | 1001 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); 1002 | return ! this.enableKeys; 1003 | 1004 | }, 1005 | 1006 | set: function ( value ) { 1007 | 1008 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' ); 1009 | this.enableKeys = ! value; 1010 | 1011 | } 1012 | 1013 | }, 1014 | 1015 | staticMoving: { 1016 | 1017 | get: function () { 1018 | 1019 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); 1020 | return ! this.enableDamping; 1021 | 1022 | }, 1023 | 1024 | set: function ( value ) { 1025 | 1026 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' ); 1027 | this.enableDamping = ! value; 1028 | 1029 | } 1030 | 1031 | }, 1032 | 1033 | dynamicDampingFactor: { 1034 | 1035 | get: function () { 1036 | 1037 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); 1038 | return this.dampingFactor; 1039 | 1040 | }, 1041 | 1042 | set: function ( value ) { 1043 | 1044 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' ); 1045 | this.dampingFactor = value; 1046 | 1047 | } 1048 | 1049 | } 1050 | 1051 | } ); 1052 | -------------------------------------------------------------------------------- /js/vendor/dat.gui.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * dat-gui JavaScript Controller Library 3 | * https://github.com/dataarts/dat.gui 4 | * 5 | * Copyright 2016 Data Arts Team, Google Creative Lab 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | */ 13 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.dat=t():e.dat=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}var i=n(1),r=o(i);e.exports=r["default"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var i=n(2),r=o(i),a=n(6),l=o(a),s=n(3),u=o(s),d=n(7),c=o(d),f=n(8),_=o(f),p=n(10),h=o(p),m=n(11),b=o(m),g=n(12),v=o(g),y=n(13),w=o(y),x=n(14),E=o(x),C=n(15),A=o(C),S=n(16),k=o(S),O=n(9),T=o(O),R=n(17),L=o(R);t["default"]={color:{Color:r["default"],math:l["default"],interpret:u["default"]},controllers:{Controller:c["default"],BooleanController:_["default"],OptionController:h["default"],StringController:b["default"],NumberController:v["default"],NumberControllerBox:w["default"],NumberControllerSlider:E["default"],FunctionController:A["default"],ColorController:k["default"]},dom:{dom:T["default"]},gui:{GUI:L["default"]},GUI:L["default"]}},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t,n){Object.defineProperty(e,t,{get:function(){return"RGB"===this.__state.space?this.__state[t]:(h.recalculateRGB(this,t,n),this.__state[t])},set:function(e){"RGB"!==this.__state.space&&(h.recalculateRGB(this,t,n),this.__state.space="RGB"),this.__state[t]=e}})}function a(e,t){Object.defineProperty(e,t,{get:function(){return"HSV"===this.__state.space?this.__state[t]:(h.recalculateHSV(this),this.__state[t])},set:function(e){"HSV"!==this.__state.space&&(h.recalculateHSV(this),this.__state.space="HSV"),this.__state[t]=e}})}t.__esModule=!0;var l=n(3),s=o(l),u=n(6),d=o(u),c=n(4),f=o(c),_=n(5),p=o(_),h=function(){function e(){if(i(this,e),this.__state=s["default"].apply(this,arguments),this.__state===!1)throw new Error("Failed to interpret color arguments");this.__state.a=this.__state.a||1}return e.prototype.toString=function(){return(0,f["default"])(this)},e.prototype.toHexString=function(){return(0,f["default"])(this,!0)},e.prototype.toOriginal=function(){return this.__state.conversion.write(this)},e}();h.recalculateRGB=function(e,t,n){if("HEX"===e.__state.space)e.__state[t]=d["default"].component_from_hex(e.__state.hex,n);else{if("HSV"!==e.__state.space)throw new Error("Corrupted color state");p["default"].extend(e.__state,d["default"].hsv_to_rgb(e.__state.h,e.__state.s,e.__state.v))}},h.recalculateHSV=function(e){var t=d["default"].rgb_to_hsv(e.r,e.g,e.b);p["default"].extend(e.__state,{s:t.s,v:t.v}),p["default"].isNaN(t.h)?p["default"].isUndefined(e.__state.h)&&(e.__state.h=0):e.__state.h=t.h},h.COMPONENTS=["r","g","b","h","s","v","hex","a"],r(h.prototype,"r",2),r(h.prototype,"g",1),r(h.prototype,"b",0),a(h.prototype,"h"),a(h.prototype,"s"),a(h.prototype,"v"),Object.defineProperty(h.prototype,"a",{get:function(){return this.__state.a},set:function(e){this.__state.a=e}}),Object.defineProperty(h.prototype,"hex",{get:function(){return"HEX"!==!this.__state.space&&(this.__state.hex=d["default"].rgb_to_hex(this.r,this.g,this.b)),this.__state.hex},set:function(e){this.__state.space="HEX",this.__state.hex=e}}),t["default"]=h},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var i=n(4),r=o(i),a=n(5),l=o(a),s=[{litmus:l["default"].isString,conversions:{THREE_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString()+t[1].toString()+t[2].toString()+t[2].toString()+t[3].toString()+t[3].toString(),0)}},write:r["default"]},SIX_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9]{6})$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString(),0)}},write:r["default"]},CSS_RGB:{read:function(e){var t=e.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3])}},write:r["default"]},CSS_RGBA:{read:function(e){var t=e.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3]),a:parseFloat(t[4])}},write:r["default"]}}},{litmus:l["default"].isNumber,conversions:{HEX:{read:function(e){return{space:"HEX",hex:e,conversionName:"HEX"}},write:function(e){return e.hex}}}},{litmus:l["default"].isArray,conversions:{RGB_ARRAY:{read:function(e){return 3===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2]}},write:function(e){return[e.r,e.g,e.b]}},RGBA_ARRAY:{read:function(e){return 4===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2],a:e[3]}},write:function(e){return[e.r,e.g,e.b,e.a]}}}},{litmus:l["default"].isObject,conversions:{RGBA_OBJ:{read:function(e){return!!(l["default"].isNumber(e.r)&&l["default"].isNumber(e.g)&&l["default"].isNumber(e.b)&&l["default"].isNumber(e.a))&&{space:"RGB",r:e.r,g:e.g,b:e.b,a:e.a}},write:function(e){return{r:e.r,g:e.g,b:e.b,a:e.a}}},RGB_OBJ:{read:function(e){return!!(l["default"].isNumber(e.r)&&l["default"].isNumber(e.g)&&l["default"].isNumber(e.b))&&{space:"RGB",r:e.r,g:e.g,b:e.b}},write:function(e){return{r:e.r,g:e.g,b:e.b}}},HSVA_OBJ:{read:function(e){return!!(l["default"].isNumber(e.h)&&l["default"].isNumber(e.s)&&l["default"].isNumber(e.v)&&l["default"].isNumber(e.a))&&{space:"HSV",h:e.h,s:e.s,v:e.v,a:e.a}},write:function(e){return{h:e.h,s:e.s,v:e.v,a:e.a}}},HSV_OBJ:{read:function(e){return!!(l["default"].isNumber(e.h)&&l["default"].isNumber(e.s)&&l["default"].isNumber(e.v))&&{space:"HSV",h:e.h,s:e.s,v:e.v}},write:function(e){return{h:e.h,s:e.s,v:e.v}}}}}],u=void 0,d=void 0,c=function(){d=!1;var e=arguments.length>1?l["default"].toArray(arguments):arguments[0];return l["default"].each(s,function(t){if(t.litmus(e))return l["default"].each(t.conversions,function(t,n){if(u=t.read(e),d===!1&&u!==!1)return d=u,u.conversionName=n,u.conversion=t,l["default"].BREAK}),l["default"].BREAK}),d};t["default"]=c},function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e,t){var n=e.__state.conversionName.toString(),o=Math.round(e.r),i=Math.round(e.g),r=Math.round(e.b),a=e.a,l=Math.round(e.h),s=e.s.toFixed(1),u=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){for(var d=e.hex.toString(16);d.length<6;)d="0"+d;return"#"+d}return"CSS_RGB"===n?"rgb("+o+","+i+","+r+")":"CSS_RGBA"===n?"rgba("+o+","+i+","+r+","+a+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+o+","+i+","+r+"]":"RGBA_ARRAY"===n?"["+o+","+i+","+r+","+a+"]":"RGB_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+",a:"+a+"}":"HSV_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+"}":"HSVA_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+",a:"+a+"}":"unknown format"}},function(e,t){"use strict";t.__esModule=!0;var n=Array.prototype.forEach,o=Array.prototype.slice,i={BREAK:{},extend:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(t[n])||(e[n]=t[n])}.bind(this))},this),e},defaults:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(e[n])&&(e[n]=t[n])}.bind(this))},this),e},compose:function(){var e=o.call(arguments);return function(){for(var t=o.call(arguments),n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,o){if(e)if(n&&e.forEach&&e.forEach===n)e.forEach(t,o);else if(e.length===e.length+0){var i=void 0,r=void 0;for(i=0,r=e.length;i>8*t&255},hex_with_component:function(e,t,o){return o<<(n=8*t)|e&~(255<-1?t.length-t.indexOf(".")-1:0}t.__esModule=!0;var s=n(7),u=o(s),d=n(5),c=o(d),f=function(e){function t(n,o,a){i(this,t);var s=r(this,e.call(this,n,o)),u=a||{};return s.__min=u.min,s.__max=u.max,s.__step=u.step,c["default"].isUndefined(s.__step)?0===s.initialValue?s.__impliedStep=1:s.__impliedStep=Math.pow(10,Math.floor(Math.log(Math.abs(s.initialValue))/Math.LN10))/10:s.__impliedStep=s.__step,s.__precision=l(s.__impliedStep),s}return a(t,e),t.prototype.setValue=function(t){var n=t;return void 0!==this.__min&&nthis.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!==0&&(n=Math.round(n/this.__step)*this.__step),e.prototype.setValue.call(this,n)},t.prototype.min=function(e){return this.__min=e,this},t.prototype.max=function(e){return this.__max=e,this},t.prototype.step=function(e){return this.__step=e,this.__impliedStep=e,this.__precision=l(e),this},t}(u["default"]);t["default"]=f},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=n(5),_=o(f),p=function(e){function t(n,o,a){function l(){var e=parseFloat(m.__input.value);_["default"].isNaN(e)||m.setValue(e)}function s(){m.__onFinishChange&&m.__onFinishChange.call(m,m.getValue())}function u(){s()}function d(e){var t=b-e.clientY;m.setValue(m.getValue()+t*m.__impliedStep),b=e.clientY}function f(){c["default"].unbind(window,"mousemove",d),c["default"].unbind(window,"mouseup",f),s()}function p(e){c["default"].bind(window,"mousemove",d),c["default"].bind(window,"mouseup",f),b=e.clientY}i(this,t);var h=r(this,e.call(this,n,o,a));h.__truncationSuspended=!1;var m=h,b=void 0;return h.__input=document.createElement("input"),h.__input.setAttribute("type","text"),c["default"].bind(h.__input,"change",l),c["default"].bind(h.__input,"blur",u),c["default"].bind(h.__input,"mousedown",p),c["default"].bind(h.__input,"keydown",function(e){13===e.keyCode&&(m.__truncationSuspended=!0,this.blur(),m.__truncationSuspended=!1,s())}),h.updateDisplay(),h.domElement.appendChild(h.__input),h}return a(t,e),t.prototype.updateDisplay=function(){return this.__input.value=this.__truncationSuspended?this.getValue():l(this.getValue(),this.__precision),e.prototype.updateDisplay.call(this)},t}(u["default"]);t["default"]=p},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o,i){return o+(i-o)*((e-t)/(n-t))}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=function(e){function t(n,o,a,s,u){function d(e){document.activeElement.blur(),c["default"].bind(window,"mousemove",f),c["default"].bind(window,"mouseup",_),f(e)}function f(e){e.preventDefault();var t=h.__background.getBoundingClientRect();return h.setValue(l(e.clientX,t.left,t.right,h.__min,h.__max)),!1}function _(){c["default"].unbind(window,"mousemove",f),c["default"].unbind(window,"mouseup",_),h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())}i(this,t);var p=r(this,e.call(this,n,o,{min:a,max:s,step:u})),h=p;return p.__background=document.createElement("div"),p.__foreground=document.createElement("div"),c["default"].bind(p.__background,"mousedown",d),c["default"].addClass(p.__background,"slider"),c["default"].addClass(p.__foreground,"slider-fg"),p.updateDisplay(),p.__background.appendChild(p.__foreground),p.domElement.appendChild(p.__background),p}return a(t,e),t.prototype.updateDisplay=function(){var t=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*t+"%",e.prototype.updateDisplay.call(this)},t}(u["default"]);t["default"]=f},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var l=n(7),s=o(l),u=n(9),d=o(u),c=function(e){function t(n,o,a){i(this,t);var l=r(this,e.call(this,n,o)),s=l;return l.__button=document.createElement("div"),l.__button.innerHTML=void 0===a?"Fire":a,d["default"].bind(l.__button,"click",function(e){return e.preventDefault(),s.fire(),!1}),d["default"].addClass(l.__button,"button"),l.domElement.appendChild(l.__button),l}return a(t,e),t.prototype.fire=function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())},t}(s["default"]);t["default"]=c},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o){e.style.background="",g["default"].each(y,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function s(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}t.__esModule=!0;var u=n(7),d=o(u),c=n(9),f=o(c),_=n(2),p=o(_),h=n(3),m=o(h),b=n(5),g=o(b),v=function(e){function t(n,o){function a(e){h(e),f["default"].bind(window,"mousemove",h),f["default"].bind(window,"mouseup",u)}function u(){f["default"].unbind(window,"mousemove",h),f["default"].unbind(window,"mouseup",u),_()}function d(){var e=(0,m["default"])(this.value);e!==!1?(y.__color.__state=e,y.setValue(y.__color.toOriginal())):this.value=y.__color.toString()}function c(){f["default"].unbind(window,"mousemove",b),f["default"].unbind(window,"mouseup",c),_()}function _(){y.__onFinishChange&&y.__onFinishChange.call(y,y.__color.toOriginal())}function h(e){e.preventDefault();var t=y.__saturation_field.getBoundingClientRect(),n=(e.clientX-t.left)/(t.right-t.left),o=1-(e.clientY-t.top)/(t.bottom-t.top);return o>1?o=1:o<0&&(o=0),n>1?n=1:n<0&&(n=0),y.__color.v=o,y.__color.s=n,y.setValue(y.__color.toOriginal()),!1}function b(e){e.preventDefault();var t=y.__hue_field.getBoundingClientRect(),n=1-(e.clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),y.__color.h=360*n,y.setValue(y.__color.toOriginal()),!1}i(this,t);var v=r(this,e.call(this,n,o));v.__color=new p["default"](v.getValue()),v.__temp=new p["default"](0);var y=v;v.domElement=document.createElement("div"),f["default"].makeSelectable(v.domElement,!1),v.__selector=document.createElement("div"),v.__selector.className="selector",v.__saturation_field=document.createElement("div"),v.__saturation_field.className="saturation-field",v.__field_knob=document.createElement("div"),v.__field_knob.className="field-knob",v.__field_knob_border="2px solid ",v.__hue_knob=document.createElement("div"),v.__hue_knob.className="hue-knob",v.__hue_field=document.createElement("div"),v.__hue_field.className="hue-field",v.__input=document.createElement("input"),v.__input.type="text",v.__input_textShadow="0 1px 1px ",f["default"].bind(v.__input,"keydown",function(e){13===e.keyCode&&d.call(this)}),f["default"].bind(v.__input,"blur",d),f["default"].bind(v.__selector,"mousedown",function(){f["default"].addClass(this,"drag").bind(window,"mouseup",function(){f["default"].removeClass(y.__selector,"drag")})});var w=document.createElement("div");return g["default"].extend(v.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),g["default"].extend(v.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:v.__field_knob_border+(v.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),g["default"].extend(v.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),g["default"].extend(v.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),g["default"].extend(w.style,{width:"100%",height:"100%",background:"none"}),l(w,"top","rgba(0,0,0,0)","#000"),g["default"].extend(v.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),s(v.__hue_field),g["default"].extend(v.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:v.__input_textShadow+"rgba(0,0,0,0.7)"}),f["default"].bind(v.__saturation_field,"mousedown",a),f["default"].bind(v.__field_knob,"mousedown",a),f["default"].bind(v.__hue_field,"mousedown",function(e){b(e),f["default"].bind(window,"mousemove",b),f["default"].bind(window,"mouseup",c)}),v.__saturation_field.appendChild(w),v.__selector.appendChild(v.__field_knob),v.__selector.appendChild(v.__saturation_field),v.__selector.appendChild(v.__hue_field),v.__hue_field.appendChild(v.__hue_knob),v.domElement.appendChild(v.__input),v.domElement.appendChild(v.__selector),v.updateDisplay(),v}return a(t,e),t.prototype.updateDisplay=function(){var e=(0,m["default"])(this.getValue());if(e!==!1){var t=!1;g["default"].each(p["default"].COMPONENTS,function(n){if(!g["default"].isUndefined(e[n])&&!g["default"].isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&g["default"].extend(this.__color.__state,e)}g["default"].extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,o=255-n;g["default"].extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,l(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),g["default"].extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})},t}(d["default"]),y=["-moz-","-o-","-webkit-","-ms-",""];t["default"]=v},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t,n){var o=document.createElement("li");return t&&o.appendChild(t),n?e.__ul.insertBefore(o,n):e.__ul.appendChild(o),e.onResize(),o}function r(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];t?n.innerHTML=n.value+"*":n.innerHTML=n.value}function a(e,t,n){if(n.__li=t,n.__gui=e,U["default"].extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:o,factoryArgs:[U["default"].toArray(arguments)]})}if(U["default"].isArray(t)||U["default"].isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:i,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){ 14 | return n.__gui.remove(n),n}}),n instanceof B["default"])!function(){var e=new N["default"](n.object,n.property,{min:n.__min,max:n.__max,step:n.__step});U["default"].each(["updateDisplay","onChange","onFinishChange","step"],function(t){var o=n[t],i=e[t];n[t]=e[t]=function(){var t=Array.prototype.slice.call(arguments);return i.apply(e,t),o.apply(n,t)}}),z["default"].addClass(t,"has-slider"),n.domElement.insertBefore(e.domElement,n.domElement.firstElementChild)}();else if(n instanceof N["default"]){var o=function(t){if(U["default"].isNumber(n.__min)&&U["default"].isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=s(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(o),i&&r.listen(),r}return t};n.min=U["default"].compose(o,n.min),n.max=U["default"].compose(o,n.max)}else n instanceof O["default"]?(z["default"].bind(t,"click",function(){z["default"].fakeEvent(n.__checkbox,"click")}),z["default"].bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof R["default"]?(z["default"].bind(t,"click",function(){z["default"].fakeEvent(n.__button,"click")}),z["default"].bind(t,"mouseover",function(){z["default"].addClass(n.__button,"hover")}),z["default"].bind(t,"mouseout",function(){z["default"].removeClass(n.__button,"hover")})):n instanceof j["default"]&&(z["default"].addClass(t,"color"),n.updateDisplay=U["default"].compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=U["default"].compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&r(e.getRoot(),!0),t},n.setValue)}function l(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(o!==-1){var i=n.__rememberedObjectIndecesToControllers[o];if(void 0===i&&(i={},n.__rememberedObjectIndecesToControllers[o]=i),i[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,a=void 0;if(r[e.preset])a=r[e.preset];else{if(!r[Q])return;a=r[Q]}if(a[o]&&void 0!==a[o][t.property]){var l=a[o][t.property];t.initialValue=l,t.setValue(l)}}}}function s(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var r=void 0;if(o.color)r=new j["default"](t,n);else{var s=[t,n].concat(o.factoryArgs);r=C["default"].apply(e,s)}o.before instanceof S["default"]&&(o.before=o.before.__li),l(e,r),z["default"].addClass(r.domElement,"c");var u=document.createElement("span");z["default"].addClass(u,"property-name"),u.innerHTML=r.property;var d=document.createElement("div");d.appendChild(u),d.appendChild(r.domElement);var c=i(e,d,o.before);return z["default"].addClass(c,oe.CLASS_CONTROLLER_ROW),r instanceof j["default"]?z["default"].addClass(c,"color"):z["default"].addClass(c,g(r.getValue())),a(e,c,r),e.__controllers.push(r),r}function u(e,t){return document.location.href+"."+t}function d(e,t,n){var o=document.createElement("option");o.innerHTML=t,o.value=t,e.__preset_select.appendChild(o),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function c(e,t){t.style.display=e.useLocalStorage?"block":"none"}function f(e){var t=e.__save_row=document.createElement("li");z["default"].addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),z["default"].addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",z["default"].addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",z["default"].addClass(o,"button"),z["default"].addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",z["default"].addClass(i,"button"),z["default"].addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",z["default"].addClass(r,"button"),z["default"].addClass(r,"revert");var a=e.__preset_select=document.createElement("select");e.load&&e.load.remembered?U["default"].each(e.load.remembered,function(t,n){d(e,n,n===e.preset)}):d(e,Q,!1),z["default"].bind(a,"change",function(){for(var t=0;t0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=h(this)),e.folders={},U["default"].each(this.__folders,function(t,n){e.folders[n]=t.getSaveObject()}),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=h(this),r(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[Q]=h(this,!0)),this.load.remembered[e]=h(this),this.preset=e,d(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){U["default"].each(this.__controllers,function(t){this.getRoot().load.remembered?l(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),U["default"].each(this.__folders,function(e){e.revert(e)}),e||r(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&b(this.__listening)},updateDisplay:function(){U["default"].each(this.__controllers,function(e){e.updateDisplay()}),U["default"].each(this.__folders,function(e){e.updateDisplay()})}}),e.exports=oe},function(e,t){"use strict";e.exports={load:function(e,t){var n=t||document,o=n.createElement("link");o.type="text/css",o.rel="stylesheet",o.href=e,n.getElementsByTagName("head")[0].appendChild(o)},inject:function(e,t){var n=t||document,o=document.createElement("style");o.type="text/css",o.innerHTML=e;var i=n.getElementsByTagName("head")[0];try{i.appendChild(o)}catch(r){}}}},function(e,t){e.exports="
Here's the new load parameter for your GUI's constructor:
Automatically save values to localStorage on exit.
The values saved to localStorage will override those passed to dat.GUI's constructor. This makes it easier to work incrementally, but localStorage is fragile, and your friends may not see the same values you do.
"},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var i=n(10),r=o(i),a=n(13),l=o(a),s=n(14),u=o(s),d=n(11),c=o(d),f=n(15),_=o(f),p=n(8),h=o(p),m=n(5),b=o(m),g=function(e,t){var n=e[t];return b["default"].isArray(arguments[2])||b["default"].isObject(arguments[2])?new r["default"](e,t,arguments[2]):b["default"].isNumber(n)?b["default"].isNumber(arguments[2])&&b["default"].isNumber(arguments[3])?b["default"].isNumber(arguments[4])?new u["default"](e,t,arguments[2],arguments[3],arguments[4]):new u["default"](e,t,arguments[2],arguments[3]):b["default"].isNumber(arguments[4])?new l["default"](e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new l["default"](e,t,{min:arguments[2],max:arguments[3]}):b["default"].isString(n)?new c["default"](e,t):b["default"].isFunction(n)?new _["default"](e,t,""):b["default"].isBoolean(n)?new h["default"](e,t):null};t["default"]=g},function(e,t){"use strict";function n(e){setTimeout(e,1e3/60)}t.__esModule=!0,t["default"]=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||n},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var r=n(9),a=o(r),l=n(5),s=o(l),u=function(){function e(){i(this,e),this.backgroundElement=document.createElement("div"),s["default"].extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),a["default"].makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),s["default"].extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;a["default"].bind(this.backgroundElement,"click",function(){t.hide()})}return e.prototype.show=function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),s["default"].defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})},e.prototype.hide=function t(){var e=this,t=function n(){e.domElement.style.display="none",e.backgroundElement.style.display="none",a["default"].unbind(e.domElement,"webkitTransitionEnd",n),a["default"].unbind(e.domElement,"transitionend",n),a["default"].unbind(e.domElement,"oTransitionEnd",n)};a["default"].bind(this.domElement,"webkitTransitionEnd",t),a["default"].bind(this.domElement,"transitionend",t),a["default"].bind(this.domElement,"oTransitionEnd",t),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"},e.prototype.layout=function(){this.domElement.style.left=window.innerWidth/2-a["default"].getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-a["default"].getHeight(this.domElement)/2+"px"},e}();t["default"]=u},function(e,t,n){t=e.exports=n(24)(),t.push([e.id,".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1!important}.dg.main .close-button.drag,.dg.main:hover .close-button{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;transition:opacity .1s linear;border:0;position:absolute;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-x:hidden}.dg.a.has-save>ul{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{position:fixed;top:0;z-index:1002}.dg li{-webkit-transition:height .1s ease-out;transition:height .1s ease-out}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;overflow:hidden;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid transparent}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:9px}.dg .c select{margin-top:5px}.dg .cr.boolean,.dg .cr.boolean *,.dg .cr.function,.dg .cr.function *,.dg .cr.function .property-name{cursor:pointer}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco,monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px Lucida Grande,sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid hsla(0,0%,100%,.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.boolean:hover,.dg .cr.function:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}",""])},function(e,t){e.exports=function(){var e=[];return e.toString=function(){for(var e=[],t=0;t',a,""].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b)&&c(b).matches||!1;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function l(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function m(){var a=s.elements;return typeof a=="string"?a.split(" "):a}function n(a){var b=j[a[h]];return b||(b={},i++,a[h]=i,j[i]=b),b}function o(a,c,d){c||(c=b);if(k)return c.createElement(a);d||(d=n(c));var g;return d.cache[a]?g=d.cache[a].cloneNode():f.test(a)?g=(d.cache[a]=d.createElem(a)).cloneNode():g=d.createElem(a),g.canHaveChildren&&!e.test(a)&&!g.tagUrn?d.frag.appendChild(g):g}function p(a,c){a||(a=b);if(k)return a.createDocumentFragment();c=c||n(a);var d=c.frag.cloneNode(),e=0,f=m(),g=f.length;for(;e",g="hidden"in a,k=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){g=!0,k=!0}})();var s={elements:d.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:c,shivCSS:d.shivCSS!==!1,supportsUnknownElements:k,shivMethods:d.shivMethods!==!1,type:"default",shivDocument:r,createElement:o,createDocumentFragment:p};a.html5=s,r(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f