├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── TASKS.md ├── dist ├── variaboard.css ├── variaboard.js ├── variaboard.min.css └── variaboard.min.js ├── docs ├── css │ ├── sourcemaps │ │ └── variaboard.min.css.map │ └── variaboard.min.css ├── index.html ├── js │ ├── sourcemaps │ │ └── variaboard.min.js.map │ └── variaboard.min.js └── jsdoc │ ├── Button.html │ ├── Calc.html │ ├── Control.html │ ├── Ease.html │ ├── Range.html │ ├── VariaBoard.html │ ├── button.js.html │ ├── controls_control.js.html │ ├── controls_range.js.html │ ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ ├── OpenSans-Regular-webfont.woff │ ├── OpenSans-Semibold-webfont.eot │ ├── OpenSans-Semibold-webfont.svg │ ├── OpenSans-Semibold-webfont.ttf │ ├── OpenSans-Semibold-webfont.woff │ ├── OpenSans-SemiboldItalic-webfont.eot │ ├── OpenSans-SemiboldItalic-webfont.svg │ ├── OpenSans-SemiboldItalic-webfont.ttf │ └── OpenSans-SemiboldItalic-webfont.woff │ ├── index.html │ ├── index.js.html │ ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js │ ├── styles │ ├── jsdoc-default.css │ ├── prettify-jsdoc.css │ └── prettify-tomorrow.css │ ├── util_calc.js.html │ └── util_ease.js.html ├── gulpfile.js ├── jsdoc.json ├── package.json └── src ├── css └── variaboard.css └── js ├── button.js ├── controls ├── boolean-control.js ├── control.js └── range-control.js ├── index.js └── util ├── calc.js └── ease.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true, 5 | "es6": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "plugins": [ "html" ], 9 | "settings": { 10 | "html/indent": "+2" // indentation is the 38 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /docs/jsdoc/Button.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Button - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

Button

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |

45 | Button 46 |

47 | 48 |

Create a button

49 | 50 | 51 |
52 | 53 |
54 |
55 | 56 | 57 |
58 | 59 | 60 |

Constructor

61 | 62 | 63 |

new Button()

64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
Source:
101 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 |
136 | 137 |
138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 |

Methods

153 | 154 | 155 | 156 |
157 | 158 | 159 | 160 |

createDOM()

161 | 162 | 163 | 164 | 165 | 166 |
167 |

Create necessary DOM elements

168 |
169 | 170 | 171 | 172 | 173 | 174 |
175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 |
Source:
202 |
205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 |
213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 |
237 | 238 | 239 |
240 | 241 | 242 | 243 |

listen()

244 | 245 | 246 | 247 | 248 | 249 |
250 |

Setup event listeners

251 |
252 | 253 | 254 | 255 | 256 | 257 |
258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 |
Source:
285 |
288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 |
296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 |
320 | 321 | 322 |
323 | 324 | 325 | 326 |

onButtonClick(e)

327 | 328 | 329 | 330 | 331 | 332 |
333 |

On button click event

334 |
335 | 336 | 337 | 338 | 339 | 340 |
341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 |
Source:
368 |
371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 |
379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 |
Parameters:
389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 424 | 425 | 426 | 427 | 428 | 429 | 433 | 434 | 435 | 436 | 437 |
NameTypeDescription
e 417 | 418 | 419 | object 420 | 421 | 422 | 423 | 430 |

Event object

431 | 432 |
438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 |
455 | 456 | 457 | 458 | 459 | 460 | 461 |
462 | 463 |
464 | 465 | 466 | 467 | 468 |
469 | 470 |
471 | 472 | 475 | 476 | 477 | 478 | 479 | -------------------------------------------------------------------------------- /docs/jsdoc/Calc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Calc - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

Calc

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |

45 | Calc 46 |

47 | 48 |

Calculation functions and helpers

49 | 50 | 51 |
52 | 53 |
54 |
55 | 56 | 57 |
58 | 59 | 60 |

Constructor

61 | 62 | 63 |

new Calc()

64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
Source:
101 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 |
136 | 137 |
138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 |

Methods

153 | 154 | 155 | 156 |
157 | 158 | 159 | 160 |

(static) clamp(val, min, max) → {number}

161 | 162 | 163 | 164 | 165 | 166 |
167 |

Clamp a value to a range

168 |
169 | 170 | 171 | 172 | 173 | 174 |
175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 |
Source:
202 |
205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 |
213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 |
Parameters:
223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 258 | 259 | 260 | 261 | 262 | 263 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 284 | 285 | 286 | 287 | 288 | 289 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 310 | 311 | 312 | 313 | 314 | 315 | 319 | 320 | 321 | 322 | 323 |
NameTypeDescription
val 251 | 252 | 253 | number 254 | 255 | 256 | 257 | 264 |

Input value

265 | 266 |
min 277 | 278 | 279 | number 280 | 281 | 282 | 283 | 290 |

Minimum range value

291 | 292 |
max 303 | 304 | 305 | number 306 | 307 | 308 | 309 | 316 |

Maximum range value

317 | 318 |
324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 |
339 |
Returns:
340 | 341 | 342 | 343 |
344 |
345 | Type: 346 |
347 |
348 | 349 | number 350 | 351 | 352 |
353 |
354 | 355 | 356 |
357 |

Clamped value within range

358 |
359 | 360 | 361 |
362 | 363 | 364 | 365 |
366 |
Example
367 | 368 |
Calc.clamp(3, 10, 150);
369 | // -> 10
370 | 
371 | Calc.clamp(400, 10, 150);
372 | // -> 150
373 | 
374 | Calc.clamp(75, 10, 100);
375 | // -> 75
376 | 377 |
378 | 379 |
380 | 381 | 382 |
383 | 384 | 385 | 386 |

(static) rand(min, max) → {number}

387 | 388 | 389 | 390 | 391 | 392 |
393 |

Get a random float within a range. If only one argument is passed, it is used as the max and the min becomes zero.

394 |
395 | 396 | 397 | 398 | 399 | 400 |
401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 |
Source:
428 |
431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 |
439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 |
Parameters:
449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 484 | 485 | 486 | 487 | 488 | 489 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 510 | 511 | 512 | 513 | 514 | 515 | 519 | 520 | 521 | 522 | 523 |
NameTypeDescription
min 477 | 478 | 479 | number 480 | 481 | 482 | 483 | 490 |

Minimum range value

491 | 492 |
max 503 | 504 | 505 | number 506 | 507 | 508 | 509 | 516 |

Maximum range value

517 | 518 |
524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 |
539 |
Returns:
540 | 541 | 542 | 543 |
544 |
545 | Type: 546 |
547 |
548 | 549 | number 550 | 551 | 552 |
553 |
554 | 555 | 556 |
557 |

Random float within the range

558 |
559 | 560 | 561 |
562 | 563 | 564 | 565 |
566 |
Example
567 | 568 |
// two arguments
569 | Calc.rand(2, 18);
570 | // -> random float between 2 and 18
571 | 
572 | // single argument
573 | Calc.rand(42.5);
574 | // -> random float between 0 and 42.5
575 | 576 |
577 | 578 |
579 | 580 | 581 | 582 | 583 | 584 | 585 |
586 | 587 |
588 | 589 | 590 | 591 | 592 |
593 | 594 |
595 | 596 | 599 | 600 | 601 | 602 | 603 | -------------------------------------------------------------------------------- /docs/jsdoc/Control.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Control - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

Control

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |

45 | Control 46 |

47 | 48 |

Create a control

49 | 50 | 51 |
52 | 53 |
54 |
55 | 56 | 57 |
58 | 59 | 60 |

Constructor

61 | 62 | 63 |

new Control()

64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
Source:
101 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 |
136 | 137 |
138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 |
157 | 158 |
159 | 160 | 161 | 162 | 163 |
164 | 165 |
166 | 167 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /docs/jsdoc/Ease.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Ease - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

Ease

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |

45 | Ease 46 |

47 | 48 |

Easing equations

49 | 50 | 51 |
52 | 53 |
54 |
55 | 56 | 57 |
58 | 59 | 60 |

Constructor

61 | 62 | 63 |

new Ease()

64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
Source:
101 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 |
136 | 137 |
138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 |
157 | 158 |
159 | 160 | 161 | 162 | 163 |
164 | 165 |
166 | 167 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /docs/jsdoc/Range.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Range - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

Range

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |

45 | Range 46 |

47 | 48 |

Create a range control

49 | 50 | 51 |
52 | 53 |
54 |
55 | 56 | 57 |
58 | 59 | 60 |

Constructor

61 | 62 | 63 |

new Range(variaboard, config)

64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
Source:
101 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
Parameters:
122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 157 | 158 | 159 | 160 | 161 | 162 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 183 | 184 | 185 | 186 | 187 | 188 | 451 | 452 | 453 | 454 | 455 |
NameTypeDescription
variaboard 150 | 151 | 152 | object 153 | 154 | 155 | 156 | 163 |

Reference to parent VariaBoard instance

164 | 165 |
config 176 | 177 | 178 | object 179 | 180 | 181 | 182 | 189 |

Configuration object

190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 226 | 227 | 228 | 229 | 230 | 231 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 252 | 253 | 254 | 255 | 256 | 257 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 278 | 279 | 280 | 281 | 282 | 283 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 304 | 305 | 306 | 307 | 308 | 309 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 330 | 331 | 332 | 333 | 334 | 335 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 356 | 357 | 358 | 359 | 360 | 361 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 382 | 383 | 384 | 385 | 386 | 387 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 408 | 409 | 410 | 411 | 412 | 413 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 434 | 435 | 436 | 437 | 438 | 439 | 443 | 444 | 445 | 446 | 447 |
NameTypeDescription
id 219 | 220 | 221 | string 222 | 223 | 224 | 225 | 232 |

Unique id/slug

233 | 234 |
title 245 | 246 | 247 | string 248 | 249 | 250 | 251 | 258 |

UI display title

259 | 260 |
min 271 | 272 | 273 | number 274 | 275 | 276 | 277 | 284 |

Minimum value

285 | 286 |
max 297 | 298 | 299 | number 300 | 301 | 302 | 303 | 310 |

Maximum value

311 | 312 |
step 323 | 324 | 325 | number 326 | 327 | 328 | 329 | 336 |

Step size

337 | 338 |
default 349 | 350 | 351 | number 352 | 353 | 354 | 355 | 362 |

Starting value

363 | 364 |
randomizable 375 | 376 | 377 | boolean 378 | 379 | 380 | 381 | 388 |

Can be randomized individually and by randomizing all

389 | 390 |
mutable 401 | 402 | 403 | boolean 404 | 405 | 406 | 407 | 414 |

Can be mutated individually and by mutating all

415 | 416 |
locked 427 | 428 | 429 | boolean 430 | 431 | 432 | 433 | 440 |

Temporarily toggle whether the control is affected by randomization and mutation

441 | 442 |
448 | 449 | 450 |
456 | 457 | 458 | 459 | 460 |
Requires:
461 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 |
480 | 481 |
482 | 483 | 484 |

Extends

485 | 486 | 487 | 488 | 489 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 |
512 | 513 |
514 | 515 | 516 | 517 | 518 |
519 | 520 |
521 | 522 | 525 | 526 | 527 | 528 | 529 | -------------------------------------------------------------------------------- /docs/jsdoc/button.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | button.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

button.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
/**
 43 |  * Create a button
 44 |  */
 45 | 
 46 | class Button {
 47 | 
 48 |   constructor(variaboard, config) {
 49 |     this.variaboard = variaboard;
 50 |     this.id = config.id;
 51 |     this.title = config.title;
 52 |     this.callback = config.callback !== undefined ? config.callback : () => {};
 53 | 
 54 |     this.createDOM();
 55 |     this.listen();
 56 |   }
 57 | 
 58 |   /**
 59 |    * Create necessary DOM elements
 60 |    */
 61 | 
 62 |   createDOM() {
 63 |     this.dom = {};
 64 | 
 65 |     // control
 66 |     this.dom.control = document.createElement('div');
 67 |     this.dom.control.classList.add(`${this.variaboard.namespace}-control`);
 68 | 
 69 |     // button
 70 |     this.dom.button = document.createElement('button');
 71 |     this.dom.button.classList.add(`${this.variaboard.namespace}-control-button`);
 72 |     this.dom.button.textContent = this.title;
 73 |     this.dom.control.appendChild(this.dom.button);
 74 | 
 75 |     // add to control to panel
 76 |     this.variaboard.dom.controls.appendChild(this.dom.control);
 77 |   }
 78 | 
 79 |   /**
 80 |    * Setup event listeners
 81 |    */
 82 | 
 83 |   listen() {
 84 |     this.dom.button.addEventListener('click', (e) => this.onButtonClick(e));
 85 |   }
 86 | 
 87 |   /**
 88 |    * On button click event
 89 |    *
 90 |    * @param {object} e - Event object
 91 |    */
 92 | 
 93 |   onButtonClick(e) {
 94 |     this.callback();
 95 |   }
 96 | 
 97 | }
 98 | 
 99 | module.exports = Button
100 | 
101 |
102 |
103 | 104 | 105 | 106 | 107 |
108 | 109 |
110 | 111 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /docs/jsdoc/controls_control.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | controls/control.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

controls/control.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
/**
 43 |  * Create a control
 44 |  */
 45 | 
 46 | class Control {
 47 | 
 48 |   constructor(variaboard, config) {
 49 |     this.variaboard = variaboard;
 50 |     this.type = config.type;
 51 |     this.id = config.id;
 52 |     this.title = config.title;
 53 |     this.default = config.default;
 54 |     this.randomizable = config.randomizable !== undefined ? config.randomizable : true;
 55 |     this.mutable = config.mutable !== undefined ? config.mutable : true;
 56 |     this.locked = config.locked !== undefined ? config.locked : false;
 57 |     this.value = this.default;
 58 | 
 59 |     this.createDOM();
 60 |   }
 61 | 
 62 |   createDOM() {
 63 |     this.dom = {};
 64 | 
 65 |     // control
 66 |     this.dom.control = document.createElement('div');
 67 |     this.dom.control.classList.add(`${this.variaboard.namespace}-control`);
 68 | 
 69 |     // title
 70 |     this.dom.title = document.createElement('h3');
 71 |     this.dom.title.classList.add(`${this.variaboard.namespace}-control-title`);
 72 |     this.dom.title.textContent = this.title;
 73 |     this.dom.control.appendChild(this.dom.title);
 74 | 
 75 |     // value
 76 |     this.dom.value = document.createElement('input');
 77 |     this.dom.value.classList.add(`${this.variaboard.namespace}-control-value`);
 78 |     this.dom.control.appendChild(this.dom.value);
 79 | 
 80 |     // add control to panel
 81 |     this.variaboard.dom.controls.appendChild(this.dom.control);
 82 |   }
 83 | 
 84 |   lock() {
 85 |     this.locked = true;
 86 |   }
 87 | 
 88 |   unlock() {
 89 |     this.locked = false;
 90 |   }
 91 | 
 92 | }
 93 | 
 94 | module.exports = Control;
 95 | 
96 |
97 |
98 | 99 | 100 | 101 | 102 |
103 | 104 |
105 | 106 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /docs/jsdoc/controls_range.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | controls/range.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

controls/range.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
const Control = require('./control');
 43 | const Calc = require('../util/calc');
 44 | 
 45 | /**
 46 |  * Create a range control
 47 |  *
 48 |  * @param {object} variaboard - Reference to parent VariaBoard instance
 49 |  * @param {object} config - Configuration object
 50 |  * @param {string} config.id - Unique id/slug
 51 |  * @param {string} config.title - UI display title
 52 |  * @param {number} config.min - Minimum value
 53 |  * @param {number} config.max - Maximum value
 54 |  * @param {number} config.step - Step size
 55 |  * @param {number} config.default - Starting value
 56 |  * @param {boolean} config.randomizable - Can be randomized individually and by randomizing all
 57 |  * @param {boolean} config.mutable - Can be mutated individually and by mutating all
 58 |  * @param {boolean} config.locked - Temporarily toggle whether the control is affected by randomization and mutation
 59 |  *
 60 |  * @extends Control
 61 |  *
 62 |  * @requires {@link Control}
 63 |  * @requires {@link Calc}
 64 |  */
 65 | 
 66 | class Range extends Control {
 67 | 
 68 |   constructor(variaboard, config) {
 69 |     super(variaboard, config);
 70 |     this.type = 'range';
 71 | 
 72 |     this.min = config.min;
 73 |     this.max = config.max;
 74 |     this.step = config.step !== undefined ? Math.abs(config.step) : 1;
 75 |     this.places = this.step.toString().indexOf('.') > -1 ? this.step.toString().split('.')[1].length : 0;
 76 |     this.valueTarget = this.value;
 77 | 
 78 |     this.mouseIsDown = false;
 79 |     this.settled = false;
 80 | 
 81 |     this.listen();
 82 | 
 83 |     this.set(this.value);
 84 |   }
 85 | 
 86 |   createDOM() {
 87 |     super.createDOM();
 88 | 
 89 |     // range
 90 |     this.dom.range = document.createElement('div');
 91 |     this.dom.range.classList.add(`${this.variaboard.namespace}-control-range`);
 92 | 
 93 |     // range inner
 94 |     this.dom.rangeInner = document.createElement('div');
 95 |     this.dom.rangeInner.classList.add(`${this.variaboard.namespace}-control-range-inner`);
 96 |     this.dom.range.appendChild(this.dom.rangeInner);
 97 |     
 98 |     this.dom.control.appendChild(this.dom.range);
 99 |   }
100 | 
101 |   listen() {
102 |     this.dom.value.addEventListener('change', (e) => this.onValueChange(e));
103 |     this.dom.range.addEventListener('mousedown', (e) => this.onValueMousedown(e));
104 |   }
105 | 
106 |   onValueChange(e) {
107 |     this.set(this.dom.value.value);
108 |     this.valueTarget = this.value;
109 |   }
110 | 
111 |   onValueMousedown(e) {
112 |     this.variaboard.mouse.down = true;
113 |     this.variaboard.mouse.anchor.x = e.clientX;
114 |     this.variaboard.mouse.anchor.y = e.clientY;
115 |     this.mouseIsDown = true;
116 |     this.setDragValue();
117 |   }
118 | 
119 |   onWindowMouseup(e) {
120 |     this.mouseIsDown = false;
121 |   }
122 | 
123 |   onWindowMousemove(e) {
124 |     if(this.mouseIsDown) {
125 |       this.setDragValue();
126 |     }
127 |   }
128 | 
129 |   randomize() {
130 |     this.settled = false;
131 |     this.valueTarget = Calc.rand(this.min, this.max);
132 |   }
133 | 
134 |   setDragValue() {
135 |     let left = this.dom.range.offsetLeft;
136 |     let width = this.dom.range.offsetWidth;
137 |     let val = Calc.map(this.variaboard.mouse.x, left, left + width, this.min, this.max);
138 |     this.set(val);
139 |     this.valueTarget = this.value;
140 |   }
141 | 
142 |   easeSet() {
143 |     if(Math.abs(this.value - this.valueTarget) > this.step / 2) {
144 |       this.value += (this.valueTarget - this.value) * 0.2;
145 |       this.set(this.value, true);
146 |     } else {
147 |       this.settled = true;
148 |       this.value = this.valueTarget;
149 |       this.set(this.value); 
150 |     }
151 |   }
152 | 
153 |   set(val, bypassRounding) {
154 |     // sanitize value
155 |     val = parseFloat(val);
156 |     val = isNaN(val) ? this.default : val;
157 |     val = Calc.clamp(val, this.min, this.max);
158 |     val = bypassRounding ? val : Calc.roundToNearestInterval(val, this.step);
159 |     this.value = val;
160 |     
161 |     // set input value
162 |     this.dom.value.value = this.value.toFixed(this.places);
163 |     
164 |     // set range value
165 |     this.dom.rangeInner.style.transform = `scaleX(${Calc.map(this.value, this.min, this.max, 0, 1)})`;
166 |     
167 |     // set the title attribute for the control
168 |     this.dom.control.setAttribute('title', `${this.title}: ${this.value.toFixed(this.places)}`);
169 |   }
170 | 
171 | }
172 | 
173 | module.exports = Range;
174 | 
175 |
176 |
177 | 178 | 179 | 180 | 181 |
182 | 183 |
184 | 185 | 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Semibold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Semibold-webfont.eot -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Semibold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Semibold-webfont.ttf -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-Semibold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-Semibold-webfont.woff -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-SemiboldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-SemiboldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-SemiboldItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-SemiboldItalic-webfont.ttf -------------------------------------------------------------------------------- /docs/jsdoc/fonts/OpenSans-SemiboldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackrugile/variaboard/6144a4f9d6983cf232a80af42c320a03a63082b8/docs/jsdoc/fonts/OpenSans-SemiboldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/jsdoc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Home - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 68 |
69 | 70 | 71 | 72 | 73 | 74 | 75 |
76 | 77 |
78 | 79 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /docs/jsdoc/index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | index.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

index.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
const Button = require('./button');
 43 | const Range = require('./controls/range');
 44 | const Calc = require('./util/calc');
 45 | 
 46 | class VariaBoard {
 47 | 
 48 |   /**
 49 |    * Create a VariaBoard control panel
 50 |    *
 51 |    * @param {object} config - Configuration object
 52 |    * @param {object|string} [config.container=document.body] - DOM element or CSS selector
 53 |    * @param {string} [config.title="Control Panel"] - Title of the panel
 54 |    *
 55 |    * @requires {@link Button}
 56 |    * @requires {@link Range}
 57 |    * @requires {@link Calc}
 58 |    */
 59 | 
 60 |   constructor(config) {
 61 |     this.namespace = 'variaboard';
 62 |     this.controls = {};
 63 |     this.buttons = {};
 64 | 
 65 |     this.mouse = {
 66 |       down: false,
 67 |       x: 0,
 68 |       y: 0,
 69 |       anchor: {
 70 |         x: 0,
 71 |         y: 0
 72 |       }
 73 |     }
 74 | 
 75 |     this.needsUpdate = false;
 76 |     this.raf = null;
 77 | 
 78 |     this.container = config.container !== undefined ? config.container : document.body;
 79 |     this.title = config.title !== undefined ? config.title : 'VariaBoard';
 80 |     
 81 |     this.createDOM();
 82 |     this.listen();
 83 |   }
 84 | 
 85 |   /**
 86 |    * Create necessary DOM elements
 87 |    */
 88 | 
 89 |   createDOM() {
 90 |     this.dom = {};
 91 | 
 92 |     // container
 93 |     this.dom.container = this.container;
 94 | 
 95 |     // panel
 96 |     this.dom.panel = document.createElement('div');
 97 |     this.dom.panel.classList.add(`${this.namespace}-panel`);
 98 | 
 99 |     // title
100 |     this.dom.title = document.createElement('h1');
101 |     this.dom.title.classList.add(`${this.namespace}-title`);
102 |     this.dom.title.textContent = this.title;
103 |     this.dom.panel.appendChild(this.dom.title);
104 | 
105 |     // controls
106 |     this.dom.controls = document.createElement('div');
107 |     this.dom.controls.classList.add(`${this.namespace}-controls`);
108 |     this.dom.panel.appendChild(this.dom.controls);
109 | 
110 |     // add panel to container
111 |     this.dom.container.appendChild(this.dom.panel);
112 |   }
113 | 
114 |   /**
115 |    * Setup event listeners
116 |    */
117 | 
118 |   listen() {
119 |     window.addEventListener('mouseup', (e) => this.onWindowMouseup(e));
120 |     window.addEventListener('mousemove', (e) => this.onWindowMousemove(e));
121 |   }
122 | 
123 |   /**
124 |    * On window mouse up event
125 |    *
126 |    * @param {object} e - Event object
127 |    */
128 | 
129 |   onWindowMouseup(e) {
130 |     this.mouse.down = false;
131 |     for(let key in this.controls) {
132 |       let control = this.controls[key];
133 |       control.onWindowMouseup(e);
134 |     }
135 |   }
136 | 
137 |   /**
138 |    * On window mouse move event
139 |    *
140 |    * @param {object} e - Event object
141 |    */
142 | 
143 |   onWindowMousemove(e) {
144 |     this.mouse.x = e.clientX;
145 |     this.mouse.y = e.clientY;
146 |     for(let key in this.controls) {
147 |       let control = this.controls[key];
148 |       control.onWindowMousemove(e);
149 |     }
150 |   }
151 | 
152 |   /**
153 |    * Update based on requestAnimationFrame()
154 |    */
155 | 
156 |   update() {
157 |     this.needsUpdate = false;
158 |     for(let key in this.controls) {
159 |       if(this.controls[key].type === 'range') {
160 |         this.controls[key].easeSet();
161 |         if(!this.controls[key].settled) {
162 |           this.needsUpdate = true;
163 |         }
164 |       }
165 |     }
166 | 
167 |     if(this.needsUpdate) {
168 |       this.raf = requestAnimationFrame(() => this.update());
169 |     }
170 |   }
171 | 
172 |   /**
173 |    * Add a button
174 |    *
175 |    * @param {object} config - Configuration object
176 |    * @param {object} config.id - ID slug
177 |    * @param {object} config.title - Title text
178 |    * @param {object} [config.callback=() => {}] - Callback function for button press
179 |    */
180 | 
181 |   addButton(config) {
182 |     this.buttons[config.id] = new Button(this, config);
183 |   }
184 | 
185 |   /**
186 |    * Add a range control via {@linkcode Range}
187 |    *
188 |    * @param {object} config - Configuration object
189 |    * @param {string} config.id - Unique id/slug
190 |    * @param {string} config.title - UI display title
191 |    * @param {number} config.min - Minimum value
192 |    * @param {number} config.max - Maximum value
193 |    * @param {number} config.step - Step size
194 |    * @param {number} config.default - Starting value
195 |    * @param {boolean} config.randomizable - Can be randomized individually and by randomizing all
196 |    * @param {boolean} config.mutable - Can be mutated individually and by mutating all
197 |    * @param {boolean} config.locked - Temporarily toggle whether the control is affected by randomization and mutation
198 |    */
199 | 
200 |   addRange(config) {
201 |     let control = new Range(this, config);
202 |     this.controls[control.id] = control;
203 |   }
204 | 
205 |   get(id) {
206 |     return this.controls[id].value;
207 |   }
208 | 
209 |   randomize() {
210 |     for(let key in this.controls) {
211 |       this.controls[key].randomize();
212 |     }
213 |     cancelAnimationFrame(this.raf);
214 |     this.update();
215 |   }
216 | 
217 |   mutate() {
218 |     for(let key in this.controls) {
219 |       let control = this.controls[key];
220 |       let size = (control.max - control.min) / 15;
221 |       control.settled = false;
222 |       if(control.value <= control.min) {
223 |         control.valueTarget = Calc.rand(control.step, control.min + size);
224 |       } else if(control.value >= control.max) {
225 |         control.valueTarget = Calc.rand(control.max - size, control.max - control.step);
226 |       } else {
227 |         control.valueTarget = control.value + Calc.rand(-size, size);
228 |       }
229 |       cancelAnimationFrame(this.raf);
230 |       this.update();
231 |     }
232 |   }
233 | 
234 | }
235 | 
236 | module.exports = VariaBoard;
237 | 
238 |
239 |
240 | 241 | 242 | 243 | 244 |
245 | 246 |
247 | 248 | 251 | 252 | 253 | 254 | 255 | 256 | -------------------------------------------------------------------------------- /docs/jsdoc/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/jsdoc/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/jsdoc/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/jsdoc/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p 2 | 3 | 4 | 5 | 6 | util/calc.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

util/calc.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
/**
 43 |  * Calculation functions and helpers
 44 |  */
 45 | 
 46 | class Calc {
 47 | 
 48 |   /**
 49 |   * Get a random float within a range. If only one argument is passed, it is used as the max and the min becomes zero.
 50 |   *
 51 |   * @param {number} min - Minimum range value
 52 |   * @param {number} max - Maximum range value
 53 |   *
 54 |   * @example
 55 |   * // two arguments
 56 |   * Calc.rand(2, 18);
 57 |   * // -> random float between 2 and 18
 58 |   *
 59 |   * // single argument
 60 |   * Calc.rand(42.5);
 61 |   * // -> random float between 0 and 42.5
 62 |   *
 63 |   * @returns {number} Random float within the range
 64 |   */
 65 |   static rand(min, max) {
 66 |     if(max === undefined) {
 67 |       max = min;
 68 |       min = 0;
 69 |     }
 70 |     return Math.random() * (max - min) + min;
 71 |   }
 72 | 
 73 |   /**
 74 |   * Clamp a value to a range
 75 |   *
 76 |   * @param {number} val - Input value
 77 |   * @param {number} min - Minimum range value
 78 |   * @param {number} max - Maximum range value
 79 |   *
 80 |   * @example
 81 |   * Calc.clamp(3, 10, 150);
 82 |   * // -> 10
 83 |   *
 84 |   * Calc.clamp(400, 10, 150);
 85 |   * // -> 150
 86 |   *
 87 |   * Calc.clamp(75, 10, 100);
 88 |   * // -> 75
 89 |   *
 90 |   * @returns {number} Clamped value within range
 91 |   */
 92 | 
 93 |   static clamp(val, min, max) {
 94 |     return Math.max(Math.min(val, max), min);
 95 |   }
 96 | 
 97 |   static map(val, inMin, inMax, outMin, outMax) {
 98 |     return ((outMax - outMin) * ((val - inMin) / (inMax - inMin))) + outMin;
 99 |   }
100 | 
101 |   static roundToNearestInterval(value, interval) {
102 |     return Math.round(value / interval) * interval;
103 |   }
104 | 
105 | }
106 | 
107 | module.exports = Calc;
108 | 
109 |
110 |
111 | 112 | 113 | 114 | 115 |
116 | 117 |
118 | 119 |
120 | Generated by JSDoc 3.5.5 on Thu Dec 28 2017 20:24:40 GMT-0700 (MST) using the Minami theme. 121 |
122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /docs/jsdoc/util_ease.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | util/ease.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

util/ease.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
/**
43 |  * Easing equations
44 |  */
45 | 
46 | class Ease {
47 | 
48 | }
49 | 
50 | module.exports = Ease;
51 | 
52 |
53 |
54 | 55 | 56 | 57 | 58 |
59 | 60 |
61 | 62 |
63 | Generated by JSDoc 3.5.5 on Thu Dec 28 2017 20:24:40 GMT-0700 (MST) using the Minami theme. 64 |
65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | const babelify = require('babelify'); 3 | const browserify = require('browserify'); 4 | const buffer = require('vinyl-buffer'); 5 | const cssnano = require('cssnano'); 6 | const del = require('del'); 7 | const gulp = require('gulp'); 8 | const gutil = require('gulp-util'); 9 | const jsdoc = require('gulp-jsdoc3'); 10 | const postcss = require('gulp-postcss'); 11 | const rename = require('gulp-rename'); 12 | const sequence = require('run-sequence'); 13 | const source = require('vinyl-source-stream'); 14 | const sourcemaps = require('gulp-sourcemaps'); 15 | const uglify = require('gulp-uglify'); 16 | const webserver = require('gulp-webserver'); 17 | 18 | gulp.task('build', () => { 19 | return sequence( 20 | 'build-css', 21 | 'build-js' 22 | ); 23 | }); 24 | 25 | gulp.task('build-css', () => { 26 | return sequence( 27 | 'clean-dist-css', 28 | 'build-css-src', 29 | 'build-css-min' 30 | ); 31 | }); 32 | 33 | gulp.task('clean-dist-css', () => { 34 | return del.sync([ 35 | './dist/*.css', 36 | './dist/sourcemaps/*.css.map' 37 | ],{ force: true }); 38 | }); 39 | 40 | gulp.task('build-css-src', () => { 41 | let plugins = [ 42 | autoprefixer({browsers: ['last 1 version']}) 43 | ]; 44 | return gulp.src('./src/css/*.css') 45 | .pipe(rename('variaboard.css')) 46 | .pipe(postcss(plugins)) 47 | .pipe(gulp.dest('./dist')); 48 | }); 49 | 50 | gulp.task('build-css-min', () => { 51 | let plugins = [ 52 | autoprefixer({browsers: ['last 1 version']}), 53 | cssnano() 54 | ]; 55 | return gulp.src('./src/css/*.css') 56 | .pipe(rename('variaboard.min.css')) 57 | .pipe(sourcemaps.init()) 58 | .pipe(postcss(plugins)) 59 | .pipe(gulp.dest('./dist')) 60 | .pipe(sourcemaps.write('./sourcemaps')) 61 | .pipe(gulp.dest('./docs/css')); 62 | }); 63 | 64 | gulp.task('build-js', () => { 65 | return sequence( 66 | 'clean-dist-js', 67 | 'build-js-src', 68 | 'build-js-min' 69 | ); 70 | }); 71 | 72 | gulp.task('clean-dist-js', () => { 73 | return del.sync([ 74 | './dist/*.js', 75 | './dist/sourcemaps/*.js.map' 76 | ],{ force: true }); 77 | }); 78 | 79 | gulp.task('build-js-src', () => { 80 | browserify({ 81 | entries: './src/js/index.js', 82 | debug: false, 83 | standalone: 'VariaBoard' 84 | }) 85 | .transform('babelify', { presets: ['env'] }) 86 | .bundle() 87 | .on('error', err => { 88 | gutil.log("Browserify Error", gutil.colors.red(err.message)) 89 | }) 90 | .pipe(source('variaboard.js')) 91 | .pipe(buffer()) 92 | .pipe(gulp.dest('./dist')); 93 | }); 94 | 95 | gulp.task('build-js-min', () => { 96 | browserify({ 97 | entries: './src/js/index.js', 98 | debug: false, 99 | standalone: 'VariaBoard' 100 | }) 101 | .transform('babelify', { presets: ['env'] }) 102 | .bundle() 103 | .on('error', err => { 104 | gutil.log("Browserify Error", gutil.colors.red(err.message)) 105 | }) 106 | .pipe(source('variaboard.min.js')) 107 | .pipe(buffer()) 108 | .pipe(uglify()) 109 | .pipe(gulp.dest('./dist')) 110 | .pipe(sourcemaps.init({ loadMaps: true })) 111 | .pipe(sourcemaps.write('./sourcemaps')) 112 | .pipe(gulp.dest('./docs/js')); 113 | }); 114 | 115 | gulp.task('docs', () => { 116 | return sequence( 117 | 'clean-docs', 118 | 'build-docs' 119 | ); 120 | }); 121 | 122 | gulp.task('clean-docs', () => { 123 | return del.sync([ 124 | './docs/jsdoc' 125 | ], { force: true }); 126 | }); 127 | 128 | gulp.task('build-docs', function (cb) { 129 | let config = require('./jsdoc.json'); 130 | gulp.src(['./README.md', './src/js/**/*.js'], { read: false }) 131 | .pipe(jsdoc(config, cb)); 132 | }); 133 | 134 | gulp.task('serve', () => { 135 | gulp.src('./docs') 136 | .pipe(webserver({ 137 | 'host': '0.0.0.0', 138 | 'fallback': './index.html', 139 | 'livereload': true, 140 | 'open': true, 141 | 'port': '4000' 142 | })); 143 | }); 144 | 145 | gulp.task('watch', ['build', 'serve'], () => { 146 | gulp.watch('./src/css/**/*.css', ['build-css']); 147 | gulp.watch('./src/js/**/*.js', ['build-js']); 148 | }); 149 | 150 | gulp.task('default', ['watch']); 151 | -------------------------------------------------------------------------------- /jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true 4 | }, 5 | "opts": { 6 | "destination": "./docs/jsdoc", 7 | "template": "node_modules/minami" 8 | }, 9 | "plugins": [ 10 | "plugins/markdown" 11 | ], 12 | "templates": { 13 | "cleverLinks": true, 14 | "monospaceLinks": true, 15 | "default": { 16 | "outputSourceFiles": true 17 | }, 18 | "outputSourceFiles": true, 19 | "navType": "vertical", 20 | "linenums": true, 21 | "dateFormat": "MMMM Do YYYY, h:mm:ss a", 22 | "systemName": "VariaBoard" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "variaboard", 3 | "author": "Jack Rugile (https://jackrugile.com)", 4 | "version": "0.1.1", 5 | "description": "VariaBoard is a control interface to modify parameters in JavaScript.", 6 | "keywords": [ 7 | "controls", 8 | "control panel", 9 | "settings", 10 | "parameters", 11 | "parameterization", 12 | "gui", 13 | "variables", 14 | "javascript" 15 | ], 16 | "main": "src/js/index.js", 17 | "license": "MIT", 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/jackrugile/variaboard.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/jackrugile/variaboard/issues" 24 | }, 25 | "homepage": "https://github.com/jackrugile/variaboard.git#readme", 26 | "devDependencies": { 27 | "autoprefixer": "^7.2.3", 28 | "babel-core": "^6.26.0", 29 | "babel-preset-env": "^1.6.1", 30 | "babelify": "^8.0.0", 31 | "browserify": "^14.5.0", 32 | "cssnano": "^3.10.0", 33 | "del": "^3.0.0", 34 | "eslint": "^4.14.0", 35 | "eslint-plugin-html": "^4.0.1", 36 | "gulp": "^3.9.1", 37 | "gulp-jsdoc3": "^1.0.1", 38 | "gulp-postcss": "^7.0.0", 39 | "gulp-rename": "^1.2.2", 40 | "gulp-sourcemaps": "^2.6.2", 41 | "gulp-uglify": "^3.0.0", 42 | "gulp-util": "^3.0.8", 43 | "gulp-webserver": "^0.9.1", 44 | "minami": "^1.2.3", 45 | "run-sequence": "^2.2.0", 46 | "vinyl-buffer": "^1.0.1", 47 | "vinyl-source-stream": "^1.1.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/css/variaboard.css: -------------------------------------------------------------------------------- 1 | /** 2 | * VariaBoard Panel 3 | */ 4 | 5 | .variaboard-panel, 6 | .variaboard-panel * { 7 | box-sizing: border-box; 8 | } 9 | 10 | .variaboard-panel { 11 | background: #000; 12 | border: 1px solid #000; 13 | color: #fff; 14 | font-family: source code pro, monospace; 15 | font-size: 14px; 16 | left: 0; 17 | max-height: 100%; 18 | max-width: 300px; 19 | overflow: auto; 20 | position: fixed; 21 | top: 0; 22 | transition: opacity 200ms; 23 | width: 100%; 24 | z-index: 99; 25 | -webkit-touch-callout: none; 26 | -webkit-user-select: none; 27 | -khtml-user-select: none; 28 | -moz-user-select: none; 29 | -ms-user-select: none; 30 | user-select: none; 31 | } 32 | 33 | /** 34 | * Selections 35 | */ 36 | 37 | .variaboard-title::selection, 38 | .variaboard-control-title::selection, 39 | .variaboard-control-value::selection, 40 | .variaboard-button::selection { 41 | background: #fff; 42 | color: #000; 43 | } 44 | 45 | .variaboard-title::-moz-selection, 46 | .variaboard-control-title::-moz-selection, 47 | .variaboard-control-value::-moz-selection, 48 | .variaboard-button::-moz-selection { 49 | background: #fff; 50 | color: #000; 51 | } 52 | 53 | /** 54 | * VariaBoard Title 55 | */ 56 | 57 | .variaboard-title { 58 | background: #111; 59 | color: #fff; 60 | cursor: pointer; 61 | height: 28px; 62 | font-size: 0.8em; 63 | font-weight: 700; 64 | line-height: 28px; 65 | margin: 0 0 1px; 66 | overflow: hidden; 67 | padding: 0 1.5em; 68 | text-overflow: ellipsis; 69 | white-space: nowrap; 70 | } 71 | 72 | .variaboard-panel-is-collapsed .variaboard-title { 73 | margin-bottom: 0; 74 | } 75 | 76 | /** 77 | * Controls 78 | */ 79 | 80 | .variaboard-controls { 81 | } 82 | 83 | .variaboard-panel-is-collapsed .variaboard-controls { 84 | display: none; 85 | } 86 | 87 | /** 88 | * Control 89 | */ 90 | 91 | .variaboard-control { 92 | border-left: 3px solid #444; 93 | display: flex; 94 | height: 28px; 95 | margin-bottom: 1px; 96 | transition: background 200ms, border-color 200ms; 97 | } 98 | 99 | .variaboard-control:hover { 100 | border-left-color: #666; 101 | transition-duration: 0ms; 102 | } 103 | 104 | .variaboard-control:last-child { 105 | margin-bottom: 0; 106 | } 107 | 108 | /** 109 | * Control Title 110 | */ 111 | 112 | .variaboard-control-title { 113 | align-items: center; 114 | background: #222; 115 | border-left: 1px solid #000; 116 | color: #bbb; 117 | cursor: pointer; 118 | display: flex; 119 | flex: 0 0 110px; 120 | font-size: 0.8em; 121 | font-weight: 400; 122 | justify-content: flex-end; 123 | line-height: 1; 124 | margin: 0 1px 0 0; 125 | overflow: hidden; 126 | padding: 0.6em 0.75em; 127 | text-align: right; 128 | text-overflow: ellipsis; 129 | transition: color 200ms; 130 | white-space: nowrap; 131 | } 132 | 133 | .variaboard-control:hover .variaboard-control-title { 134 | color: #fff; 135 | transition-duration: 0ms; 136 | } 137 | 138 | /** 139 | * Control Checkbox 140 | */ 141 | 142 | .variaboard-control-checkbox-wrap { 143 | align-items: center; 144 | background: #111; 145 | border: 1px solid #111; 146 | cursor: pointer; 147 | display: flex; 148 | flex: 0 0 80px; 149 | margin: 0 1px 0 0; 150 | padding: 0 0.6em; 151 | position: relative; 152 | } 153 | 154 | .variaboard-control-checkbox { 155 | cursor: pointer; 156 | opacity: 0; 157 | position: absolute 158 | } 159 | 160 | .variaboard-control-checkbox-indicator { 161 | align-items: center; 162 | background: none; 163 | border: 1px solid #333; 164 | cursor: pointer; 165 | display: flex; 166 | height: 1.2em; 167 | justify-content: center; 168 | transition: background 200ms; 169 | width: 1.2em; 170 | } 171 | 172 | .variaboard-control-checkbox-indicator:before { 173 | color: #bbb; 174 | content: '\2713'; 175 | font-size: 0.8em; 176 | opacity: 0; 177 | transition: color 200ms, opacity 200ms; 178 | } 179 | 180 | .variaboard-control.variaboard-control-is-focused .variaboard-control-checkbox-indicator { 181 | border-color: #fff; 182 | } 183 | 184 | .variaboard-control-checkbox:checked ~ .variaboard-control-checkbox-indicator { 185 | background: #222; 186 | } 187 | 188 | .variaboard-control-checkbox:checked ~ .variaboard-control-checkbox-indicator:before { 189 | opacity: 1; 190 | } 191 | 192 | .variaboard-control:hover .variaboard-control-checkbox:checked ~ .variaboard-control-checkbox-indicator:before { 193 | color: #fff; 194 | } 195 | 196 | .variaboard-control.variaboard-control-is-focused .variaboard-control-checkbox:checked ~ .variaboard-control-checkbox-indicator:before { 197 | color: #fff; 198 | } 199 | 200 | .variaboard-control-title:active ~ .variaboard-control-checkbox-wrap .variaboard-control-checkbox-indicator, 201 | .variaboard-control-checkbox-wrap:active .variaboard-control-checkbox-indicator { 202 | border-color: #fff; 203 | } 204 | 205 | .variaboard-control-checkbox-stub { 206 | background: #111; 207 | flex: 1 1 auto; 208 | } 209 | 210 | /** 211 | * Control Value 212 | */ 213 | 214 | .variaboard-control-value-wrap { 215 | flex: 0 0 80px; 216 | margin: 0 1px 0 0; 217 | } 218 | 219 | .variaboard-control-value { 220 | background: #111; 221 | border: 1px solid #111; 222 | border-radius: 0; 223 | color: #bbb; 224 | font-family: inherit; 225 | font-size: 0.8em; 226 | font-weight: 400; 227 | height: 100%; 228 | line-height: 1; 229 | margin: 0; 230 | padding: 0.6em 0.75em; 231 | transition: color 200ms, border-color 200ms; 232 | width: 100%; 233 | -webkit-appearance: none; 234 | } 235 | 236 | .variaboard-control:hover .variaboard-control-value { 237 | color: #fff; 238 | transition-duration: 0ms; 239 | } 240 | 241 | .variaboard-control-value:focus { 242 | border-color: #fff; 243 | color: #fff; 244 | outline: none; 245 | transition-duration: 0ms; 246 | } 247 | 248 | /** 249 | * Button 250 | */ 251 | 252 | .variaboard-button { 253 | align-items: center; 254 | background: linear-gradient(#333 50%, #222 50%); 255 | border: none; 256 | border-left: 1px solid #000; 257 | border-radius: 0; 258 | color: #bbb; 259 | cursor: pointer; 260 | display: flex; 261 | font-family: inherit; 262 | font-size: 0.8em; 263 | font-weight: 700; 264 | height: 100%; 265 | line-height: 1; 266 | margin: 0; 267 | padding: 0 1.5em; 268 | position: relative; 269 | text-align: left; 270 | text-decoration: none; 271 | transition: color 200ms; 272 | width: 100%; 273 | -webkit-appearance: none; 274 | } 275 | 276 | .variaboard-button:after { 277 | background: #fff; 278 | bottom: 0; 279 | content: ''; 280 | left: 0; 281 | opacity: 0; 282 | position: absolute; 283 | right: 0; 284 | top: 0; 285 | transition: opacity 200ms; 286 | } 287 | 288 | .variaboard-button:hover { 289 | color: #fff; 290 | transition-duration: 0ms; 291 | } 292 | 293 | .variaboard-button:active { 294 | transition-duration: 0ms; 295 | } 296 | 297 | .variaboard-button:active:after { 298 | opacity: 0.3; 299 | transition-duration: 0ms; 300 | } 301 | 302 | .variaboard-button:focus { 303 | box-shadow: inset 0 0 0 1px #fff; 304 | outline: none; 305 | } 306 | 307 | /** 308 | * Control Range 309 | */ 310 | 311 | .variaboard-control-range { 312 | background: #111; 313 | cursor: ew-resize; 314 | cursor: grab; 315 | flex: 1 1 auto; 316 | overflow: hidden; 317 | position: relative; 318 | } 319 | 320 | .variaboard-control.variaboard-control-is-dragging .variaboard-control-range { 321 | cursor: ew-resize; 322 | cursor: grabbing; 323 | } 324 | 325 | .variaboard-control-range-inner { 326 | background: #222; 327 | height: 101%; 328 | left: 0; 329 | position: absolute; 330 | right: 1px; 331 | top: 0; 332 | transform: translateX(-100%); 333 | transition: background 200ms, transform 300ms cubic-bezier(0.19, 1, 0.22, 1); 334 | } 335 | 336 | .variaboard-control-range-inner:after { 337 | background: linear-gradient(#999, #444); 338 | bottom: 0; 339 | content: ''; 340 | left: 100%; 341 | position: absolute; 342 | top: 0; 343 | transition: background 200ms; 344 | width: 1px; 345 | } 346 | 347 | .variaboard-control.variaboard-control-eased .variaboard-control-range-inner { 348 | transition: background 200ms; 349 | } 350 | 351 | .variaboard-control:hover .variaboard-control-range-inner { 352 | background: #333; 353 | transition-duration: 0ms; 354 | } 355 | 356 | .variaboard-control.variaboard-control-is-dragging .variaboard-control-range-inner { 357 | transition-duration: 0ms; 358 | } 359 | -------------------------------------------------------------------------------- /src/js/button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Create a button 5 | */ 6 | 7 | class Button { 8 | 9 | constructor(variaboard, config) { 10 | this.variaboard = variaboard; 11 | this.id = config.id; 12 | this.title = config.title; 13 | this.description = config.description !== undefined ? config.description : null; 14 | this.callback = config.callback !== undefined ? config.callback : () => {}; 15 | 16 | this.createDOM(); 17 | this.listen(); 18 | } 19 | 20 | /** 21 | * Create necessary DOM elements 22 | */ 23 | 24 | createDOM() { 25 | this.dom = {}; 26 | 27 | // control 28 | this.dom.control = document.createElement('div'); 29 | this.dom.control.classList.add(`${this.variaboard.namespace}-control`); 30 | 31 | // button 32 | this.dom.button = document.createElement('a'); 33 | this.dom.button.classList.add(`${this.variaboard.namespace}-button`); 34 | this.dom.button.textContent = this.title; 35 | if(this.description) { 36 | this.dom.control.setAttribute('title', `${this.title}: ${this.description}`); 37 | } else { 38 | this.dom.control.setAttribute('title', `${this.title}`); 39 | } 40 | this.dom.control.appendChild(this.dom.button); 41 | 42 | // add to control to panel 43 | this.variaboard.dom.controls.appendChild(this.dom.control); 44 | } 45 | 46 | /** 47 | * Setup event listeners 48 | */ 49 | 50 | listen() { 51 | this.dom.button.addEventListener('click', (e) => this.onButtonClick(e)); 52 | } 53 | 54 | /** 55 | * On button click event 56 | * 57 | * @param {object} e - Event object 58 | */ 59 | 60 | onButtonClick(e) { 61 | this.callback(e, this, this.variaboard); 62 | } 63 | 64 | } 65 | 66 | module.exports = Button; 67 | -------------------------------------------------------------------------------- /src/js/controls/boolean-control.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Control = require('./control'); 4 | const Calc = require('../util/calc'); 5 | 6 | class BooleanControl extends Control { 7 | 8 | constructor(variaboard, config) { 9 | super(); 10 | 11 | this.type = 'boolean'; 12 | this.variaboard = variaboard; 13 | this.id = config.id; 14 | this.title = config.title; 15 | this.description = config.description !== undefined ? config.description : null; 16 | this.default = config.default; 17 | this.randomizable = config.randomizable !== undefined ? config.randomizable : true; 18 | this.mutable = config.mutable !== undefined ? config.mutable : true; 19 | this.locked = config.locked !== undefined ? config.locked : false; 20 | this.suffix = config.suffix !== undefined ? config.suffix : ''; 21 | this.isFocused = false; 22 | this.createDOM(); 23 | this.listen(); 24 | this.set(this.default, true, false); 25 | 26 | } 27 | 28 | createDOM() { 29 | this.dom = {}; 30 | 31 | // control 32 | this.dom.control = document.createElement('div'); 33 | this.dom.control.classList.add(`${this.variaboard.namespace}-control`); 34 | 35 | // title 36 | this.dom.title = document.createElement('label'); 37 | this.dom.title.classList.add(`${this.variaboard.namespace}-control-title`); 38 | this.dom.title.textContent = this.title; 39 | this.dom.title.setAttribute('for', `${this.variaboard.namespace}-${this.id}-${this.variaboard.id}`); 40 | this.dom.control.appendChild(this.dom.title); 41 | 42 | // checkbox wrap 43 | this.dom.checkboxWrap = document.createElement('div'); 44 | this.dom.checkboxWrap.classList.add(`${this.variaboard.namespace}-control-checkbox-wrap`); 45 | this.dom.control.appendChild(this.dom.checkboxWrap); 46 | 47 | // checkbox 48 | this.dom.checkbox = document.createElement('input'); 49 | this.dom.checkbox.classList.add(`${this.variaboard.namespace}-control-checkbox`); 50 | this.dom.checkbox.setAttribute('type', 'checkbox'); 51 | this.dom.checkbox.setAttribute('id', `${this.variaboard.namespace}-${this.id}-${this.variaboard.id}`); 52 | this.dom.checkboxWrap.appendChild(this.dom.checkbox); 53 | 54 | // checkbox indicator 55 | this.dom.checkboxIndicator = document.createElement('div'); 56 | this.dom.checkboxIndicator.classList.add(`${this.variaboard.namespace}-control-checkbox-indicator`); 57 | this.dom.checkboxWrap.appendChild(this.dom.checkboxIndicator); 58 | 59 | // checkbox indicator 60 | this.dom.checkboxStub = document.createElement('div'); 61 | this.dom.checkboxStub.classList.add(`${this.variaboard.namespace}-control-checkbox-stub`); 62 | this.dom.control.appendChild(this.dom.checkboxStub); 63 | 64 | // add control to panel 65 | this.variaboard.dom.controls.appendChild(this.dom.control); 66 | } 67 | 68 | listen() { 69 | this.dom.checkbox.addEventListener('change', (e) => this.onCheckboxChange(e)); 70 | this.dom.checkbox.addEventListener('focus', (e) => this.onValueFocus(e)); 71 | this.dom.checkbox.addEventListener('blur', (e) => this.onValueBlur(e)); 72 | this.dom.checkboxWrap.addEventListener('click', (e) => this.onCheckboxWrapClick(e)); 73 | } 74 | 75 | onCheckboxChange() { 76 | this.set(this.dom.checkbox.checked); 77 | } 78 | 79 | onValueFocus() { 80 | this.isFocused = true; 81 | this.dom.control.classList.add(`${this.variaboard.namespace}-control-is-focused`); 82 | } 83 | 84 | onValueBlur() { 85 | this.isFocused = false; 86 | this.dom.control.classList.remove(`${this.variaboard.namespace}-control-is-focused`); 87 | } 88 | 89 | onCheckboxWrapClick() { 90 | this.dom.checkbox.focus(); 91 | this.set(!this.dom.checkbox.checked); 92 | } 93 | 94 | randomize() { 95 | if(this.locked) { 96 | return; 97 | } 98 | 99 | let val = Math.random() > 0.5 ? true : false; 100 | this.set(val); 101 | 102 | this.dom.control.classList.add(`${this.variaboard.namespace}-control-randomizing`); 103 | void this.dom.control.offsetWidth; 104 | this.dom.control.classList.remove(`${this.variaboard.namespace}-control-randomizing`); 105 | } 106 | 107 | mutate() { 108 | if(this.locked) { 109 | return; 110 | } 111 | 112 | let val = Math.random() > 0.5 ? true : false; 113 | this.set(val); 114 | 115 | this.dom.control.classList.add(`${this.variaboard.namespace}-control-mutating`); 116 | void this.dom.control.offsetWidth; 117 | this.dom.control.classList.remove(`${this.variaboard.namespace}-control-mutating`); 118 | } 119 | 120 | lock() { 121 | this.locked = true; 122 | } 123 | 124 | unlock() { 125 | this.locked = false; 126 | } 127 | 128 | set(val, force = false, triggerChange = true) { 129 | // exit out if the value hasn't changed and it is not forced 130 | if(val === this.value && !force) { 131 | return; 132 | } 133 | 134 | // set the new value 135 | this.value = val; 136 | 137 | // set checkbox value 138 | this.dom.checkbox.checked = this.value; 139 | 140 | // set the title attribute for the control 141 | let title = `${this.title}: ${this.value}${this.suffix}`; 142 | if(this.description) { 143 | title = `${this.title}: ${this.value}${this.suffix}\n${this.description}`; 144 | } 145 | this.dom.control.setAttribute('title', title); 146 | 147 | // queue up change callback 148 | if(triggerChange) { 149 | window.cancelAnimationFrame(this.variaboard.changeRaf); 150 | this.variaboard.changeRaf = window.requestAnimationFrame(this.variaboard.changeCallback.bind(this.variaboard)); 151 | } 152 | } 153 | 154 | } 155 | 156 | module.exports = BooleanControl; 157 | -------------------------------------------------------------------------------- /src/js/controls/control.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Create a control 5 | */ 6 | 7 | class Control { 8 | 9 | constructor() { 10 | } 11 | 12 | } 13 | 14 | module.exports = Control; 15 | -------------------------------------------------------------------------------- /src/js/controls/range-control.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Control = require('./control'); 4 | const Calc = require('../util/calc'); 5 | const Ease = require('../util/ease'); 6 | 7 | /** 8 | * Create a range control 9 | * 10 | * @param {object} variaboard - Reference to parent VariaBoard instance 11 | * @param {object} config - Configuration object 12 | * @param {string} config.id - Unique id/slug 13 | * @param {string} config.title - UI display title 14 | * @param {number} config.min - Minimum value 15 | * @param {number} config.max - Maximum value 16 | * @param {number} config.step - Step size 17 | * @param {number} config.default - Starting value 18 | * @param {boolean} config.randomizable - Can be randomized individually and by randomizing all 19 | * @param {boolean} config.mutable - Can be mutated individually and by mutating all 20 | * @param {boolean} config.locked - Temporarily toggle whether the control is affected by randomization and mutation 21 | * @param {boolean} config.eased - When randomizing or mutating a value, animate the value with eased 22 | * 23 | * @extends Control 24 | * 25 | * @requires {@link Control} 26 | * @requires {@link Calc} 27 | */ 28 | 29 | class RangeControl extends Control { 30 | 31 | constructor(variaboard, config) { 32 | super(); 33 | 34 | this.type = 'range'; 35 | this.variaboard = variaboard; 36 | this.id = config.id; 37 | this.title = config.title; 38 | this.description = config.description !== undefined ? config.description : null; 39 | this.default = config.default; 40 | this.randomizable = config.randomizable !== undefined ? config.randomizable : true; 41 | this.mutable = config.mutable !== undefined ? config.mutable : true; 42 | this.locked = config.locked !== undefined ? config.locked : false; 43 | this.suffix = config.suffix !== undefined ? config.suffix : ''; 44 | this.min = config.min; 45 | this.max = config.max; 46 | this.size = this.max - this.min; 47 | this.step = config.step !== undefined ? Math.abs(config.step) : 1; 48 | this.eased = config.eased !== undefined ? config.eased : true; 49 | this.easedDuration = config.easedDuration !== undefined ? config.easedDuration : 300; 50 | this.easedFunc = config.easedFunc !== undefined ? Ease[config.easedFunc] : Ease['outExpo']; 51 | this.places = this.step.toString().indexOf('.') > -1 ? this.step.toString().split('.')[1].length : 0; 52 | 53 | this.easedValueStart = this.default; 54 | this.easedValueTarget = this.default; 55 | this.easedTime = null; 56 | this.easedLastTime = null; 57 | this.easedElapsedTime = 0; 58 | 59 | this.isMouseDown = false; 60 | this.settled = false; 61 | this.isFocused = false; 62 | 63 | this.createDOM(); 64 | 65 | this.onWindowResize(); 66 | 67 | this.listen(); 68 | this.set(this.default, true, false); 69 | } 70 | 71 | createDOM() { 72 | this.dom = {}; 73 | 74 | // control 75 | this.dom.control = document.createElement('div'); 76 | this.dom.control.classList.add(`${this.variaboard.namespace}-control`); 77 | if(this.eased) { 78 | this.dom.control.classList.add(`${this.variaboard.namespace}-control-eased`); 79 | } 80 | 81 | // title 82 | this.dom.title = document.createElement('label'); 83 | this.dom.title.classList.add(`${this.variaboard.namespace}-control-title`); 84 | this.dom.title.textContent = this.title; 85 | this.dom.title.setAttribute('for', `${this.variaboard.namespace}-${this.id}-${this.variaboard.id}`); 86 | this.dom.control.appendChild(this.dom.title); 87 | 88 | // value wrap 89 | this.dom.valueWrap = document.createElement('div'); 90 | this.dom.valueWrap.classList.add(`${this.variaboard.namespace}-control-value-wrap`); 91 | this.dom.control.appendChild(this.dom.valueWrap); 92 | 93 | // value 94 | this.dom.value = document.createElement('input'); 95 | this.dom.value.classList.add(`${this.variaboard.namespace}-control-value`); 96 | this.dom.value.setAttribute('id', `${this.variaboard.namespace}-${this.id}-${this.variaboard.id}`); 97 | this.dom.valueWrap.appendChild(this.dom.value); 98 | 99 | // add control to panel 100 | this.variaboard.dom.controls.appendChild(this.dom.control); 101 | 102 | // range 103 | this.dom.range = document.createElement('div'); 104 | this.dom.range.classList.add(`${this.variaboard.namespace}-control-range`); 105 | 106 | // range inner 107 | this.dom.rangeInner = document.createElement('div'); 108 | this.dom.rangeInner.classList.add(`${this.variaboard.namespace}-control-range-inner`); 109 | this.dom.range.appendChild(this.dom.rangeInner); 110 | 111 | this.dom.control.appendChild(this.dom.range); 112 | } 113 | 114 | listen() { 115 | this.dom.value.addEventListener('change', (e) => this.onValueChange(e)); 116 | this.dom.value.addEventListener('focus', (e) => this.onValueFocus(e)); 117 | this.dom.value.addEventListener('blur', (e) => this.onValueBlur(e)); 118 | this.dom.value.addEventListener('keydown', (e) => this.onValueKeydown(e)); 119 | this.dom.value.addEventListener('wheel', (e) => this.onValueMousewheel(e)); 120 | 121 | this.dom.range.addEventListener('mousedown', (e) => this.onRangeMousedown(e)); 122 | } 123 | 124 | onValueChange() { 125 | this.set(this.dom.value.value); 126 | this.easedValueTarget = this.value; 127 | } 128 | 129 | onValueFocus() { 130 | this.isFocused = true; 131 | } 132 | 133 | onValueBlur() { 134 | this.isFocused = false; 135 | } 136 | 137 | onValueKeydown(e) { 138 | let change = e.shiftKey ? this.step * 4 : this.step; 139 | switch(e.which) { 140 | case 38: 141 | this.set(this.value + change); 142 | break; 143 | case 40: 144 | this.set(this.value - change); 145 | break; 146 | } 147 | } 148 | 149 | onValueMousewheel(e) { 150 | if(this.isFocused) { 151 | let change = e.shiftKey ? this.step * 4 : this.step; 152 | if(e.wheelDelta < 0) { 153 | this.set(this.value - change); 154 | } else if(e.wheelDelta > 0) { 155 | this.set(this.value + change); 156 | } 157 | } 158 | } 159 | 160 | onRangeMousedown(e) { 161 | this.variaboard.onDragStart(); 162 | this.variaboard.mouse.down = true; 163 | this.variaboard.mouse.anchor.x = e.clientX; 164 | this.variaboard.mouse.anchor.y = e.clientY; 165 | this.isMouseDown = true; 166 | this.dom.control.classList.add(`${this.variaboard.namespace}-control-is-dragging`); 167 | this.setDragValue(); 168 | } 169 | 170 | onWindowMouseup() { 171 | this.variaboard.onDragEnd(); 172 | this.isMouseDown = false; 173 | this.dom.control.classList.remove(`${this.variaboard.namespace}-control-is-dragging`); 174 | } 175 | 176 | onWindowMousemove() { 177 | if(this.isMouseDown) { 178 | this.setDragValue(); 179 | } 180 | } 181 | 182 | onWindowResize() { 183 | this.bcr = this.dom.range.getBoundingClientRect(); 184 | } 185 | 186 | randomize() { 187 | if(this.locked) { 188 | return; 189 | } 190 | 191 | let val = Calc.roundToNearestInterval(Calc.rand(this.min, this.max), this.step); 192 | if(this.eased) { 193 | this.easeSet(val); 194 | } else { 195 | this.set(val); 196 | } 197 | 198 | this.dom.control.classList.add(`${this.variaboard.namespace}-control-randomizing`); 199 | void this.dom.control.offsetWidth; 200 | this.dom.control.classList.remove(`${this.variaboard.namespace}-control-randomizing`); 201 | } 202 | 203 | mutate() { 204 | if(this.locked) { 205 | return; 206 | } 207 | 208 | let size = Math.max(this.size / 15, this.step); 209 | let val = null; 210 | if(this.value === this.min) { 211 | val = this.value + Calc.rand(0, size); 212 | } else if(this.value === this.max) { 213 | val = this.value + Calc.rand(-size, 0); 214 | } else { 215 | val = this.value + Calc.rand(-size, size); 216 | } 217 | 218 | if(this.eased) { 219 | this.easeSet(val); 220 | } else { 221 | this.set(val); 222 | } 223 | 224 | this.dom.control.classList.add(`${this.variaboard.namespace}-control-mutating`); 225 | void this.dom.control.offsetWidth; 226 | this.dom.control.classList.remove(`${this.variaboard.namespace}-control-mutating`); 227 | } 228 | 229 | lock() { 230 | this.locked = true; 231 | } 232 | 233 | unlock() { 234 | this.locked = false; 235 | } 236 | 237 | setDragValue() { 238 | this.set(Calc.map(this.variaboard.mouse.x, this.bcr.left, this.bcr.right, this.min, this.max)); 239 | this.easedValueTarget = this.value; 240 | } 241 | 242 | easeSet(val) { 243 | this.easedTime = null; 244 | this.easedLastTime = null; 245 | this.easedElapsedTime = 0; 246 | this.easedValueStart = this.value; 247 | this.easedValueTarget = val; 248 | this.settled = false; 249 | window.cancelAnimationFrame(this.variaboard.raf); 250 | this.variaboard.update(); 251 | } 252 | 253 | easeUpdate() { 254 | this.easedTime = Date.now(); 255 | if(this.easedLastTime !== null) { 256 | this.easedElapsedTime += this.easedTime - this.easedLastTime; 257 | this.easedElapsedTime = Calc.clamp(this.easedElapsedTime, 0, this.easedDuration); 258 | } 259 | this.easedLastTime = this.easedTime; 260 | 261 | if(this.easedElapsedTime < this.easedDuration) { 262 | this.set(Calc.map(this.easedFunc(this.easedElapsedTime, 0, 1, this.easedDuration), 0, 1, this.easedValueStart, this.easedValueTarget)); 263 | } else { 264 | this.easedTime = null; 265 | this.easedLastTime = null; 266 | this.easedElapsedTime = 0; 267 | this.settled = true; 268 | this.set(this.easedValueTarget); 269 | } 270 | } 271 | 272 | set(val, force = false, triggerChange = true) { 273 | // sanitize value 274 | val = parseFloat(val); 275 | val = isNaN(val) ? this.default : val; 276 | val = Calc.clamp(val, this.min, this.max); 277 | val = Calc.roundToNearestInterval(val, this.step); 278 | 279 | // exit out if the value hasn't changed and it is not forced 280 | if(val === this.value && !force) { 281 | // replace what a user has typed, if they did 282 | this.dom.value.value = this.value.toFixed(this.places); 283 | return; 284 | } 285 | 286 | // set the new value 287 | this.value = val; 288 | 289 | // set input value 290 | this.dom.value.value = this.value.toFixed(this.places); 291 | 292 | // set range value 293 | this.dom.rangeInner.style.transform = `translateX(${Calc.map(this.value, this.min, this.max, -100, 0)}%)`; 294 | 295 | // set the title attribute for the control 296 | let title = `${this.title}: ${this.value.toFixed(this.places)}${this.suffix}`; 297 | if(this.description) { 298 | title = `${this.title}: ${this.value.toFixed(this.places)}${this.suffix}\n${this.description}`; 299 | } 300 | this.dom.control.setAttribute('title', title); 301 | 302 | // queue up change callback 303 | if(triggerChange) { 304 | window.cancelAnimationFrame(this.variaboard.changeRaf); 305 | this.variaboard.changeRaf = window.requestAnimationFrame(this.variaboard.changeCallback.bind(this.variaboard)); 306 | } 307 | } 308 | 309 | } 310 | 311 | module.exports = RangeControl; 312 | -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Button = require('./button'); 4 | const RangeControl = require('./controls/range-control'); 5 | const BooleanControl = require('./controls/boolean-control'); 6 | 7 | class VariaBoard { 8 | 9 | /** 10 | * Create a VariaBoard control panel 11 | * 12 | * @param {object} config - Configuration object 13 | * @param {object|string} [config.container=document.body] - DOM element or CSS selector 14 | * @param {string} [config.title] - Title of the panel 15 | * 16 | * @requires {@link Button} 17 | * @requires {@link Range} 18 | */ 19 | 20 | constructor(config) { 21 | this.namespace = 'variaboard'; 22 | this.id = Math.random().toString(36).substr(2, 8); 23 | this.controls = {}; 24 | this.buttons = {}; 25 | 26 | this.mouse = { 27 | down: false, 28 | x: 0, 29 | y: 0, 30 | anchor: { 31 | x: 0, 32 | y: 0 33 | } 34 | }; 35 | 36 | this.needsUpdate = false; 37 | this.raf = null; 38 | this.isDragging = false; 39 | this.isCollapsed = false; 40 | 41 | this.changeRaf = null; 42 | 43 | this.container = config.container !== undefined ? config.container : document.body; 44 | this.class = config.class !== undefined ? config.class : null; 45 | this.title = config.title !== undefined ? config.title : null; 46 | this.changeCallback = config.changeCallback !== undefined ? config.changeCallback : () => {}; 47 | 48 | this.createDOM(); 49 | this.listen(); 50 | } 51 | 52 | /** 53 | * Create necessary DOM elements 54 | */ 55 | 56 | createDOM() { 57 | this.dom = {}; 58 | 59 | // container 60 | this.dom.container = this.container; 61 | 62 | // panel 63 | this.dom.panel = document.createElement('div'); 64 | this.dom.panel.classList.add(`${this.namespace}-panel`); 65 | if(this.class) { 66 | this.dom.panel.classList.add(this.class); 67 | } 68 | 69 | // title 70 | if(this.title) { 71 | this.dom.title = document.createElement('h1'); 72 | this.dom.title.classList.add(`${this.namespace}-title`); 73 | this.dom.title.textContent = this.title; 74 | this.dom.title.setAttribute('title', `${this.title}: Click to toggle visibility`); 75 | this.dom.panel.appendChild(this.dom.title); 76 | } 77 | 78 | // controls 79 | this.dom.controls = document.createElement('div'); 80 | this.dom.controls.classList.add(`${this.namespace}-controls`); 81 | this.dom.panel.appendChild(this.dom.controls); 82 | 83 | // add panel to container 84 | this.dom.container.appendChild(this.dom.panel); 85 | } 86 | 87 | /** 88 | * Setup event listeners 89 | */ 90 | 91 | listen() { 92 | window.addEventListener('mouseup', (e) => this.onWindowMouseup(e)); 93 | window.addEventListener('mousemove', (e) => this.onWindowMousemove(e)); 94 | window.addEventListener('resize', () => this.onWindowResize()); 95 | 96 | this.dom.title.addEventListener('click', () => this.onTitleClick()); 97 | } 98 | 99 | /** 100 | * On window mouse up event 101 | * 102 | * @param {object} e - Event object 103 | */ 104 | 105 | onWindowMouseup(e) { 106 | this.mouse.down = false; 107 | for(let key in this.controls) { 108 | let control = this.controls[key]; 109 | if(control && control.type === 'range') { 110 | control.onWindowMouseup(e); 111 | } 112 | } 113 | } 114 | 115 | /** 116 | * On window mouse move event 117 | * 118 | * @param {object} e - Event object 119 | */ 120 | 121 | onWindowMousemove(e) { 122 | this.mouse.x = e.clientX; 123 | this.mouse.y = e.clientY; 124 | for(let key in this.controls) { 125 | let control = this.controls[key]; 126 | if(control && control.type === 'range') { 127 | control.onWindowMousemove(e); 128 | } 129 | } 130 | } 131 | 132 | /** 133 | * On window resize event 134 | */ 135 | 136 | onWindowResize() { 137 | for(let key in this.controls) { 138 | let control = this.controls[key]; 139 | if(control && control.type === 'range') { 140 | control.onWindowResize(); 141 | } 142 | } 143 | } 144 | 145 | onTitleClick() { 146 | if(this.isCollapsed) { 147 | this.dom.panel.classList.remove(`${this.namespace}-panel-is-collapsed`); 148 | this.isCollapsed = false; 149 | } else { 150 | this.dom.panel.classList.add(`${this.namespace}-panel-is-collapsed`); 151 | this.isCollapsed = true; 152 | } 153 | } 154 | 155 | onDragStart() { 156 | this.isDragging = true; 157 | this.dom.panel.classList.add(`${this.namespace}-is-dragging`); 158 | } 159 | 160 | onDragEnd() { 161 | this.isDragging = false; 162 | this.dom.panel.classList.remove(`${this.namespace}-is-dragging`); 163 | } 164 | 165 | /** 166 | * Update based on requestAnimationFrame() 167 | */ 168 | 169 | update() { 170 | this.needsUpdate = false; 171 | for(let key in this.controls) { 172 | if(this.controls[key].type === 'range') { 173 | if(!this.controls[key].settled) { 174 | this.needsUpdate = true; 175 | this.controls[key].easeUpdate(); 176 | } 177 | } 178 | } 179 | 180 | if(this.needsUpdate) { 181 | this.raf = window.requestAnimationFrame(() => this.update()); 182 | } 183 | } 184 | 185 | /** 186 | * Add a button 187 | * 188 | * @param {object} config - Configuration object 189 | * @param {object} config.id - ID slug 190 | * @param {object} config.title - Title text 191 | * @param {object} [config.callback=() => {}] - Callback function for button press 192 | * 193 | * @returns {object} Button object 194 | */ 195 | 196 | addButton(config) { 197 | this.buttons[config.id] = new Button(this, config); 198 | return this; 199 | } 200 | 201 | /** 202 | * Add a range control via {@linkcode Range} 203 | * 204 | * @param {object} config - Configuration object 205 | * @param {string} config.id - Unique id/slug 206 | * @param {string} config.title - UI display title 207 | * @param {number} config.min - Minimum value 208 | * @param {number} config.max - Maximum value 209 | * @param {number} config.step - Step size 210 | * @param {number} config.default - Starting value 211 | * @param {boolean} config.randomizable - Can be randomized individually and by randomizing all 212 | * @param {boolean} config.mutable - Can be mutated individually and by mutating all 213 | * @param {boolean} config.locked - Temporarily toggle whether the control is affected by randomization and mutation 214 | * 215 | * @returns {object} Range object 216 | */ 217 | 218 | addRange(config) { 219 | this.controls[config.id] = new RangeControl(this, config); 220 | return this; 221 | } 222 | 223 | addBoolean(config) { 224 | this.controls[config.id] = new BooleanControl(this, config); 225 | return this; 226 | } 227 | 228 | get(id) { 229 | let control = this.controls[id]; 230 | if(control) { 231 | return control.value; 232 | } 233 | } 234 | 235 | set(id, val) { 236 | let control = this.controls[id]; 237 | if(control) { 238 | if(control.eased) { 239 | control.easeSet(val); 240 | } else { 241 | control.set(val); 242 | } 243 | } 244 | } 245 | 246 | reset() { 247 | for(let key in this.controls) { 248 | let control = this.controls[key]; 249 | if(control.eased) { 250 | control.easeSet(control.default); 251 | } else { 252 | control.set(control.default); 253 | } 254 | } 255 | } 256 | 257 | randomize() { 258 | for(let key in this.controls) { 259 | this.controls[key].randomize(); 260 | } 261 | } 262 | 263 | mutate() { 264 | for(let key in this.controls) { 265 | this.controls[key].mutate(); 266 | } 267 | } 268 | 269 | } 270 | 271 | module.exports = VariaBoard; 272 | -------------------------------------------------------------------------------- /src/js/util/calc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Calculation functions and helpers 5 | */ 6 | 7 | class Calc { 8 | 9 | /** 10 | * Get a random float within a range. If only one argument is passed, it is used as the max and the min becomes zero. 11 | * 12 | * @param {number} min - Minimum range value 13 | * @param {number} max - Maximum range value 14 | * 15 | * @example 16 | * // two arguments 17 | * Calc.rand(2, 18); 18 | * // -> random float between 2 and 18 19 | * 20 | * // single argument 21 | * Calc.rand(42.5); 22 | * // -> random float between 0 and 42.5 23 | * 24 | * @returns {number} Random float within the range 25 | */ 26 | static rand(min, max) { 27 | if(max === undefined) { 28 | max = min; 29 | min = 0; 30 | } 31 | return Math.random() * (max - min) + min; 32 | } 33 | 34 | /** 35 | * Clamp a value to a range 36 | * 37 | * @param {number} val - Input value 38 | * @param {number} min - Minimum range value 39 | * @param {number} max - Maximum range value 40 | * 41 | * @example 42 | * Calc.clamp(3, 10, 150); 43 | * // -> 10 44 | * 45 | * Calc.clamp(400, 10, 150); 46 | * // -> 150 47 | * 48 | * Calc.clamp(75, 10, 100); 49 | * // -> 75 50 | * 51 | * @returns {number} Clamped value within range 52 | */ 53 | 54 | static clamp(val, min, max) { 55 | return Math.max(Math.min(val, max), min); 56 | } 57 | 58 | static map(val, inMin, inMax, outMin, outMax) { 59 | return ((outMax - outMin) * ((val - inMin) / (inMax - inMin))) + outMin; 60 | } 61 | 62 | static roundToNearestInterval(value, interval) { 63 | return Math.round(value / interval) * interval; 64 | } 65 | 66 | } 67 | 68 | module.exports = Calc; 69 | --------------------------------------------------------------------------------