vendor: 4,306 bytes, lines 1-152
1// modules are defined as an array 2// [ module function, map of requires ] 3// 4// map of requires is short require name -> numeric require 5// 6// anything defined in a previous bundle is accessed via the 7// orig method which is the require for previous bundles 8parcelRequire = (function (modules, cache, entry, globalName) { 9 // Save the require from previous bundle to this closure if any 10 var previousRequire = typeof parcelRequire === 'function' && parcelRequire; 11 var nodeRequire = typeof require === 'function' && require; 12 13 function newRequire(name, jumped) { 14 if (!cache[name]) { 15 if (!modules[name]) { 16 // if we cannot find the module within our internal map or 17 // cache jump to the current global require ie. the last bundle 18 // that was added to the page. 19 var currentRequire = typeof parcelRequire === 'function' && parcelRequire; 20 if (!jumped && currentRequire) { 21 return currentRequire(name, true); 22 } 23 24 // If there are other bundles on this page the require from the 25 // previous one is saved to 'previousRequire'. Repeat this as 26 // many times as there are bundles until the module is found or 27 // we exhaust the require chain. 28 if (previousRequire) { 29 return previousRequire(name, true); 30 } 31 32 // Try the node require function if it exists. 33 if (nodeRequire && typeof name === 'string') { 34 return nodeRequire(name); 35 } 36 37 var err = new Error('Cannot find module \'' + name + '\''); 38 err.code = 'MODULE_NOT_FOUND'; 39 throw err; 40 } 41 42 localRequire.resolve = resolve; 43 localRequire.cache = {}; 44 45 var module = cache[name] = new newRequire.Module(name); 46 47 modules[name][0].call(module.exports, localRequire, module, module.exports, this); 48 } 49 50 return cache[name].exports; 51 52 function localRequire(x){ 53 return newRequire(localRequire.resolve(x)); 54 } 55 56 function resolve(x){ 57 return modules[name][1][x] || x; 58 } 59 } 60 61 function Module(moduleName) { 62 this.id = moduleName; 63 this.bundle = newRequire; 64 this.exports = {}; 65 } 66 67 newRequire.isParcelRequire = true; 68 newRequire.Module = Module; 69 newRequire.modules = modules; 70 newRequire.cache = cache; 71 newRequire.parent = previousRequire; 72 newRequire.register = function (id, exports) { 73 modules[id] = [function (require, module) { 74 module.exports = exports; 75 }, {}]; 76 }; 77 78 var error; 79 for (var i = 0; i < entry.length; i++) { 80 try { 81 newRequire(entry[i]); 82 } catch (e) { 83 // Save first error but execute all entries 84 if (!error) { 85 error = e; 86 } 87 } 88 } 89 90 if (entry.length) { 91 // Expose entry point to Node, AMD or browser globals 92 // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js 93 var mainExports = newRequire(entry[entry.length - 1]); 94 95 // CommonJS 96 if (typeof exports === "object" && typeof module !== "undefined") { 97 module.exports = mainExports; 98 99 // RequireJS 100 } else if (typeof define === "function" && define.amd) { 101 define(function () { 102 return mainExports; 103 }); 104 105 // <script> 106 } else if (globalName) { 107 this[globalName] = mainExports; 108 } 109 } 110 111 // Override the current require with this new one 112 parcelRequire = newRequire; 113 114 if (error) { 115 // throw error from earlier, _after updating parcelRequire_ 116 throw error; 117 } 118 119 return newRequire; 120})({"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/src/builtins/bundle-url.js":[function(require,module,exports) { 121var bundleURL = null; 122 123function getBundleURLCached() { 124 if (!bundleURL) { 125 bundleURL = getBundleURL(); 126 } 127 128 return bundleURL; 129} 130 131function getBundleURL() { 132 // Attempt to find the URL of the current script and use that as the base URL 133 try { 134 throw new Error(); 135 } catch (err) { 136 var matches = ('' + err.stack).match(/(https?|file|ftp|chrome-extension|moz-extension):\/\/[^)\n]+/g); 137 138 if (matches) { 139 return getBaseURL(matches[0]); 140 } 141 } 142 143 return '/'; 144} 145 146function getBaseURL(url) { 147 return ('' + url).replace(/^((?:https?|file|ftp|chrome-extension|moz-extension):\/\/.+)\/[^/]+$/, '$1') + '/'; 148} 149 150exports.getBundleURL = getBundleURLCached; 151exports.getBaseURL = getBaseURL; 152},{}
152],"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/src/builtins/css-loader.js":[function(require,module,exports) { 153var bundle = require('./bundle-url'); 154 155function updateLink(link) { 156 var newLink = link.cloneNode(); 157 158 newLink.onload = function () { 159 link.remove(); 160 }; 161 162 newLink.href = link.href.split('?')[0] + '?' + Date.now(); 163 link.parentNode.insertBefore(newLink, link.nextSibling); 164} 165 166var cssTimeout = null; 167 168function reloadCSS() { 169 if (cssTimeout) { 170 return; 171 } 172 173 cssTimeout = setTimeout(function () { 174 var links = document.querySelectorAll('link[rel="stylesheet"]'); 175 176 for (var i = 0; i < links.length; i++) { 177 if (bundle.getBaseURL(links[i].href) === bundle.getBundleURL()) { 178 updateLink(links[i]); 179 } 180 } 181 182 cssTimeout = null; 183 }, 50); 184} 185 186module.exports = reloadCSS; 187},{"./bundle-url":"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/src/builtins/bundle-url.js"}],"scss/style.scss":[function(require,module,exports) { 188var reloadCSS = require('_css_loader'); 189 190module.hot.dispose(reloadCSS); 191module.hot.accept(reloadCSS); 192},{"_css_loader":"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/src/builtins/css-loader.js"}],"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/base64-js/index.js":[function(require,module,exports) { 193'use strict' 194 195exports.byteLength = byteLength 196exports.toByteArray = toByteArray 197exports.fromByteArray = fromByteArray 198 199var lookup = [] 200var revLookup = [] 201var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array 202 203var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' 204for (var i = 0, len = code.length; i < len; ++i) { 205 lookup[i] = code[i] 206 revLookup[code.charCodeAt(i)] = i 207} 208 209// Support decoding URL-safe base64 strings, as Node.js does. 210// See: https://en.wikipedia.org/wiki/Base64#URL_applications 211revLookup['-'.charCodeAt(0)] = 62 212revLookup['_'.charCodeAt(0)] = 63 213 214function getLens (b64) { 215 var len = b64.length 216 217 if (len % 4 > 0) { 218 throw new Error('Invalid string. Length must be a multiple of 4') 219 } 220 221 // Trim off extra bytes after placeholder bytes are found 222 // See: https://github.com/beatgammit/base64-js/issues/42 223 var validLen = b64.indexOf('=') 224 if (validLen === -1) validLen = len 225 226 var placeHoldersLen = validLen === len 227 ? 0 228 : 4 - (validLen % 4) 229 230 return [validLen, placeHoldersLen] 231} 232 233// base64 is 4/3 + up to two characters of the original data 234function byteLength (b64) { 235 var lens = getLens(b64) 236 var validLen = lens[0] 237 var placeHoldersLen = lens[1] 238 return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen 239} 240 241function _byteLength (b64, validLen, placeHoldersLen) { 242 return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen 243} 244 245function toByteArray (b64) { 246 var tmp 247 var lens = getLens(b64) 248 var validLen = lens[0] 249 var placeHoldersLen = lens[1] 250 251 var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) 252 253 var curByte = 0 254 255 // if there are placeholders, only get up to the last complete 4 chars 256 var len = placeHoldersLen > 0 257 ? validLen - 4 258 : validLen 259 260 for (var i = 0; i < len; i += 4) { 261 tmp = 262 (revLookup[b64.charCodeAt(i)] << 18) | 263 (revLookup[b64.charCodeAt(i + 1)] << 12) | 264 (revLookup[b64.charCodeAt(i + 2)] << 6) | 265 revLookup[b64.charCodeAt(i + 3)] 266 arr[curByte++] = (tmp >> 16) & 0xFF 267 arr[curByte++] = (tmp >> 8) & 0xFF 268 arr[curByte++] = tmp & 0xFF 269 } 270 271 if (placeHoldersLen === 2) { 272 tmp = 273 (revLookup[b64.charCodeAt(i)] << 2) | 274 (revLookup[b64.charCodeAt(i + 1)] >> 4) 275 arr[curByte++] = tmp & 0xFF 276 } 277 278 if (placeHoldersLen === 1) { 279 tmp = 280 (revLookup[b64.charCodeAt(i)] << 10) | 281 (revLookup[b64.charCodeAt(i + 1)] << 4) | 282 (revLookup[b64.charCodeAt(i + 2)] >> 2) 283 arr[curByte++] = (tmp >> 8) & 0xFF 284 arr[curByte++] = tmp & 0xFF 285 } 286 287 return arr 288} 289 290function tripletToBase64 (num) { 291 return lookup[num >> 18 & 0x3F] + 292 lookup[num >> 12 & 0x3F] + 293 lookup[num >> 6 & 0x3F] + 294 lookup[num & 0x3F] 295} 296 297function encodeChunk (uint8, start, end) { 298 var tmp 299 var output = [] 300 for (var i = start; i < end; i += 3) { 301 tmp = 302 ((uint8[i] << 16) & 0xFF0000) + 303 ((uint8[i + 1] << 8) & 0xFF00) + 304 (uint8[i + 2] & 0xFF) 305 output.push(tripletToBase64(tmp)) 306 } 307 return output.join('') 308} 309 310function fromByteArray (uint8) { 311 var tmp 312 var len = uint8.length 313 var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes 314 var parts = [] 315 var maxChunkLength = 16383 // must be multiple of 3 316 317 // go through the array every three bytes, we'll deal with trailing stuff later 318 for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { 319 parts.push(encodeChunk( 320 uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) 321 )) 322 } 323 324 // pad the end with zeros, but make sure to not forget the extra bytes 325 if (extraBytes === 1) { 326 tmp = uint8[len - 1] 327 parts.push( 328 lookup[tmp >> 2] + 329 lookup[(tmp << 4) & 0x3F] + 330 '==' 331 ) 332 } else if (extraBytes === 2) { 333 tmp = (uint8[len - 2] << 8) + uint8[len - 1] 334 parts.push( 335 lookup[tmp >> 10] + 336 lookup[(tmp >> 4) & 0x3F] + 337 lookup[(tmp << 2) & 0x3F] + 338 '=' 339 ) 340 } 341 342 return parts.join('') 343} 344 345},{}
vendor: 2,928 bytes, lines 345-453
345],"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/ieee754/index.js":[function(require,module,exports) { 346exports.read = function (buffer, offset, isLE, mLen, nBytes) { 347 var e, m 348 var eLen = (nBytes * 8) - mLen - 1 349 var eMax = (1 << eLen) - 1 350 var eBias = eMax >> 1 351 var nBits = -7 352 var i = isLE ? (nBytes - 1) : 0 353 var d = isLE ? -1 : 1 354 var s = buffer[offset + i] 355 356 i += d 357 358 e = s & ((1 << (-nBits)) - 1) 359 s >>= (-nBits) 360 nBits += eLen 361 for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} 362 363 m = e & ((1 << (-nBits)) - 1) 364 e >>= (-nBits) 365 nBits += mLen 366 for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} 367 368 if (e === 0) { 369 e = 1 - eBias 370 } else if (e === eMax) { 371 return m ? NaN : ((s ? -1 : 1) * Infinity) 372 } else { 373 m = m + Math.pow(2, mLen) 374 e = e - eBias 375 } 376 return (s ? -1 : 1) * m * Math.pow(2, e - mLen) 377} 378 379exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { 380 var e, m, c 381 var eLen = (nBytes * 8) - mLen - 1 382 var eMax = (1 << eLen) - 1 383 var eBias = eMax >> 1 384 var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) 385 var i = isLE ? 0 : (nBytes - 1) 386 var d = isLE ? 1 : -1 387 var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 388 389 value = Math.abs(value) 390 391 if (isNaN(value) || value === Infinity) { 392 m = isNaN(value) ? 1 : 0 393 e = eMax 394 } else { 395 e = Math.floor(Math.log(value) / Math.LN2) 396 if (value * (c = Math.pow(2, -e)) < 1) { 397 e-- 398 c *= 2 399 } 400 if (e + eBias >= 1) { 401 value += rt / c 402 } else { 403 value += rt * Math.pow(2, 1 - eBias) 404 } 405 if (value * c >= 2) { 406 e++ 407 c /= 2 408 } 409 410 if (e + eBias >= eMax) { 411 m = 0 412 e = eMax 413 } else if (e + eBias >= 1) { 414 m = ((value * c) - 1) * Math.pow(2, mLen) 415 e = e + eBias 416 } else { 417 m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) 418 e = 0 419 } 420 } 421 422 for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} 423 424 e = (e << mLen) | m 425 eLen += mLen 426 for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} 427 428 buffer[offset + i - d] |= s * 128 429} 430 431},{}],"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/isarray/index.js":[function(require,module,exports) { 432var toString = {}.toString; 433 434module.exports = Array.isArray || function (arr) { 435 return toString.call(arr) == '[object Array]'; 436}; 437 438},{}],"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/buffer/index.js":[function(require,module,exports) { 439 440var global = arguments[3]; 441/*! 442 * The buffer module from node.js, for the browser. 443 * 444 * @author Feross Aboukhadijeh <[email protected]> <http://feross.org> 445 * @license MIT 446 */ 447/* eslint-disable no-proto */ 448 449'use strict' 450 451var base64 = require('base64-js') 452var ieee754 = require('ieee754') 453var isArray = require('isarray'
vendor: 48,315 bytes, lines 453-2230
453) 454 455exports.Buffer = Buffer 456exports.SlowBuffer = SlowBuffer 457exports.INSPECT_MAX_BYTES = 50 458 459/** 460 * If `Buffer.TYPED_ARRAY_SUPPORT`: 461 * === true Use Uint8Array implementation (fastest) 462 * === false Use Object implementation (most compatible, even IE6) 463 * 464 * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, 465 * Opera 11.6+, iOS 4.2+. 466 * 467 * Due to various browser bugs, sometimes the Object implementation will be used even 468 * when the browser supports typed arrays. 469 * 470 * Note: 471 * 472 * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, 473 * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. 474 * 475 * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. 476 * 477 * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of 478 * incorrect length in some situations. 479 480 * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they 481 * get the Object implementation, which is slower but behaves correctly. 482 */ 483Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined 484 ? global.TYPED_ARRAY_SUPPORT 485 : typedArraySupport() 486 487/* 488 * Export kMaxLength after typed array support is determined. 489 */ 490exports.kMaxLength = kMaxLength() 491 492function typedArraySupport () { 493 try { 494 var arr = new Uint8Array(1) 495 arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }} 496 return arr.foo() === 42 && // typed array instances can be augmented 497 typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` 498 arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` 499 } catch (e) { 500 return false 501 } 502} 503 504function kMaxLength () { 505 return Buffer.TYPED_ARRAY_SUPPORT 506 ? 0x7fffffff 507 : 0x3fffffff 508} 509 510function createBuffer (that, length) { 511 if (kMaxLength() < length) { 512 throw new RangeError('Invalid typed array length') 513 } 514 if (Buffer.TYPED_ARRAY_SUPPORT) { 515 // Return an augmented `Uint8Array` instance, for best performance 516 that = new Uint8Array(length) 517 that.__proto__ = Buffer.prototype 518 } else { 519 // Fallback: Return an object instance of the Buffer class 520 if (that === null) { 521 that = new Buffer(length) 522 } 523 that.length = length 524 } 525 526 return that 527} 528 529/** 530 * The Buffer constructor returns instances of `Uint8Array` that have their 531 * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of 532 * `Uint8Array`, so the returned instances will have all the node `Buffer` methods 533 * and the `Uint8Array` methods. Square bracket notation works as expected -- it 534 * returns a single octet. 535 * 536 * The `Uint8Array` prototype remains unmodified. 537 */ 538 539function Buffer (arg, encodingOrOffset, length) { 540 if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { 541 return new Buffer(arg, encodingOrOffset, length) 542 } 543 544 // Common case. 545 if (typeof arg === 'number') { 546 if (typeof encodingOrOffset === 'string') { 547 throw new Error( 548 'If encoding is specified then the first argument must be a string' 549 ) 550 } 551 return allocUnsafe(this, arg) 552 } 553 return from(this, arg, encodingOrOffset, length) 554} 555 556Buffer.poolSize = 8192 // not used by this implementation 557 558// TODO: Legacy, not needed anymore. Remove in next major version. 559Buffer._augment = function (arr) { 560 arr.__proto__ = Buffer.prototype 561 return arr 562} 563 564function from (that, value, encodingOrOffset, length) { 565 if (typeof value === 'number') { 566 throw new TypeError('"value" argument must not be a number') 567 } 568 569 if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { 570 return fromArrayBuffer(that, value, encodingOrOffset, length) 571 } 572 573 if (typeof value === 'string') { 574 return fromString(that, value, encodingOrOffset) 575 } 576 577 return fromObject(that, value) 578} 579 580/** 581 * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError 582 * if value is a number. 583 * Buffer.from(str[, encoding]) 584 * Buffer.from(array) 585 * Buffer.from(buffer) 586 * Buffer.from(arrayBuffer[, byteOffset[, length]]) 587 **/ 588Buffer.from = function (value, encodingOrOffset, length) { 589 return from(null, value, encodingOrOffset, length) 590} 591 592if (Buffer.TYPED_ARRAY_SUPPORT) { 593 Buffer.prototype.__proto__ = Uint8Array.prototype 594 Buffer.__proto__ = Uint8Array 595 if (typeof Symbol !== 'undefined' && Symbol.species && 596 Buffer[Symbol.species] === Buffer) { 597 // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 598 Object.defineProperty(Buffer, Symbol.species, { 599 value: null, 600 configurable: true 601 }) 602 } 603} 604 605function assertSize (size) { 606 if (typeof size !== 'number') { 607 throw new TypeError('"size" argument must be a number') 608 } else if (size < 0) { 609 throw new RangeError('"size" argument must not be negative') 610 } 611} 612 613function alloc (that, size, fill, encoding) { 614 assertSize(size) 615 if (size <= 0) { 616 return createBuffer(that, size) 617 } 618 if (fill !== undefined) { 619 // Only pay attention to encoding if it's a string. This 620 // prevents accidentally sending in a number that would 621 // be interpretted as a start offset. 622 return typeof encoding === 'string' 623 ? createBuffer(that, size).fill(fill, encoding) 624 : createBuffer(that, size).fill(fill) 625 } 626 return createBuffer(that, size) 627} 628 629/** 630 * Creates a new filled Buffer instance. 631 * alloc(size[, fill[, encoding]]) 632 **/ 633Buffer.alloc = function (size, fill, encoding) { 634 return alloc(null, size, fill, encoding) 635} 636 637function allocUnsafe (that, size) { 638 assertSize(size) 639 that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) 640 if (!Buffer.TYPED_ARRAY_SUPPORT) { 641 for (var i = 0; i < size; ++i) { 642 that[i] = 0 643 } 644 } 645 return that 646} 647 648/** 649 * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. 650 * */ 651Buffer.allocUnsafe = function (size) { 652 return allocUnsafe(null, size) 653} 654/** 655 * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. 656 */ 657Buffer.allocUnsafeSlow = function (size) { 658 return allocUnsafe(null, size) 659} 660 661function fromString (that, string, encoding) { 662 if (typeof encoding !== 'string' || encoding === '') { 663 encoding = 'utf8' 664 } 665 666 if (!Buffer.isEncoding(encoding)) { 667 throw new TypeError('"encoding" must be a valid string encoding') 668 } 669 670 var length = byteLength(string, encoding) | 0 671 that = createBuffer(that, length) 672 673 var actual = that.write(string, encoding) 674 675 if (actual !== length) { 676 // Writing a hex string, for example, that contains invalid characters will 677 // cause everything after the first invalid character to be ignored. (e.g. 678 // 'abxxcd' will be treated as 'ab') 679 that = that.slice(0, actual) 680 } 681 682 return that 683} 684 685function fromArrayLike (that, array) { 686 var length = array.length < 0 ? 0 : checked(array.length) | 0 687 that = createBuffer(that, length) 688 for (var i = 0; i < length; i += 1) { 689 that[i] = array[i] & 255 690 } 691 return that 692} 693 694function fromArrayBuffer (that, array, byteOffset, length) { 695 array.byteLength // this throws if `array` is not a valid ArrayBuffer 696 697 if (byteOffset < 0 || array.byteLength < byteOffset) { 698 throw new RangeError('\'offset\' is out of bounds') 699 } 700 701 if (array.byteLength < byteOffset + (length || 0)) { 702 throw new RangeError('\'length\' is out of bounds') 703 } 704 705 if (byteOffset === undefined && length === undefined) { 706 array = new Uint8Array(array) 707 } else if (length === undefined) { 708 array = new Uint8Array(array, byteOffset) 709 } else { 710 array = new Uint8Array(array, byteOffset, length) 711 } 712 713 if (Buffer.TYPED_ARRAY_SUPPORT) { 714 // Return an augmented `Uint8Array` instance, for best performance 715 that = array 716 that.__proto__ = Buffer.prototype 717 } else { 718 // Fallback: Return an object instance of the Buffer class 719 that = fromArrayLike(that, array) 720 } 721 return that 722} 723 724function fromObject (that, obj) { 725 if (Buffer.isBuffer(obj)) { 726 var len = checked(obj.length) | 0 727 that = createBuffer(that, len) 728 729 if (that.length === 0) { 730 return that 731 } 732 733 obj.copy(that, 0, 0, len) 734 return that 735 } 736 737 if (obj) { 738 if ((typeof ArrayBuffer !== 'undefined' && 739 obj.buffer instanceof ArrayBuffer) || 'length' in obj) { 740 if (typeof obj.length !== 'number' || isnan(obj.length)) { 741 return createBuffer(that, 0) 742 } 743 return fromArrayLike(that, obj) 744 } 745 746 if (obj.type === 'Buffer' && isArray(obj.data)) { 747 return fromArrayLike(that, obj.data) 748 } 749 } 750 751 throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') 752} 753 754function checked (length) { 755 // Note: cannot use `length < kMaxLength()` here because that fails when 756 // length is NaN (which is otherwise coerced to zero.) 757 if (length >= kMaxLength()) { 758 throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 759 'size: 0x' + kMaxLength().toString(16) + ' bytes') 760 } 761 return length | 0 762} 763 764function SlowBuffer (length) { 765 if (+length != length) { // eslint-disable-line eqeqeq 766 length = 0 767 } 768 return Buffer.alloc(+length) 769} 770 771Buffer.isBuffer = function isBuffer (b) { 772 return !!(b != null && b._isBuffer) 773} 774 775Buffer.compare = function compare (a, b) { 776 if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { 777 throw new TypeError('Arguments must be Buffers') 778 } 779 780 if (a === b) return 0 781 782 var x = a.length 783 var y = b.length 784 785 for (var i = 0, len = Math.min(x, y); i < len; ++i) { 786 if (a[i] !== b[i]) { 787 x = a[i] 788 y = b[i] 789 break 790 } 791 } 792 793 if (x < y) return -1 794 if (y < x) return 1 795 return 0 796} 797 798Buffer.isEncoding = function isEncoding (encoding) { 799 switch (String(encoding).toLowerCase()) { 800 case 'hex': 801 case 'utf8': 802 case 'utf-8': 803 case 'ascii': 804 case 'latin1': 805 case 'binary': 806 case 'base64': 807 case 'ucs2': 808 case 'ucs-2': 809 case 'utf16le': 810 case 'utf-16le': 811 return true 812 default: 813 return false 814 } 815} 816 817Buffer.concat = function concat (list, length) { 818 if (!isArray(list)) { 819 throw new TypeError('"list" argument must be an Array of Buffers') 820 } 821 822 if (list.length === 0) { 823 return Buffer.alloc(0) 824 } 825 826 var i 827 if (length === undefined) { 828 length = 0 829 for (i = 0; i < list.length; ++i) { 830 length += list[i].length 831 } 832 } 833 834 var buffer = Buffer.allocUnsafe(length) 835 var pos = 0 836 for (i = 0; i < list.length; ++i) { 837 var buf = list[i] 838 if (!Buffer.isBuffer(buf)) { 839 throw new TypeError('"list" argument must be an Array of Buffers') 840 } 841 buf.copy(buffer, pos) 842 pos += buf.length 843 } 844 return buffer 845} 846 847function byteLength (string, encoding) { 848 if (Buffer.isBuffer(string)) { 849 return string.length 850 } 851 if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && 852 (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { 853 return string.byteLength 854 } 855 if (typeof string !== 'string') { 856 string = '' + string 857 } 858 859 var len = string.length 860 if (len === 0) return 0 861 862 // Use a for loop to avoid recursion 863 var loweredCase = false 864 for (;;) { 865 switch (encoding) { 866 case 'ascii': 867 case 'latin1': 868 case 'binary': 869 return len 870 case 'utf8': 871 case 'utf-8': 872 case undefined: 873 return utf8ToBytes(string).length 874 case 'ucs2': 875 case 'ucs-2': 876 case 'utf16le': 877 case 'utf-16le': 878 return len * 2 879 case 'hex': 880 return len >>> 1 881 case 'base64': 882 return base64ToBytes(string).length 883 default: 884 if (loweredCase) return utf8ToBytes(string).length // assume utf8 885 encoding = ('' + encoding).toLowerCase() 886 loweredCase = true 887 } 888 } 889} 890Buffer.byteLength = byteLength 891 892function slowToString (encoding, start, end) { 893 var loweredCase = false 894 895 // No need to verify that "this.length <= MAX_UINT32" since it's a read-only 896 // property of a typed array. 897 898 // This behaves neither like String nor Uint8Array in that we set start/end 899 // to their upper/lower bounds if the value passed is out of range. 900 // undefined is handled specially as per ECMA-262 6th Edition, 901 // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. 902 if (start === undefined || start < 0) { 903 start = 0 904 } 905 // Return early if start > this.length. Done here to prevent potential uint32 906 // coercion fail below. 907 if (start > this.length) { 908 return '' 909 } 910 911 if (end === undefined || end > this.length) { 912 end = this.length 913 } 914 915 if (end <= 0) { 916 return '' 917 } 918 919 // Force coersion to uint32. This will also coerce falsey/NaN values to 0. 920 end >>>= 0 921 start >>>= 0 922 923 if (end <= start) { 924 return '' 925 } 926 927 if (!encoding) encoding = 'utf8' 928 929 while (true) { 930 switch (encoding) { 931 case 'hex': 932 return hexSlice(this, start, end) 933 934 case 'utf8': 935 case 'utf-8': 936 return utf8Slice(this, start, end) 937 938 case 'ascii': 939 return asciiSlice(this, start, end) 940 941 case 'latin1': 942 case 'binary': 943 return latin1Slice(this, start, end) 944 945 case 'base64': 946 return base64Slice(this, start, end) 947 948 case 'ucs2': 949 case 'ucs-2': 950 case 'utf16le': 951 case 'utf-16le': 952 return utf16leSlice(this, start, end) 953 954 default: 955 if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) 956 encoding = (encoding + '').toLowerCase() 957 loweredCase = true 958 } 959 } 960} 961 962// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect 963// Buffer instances. 964Buffer.prototype._isBuffer = true 965 966function swap (b, n, m) { 967 var i = b[n] 968 b[n] = b[m] 969 b[m] = i 970} 971 972Buffer.prototype.swap16 = function swap16 () { 973 var len = this.length 974 if (len % 2 !== 0) { 975 throw new RangeError('Buffer size must be a multiple of 16-bits') 976 } 977 for (var i = 0; i < len; i += 2) { 978 swap(this, i, i + 1) 979 } 980 return this 981} 982 983Buffer.prototype.swap32 = function swap32 () { 984 var len = this.length 985 if (len % 4 !== 0) { 986 throw new RangeError('Buffer size must be a multiple of 32-bits') 987 } 988 for (var i = 0; i < len; i += 4) { 989 swap(this, i, i + 3) 990 swap(this, i + 1, i + 2) 991 } 992 return this 993} 994 995Buffer.prototype.swap64 = function swap64 () { 996 var len = this.length 997 if (len % 8 !== 0) { 998 throw new RangeError('Buffer size must be a multiple of 64-bits') 999 } 1000 for (var i = 0; i < len; i += 8) { 1001 swap(this, i, i + 7) 1002 swap(this, i + 1, i + 6) 1003 swap(this, i + 2, i + 5) 1004 swap(this, i + 3, i + 4) 1005 } 1006 return this 1007} 1008 1009Buffer.prototype.toString = function toString () { 1010 var length = this.length | 0 1011 if (length === 0) return '' 1012 if (arguments.length === 0) return utf8Slice(this, 0, length) 1013 return slowToString.apply(this, arguments) 1014} 1015 1016Buffer.prototype.equals = function equals (b) { 1017 if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') 1018 if (this === b) return true 1019 return Buffer.compare(this, b) === 0 1020} 1021 1022Buffer.prototype.inspect = function inspect () { 1023 var str = '' 1024 var max = exports.INSPECT_MAX_BYTES 1025 if (this.length > 0) { 1026 str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') 1027 if (this.length > max) str += ' ... ' 1028 } 1029 return '<Buffer ' + str + '>' 1030} 1031 1032Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { 1033 if (!Buffer.isBuffer(target)) { 1034 throw new TypeError('Argument must be a Buffer') 1035 } 1036 1037 if (start === undefined) { 1038 start = 0 1039 } 1040 if (end === undefined) { 1041 end = target ? target.length : 0 1042 } 1043 if (thisStart === undefined) { 1044 thisStart = 0 1045 } 1046 if (thisEnd === undefined) { 1047 thisEnd = this.length 1048 } 1049 1050 if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { 1051 throw new RangeError('out of range index') 1052 } 1053 1054 if (thisStart >= thisEnd && start >= end) { 1055 return 0 1056 } 1057 if (thisStart >= thisEnd) { 1058 return -1 1059 } 1060 if (start >= end) { 1061 return 1 1062 } 1063 1064 start >>>= 0 1065 end >>>= 0 1066 thisStart >>>= 0 1067 thisEnd >>>= 0 1068 1069 if (this === target) return 0 1070 1071 var x = thisEnd - thisStart 1072 var y = end - start 1073 var len = Math.min(x, y) 1074 1075 var thisCopy = this.slice(thisStart, thisEnd) 1076 var targetCopy = target.slice(start, end) 1077 1078 for (var i = 0; i < len; ++i) { 1079 if (thisCopy[i] !== targetCopy[i]) { 1080 x = thisCopy[i] 1081 y = targetCopy[i] 1082 break 1083 } 1084 } 1085 1086 if (x < y) return -1 1087 if (y < x) return 1 1088 return 0 1089} 1090 1091// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, 1092// OR the last index of `val` in `buffer` at offset <= `byteOffset`. 1093// 1094// Arguments: 1095// - buffer - a Buffer to search 1096// - val - a string, Buffer, or number 1097// - byteOffset - an index into `buffer`; will be clamped to an int32 1098// - encoding - an optional encoding, relevant is val is a string 1099// - dir - true for indexOf, false for lastIndexOf 1100function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { 1101 // Empty buffer means no match 1102 if (buffer.length === 0) return -1 1103 1104 // Normalize byteOffset 1105 if (typeof byteOffset === 'string') { 1106 encoding = byteOffset 1107 byteOffset = 0 1108 } else if (byteOffset > 0x7fffffff) { 1109 byteOffset = 0x7fffffff 1110 } else if (byteOffset < -0x80000000) { 1111 byteOffset = -0x80000000 1112 } 1113 byteOffset = +byteOffset // Coerce to Number. 1114 if (isNaN(byteOffset)) { 1115 // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer 1116 byteOffset = dir ? 0 : (buffer.length - 1) 1117 } 1118 1119 // Normalize byteOffset: negative offsets start from the end of the buffer 1120 if (byteOffset < 0) byteOffset = buffer.length + byteOffset 1121 if (byteOffset >= buffer.length) { 1122 if (dir) return -1 1123 else byteOffset = buffer.length - 1 1124 } else if (byteOffset < 0) { 1125 if (dir) byteOffset = 0 1126 else return -1 1127 } 1128 1129 // Normalize val 1130 if (typeof val === 'string') { 1131 val = Buffer.from(val, encoding) 1132 } 1133 1134 // Finally, search either indexOf (if dir is true) or lastIndexOf 1135 if (Buffer.isBuffer(val)) { 1136 // Special case: looking for empty string/buffer always fails 1137 if (val.length === 0) { 1138 return -1 1139 } 1140 return arrayIndexOf(buffer, val, byteOffset, encoding, dir) 1141 } else if (typeof val === 'number') { 1142 val = val & 0xFF // Search for a byte value [0-255] 1143 if (Buffer.TYPED_ARRAY_SUPPORT && 1144 typeof Uint8Array.prototype.indexOf === 'function') { 1145 if (dir) { 1146 return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) 1147 } else { 1148 return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) 1149 } 1150 } 1151 return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) 1152 } 1153 1154 throw new TypeError('val must be string, number or Buffer') 1155} 1156 1157function arrayIndexOf (arr, val, byteOffset, encoding, dir) { 1158 var indexSize = 1 1159 var arrLength = arr.length 1160 var valLength = val.length 1161 1162 if (encoding !== undefined) { 1163 encoding = String(encoding).toLowerCase() 1164 if (encoding === 'ucs2' || encoding === 'ucs-2' || 1165 encoding === 'utf16le' || encoding === 'utf-16le') { 1166 if (arr.length < 2 || val.length < 2) { 1167 return -1 1168 } 1169 indexSize = 2 1170 arrLength /= 2 1171 valLength /= 2 1172 byteOffset /= 2 1173 } 1174 } 1175 1176 function read (buf, i) { 1177 if (indexSize === 1) { 1178 return buf[i] 1179 } else { 1180 return buf.readUInt16BE(i * indexSize) 1181 } 1182 } 1183 1184 var i 1185 if (dir) { 1186 var foundIndex = -1 1187 for (i = byteOffset; i < arrLength; i++) { 1188 if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { 1189 if (foundIndex === -1) foundIndex = i 1190 if (i - foundIndex + 1 === valLength) return foundIndex * indexSize 1191 } else { 1192 if (foundIndex !== -1) i -= i - foundIndex 1193 foundIndex = -1 1194 } 1195 } 1196 } else { 1197 if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength 1198 for (i = byteOffset; i >= 0; i--) { 1199 var found = true 1200 for (var j = 0; j < valLength; j++) { 1201 if (read(arr, i + j) !== read(val, j)) { 1202 found = false 1203 break 1204 } 1205 } 1206 if (found) return i 1207 } 1208 } 1209 1210 return -1 1211} 1212 1213Buffer.prototype.includes = function includes (val, byteOffset, encoding) { 1214 return this.indexOf(val, byteOffset, encoding) !== -1 1215} 1216 1217Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { 1218 return bidirectionalIndexOf(this, val, byteOffset, encoding, true) 1219} 1220 1221Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { 1222 return bidirectionalIndexOf(this, val, byteOffset, encoding, false) 1223} 1224 1225function hexWrite (buf, string, offset, length) { 1226 offset = Number(offset) || 0 1227 var remaining = buf.length - offset 1228 if (!length) { 1229 length = remaining 1230 } else { 1231 length = Number(length) 1232 if (length > remaining) { 1233 length = remaining 1234 } 1235 } 1236 1237 // must be an even number of digits 1238 var strLen = string.length 1239 if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') 1240 1241 if (length > strLen / 2) { 1242 length = strLen / 2 1243 } 1244 for (var i = 0; i < length; ++i) { 1245 var parsed = parseInt(string.substr(i * 2, 2), 16) 1246 if (isNaN(parsed)) return i 1247 buf[offset + i] = parsed 1248 } 1249 return i 1250} 1251 1252function utf8Write (buf, string, offset, length) { 1253 return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) 1254} 1255 1256function asciiWrite (buf, string, offset, length) { 1257 return blitBuffer(asciiToBytes(string), buf, offset, length) 1258} 1259 1260function latin1Write (buf, string, offset, length) { 1261 return asciiWrite(buf, string, offset, length) 1262} 1263 1264function base64Write (buf, string, offset, length) { 1265 return blitBuffer(base64ToBytes(string), buf, offset, length) 1266} 1267 1268function ucs2Write (buf, string, offset, length) { 1269 return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) 1270} 1271 1272Buffer.prototype.write = function write (string, offset, length, encoding) { 1273 // Buffer#write(string) 1274 if (offset === undefined) { 1275 encoding = 'utf8' 1276 length = this.length 1277 offset = 0 1278 // Buffer#write(string, encoding) 1279 } else if (length === undefined && typeof offset === 'string') { 1280 encoding = offset 1281 length = this.length 1282 offset = 0 1283 // Buffer#write(string, offset[, length][, encoding]) 1284 } else if (isFinite(offset)) { 1285 offset = offset | 0 1286 if (isFinite(length)) { 1287 length = length | 0 1288 if (encoding === undefined) encoding = 'utf8' 1289 } else { 1290 encoding = length 1291 length = undefined 1292 } 1293 // legacy write(string, encoding, offset, length) - remove in v0.13 1294 } else { 1295 throw new Error( 1296 'Buffer.write(string, encoding, offset[, length]) is no longer supported' 1297 ) 1298 } 1299 1300 var remaining = this.length - offset 1301 if (length === undefined || length > remaining) length = remaining 1302 1303 if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { 1304 throw new RangeError('Attempt to write outside buffer bounds') 1305 } 1306 1307 if (!encoding) encoding = 'utf8' 1308 1309 var loweredCase = false 1310 for (;;) { 1311 switch (encoding) { 1312 case 'hex': 1313 return hexWrite(this, string, offset, length) 1314 1315 case 'utf8': 1316 case 'utf-8': 1317 return utf8Write(this, string, offset, length) 1318 1319 case 'ascii': 1320 return asciiWrite(this, string, offset, length) 1321 1322 case 'latin1': 1323 case 'binary': 1324 return latin1Write(this, string, offset, length) 1325 1326 case 'base64': 1327 // Warning: maxLength not taken into account in base64Write 1328 return base64Write(this, string, offset, length) 1329 1330 case 'ucs2': 1331 case 'ucs-2': 1332 case 'utf16le': 1333 case 'utf-16le': 1334 return ucs2Write(this, string, offset, length) 1335 1336 default: 1337 if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) 1338 encoding = ('' + encoding).toLowerCase() 1339 loweredCase = true 1340 } 1341 } 1342} 1343 1344Buffer.prototype.toJSON = function toJSON () { 1345 return { 1346 type: 'Buffer', 1347 data: Array.prototype.slice.call(this._arr || this, 0) 1348 } 1349} 1350 1351function base64Slice (buf, start, end) { 1352 if (start === 0 && end === buf.length) { 1353 return base64.fromByteArray(buf) 1354 } else { 1355 return base64.fromByteArray(buf.slice(start, end)) 1356 } 1357} 1358 1359function utf8Slice (buf, start, end) { 1360 end = Math.min(buf.length, end) 1361 var res = [] 1362 1363 var i = start 1364 while (i < end) { 1365 var firstByte = buf[i] 1366 var codePoint = null 1367 var bytesPerSequence = (firstByte > 0xEF) ? 4 1368 : (firstByte > 0xDF) ? 3 1369 : (firstByte > 0xBF) ? 2 1370 : 1 1371 1372 if (i + bytesPerSequence <= end) { 1373 var secondByte, thirdByte, fourthByte, tempCodePoint 1374 1375 switch (bytesPerSequence) { 1376 case 1: 1377 if (firstByte < 0x80) { 1378 codePoint = firstByte 1379 } 1380 break 1381 case 2: 1382 secondByte = buf[i + 1] 1383 if ((secondByte & 0xC0) === 0x80) { 1384 tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) 1385 if (tempCodePoint > 0x7F) { 1386 codePoint = tempCodePoint 1387 } 1388 } 1389 break 1390 case 3: 1391 secondByte = buf[i + 1] 1392 thirdByte = buf[i + 2] 1393 if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { 1394 tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) 1395 if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { 1396 codePoint = tempCodePoint 1397 } 1398 } 1399 break 1400 case 4: 1401 secondByte = buf[i + 1] 1402 thirdByte = buf[i + 2] 1403 fourthByte = buf[i + 3] 1404 if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { 1405 tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) 1406 if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { 1407 codePoint = tempCodePoint 1408 } 1409 } 1410 } 1411 } 1412 1413 if (codePoint === null) { 1414 // we did not generate a valid codePoint so insert a 1415 // replacement char (U+FFFD) and advance only 1 byte 1416 codePoint = 0xFFFD 1417 bytesPerSequence = 1 1418 } else if (codePoint > 0xFFFF) { 1419 // encode to utf16 (surrogate pair dance) 1420 codePoint -= 0x10000 1421 res.push(codePoint >>> 10 & 0x3FF | 0xD800) 1422 codePoint = 0xDC00 | codePoint & 0x3FF 1423 } 1424 1425 res.push(codePoint) 1426 i += bytesPerSequence 1427 } 1428 1429 return decodeCodePointsArray(res) 1430} 1431 1432// Based on http://stackoverflow.com/a/22747272/680742, the browser with 1433// the lowest limit is Chrome, with 0x10000 args. 1434// We go 1 magnitude less, for safety 1435var MAX_ARGUMENTS_LENGTH = 0x1000 1436 1437function decodeCodePointsArray (codePoints) { 1438 var len = codePoints.length 1439 if (len <= MAX_ARGUMENTS_LENGTH) { 1440 return String.fromCharCode.apply(String, codePoints) // avoid extra slice() 1441 } 1442 1443 // Decode in chunks to avoid "call stack size exceeded". 1444 var res = '' 1445 var i = 0 1446 while (i < len) { 1447 res += String.fromCharCode.apply( 1448 String, 1449 codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) 1450 ) 1451 } 1452 return res 1453} 1454 1455function asciiSlice (buf, start, end) { 1456 var ret = '' 1457 end = Math.min(buf.length, end) 1458 1459 for (var i = start; i < end; ++i) { 1460 ret += String.fromCharCode(buf[i] & 0x7F) 1461 } 1462 return ret 1463} 1464 1465function latin1Slice (buf, start, end) { 1466 var ret = '' 1467 end = Math.min(buf.length, end) 1468 1469 for (var i = start; i < end; ++i) { 1470 ret += String.fromCharCode(buf[i]) 1471 } 1472 return ret 1473} 1474 1475function hexSlice (buf, start, end) { 1476 var len = buf.length 1477 1478 if (!start || start < 0) start = 0 1479 if (!end || end < 0 || end > len) end = len 1480 1481 var out = '' 1482 for (var i = start; i < end; ++i) { 1483 out += toHex(buf[i]) 1484 } 1485 return out 1486} 1487 1488function utf16leSlice (buf, start, end) { 1489 var bytes = buf.slice(start, end) 1490 var res = '' 1491 for (var i = 0; i < bytes.length; i += 2) { 1492 res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) 1493 } 1494 return res 1495} 1496 1497Buffer.prototype.slice = function slice (start, end) { 1498 var len = this.length 1499 start = ~~start 1500 end = end === undefined ? len : ~~end 1501 1502 if (start < 0) { 1503 start += len 1504 if (start < 0) start = 0 1505 } else if (start > len) { 1506 start = len 1507 } 1508 1509 if (end < 0) { 1510 end += len 1511 if (end < 0) end = 0 1512 } else if (end > len) { 1513 end = len 1514 } 1515 1516 if (end < start) end = start 1517 1518 var newBuf 1519 if (Buffer.TYPED_ARRAY_SUPPORT) { 1520 newBuf = this.subarray(start, end) 1521 newBuf.__proto__ = Buffer.prototype 1522 } else { 1523 var sliceLen = end - start 1524 newBuf = new Buffer(sliceLen, undefined) 1525 for (var i = 0; i < sliceLen; ++i) { 1526 newBuf[i] = this[i + start] 1527 } 1528 } 1529 1530 return newBuf 1531} 1532 1533/* 1534 * Need to make sure that buffer isn't trying to write out of bounds. 1535 */ 1536function checkOffset (offset, ext, length) { 1537 if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') 1538 if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') 1539} 1540 1541Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { 1542 offset = offset | 0 1543 byteLength = byteLength | 0 1544 if (!noAssert) checkOffset(offset, byteLength, this.length) 1545 1546 var val = this[offset] 1547 var mul = 1 1548 var i = 0 1549 while (++i < byteLength && (mul *= 0x100)) { 1550 val += this[offset + i] * mul 1551 } 1552 1553 return val 1554} 1555 1556Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { 1557 offset = offset | 0 1558 byteLength = byteLength | 0 1559 if (!noAssert) { 1560 checkOffset(offset, byteLength, this.length) 1561 } 1562 1563 var val = this[offset + --byteLength] 1564 var mul = 1 1565 while (byteLength > 0 && (mul *= 0x100)) { 1566 val += this[offset + --byteLength] * mul 1567 } 1568 1569 return val 1570} 1571 1572Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { 1573 if (!noAssert) checkOffset(offset, 1, this.length) 1574 return this[offset] 1575} 1576 1577Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { 1578 if (!noAssert) checkOffset(offset, 2, this.length) 1579 return this[offset] | (this[offset + 1] << 8) 1580} 1581 1582Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { 1583 if (!noAssert) checkOffset(offset, 2, this.length) 1584 return (this[offset] << 8) | this[offset + 1] 1585} 1586 1587Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { 1588 if (!noAssert) checkOffset(offset, 4, this.length) 1589 1590 return ((this[offset]) | 1591 (this[offset + 1] << 8) | 1592 (this[offset + 2] << 16)) + 1593 (this[offset + 3] * 0x1000000) 1594} 1595 1596Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { 1597 if (!noAssert) checkOffset(offset, 4, this.length) 1598 1599 return (this[offset] * 0x1000000) + 1600 ((this[offset + 1] << 16) | 1601 (this[offset + 2] << 8) | 1602 this[offset + 3]) 1603} 1604 1605Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { 1606 offset = offset | 0 1607 byteLength = byteLength | 0 1608 if (!noAssert) checkOffset(offset, byteLength, this.length) 1609 1610 var val = this[offset] 1611 var mul = 1 1612 var i = 0 1613 while (++i < byteLength && (mul *= 0x100)) { 1614 val += this[offset + i] * mul 1615 } 1616 mul *= 0x80 1617 1618 if (val >= mul) val -= Math.pow(2, 8 * byteLength) 1619 1620 return val 1621} 1622 1623Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { 1624 offset = offset | 0 1625 byteLength = byteLength | 0 1626 if (!noAssert) checkOffset(offset, byteLength, this.length) 1627 1628 var i = byteLength 1629 var mul = 1 1630 var val = this[offset + --i] 1631 while (i > 0 && (mul *= 0x100)) { 1632 val += this[offset + --i] * mul 1633 } 1634 mul *= 0x80 1635 1636 if (val >= mul) val -= Math.pow(2, 8 * byteLength) 1637 1638 return val 1639} 1640 1641Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { 1642 if (!noAssert) checkOffset(offset, 1, this.length) 1643 if (!(this[offset] & 0x80)) return (this[offset]) 1644 return ((0xff - this[offset] + 1) * -1) 1645} 1646 1647Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { 1648 if (!noAssert) checkOffset(offset, 2, this.length) 1649 var val = this[offset] | (this[offset + 1] << 8) 1650 return (val & 0x8000) ? val | 0xFFFF0000 : val 1651} 1652 1653Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { 1654 if (!noAssert) checkOffset(offset, 2, this.length) 1655 var val = this[offset + 1] | (this[offset] << 8) 1656 return (val & 0x8000) ? val | 0xFFFF0000 : val 1657} 1658 1659Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { 1660 if (!noAssert) checkOffset(offset, 4, this.length) 1661 1662 return (this[offset]) | 1663 (this[offset + 1] << 8) | 1664 (this[offset + 2] << 16) | 1665 (this[offset + 3] << 24) 1666} 1667 1668Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { 1669 if (!noAssert) checkOffset(offset, 4, this.length) 1670 1671 return (this[offset] << 24) | 1672 (this[offset + 1] << 16) | 1673 (this[offset + 2] << 8) | 1674 (this[offset + 3]) 1675} 1676 1677Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { 1678 if (!noAssert) checkOffset(offset, 4, this.length) 1679 return ieee754.read(this, offset, true, 23, 4) 1680} 1681 1682Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { 1683 if (!noAssert) checkOffset(offset, 4, this.length) 1684 return ieee754.read(this, offset, false, 23, 4) 1685} 1686 1687Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { 1688 if (!noAssert) checkOffset(offset, 8, this.length) 1689 return ieee754.read(this, offset, true, 52, 8) 1690} 1691 1692Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { 1693 if (!noAssert) checkOffset(offset, 8, this.length) 1694 return ieee754.read(this, offset, false, 52, 8) 1695} 1696 1697function checkInt (buf, value, offset, ext, max, min) { 1698 if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') 1699 if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') 1700 if (offset + ext > buf.length) throw new RangeError('Index out of range') 1701} 1702 1703Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { 1704 value = +value 1705 offset = offset | 0 1706 byteLength = byteLength | 0 1707 if (!noAssert) { 1708 var maxBytes = Math.pow(2, 8 * byteLength) - 1 1709 checkInt(this, value, offset, byteLength, maxBytes, 0) 1710 } 1711 1712 var mul = 1 1713 var i = 0 1714 this[offset] = value & 0xFF 1715 while (++i < byteLength && (mul *= 0x100)) { 1716 this[offset + i] = (value / mul) & 0xFF 1717 } 1718 1719 return offset + byteLength 1720} 1721 1722Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { 1723 value = +value 1724 offset = offset | 0 1725 byteLength = byteLength | 0 1726 if (!noAssert) { 1727 var maxBytes = Math.pow(2, 8 * byteLength) - 1 1728 checkInt(this, value, offset, byteLength, maxBytes, 0) 1729 } 1730 1731 var i = byteLength - 1 1732 var mul = 1 1733 this[offset + i] = value & 0xFF 1734 while (--i >= 0 && (mul *= 0x100)) { 1735 this[offset + i] = (value / mul) & 0xFF 1736 } 1737 1738 return offset + byteLength 1739} 1740 1741Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { 1742 value = +value 1743 offset = offset | 0 1744 if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) 1745 if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) 1746 this[offset] = (value & 0xff) 1747 return offset + 1 1748} 1749 1750function objectWriteUInt16 (buf, value, offset, littleEndian) { 1751 if (value < 0) value = 0xffff + value + 1 1752 for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { 1753 buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> 1754 (littleEndian ? i : 1 - i) * 8 1755 } 1756} 1757 1758Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { 1759 value = +value 1760 offset = offset | 0 1761 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) 1762 if (Buffer.TYPED_ARRAY_SUPPORT) { 1763 this[offset] = (value & 0xff) 1764 this[offset + 1] = (value >>> 8) 1765 } else { 1766 objectWriteUInt16(this, value, offset, true) 1767 } 1768 return offset + 2 1769} 1770 1771Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { 1772 value = +value 1773 offset = offset | 0 1774 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) 1775 if (Buffer.TYPED_ARRAY_SUPPORT) { 1776 this[offset] = (value >>> 8) 1777 this[offset + 1] = (value & 0xff) 1778 } else { 1779 objectWriteUInt16(this, value, offset, false) 1780 } 1781 return offset + 2 1782} 1783 1784function objectWriteUInt32 (buf, value, offset, littleEndian) { 1785 if (value < 0) value = 0xffffffff + value + 1 1786 for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { 1787 buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff 1788 } 1789} 1790 1791Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { 1792 value = +value 1793 offset = offset | 0 1794 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) 1795 if (Buffer.TYPED_ARRAY_SUPPORT) { 1796 this[offset + 3] = (value >>> 24) 1797 this[offset + 2] = (value >>> 16) 1798 this[offset + 1] = (value >>> 8) 1799 this[offset] = (value & 0xff) 1800 } else { 1801 objectWriteUInt32(this, value, offset, true) 1802 } 1803 return offset + 4 1804} 1805 1806Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { 1807 value = +value 1808 offset = offset | 0 1809 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) 1810 if (Buffer.TYPED_ARRAY_SUPPORT) { 1811 this[offset] = (value >>> 24) 1812 this[offset + 1] = (value >>> 16) 1813 this[offset + 2] = (value >>> 8) 1814 this[offset + 3] = (value & 0xff) 1815 } else { 1816 objectWriteUInt32(this, value, offset, false) 1817 } 1818 return offset + 4 1819} 1820 1821Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { 1822 value = +value 1823 offset = offset | 0 1824 if (!noAssert) { 1825 var limit = Math.pow(2, 8 * byteLength - 1) 1826 1827 checkInt(this, value, offset, byteLength, limit - 1, -limit) 1828 } 1829 1830 var i = 0 1831 var mul = 1 1832 var sub = 0 1833 this[offset] = value & 0xFF 1834 while (++i < byteLength && (mul *= 0x100)) { 1835 if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { 1836 sub = 1 1837 } 1838 this[offset + i] = ((value / mul) >> 0) - sub & 0xFF 1839 } 1840 1841 return offset + byteLength 1842} 1843 1844Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { 1845 value = +value 1846 offset = offset | 0 1847 if (!noAssert) { 1848 var limit = Math.pow(2, 8 * byteLength - 1) 1849 1850 checkInt(this, value, offset, byteLength, limit - 1, -limit) 1851 } 1852 1853 var i = byteLength - 1 1854 var mul = 1 1855 var sub = 0 1856 this[offset + i] = value & 0xFF 1857 while (--i >= 0 && (mul *= 0x100)) { 1858 if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { 1859 sub = 1 1860 } 1861 this[offset + i] = ((value / mul) >> 0) - sub & 0xFF 1862 } 1863 1864 return offset + byteLength 1865} 1866 1867Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { 1868 value = +value 1869 offset = offset | 0 1870 if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) 1871 if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) 1872 if (value < 0) value = 0xff + value + 1 1873 this[offset] = (value & 0xff) 1874 return offset + 1 1875} 1876 1877Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { 1878 value = +value 1879 offset = offset | 0 1880 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) 1881 if (Buffer.TYPED_ARRAY_SUPPORT) { 1882 this[offset] = (value & 0xff) 1883 this[offset + 1] = (value >>> 8) 1884 } else { 1885 objectWriteUInt16(this, value, offset, true) 1886 } 1887 return offset + 2 1888} 1889 1890Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { 1891 value = +value 1892 offset = offset | 0 1893 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) 1894 if (Buffer.TYPED_ARRAY_SUPPORT) { 1895 this[offset] = (value >>> 8) 1896 this[offset + 1] = (value & 0xff) 1897 } else { 1898 objectWriteUInt16(this, value, offset, false) 1899 } 1900 return offset + 2 1901} 1902 1903Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { 1904 value = +value 1905 offset = offset | 0 1906 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) 1907 if (Buffer.TYPED_ARRAY_SUPPORT) { 1908 this[offset] = (value & 0xff) 1909 this[offset + 1] = (value >>> 8) 1910 this[offset + 2] = (value >>> 16) 1911 this[offset + 3] = (value >>> 24) 1912 } else { 1913 objectWriteUInt32(this, value, offset, true) 1914 } 1915 return offset + 4 1916} 1917 1918Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { 1919 value = +value 1920 offset = offset | 0 1921 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) 1922 if (value < 0) value = 0xffffffff + value + 1 1923 if (Buffer.TYPED_ARRAY_SUPPORT) { 1924 this[offset] = (value >>> 24) 1925 this[offset + 1] = (value >>> 16) 1926 this[offset + 2] = (value >>> 8) 1927 this[offset + 3] = (value & 0xff) 1928 } else { 1929 objectWriteUInt32(this, value, offset, false) 1930 } 1931 return offset + 4 1932} 1933 1934function checkIEEE754 (buf, value, offset, ext, max, min) { 1935 if (offset + ext > buf.length) throw new RangeError('Index out of range') 1936 if (offset < 0) throw new RangeError('Index out of range') 1937} 1938 1939function writeFloat (buf, value, offset, littleEndian, noAssert) { 1940 if (!noAssert) { 1941 checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) 1942 } 1943 ieee754.write(buf, value, offset, littleEndian, 23, 4) 1944 return offset + 4 1945} 1946 1947Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { 1948 return writeFloat(this, value, offset, true, noAssert) 1949} 1950 1951Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { 1952 return writeFloat(this, value, offset, false, noAssert) 1953} 1954 1955function writeDouble (buf, value, offset, littleEndian, noAssert) { 1956 if (!noAssert) { 1957 checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) 1958 } 1959 ieee754.write(buf, value, offset, littleEndian, 52, 8) 1960 return offset + 8 1961} 1962 1963Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { 1964 return writeDouble(this, value, offset, true, noAssert) 1965} 1966 1967Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { 1968 return writeDouble(this, value, offset, false, noAssert) 1969} 1970 1971// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) 1972Buffer.prototype.copy = function copy (target, targetStart, start, end) { 1973 if (!start) start = 0 1974 if (!end && end !== 0) end = this.length 1975 if (targetStart >= target.length) targetStart = target.length 1976 if (!targetStart) targetStart = 0 1977 if (end > 0 && end < start) end = start 1978 1979 // Copy 0 bytes; we're done 1980 if (end === start) return 0 1981 if (target.length === 0 || this.length === 0) return 0 1982 1983 // Fatal error conditions 1984 if (targetStart < 0) { 1985 throw new RangeError('targetStart out of bounds') 1986 } 1987 if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') 1988 if (end < 0) throw new RangeError('sourceEnd out of bounds') 1989 1990 // Are we oob? 1991 if (end > this.length) end = this.length 1992 if (target.length - targetStart < end - start) { 1993 end = target.length - targetStart + start 1994 } 1995 1996 var len = end - start 1997 var i 1998 1999 if (this === target && start < targetStart && targetStart < end) { 2000 // descending copy from end 2001 for (i = len - 1; i >= 0; --i) { 2002 target[i + targetStart] = this[i + start] 2003 } 2004 } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { 2005 // ascending copy from start 2006 for (i = 0; i < len; ++i) { 2007 target[i + targetStart] = this[i + start] 2008 } 2009 } else { 2010 Uint8Array.prototype.set.call( 2011 target, 2012 this.subarray(start, start + len), 2013 targetStart 2014 ) 2015 } 2016 2017 return len 2018} 2019 2020// Usage: 2021// buffer.fill(number[, offset[, end]]) 2022// buffer.fill(buffer[, offset[, end]]) 2023// buffer.fill(string[, offset[, end]][, encoding]) 2024Buffer.prototype.fill = function fill (val, start, end, encoding) { 2025 // Handle string cases: 2026 if (typeof val === 'string') { 2027 if (typeof start === 'string') { 2028 encoding = start 2029 start = 0 2030 end = this.length 2031 } else if (typeof end === 'string') { 2032 encoding = end 2033 end = this.length 2034 } 2035 if (val.length === 1) { 2036 var code = val.charCodeAt(0) 2037 if (code < 256) { 2038 val = code 2039 } 2040 } 2041 if (encoding !== undefined && typeof encoding !== 'string') { 2042 throw new TypeError('encoding must be a string') 2043 } 2044 if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { 2045 throw new TypeError('Unknown encoding: ' + encoding) 2046 } 2047 } else if (typeof val === 'number') { 2048 val = val & 255 2049 } 2050 2051 // Invalid ranges are not set to a default, so can range check early. 2052 if (start < 0 || this.length < start || this.length < end) { 2053 throw new RangeError('Out of range index') 2054 } 2055 2056 if (end <= start) { 2057 return this 2058 } 2059 2060 start = start >>> 0 2061 end = end === undefined ? this.length : end >>> 0 2062 2063 if (!val) val = 0 2064 2065 var i 2066 if (typeof val === 'number') { 2067 for (i = start; i < end; ++i) { 2068 this[i] = val 2069 } 2070 } else { 2071 var bytes = Buffer.isBuffer(val) 2072 ? val 2073 : utf8ToBytes(new Buffer(val, encoding).toString()) 2074 var len = bytes.length 2075 for (i = 0; i < end - start; ++i) { 2076 this[i + start] = bytes[i % len] 2077 } 2078 } 2079 2080 return this 2081} 2082 2083// HELPER FUNCTIONS 2084// ================ 2085 2086var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g 2087 2088function base64clean (str) { 2089 // Node strips out invalid characters like \n and \t from the string, base64-js does not 2090 str = stringtrim(str).replace(INVALID_BASE64_RE, '') 2091 // Node converts strings with length < 2 to '' 2092 if (str.length < 2) return '' 2093 // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not 2094 while (str.length % 4 !== 0) { 2095 str = str + '=' 2096 } 2097 return str 2098} 2099 2100function stringtrim (str) { 2101 if (str.trim) return str.trim() 2102 return str.replace(/^\s+|\s+$/g, '') 2103} 2104 2105function toHex (n) { 2106 if (n < 16) return '0' + n.toString(16) 2107 return n.toString(16) 2108} 2109 2110function utf8ToBytes (string, units) { 2111 units = units || Infinity 2112 var codePoint 2113 var length = string.length 2114 var leadSurrogate = null 2115 var bytes = [] 2116 2117 for (var i = 0; i < length; ++i) { 2118 codePoint = string.charCodeAt(i) 2119 2120 // is surrogate component 2121 if (codePoint > 0xD7FF && codePoint < 0xE000) { 2122 // last char was a lead 2123 if (!leadSurrogate) { 2124 // no lead yet 2125 if (codePoint > 0xDBFF) { 2126 // unexpected trail 2127 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) 2128 continue 2129 } else if (i + 1 === length) { 2130 // unpaired lead 2131 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) 2132 continue 2133 } 2134 2135 // valid lead 2136 leadSurrogate = codePoint 2137 2138 continue 2139 } 2140 2141 // 2 leads in a row 2142 if (codePoint < 0xDC00) { 2143 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) 2144 leadSurrogate = codePoint 2145 continue 2146 } 2147 2148 // valid surrogate pair 2149 codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 2150 } else if (leadSurrogate) { 2151 // valid bmp char, but last char was a lead 2152 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) 2153 } 2154 2155 leadSurrogate = null 2156 2157 // encode utf8 2158 if (codePoint < 0x80) { 2159 if ((units -= 1) < 0) break 2160 bytes.push(codePoint) 2161 } else if (codePoint < 0x800) { 2162 if ((units -= 2) < 0) break 2163 bytes.push( 2164 codePoint >> 0x6 | 0xC0, 2165 codePoint & 0x3F | 0x80 2166 ) 2167 } else if (codePoint < 0x10000) { 2168 if ((units -= 3) < 0) break 2169 bytes.push( 2170 codePoint >> 0xC | 0xE0, 2171 codePoint >> 0x6 & 0x3F | 0x80, 2172 codePoint & 0x3F | 0x80 2173 ) 2174 } else if (codePoint < 0x110000) { 2175 if ((units -= 4) < 0) break 2176 bytes.push( 2177 codePoint >> 0x12 | 0xF0, 2178 codePoint >> 0xC & 0x3F | 0x80, 2179 codePoint >> 0x6 & 0x3F | 0x80, 2180 codePoint & 0x3F | 0x80 2181 ) 2182 } else { 2183 throw new Error('Invalid code point') 2184 } 2185 } 2186 2187 return bytes 2188} 2189 2190function asciiToBytes (str) { 2191 var byteArray = [] 2192 for (var i = 0; i < str.length; ++i) { 2193 // Node's code seems to be doing this and not & 0x7F.. 2194 byteArray.push(str.charCodeAt(i) & 0xFF) 2195 } 2196 return byteArray 2197} 2198 2199function utf16leToBytes (str, units) { 2200 var c, hi, lo 2201 var byteArray = [] 2202 for (var i = 0; i < str.length; ++i) { 2203 if ((units -= 2) < 0) break 2204 2205 c = str.charCodeAt(i) 2206 hi = c >> 8 2207 lo = c % 256 2208 byteArray.push(lo) 2209 byteArray.push(hi) 2210 } 2211 2212 return byteArray 2213} 2214 2215function base64ToBytes (str) { 2216 return base64.toByteArray(base64clean(str)) 2217} 2218 2219function blitBuffer (src, dst, offset, length) { 2220 for (var i = 0; i < length; ++i) { 2221 if ((i + offset >= dst.length) || (i >= src.length)) break 2222 dst[i + offset] = src[i] 2223 } 2224 return i 2225} 2226 2227function isnan (val) { 2228 return val !== val // eslint-disable-line no-self-compare 2229} 2230
vendor: 3,632 bytes, lines 2231-2326
2231},{"base64-js":"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/base64-js/index.js","ieee754":"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/ieee754/index.js","isarray":"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/isarray/index.js","buffer":"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/buffer/index.js"}],"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/process/browser.js":[function(require,module,exports) { 2232 2233// shim for using process in browser 2234var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it 2235// don't break things. But we need to wrap it in a try catch in case it is 2236// wrapped in strict mode code which doesn't define any globals. It's inside a 2237// function because try/catches deoptimize in certain engines. 2238 2239var cachedSetTimeout; 2240var cachedClearTimeout; 2241 2242function defaultSetTimout() { 2243 throw new Error('setTimeout has not been defined'); 2244} 2245 2246function defaultClearTimeout() { 2247 throw new Error('clearTimeout has not been defined'); 2248} 2249 2250(function () { 2251 try { 2252 if (typeof setTimeout === 'function') { 2253 cachedSetTimeout = setTimeout; 2254 } else { 2255 cachedSetTimeout = defaultSetTimout; 2256 } 2257 } catch (e) { 2258 cachedSetTimeout = defaultSetTimout; 2259 } 2260 2261 try { 2262 if (typeof clearTimeout === 'function') { 2263 cachedClearTimeout = clearTimeout; 2264 } else { 2265 cachedClearTimeout = defaultClearTimeout; 2266 } 2267 } catch (e) { 2268 cachedClearTimeout = defaultClearTimeout; 2269 } 2270})(); 2271 2272function runTimeout(fun) { 2273 if (cachedSetTimeout === setTimeout) { 2274 //normal enviroments in sane situations 2275 return setTimeout(fun, 0); 2276 } // if setTimeout wasn't available but was latter defined 2277 2278 2279 if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { 2280 cachedSetTimeout = setTimeout; 2281 return setTimeout(fun, 0); 2282 } 2283 2284 try { 2285 // when when somebody has screwed with setTimeout but no I.E. maddness 2286 return cachedSetTimeout(fun, 0); 2287 } catch (e) { 2288 try { 2289 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 2290 return cachedSetTimeout.call(null, fun, 0); 2291 } catch (e) { 2292 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error 2293 return cachedSetTimeout.call(this, fun, 0); 2294 } 2295 } 2296} 2297 2298function runClearTimeout(marker) { 2299 if (cachedClearTimeout === clearTimeout) { 2300 //normal enviroments in sane situations 2301 return clearTimeout(marker); 2302 } // if clearTimeout wasn't available but was latter defined 2303 2304 2305 if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { 2306 cachedClearTimeout = clearTimeout; 2307 return clearTimeout(marker); 2308 } 2309 2310 try { 2311 // when when somebody has screwed with setTimeout but no I.E. maddness 2312 return cachedClearTimeout(marker); 2313 } catch (e) { 2314 try { 2315 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 2316 return cachedClearTimeout.call(null, marker); 2317 } catch (e) { 2318 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. 2319 // Some versions of I.E. have different rules for clearTimeout vs setTimeout 2320 return cachedClearTimeout.call(this, marker); 2321 } 2322 } 2323} 2324 2325var queue = []; 2326var draining = false;
vendor: 4,192 bytes, lines 2327-2514
2327var currentQueue; 2328var queueIndex = -1; 2329 2330function cleanUpNextTick() { 2331 if (!draining || !currentQueue) { 2332 return; 2333 } 2334 2335 draining = false; 2336 2337 if (currentQueue.length) { 2338 queue = currentQueue.concat(queue); 2339 } else { 2340 queueIndex = -1; 2341 } 2342 2343 if (queue.length) { 2344 drainQueue(); 2345 } 2346} 2347 2348function drainQueue() { 2349 if (draining) { 2350 return; 2351 } 2352 2353 var timeout = runTimeout(cleanUpNextTick); 2354 draining = true; 2355 var len = queue.length; 2356 2357 while (len) { 2358 currentQueue = queue; 2359 queue = []; 2360 2361 while (++queueIndex < len) { 2362 if (currentQueue) { 2363 currentQueue[queueIndex].run(); 2364 } 2365 } 2366 2367 queueIndex = -1; 2368 len = queue.length; 2369 } 2370 2371 currentQueue = null; 2372 draining = false; 2373 runClearTimeout(timeout); 2374} 2375 2376process.nextTick = function (fun) { 2377 var args = new Array(arguments.length - 1); 2378 2379 if (arguments.length > 1) { 2380 for (var i = 1; i < arguments.length; i++) { 2381 args[i - 1] = arguments[i]; 2382 } 2383 } 2384 2385 queue.push(new Item(fun, args)); 2386 2387 if (queue.length === 1 && !draining) { 2388 runTimeout(drainQueue); 2389 } 2390}; // v8 likes predictible objects 2391 2392 2393function Item(fun, array) { 2394 this.fun = fun; 2395 this.array = array; 2396} 2397 2398Item.prototype.run = function () { 2399 this.fun.apply(null, this.array); 2400}; 2401 2402process.title = 'browser'; 2403process.env = {}; 2404process.argv = []; 2405process.version = ''; // empty string to avoid regexp issues 2406 2407process.versions = {}; 2408 2409function noop() {} 2410 2411process.on = noop; 2412process.addListener = noop; 2413process.once = noop; 2414process.off = noop; 2415process.removeListener = noop; 2416process.removeAllListeners = noop; 2417process.emit = noop; 2418process.prependListener = noop; 2419process.prependOnceListener = noop; 2420 2421process.listeners = function (name) { 2422 return []; 2423}; 2424 2425process.binding = function (name) { 2426 throw new Error('process.binding is not supported'); 2427}; 2428 2429process.cwd = function () { 2430 return '/'; 2431}; 2432 2433process.chdir = function (dir) { 2434 throw new Error('process.chdir is not supported'); 2435}; 2436 2437process.umask = function () { 2438 return 0; 2439}; 2440},{}],"../node_modules/p5/lib/p5.js":[function(require,module,exports) { 2441var define; 2442var global = arguments[3]; 2443var Buffer = require("buffer").Buffer; 2444var process = require("process"); 2445/*! p5.js v0.7.3 January 20, 2019 */ 2446(function (f) { 2447 if (typeof exports === "object" && typeof module !== "undefined") { 2448 module.exports = f(); 2449 } else if (typeof define === "function" && define.amd) { 2450 define([], f); 2451 } else { 2452 var g; 2453 2454 if (typeof window !== "undefined") { 2455 g = window; 2456 } else if (typeof global !== "undefined") { 2457 g = global; 2458 } else if (typeof self !== "undefined") { 2459 g = self; 2460 } else { 2461 g = this; 2462 } 2463 2464 g.p5 = f(); 2465 } 2466})(function () { 2467 var define, module, exports; 2468 return function () { 2469 function r(e, n, t) { 2470 function o(i, f) { 2471 if (!n[i]) { 2472 if (!e[i]) { 2473 var c = "function" == typeof require && require; 2474 if (!f && c) return c(i, !0); 2475 if (u) return u(i, !0); 2476 var a = new Error("Cannot find module '" + i + "'"); 2477 throw a.code = "MODULE_NOT_FOUND", a; 2478 } 2479 2480 var p = n[i] = { 2481 exports: {} 2482 }; 2483 e[i][0].call(p.exports, function (r) { 2484 var n = e[i][1][r]; 2485 return o(n || r); 2486 }, p, p.exports, r, e, n, t); 2487 } 2488 2489 return n[i].exports; 2490 } 2491 2492 for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) o(t[i]); 2493 2494 return o; 2495 } 2496 2497 return r; 2498 }()({ 2499 1: [function (_dereq_, module, exports) { 2500 module.exports = { 2501 "project": { 2502 "name": "p5", 2503 "description": "[](https://travis-ci.org/processing/p5.js) [](https://www.npmjs.com/package/p5)", 2504 "version": "0.7.3", 2505 "url": "https://github.com/processing/p5.js#readme" 2506 }, 2507 "files": { 2508 "src/color/color_conversion.js": { 2509 "name": "src/color/color_conversion.js", 2510 "modules": { 2511 "Color Conversion": 1 2512 }, 2513 "classes": {}, 2514 "fors": {
2515 "p5": 1 2516 }, 2517 "namespaces": {} 2518 }, 2519 "src/color/creating_reading.js": { 2520 "name": "src/color/creating_reading.js", 2521 "modules": { 2522 "Creating & Reading": 1 2523 }, 2524 "classes": {}, 2525 "fors": { 2526 "p5": 1 2527 }, 2528 "namespaces": {} 2529 }, 2530 "src/color/p5.Color.js": { 2531 "name": "src/color/p5.Color.js", 2532 "modules": {}, 2533 "classes": { 2534 "p5.Color": 1 2535 }, 2536 "fors": { 2537 "p5": 1 2538 }, 2539 "namespaces": {} 2540 }, 2541 "src/color/setting.js": { 2542 "name": "src/color/setting.js", 2543 "modules": { 2544 "Setting": 1 2545 }, 2546 "classes": {}, 2547 "fors": { 2548 "p5": 1 2549 }, 2550 "namespaces": {} 2551 }, 2552 "src/core/shape/2d_primitives.js": { 2553 "name": "src/core/shape/2d_primitives.js", 2554 "modules": { 2555 "2D Primitives": 1 2556 }, 2557 "classes": {}, 2558 "fors": { 2559 "p5": 1 2560 }, 2561 "namespaces": {} 2562 }, 2563 "src/core/shape/attributes.js": { 2564 "name": "src/core/shape/attributes.js", 2565 "modules": { 2566 "Attributes": 1 2567 }, 2568 "classes": {}, 2569 "fors": { 2570 "p5": 1 2571 }, 2572 "namespaces": {} 2573 }, 2574 "src/core/shape/curves.js": { 2575 "name": "src/core/shape/curves.js", 2576 "modules": { 2577 "Curves": 1 2578 }, 2579 "classes": {}, 2580 "fors": { 2581 "p5": 1 2582 }, 2583 "namespaces": {} 2584 }, 2585 "src/core/shape/vertex.js": { 2586 "name": "src/core/shape/vertex.js", 2587 "modules": { 2588 "Vertex": 1 2589 }, 2590 "classes": {}, 2591 "fors": { 2592 "p5": 1 2593 }, 2594 "namespaces": {} 2595 }, 2596 "src/core/constants.js": { 2597 "name": "src/core/constants.js", 2598 "modules": { 2599 "Constants": 1 2600 }, 2601 "classes": {}, 2602 "fors": { 2603 "p5": 1 2604 }, 2605 "namespaces": {} 2606 }, 2607 "src/core/environment.js": { 2608 "name": "src/core/environment.js", 2609 "modules": { 2610 "Environment": 1 2611 }, 2612 "classes": {}, 2613 "fors": { 2614 "p5": 1 2615 }, 2616 "namespaces": {} 2617 }, 2618 "src/core/error_helpers.js": { 2619 "name": "src/core/error_helpers.js", 2620 "modules": {}, 2621 "classes": {}, 2622 "fors": { 2623 "p5": 1 2624 }, 2625 "namespaces": {} 2626 }, 2627 "src/core/helpers.js": { 2628 "name": "src/core/helpers.js", 2629 "modules": {}, 2630 "classes": {}, 2631 "fors": {}, 2632 "namespaces": {} 2633 }, 2634 "src/core/init.js": { 2635 "name": "src/core/init.js", 2636 "modules": {}, 2637 "classes": {}, 2638 "fors": {}, 2639 "namespaces": {} 2640 }, 2641 "src/core/legacy.js": { 2642 "name": "src/core/legacy.js", 2643 "modules": {}, 2644 "classes": {}, 2645 "fors": { 2646 "p5": 1 2647 }, 2648 "namespaces": {} 2649 }, 2650 "src/core/main.js": { 2651 "name": "src/core/main.js", 2652 "modules": { 2653 "Structure": 1 2654 }, 2655 "classes": { 2656 "p5": 1 2657 }, 2658 "fors": { 2659 "p5": 1 2660 }, 2661 "namespaces": {} 2662 }, 2663 "src/core/p5.Element.js": { 2664 "name": "src/core/p5.Element.js", 2665 "modules": { 2666 "DOM": 1 2667 }, 2668 "classes": { 2669 "p5.Element": 1 2670 }, 2671 "fors": { 2672 "p5.Element": 1 2673 }, 2674 "namespaces": {} 2675 }, 2676 "src/core/p5.Graphics.js": { 2677 "name": "src/core/p5.Graphics.js", 2678 "modules": { 2679 "Rendering": 1 2680 }, 2681 "classes": {
2682 "p5.Graphics": 1 2683 }, 2684 "fors": { 2685 "p5": 1 2686 }, 2687 "namespaces": {} 2688 }, 2689 "src/core/p5.Renderer.js": { 2690 "name": "src/core/p5.Renderer.js", 2691 "modules": {}, 2692 "classes": { 2693 "p5.Renderer": 1 2694 }, 2695 "fors": { 2696 "p5": 1 2697 }, 2698 "namespaces": {} 2699 }, 2700 "src/core/p5.Renderer2D.js": { 2701 "name": "src/core/p5.Renderer2D.js", 2702 "modules": {}, 2703 "classes": {}, 2704 "fors": {}, 2705 "namespaces": {} 2706 }, 2707 "src/core/rendering.js": { 2708 "name": "src/core/rendering.js", 2709 "modules": {}, 2710 "classes": {}, 2711 "fors": { 2712 "p5": 1 2713 }, 2714 "namespaces": {} 2715 }, 2716 "src/core/shim.js": { 2717 "name": "src/core/shim.js", 2718 "modules": {}, 2719 "classes": {}, 2720 "fors": {}, 2721 "namespaces": {} 2722 }, 2723 "src/core/structure.js": { 2724 "name": "src/core/structure.js", 2725 "modules": {}, 2726 "classes": {}, 2727 "fors": { 2728 "p5": 1 2729 }, 2730 "namespaces": {} 2731 }, 2732 "src/core/transform.js": { 2733 "name": "src/core/transform.js", 2734 "modules": { 2735 "Transform": 1 2736 }, 2737 "classes": {}, 2738 "fors": { 2739 "p5": 1 2740 }, 2741 "namespaces": {} 2742 }, 2743 "src/data/p5.TypedDict.js": { 2744 "name": "src/data/p5.TypedDict.js", 2745 "modules": { 2746 "Dictionary": 1 2747 }, 2748 "classes": { 2749 "p5.TypedDict": 1, 2750 "p5.StringDict": 1, 2751 "p5.NumberDict": 1 2752 }, 2753 "fors": { 2754 "p5.TypedDict": 1, 2755 "p5": 1 2756 }, 2757 "namespaces": {} 2758 }, 2759 "src/events/acceleration.js": { 2760 "name": "src/events/acceleration.js", 2761 "modules": { 2762 "Acceleration": 1 2763 }, 2764 "classes": {}, 2765 "fors": { 2766 "p5": 1 2767 }, 2768 "namespaces": {} 2769 }, 2770 "src/events/keyboard.js": { 2771 "name": "src/events/keyboard.js", 2772 "modules": { 2773 "Keyboard": 1 2774 }, 2775 "classes": {}, 2776 "fors": { 2777 "p5": 1 2778 }, 2779 "namespaces": {} 2780 }, 2781 "src/events/mouse.js": { 2782 "name": "src/events/mouse.js", 2783 "modules": { 2784 "Mouse": 1 2785 }, 2786 "classes": {}, 2787 "fors": { 2788 "p5": 1 2789 }, 2790 "namespaces": {} 2791 }, 2792 "src/events/touch.js": { 2793 "name": "src/events/touch.js", 2794 "modules": { 2795 "Touch": 1 2796 }, 2797 "classes": {}, 2798 "fors": { 2799 "p5": 1 2800 }, 2801 "namespaces": {} 2802 }, 2803 "src/image/filters.js": { 2804 "name": "src/image/filters.js", 2805 "modules": {}, 2806 "classes": {}, 2807 "fors": {}, 2808 "namespaces": {} 2809 }, 2810 "src/image/image.js": { 2811 "name": "src/image/image.js", 2812 "modules": { 2813 "Image": 1 2814 }, 2815 "classes": {}, 2816 "fors": { 2817 "p5": 1 2818 }, 2819 "namespaces": {} 2820 }, 2821 "src/image/loading_displaying.js": { 2822 "name": "src/image/loading_displaying.js", 2823 "modules": { 2824 "Loading & Displaying": 1 2825 }, 2826 "classes": {}, 2827 "fors": { 2828 "p5": 1 2829 }, 2830 "namespaces": {} 2831 }, 2832 "src/image/p5.Image.js": { 2833 "name": "src/image/p5.Image.js", 2834 "modules": {}, 2835 "classes": { 2836 "p5.Image": 1 2837 }, 2838 "fors": {}, 2839 "namespaces": {} 2840 }, 2841 "src/image/pixels.js": { 2842 "name": "src/image/pixels.js", 2843 "modules": { 2844 "Pixels": 1 2845 }, 2846 "classes": {}, 2847 "fors": {
2848 "p5": 1 2849 }, 2850 "namespaces": {} 2851 }, 2852 "src/io/files.js": { 2853 "name": "src/io/files.js", 2854 "modules": { 2855 "Input": 1, 2856 "Output": 1 2857 }, 2858 "classes": { 2859 "p5.PrintWriter": 1 2860 }, 2861 "fors": { 2862 "p5": 1 2863 }, 2864 "namespaces": {} 2865 }, 2866 "src/io/p5.Table.js": { 2867 "name": "src/io/p5.Table.js", 2868 "modules": { 2869 "Table": 1 2870 }, 2871 "classes": { 2872 "p5.Table": 1 2873 }, 2874 "fors": {}, 2875 "namespaces": {} 2876 }, 2877 "src/io/p5.TableRow.js": { 2878 "name": "src/io/p5.TableRow.js", 2879 "modules": {}, 2880 "classes": { 2881 "p5.TableRow": 1 2882 }, 2883 "fors": {}, 2884 "namespaces": {} 2885 }, 2886 "src/io/p5.XML.js": { 2887 "name": "src/io/p5.XML.js", 2888 "modules": { 2889 "XML": 1 2890 }, 2891 "classes": { 2892 "p5.XML": 1 2893 }, 2894 "fors": {}, 2895 "namespaces": {} 2896 }, 2897 "src/math/calculation.js": { 2898 "name": "src/math/calculation.js", 2899 "modules": { 2900 "Calculation": 1 2901 }, 2902 "classes": {}, 2903 "fors": { 2904 "p5": 1 2905 }, 2906 "namespaces": {} 2907 }, 2908 "src/math/math.js": { 2909 "name": "src/math/math.js", 2910 "modules": { 2911 "Math": 1 2912 }, 2913 "classes": {}, 2914 "fors": { 2915 "p5": 1 2916 }, 2917 "namespaces": {} 2918 }, 2919 "src/math/noise.js": { 2920 "name": "src/math/noise.js", 2921 "modules": { 2922 "Noise": 1 2923 }, 2924 "classes": {}, 2925 "fors": { 2926 "p5": 1 2927 }, 2928 "namespaces": {} 2929 }, 2930 "src/math/p5.Vector.js": { 2931 "name": "src/math/p5.Vector.js", 2932 "modules": {}, 2933 "classes": { 2934 "p5.Vector": 1 2935 }, 2936 "fors": {}, 2937 "namespaces": {} 2938 }, 2939 "src/math/random.js": { 2940 "name": "src/math/random.js", 2941 "modules": { 2942 "Random": 1 2943 }, 2944 "classes": {}, 2945 "fors": { 2946 "p5": 1 2947 }, 2948 "namespaces": {} 2949 }, 2950 "src/math/trigonometry.js": { 2951 "name": "src/math/trigonometry.js", 2952 "modules": { 2953 "Trigonometry": 1 2954 }, 2955 "classes": {}, 2956 "fors": { 2957 "p5": 1 2958 }, 2959 "namespaces": {} 2960 }, 2961 "src/typography/attributes.js": { 2962 "name": "src/typography/attributes.js", 2963 "modules": {}, 2964 "classes": {}, 2965 "fors": { 2966 "p5": 1 2967 }, 2968 "namespaces": {} 2969 }, 2970 "src/typography/loading_displaying.js": { 2971 "name": "src/typography/loading_displaying.js", 2972 "modules": {}, 2973 "classes": {}, 2974 "fors": { 2975 "p5": 1 2976 }, 2977 "namespaces": {} 2978 }, 2979 "src/typography/p5.Font.js": { 2980 "name": "src/typography/p5.Font.js", 2981 "modules": { 2982 "Font": 1 2983 }, 2984 "classes": { 2985 "p5.Font": 1 2986 }, 2987 "fors": {}, 2988 "namespaces": {} 2989 }, 2990 "src/utilities/array_functions.js": { 2991 "name": "src/utilities/array_functions.js", 2992 "modules": { 2993 "Array Functions": 1 2994 }, 2995 "classes": {}, 2996 "fors": { 2997 "p5": 1 2998 }, 2999 "namespaces": {} 3000 }, 3001 "src/utilities/conversion.js": { 3002 "name": "src/utilities/conversion.js", 3003 "modules": { 3004 "Conversion": 1 3005 }, 3006 "classes": {}, 3007 "fors": {
3008 "p5": 1 3009 }, 3010 "namespaces": {} 3011 }, 3012 "src/utilities/string_functions.js": { 3013 "name": "src/utilities/string_functions.js", 3014 "modules": { 3015 "String Functions": 1 3016 }, 3017 "classes": {}, 3018 "fors": { 3019 "p5": 1 3020 }, 3021 "namespaces": {} 3022 }, 3023 "src/utilities/time_date.js": { 3024 "name": "src/utilities/time_date.js", 3025 "modules": { 3026 "Time & Date": 1 3027 }, 3028 "classes": {}, 3029 "fors": { 3030 "p5": 1 3031 }, 3032 "namespaces": {} 3033 }, 3034 "src/webgl/3d_primitives.js": { 3035 "name": "src/webgl/3d_primitives.js", 3036 "modules": { 3037 "3D Primitives": 1 3038 }, 3039 "classes": {}, 3040 "fors": { 3041 "p5": 1 3042 }, 3043 "namespaces": {} 3044 }, 3045 "src/webgl/interaction.js": { 3046 "name": "src/webgl/interaction.js", 3047 "modules": { 3048 "Interaction": 1 3049 }, 3050 "classes": {}, 3051 "fors": { 3052 "p5": 1 3053 }, 3054 "namespaces": {} 3055 }, 3056 "src/webgl/light.js": { 3057 "name": "src/webgl/light.js", 3058 "modules": { 3059 "Lights": 1 3060 }, 3061 "classes": {}, 3062 "fors": { 3063 "p5": 1 3064 }, 3065 "namespaces": {} 3066 }, 3067 "src/webgl/loading.js": { 3068 "name": "src/webgl/loading.js", 3069 "modules": { 3070 "3D Models": 1 3071 }, 3072 "classes": {}, 3073 "fors": { 3074 "p5": 1 3075 }, 3076 "namespaces": {} 3077 }, 3078 "src/webgl/material.js": { 3079 "name": "src/webgl/material.js", 3080 "modules": { 3081 "Material": 1 3082 }, 3083 "classes": {}, 3084 "fors": { 3085 "p5": 1 3086 }, 3087 "namespaces": {} 3088 }, 3089 "src/webgl/p5.Camera.js": { 3090 "name": "src/webgl/p5.Camera.js", 3091 "modules": { 3092 "Camera": 1 3093 }, 3094 "classes": { 3095 "p5.Camera": 1 3096 }, 3097 "fors": { 3098 "p5": 1, 3099 "p5.Camera": 1 3100 }, 3101 "namespaces": {} 3102 }, 3103 "src/webgl/p5.Geometry.js": { 3104 "name": "src/webgl/p5.Geometry.js", 3105 "modules": {}, 3106 "classes": { 3107 "p5.Geometry": 1 3108 }, 3109 "fors": {}, 3110 "namespaces": {} 3111 }, 3112 "src/webgl/p5.Matrix.js": { 3113 "name": "src/webgl/p5.Matrix.js", 3114 "modules": {}, 3115 "classes": { 3116 "p5.Matrix": 1 3117 }, 3118 "fors": {}, 3119 "namespaces": {} 3120 }, 3121 "src/webgl/p5.RendererGL.Immediate.js": { 3122 "name": "src/webgl/p5.RendererGL.Immediate.js", 3123 "modules": {}, 3124 "classes": {}, 3125 "fors": {}, 3126 "namespaces": {} 3127 }, 3128 "src/webgl/p5.RendererGL.Retained.js": { 3129 "name": "src/webgl/p5.RendererGL.Retained.js", 3130 "modules": {}, 3131 "classes": {}, 3132 "fors": {}, 3133 "namespaces": {} 3134 }, 3135 "src/webgl/p5.RendererGL.js": { 3136 "name": "src/webgl/p5.RendererGL.js", 3137 "modules": {}, 3138 "classes": { 3139 "p5.RendererGL": 1 3140 }, 3141 "fors": { 3142 "p5": 1 3143 }, 3144 "namespaces": {} 3145 }, 3146 "src/webgl/p5.Shader.js": { 3147 "name": "src/webgl/p5.Shader.js", 3148 "modules": { 3149 "Shaders": 1 3150 }, 3151 "classes": { 3152 "p5.Shader": 1 3153 }, 3154 "fors": { 3155 "p5": 1 3156 }, 3157 "namespaces": {} 3158 }, 3159 "src/webgl/p5.Texture.js": { 3160 "name": "src/webgl/p5.Texture.js", 3161 "modules": {}, 3162 "classes": {
3163 "p5.Texture": 1 3164 }, 3165 "fors": { 3166 "p5": 1 3167 }, 3168 "namespaces": {} 3169 }, 3170 "src/webgl/text.js": { 3171 "name": "src/webgl/text.js", 3172 "modules": {}, 3173 "classes": { 3174 "ImageInfos": 1, 3175 "FontInfo": 1, 3176 "Cubic": 1 3177 }, 3178 "fors": {}, 3179 "namespaces": {} 3180 }, 3181 "lib/addons/p5.dom.js": { 3182 "name": "lib/addons/p5.dom.js", 3183 "modules": { 3184 "p5.dom": 1 3185 }, 3186 "classes": { 3187 "p5.MediaElement": 1, 3188 "p5.File": 1 3189 }, 3190 "fors": { 3191 "p5": 1, 3192 "p5.Element": 1 3193 }, 3194 "namespaces": {} 3195 }, 3196 "lib/addons/p5.sound.js": { 3197 "name": "lib/addons/p5.sound.js", 3198 "modules": { 3199 "p5.sound": 1 3200 }, 3201 "classes": { 3202 "p5.SoundFile": 1, 3203 "p5.Amplitude": 1, 3204 "p5.FFT": 1, 3205 "p5.Signal": 1, 3206 "p5.Oscillator": 1, 3207 "p5.SinOsc": 1, 3208 "p5.TriOsc": 1, 3209 "p5.SawOsc": 1, 3210 "p5.SqrOsc": 1, 3211 "p5.Envelope": 1, 3212 "p5.Pulse": 1, 3213 "p5.Noise": 1, 3214 "p5.AudioIn": 1, 3215 "p5.Effect": 1, 3216 "p5.Filter": 1, 3217 "p5.LowPass": 1, 3218 "p5.HighPass": 1, 3219 "p5.BandPass": 1, 3220 "p5.EQ": 1, 3221 "p5.Panner3D": 1, 3222 "p5.Delay": 1, 3223 "p5.Reverb": 1, 3224 "p5.Convolver": 1, 3225 "p5.Phrase": 1, 3226 "p5.Part": 1, 3227 "p5.Score": 1, 3228 "p5.SoundLoop": 1, 3229 "p5.Compressor": 1, 3230 "p5.SoundRecorder": 1, 3231 "p5.PeakDetect": 1, 3232 "p5.Gain": 1, 3233 "p5.AudioVoice": 1, 3234 "p5.MonoSynth": 1, 3235 "p5.PolySynth": 1, 3236 "p5.Distortion": 1 3237 }, 3238 "fors": { 3239 "p5.sound": 1, 3240 "p5": 1 3241 }, 3242 "namespaces": {} 3243 }, 3244 "lib/addons/p5.sound.min.js": { 3245 "name": "lib/addons/p5.sound.min.js", 3246 "modules": {}, 3247 "classes": {}, 3248 "fors": {}, 3249 "namespaces": {} 3250 } 3251 }, 3252 "modules": { 3253 "Color": { 3254 "name": "Color", 3255 "submodules": { 3256 "Color Conversion": 1, 3257 "Creating & Reading": 1, 3258 "Setting": 1 3259 }, 3260 "elements": {}, 3261 "classes": { 3262 "p5.Color": 1 3263 }, 3264 "fors": { 3265 "p5": 1 3266 }, 3267 "namespaces": {}, 3268 "file": "src/color/p5.Color.js", 3269 "line": 16 3270 }, 3271 "Color Conversion": { 3272 "name": "Color Conversion", 3273 "submodules": {}, 3274 "elements": {}, 3275 "classes": {}, 3276 "fors": { 3277 "p5": 1 3278 }, 3279 "is_submodule": 1, 3280 "namespaces": {}, 3281 "module": "Color", 3282 "namespace": "", 3283 "file": "src/color/color_conversion.js", 3284 "line": 1, 3285 "requires": ["core"] 3286 }, 3287 "Creating & Reading": { 3288 "name": "Creating & Reading", 3289 "submodules": {}, 3290 "elements": {}, 3291 "classes": { 3292 "p5.Color": 1 3293 }, 3294 "fors": { 3295 "p5": 1 3296 }, 3297 "is_submodule": 1, 3298 "namespaces": {}, 3299 "module": "Color", 3300 "namespace": "", 3301 "file": "src/color/p5.Color.js", 3302 "line": 16, 3303 "requires": ["core", "constants"], 3304 "description": "<p>Each color stores the color mode and level maxes that applied at the\ntime of its construction. These are used to interpret the input arguments\n(at construction and later for that instance of color) and to format the\noutput e.g. when <a href=\"#/p5/saturation\">saturation()</a> is requested.</p>\n<p>Internally we store an array representing the ideal RGBA values in floating\npoint form, normalized from 0 to 1. From this we calculate the closest\nscreen color (RGBA levels from 0 to 255) and expose this to the renderer.</p>\n<p>We also cache normalized, floating point components of the color in various\nrepresentations as they are calculated. This is done to prevent repeating a\nconversion that has already been performed.</p>\n" 3305 }, 3306 "Setting": { 3307 "name": "Setting", 3308 "submodules": {}, 3309 "elements": {}, 3310 "classes": {}, 3311 "fors": {
3312 "p5": 1 3313 }, 3314 "is_submodule": 1, 3315 "namespaces": {}, 3316 "module": "Color", 3317 "namespace": "", 3318 "file": "src/color/setting.js", 3319 "line": 1, 3320 "requires": ["core", "constants"] 3321 }, 3322 "Shape": { 3323 "name": "Shape", 3324 "submodules": { 3325 "2D Primitives": 1, 3326 "Curves": 1, 3327 "Vertex": 1, 3328 "3D Primitives": 1, 3329 "3D Models": 1 3330 }, 3331 "elements": {}, 3332 "classes": {}, 3333 "fors": { 3334 "p5": 1 3335 }, 3336 "namespaces": {} 3337 }, 3338 "2D Primitives": { 3339 "name": "2D Primitives", 3340 "submodules": {}, 3341 "elements": {}, 3342 "classes": {}, 3343 "fors": { 3344 "p5": 1 3345 }, 3346 "is_submodule": 1, 3347 "namespaces": {}, 3348 "module": "Shape", 3349 "namespace": "", 3350 "file": "src/core/shape/2d_primitives.js", 3351 "line": 1, 3352 "requires": ["core", "constants"] 3353 }, 3354 "Attributes": { 3355 "name": "Attributes", 3356 "submodules": {}, 3357 "elements": {}, 3358 "classes": {}, 3359 "fors": { 3360 "p5": 1 3361 }, 3362 "is_submodule": 1, 3363 "namespaces": {}, 3364 "module": "Typography", 3365 "namespace": "", 3366 "file": "src/core/shape/attributes.js", 3367 "line": 1, 3368 "requires": ["core", "constants"] 3369 }, 3370 "Curves": { 3371 "name": "Curves", 3372 "submodules": {}, 3373 "elements": {}, 3374 "classes": {}, 3375 "fors": { 3376 "p5": 1 3377 }, 3378 "is_submodule": 1, 3379 "namespaces": {}, 3380 "module": "Shape", 3381 "namespace": "", 3382 "file": "src/core/shape/curves.js", 3383 "line": 1, 3384 "requires": ["core"] 3385 }, 3386 "Vertex": { 3387 "name": "Vertex", 3388 "submodules": {}, 3389 "elements": {}, 3390 "classes": {}, 3391 "fors": { 3392 "p5": 1 3393 }, 3394 "is_submodule": 1, 3395 "namespaces": {}, 3396 "module": "Shape", 3397 "namespace": "", 3398 "file": "src/core/shape/vertex.js", 3399 "line": 1, 3400 "requires": ["core", "constants"] 3401 }, 3402 "Constants": { 3403 "name": "Constants", 3404 "submodules": {}, 3405 "elements": {}, 3406 "classes": {}, 3407 "fors": { 3408 "p5": 1 3409 }, 3410 "namespaces": {}, 3411 "module": "Constants", 3412 "file": "src/core/constants.js", 3413 "line": 1 3414 }, 3415 "Environment": { 3416 "name": "Environment", 3417 "submodules": {}, 3418 "elements": {}, 3419 "classes": {}, 3420 "fors": { 3421 "p5": 1 3422 }, 3423 "namespaces": {}, 3424 "module": "Environment", 3425 "file": "src/core/environment.js", 3426 "line": 1, 3427 "requires": ["core", "constants"] 3428 }, 3429 "Structure": { 3430 "name": "Structure", 3431 "submodules": {}, 3432 "elements": {}, 3433 "classes": {}, 3434 "fors": { 3435 "p5": 1 3436 }, 3437 "namespaces": {}, 3438 "module": "IO", 3439 "file": "src/core/main.js", 3440 "line": 1, 3441 "requires": ["constants"] 3442 }, 3443 "DOM": { 3444 "name": "DOM", 3445 "submodules": {}, 3446 "elements": {}, 3447 "classes": { 3448 "p5.Element": 1 3449 }, 3450 "fors": { 3451 "p5.Element": 1 3452 }, 3453 "namespaces": {}, 3454 "module": "DOM", 3455 "file": "src/core/p5.Element.js", 3456 "line": 11, 3457 "description": "<p>Base class for all elements added to a sketch, including canvas,\ngraphics buffers, and other HTML elements. Methods in blue are\nincluded in the core functionality, methods in brown are added\nwith the <a href=\"http://p5js.org/reference/#/libraries/p5.dom\">p5.dom\nlibrary</a>.\nIt is not called directly, but <a href=\"#/p5.Element\">p5.Element</a>\nobjects are created by calling <a href=\"#/p5/createCanvas\">createCanvas</a>, <a href=\"#/p5/createGraphics\">createGraphics</a>,\nor in the p5.dom library, <a href=\"#/p5/createDiv\">createDiv</a>, <a href=\"#/p5/createImg\">createImg</a>, <a href=\"#/p5/createInput\">createInput</a>, etc.</p>\n" 3458 }, 3459 "Rendering": { 3460 "name": "Rendering", 3461 "submodules": { 3462 "undefined": 1 3463 }, 3464 "elements": {}, 3465 "classes": {
3466 "p5.RendererGL": 1, 3467 "p5.Graphics": 1, 3468 "p5.Renderer": 1 3469 }, 3470 "fors": { 3471 "p5": 1 3472 }, 3473 "namespaces": {}, 3474 "module": "Rendering", 3475 "file": "src/webgl/p5.RendererGL.js", 3476 "line": 428, 3477 "description": "<p>Thin wrapper around a renderer, to be used for creating a\ngraphics buffer object. Use this class if you need\nto draw into an off-screen graphics buffer. The two parameters define the\nwidth and height in pixels. The fields and methods for this class are\nextensive, but mirror the normal drawing API for p5.</p>\n" 3478 }, 3479 "Transform": { 3480 "name": "Transform", 3481 "submodules": {}, 3482 "elements": {}, 3483 "classes": {}, 3484 "fors": { 3485 "p5": 1 3486 }, 3487 "namespaces": {}, 3488 "module": "Transform", 3489 "file": "src/core/transform.js", 3490 "line": 1, 3491 "requires": ["core", "constants"] 3492 }, 3493 "Data": { 3494 "name": "Data", 3495 "submodules": { 3496 "Dictionary": 1, 3497 "Array Functions": 1, 3498 "Conversion": 1, 3499 "String Functions": 1 3500 }, 3501 "elements": {}, 3502 "classes": { 3503 "p5.TypedDict": 1, 3504 "p5.StringDict": 1, 3505 "p5.NumberDict": 1 3506 }, 3507 "fors": { 3508 "p5.TypedDict": 1, 3509 "p5": 1 3510 }, 3511 "namespaces": {}, 3512 "file": "src/data/p5.TypedDict.js", 3513 "line": 422 3514 }, 3515 "Dictionary": { 3516 "name": "Dictionary", 3517 "submodules": {}, 3518 "elements": {}, 3519 "classes": { 3520 "p5.TypedDict": 1, 3521 "p5.StringDict": 1, 3522 "p5.NumberDict": 1 3523 }, 3524 "fors": { 3525 "p5.TypedDict": 1, 3526 "p5": 1 3527 }, 3528 "is_submodule": 1, 3529 "namespaces": {}, 3530 "module": "Data", 3531 "namespace": "", 3532 "file": "src/data/p5.TypedDict.js", 3533 "line": 422, 3534 "requires": ["core\n\nThis module defines the p5 methods for the p5 Dictionary classes.\nThe classes StringDict and NumberDict are for storing and working\nwith key-value pairs."], 3535 "description": "<p>Base class for all p5.Dictionary types. Specifically\n typed Dictionary classes inherit from this class.</p>\n" 3536 }, 3537 "Events": { 3538 "name": "Events", 3539 "submodules": { 3540 "Acceleration": 1, 3541 "Keyboard": 1, 3542 "Mouse": 1, 3543 "Touch": 1 3544 }, 3545 "elements": {}, 3546 "classes": {}, 3547 "fors": { 3548 "p5": 1 3549 }, 3550 "namespaces": {} 3551 }, 3552 "Acceleration": { 3553 "name": "Acceleration", 3554 "submodules": {}, 3555 "elements": {}, 3556 "classes": {}, 3557 "fors": { 3558 "p5": 1 3559 }, 3560 "is_submodule": 1, 3561 "namespaces": {}, 3562 "module": "Events", 3563 "namespace": "", 3564 "file": "src/events/acceleration.js", 3565 "line": 1, 3566 "requires": ["core"] 3567 }, 3568 "Keyboard": { 3569 "name": "Keyboard", 3570 "submodules": {}, 3571 "elements": {}, 3572 "classes": {}, 3573 "fors": { 3574 "p5": 1 3575 }, 3576 "is_submodule": 1, 3577 "namespaces": {}, 3578 "module": "Events", 3579 "namespace": "", 3580 "file": "src/events/keyboard.js", 3581 "line": 1, 3582 "requires": ["core"] 3583 }, 3584 "Mouse": { 3585 "name": "Mouse", 3586 "submodules": {}, 3587 "elements": {}, 3588 "classes": {}, 3589 "fors": { 3590 "p5": 1 3591 }, 3592 "is_submodule": 1, 3593 "namespaces": {}, 3594 "module": "Events", 3595 "namespace": "", 3596 "file": "src/events/mouse.js", 3597 "line": 1, 3598 "requires": ["core", "constants"] 3599 }, 3600 "Touch": { 3601 "name": "Touch", 3602 "submodules": {}, 3603 "elements": {}, 3604 "classes": {}, 3605 "fors": {
3606 "p5": 1 3607 }, 3608 "is_submodule": 1, 3609 "namespaces": {}, 3610 "module": "Events", 3611 "namespace": "", 3612 "file": "src/events/touch.js", 3613 "line": 1, 3614 "requires": ["core"] 3615 }, 3616 "Image": { 3617 "name": "Image", 3618 "submodules": { 3619 "Pixels": 1 3620 }, 3621 "elements": {}, 3622 "classes": { 3623 "p5.Image": 1 3624 }, 3625 "fors": { 3626 "p5": 1 3627 }, 3628 "namespaces": {}, 3629 "module": "Image", 3630 "file": "src/image/p5.Image.js", 3631 "line": 23, 3632 "requires": ["core"], 3633 "description": "<p>Creates a new <a href=\"#/p5.Image\">p5.Image</a>. A <a href=\"#/p5.Image\">p5.Image</a> is a canvas backed representation of an\nimage.\n<br><br>\np5 can display .gif, .jpg and .png images. Images may be displayed\nin 2D and 3D space. Before an image is used, it must be loaded with the\n<a href=\"#/p5/loadImage\">loadImage()</a> function. The <a href=\"#/p5.Image\">p5.Image</a> class contains fields for the width and\nheight of the image, as well as an array called <a href=\"#/p5.Image/pixels\">pixels[]</a> that contains the\nvalues for every pixel in the image.\n<br><br>\nThe methods described below allow easy access to the image's pixels and\nalpha channel and simplify the process of compositing.\n<br><br>\nBefore using the <a href=\"#/p5.Image/pixels\">pixels[]</a> array, be sure to use the <a href=\"#/p5.Image/loadPixels\">loadPixels()</a> method on\nthe image to make sure that the pixel data is properly loaded.</p>\n" 3634 }, 3635 "Loading & Displaying": { 3636 "name": "Loading & Displaying", 3637 "submodules": {}, 3638 "elements": {}, 3639 "classes": {}, 3640 "fors": { 3641 "p5": 1 3642 }, 3643 "is_submodule": 1, 3644 "namespaces": {}, 3645 "module": "Typography", 3646 "namespace": "", 3647 "file": "src/image/loading_displaying.js", 3648 "line": 1, 3649 "requires": ["core"] 3650 }, 3651 "Pixels": { 3652 "name": "Pixels", 3653 "submodules": {}, 3654 "elements": {}, 3655 "classes": {}, 3656 "fors": { 3657 "p5": 1 3658 }, 3659 "is_submodule": 1, 3660 "namespaces": {}, 3661 "module": "Image", 3662 "namespace": "", 3663 "file": "src/image/pixels.js", 3664 "line": 1, 3665 "requires": ["core"] 3666 }, 3667 "IO": { 3668 "name": "IO", 3669 "submodules": { 3670 "Structure": 1, 3671 "Input": 1, 3672 "Output": 1, 3673 "Table": 1, 3674 "XML": 1, 3675 "Time & Date": 1 3676 }, 3677 "elements": {}, 3678 "classes": { 3679 "p5": 1, 3680 "p5.PrintWriter": 1, 3681 "p5.Table": 1, 3682 "p5.TableRow": 1, 3683 "p5.XML": 1 3684 }, 3685 "fors": { 3686 "p5": 1 3687 }, 3688 "namespaces": {}, 3689 "file": "src/io/p5.XML.js", 3690 "line": 11 3691 }, 3692 "Input": { 3693 "name": "Input", 3694 "submodules": {}, 3695 "elements": {}, 3696 "classes": {}, 3697 "fors": { 3698 "p5": 1 3699 }, 3700 "is_submodule": 1, 3701 "namespaces": {}, 3702 "module": "IO", 3703 "namespace": "", 3704 "file": "src/io/files.js", 3705 "line": 1, 3706 "requires": ["core"] 3707 }, 3708 "Output": { 3709 "name": "Output", 3710 "submodules": {}, 3711 "elements": {}, 3712 "classes": { 3713 "p5": 1, 3714 "p5.PrintWriter": 1 3715 }, 3716 "fors": { 3717 "p5": 1 3718 }, 3719 "is_submodule": 1, 3720 "namespaces": {}, 3721 "module": "IO", 3722 "namespace": "", 3723 "file": "src/io/files.js", 3724 "line": 1228, 3725 "description": "<p>This is the p5 instance constructor.</p>\n<p>A p5 instance holds all the properties and methods related to\na p5 sketch. It expects an incoming sketch closure and it can also\ntake an optional node parameter for attaching the generated p5 canvas\nto a node. The sketch closure takes the newly created p5 instance as\nits s
3725ole argument and may optionally set <a href=\"#/p5/preload\">preload()</a>, <a href=\"#/p5/setup\">setup()</a>, and/or\n<a href=\"#/p5/draw\">draw()</a> properties on it for running a sketch.</p>\n<p>A p5 sketch can run in "global" or "instance" mode:\n"global" - all properties and methods are attached to the window\n"instance" - all properties and methods are bound to this p5 object</p>\n" 3726 }, 3727 "Table": { 3728 "name": "Table", 3729 "submodules": {}, 3730 "elements": {}, 3731 "classes": { 3732 "p5.Table": 1, 3733 "p5.TableRow": 1 3734 }, 3735 "fors": {}, 3736 "is_submodule": 1, 3737 "namespaces": {}, 3738 "module": "IO", 3739 "namespace": "", 3740 "file": "src/io/p5.TableRow.js", 3741 "line": 11, 3742 "requires": ["core"], 3743 "description": "<p><a href=\"#/p5.Table\">Table</a> objects store data with multiple rows and columns, much\nlike in a traditional spreadsheet. Tables can be generated from\nscratch, dynamically, or using data from an existing file.</p>\n" 3744 }, 3745 "XML": { 3746 "name": "XML", 3747 "submodules": {}, 3748 "elements": {}, 3749 "classes": { 3750 "p5.XML": 1 3751 }, 3752 "fors": {}, 3753 "is_submodule": 1, 3754 "namespaces": {}, 3755 "module": "IO", 3756 "namespace": "", 3757 "file": "src/io/p5.XML.js", 3758 "line": 11, 3759 "requires": ["core"], 3760 "description": "<p>XML is a representation of an XML object, able to parse XML code. Use\n<a href=\"#/p5/loadXML\">loadXML()</a> to load external XML files and create XML objects.</p>\n" 3761 }, 3762 "Math": { 3763 "name": "Math", 3764 "submodules": { 3765 "Calculation": 1, 3766 "Noise": 1, 3767 "Random": 1, 3768 "Trigonometry": 1 3769 }, 3770 "elements": {}, 3771 "classes": { 3772 "p5.Vector": 1 3773 }, 3774 "fors": { 3775 "p5": 1 3776 }, 3777 "namespaces": {}, 3778 "module": "Math", 3779 "file": "src/math/p5.Vector.js", 3780 "line": 12, 3781 "requires": ["core"], 3782 "description": "<p>A class to describe a two or three dimensional vector, specifically\na Euclidean (also known as geometric) vector. A vector is an entity\nthat has both magnitude and direction. The datatype, however, stores\nthe components of the vector (x, y for 2D, and x, y, z for 3D). The magnitude\nand direction can be accessed via the methods <a href=\"#/p5/mag\">mag()</a> and <a href=\"#/p5/heading\">heading()</a>.\n<br><br>\nIn many of the p5.js examples, you will see <a href=\"#/p5.Vector\">p5.Vector</a> used to describe a\nposition, velocity, or acceleration. For example, if you consider a rectangle\nmoving across the screen, at any given instant it has a position (a vector\nthat points from the origin to its location), a velocity (the rate at which\nthe object's position changes per time unit, expressed as a vector), and\nacceleration (the rate at which the object's velocity changes per time\nunit, expressed as a vector).\n<br><br>\nSince vectors represent groupings of values, we cannot simply use\ntraditional addition/multiplication/etc. Instead, we'll need to do some\n"vector" math, which is made easy by the methods inside the <a href=\"#/p5.Vector\">p5.Vector</a> class.</p>\n" 3783 }, 3784 "Calculation": { 3785 "name": "Calculation", 3786 "submodules": {}, 3787 "elements": {}, 3788 "classes": {}, 3789 "fors": { 3790 "p5": 1 3791 }, 3792 "is_submodule": 1, 3793 "namespaces": {}, 3794 "module": "Math", 3795 "namespace": "", 3796 "file": "src/math/calculation.js", 3797 "line": 1, 3798 "requires": ["core"] 3799 }, 3800 "Noise": { 3801 "name": "Noise", 3802 "submodules": {}, 3803 "elements": {}, 3804 "classes": {}, 3805 "fors": {
3806 "p5": 1 3807 }, 3808 "is_submodule": 1, 3809 "namespaces": {}, 3810 "module": "Math", 3811 "namespace": "", 3812 "file": "src/math/noise.js", 3813 "line": 14, 3814 "requires": ["core"] 3815 }, 3816 "Random": { 3817 "name": "Random", 3818 "submodules": {}, 3819 "elements": {}, 3820 "classes": {}, 3821 "fors": { 3822 "p5": 1 3823 }, 3824 "is_submodule": 1, 3825 "namespaces": {}, 3826 "module": "Math", 3827 "namespace": "", 3828 "file": "src/math/random.js", 3829 "line": 1, 3830 "requires": ["core"] 3831 }, 3832 "Trigonometry": { 3833 "name": "Trigonometry", 3834 "submodules": {}, 3835 "elements": {}, 3836 "classes": {}, 3837 "fors": { 3838 "p5": 1 3839 }, 3840 "is_submodule": 1, 3841 "namespaces": {}, 3842 "module": "Math", 3843 "namespace": "", 3844 "file": "src/math/trigonometry.js", 3845 "line": 1, 3846 "requires": ["core", "constants"] 3847 }, 3848 "Typography": { 3849 "name": "Typography", 3850 "submodules": { 3851 "Attributes": 1, 3852 "Loading & Displaying": 1, 3853 "Font": 1 3854 }, 3855 "elements": {}, 3856 "classes": { 3857 "p5.Font": 1 3858 }, 3859 "fors": { 3860 "p5": 1 3861 }, 3862 "namespaces": {}, 3863 "file": "src/typography/p5.Font.js", 3864 "line": 15 3865 }, 3866 "Font": { 3867 "name": "Font", 3868 "submodules": {}, 3869 "elements": {}, 3870 "classes": { 3871 "p5.Font": 1 3872 }, 3873 "fors": {}, 3874 "is_submodule": 1, 3875 "namespaces": {}, 3876 "module": "Typography", 3877 "namespace": "", 3878 "file": "src/typography/p5.Font.js", 3879 "line": 15, 3880 "description": "<p>This module defines the <a href=\"#/p5.Font\">p5.Font</a> class and functions for\ndrawing text to the display canvas.</p>\n", 3881 "requires": ["core", "constants"] 3882 }, 3883 "Array Functions": { 3884 "name": "Array Functions", 3885 "submodules": {}, 3886 "elements": {}, 3887 "classes": {}, 3888 "fors": { 3889 "p5": 1 3890 }, 3891 "is_submodule": 1, 3892 "namespaces": {}, 3893 "module": "Data", 3894 "namespace": "", 3895 "file": "src/utilities/array_functions.js", 3896 "line": 1, 3897 "requires": ["core"] 3898 }, 3899 "Conversion": { 3900 "name": "Conversion", 3901 "submodules": {}, 3902 "elements": {}, 3903 "classes": {}, 3904 "fors": { 3905 "p5": 1 3906 }, 3907 "is_submodule": 1, 3908 "namespaces": {}, 3909 "module": "Data", 3910 "namespace": "", 3911 "file": "src/utilities/conversion.js", 3912 "line": 1, 3913 "requires": ["core"] 3914 }, 3915 "String Functions": { 3916 "name": "String Functions", 3917 "submodules": {}, 3918 "elements": {}, 3919 "classes": {}, 3920 "fors": { 3921 "p5": 1 3922 }, 3923 "is_submodule": 1, 3924 "namespaces": {}, 3925 "module": "Data", 3926 "namespace": "", 3927 "file": "src/utilities/string_functions.js", 3928 "line": 1, 3929 "requires": ["core"] 3930 }, 3931 "Time & Date": { 3932 "name": "Time & Date", 3933 "submodules": {}, 3934 "elements": {}, 3935 "classes": {}, 3936 "fors": { 3937 "p5": 1 3938 }, 3939 "is_submodule": 1, 3940 "namespaces": {}, 3941 "module": "IO", 3942 "namespace": "", 3943 "file": "src/utilities/time_date.js", 3944 "line": 1, 3945 "requires": ["core"] 3946 }, 3947 "3D Primitives": { 3948 "name": "3D Primitives", 3949 "submodules": {}, 3950 "elements": {}, 3951 "classes": {}, 3952 "fors": {
3953 "p5": 1 3954 }, 3955 "is_submodule": 1, 3956 "namespaces": {}, 3957 "module": "Shape", 3958 "namespace": "", 3959 "file": "src/webgl/3d_primitives.js", 3960 "line": 1, 3961 "requires": ["core", "p5.Geometry"] 3962 }, 3963 "Lights, Camera": { 3964 "name": "Lights, Camera", 3965 "submodules": { 3966 "Interaction": 1, 3967 "Lights": 1, 3968 "Material": 1, 3969 "Camera": 1, 3970 "Shaders": 1 3971 }, 3972 "elements": {}, 3973 "classes": { 3974 "p5.Camera": 1, 3975 "p5.Geometry": 1, 3976 "p5.Matrix": 1, 3977 "p5.Shader": 1, 3978 "p5.Texture": 1, 3979 "ImageInfos": 1, 3980 "FontInfo": 1, 3981 "Cubic": 1 3982 }, 3983 "fors": { 3984 "p5": 1, 3985 "p5.Camera": 1 3986 }, 3987 "namespaces": {}, 3988 "file": "src/webgl/text.js", 3989 "line": 259 3990 }, 3991 "Interaction": { 3992 "name": "Interaction", 3993 "submodules": {}, 3994 "elements": {}, 3995 "classes": {}, 3996 "fors": { 3997 "p5": 1 3998 }, 3999 "is_submodule": 1, 4000 "namespaces": {}, 4001 "module": "Lights, Camera", 4002 "namespace": "", 4003 "file": "src/webgl/interaction.js", 4004 "line": 1, 4005 "requires": ["core"] 4006 }, 4007 "Lights": { 4008 "name": "Lights", 4009 "submodules": {}, 4010 "elements": {}, 4011 "classes": {}, 4012 "fors": { 4013 "p5": 1 4014 }, 4015 "is_submodule": 1, 4016 "namespaces": {}, 4017 "module": "Lights, Camera", 4018 "namespace": "", 4019 "file": "src/webgl/light.js", 4020 "line": 1, 4021 "requires": ["core"] 4022 }, 4023 "3D Models": { 4024 "name": "3D Models", 4025 "submodules": {}, 4026 "elements": {}, 4027 "classes": {}, 4028 "fors": { 4029 "p5": 1 4030 }, 4031 "is_submodule": 1, 4032 "namespaces": {}, 4033 "module": "Shape", 4034 "namespace": "", 4035 "file": "src/webgl/loading.js", 4036 "line": 1, 4037 "requires": ["core", "p5.Geometry"] 4038 }, 4039 "Material": { 4040 "name": "Material", 4041 "submodules": {}, 4042 "elements": {}, 4043 "classes": { 4044 "p5.Texture": 1 4045 }, 4046 "fors": { 4047 "p5": 1 4048 }, 4049 "is_submodule": 1, 4050 "namespaces": {}, 4051 "module": "Lights, Camera", 4052 "namespace": "", 4053 "file": "src/webgl/p5.Texture.js", 4054 "line": 14, 4055 "requires": ["core"], 4056 "description": "<p>This module defines the p5.Texture class</p>\n" 4057 }, 4058 "Camera": { 4059 "name": "Camera", 4060 "submodules": {}, 4061 "elements": {}, 4062 "classes": { 4063 "p5.Camera": 1 4064 }, 4065 "fors": { 4066 "p5": 1, 4067 "p5.Camera": 1 4068 }, 4069 "is_submodule": 1, 4070 "namespaces": {}, 4071 "module": "Lights, Camera", 4072 "namespace": "", 4073 "file": "src/webgl/p5.Camera.js", 4074 "line": 209, 4075 "requires": ["core"], 4076 "description": "<p>This class describes a camera for use in p5's\n<a href=\"https://github.com/processing/p5.js/wiki/Getting-started-with-WebGL-in-p5\">\nWebGL mode</a>. It contains camera position, orientation, and projection\ninformation necessary for rendering a 3D scene.</p>\n<p>New p5.Camera objects can be made through the\n<a href=\"#/p5/createCamera\">createCamera()</a> function and controlled through\nthe methods described below. A camera created in this way will use a default\nposition in the scene and a default perspective projection until these\nproperties are changed through the various methods available. It is possible\nto create multiple cameras, in which case the current camera\ncan be set through the <a href=\"#/p5/setCamera\">setCamera()</a> method.</p>\n<p>Note:\nThe methods below operate in two coordinate systems: the 'world' coordinate\nsystem describe positions in terms of their relationship to the origin along\nthe X, Y and Z axes whereas the camera's 'local' coordinate system\ndescribes positions from the camera's point of view: left-right, up-down,\nand forward-backward. The <a href=\"#/p5.Camera/move\">move()</a> method,\nfor instance, moves the camera along its own axes, whereas the\n<a href=\"#/p5.Camera/setPosition\">setPosition()</a>\nmethod sets the camera's position in world-space.</p>\n" 4077 }, 4078 "Shaders": { 4079 "name": "Shaders", 4080 "submodules": {}, 4081 "elements": {}, 4082 "classes": {
4083 "p5.Shader": 1 4084 }, 4085 "fors": { 4086 "p5": 1 4087 }, 4088 "is_submodule": 1, 4089 "namespaces": {}, 4090 "module": "Lights, Camera", 4091 "namespace": "", 4092 "file": "src/webgl/p5.Shader.js", 4093 "line": 13, 4094 "description": "<p>This module defines the p5.Shader class</p>\n", 4095 "requires": ["core"] 4096 }, 4097 "p5.dom": { 4098 "name": "p5.dom", 4099 "submodules": {}, 4100 "elements": {}, 4101 "classes": { 4102 "p5.MediaElement": 1, 4103 "p5.File": 1 4104 }, 4105 "fors": { 4106 "p5": 1, 4107 "p5.Element": 1 4108 }, 4109 "namespaces": {}, 4110 "module": "p5.dom", 4111 "file": "lib/addons/p5.dom.js", 4112 "line": 3170, 4113 "description": "<p><p>The web is much more than just canvas and p5.dom makes it easy to interact\nwith other HTML5 objects, including text, hyperlink, image, input, video,\naudio, and webcam.</p></p>\n<p><p>There is a set of creation methods, DOM manipulation methods, and\nan extended <a href=\"#/p5.Element\">p5.Element</a> that supports a range of HTML elements. See the\n<a href='https://github.com/processing/p5.js/wiki/Beyond-the-canvas'>\nbeyond the canvas tutorial</a> for a full overview of how this addon works.</p>\n<p><p>Methods and properties shown in black are part of the p5.js core, items in\nblue are part of the p5.dom library. You will need to include an extra file\nin order to access the blue functions. See the\n<a href='http://p5js.org/libraries/#using-a-library'>using a library</a>\nsection for information on how to include this library. p5.dom comes with\n<a href='http://p5js.org/download'>p5 complete</a> or you can download the single file\n<a href='https://raw.githubusercontent.com/lmccart/p5.js/master/lib/addons/p5.dom.js'>\nhere</a>.</p></p>\n<p><p>See <a href='https://github.com/processing/p5.js/wiki/Beyond-the-canvas'>tutorial: beyond the canvas</a>\nfor more info on how to use this library.</a></p>\n", 4114 "tag": "main", 4115 "itemtype": "main" 4116 }, 4117 "p5.sound": { 4118 "name": "p5.sound", 4119 "submodules": {}, 4120 "elements": {}, 4121 "classes": { 4122 "p5.sound": 1, 4123 "p5.SoundFile": 1, 4124 "p5.Amplitude": 1, 4125 "p5.FFT": 1, 4126 "p5.Signal": 1, 4127 "p5.Oscillator": 1, 4128 "p5.SinOsc": 1, 4129 "p5.TriOsc": 1, 4130 "p5.SawOsc": 1, 4131 "p5.SqrOsc": 1, 4132 "p5.Envelope": 1, 4133 "p5.Pulse": 1, 4134 "p5.Noise": 1, 4135 "p5.AudioIn": 1, 4136 "p5.Effect": 1, 4137 "p5.Filter": 1, 4138 "p5.LowPass": 1, 4139 "p5.HighPass": 1, 4140 "p5.BandPass": 1, 4141 "p5.EQ": 1, 4142 "p5.Panner3D": 1, 4143 "p5.Delay": 1, 4144 "p5.Reverb": 1, 4145 "p5.Convolver": 1, 4146 "p5.Phrase": 1, 4147 "p5.Part": 1, 4148 "p5.Score": 1, 4149 "p5.SoundLoop": 1, 4150 "p5.Compressor": 1, 4151 "p5.SoundRecorder": 1, 4152 "p5.PeakDetect": 1, 4153 "p5.Gain": 1, 4154 "p5.AudioVoice": 1, 4155 "p5.MonoSynth": 1, 4156 "p5.PolySynth": 1, 4157 "p5.Distortion": 1 4158 }, 4159 "fors": { 4160 "p5.sound": 1, 4161 "p5": 1 4162 }, 4163 "namespaces": {}, 4164 "module": "p5.sound", 4165 "file": "lib/addons/p5.sound.js", 4166 "line": 12761, 4167 "description": "<p>p5.sound extends p5 with <a href=\"http://caniuse.com/audio-api\"\ntarget=\"_blank\">Web Audio</a> functionality including audio input,\nplayback, analysis and synthesis.\n<br/><br/>\n<a href=\"#/p5.SoundFile\"><b>p5.SoundFile</b></a>: Load and play sound files.<br/>\n<a href=\"#/p5.Amplitude\"><b>p5.Amplitude</b></a>: Get the current volume of a sound.<br/>\n<a href=\"#/p5.AudioIn\"><b>p5.AudioIn</b></a>: Get sound from an input source, typically\n a computer microphone.<br/>\n<a href=\"#/p5.FFT\"><b>p5.FFT</b></a>: Analyze the frequency of sound. Returns\n results from the frequency spectrum or time domain (waveform).<br/>\n<a href=\"#/p5.Oscillator\"><b>p5.Oscillator</b></a>: Generate Sine,\n Triangle, Square and Sawtooth waveforms. Base class of\n
4167<a href=\"#/p5.Noise\">p5.Noise</a> and <a href=\"#/p5.Pulse\">p5.Pulse</a>.\n <br/>\n<a href=\"#/p5.Envelope\"><b>p5.Envelope</b></a>: An Envelope is a series\n of fades over time. Often used to control an object's\n output gain level as an "ADSR Envelope" (Attack, Decay,\n Sustain, Release). Can also modulate other parameters.<br/>\n<a href=\"#/p5.Delay\"><b>p5.Delay</b></a>: A delay effect with\n parameters for feedback, delayTime, and lowpass filter.<br/>\n<a href=\"#/p5.Filter\"><b>p5.Filter</b></a>: Filter the frequency range of a\n sound.\n<br/>\n<a href=\"#/p5.Reverb\"><b>p5.Reverb</b></a>: Add reverb to a sound by specifying\n duration and decay. <br/>\n<b><a href=\"#/p5.Convolver\">p5.Convolver</a>:</b> Extends\n<a href=\"#/p5.Reverb\">p5.Reverb</a> to simulate the sound of real\n physical spaces through convolution.<br/>\n<b><a href=\"#/p5.SoundRecorder\">p5.SoundRecorder</a></b>: Record sound for playback\n / save the .wav file.\n<b><a href=\"#/p5.Phrase\">p5.Phrase</a></b>, <b><a href=\"#/p5.Part\">p5.Part</a></b> and\n<b><a href=\"#/p5.Score\">p5.Score</a></b>: Compose musical sequences.\n<br/><br/>\np5.sound is on <a href=\"https://github.com/therewasaguy/p5.sound/\">GitHub</a>.\nDownload the latest version\n<a href=\"https://github.com/therewasaguy/p5.sound/blob/master/lib/p5.sound.js\">here</a>.</p>\n", 4168 "tag": "main", 4169 "itemtype": "main" 4170 } 4171 }, 4172 "classes": { 4173 "p5": { 4174 "name": "p5", 4175 "shortname": "p5", 4176 "classitems": [], 4177 "plugins": [], 4178 "extensions": [], 4179 "plugin_for": [], 4180 "extension_for": [], 4181 "module": "IO", 4182 "submodule": "Output", 4183 "namespace": "", 4184 "file": "src/core/main.js", 4185 "line": 15, 4186 "description": "<p>This is the p5 instance constructor.</p>\n<p>A p5 instance holds all the properties and methods related to\na p5 sketch. It expects an incoming sketch closure and it can also\ntake an optional node parameter for attaching the generated p5 canvas\nto a node. The sketch closure takes the newly created p5 instance as\nits sole argument and may optionally set <a href=\"#/p5/preload\">preload()</a>, <a href=\"#/p5/setup\">setup()</a>, and/or\n<a href=\"#/p5/draw\">draw()</a> properties on it for running a sketch.</p>\n<p>A p5 sketch can run in "global" or "instance" mode:\n"global" - all properties and methods are attached to the window\n"instance" - all properties and methods are bound to this p5 object</p>\n", 4187 "is_constructor": 1, 4188 "params": [{ 4189 "name": "sketch", 4190 "description": "<p>a closure that can set optional <a href=\"#/p5/preload\">preload()</a>,\n <a href=\"#/p5/setup\">setup()</a>, and/or <a href=\"#/p5/draw\">draw()</a> properties on the\n given p5 instance</p>\n", 4191 "type": "Function" 4192 }, { 4193 "name": "node", 4194 "description": "<p>element to attach canvas to, if a\n boolean is passed in use it as sync</p>\n", 4195 "type": "HTMLElement|Boolean", 4196 "optional": true 4197 }, { 4198 "name": "sync", 4199 "description": "<p>start synchronously (optional)</p>\n", 4200 "type": "Boolean", 4201 "optional": true 4202 }], 4203 "return": { 4204 "description": "a p5 instance", 4205 "type": "P5" 4206 } 4207 }, 4208 "p5.Color": { 4209 "name": "p5.Color", 4210 "shortname": "p5.Color", 4211 "classitems": [], 4212 "plugins": [], 4213 "extensions": [], 4214 "plugin_for": [], 4215 "extension_for": [], 4216 "module": "Color", 4217 "submodule": "Creating & Reading", 4218 "namespace": "", 4219 "file": "src/color/p5.Color.js", 4220 "line": 16, 4221 "description": "<p>Each color stores the color mode and level maxes that applied at the\ntime of its construction. These are used to interpret the input arguments\n(at construction and later for that instance of color) and to format the\noutput e.g. when <a href=\"#/p5/saturation\">saturation()</a> is requested.</p>\n<p>Internally we store an array representing the ideal RGBA values in floating\npoint form, normalized from 0 to 1. From this we calculate the closest\nscreen color (RGBA levels from 0 to 255) and expose this to the renderer.</p>\n<p>We also cache normalized, floating point components of the color in various\nrepresentations as they are calculated. This is done to prevent repeating a\nconversion that has already been performed.</p>\n" 4222 },
4223 "p5.Element": { 4224 "name": "p5.Element", 4225 "shortname": "p5.Element", 4226 "classitems": [], 4227 "plugins": [], 4228 "extensions": [], 4229 "plugin_for": [], 4230 "extension_for": [], 4231 "module": "DOM", 4232 "submodule": "DOM", 4233 "namespace": "", 4234 "file": "src/core/p5.Element.js", 4235 "line": 11, 4236 "description": "<p>Base class for all elements added to a sketch, including canvas,\ngraphics buffers, and other HTML elements. Methods in blue are\nincluded in the core functionality, methods in brown are added\nwith the <a href=\"http://p5js.org/reference/#/libraries/p5.dom\">p5.dom\nlibrary</a>.\nIt is not called directly, but <a href=\"#/p5.Element\">p5.Element</a>\nobjects are created by calling <a href=\"#/p5/createCanvas\">createCanvas</a>, <a href=\"#/p5/createGraphics\">createGraphics</a>,\nor in the p5.dom library, <a href=\"#/p5/createDiv\">createDiv</a>, <a href=\"#/p5/createImg\">createImg</a>, <a href=\"#/p5/createInput\">createInput</a>, etc.</p>\n", 4237 "params": [{ 4238 "name": "elt", 4239 "description": "<p>DOM node that is wrapped</p>\n", 4240 "type": "String" 4241 }, { 4242 "name": "pInst", 4243 "description": "<p>pointer to p5 instance</p>\n", 4244 "type": "P5", 4245 "optional": true 4246 }] 4247 }, 4248 "p5.Graphics": { 4249 "name": "p5.Graphics", 4250 "shortname": "p5.Graphics", 4251 "classitems": [], 4252 "plugins": [], 4253 "extensions": [], 4254 "plugin_for": [], 4255 "extension_for": [], 4256 "module": "Rendering", 4257 "submodule": "Rendering", 4258 "namespace": "", 4259 "file": "src/core/p5.Graphics.js", 4260 "line": 12, 4261 "description": "<p>Thin wrapper around a renderer, to be used for creating a\ngraphics buffer object. Use this class if you need\nto draw into an off-screen graphics buffer. The two parameters define the\nwidth and height in pixels. The fields and methods for this class are\nextensive, but mirror the normal drawing API for p5.</p>\n", 4262 "extends": "p5.Element", 4263 "params": [{ 4264 "name": "w", 4265 "description": "<p>width</p>\n", 4266 "type": "Number" 4267 }, { 4268 "name": "h", 4269 "description": "<p>height</p>\n", 4270 "type": "Number" 4271 }, { 4272 "name": "renderer", 4273 "description": "<p>the renderer to use, either P2D or WEBGL</p>\n", 4274 "type": "Constant" 4275 }, { 4276 "name": "pInst", 4277 "description": "<p>pointer to p5 instance</p>\n", 4278 "type": "P5", 4279 "optional": true 4280 }] 4281 }, 4282 "p5.Renderer": { 4283 "name": "p5.Renderer", 4284 "shortname": "p5.Renderer", 4285 "classitems": [], 4286 "plugins": [], 4287 "extensions": [], 4288 "plugin_for": [], 4289 "extension_for": [], 4290 "module": "Rendering", 4291 "submodule": "Rendering", 4292 "namespace": "", 4293 "file": "src/core/p5.Renderer.js", 4294 "line": 12, 4295 "description": "<p>Main graphics and rendering context, as well as the base API\nimplementation for p5.js "core". To be used as the superclass for\nRenderer2D and Renderer3D classes, respecitvely.</p>\n", 4296 "is_constructor": 1, 4297 "extends": "p5.Element", 4298 "params": [{ 4299 "name": "elt", 4300 "description": "<p>DOM node that is wrapped</p>\n", 4301 "type": "String" 4302 }, { 4303 "name": "pInst", 4304 "description": "<p>pointer to p5 instance</p>\n", 4305 "type": "P5", 4306 "optional": true 4307 }, { 4308 "name": "isMainCanvas", 4309 "description": "<p>whether we're using it as main canvas</p>\n", 4310 "type": "Boolean", 4311 "optional": true 4312 }] 4313 },
4314 "p5.TypedDict": { 4315 "name": "p5.TypedDict", 4316 "shortname": "p5.TypedDict", 4317 "classitems": [], 4318 "plugins": [], 4319 "extensions": [], 4320 "plugin_for": [], 4321 "extension_for": [], 4322 "module": "Data", 4323 "submodule": "Dictionary", 4324 "namespace": "", 4325 "file": "src/data/p5.TypedDict.js", 4326 "line": 84, 4327 "description": "<p>Base class for all p5.Dictionary types. Specifically\n typed Dictionary classes inherit from this class.</p>\n" 4328 }, 4329 "p5.StringDict": { 4330 "name": "p5.StringDict", 4331 "shortname": "p5.StringDict", 4332 "classitems": [], 4333 "plugins": [], 4334 "extensions": [], 4335 "plugin_for": [], 4336 "extension_for": [], 4337 "module": "Data", 4338 "submodule": "Dictionary", 4339 "namespace": "", 4340 "file": "src/data/p5.TypedDict.js", 4341 "line": 403, 4342 "description": "<p>A simple Dictionary class for Strings.</p>\n", 4343 "extends": "p5.TypedDict" 4344 }, 4345 "p5.NumberDict": { 4346 "name": "p5.NumberDict", 4347 "shortname": "p5.NumberDict", 4348 "classitems": [], 4349 "plugins": [], 4350 "extensions": [], 4351 "plugin_for": [], 4352 "extension_for": [], 4353 "module": "Data", 4354 "submodule": "Dictionary", 4355 "namespace": "", 4356 "file": "src/data/p5.TypedDict.js", 4357 "line": 422, 4358 "description": "<p>A simple Dictionary class for Numbers.</p>\n", 4359 "extends": "p5.TypedDict" 4360 }, 4361 "p5.Image": { 4362 "name": "p5.Image", 4363 "shortname": "p5.Image", 4364 "classitems": [], 4365 "plugins": [], 4366 "extensions": [], 4367 "plugin_for": [], 4368 "extension_for": [], 4369 "module": "Image", 4370 "submodule": "Image", 4371 "namespace": "", 4372 "file": "src/image/p5.Image.js", 4373 "line": 23, 4374 "description": "<p>Creates a new <a href=\"#/p5.Image\">p5.Image</a>. A <a href=\"#/p5.Image\">p5.Image</a> is a canvas backed representation of an\nimage.\n<br><br>\np5 can display .gif, .jpg and .png images. Images may be displayed\nin 2D and 3D space. Before an image is used, it must be loaded with the\n<a href=\"#/p5/loadImage\">loadImage()</a> function. The <a href=\"#/p5.Image\">p5.Image</a> class contains fields for the width and\nheight of the image, as well as an array called <a href=\"#/p5.Image/pixels\">pixels[]</a> that contains the\nvalues for every pixel in the image.\n<br><br>\nThe methods described below allow easy access to the image's pixels and\nalpha channel and simplify the process of compositing.\n<br><br>\nBefore using the <a href=\"#/p5.Image/pixels\">pixels[]</a> array, be sure to use the <a href=\"#/p5.Image/loadPixels\">loadPixels()</a> method on\nthe image to make sure that the pixel data is properly loaded.</p>\n", 4375 "example": ["\n<div><code>\nfunction setup() {\n let img = createImage(100, 100); // same as new p5.Image(100, 100);\n img.loadPixels();\n createCanvas(100, 100);\n background(0);\n\n // helper for writing color to array\n function writeColor(image, x, y, red, green, blue, alpha) {\n let index = (x + y * width) * 4;\n image.pixels[index] = red;\n image.pixels[index + 1] = green;\n image.pixels[index + 2] = blue;\n image.pixels[index + 3] = alpha;\n }\n\n let x, y;\n // fill with random colors\n for (y = 0; y < img.height; y++) {\n for (x = 0; x < img.width; x++) {\n let red = random(255);\n let green = random(255);\n let blue = random(255);\n let alpha = 255;\n writeColor(img, x, y, red, green, blue, alpha);\n }\n }\n\n // draw a red line\n y = 0;\n for (x = 0; x < img.width; x++) {\n writeColor(img, x, y, 255, 0, 0, 255);\n }\n\n // draw a green line\n y = img.height - 1;\n for (x = 0; x < img.width; x++) {\n writeColor(img, x, y, 0, 255, 0, 255);\n }\n\n img.updatePixels();\n image(img, 0, 0);\n}\n</code></div>"], 4376 "params": [{ 4377 "name": "width", 4378 "description": "", 4379 "type": "Number" 4380 }, { 4381 "name": "height", 4382 "description": "", 4383 "type": "Number" 4384 }] 4385 },
4386 "p5.PrintWriter": { 4387 "name": "p5.PrintWriter", 4388 "shortname": "p5.PrintWriter", 4389 "classitems": [], 4390 "plugins": [], 4391 "extensions": [], 4392 "plugin_for": [], 4393 "extension_for": [], 4394 "module": "IO", 4395 "submodule": "Output", 4396 "namespace": "", 4397 "file": "src/io/files.js", 4398 "line": 1228, 4399 "params": [{ 4400 "name": "filename", 4401 "description": "", 4402 "type": "String" 4403 }, { 4404 "name": "extension", 4405 "description": "", 4406 "type": "String", 4407 "optional": true 4408 }] 4409 }, 4410 "p5.Table": { 4411 "name": "p5.Table", 4412 "shortname": "p5.Table", 4413 "classitems": [], 4414 "plugins": [], 4415 "extensions": [], 4416 "plugin_for": [], 4417 "extension_for": [], 4418 "module": "IO", 4419 "submodule": "Table", 4420 "namespace": "", 4421 "file": "src/io/p5.Table.js", 4422 "line": 35, 4423 "description": "<p><a href=\"#/p5.Table\">Table</a> objects store data with multiple rows and columns, much\nlike in a traditional spreadsheet. Tables can be generated from\nscratch, dynamically, or using data from an existing file.</p>\n", 4424 "is_constructor": 1, 4425 "params": [{ 4426 "name": "rows", 4427 "description": "<p>An array of p5.TableRow objects</p>\n", 4428 "type": "p5.TableRow[]", 4429 "optional": true 4430 }] 4431 }, 4432 "p5.TableRow": { 4433 "name": "p5.TableRow", 4434 "shortname": "p5.TableRow", 4435 "classitems": [], 4436 "plugins": [], 4437 "extensions": [], 4438 "plugin_for": [], 4439 "extension_for": [], 4440 "module": "IO", 4441 "submodule": "Table", 4442 "namespace": "", 4443 "file": "src/io/p5.TableRow.js", 4444 "line": 11, 4445 "description": "<p>A TableRow object represents a single row of data values,\nstored in columns, from a table.</p>\n<p>A Table Row contains both an ordered array, and an unordered\nJSON object.</p>\n", 4446 "is_constructor": 1, 4447 "params": [{ 4448 "name": "str", 4449 "description": "<p>optional: populate the row with a\n string of values, separated by the\n separator</p>\n", 4450 "type": "String", 4451 "optional": true 4452 }, { 4453 "name": "separator", 4454 "description": "<p>comma separated values (csv) by default</p>\n", 4455 "type": "String", 4456 "optional": true 4457 }] 4458 }, 4459 "p5.XML": { 4460 "name": "p5.XML", 4461 "shortname": "p5.XML", 4462 "classitems": [], 4463 "plugins": [], 4464 "extensions": [], 4465 "plugin_for": [], 4466 "extension_for": [], 4467 "module": "IO", 4468 "submodule": "XML", 4469 "namespace": "", 4470 "file": "src/io/p5.XML.js", 4471 "line": 11, 4472 "description": "<p>XML is a representation of an XML object, able to parse XML code. Use\n<a href=\"#/p5/loadXML\">loadXML()</a> to load external XML files and create XML objects.</p>\n", 4473 "is_constructor": 1, 4474 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let children = xml.getChildren('animal');\n\n for (let i = 0; i < children.length; i++) {\n let id = children[i].getNum('id');
4474\n let coloring = children[i].getString('species');\n let name = children[i].getContent();\n print(id + ', ' + coloring + ', ' + name);\n }\n}\n\n// Sketch prints:\n// 0, Capra hircus, Goat\n// 1, Panthera pardus, Leopard\n// 2, Equus zebra, Zebra\n</code></div>"], 4475 "alt": "no image displayed" 4476 }, 4477 "p5.Vector": { 4478 "name": "p5.Vector", 4479 "shortname": "p5.Vector", 4480 "classitems": [], 4481 "plugins": [], 4482 "extensions": [], 4483 "plugin_for": [], 4484 "extension_for": [], 4485 "module": "Math", 4486 "submodule": "Math", 4487 "namespace": "", 4488 "file": "src/math/p5.Vector.js", 4489 "line": 12, 4490 "description": "<p>A class to describe a two or three dimensional vector, specifically\na Euclidean (also known as geometric) vector. A vector is an entity\nthat has both magnitude and direction. The datatype, however, stores\nthe components of the vector (x, y for 2D, and x, y, z for 3D). The magnitude\nand direction can be accessed via the methods <a href=\"#/p5/mag\">mag()</a> and <a href=\"#/p5/heading\">heading()</a>.\n<br><br>\nIn many of the p5.js examples, you will see <a href=\"#/p5.Vector\">p5.Vector</a> used to describe a\nposition, velocity, or acceleration. For example, if you consider a rectangle\nmoving across the screen, at any given instant it has a position (a vector\nthat points from the origin to its location), a velocity (the rate at which\nthe object's position changes per time unit, expressed as a vector), and\nacceleration (the rate at which the object's velocity changes per time\nunit, expressed as a vector).\n<br><br>\nSince vectors represent groupings of values, we cannot simply use\ntraditional addition/multiplication/etc. Instead, we'll need to do some\n"vector" math, which is made easy by the methods inside the <a href=\"#/p5.Vector\">p5.Vector</a> class.</p>\n", 4491 "params": [{ 4492 "name": "x", 4493 "description": "<p>x component of the vector</p>\n", 4494 "type": "Number", 4495 "optional": true 4496 }, { 4497 "name": "y", 4498 "description": "<p>y component of the vector</p>\n", 4499 "type": "Number", 4500 "optional": true 4501 }, { 4502 "name": "z", 4503 "description": "<p>z component of the vector</p>\n", 4504 "type": "Number", 4505 "optional": true 4506 }], 4507 "example": ["\n<div>\n<code>\nlet v1 = createVector(40, 50);\nlet v2 = createVector(40, 50);\n\nellipse(v1.x, v1.y, 50, 50);\nellipse(v2.x, v2.y, 50, 50);\nv1.add(v2);\nellipse(v1.x, v1.y, 50, 50);\n</code>\n</div>"], 4508 "alt": "2 white ellipses. One center-left the other bottom right and off canvas" 4509 }, 4510 "p5.Font": { 4511 "name": "p5.Font", 4512 "shortname": "p5.Font", 4513 "classitems": [], 4514 "plugins": [], 4515 "extensions": [], 4516 "plugin_for": [], 4517 "extension_for": [], 4518 "module": "Typography", 4519 "submodule": "Font", 4520 "namespace": "", 4521 "file": "src/typography/p5.Font.js", 4522 "line": 15, 4523 "description": "<p>Base class for font handling</p>\n", 4524 "params": [{ 4525 "name": "pInst", 4526 "description": "<p>pointer to p5 instance</p>\n", 4527 "type": "P5", 4528 "optional": true 4529 }] 4530 }, 4531 "p5.Camera": { 4532 "name": "p5.Camera", 4533 "shortname": "p5.Camera", 4534 "classitems": [], 4535 "plugins": [], 4536 "extensions": [], 4537 "plugin_for": [], 4538 "extension_for": [], 4539 "module": "Lights, Camera", 4540 "submodule": "Camera", 4541 "namespace": "", 4542 "file": "src/webgl/p5.Camera.js", 4543 "line": 209, 4544 "description": "<p>This class describes a camera for use in p5's\n<a href=\"https://github.com/processing/p5.js/wiki/Getting-started-with-WebGL-in-p5\">\nWebGL mode</a>. It contains camera position, orientation, and projection\ninformation necessary for rendering a 3D scene.</p>\n<p>New p5.Camera objects can be made through the\n<a href=\"#/p5/createCamera\">createCamera()</a> function and controlled through\nthe methods described below. A camera created in this way will use a default\nposition in the scene and a default perspective projection until these\nproperties are changed through the various methods available. It is possible\nto create multiple cameras, in which case the current camera\ncan be set through the <a href=\"#/p5/setCamera\">setCamera()</a> method.</p>\n<p>Note:\nThe methods below operate in two coordinate systems: the 'world' coordinate\nsystem describe positions in terms of their relationship to the origin along\nthe X, Y and Z axes whereas the camera's 'local' coordinate system\ndescribes positions from the camera's point of view: left-right, up-down,\nand forward-backward. The <a href=\"#/p5.Camera/move\">move()</a> method,\nfor instance, moves the camera along its own axes, whereas the\n<a href=\"#/p5.Camera/setPosition\">setPosition()</a>\nmethod sets the camera's position in world-space.</p>\n", 4545 "params": [{ 4546 "name": "rendererGL", 4547 "description": "<p>instance of WebGL renderer</p>\n", 4548 "type": "RendererGL" 4549 }], 4550 "example": ["\n<div>\n<code>\nlet cam;\nlet delta = 0.01;\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n normalMaterial();\n cam = createCamera();\n // set initial pan angle\n cam.pan(-0.8);\n}\n\nfunction draw() {\n background(200);\n\n // pan camera according to angle 'delta'\n cam.pan(delta);\n\n // every 160 frames, switch direction\n if (frameCount % 160 === 0) {\n delta *= -1;\n }\n\n rotateX(frameCount * 0.01);\n translate(-100, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n}\n</code>\n</div>"], 4551 "alt": "camera view pans left and right across a series of rotating 3D boxes." 4552 },
4553 "p5.Geometry": { 4554 "name": "p5.Geometry", 4555 "shortname": "p5.Geometry", 4556 "classitems": [], 4557 "plugins": [], 4558 "extensions": [], 4559 "plugin_for": [], 4560 "extension_for": [], 4561 "module": "Lights, Camera", 4562 "namespace": "", 4563 "file": "src/webgl/p5.Geometry.js", 4564 "line": 6, 4565 "description": "<p>p5 Geometry class</p>\n", 4566 "is_constructor": 1, 4567 "params": [{ 4568 "name": "detailX", 4569 "description": "<p>number of vertices on horizontal surface</p>\n", 4570 "type": "Integer", 4571 "optional": true 4572 }, { 4573 "name": "detailY", 4574 "description": "<p>number of vertices on horizontal surface</p>\n", 4575 "type": "Integer", 4576 "optional": true 4577 }, { 4578 "name": "callback", 4579 "description": "<p>function to call upon object instantiation.</p>\n", 4580 "type": "Function", 4581 "optional": true 4582 }] 4583 }, 4584 "p5.Shader": { 4585 "name": "p5.Shader", 4586 "shortname": "p5.Shader", 4587 "classitems": [], 4588 "plugins": [], 4589 "extensions": [], 4590 "plugin_for": [], 4591 "extension_for": [], 4592 "module": "Lights, Camera", 4593 "submodule": "Shaders", 4594 "namespace": "", 4595 "file": "src/webgl/p5.Shader.js", 4596 "line": 13, 4597 "description": "<p>Shader class for WEBGL Mode</p>\n", 4598 "params": [{ 4599 "name": "renderer", 4600 "description": "<p>an instance of p5.RendererGL that\nwill provide the GL context for this new p5.Shader</p>\n", 4601 "type": "p5.RendererGL" 4602 }, { 4603 "name": "vertSrc", 4604 "description": "<p>source code for the vertex shader (as a string)</p>\n", 4605 "type": "String" 4606 }, { 4607 "name": "fragSrc", 4608 "description": "<p>source code for the fragment shader (as a string)</p>\n", 4609 "type": "String" 4610 }] 4611 }, 4612 "p5.MediaElement": { 4613 "name": "p5.MediaElement", 4614 "shortname": "p5.MediaElement", 4615 "classitems": [], 4616 "plugins": [], 4617 "extensions": [], 4618 "plugin_for": [], 4619 "extension_for": [], 4620 "module": "p5.dom", 4621 "submodule": "p5.dom", 4622 "namespace": "", 4623 "file": "lib/addons/p5.dom.js", 4624 "line": 2062, 4625 "description": "<p>Extends <a href=\"#/p5.Element\">p5.Element</a> to handle audio and video. In addition to the methods\nof <a href=\"#/p5.Element\">p5.Element</a>, it also contains methods for controlling media. It is not\ncalled directly, but <a href=\"#/p5.MediaElement\">p5.MediaElement</a>s are created by calling <a href=\"#/p5/createVideo\">createVideo</a>,\n<a href=\"#/p5/createAudio\">createAudio</a>, and <a href=\"#/p5/createCapture\">createCapture</a>.</p>\n", 4626 "is_constructor": 1, 4627 "params": [{ 4628 "name": "elt", 4629 "description": "<p>DOM node that is wrapped</p>\n", 4630 "type": "String" 4631 }] 4632 }, 4633 "p5.File": { 4634 "name": "p5.File", 4635 "shortname": "p5.File", 4636 "classitems": [], 4637 "plugins": [], 4638 "extensions": [], 4639 "plugin_for": [], 4640 "extension_for": [], 4641 "module": "p5.dom", 4642 "submodule": "p5.dom", 4643 "namespace": "", 4644 "file": "lib/addons/p5.dom.js", 4645 "line": 3170, 4646 "description": "<p>Base class for a file\nUsing this for createFileInput</p>\n", 4647 "is_constructor": 1, 4648 "params": [{ 4649 "name": "file", 4650 "description": "<p>File that is wrapped</p>\n", 4651 "type": "File" 4652 }] 4653 }, 4654 "p5.sound": { 4655 "name": "p5.sound", 4656 "shortname": "p5.sound", 4657 "classitems": [], 4658 "plugins": [], 4659 "extensions": [], 4660 "plugin_for": [], 4661 "extension_for": [], 4662 "module": "p5.sound", 4663 "submodule": "p5.sound", 4664 "namespace": "" 4665 },
4666 "p5.SoundFile": { 4667 "name": "p5.SoundFile", 4668 "shortname": "p5.SoundFile", 4669 "classitems": [], 4670 "plugins": [], 4671 "extensions": [], 4672 "plugin_for": [], 4673 "extension_for": [], 4674 "module": "p5.sound", 4675 "submodule": "p5.sound", 4676 "namespace": "", 4677 "file": "lib/addons/p5.sound.js", 4678 "line": 1005, 4679 "description": "<p>SoundFile object with a path to a file.</p>\n\n<p>The p5.SoundFile may not be available immediately because\nit loads the file information asynchronously.</p>\n\n<p>To do something with the sound as soon as it loads\npass the name of a function as the second parameter.</p>\n\n<p>Only one file path is required. However, audio file formats\n(i.e. mp3, ogg, wav and m4a/aac) are not supported by all\nweb browsers. If you want to ensure compatability, instead of a single\nfile path, you may include an Array of filepaths, and the browser will\nchoose a format that works.</p>", 4680 "is_constructor": 1, 4681 "params": [{ 4682 "name": "path", 4683 "description": "<p>path to a sound file (String). Optionally,\n you may include multiple file formats in\n an array. Alternately, accepts an object\n from the HTML5 File API, or a p5.File.</p>\n", 4684 "type": "String|Array" 4685 }, { 4686 "name": "successCallback", 4687 "description": "<p>Name of a function to call once file loads</p>\n", 4688 "type": "Function", 4689 "optional": true 4690 }, { 4691 "name": "errorCallback", 4692 "description": "<p>Name of a function to call if file fails to\n load. This function will receive an error or\n XMLHttpRequest object with information\n about what went wrong.</p>\n", 4693 "type": "Function", 4694 "optional": true 4695 }, { 4696 "name": "whileLoadingCallback", 4697 "description": "<p>Name of a function to call while file\n is loading. That function will\n receive progress of the request to\n load the sound file\n (between 0 and 1) as its first\n parameter. This progress\n does not account for the additional\n time needed to decode the audio data.</p>\n", 4698 "type": "Function", 4699 "optional": true 4700 }], 4701 "example": ["\n<div><code>\n\nfunction preload() {\n soundFormats('mp3', 'ogg');\n mySound = loadSound('assets/doorbell.mp3');\n}\n\nfunction setup() {\n mySound.setVolume(0.1);\n mySound.play();\n}\n\n </code></div>"] 4702 }, 4703 "p5.Amplitude": { 4704 "name": "p5.Amplitude", 4705 "shortname": "p5.Amplitude", 4706 "classitems": [], 4707 "plugins": [], 4708 "extensions": [], 4709 "plugin_for": [], 4710 "extension_for": [], 4711 "module": "p5.sound", 4712 "submodule": "p5.sound", 4713 "namespace": "", 4714 "file": "lib/addons/p5.sound.js", 4715 "line": 2533, 4716 "description": "<p>Amplitude measures volume between 0.0 and 1.0.\nListens to all p5sound by default, or use setInput()\nto listen to a specific sound source. Accepts an optional\nsmoothing value, which defaults to 0.</p>\n", 4717 "is_constructor": 1, 4718 "params": [{ 4719 "name": "smoothing", 4720 "description": "<p>between 0.0 and .999 to smooth\n amplitude readings (defaults to 0)</p>\n", 4721 "type": "Number", 4722 "optional": true 4723 }], 4724 "example": ["\n<div><code>\nvar sound, amplitude, cnv;\n\nfunction preload(){\n sound = loadSound('assets/beat.mp3');\n}\nfunction setup() {\n cnv = createCanvas(100,100);\n amplitude = new p5.Amplitude();\n\n // start / stop the sound when canvas is clicked\n cnv.mouseClicked(function() {\
4724n if (sound.isPlaying() ){\n sound.stop();\n } else {\n sound.play();\n }\n });\n}\nfunction draw() {\n background(0);\n fill(255);\n var level = amplitude.getLevel();\n var size = map(level, 0, 1, 0, 200);\n ellipse(width/2, height/2, size, size);\n}\n\n</code></div>"] 4725 }, 4726 "p5.FFT": { 4727 "name": "p5.FFT", 4728 "shortname": "p5.FFT", 4729 "classitems": [], 4730 "plugins": [], 4731 "extensions": [], 4732 "plugin_for": [], 4733 "extension_for": [], 4734 "module": "p5.sound", 4735 "submodule": "p5.sound", 4736 "namespace": "", 4737 "file": "lib/addons/p5.sound.js", 4738 "line": 2812, 4739 "description": "<p>FFT (Fast Fourier Transform) is an analysis algorithm that\nisolates individual\n<a href=\"https://en.wikipedia.org/wiki/Audio_frequency\">\naudio frequencies</a> within a waveform.</p>\n\n<p>Once instantiated, a p5.FFT object can return an array based on\ntwo types of analyses: <br> ⢠<code>FFT.waveform()</code> computes\namplitude values along the time domain. The array indices correspond\nto samples across a brief moment in time. Each value represents\namplitude of the waveform at that sample of time.<br>\n⢠<code>FFT.analyze() </code> computes amplitude values along the\nfrequency domain. The array indices correspond to frequencies (i.e.\npitches), from the lowest to the highest that humans can hear. Each\nvalue represents amplitude at that slice of the frequency spectrum.\nUse with <code>getEnergy()</code> to measure amplitude at specific\nfrequencies, or within a range of frequencies. </p>\n\n<p>FFT analyzes a very short snapshot of sound called a sample\nbuffer. It returns an array of amplitude measurements, referred\nto as <code>bins</code>. The array is 1024 bins long by default.\nYou can change the bin array length, but it must be a power of 2\nbetween 16 and 1024 in order for the FFT algorithm to function\ncorrectly. The actual size of the FFT buffer is twice the\nnumber of bins, so given a standard sample rate, the buffer is\n2048/44100 seconds long.</p>", 4740 "is_constructor": 1, 4741 "params": [{ 4742 "name": "smoothing", 4743 "description": "<p>Smooth results of Freq Spectrum.\n 0.0 < smoothing < 1.0.\n Defaults to 0.8.</p>\n", 4744 "type": "Number", 4745 "optional": true 4746 }, { 4747 "name": "bins", 4748 "description": "<p>Length of resulting array.\n Must be a power of two between\n 16 and 1024. Defaults to 1024.</p>\n", 4749 "type": "Number", 4750 "optional": true 4751 }], 4752 "example": ["\n<div><code>\nfunction preload(){\n sound = loadSound('assets/Damscray_DancingTiger.mp3');\n}\n\nfunction setup(){\n var cnv = createCanvas(100,100);\n cnv.mouseClicked(togglePlay);\n fft = new p5.FFT();\n sound.amp(0.2);\n}\n\nfunction draw(){\n background(0);\n\n var spectrum = fft.analyze();\n noStroke();\n fill(0,255,0); // spectrum is green\n for (var i = 0; i< spectrum.length; i++){\n var x = map(i, 0, spectrum.length, 0, width);\n var h = -height + map(spectrum[i], 0, 255, height, 0);\n rect(x, height, width / spectrum.length, h )\n }\n\n var waveform = fft.waveform();\n noFill();\n beginShape();\n stroke(255,0,0); // waveform is red\n strokeWeight(1);\n for (var i = 0; i< waveform.length; i++){\n var x = map(i, 0, waveform.length, 0, width);\n var y = map( waveform[i], -1, 1, 0, height);\n vertex(x,y);\n }\n endShape();\n\n text('click to play/pause', 4, 10);\n}\n\n// fade sound if mouse is over canvas\nfunction togglePlay() {\n if (sound.isPlaying()) {\n sound.pause();\n } else {\n sound.loop();\n }\n}\n</code></div>"] 4753 }, 4754 "p5.Signal": { 4755 "name": "p5.Signal", 4756 "shortname": "p5.Signal", 4757 "classitems": [], 4758 "plugins": [], 4759 "extensions": [], 4760 "plugin_for": [], 4761 "extension_for": [], 4762 "module": "p5.sound", 4763 "submodule": "p5.sound", 4764 "namespace": "", 4765 "file": "lib/addons/p5.sound.js", 4766 "line": 5215, 4767 "description": "<p>p5.Signal is a constant audio-rate signal used by p5.Oscillator\nand p5.Envelope for modulation math.</p>\n\n<p>This is necessary because Web Audio is processed on a seprate clock.\nFor example, the p5 draw loop runs about 60 times per second. But\nthe audio clock must process samples 44100 times per second. If we\nwant to add a value to each of those samples, we can't do it in the\ndraw loop, but we can do it by adding a constant-rate audio signal.</p.\n\n<p>This class mostly functions behind the scenes in p5.sound, and returns\na Tone.Signal from the Tone.js library by Yotam Mann.\nIf you want to work directly with audio signals for modular\nsynthesis, check out\n<a href='http://bit.ly/1oIoEng' target=_'blank'>tone.js.</a></p>", 4768 "is_constructor": 1, 4769 "return": { 4770 "description": "A Signal object from the Tone.js library", 4771 "type": "Tone.Signal" 4772 }, 4773 "example": ["\n<div><code>\nfunction setup() {\n carrier = new p5.Oscillator('sine');\n carrier.amp(1); // set amplitude\n carrier.freq(220); // set frequency\n carrier.start(); // start oscillating\n\n modulator = new p5.Oscillator('sawtooth');\n modulator.disconnect();\n modulator.amp(1);\n modulator.freq(4);\n modulator.start();\n\n // Modulator's default amplitude range is -1 to 1.\n // Multiply it by -200, so the range is -200 to 200\n // then add 220 s
4773o the range is 20 to 420\n carrier.freq( modulator.mult(-200).add(220) );\n}\n</code></div>"] 4774 }, 4775 "p5.Oscillator": { 4776 "name": "p5.Oscillator", 4777 "shortname": "p5.Oscillator", 4778 "classitems": [], 4779 "plugins": [], 4780 "extensions": [], 4781 "plugin_for": [], 4782 "extension_for": [], 4783 "module": "p5.sound", 4784 "submodule": "p5.sound", 4785 "namespace": "", 4786 "file": "lib/addons/p5.sound.js", 4787 "line": 5361, 4788 "description": "<p>Creates a signal that oscillates between -1.0 and 1.0.\nBy default, the oscillation takes the form of a sinusoidal\nshape ('sine'). Additional types include 'triangle',\n'sawtooth' and 'square'. The frequency defaults to\n440 oscillations per second (440Hz, equal to the pitch of an\n'A' note).</p>\n\n<p>Set the type of oscillation with setType(), or by instantiating a\nspecific oscillator: <a href=\"/reference/#/p5.SinOsc\">p5.SinOsc</a>, <a\nhref=\"/reference/#/p5.TriOsc\">p5.TriOsc</a>, <a\nhref=\"/reference/#/p5.SqrOsc\">p5.SqrOsc</a>, or <a\nhref=\"/reference/#/p5.SawOsc\">p5.SawOsc</a>.\n</p>", 4789 "is_constructor": 1, 4790 "params": [{ 4791 "name": "freq", 4792 "description": "<p>frequency defaults to 440Hz</p>\n", 4793 "type": "Number", 4794 "optional": true 4795 }, { 4796 "name": "type", 4797 "description": "<p>type of oscillator. Options:\n 'sine' (default), 'triangle',\n 'sawtooth', 'square'</p>\n", 4798 "type": "String", 4799 "optional": true 4800 }], 4801 "example": ["\n<div><code>\nvar osc;\nvar playing = false;\n\nfunction setup() {\n backgroundColor = color(255,0,255);\n textAlign(CENTER);\n\n osc = new p5.Oscillator();\n osc.setType('sine');\n osc.freq(240);\n osc.amp(0);\n osc.start();\n}\n\nfunction draw() {\n background(backgroundColor)\n text('click to play', width/2, height/2);\n}\n\nfunction mouseClicked() {\n if (mouseX > 0 && mouseX < width && mouseY < height && mouseY > 0) {\n if (!playing) {\n // ramp amplitude to 0.5 over 0.05 seconds\n osc.amp(0.5, 0.05);\n playing = true;\n backgroundColor = color(0,255,255);\n } else {\n // ramp amplitude to 0 over 0.5 seconds\n osc.amp(0, 0.5);\n playing = false;\n backgroundColor = color(255,0,255);\n }\n }\n}\n</code> </div>"] 4802 }, 4803 "p5.SinOsc": { 4804 "name": "p5.SinOsc", 4805 "shortname": "p5.SinOsc", 4806 "classitems": [], 4807 "plugins": [], 4808 "extensions": [], 4809 "plugin_for": [], 4810 "extension_for": [], 4811 "module": "p5.sound", 4812 "submodule": "p5.sound", 4813 "namespace": "", 4814 "file": "lib/addons/p5.sound.js", 4815 "line": 5802, 4816 "description": "<p>Constructor: <code>new p5.SinOsc()</code>.\nThis creates a Sine Wave Oscillator and is\nequivalent to <code> new p5.Oscillator('sine')\n</code> or creating a p5.Oscillator and then calling\nits method <code>setType('sine')</code>.\nSee p5.Oscillator for methods.</p>\n", 4817 "is_constructor": 1, 4818 "extends": "p5.Oscillator", 4819 "params": [{ 4820 "name": "freq", 4821 "description": "<p>Set the frequency</p>\n", 4822 "type": "Number", 4823 "optional": true 4824 }] 4825 }, 4826 "p5.TriOsc": { 4827 "name": "p5.TriOsc", 4828 "shortname": "p5.TriOsc", 4829 "classitems": [], 4830 "plugins": [], 4831 "extensions": [], 4832 "plugin_for": [], 4833 "extension_for": [], 4834 "module": "p5.sound", 4835 "submodule": "p5.sound", 4836 "namespace": "", 4837 "file": "lib/addons/p5.sound.js", 4838 "line": 5819, 4839 "description": "<p>Constructor: <code>new p5.TriOsc()</code>.\nThis creates a Triangle Wave Oscillator and is\nequivalent to <code>new p5.Oscillator('triangle')\n</code> or creating a p5.Oscillator and then calling\nits method <code>setType('triangle')</code>.\nSee p5.Oscillator for methods.</p>\n", 4840 "is_constructor": 1, 4841 "extends": "p5.Oscillator", 4842 "params": [{ 4843 "name": "freq", 4844 "description": "<p>Set the frequency</p>\n", 4845 "type": "Number", 4846 "optional": true 4847 }] 4848 },
4849 "p5.SawOsc": { 4850 "name": "p5.SawOsc", 4851 "shortname": "p5.SawOsc", 4852 "classitems": [], 4853 "plugins": [], 4854 "extensions": [], 4855 "plugin_for": [], 4856 "extension_for": [], 4857 "module": "p5.sound", 4858 "submodule": "p5.sound", 4859 "namespace": "", 4860 "file": "lib/addons/p5.sound.js", 4861 "line": 5836, 4862 "description": "<p>Constructor: <code>new p5.SawOsc()</code>.\nThis creates a SawTooth Wave Oscillator and is\nequivalent to <code> new p5.Oscillator('sawtooth')\n</code> or creating a p5.Oscillator and then calling\nits method <code>setType('sawtooth')</code>.\nSee p5.Oscillator for methods.</p>\n", 4863 "is_constructor": 1, 4864 "extends": "p5.Oscillator", 4865 "params": [{ 4866 "name": "freq", 4867 "description": "<p>Set the frequency</p>\n", 4868 "type": "Number", 4869 "optional": true 4870 }] 4871 }, 4872 "p5.SqrOsc": { 4873 "name": "p5.SqrOsc", 4874 "shortname": "p5.SqrOsc", 4875 "classitems": [], 4876 "plugins": [], 4877 "extensions": [], 4878 "plugin_for": [], 4879 "extension_for": [], 4880 "module": "p5.sound", 4881 "submodule": "p5.sound", 4882 "namespace": "", 4883 "file": "lib/addons/p5.sound.js", 4884 "line": 5853, 4885 "description": "<p>Constructor: <code>new p5.SqrOsc()</code>.\nThis creates a Square Wave Oscillator and is\nequivalent to <code> new p5.Oscillator('square')\n</code> or creating a p5.Oscillator and then calling\nits method <code>setType('square')</code>.\nSee p5.Oscillator for methods.</p>\n", 4886 "is_constructor": 1, 4887 "extends": "p5.Oscillator", 4888 "params": [{ 4889 "name": "freq", 4890 "description": "<p>Set the frequency</p>\n", 4891 "type": "Number", 4892 "optional": true 4893 }] 4894 }, 4895 "p5.Envelope": { 4896 "name": "p5.Envelope", 4897 "shortname": "p5.Envelope", 4898 "classitems": [], 4899 "plugins": [], 4900 "extensions": [], 4901 "plugin_for": [], 4902 "extension_for": [], 4903 "module": "p5.sound", 4904 "submodule": "p5.sound", 4905 "namespace": "", 4906 "file": "lib/addons/p5.sound.js", 4907 "line": 6310, 4908 "description": "<p>Envelopes are pre-defined amplitude distribution over time.\nTypically, envelopes are used to control the output volume\nof an object, a series of fades referred to as Attack, Decay,\nSustain and Release (\n<a href=\"https://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg\">ADSR</a>\n). Envelopes can also control other Web Audio Parametersâfor example, a p5.Envelope can\ncontrol an Oscillator's frequency like this: <code>osc.freq(env)</code>.</p>\n<p>Use <code><a href=\"#/p5.Envelope/setRange\">setRange</a></code> to change the attack/release level.\nUse <code><a href=\"#/p5.Envelope/setADSR\">setADSR</a></code> to change attackTime, decayTime, sustainPercent and releaseTime.</p>\n<p>Use the <code><a href=\"#/p5.Envelope/play\">play</a></code> method to play the entire envelope,\nthe <code><a href=\"#/p5.Envelope/ramp\">ramp</a></code> method for a pingable trigger,\nor <code><a href=\"#/p5.Envelope/triggerAttack\">triggerAttack</a></code>/\n<code><a href=\"#/p5.Envelope/triggerRelease\">triggerRelease</a></code> to trigger noteOn/noteOff.</p>", 4909 "is_constructor": 1, 4910 "example": ["\n<div><code>\nvar attackLevel = 1.0;\nvar releaseLevel = 0;\n\nvar attackTime = 0.001;\nvar decayTime = 0.2;\nvar susPercent = 0.2;\nvar releaseTime = 0.5;\n\nvar env, triOsc;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n\n env = new p5.Envelope();\n env.setADSR(attackTime, decayTime, susPercent, releaseTime);\n env.setRange(attackLevel, releaseLevel);\n\n triOsc = new p5.Oscillator('triangle');\n triOsc.amp(env);\n triOsc.start();\n triOsc.freq(220);\n\n cnv.mousePressed(playEnv);\n}\n\nfunction playEnv() {\n env.play();\n}\n</code></div>"] 4911 },
4912 "p5.Pulse": { 4913 "name": "p5.Pulse", 4914 "shortname": "p5.Pulse", 4915 "classitems": [], 4916 "plugins": [], 4917 "extensions": [], 4918 "plugin_for": [], 4919 "extension_for": [], 4920 "module": "p5.sound", 4921 "submodule": "p5.sound", 4922 "namespace": "", 4923 "file": "lib/addons/p5.sound.js", 4924 "line": 7108, 4925 "description": "<p>Creates a Pulse object, an oscillator that implements\nPulse Width Modulation.\nThe pulse is created with two oscillators.\nAccepts a parameter for frequency, and to set the\nwidth between the pulses. See <a href=\"\nhttp://p5js.org/reference/#/p5.Oscillator\">\n<code>p5.Oscillator</code> for a full list of methods.</p>\n", 4926 "extends": "p5.Oscillator", 4927 "is_constructor": 1, 4928 "params": [{ 4929 "name": "freq", 4930 "description": "<p>Frequency in oscillations per second (Hz)</p>\n", 4931 "type": "Number", 4932 "optional": true 4933 }, { 4934 "name": "w", 4935 "description": "<p>Width between the pulses (0 to 1.0,\n defaults to 0)</p>\n", 4936 "type": "Number", 4937 "optional": true 4938 }], 4939 "example": ["\n<div><code>\nvar pulse;\nfunction setup() {\n background(0);\n\n // Create and start the pulse wave oscillator\n pulse = new p5.Pulse();\n pulse.amp(0.5);\n pulse.freq(220);\n pulse.start();\n}\n\nfunction draw() {\n var w = map(mouseX, 0, width, 0, 1);\n w = constrain(w, 0, 1);\n pulse.width(w)\n}\n</code></div>"] 4940 }, 4941 "p5.Noise": { 4942 "name": "p5.Noise", 4943 "shortname": "p5.Noise", 4944 "classitems": [], 4945 "plugins": [], 4946 "extensions": [], 4947 "plugin_for": [], 4948 "extension_for": [], 4949 "module": "p5.sound", 4950 "submodule": "p5.sound", 4951 "namespace": "", 4952 "file": "lib/addons/p5.sound.js", 4953 "line": 7287, 4954 "description": "<p>Noise is a type of oscillator that generates a buffer with random values.</p>\n", 4955 "extends": "p5.Oscillator", 4956 "is_constructor": 1, 4957 "params": [{ 4958 "name": "type", 4959 "description": "<p>Type of noise can be 'white' (default),\n 'brown' or 'pink'.</p>\n", 4960 "type": "String" 4961 }] 4962 }, 4963 "p5.AudioIn": { 4964 "name": "p5.AudioIn", 4965 "shortname": "p5.AudioIn", 4966 "classitems": [], 4967 "plugins": [], 4968 "extensions": [], 4969 "plugin_for": [], 4970 "extension_for": [], 4971 "module": "p5.sound", 4972 "submodule": "p5.sound", 4973 "namespace": "", 4974 "file": "lib/addons/p5.sound.js", 4975 "line": 7435, 4976 "description": "<p>Get audio from an input, i.e. your computer's microphone.</p>\n\n<p>Turn the mic on/off with the start() and stop() methods. When the mic\nis on, its volume can be measured with getLevel or by connecting an\nFFT object.</p>\n\n<p>If you want to hear the AudioIn, use the .connect() method.\nAudioIn does not connect to p5.sound output by default to prevent\nfeedback.</p>\n\n<p><em>Note: This uses the <a href=\"http://caniuse.com/stream\">getUserMedia/\nStream</a> API, which is not supported by certain browsers. Access in Chrome browser\nis limited to localhost and https, but access over http may be limited.</em></p>", 4977 "is_constructor": 1, 4978 "params": [{ 4979 "name": "errorCallback", 4980 "description": "<p>A function to call if there is an error\n accessing the AudioIn. For example,\n Safari and iOS devices do not\n currently allow microphone access.</p>\n", 4981 "type": "Function", 4982 "optional": true 4983 }], 4984 "example": ["\n<div><code>\nvar mic;\nfunction setup(){\n mic = new p5.AudioIn()\n mic.start();\n}\nfunction draw(){\n background(0);\n micLevel = mic.getLevel();\n ellipse(width/2, constrain(height-micLevel*height*5, 0, height), 10, 10);\n}\n</code></div>"] 4985 },
4986 "p5.Effect": { 4987 "name": "p5.Effect", 4988 "shortname": "p5.Effect", 4989 "classitems": [], 4990 "plugins": [], 4991 "extensions": [], 4992 "plugin_for": [], 4993 "extension_for": [], 4994 "module": "p5.sound", 4995 "submodule": "p5.sound", 4996 "namespace": "", 4997 "file": "lib/addons/p5.sound.js", 4998 "line": 8351, 4999 "description": "<p>Effect is a base class for audio effects in p5. <br>\nThis module handles the nodes and methods that are \ncommon and useful for current and future effects.</p>\n<p>This class is extended by <a href=\"/reference/#/p5.Distortion\">p5.Distortion</a>, \n<a href=\"/reference/#/p5.Compressor\">p5.Compressor</a>,\n<a href=\"/reference/#/p5.Delay\">p5.Delay</a>, \n<a href=\"/reference/#/p5.Filter\">p5.Filter</a>, \n<a href=\"/reference/#/p5.Reverb\">p5.Reverb</a>.</p>\n", 5000 "is_constructor": 1, 5001 "params": [{ 5002 "name": "ac", 5003 "description": "<p>Reference to the audio context of the p5 object</p>\n", 5004 "type": "Object", 5005 "optional": true 5006 }, { 5007 "name": "input", 5008 "description": "<p>Gain Node effect wrapper</p>\n", 5009 "type": "AudioNode", 5010 "optional": true 5011 }, { 5012 "name": "output", 5013 "description": "<p>Gain Node effect wrapper</p>\n", 5014 "type": "AudioNode", 5015 "optional": true 5016 }, { 5017 "name": "_drywet", 5018 "description": "<p>Tone.JS CrossFade node (defaults to value: 1)</p>\n", 5019 "type": "Object", 5020 "optional": true 5021 }, { 5022 "name": "wet", 5023 "description": "<p>Effects that extend this class should connect\n to the wet signal to this gain node, so that dry and wet \n signals are mixed properly.</p>\n", 5024 "type": "AudioNode", 5025 "optional": true 5026 }] 5027 }, 5028 "p5.Filter": { 5029 "name": "p5.Filter", 5030 "shortname": "p5.Filter", 5031 "classitems": [], 5032 "plugins": [], 5033 "extensions": [], 5034 "plugin_for": [], 5035 "extension_for": [], 5036 "module": "p5.sound", 5037 "submodule": "p5.sound", 5038 "namespace": "", 5039 "file": "lib/addons/p5.sound.js", 5040 "line": 8493, 5041 "description": "<p><p>A p5.Filter uses a Web Audio Biquad Filter to filter\nthe frequency response of an input source. Subclasses\ninclude:</p></p>\n<ul>\n<li><a href=\"/reference/#/p5.LowPass\"><code>p5.LowPass</code></a>:\nAllows frequencies below the cutoff frequency to pass through,\nand attenuates frequencies above the cutoff.<br/></li>\n<li><a href=\"/reference/#/p5.HighPass\"><code>p5.HighPass</code></a>:\nThe opposite of a lowpass filter. <br/></li>\n<li><a href=\"/reference/#/p5.BandPass\"><code>p5.BandPass</code></a>:\nAllows a range of frequencies to pass through and attenuates\nthe frequencies below and above this frequency range.<br/></li>\n</ul>\n<p>The <code>.res()</code> method controls either width of the\nbandpass, or resonance of the low/highpass cutoff frequency.</p>\n<p>This class extends <a href = \"/reference/#/p5.Effect\">p5.Effect</a>.<br>Methods <a href = \"/reference/#/p5.Effect/amp\">amp()</a>, <a href = \"/reference/#/p5.Effect/chain\">chain()</a>, \n<a href = \"/reference/#/p5.Effect/drywet\">drywet()</a>, <a href = \"/reference/#/p5.Effect/connect\">connect()</a>, and \n<a href = \"/reference/#/p5.Effect/disconnect\">disconnect()</a> are available.</p>\n", 5042 "extends": "p5.Effect", 5043 "is_constructor": 1, 5044 "params": [{ 5045 "name": "type", 5046 "description": "<p>'lowpass' (default), 'highpass', 'bandpass'</p>\n", 5047 "type": "String", 5048 "optional": true 5049 }], 5050 "example": ["\n<div><code>\nvar fft, noise, filter;\n\nfunction setup() {\n fill(255, 40, 255);\n\n filter = new p5.BandPass();\n\n noise = new p5.Noise();\n // disconnect unfiltered noise,\n // and connect to filter\n noise.disconnect();\n noise.connect(filter);\n noise.start();\n\n fft = new p5.FFT();\n}\n\nfunction draw() {\n background(30);\n\n // set the BandPass frequency based on mouseX\n var freq = map(mouseX, 0, width, 20, 10000);\n filter.freq(freq);\n // give the filter a narrow band (lower res = wider bandpass)\n filter.res(50);\n\n // draw filtered spectrum\n var spectrum = fft.analyze();\n noStroke();\n for (var i = 0; i < spectrum.length;
5050 i++) {\n var x = map(i, 0, spectrum.length, 0, width);\n var h = -height + map(spectrum[i], 0, 255, height, 0);\n rect(x, height, width/spectrum.length, h);\n }\n\n isMouseOverCanvas();\n}\n\nfunction isMouseOverCanvas() {\n var mX = mouseX, mY = mouseY;\n if (mX > 0 && mX < width && mY < height && mY > 0) {\n noise.amp(0.5, 0.2);\n } else {\n noise.amp(0, 0.2);\n }\n}\n</code></div>"] 5051 }, 5052 "p5.LowPass": { 5053 "name": "p5.LowPass", 5054 "shortname": "p5.LowPass", 5055 "classitems": [], 5056 "plugins": [], 5057 "extensions": [], 5058 "plugin_for": [], 5059 "extension_for": [], 5060 "module": "p5.sound", 5061 "submodule": "p5.sound", 5062 "namespace": "", 5063 "file": "lib/addons/p5.sound.js", 5064 "line": 8724, 5065 "description": "<p>Constructor: <code>new p5.LowPass()</code> Filter.\nThis is the same as creating a p5.Filter and then calling\nits method <code>setType('lowpass')</code>.\nSee p5.Filter for methods.</p>\n", 5066 "is_constructor": 1, 5067 "extends": "p5.Filter" 5068 }, 5069 "p5.HighPass": { 5070 "name": "p5.HighPass", 5071 "shortname": "p5.HighPass", 5072 "classitems": [], 5073 "plugins": [], 5074 "extensions": [], 5075 "plugin_for": [], 5076 "extension_for": [], 5077 "module": "p5.sound", 5078 "submodule": "p5.sound", 5079 "namespace": "", 5080 "file": "lib/addons/p5.sound.js", 5081 "line": 8738, 5082 "description": "<p>Constructor: <code>new p5.HighPass()</code> Filter.\nThis is the same as creating a p5.Filter and then calling\nits method <code>setType('highpass')</code>.\nSee p5.Filter for methods.</p>\n", 5083 "is_constructor": 1, 5084 "extends": "p5.Filter" 5085 }, 5086 "p5.BandPass": { 5087 "name": "p5.BandPass", 5088 "shortname": "p5.BandPass", 5089 "classitems": [], 5090 "plugins": [], 5091 "extensions": [], 5092 "plugin_for": [], 5093 "extension_for": [], 5094 "module": "p5.sound", 5095 "submodule": "p5.sound", 5096 "namespace": "", 5097 "file": "lib/addons/p5.sound.js", 5098 "line": 8752, 5099 "description": "<p>Constructor: <code>new p5.BandPass()</code> Filter.\nThis is the same as creating a p5.Filter and then calling\nits method <code>setType('bandpass')</code>.\nSee p5.Filter for methods.</p>\n", 5100 "is_constructor": 1, 5101 "extends": "p5.Filter" 5102 }, 5103 "p5.EQ": { 5104 "name": "p5.EQ", 5105 "shortname": "p5.EQ", 5106 "classitems": [], 5107 "plugins": [], 5108 "extensions": [], 5109 "plugin_for": [], 5110 "extension_for": [], 5111 "module": "p5.sound", 5112 "submodule": "p5.sound", 5113 "namespace": "", 5114 "file": "lib/addons/p5.sound.js", 5115 "line": 8823, 5116 "description": "<p>p5.EQ is an audio effect that performs the function of a multiband\naudio equalizer. Equalization is used to adjust the balance of\nfrequency compoenents of an audio signal. This process is commonly used\nin sound production and recording to change the waveform before it reaches\na sound output device. EQ can also be used as an audio effect to create\ninteresting distortions by filtering out parts of the spectrum. p5.EQ is\nbuilt using a chain of Web Audio Biquad Filter Nodes and can be\ninstantiated with 3 or 8 bands. Bands can be added or removed from\nthe EQ by directly modifying p5.EQ.bands (the array that stores filters).</p>\n<p>This class extends <a href = \"/reference/#/p5.Effect\">p5.Effect</a>.\nMethods <a href = \"/reference/#/p5.Effect/amp\">amp()</a>, <a href = \"/reference/#/p5.Effect/chain\">chain()</a>,\n<a href = \"/reference/#/p5.Effect/drywet\">drywet()</a>, <a href = \"/reference/#/p5.Effect/connect\">connect()</a>, and\n<a href = \"/reference/#/p5.Effect/disconnect\">disconnect()</a> are available.</p>\n", 5117 "is_constructor": 1,
5118 "extends": "p5.Effect", 5119 "params": [{ 5120 "name": "_eqsize", 5121 "description": "<p>Constructor will accept 3 or 8, defaults to 3</p>\n", 5122 "type": "Number", 5123 "optional": true 5124 }], 5125 "return": { 5126 "description": "p5.EQ object", 5127 "type": "Object" 5128 }, 5129 "example": ["\n<div><code>\nvar eq;\nvar band_names;\nvar band_index;\n\nvar soundFile, play;\n\nfunction preload() {\n soundFormats('mp3', 'ogg');\n soundFile = loadSound('assets/beat');\n}\n\nfunction setup() {\n eq = new p5.EQ(3);\n soundFile.disconnect();\n eq.process(soundFile);\n\n band_names = ['lows','mids','highs'];\n band_index = 0;\n play = false;\n textAlign(CENTER);\n}\n\nfunction draw() {\n background(30);\n noStroke();\n fill(255);\n text('click to kill',50,25);\n\n fill(255, 40, 255);\n textSize(26);\n text(band_names[band_index],50,55);\n\n fill(255);\n textSize(9);\n text('space = play/pause',50,80);\n}\n\n//If mouse is over canvas, cycle to the next band and kill the frequency\nfunction mouseClicked() {\n for (var i = 0; i < eq.bands.length; i++) {\n eq.bands[i].gain(0);\n }\n eq.bands[band_index].gain(-40);\n if (mouseX > 0 && mouseX < width && mouseY < height && mouseY > 0) {\n band_index === 2 ? band_index = 0 : band_index++;\n }\n}\n\n//use space bar to trigger play / pause\nfunction keyPressed() {\n if (key===' ') {\n play = !play\n play ? soundFile.loop() : soundFile.pause();\n }\n}\n</code></div>"] 5130 }, 5131 "p5.Panner3D": { 5132 "name": "p5.Panner3D", 5133 "shortname": "p5.Panner3D", 5134 "classitems": [], 5135 "plugins": [], 5136 "extensions": [], 5137 "plugin_for": [], 5138 "extension_for": [], 5139 "module": "p5.sound", 5140 "submodule": "p5.sound", 5141 "namespace": "", 5142 "file": "lib/addons/p5.sound.js", 5143 "line": 9015, 5144 "description": "<p>Panner3D is based on the <a title=\"Web Audio Panner docs\" href=\n\"https://developer.mozilla.org/en-US/docs/Web/API/PannerNode\">\nWeb Audio Spatial Panner Node</a>.\nThis panner is a spatial processing node that allows audio to be positioned\nand oriented in 3D space.</p>\n<p>The position is relative to an <a title=\"Web Audio Listener docs\" href=\n\"https://developer.mozilla.org/en-US/docs/Web/API/AudioListener\">\nAudio Context Listener</a>, which can be accessed\nby <code>p5.soundOut.audiocontext.listener</code></p>\n", 5145 "is_constructor": 1 5146 }, 5147 "p5.Delay": { 5148 "name": "p5.Delay", 5149 "shortname": "p5.Delay", 5150 "classitems": [], 5151 "plugins": [], 5152 "extensions": [], 5153 "plugin_for": [], 5154 "extension_for": [], 5155 "module": "p5.sound", 5156 "submodule": "p5.sound", 5157 "namespace": "", 5158 "file": "lib/addons/p5.sound.js", 5159 "line": 9466, 5160 "description": "<p>Delay is an echo effect. It processes an existing sound source,\nand outputs a delayed version of that sound. The p5.Delay can\nproduce different effects depending on the delayTime, feedback,\nfilter, and type. In the example below, a feedback of 0.5 (the\ndefaul value) will produce a looping delay that decreases in\nvolume by 50% each repeat. A filter will cut out the high\nfrequencies so that the delay does not sound as piercing as the\noriginal source.</p>\n<p>This class extends <a href = \"/reference/#/p5.Effect\">p5.Effect</a>.<br>Methods <a href = \"/reference/#/p5.Effect/amp\">amp()</a>, <a href = \"/reference/#/p5.Effect/chain\">chain()</a>, \n<a href = \"/reference/#/p5.Effect/drywet\">drywet()</a>, <a href = \"/reference/#/p5.Effect/connect\">connect()</a>, and \n<a href = \"/reference/#/p5.Effect/disconnect\">disconnect()</a> are available.</p>\n", 5161 "extends": "p5.Effect", 5162 "is_constructor": 1, 5163 "example": ["\n<div><code>\nvar noise, env, delay;\n\nfunction setup() {\n background(0);\n noStroke();\n fill(255);\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n\n noise = new p5.Noise('brown');\n noise.amp(0);\n noise.start();\n\n delay = new p5.Delay();\n\n // delay.process() accepts 4 parameters:\n // source, delayTime, feedback, filter frequency\n // play with these numbers!!\n delay.process(noise, .12, .7, 2300);\n\n // play the noise with an envelope,\n // a series of fades ( time / value pairs )\n env = new p5.Envelope(.01, 0.2, .2, .1);\n}\n\n// mouseClick triggers envelope\nfunction mouseClicked() {\n // is mouse over canvas?\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n env.play(noise);\n }\n}\n</code></div>"] 5164 },
5165 "p5.Reverb": { 5166 "name": "p5.Reverb", 5167 "shortname": "p5.Reverb", 5168 "classitems": [], 5169 "plugins": [], 5170 "extensions": [], 5171 "plugin_for": [], 5172 "extension_for": [], 5173 "module": "p5.sound", 5174 "submodule": "p5.sound", 5175 "namespace": "", 5176 "file": "lib/addons/p5.sound.js", 5177 "line": 9743, 5178 "description": "<p>Reverb adds depth to a sound through a large number of decaying\nechoes. It creates the perception that sound is occurring in a\nphysical space. The p5.Reverb has paramters for Time (how long does the\nreverb last) and decayRate (how much the sound decays with each echo)\nthat can be set with the .set() or .process() methods. The p5.Convolver\nextends p5.Reverb allowing you to recreate the sound of actual physical\nspaces through convolution.</p>\n<p>This class extends <a href = \"/reference/#/p5.Effect\">p5.Effect</a>.\nMethods <a href = \"/reference/#/p5.Effect/amp\">amp()</a>, <a href = \"/reference/#/p5.Effect/chain\">chain()</a>,\n<a href = \"/reference/#/p5.Effect/drywet\">drywet()</a>, <a href = \"/reference/#/p5.Effect/connect\">connect()</a>, and\n<a href = \"/reference/#/p5.Effect/disconnect\">disconnect()</a> are available.</p>\n", 5179 "extends": "p5.Effect", 5180 "is_constructor": 1, 5181 "example": ["\n<div><code>\nvar soundFile, reverb;\nfunction preload() {\n soundFile = loadSound('assets/Damscray_DancingTiger.mp3');\n}\n\nfunction setup() {\n reverb = new p5.Reverb();\n soundFile.disconnect(); // so we'll only hear reverb...\n\n // connect soundFile to reverb, process w/\n // 3 second reverbTime, decayRate of 2%\n reverb.process(soundFile, 3, 2);\n soundFile.play();\n}\n</code></div>"] 5182 }, 5183 "p5.Convolver": { 5184 "name": "p5.Convolver", 5185 "shortname": "p5.Convolver", 5186 "classitems": [], 5187 "plugins": [], 5188 "extensions": [], 5189 "plugin_for": [], 5190 "extension_for": [], 5191 "module": "p5.sound", 5192 "submodule": "p5.sound", 5193 "namespace": "", 5194 "file": "lib/addons/p5.sound.js", 5195 "line": 9914, 5196 "description": "<p>p5.Convolver extends p5.Reverb. It can emulate the sound of real\nphysical spaces through a process called <a href=\"\nhttps://en.wikipedia.org/wiki/Convolution_reverb#Real_space_simulation\">\nconvolution</a>.</p>\n\n<p>Convolution multiplies any audio input by an "impulse response"\nto simulate the dispersion of sound over time. The impulse response is\ngenerated from an audio file that you provide. One way to\ngenerate an impulse response is to pop a balloon in a reverberant space\nand record the echo. Convolution can also be used to experiment with\nsound.</p>\n\n<p>Use the method <code>createConvolution(path)</code> to instantiate a\np5.Convolver with a path to your impulse response audio file.</p>", 5197 "extends": "p5.Effect", 5198 "is_constructor": 1, 5199 "params": [{ 5200 "name": "path", 5201 "description": "<p>path to a sound file</p>\n", 5202 "type": "String" 5203 }, { 5204 "name": "callback", 5205 "description": "<p>function to call when loading succeeds</p>\n", 5206 "type": "Function", 5207 "optional": true 5208 }, { 5209 "name": "errorCallback", 5210 "description": "<p>function to call if loading fails.\n This function will receive an error or\n XMLHttpRequest object with information\n about what went wrong.</p>\n", 5211 "type": "Function", 5212 "optional": true 5213 }], 5214 "example": ["\n<div><code>\nvar cVerb, sound;\nfunction preload() {\n // We have both MP3 and OGG versions of all sound assets\n soundFormats('ogg', 'mp3');\n\n // Try replacing 'bx-spring' with other soundfiles like\n // 'concrete-tunnel' 'small-plate' 'drum' 'beatbox'\n
5214cVerb = createConvolver('assets/bx-spring.mp3');\n\n // Try replacing 'Damscray_DancingTiger' with\n // 'beat', 'doorbell', lucky_dragons_-_power_melody'\n sound = loadSound('assets/Damscray_DancingTiger.mp3');\n}\n\nfunction setup() {\n // disconnect from master output...\n sound.disconnect();\n\n // ...and process with cVerb\n // so that we only hear the convolution\n cVerb.process(sound);\n\n sound.play();\n}\n</code></div>"] 5215 }, 5216 "p5.Phrase": { 5217 "name": "p5.Phrase", 5218 "shortname": "p5.Phrase", 5219 "classitems": [], 5220 "plugins": [], 5221 "extensions": [], 5222 "plugin_for": [], 5223 "extension_for": [], 5224 "module": "p5.sound", 5225 "submodule": "p5.sound", 5226 "namespace": "", 5227 "file": "lib/addons/p5.sound.js", 5228 "line": 10470, 5229 "description": "<p>A phrase is a pattern of musical events over time, i.e.\na series of notes and rests.</p>\n\n<p>Phrases must be added to a p5.Part for playback, and\neach part can play multiple phrases at the same time.\nFor example, one Phrase might be a kick drum, another\ncould be a snare, and another could be the bassline.</p>\n\n<p>The first parameter is a name so that the phrase can be\nmodified or deleted later. The callback is a a function that\nthis phrase will call at every stepâfor example it might be\ncalled <code>playNote(value){}</code>. The array determines\nwhich value is passed into the callback at each step of the\nphrase. It can be numbers, an object with multiple numbers,\nor a zero (0) indicates a rest so the callback won't be called).</p>", 5230 "is_constructor": 1, 5231 "params": [{ 5232 "name": "name", 5233 "description": "<p>Name so that you can access the Phrase.</p>\n", 5234 "type": "String" 5235 }, { 5236 "name": "callback", 5237 "description": "<p>The name of a function that this phrase\n will call. Typically it will play a sound,\n and accept two parameters: a time at which\n to play the sound (in seconds from now),\n and a value from the sequence array. The\n time should be passed into the play() or\n start() method to ensure precision.</p>\n", 5238 "type": "Function" 5239 }, { 5240 "name": "sequence", 5241 "description": "<p>Array of values to pass into the callback\n at each step of the phrase.</p>\n", 5242 "type": "Array" 5243 }], 5244 "example": ["\n<div><code>\nvar mySound, myPhrase, myPart;\nvar pattern = [1,0,0,2,0,2,0,0];\nvar msg = 'click to play';\n\nfunction preload() {\n mySound = loadSound('assets/beatbox.mp3');\n}\n\nfunction setup() {\n noStroke();\n fill(255);\n textAlign(CENTER);\n masterVolume(0.1);\n\n myPhrase = new p5.Phrase('bbox', makeSound, pattern);\n myPart = new p5.Part();\n myPart.addPhrase(myPhrase);\n myPart.setBPM(60);\n}\n\nfunction draw() {\n background(0);\n text(msg, width/2, height/2);\n}\n\nfunction makeSound(time, playbackRate) {\n mySound.rate(playbackRate);\n mySound.play(time);\n}\n\nfunction mouseClicked() {\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n myPart.start();\n msg = 'playing pattern';\n }\n}\n\n</code></div>"] 5245 }, 5246 "p5.Part": { 5247 "name": "p5.Part", 5248 "shortname": "p5.Part", 5249 "classitems": [], 5250 "plugins": [], 5251 "extensions": [], 5252 "plugin_for": [], 5253 "extension_for": [], 5254 "module": "p5.sound", 5255 "submodule": "p5.sound", 5256 "namespace": "", 5257 "file": "lib/addons/p5.sound.js", 5258 "line": 10555, 5259 "description": "<p>A p5.Part plays back one or more p5.Phrases. Instantiate a part\nwith steps and tatums. By default, each step represents a 1/16th note.</p>\n\n<p>See p5.Phrase for more about musical timing.</p>", 5260 "is_constructor": 1, 5261 "params": [{ 5262 "name": "steps", 5263 "description": "<p>Steps in the part</p>\n", 5264 "type": "Number", 5265 "optional": true 5266 }, { 5267 "name": "tatums", 5268 "description": "<p>Divisions of a beat, e.g. use 1/4, or 0.25 for a quater note (default is 1/16, a sixteenth note)</p>\n", 5269 "type": "Number", 5270 "optional": true 5271 }], 5272 "example": ["\n<div><code>\nvar box, drum, myPart;\nvar boxPat = [1,0,0,2,0,2,0,0];\nvar drumPat = [0,1,1,0,2,0,1,0];\nvar msg = 'click to play';\n\nfunction preload() {\n box = loadSound('assets/beatbox.mp3');\n drum = loadSound('assets/drum.mp3');\n}\n\nfunction setup() {\n noStroke();\n fill(255);\n textAlign(CENTER);\n masterVolume(0.1);\n\n var boxPhrase = new p5.Phrase('box', playBox, boxPat);\n var drumPhrase = new p5.Phrase('drum', playDrum, drumPat);\n myPart = new p5.Part();\n myPart.addPhrase(boxPhrase);\n myPart.addPhrase(drumPhrase);\n myPart.setBPM(60);\n masterVolume(0.1);\n}\n\nfunction draw() {\n background(0);\n text(msg, width/2, height/2);\n}\n\nfunction playBox(time, playbackRate) {\n box.rate(playbackRate);\n box.play(time);\n}\n\nfunction playDrum(time, playbackRate) {\n drum.rate(playbackRate);\n drum.play(time);\n}\n\nfunction mouseClicked() {\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n myPart.start();\n msg = 'playing part';\n }\n}\n</code></div>"] 5273 },
5274 "p5.Score": { 5275 "name": "p5.Score", 5276 "shortname": "p5.Score", 5277 "classitems": [], 5278 "plugins": [], 5279 "extensions": [], 5280 "plugin_for": [], 5281 "extension_for": [], 5282 "module": "p5.sound", 5283 "submodule": "p5.sound", 5284 "namespace": "", 5285 "file": "lib/addons/p5.sound.js", 5286 "line": 10808, 5287 "description": "<p>A Score consists of a series of Parts. The parts will\nbe played back in order. For example, you could have an\nA part, a B part, and a C part, and play them back in this order\n<code>new p5.Score(a, a, b, a, c)</code></p>\n", 5288 "is_constructor": 1, 5289 "params": [{ 5290 "name": "parts", 5291 "description": "<p>One or multiple parts, to be played in sequence.</p>\n", 5292 "type": "p5.Part", 5293 "optional": true, 5294 "multiple": true 5295 }] 5296 }, 5297 "p5.SoundLoop": { 5298 "name": "p5.SoundLoop", 5299 "shortname": "p5.SoundLoop", 5300 "classitems": [], 5301 "plugins": [], 5302 "extensions": [], 5303 "plugin_for": [], 5304 "extension_for": [], 5305 "module": "p5.sound", 5306 "submodule": "p5.sound", 5307 "namespace": "", 5308 "file": "lib/addons/p5.sound.js", 5309 "line": 10939, 5310 "description": "<p>SoundLoop</p>\n", 5311 "is_constructor": 1, 5312 "params": [{ 5313 "name": "callback", 5314 "description": "<p>this function will be called on each iteration of theloop</p>\n", 5315 "type": "Function" 5316 }, { 5317 "name": "interval", 5318 "description": "<p>amount of time or beats for each iteration of the loop\n defaults to 1</p>\n", 5319 "type": "Number|String", 5320 "optional": true 5321 }], 5322 "example": ["\n<div><code>\nvar click;\nvar looper1;\n\nfunction preload() {\n click = loadSound('assets/drum.mp3');\n}\n\nfunction setup() {\n //the looper's callback is passed the timeFromNow\n //this value should be used as a reference point from \n //which to schedule sounds \n looper1 = new p5.SoundLoop(function(timeFromNow){\n click.play(timeFromNow);\n background(255 * (looper1.iterations % 2));\n }, 2);\n\n //stop after 10 iteratios;\n looper1.maxIterations = 10;\n //start the loop\n looper1.start();\n}\n</code></div>"] 5323 }, 5324 "p5.Compressor": { 5325 "name": "p5.Compressor", 5326 "shortname": "p5.Compressor", 5327 "classitems": [], 5328 "plugins": [], 5329 "extensions": [], 5330 "plugin_for": [], 5331 "extension_for": [], 5332 "module": "p5.sound", 5333 "submodule": "p5.sound", 5334 "namespace": "", 5335 "file": "lib/addons/p5.sound.js", 5336 "line": 11199, 5337 "description": "<p>Compressor is an audio effect class that performs dynamics compression\non an audio input source. This is a very commonly used technique in music\nand sound production. Compression creates an overall louder, richer, \nand fuller sound by lowering the volume of louds and raising that of softs.\nCompression can be used to avoid clipping (sound distortion due to \npeaks in volume) and is especially useful when many sounds are played \nat once. Compression can be used on indivudal sound sources in addition\nto the master output. </p>\n<p>This class extends <a href = \"/reference/#/p5.Effect\">p5.Effect</a>.<br>Methods <a href = \"/reference/#/p5.Effect/amp\">amp()</a>, <a href = \"/reference/#/p5.Effect/chain\">chain()</a>, \n<a href = \"/reference/#/p5.Effect/drywet\">drywet()</a>, <a href = \"/reference/#/p5.Effect/connect\">connect()</a>, and \n<a href = \"/reference/#/p5.Effect/disconnect\">disconnect()</a> are available.</p>\n", 5338 "is_constructor": 1, 5339 "extends": "p5.Effect" 5340 }, 5341 "p5.SoundRecorder": { 5342 "name": "p5.SoundRecorder", 5343 "shortname": "p5.SoundRecorder", 5344 "classitems": [], 5345 "plugins": [], 5346 "extensions": [], 5347 "plugin_for": [], 5348 "extension_for": [], 5349 "module": "p5.sound", 5350 "submodule": "p5.sound", 5351 "namespace": "", 5352 "file": "lib/addons/p5.sound.js", 5353 "line": 11411, 5354 "description": "<p>
5354Record sounds for playback and/or to save as a .wav file.\nThe p5.SoundRecorder records all sound output from your sketch,\nor can be assigned a specific source with setInput().</p>\n<p>The record() method accepts a p5.SoundFile as a parameter.\nWhen playback is stopped (either after the given amount of time,\nor with the stop() method), the p5.SoundRecorder will send its\nrecording to that p5.SoundFile for playback.</p>", 5355 "is_constructor": 1, 5356 "example": ["\n<div><code>\nvar mic, recorder, soundFile;\nvar state = 0;\n\nfunction setup() {\n background(200);\n // create an audio in\n mic = new p5.AudioIn();\n\n // prompts user to enable their browser mic\n mic.start();\n\n // create a sound recorder\n recorder = new p5.SoundRecorder();\n\n // connect the mic to the recorder\n recorder.setInput(mic);\n\n // this sound file will be used to\n // playback & save the recording\n soundFile = new p5.SoundFile();\n\n text('keyPress to record', 20, 20);\n}\n\nfunction keyPressed() {\n // make sure user enabled the mic\n if (state === 0 && mic.enabled) {\n\n // record to our p5.SoundFile\n recorder.record(soundFile);\n\n background(255,0,0);\n text('Recording!', 20, 20);\n state++;\n }\n else if (state === 1) {\n background(0,255,0);\n\n // stop recorder and\n // send result to soundFile\n recorder.stop();\n\n text('Stopped', 20, 20);\n state++;\n }\n\n else if (state === 2) {\n soundFile.play(); // play the result!\n save(soundFile, 'mySound.wav');\n state++;\n }\n}\n</div></code>"] 5357 }, 5358 "p5.PeakDetect": { 5359 "name": "p5.PeakDetect", 5360 "shortname": "p5.PeakDetect", 5361 "classitems": [], 5362 "plugins": [], 5363 "extensions": [], 5364 "plugin_for": [], 5365 "extension_for": [], 5366 "module": "p5.sound", 5367 "submodule": "p5.sound", 5368 "namespace": "", 5369 "file": "lib/addons/p5.sound.js", 5370 "line": 11649, 5371 "description": "<p>PeakDetect works in conjunction with p5.FFT to\nlook for onsets in some or all of the frequency spectrum.\n</p>\n<p>\nTo use p5.PeakDetect, call <code>update</code> in the draw loop\nand pass in a p5.FFT object.\n</p>\n<p>\nYou can listen for a specific part of the frequency spectrum by\nsetting the range between <code>freq1</code> and <code>freq2</code>.\n</p>\n\n<p><code>threshold</code> is the threshold for detecting a peak,\nscaled between 0 and 1. It is logarithmic, so 0.1 is half as loud\nas 1.0.</p>\n\n<p>\nThe update method is meant to be run in the draw loop, and\n<b>frames</b> determines how many loops must pass before\nanother peak can be detected.\nFor example, if the frameRate() = 60, you could detect the beat of a\n120 beat-per-minute song with this equation:\n<code> framesPerPeak = 60 / (estimatedBPM / 60 );</code>\n</p>\n\n<p>\nBased on example contribtued by @b2renger, and a simple beat detection\nexplanation by <a href=\"a\nhref="http://www.airtightinteractive.com/2013/10/making-audio-reactive-visuals/"\ntarget="_blank"\">a\nhref="http://www.airtightinteractive.com/2013/10/making-audio-reactive-visuals/"\ntarget="_blank"</a>Felix Turner</a>.\n</p>", 5372 "is_constructor": 1, 5373 "params": [{ 5374 "name": "freq1", 5375 "description": "<p>lowFrequency - defaults to 20Hz</p>\n", 5376 "type": "Number", 5377 "optional": true 5378 }, { 5379 "name": "freq2", 5380 "description": "<p>highFrequency - defaults to 20000 Hz</p>\n", 5381 "type": "Number", 5382 "optional": true 5383 }, { 5384 "name": "threshold", 5385 "description": "<p>Threshold for detecting a beat between 0 and 1\n scaled logarithmically where 0.1 is 1/2 the loudness\n of 1.0. Defaults to 0.35.</p>\n", 5386 "type": "Number", 5387 "optional": true 5388 }, { 5389 "name": "framesPerPeak", 5390 "description": "<p>Defaults to 20.</p>\n", 5391 "type": "Number", 5392 "optional": true 5393 }], 5394 "example": ["\n<div><code>\n\nvar cnv, soundFile, fft, peakDetect;\nvar ellipseWidth = 10;\n\nfunction preload() {\n soundFile = loadSound('assets/beat.mp3');\n}\n\nfunction setup() {\n background(0);\n noStroke();\n fill(255);\n textAlign(CENTER);\n\n // p5.PeakDetect requires a p5.FFT\n fft = new p5.FFT();\n peakDetect = new p5.PeakDetect();\n}\n\nfunction draw() {\n background(0);\n text('click to play/pause', width/2, height/2);\n\n // peakDetect accepts an fft post-analysis\n fft.analyze();\n peakDetect.update(fft);\n\n if ( peakDetect.isDetected ) {\n ellipseWidth = 50;\n } else {\n ellipseWidth *= 0.95;\n }\n\n ellipse(width/2, height/2, ellipseWidth, ellipseWidth);\n}\n\n// toggle play/stop when canvas is clicked\nfunction mouseClicked() {\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n if (soundFile.isPlaying() ) {\n soundFile.stop();\n } else {\n soundFile.play();\n }\n }\n}\n</code></div>"] 5395 },
5396 "p5.Gain": { 5397 "name": "p5.Gain", 5398 "shortname": "p5.Gain", 5399 "classitems": [], 5400 "plugins": [], 5401 "extensions": [], 5402 "plugin_for": [], 5403 "extension_for": [], 5404 "module": "p5.sound", 5405 "submodule": "p5.sound", 5406 "namespace": "", 5407 "file": "lib/addons/p5.sound.js", 5408 "line": 11873, 5409 "description": "<p>A gain node is usefull to set the relative volume of sound.\nIt's typically used to build mixers.</p>\n", 5410 "is_constructor": 1, 5411 "example": ["\n<div><code>\n\n // load two soundfile and crossfade beetween them\n var sound1,sound2;\n var gain1, gain2, gain3;\n\n function preload(){\n soundFormats('ogg', 'mp3');\n sound1 = loadSound('assets/Damscray_-_Dancing_Tiger_01');\n sound2 = loadSound('assets/beat.mp3');\n }\n\n function setup() {\n createCanvas(400,200);\n\n // create a 'master' gain to which we will connect both soundfiles\n gain3 = new p5.Gain();\n gain3.connect();\n\n // setup first sound for playing\n sound1.rate(1);\n sound1.loop();\n sound1.disconnect(); // diconnect from p5 output\n\n gain1 = new p5.Gain(); // setup a gain node\n gain1.setInput(sound1); // connect the first sound to its input\n gain1.connect(gain3); // connect its output to the 'master'\n\n sound2.rate(1);\n sound2.disconnect();\n sound2.loop();\n\n gain2 = new p5.Gain();\n gain2.setInput(sound2);\n gain2.connect(gain3);\n\n }\n\n function draw(){\n background(180);\n\n // calculate the horizontal distance beetween the mouse and the right of the screen\n var d = dist(mouseX,0,width,0);\n\n // map the horizontal position of the mouse to values useable for volume control of sound1\n var vol1 = map(mouseX,0,width,0,1);\n var vol2 = 1-vol1; // when sound1 is loud, sound2 is quiet and vice versa\n\n gain1.amp(vol1,0.5,0);\n gain2.amp(vol2,0.5,0);\n\n // map the vertical position of the mouse to values useable for 'master volume control'\n var vol3 = map(mouseY,0,height,0,1);\n gain3.amp(vol3,0.5,0);\n }\n</code></div>\n"] 5412 }, 5413 "p5.AudioVoice": { 5414 "name": "p5.AudioVoice", 5415 "shortname": "p5.AudioVoice", 5416 "classitems": [], 5417 "plugins": [], 5418 "extensions": [], 5419 "plugin_for": [], 5420 "extension_for": [], 5421 "module": "p5.sound", 5422 "submodule": "p5.sound", 5423 "namespace": "", 5424 "file": "lib/addons/p5.sound.js", 5425 "line": 12014, 5426 "description": "<p>Base class for monophonic synthesizers. Any extensions of this class\nshould follow the API and implement the methods below in order to \nremain compatible with p5.PolySynth();</p>\n", 5427 "is_constructor": 1 5428 }, 5429 "p5.MonoSynth": { 5430 "name": "p5.MonoSynth", 5431 "shortname": "p5.MonoSynth", 5432 "classitems": [], 5433 "plugins": [], 5434 "extensions": [], 5435 "plugin_for": [], 5436 "extension_for": [], 5437 "module": "p5.sound", 5438 "submodule": "p5.sound", 5439 "namespace": "", 5440 "file": "lib/addons/p5.sound.js", 5441 "line": 12067, 5442 "description": "<p>A MonoSynth is used as a single voice for sound synthesis.\nThis is a class to be used in conjunction with the PolySynth\nclass. Custom synthetisers should be built inheriting from\nthis class.</p>\n", 5443 "is_constructor": 1, 5444 "example": ["\n<div><code>\nvar monoSynth;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n cnv.mousePressed(playSynth);\n\n monoSynth = new p5.MonoSynth();\n\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n}\n\nfunction playSynth() {\n // time from now (in seconds)\n var time = 0;\n // note duration (in seconds)\n var dur = 0.25;\n // velocity (volume, from 0 to 1)\n var v = 0.2;\n\n monoSynth.play(\"G3\", v, time, dur);\n monoSynth.play(\"C4\", v, time += dur, dur);\n\n background(random(255), random(255), 255);\n text('click to play', width/2, height/2);\n}\n</code></div>"] 5445 },
5446 "p5.PolySynth": { 5447 "name": "p5.PolySynth", 5448 "shortname": "p5.PolySynth", 5449 "classitems": [], 5450 "plugins": [], 5451 "extensions": [], 5452 "plugin_for": [], 5453 "extension_for": [], 5454 "module": "p5.sound", 5455 "submodule": "p5.sound", 5456 "namespace": "", 5457 "file": "lib/addons/p5.sound.js", 5458 "line": 12356, 5459 "description": "<p>An AudioVoice is used as a single voice for sound synthesis.\nThe PolySynth class holds an array of AudioVoice, and deals\nwith voices allocations, with setting notes to be played, and\nparameters to be set.</p>\n", 5460 "is_constructor": 1, 5461 "params": [{ 5462 "name": "synthVoice", 5463 "description": "<p>A monophonic synth voice inheriting\n the AudioVoice class. Defaults to p5.MonoSynth</p>\n", 5464 "type": "Number", 5465 "optional": true 5466 }, { 5467 "name": "maxVoices", 5468 "description": "<p>Number of voices, defaults to 8;</p>\n", 5469 "type": "Number", 5470 "optional": true 5471 }], 5472 "example": ["\n<div><code>\nvar polySynth;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n cnv.mousePressed(playSynth);\n\n polySynth = new p5.PolySynth();\n\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n}\n\nfunction playSynth() {\n // note duration (in seconds)\n var dur = 1.5;\n\n // time from now (in seconds)\n var time = 0;\n\n // velocity (volume, from 0 to 1)\n var vel = 0.1;\n\n // notes can overlap with each other\n polySynth.play(\"G2\", vel, 0, dur);\n polySynth.play(\"C3\", vel, time += 1/3, dur);\n polySynth.play(\"G3\", vel, time += 1/3, dur);\n\n background(random(255), random(255), 255);\n text('click to play', width/2, height/2);\n}\n</code></div>"] 5473 }, 5474 "p5.Distortion": { 5475 "name": "p5.Distortion", 5476 "shortname": "p5.Distortion", 5477 "classitems": [], 5478 "plugins": [], 5479 "extensions": [], 5480 "plugin_for": [], 5481 "extension_for": [], 5482 "module": "p5.sound", 5483 "submodule": "p5.sound", 5484 "namespace": "", 5485 "file": "lib/addons/p5.sound.js", 5486 "line": 12761, 5487 "description": "<p>A Distortion effect created with a Waveshaper Node,\nwith an approach adapted from\n<a href=\"http://stackoverflow.com/questions/22312841/waveshaper-node-in-webaudio-how-to-emulate-distortion\">Kevin Ennis</a></p>\n<p>This class extends <a href = \"/reference/#/p5.Effect\">p5.Effect</a>.<br>Methods <a href = \"/reference/#/p5.Effect/amp\">amp()</a>, <a href = \"/reference/#/p5.Effect/chain\">chain()</a>, \n<a href = \"/reference/#/p5.Effect/drywet\">drywet()</a>, <a href = \"/reference/#/p5.Effect/connect\">connect()</a>, and \n<a href = \"/reference/#/p5.Effect/disconnect\">disconnect()</a> are available.</p>\n", 5488 "extends": "p5.Effect", 5489 "is_constructor": 1, 5490 "params": [{ 5491 "name": "amount", 5492 "description": "<p>Unbounded distortion amount.\n Normal values range from 0-1.</p>\n", 5493 "type": "Number", 5494 "optional": true, 5495 "optdefault": "0.25" 5496 }, { 5497 "name": "oversample", 5498 "description": "<p>'none', '2x', or '4x'.</p>\n", 5499 "type": "String", 5500 "optional": true, 5501 "optdefault": "'none'" 5502 }] 5503 } 5504 }, 5505 "elements": {}, 5506 "classitems": [{ 5507 "file": "src/color/color_conversion.js", 5508 "line": 10, 5509 "description": "<p>Conversions adapted from <a href=\"http://www.easyrgb.com/en/math.php\">http://www.easyrgb.com/en/math.php</a>.</p>\n<p>In these functions, hue is always in the range [0, 1], just like all other\ncomponents are in the range [0, 1]. 'Brightness' and 'value' are used\ninterchangeably.</p>\n", 5510 "class": "p5", 5511 "module": "Color", 5512 "submodule": "Color Conversion" 5513 }, { 5514 "file": "src/color/color_conversion.js", 5515 "line": 21, 5516 "description": "<p>Convert an HSBA array to HSLA.</p>\n", 5517 "class": "p5", 5518 "module": "Color", 5519 "submodule": "Color Conversion" 5520 }, { 5521 "file": "src/color/color_conversion.js", 5522 "line": 47, 5523 "description": "<p>Convert an HSBA array to RGBA.</p>\n", 5524 "class": "p5", 5525 "module": "Color", 5526 "submodule": "Color Conversion" 5527 }, { 5528 "file": "src/color/color_conversion.js", 5529 "line": 102, 5530 "description": "<p>Convert an HSLA array to HSBA.</p>\n", 5531 "class": "p5", 5532 "module": "Color", 5533 "submodule": "Color Conversion" 5534 }, { 5535 "file": "src/color/color_conversion.js", 5536 "line": 125, 5537 "description": "<p>Convert an HSLA array to RGBA.</p>\n<p>We need to change basis from HSLA to something that can be more easily be\nprojected onto RGBA. We will choose hue and brightness as our first two\ncomponents, and pick a convenient third one ('zest') so that we don't need\nto calculate formal HSBA saturation.</p>\n", 5538 "class": "p5", 5539 "module": "Color", 5540 "submodule": "Color Conversion" 5541 }, { 5542 "file": "src/color/color_conversion.js", 5543 "line": 189, 5544 "description": "<p>Convert an RGBA array to HSBA.</p>\n", 5545 "class": "p5", 5546 "module": "Color", 5547 "submodule": "Color Conversion" 5548 }, { 5549 "file": "src/color/color_conversion.js", 5550 "line": 228, 5551 "description": "<p>Convert an RGBA array to HSLA.</p>\n", 5552 "class": "p5", 5553 "module": "Color", 5554 "submodule": "Color Conversion" 5555 }, { 5556 "file": "src/color/creating_reading.js", 5557 "line": 16, 5558 "description": "<p>Extracts the alpha value from a color or pixel array.</p>\n", 5559 "itemtype": "method", 5560 "name": "alpha", 5561 "params": [{ 5562 "name": "color", 5563 "description": "<p><a href=\"#/p5.Color\">p5.Color</a> object, color components,\n or CSS color</p>\n", 5564 "type": "p5.Color|Number[]|String" 5565 }], 5566 "return": { 5567 "description": "the alpha value", 5568 "type": "Number" 5569 }, 5570 "example": ["\n<div>\n<code>\nnoStroke();\nlet c = color(0, 126, 255, 102);\nfill(c);\nrect(15, 15, 35, 70);\nlet value = alpha(c); // Sets 'value' to 102\nfill(value);\nrect(50, 15, 35, 70);\n</code>\n</div>"], 5571 "alt": "Left half of canvas light blue and right half light charcoal grey.\nLeft half of canvas light purple and right half a royal blue.\nLeft half of canvas salmon pink and the right half white.\nYellow rect in middle right of canvas, with 55 pixel width and height.\nYellow ellipse in top left canvas, black ellipse in bottom right,both 80x80.\nBright fuschia rect in middle of canvas, 60 pixel width and height.\nTwo bright green rects on opposite sides of the canvas, both 45x80.\nFour blue rects in each corner of the canvas, each are 35x35.\nBright sea green rect on left and darker rect on right of canvas, both 45x80.\nDark green rect on left and light green rect on right of canvas, both 45x80.\nDark blue rect on left and light teal rect on right of canvas, both 45x80.\nblue rect on left and green on right, both with black outlines & 35x60.\nsalmon pink rect on left and black on right, both 35x60.\n4 rects, tan, brown, brownish purple and purple, with white outlines & 20x60.\nlight pastel green rect on left and dark grey rect on right, both 35x60.\nyellow rect on left and red rect on right, both with black outlines & 35x60.\ngrey canvas\ndeep pink rect on left and grey rect on right, both 35x60.", 5572 "class": "p5", 5573 "module": "Color", 5574 "submodule": "Creating & Reading" 5575 }, { 5576 "file": "src/color/creating_reading.js", 5577 "line": 61, 5578 "description": "<p>Extracts the blue value from a color or pixel array.</p>\n", 5579 "itemtype": "method", 5580 "name": "blue", 5581 "params": [{ 5582 "name": "color", 5583 "description": "<p><a href=\"#/p5.Color\">p5.Color</a> object, color components,\n or CSS color</p>\n", 5584 "type": "p5.Color|Number[]|String" 5585 }], 5586 "return": { 5587 "description": "the blue value", 5588 "type": "Number" 5589 }, 5590 "example": ["\n<div>\n<code>\nlet c = color(175, 100, 220); // Define color 'c'\nfill(c); // Use color variable 'c' as fill color\nrect(15, 20, 35, 60); // Draw left rectangle\n\nlet blueValue = blue(c); // Get blue in 'c'\nprint(blueValue); // Prints \"220.0\"\nfill(0, 0, blueValue); // Use 'blueValue' in new fill\nrect(50, 20, 35, 60); // Draw right rectangle\n</code>\n</div>"], 5591 "alt": "Left half of canvas light purple and right half a royal blue.", 5592 "class": "p5", 5593 "module": "Color", 5594 "submodule": "Creating & Reading" 5595 }, { 5596 "file": "src/color/creating_reading.js", 5597 "line": 91, 5598 "description": "<p>Extracts the HSB brightness value from a color or pixel array.</p>\n", 5599 "itemtype": "method", 5600 "name": "brightness", 5601 "params": [{ 5602 "name": "color", 5603 "description": "<p><a href=\"#/p5.Color\">p5.Color</a> object, color components,\n or CSS color</p>\n", 5604 "type": "p5.Color|Number[]|String" 5605 }], 5606 "return": { 5607 "description": "the brightness value", 5608 "type": "Number" 5609 }, 5610 "example": ["\n<div>\n<code>\nnoStroke();\ncolorMode(HSB, 255);\nlet c = color(0, 126, 255);\nfill(c);\nrect(15, 20, 35, 60);\nlet value = brightness(c); // Sets 'value' to 255\nfill(value);\nrect(50, 20, 35, 60);\n</code>\n</div>"], 5611 "alt": "Left half of canvas salmon pink and the right half white.", 5612 "class": "p5", 5613 "module": "Color", 5614 "submodule": "Creating & Reading" 5615 }, { 5616 "file": "src/color/creating_reading.js", 5617 "line": 121, 5618 "description": "<p>Creates colors for storing in variables of the color datatype. The\nparameters are interpreted as RGB or HSB values depending on the\ncurrent <a href=\"#/p5/colorMode\">colorMode()</a>. The default mode is RGB values from 0 to 255\nand, therefore, the function call color(255, 204, 0) will return a\nbright yellow color.\n<br><br>\nNote that if only one value is provided to <a href=\"#/p5/color\">color()</a>, it will be interpreted\nas a grayscale value. Add a second value, and it will be used for alpha\ntransparency. When three values are specified, they are interpreted as\neither RGB or HSB values. Adding a fourth value applies alpha\ntransparency.\n<br><br>
5618\nIf a single string argument is provided, RGB, RGBA and Hex CSS color\nstrings and all named color strings are supported. In this case, an alpha\nnumber value as a second argument is not supported, the RGBA form should be\nused.</p>\n", 5619 "itemtype": "method", 5620 "name": "color", 5621 "return": { 5622 "description": "resulting color", 5623 "type": "p5.Color" 5624 }, 5625 "example": ["\n<div>\n<code>\nlet c = color(255, 204, 0); // Define color 'c'\nfill(c); // Use color variable 'c' as fill color\nnoStroke(); // Don't draw a stroke around shapes\nrect(30, 20, 55, 55); // Draw rectangle\n</code>\n</div>\n\n<div>\n<code>\nlet c = color(255, 204, 0); // Define color 'c'\nfill(c); // Use color variable 'c' as fill color\nnoStroke(); // Don't draw a stroke around shapes\nellipse(25, 25, 80, 80); // Draw left circle\n\n// Using only one value with color()\n// generates a grayscale value.\nc = color(65); // Update 'c' with grayscale value\nfill(c); // Use updated 'c' as fill color\nellipse(75, 75, 80, 80); // Draw right circle\n</code>\n</div>\n\n<div>\n<code>\n// Named SVG & CSS colors may be used,\nlet c = color('magenta');\nfill(c); // Use 'c' as fill color\nnoStroke(); // Don't draw a stroke around shapes\nrect(20, 20, 60, 60); // Draw rectangle\n</code>\n</div>\n\n<div>\n<code>\n// as can hex color codes:\nnoStroke(); // Don't draw a stroke around shapes\nlet c = color('#0f0');\nfill(c); // Use 'c' as fill color\nrect(0, 10, 45, 80); // Draw rectangle\n\nc = color('#00ff00');\nfill(c); // Use updated 'c' as fill color\nrect(55, 10, 45, 80); // Draw rectangle\n</code>\n</div>\n\n<div>\n<code>\n// RGB and RGBA color strings are also supported:\n// these all set to the same color (solid blue)\nlet c;\nnoStroke(); // Don't draw a stroke around shapes\nc = color('rgb(0,0,255)');\nfill(c); // Use 'c' as fill color\nrect(10, 10, 35, 35); // Draw rectangle\n\nc = color('rgb(0%, 0%, 100%)');\nfill(c); // Use updated 'c' as fill color\nrect(55, 10, 35, 35); // Draw rectangle\n\nc = color('rgba(0, 0, 255, 1)');\nfill(c); // Use updated 'c' as fill color\nrect(10, 55, 35, 35); // Draw rectangle\n\nc = color('rgba(0%, 0%, 100%, 1)');\nfill(c); // Use updated 'c' as fill color\nrect(55, 55, 35, 35); // Draw rectangle\n</code>\n</div>\n\n<div>\n<code>\n// HSL color is also supported and can be specified\n// by value\nlet c;\nnoStroke(); // Don't draw a stroke around shapes\nc = color('hsl(160, 100%, 50%)');\nfill(c); // Use 'c' as fill color\nrect(0, 10, 45, 80); // Draw rectangle\n\nc = color('hsla(160, 100%, 50%, 0.5)');\nfill(c); // Use updated 'c' as fill color\nrect(55, 10, 45, 80); // Draw rectangle\n</code>\n</div>\n\n<div>\n<code>\n// HSB color is also supported and can be specified\n// by value\nlet c;\nnoStroke(); // Don't draw a stroke around shapes\nc = color('hsb(160, 100%, 50%)');\nfill(c); // Use 'c' as fill color\nrect(0, 10, 45, 80); // Draw rectangle\n\nc = color('hsba(160, 100%, 50%, 0.5)');\nfill(c); // Use updated 'c' as fill color\nrect(55, 10, 45, 80); // Draw rectangle\n</code>\n</div>\n\n<div>\n<code>\nlet c; // Declare color 'c'\nnoStroke(); // Don't draw a stroke around shapes\n\n// If no colorMode is specified, then the\n// default of RGB with scale of 0-255 is used.\nc = color(50, 55, 100); // Create a color for 'c'\nfill(c); // Use color variable 'c' as fill color\nrect(0, 10, 45, 80); // Draw left rect\n\ncolorMode(HSB, 100); // Use HSB with scale of 0-100\nc = color(50, 55, 100); // Update 'c' with new color\nfill(c); // Use updated 'c' as fill color\nrect(55, 10, 45, 80); // Draw right rect\n</code>\n</div>"], 5626 "alt": "Yellow rect in middle right of canvas, with 55 pixel width and height.\nYellow ellipse in top left of canvas, black ellipse in bottom right,both 80x80.\nBright fuschia rect in middle of canvas, 60 pixel width and height.\nTwo bright green rects on opposite sides of the canvas, both 45x80.\nFour blue rects in each corner of the canvas, each are 35x35.\nBright sea green rect on left and darker rect on right of canvas, both 45x80.\nDark green rect on left and lighter green rect on right of canvas, both 45x80.\nDark blue rect on left and light teal rect on right of canvas, both 45x80.", 5627 "class": "p5", 5628 "module": "Color", 5629 "submodule": "Creating & Reading", 5630 "overloads": [{ 5631 "line": 121, 5632 "params": [{ 5633 "name": "gray", 5634 "description": "<p>number specifying value between white\n and black.</p>\n", 5635 "type": "Number" 5636 }, { 5637 "name": "alpha", 5638 "description": "<p>alpha value relative to current color range\n (default is 0-255)</p>\n", 5639 "type": "Number", 5640 "optional": true 5641 }], 5642 "return": { 5643 "description": "resulting color", 5644 "type": "p5.Color" 5645 } 5646 }, { 5647 "line": 280, 5648 "params": [{ 5649 "name": "v1", 5650 "description": "<p>red or hue value relative to\n the current color range</p>\n", 5651 "type": "Number" 5652 }, { 5653 "name": "v2", 5654 "description": "<p>
5654green or saturation value\n relative to the current color range</p>\n", 5655 "type": "Number" 5656 }, { 5657 "name": "v3", 5658 "description": "<p>blue or brightness value\n relative to the current color range</p>\n", 5659 "type": "Number" 5660 }, { 5661 "name": "alpha", 5662 "description": "", 5663 "type": "Number", 5664 "optional": true 5665 }], 5666 "return": { 5667 "description": "", 5668 "type": "p5.Color" 5669 } 5670 }, { 5671 "line": 292, 5672 "params": [{ 5673 "name": "value", 5674 "description": "<p>a color string</p>\n", 5675 "type": "String" 5676 }], 5677 "return": { 5678 "description": "", 5679 "type": "p5.Color" 5680 } 5681 }, { 5682 "line": 297, 5683 "params": [{ 5684 "name": "values", 5685 "description": "<p>an array containing the red,green,blue &\n and alpha components of the color</p>\n", 5686 "type": "Number[]" 5687 }], 5688 "return": { 5689 "description": "", 5690 "type": "p5.Color" 5691 } 5692 }, { 5693 "line": 303, 5694 "params": [{ 5695 "name": "color", 5696 "description": "", 5697 "type": "p5.Color" 5698 }], 5699 "return": { 5700 "description": "", 5701 "type": "p5.Color" 5702 } 5703 }] 5704 }, { 5705 "file": "src/color/creating_reading.js", 5706 "line": 319, 5707 "description": "<p>Extracts the green value from a color or pixel array.</p>\n", 5708 "itemtype": "method", 5709 "name": "green", 5710 "params": [{ 5711 "name": "color", 5712 "description": "<p><a href=\"#/p5.Color\">p5.Color</a> object, color components,\n or CSS color</p>\n", 5713 "type": "p5.Color|Number[]|String" 5714 }], 5715 "return": { 5716 "description": "the green value", 5717 "type": "Number" 5718 }, 5719 "example": ["\n<div>\n<code>\nlet c = color(20, 75, 200); // Define color 'c'\nfill(c); // Use color variable 'c' as fill color\nrect(15, 20, 35, 60); // Draw left rectangle\n\nlet greenValue = green(c); // Get green in 'c'\nprint(greenValue); // Print \"75.0\"\nfill(0, greenValue, 0); // Use 'greenValue' in new fill\nrect(50, 20, 35, 60); // Draw right rectangle\n</code>\n</div>"], 5720 "alt": "blue rect on left and green on right, both with black outlines & 35x60.", 5721 "class": "p5", 5722 "module": "Color", 5723 "submodule": "Creating & Reading" 5724 }, { 5725 "file": "src/color/creating_reading.js", 5726 "line": 350, 5727 "description": "<p>Extracts the hue value from a color or pixel array.</p>\n<p>Hue exists in both HSB and HSL. This function will return the\nHSB-normalized hue when supplied with an HSB color object (or when supplied\nwith a pixel array while the color mode is HSB), but will default to the\nHSL-normalized hue otherwise. (The values will only be different if the\nmaximum hue setting for each system is different.)</p>\n", 5728 "itemtype": "method", 5729 "name": "hue", 5730 "params": [{ 5731 "name": "color", 5732 "description": "<p><a href=\"#/p5.Color\">p5.Color</a> object, color components,\n or CSS color</p>\n", 5733 "type": "p5.Color|Number[]|String" 5734 }], 5735 "return": { 5736 "description": "the hue", 5737 "type": "Number" 5738 }, 5739 "example": ["\n<div>\n<code>\nnoStroke();\ncolorMode(HSB, 255);\nlet c = color(0, 126, 255);\nfill(c);\nrect(15, 20, 35, 60);\nlet value = hue(c); // Sets 'value' to \"0\"\nfill(value);\nrect(50, 20, 35, 60);\n</code>\n</div>"], 5740 "alt": "salmon pink rect on left and black on right, both 35x60.", 5741 "class": "p5", 5742 "module": "Color", 5743 "submodule": "Creating & Reading" 5744 }, { 5745 "file": "src/color/creating_reading.js", 5746 "line": 387, 5747 "description": "<p>Blends two colors to find a third color somewhere between them. The amt\nparameter is the amount to interpolate between the two values where 0.0\nequal to the first color, 0.1 is very near the first color, 0.5 is halfway\nin between, etc. An amount below 0 will be treated as 0. Likewise, amounts\nabove 1 will be capped at 1. This is different from the behavior of <a href=\"#/p5/lerp\">lerp()</a>,\nbut necessary because otherwise numbers outside the range will produce\nstrange and unexpected colors.\n<br><br>\nThe way that colours are interpolated depends on the current color mode.</p>\n", 5748 "itemtype": "method", 5749 "name": "lerpColor", 5750 "params": [{ 5751 "name": "c1", 5752 "description": "<p>interpolate from this color</p>\n", 5753 "type": "p5.Color" 5754 }, { 5755 "name": "c2", 5756 "description": "<p>interpolate to this color</p>\n", 5757 "type": "p5.Color" 5758 }, { 5759 "name": "amt", 5760 "description": "<p>number between 0 and 1</p>\n", 5761 "type": "Number" 5762 }], 5763 "return": { 5764 "description": "interpolated color", 5765 "type": "p5.Color" 5766 }, 5767 "example": ["\n<div>\n<code>\ncolorMode(RGB);
5767\nstroke(255);\nbackground(51);\nlet from = color(218, 165, 32);\nlet to = color(72, 61, 139);\ncolorMode(RGB); // Try changing to HSB.\nlet interA = lerpColor(from, to, 0.33);\nlet interB = lerpColor(from, to, 0.66);\nfill(from);\nrect(10, 20, 20, 60);\nfill(interA);\nrect(30, 20, 20, 60);\nfill(interB);\nrect(50, 20, 20, 60);\nfill(to);\nrect(70, 20, 20, 60);\n</code>\n</div>"], 5768 "alt": "4 rects one tan, brown, brownish purple, purple, with white outlines & 20x60", 5769 "class": "p5", 5770 "module": "Color", 5771 "submodule": "Creating & Reading" 5772 }, { 5773 "file": "src/color/creating_reading.js", 5774 "line": 484, 5775 "description": "<p>Extracts the HSL lightness value from a color or pixel array.</p>\n", 5776 "itemtype": "method", 5777 "name": "lightness", 5778 "params": [{ 5779 "name": "color", 5780 "description": "<p><a href=\"#/p5.Color\">p5.Color</a> object, color components,\n or CSS color</p>\n", 5781 "type": "p5.Color|Number[]|String" 5782 }], 5783 "return": { 5784 "description": "the lightness", 5785 "type": "Number" 5786 }, 5787 "example": ["\n<div>\n<code>\nnoStroke();\ncolorMode(HSL);\nlet c = color(156, 100, 50, 1);\nfill(c);\nrect(15, 20, 35, 60);\nlet value = lightness(c); // Sets 'value' to 50\nfill(value);\nrect(50, 20, 35, 60);\n</code>\n</div>"], 5788 "alt": "light pastel green rect on left and dark grey rect on right, both 35x60.", 5789 "class": "p5", 5790 "module": "Color", 5791 "submodule": "Creating & Reading" 5792 }, { 5793 "file": "src/color/creating_reading.js", 5794 "line": 514, 5795 "description": "<p>Extracts the red value from a color or pixel array.</p>\n", 5796 "itemtype": "method", 5797 "name": "red", 5798 "params": [{ 5799 "name": "color", 5800 "description": "<p><a href=\"#/p5.Color\">p5.Color</a> object, color components,\n or CSS color</p>\n", 5801 "type": "p5.Color|Number[]|String" 5802 }], 5803 "return": { 5804 "description": "the red value", 5805 "type": "Number" 5806 }, 5807 "example": ["\n<div>\n<code>\nlet c = color(255, 204, 0); // Define color 'c'\nfill(c); // Use color variable 'c' as fill color\nrect(15, 20, 35, 60); // Draw left rectangle\n\nlet redValue = red(c); // Get red in 'c'\nprint(redValue); // Print \"255.0\"\nfill(redValue, 0, 0); // Use 'redValue' in new fill\nrect(50, 20, 35, 60); // Draw right rectangle\n</code>\n</div>\n\n<div>\n<code>\ncolorMode(RGB, 255);\nlet c = color(127, 255, 0);\ncolorMode(RGB, 1);\nlet myColor = red(c);\nprint(myColor);\n</code>\n</div>"], 5808 "alt": "yellow rect on left and red rect on right, both with black outlines and 35x60.\ngrey canvas", 5809 "class": "p5", 5810 "module": "Color", 5811 "submodule": "Creating & Reading" 5812 }, { 5813 "file": "src/color/creating_reading.js", 5814 "line": 554, 5815 "description": "<p>Extracts the saturation value from a color or pixel array.</p>\n<p>Saturation is scaled differently in HSB and HSL. This function will return\nthe HSB saturation when supplied with an HSB color object (or when supplied\nwith a pixel array while the color mode is HSB), but will default to the\nHSL saturation otherwise.</p>\n", 5816 "itemtype": "method", 5817 "name": "saturation", 5818 "params": [{ 5819 "name": "color", 5820 "description": "<p><a href=\"#/p5.Color\">p5.Color</a> object, color components,\n or CSS color</p>\n", 5821 "type": "p5.Color|Number[]|String" 5822 }], 5823 "return": { 5824 "description": "the saturation value", 5825 "type": "Number" 5826 }, 5827 "example": ["\n<div>\n<code>\nnoStroke();\ncolorMode(HSB, 255);\nlet c = color(0, 126, 255);\nfill(c);\nrect(15, 20, 35, 60);\nlet value = saturation(c); // Sets 'value' to 126\nfill(value);\nrect(50, 20, 35, 60);\n</code>\n</div>"], 5828 "alt": "deep pink rect on left and grey rect on right, both 35x60.", 5829 "class": "p5", 5830 "module": "Color", 5831 "submodule": "Creating & Reading" 5832 }, { 5833 "file": "src/color/p5.Color.js", 5834 "line": 52, 5835 "description": "<p>This function returns the color formatted as a string. This can be useful\nfor debugging, or for using p5.js with other libraries.</p>\n", 5836 "itemtype": "method", 5837 "name": "toString", 5838 "params": [{ 5839 "name": "format", 5840 "description": "<p>How the color string will be formatted.\nLeaving this empty formats the string as rgba(r, g, b, a).\n'#rgb' '#rgba' '#rrggbb' and '#rrggbbaa' format as hexadecimal color codes.\n'rgb' 'hsb' and 'hsl' return the color formatted in the specified color mode.\n'rgba' 'hsba' and 'hsla' are the same as above but with alpha channels.\n'rgb%' 'hsb%' 'hsl%' 'rgba%' 'hsba%' and 'hsla%' format as percentages.</p>\n", 5841 "type": "String", 5842 "optional": true 5843 }], 5844 "return": { 5845 "description": "the formatted string", 5846 "type": "String" 5847 }, 5848 "example": ["\n<div>\n<code>\nlet myColor;\nfunction setup() {\n createCanvas(200, 200);
5848\n stroke(255);\n myColor = color(100, 100, 250);\n fill(myColor);\n}\n\nfunction draw() {\n rotate(HALF_PI);\n text(myColor.toString(), 0, -5);\n text(myColor.toString('#rrggbb'), 0, -30);\n text(myColor.toString('rgba%'), 0, -55);\n}\n</code>\n</div>"], 5849 "alt": "canvas with text representation of color", 5850 "class": "p5.Color", 5851 "module": "Color", 5852 "submodule": "Creating & Reading" 5853 }, { 5854 "file": "src/color/p5.Color.js", 5855 "line": 248, 5856 "itemtype": "method", 5857 "name": "setRed", 5858 "params": [{ 5859 "name": "red", 5860 "description": "<p>the new red value</p>\n", 5861 "type": "Number" 5862 }], 5863 "example": ["\n<div>\n<code>\nlet backgroundColor;\n\nfunction setup() {\n backgroundColor = color(100, 50, 150);\n}\n\nfunction draw() {\n backgroundColor.setRed(128 + 128 * sin(millis() / 1000));\n background(backgroundColor);\n}\n</code>\n</div>"], 5864 "alt": "canvas with gradually changing background color", 5865 "class": "p5.Color", 5866 "module": "Color", 5867 "submodule": "Creating & Reading" 5868 }, { 5869 "file": "src/color/p5.Color.js", 5870 "line": 275, 5871 "itemtype": "method", 5872 "name": "setGreen", 5873 "params": [{ 5874 "name": "green", 5875 "description": "<p>the new green value</p>\n", 5876 "type": "Number" 5877 }], 5878 "example": ["\n<div>\n<code>\nlet backgroundColor;\n\nfunction setup() {\n backgroundColor = color(100, 50, 150);\n}\n\nfunction draw() {\n backgroundColor.setGreen(128 + 128 * sin(millis() / 1000));\n background(backgroundColor);\n}\n</code>\n</div>"], 5879 "alt": "canvas with gradually changing background color", 5880 "class": "p5.Color", 5881 "module": "Color", 5882 "submodule": "Creating & Reading" 5883 }, { 5884 "file": "src/color/p5.Color.js", 5885 "line": 302, 5886 "itemtype": "method", 5887 "name": "setBlue", 5888 "params": [{ 5889 "name": "blue", 5890 "description": "<p>the new blue value</p>\n", 5891 "type": "Number" 5892 }], 5893 "example": ["\n<div>\n<code>\nlet backgroundColor;\n\nfunction setup() {\n backgroundColor = color(100, 50, 150);\n}\n\nfunction draw() {\n backgroundColor.setBlue(128 + 128 * sin(millis() / 1000));\n background(backgroundColor);\n}\n</code>\n</div>"], 5894 "alt": "canvas with gradually changing background color", 5895 "class": "p5.Color", 5896 "module": "Color", 5897 "submodule": "Creating & Reading" 5898 }, { 5899 "file": "src/color/p5.Color.js", 5900 "line": 329, 5901 "itemtype": "method", 5902 "name": "setAlpha", 5903 "params": [{ 5904 "name": "alpha", 5905 "description": "<p>the new alpha value</p>\n", 5906 "type": "Number" 5907 }], 5908 "example": ["\n<div>\n<code>\nlet squareColor;\n\nfunction setup() {\n ellipseMode(CORNERS);\n strokeWeight(4);\n squareColor = color(100, 50, 150);\n}\n\nfunction draw() {\n background(255);\n\n noFill();\n stroke(0);\n ellipse(10, 10, width - 10, height - 10);\n\n squareColor.setAlpha(128 + 128 * sin(millis() / 1000));\n fill(squareColor);\n noStroke();\n rect(13, 13, width - 26, height - 26);\n}\n</code>\n</div>"], 5909 "alt": "circle behind a square with gradually changing opacity", 5910 "class": "p5.Color", 5911 "module": "Color", 5912 "submodule": "Creating & Reading" 5913 }, { 5914 "file": "src/color/p5.Color.js", 5915 "line": 410, 5916 "description": "<p>Hue is the same in HSB and HSL, but the maximum value may be different.\nThis function will return the HSB-normalized saturation when supplied with\nan HSB color object, but will default to the HSL-normalized saturation\notherwise.</p>\n", 5917 "class": "p5.Color", 5918 "module": "Color", 5919 "submodule": "Creating & Reading" 5920 }, { 5921 "file": "src/color/p5.Color.js", 5922 "line": 441, 5923 "description": "<p>Saturation is scaled differently in HSB and HSL. This function will return\nthe HSB saturation when supplied with an HSB color object, but will default\nto the HSL saturation otherwise.</p>\n", 5924 "class": "p5.Color", 5925 "module": "Color", 5926 "submodule": "Creating & Reading" 5927 }, { 5928 "file": "src/color/p5.Color.js", 5929 "line": 460, 5930 "description": "<p>CSS named colors.</p>\n", 5931 "class": "p5.Color", 5932 "module": "Color", 5933 "submodule": "Creating & Reading" 5934 }, { 5935 "file": "src/color/p5.Color.js", 5936 "line": 613, 5937 "description": "<p>These regular expressions are used to build up the patterns for matching\nviable CSS color strings: fragmenting the regexes in this way increases the\nlegibility and comprehensibility of the code.</p>\n<p>Note that RGB values of .9 are not parsed by IE, but are supported here for\ncolor string consistency.</p>\n", 5938 "class": "p5.Color", 5939 "module": "Color", 5940 "submodule": "Creating & Reading" 5941 }, { 5942 "file": "src/color/p5.Color.js", 5943 "line": 626, 5944 "description": "<p>Full color string patterns. The capture groups are necessary.</p>\n", 5945 "class": "p5.Color", 5946 "module": "Color", 5947 "submodule": "Creating & Reading" 5948 }, { 5949 "file": "src/color/p5.Color.js", 5950 "line": 989, 5951 "description": "<p>For HSB and HSL, interpret the gray level as a brightness/lightness\nvalue (they are equivalent when chroma is zero). For RGB, normalize the\ngray level according to the blue maximum.</p>\n", 5952 "class": "p5.Color", 5953 "module": "Color", 5954 "submodule": "Creating & Reading" 5955 }, { 5956 "file": "src/color/setting.js", 5957 "line": 15, 5958 "description": "<p>The <a href=\"#/p5/background\">background()</a> function sets the color used for the background of the\np5.js canvas. The default background is transparent. This function is\ntypically used within <a href=\"#/p5/draw\">draw()</a> to clear the display window at the beginning\nof each frame, but it can be used inside <a href=\"#/p5/setup\">setup()</a> to set the background on\nthe first frame of animation or if the background need only be set once.\n<br><br>\nThe color is either specified in terms of the RGB, HSB, or HSL color\ndepending on the current <a href=\"#/p5/colorMode\">
5958colorMode</a>. (The default color space is RGB, with\neach value in the range from 0 to 255). The alpha range by default is also 0 to 255.\n<br><br>\nIf a single string argument is provided, RGB, RGBA and Hex CSS color strings\nand all named color strings are supported. In this case, an alpha number\nvalue as a second argument is not supported, the RGBA form should be used.\n<br><br>\nA <a href=\"#/p5.Color\">p5.Color</a> object can also be provided to set the background color.\n<br><br>\nA <a href=\"#/p5.Image\">p5.Image</a> can also be provided to set the background image.</p>\n", 5959 "itemtype": "method", 5960 "name": "background", 5961 "chainable": 1, 5962 "example": ["\n<div>\n<code>\n// Grayscale integer value\nbackground(51);\n</code>\n</div>\n\n<div>\n<code>\n// R, G & B integer values\nbackground(255, 204, 0);\n</code>\n</div>\n\n<div>\n<code>\n// H, S & B integer values\ncolorMode(HSB);\nbackground(255, 204, 100);\n</code>\n</div>\n\n<div>\n<code>\n// Named SVG/CSS color string\nbackground('red');\n</code>\n</div>\n\n<div>\n<code>\n// three-digit hexadecimal RGB notation\nbackground('#fae');\n</code>\n</div>\n\n<div>\n<code>\n// six-digit hexadecimal RGB notation\nbackground('#222222');\n</code>\n</div>\n\n<div>\n<code>\n// integer RGB notation\nbackground('rgb(0,255,0)');\n</code>\n</div>\n\n<div>\n<code>\n// integer RGBA notation\nbackground('rgba(0,255,0, 0.25)');\n</code>\n</div>\n\n<div>\n<code>\n// percentage RGB notation\nbackground('rgb(100%,0%,10%)');\n</code>\n</div>\n\n<div>\n<code>\n// percentage RGBA notation\nbackground('rgba(100%,0%,100%,0.5)');\n</code>\n</div>\n\n<div>\n<code>\n// p5 Color object\nbackground(color(0, 0, 255));\n</code>\n</div>"], 5963 "alt": "canvas with darkest charcoal grey background.\ncanvas with yellow background.\ncanvas with royal blue background.\ncanvas with red background.\ncanvas with pink background.\ncanvas with black background.\ncanvas with bright green background.\ncanvas with soft green background.\ncanvas with red background.\ncanvas with light purple background.\ncanvas with blue background.", 5964 "class": "p5", 5965 "module": "Color", 5966 "submodule": "Setting", 5967 "overloads": [{ 5968 "line": 15, 5969 "params": [{ 5970 "name": "color", 5971 "description": "<p>any value created by the <a href=\"#/p5/color\">color()</a> function</p>\n", 5972 "type": "p5.Color" 5973 }], 5974 "chainable": 1 5975 }, { 5976 "line": 131, 5977 "params": [{ 5978 "name": "colorstring", 5979 "description": "<p>color string, possible formats include: integer\n rgb() or rgba(), percentage rgb() or rgba(),\n 3-digit hex, 6-digit hex</p>\n", 5980 "type": "String" 5981 }, { 5982 "name": "a", 5983 "description": "<p>opacity of the background relative to current\n color range (default is 0-255)</p>\n", 5984 "type": "Number", 5985 "optional": true 5986 }], 5987 "chainable": 1 5988 }, { 5989 "line": 141, 5990 "params": [{ 5991 "name": "gray", 5992 "description": "<p>specifies a value between white and black</p>\n", 5993 "type": "Number" 5994 }, { 5995 "name": "a", 5996 "description": "", 5997 "type": "Number", 5998 "optional": true 5999 }], 6000 "chainable": 1 6001 }, { 6002 "line": 148, 6003 "params": [{ 6004 "name": "v1", 6005 "description": "<p>red or hue value (depending on the current color\n mode)</p>\n", 6006 "type": "Number" 6007 }, { 6008 "name": "v2", 6009 "description": "<p>green or saturation value (depending on the current\n color mode)</p>\n", 6010 "type": "Number" 6011 }, { 6012 "name": "v3", 6013 "description": "<p>blue or brightness value (depending on the current\n color mode)</p>\n", 6014 "type": "Number" 6015 }, { 6016 "name": "a", 6017 "description": "", 6018 "type": "Number", 6019 "optional": true 6020 }], 6021 "chainable": 1 6022 }, { 6023 "line": 160,
6024 "params": [{ 6025 "name": "values", 6026 "description": "<p>an array containing the red,green,blue &\n and alpha components of the color</p>\n", 6027 "type": "Number[]" 6028 }], 6029 "chainable": 1 6030 }, { 6031 "line": 167, 6032 "params": [{ 6033 "name": "image", 6034 "description": "<p>image created with <a href=\"#/p5/loadImage\">loadImage()</a> or <a href=\"#/p5/createImage\">createImage()</a>,\n to set as background\n (must be same size as the sketch window)</p>\n", 6035 "type": "p5.Image" 6036 }, { 6037 "name": "a", 6038 "description": "", 6039 "type": "Number", 6040 "optional": true 6041 }], 6042 "chainable": 1 6043 }] 6044 }, { 6045 "file": "src/color/setting.js", 6046 "line": 185, 6047 "description": "<p>Clears the pixels within a buffer. This function only works on p5.Canvas\nobjects created with the <a href=\"#/p5/createCanvas\">createCanvas()</a> function; it won't work with the\nmain display window. Unlike the main graphics context, pixels in\nadditional graphics areas created with <a href=\"#/p5/createGraphics\">createGraphics()</a> can be entirely\nor partially transparent. This function clears everything to make all of\nthe pixels 100% transparent.</p>\n", 6048 "itemtype": "method", 6049 "name": "clear", 6050 "chainable": 1, 6051 "example": ["\n<div>\n<code>\n// Clear the screen on mouse press.\nfunction setup() {\n createCanvas(100, 100);\n}\n\nfunction draw() {\n ellipse(mouseX, mouseY, 20, 20);\n}\n\nfunction mousePressed() {\n clear();\n}\n</code>\n</div>"], 6052 "alt": "20x20 white ellipses are continually drawn at mouse x and y coordinates.", 6053 "class": "p5", 6054 "module": "Color", 6055 "submodule": "Setting" 6056 }, { 6057 "file": "src/color/setting.js", 6058 "line": 223, 6059 "description": "<p><a href=\"#/p5/colorMode\">colorMode()</a> changes the way p5.js interprets color data. By default, the\nparameters for <a href=\"#/p5/fill\">fill()</a>, <a href=\"#/p5/stroke\">stroke()</a>, <a href=\"#/p5/background\">background()</a>, and <a href=\"#/p5/color\">color()</a> are defined by\nvalues between 0 and 255 using the RGB color model. This is equivalent to\nsetting colorMode(RGB, 255). Setting colorMode(HSB) lets you use the HSB\nsystem instead. By default, this is colorMode(HSB, 360, 100, 100, 1). You\ncan also use HSL.\n<br><br>\nNote: existing color objects remember the mode that they were created in,\nso you can change modes as you like without affecting their appearance.</p>\n", 6060 "itemtype": "method", 6061 "name": "colorMode", 6062 "chainable": 1, 6063 "example": ["\n<div>\n<code>\nnoStroke();\ncolorMode(RGB, 100);\nfor (let i = 0; i < 100; i++) {\n for (let j = 0; j < 100; j++) {\n stroke(i, j, 0);\n point(i, j);\n }\n}\n</code>\n</div>\n\n<div>\n<code>\nnoStroke();\ncolorMode(HSB, 100);\nfor (let i = 0; i < 100; i++) {\n for (let j = 0; j < 100; j++) {\n stroke(i, j, 100);\n point(i, j);\n }\n}\n</code>\n</div>\n\n<div>\n<code>\ncolorMode(RGB, 255);\nlet c = color(127, 255, 0);\n\ncolorMode(RGB, 1);\nlet myColor = c._getRed();\ntext(myColor, 10, 10, 80, 80);\n</code>\n</div>\n\n<div>\n<code>\nnoFill();\ncolorMode(RGB, 255, 255, 255, 1);\nbackground(255);\n\nstrokeWeight(4);\nstroke(255, 0, 10, 0.3);\nellipse(40, 40, 50, 50);\nellipse(50, 50, 40, 40);\n</code>\n</div>"], 6064 "alt": "Green to red gradient from bottom L to top R. shading originates from top left.\nRainbow gradient from left to right. Brightness increasing to white at top.\nunknown image.\n50x50 ellipse at middle L & 40x40 ellipse at center. Transluscent pink outlines.", 6065 "class": "p5", 6066 "module": "Color", 6067 "submodule": "Setting", 6068 "overloads": [{ 6069 "line": 223, 6070 "params": [{ 6071 "name": "mode", 6072 "description": "<p>either RGB, HSB or HSL, corresponding to\n Red/Green/Blue and Hue/Saturation/Brightness\n (or Lightness)</p>\n", 6073 "type": "Constant" 6074 }, { 6075 "name": "max", 6076 "description": "<p>range for all values</p>\n", 6077 "type": "Number", 6078 "optional": true 6079 }], 6080 "chainable": 1 6081 }, { 6082 "line": 300, 6083 "params": [{ 6084 "name": "mode", 6085 "description": "", 6086 "type": "Constant" 6087 }, { 6088 "name": "max1", 6089 "description": "<p>range for the red or hue depending on the\n current color mode</p>\n", 6090 "type": "Number" 6091 }, { 6092 "name": "max2", 6093 "description": "<p>range for the green or saturation depending\n on the current color mode</p>\n", 6094 "type": "Number" 6095 }, { 6096 "name": "max3", 6097 "description": "<p>range for the blue or brightness/lighntess\n depending on the current color mode</p>\n", 6098 "type": "Number" 6099 }, { 6100 "name": "maxA", 6101 "description": "<p>range for the alpha</p>\n", 6102 "type": "Number", 6103 "optional": true 6104 }], 6105 "chainable": 1 6106 }] 6107 }, { 6108 "file": "src/color/setting.js", 6109 "line": 344, 6110 "description": "<p>Sets the color used to fill shapes. For example, if you run\nfill(204, 102, 0), all subsequent shapes will be filled with orange. This\ncolor is either specified in terms of the RGB or HSB color depending on\nthe current <a href=\"#/p5/colorMode\">colorMode()</a>. (The default color space is RGB, with each value\nin the range from 0 to 255). The alpha range by default is also 0 to 255.\n<br><br>
6110\nIf a single string argument is provided, RGB, RGBA and Hex CSS color strings\nand all named color strings are supported. In this case, an alpha number\nvalue as a second argument is not supported, the RGBA form should be used.\n<br><br>\nA p5 <a href=\"#/p5.Color\">Color</a> object can also be provided to set the fill color.</p>\n", 6111 "itemtype": "method", 6112 "name": "fill", 6113 "chainable": 1, 6114 "example": ["\n<div>\n<code>\n// Grayscale integer value\nfill(51);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// R, G & B integer values\nfill(255, 204, 0);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// H, S & B integer values\ncolorMode(HSB);\nfill(255, 204, 100);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// Named SVG/CSS color string\nfill('red');\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// three-digit hexadecimal RGB notation\nfill('#fae');\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// six-digit hexadecimal RGB notation\nfill('#222222');\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// integer RGB notation\nfill('rgb(0,255,0)');\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// integer RGBA notation\nfill('rgba(0,255,0, 0.25)');\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// percentage RGB notation\nfill('rgb(100%,0%,10%)');\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// percentage RGBA notation\nfill('rgba(100%,0%,100%,0.5)');\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// p5 Color object\nfill(color(0, 0, 255));\nrect(20, 20, 60, 60);\n</code>\n</div>"], 6115 "alt": "60x60 dark charcoal grey rect with black outline in center of canvas.\n60x60 yellow rect with black outline in center of canvas.\n60x60 royal blue rect with black outline in center of canvas.\n60x60 red rect with black outline in center of canvas.\n60x60 pink rect with black outline in center of canvas.\n60x60 black rect with black outline in center of canvas.\n60x60 light green rect with black outline in center of canvas.\n60x60 soft green rect with black outline in center of canvas.\n60x60 red rect with black outline in center of canvas.\n60x60 dark fushcia rect with black outline in center of canvas.\n60x60 blue rect with black outline in center of canvas.", 6116 "class": "p5", 6117 "module": "Color", 6118 "submodule": "Setting", 6119 "overloads": [{ 6120 "line": 344, 6121 "params": [{ 6122 "name": "v1", 6123 "description": "<p>red or hue value relative to\n the current color range</p>\n", 6124 "type": "Number" 6125 }, { 6126 "name": "v2", 6127 "description": "<p>green or saturation value\n relative to the current color range</p>\n", 6128 "type": "Number" 6129 }, { 6130 "name": "v3", 6131 "description": "<p>blue or brightness value\n relative to the current color range</p>\n", 6132 "type": "Number" 6133 }, { 6134 "name": "alpha", 6135 "description": "", 6136 "type": "Number", 6137 "optional": true 6138 }], 6139 "chainable": 1 6140 }, { 6141 "line": 469, 6142 "params": [{ 6143 "name": "value", 6144 "description": "<p>a color string</p>\n", 6145 "type": "String" 6146 }], 6147 "chainable": 1 6148 }, { 6149 "line": 475, 6150 "params": [{ 6151 "name": "gray", 6152 "description": "<p>a gray value</p>\n", 6153 "type": "Number" 6154 }, { 6155 "name": "alpha", 6156 "description": "", 6157 "type": "Number", 6158 "optional": true 6159 }], 6160 "chainable": 1 6161 }, { 6162 "line": 482, 6163 "params": [{ 6164 "name": "values", 6165 "description": "<p>an array containing the red,green,blue &\n and alpha components of the color</p>\n", 6166 "type": "Number[]" 6167 }], 6168 "chainable": 1 6169 }, { 6170 "line": 489, 6171 "params": [{ 6172 "name": "color", 6173 "description": "<p>the fill color</p>\n", 6174 "type": "p5.Color" 6175 }], 6176 "chainable": 1 6177 }] 6178 }, { 6179 "file": "src/color/setting.js", 6180 "line": 501, 6181 "description": "<p>Disables filling geometry. If both <a href=\"#/p5/noStroke\">noStroke()</a> and <a href=\"#/p5/noFill\">noFill()</a> are called,\nnothing will be drawn to the screen.</p>\n", 6182 "itemtype": "method", 6183 "name": "noFill", 6184 "chainable": 1, 6185 "example": ["\n<div>\n<code>\nrect(15, 10, 55, 55);\nnoFill();\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div modernizr='webgl'>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(0);\n noFill();\n stroke(100, 100, 240);\n rotateX(frameCount * 0.01);\n rotateY(frameCount * 0.01);\n box(45, 45, 45);\n}\n</code>\n</div>"], 6186 "alt": "white rect top middle and noFill rect center. Both 60x60 with black outlines.\nblack canvas with purple cube wireframe spinning", 6187 "class": "p5", 6188 "module": "Color", 6189 "submodule": "Setting" 6190 }, { 6191 "file": "src/color/setting.js", 6192 "line": 542, 6193 "description": "<p>Disables drawing the stroke (outline). If both <a href=\"#/p5/noStroke\">noStroke()</a> and <a href=\"#/p5/noFill\">noFill()</a>
6193\nare called, nothing will be drawn to the screen.</p>\n", 6194 "itemtype": "method", 6195 "name": "noStroke", 6196 "chainable": 1, 6197 "example": ["\n<div>\n<code>\nnoStroke();\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div modernizr='webgl'>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(0);\n noStroke();\n fill(240, 150, 150);\n rotateX(frameCount * 0.01);\n rotateY(frameCount * 0.01);\n box(45, 45, 45);\n}\n</code>\n</div>"], 6198 "alt": "60x60 white rect at center. no outline.\nblack canvas with pink cube spinning", 6199 "class": "p5", 6200 "module": "Color", 6201 "submodule": "Setting" 6202 }, { 6203 "file": "src/color/setting.js", 6204 "line": 582, 6205 "description": "<p>Sets the color used to draw lines and borders around shapes. This color\nis either specified in terms of the RGB or HSB color depending on the\ncurrent <a href=\"#/p5/colorMode\">colorMode()</a> (the default color space is RGB, with each value in\nthe range from 0 to 255). The alpha range by default is also 0 to 255.\n<br><br>\nIf a single string argument is provided, RGB, RGBA and Hex CSS color\nstrings and all named color strings are supported. In this case, an alpha\nnumber value as a second argument is not supported, the RGBA form should be\nused.\n<br><br>\nA p5 <a href=\"#/p5.Color\">Color</a> object can also be provided to set the stroke color.</p>\n", 6206 "itemtype": "method", 6207 "name": "stroke", 6208 "chainable": 1, 6209 "example": ["\n<div>\n<code>\n// Grayscale integer value\nstrokeWeight(4);\nstroke(51);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// R, G & B integer values\nstroke(255, 204, 0);\nstrokeWeight(4);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// H, S & B integer values\ncolorMode(HSB);\nstrokeWeight(4);\nstroke(255, 204, 100);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// Named SVG/CSS color string\nstroke('red');\nstrokeWeight(4);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// three-digit hexadecimal RGB notation\nstroke('#fae');\nstrokeWeight(4);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// six-digit hexadecimal RGB notation\nstroke('#222222');\nstrokeWeight(4);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// integer RGB notation\nstroke('rgb(0,255,0)');\nstrokeWeight(4);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// integer RGBA notation\nstroke('rgba(0,255,0,0.25)');\nstrokeWeight(4);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// percentage RGB notation\nstroke('rgb(100%,0%,10%)');\nstrokeWeight(4);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// percentage RGBA notation\nstroke('rgba(100%,0%,100%,0.5)');\nstrokeWeight(4);\nrect(20, 20, 60, 60);\n</code>\n</div>\n\n<div>\n<code>\n// p5 Color object\nstroke(color(0, 0, 255));\nstrokeWeight(4);\nrect(20, 20, 60, 60);\n</code>\n</div>"], 6210 "alt": "60x60 white rect at center. Dark charcoal grey outline.\n60x60 white rect at center. Yellow outline.\n60x60 white rect at center. Royal blue outline.\n60x60 white rect at center. Red outline.\n60x60 white rect at center. Pink outline.\n60x60 white rect at center. Black outline.\n60x60 white rect at center. Bright green outline.\n60x60 white rect at center. Soft green outline.\n60x60 white rect at center. Red outline.\n60x60 white rect at center. Dark fushcia outline.\n60x60 white rect at center. Blue outline.", 6211 "class": "p5", 6212 "module": "Color", 6213 "submodule": "Setting", 6214 "overloads": [{ 6215 "line": 582, 6216 "params": [{ 6217 "name": "v1", 6218 "description": "<p>red or hue value relative to\n the current color range</p>\n", 6219 "type": "Number" 6220 }, { 6221 "name": "v2", 6222 "description": "<p>green or saturation value\n relative to the current color range</p>\n", 6223 "type": "Number" 6224 }, { 6225 "name": "v3", 6226 "description": "<p>
6226blue or brightness value\n relative to the current color range</p>\n", 6227 "type": "Number" 6228 }, { 6229 "name": "alpha", 6230 "description": "", 6231 "type": "Number", 6232 "optional": true 6233 }], 6234 "chainable": 1 6235 }, { 6236 "line": 721, 6237 "params": [{ 6238 "name": "value", 6239 "description": "<p>a color string</p>\n", 6240 "type": "String" 6241 }], 6242 "chainable": 1 6243 }, { 6244 "line": 727, 6245 "params": [{ 6246 "name": "gray", 6247 "description": "<p>a gray value</p>\n", 6248 "type": "Number" 6249 }, { 6250 "name": "alpha", 6251 "description": "", 6252 "type": "Number", 6253 "optional": true 6254 }], 6255 "chainable": 1 6256 }, { 6257 "line": 734, 6258 "params": [{ 6259 "name": "values", 6260 "description": "<p>an array containing the red,green,blue &\n and alpha components of the color</p>\n", 6261 "type": "Number[]" 6262 }], 6263 "chainable": 1 6264 }, { 6265 "line": 741, 6266 "params": [{ 6267 "name": "color", 6268 "description": "<p>the stroke color</p>\n", 6269 "type": "p5.Color" 6270 }], 6271 "chainable": 1 6272 }] 6273 }, { 6274 "file": "src/core/shape/2d_primitives.js", 6275 "line": 16, 6276 "description": "<p>Draw an arc to the screen. If called with only x, y, w, h, start, and\nstop, the arc will be drawn and filled as an open pie segment. If a mode parameter is provided, the arc\nwill be filled like an open semi-circle (OPEN) , a closed semi-circle (CHORD), or as a closed pie segment (PIE). The\norigin may be changed with the <a href=\"#/p5/ellipseMode\">ellipseMode()</a> function.<br><br>\nNote that drawing a full circle (ex: 0 to TWO_PI) will appear blank\nbecause 0 and TWO_PI are the same position on the unit circle. The\nbest way to handle this is by using the <a href=\"#/p5/ellipse\">ellipse()</a> function instead\nto create a closed ellipse, and to use the <a href=\"#/p5/arc\">arc()</a> function\nonly to draw parts of an ellipse.</p>\n", 6277 "itemtype": "method", 6278 "name": "arc", 6279 "params": [{ 6280 "name": "x", 6281 "description": "<p>x-coordinate of the arc's ellipse</p>\n", 6282 "type": "Number" 6283 }, { 6284 "name": "y", 6285 "description": "<p>y-coordinate of the arc's ellipse</p>\n", 6286 "type": "Number" 6287 }, { 6288 "name": "w", 6289 "description": "<p>width of the arc's ellipse by default</p>\n", 6290 "type": "Number" 6291 }, { 6292 "name": "h", 6293 "description": "<p>height of the arc's ellipse by default</p>\n", 6294 "type": "Number" 6295 }, { 6296 "name": "start", 6297 "description": "<p>angle to start the arc, specified in radians</p>\n", 6298 "type": "Number" 6299 }, { 6300 "name": "stop", 6301 "description": "<p>angle to stop the arc, specified in radians</p>\n", 6302 "type": "Number" 6303 }, { 6304 "name": "mode", 6305 "description": "<p>optional parameter to determine the way of drawing\n the arc. either CHORD, PIE or OPEN</p>\n", 6306 "type": "Constant", 6307 "optional": true 6308 }, { 6309 "name": "detail", 6310 "description": "<p>optional parameter for WebGL mode only. This is to\n specify the number of vertices that makes up the\n perimeter of the arc. Default value is 25.</p>\n", 6311 "type": "Number", 6312 "optional": true 6313 }], 6314 "chainable": 1, 6315 "example": ["\n<div>\n<code>\narc(50, 55, 50, 50, 0, HALF_PI);\nnoFill();\narc(50, 55, 60, 60, HALF_PI, PI);\narc(50, 55, 70, 70, PI, PI + QUARTER_PI);\narc(50, 55, 80, 80, PI + QUARTER_PI, TWO_PI);\n</code>\n</div>\n\n<div>\n<code>\narc(50, 50, 80, 80, 0, PI + QUARTER_PI);\n</code>\n</div>\n\n<div>\n<code>\narc(50, 50, 80, 80, 0, PI + QUARTER_PI, OPEN);\n</code>\n</div>\n\n<div>\n<code>\narc(50, 50, 80, 80, 0, PI + QUARTER_PI, CHORD);\n</code>\n</div>\n\n<div>\n<code>\narc(50, 50, 80, 80, 0, PI + QUARTER_PI, PIE);\n</code>\n</div>"], 6316 "alt": "shattered outline of an ellipse with a quarter of a white circle bottom-right.\nwhite ellipse with top right quarter missing.\nwhite ellipse with black outline with top right missing.\nwhite ellipse with top right missing with black outline around shape.\nwhite ellipse with top right quarter missing with black outline around the shape.", 6317 "class": "p5", 6318 "module": "Shape", 6319 "submodule": "2D Primitives" 6320 }, { 6321 "file": "src/core/shape/2d_primitives.js", 6322 "line": 149, 6323 "description": "<p>Draws an ellipse (oval) to the screen. An ellipse with equal width and\nheight is a circle. By default, the first two parameters set the location,\nand the third and fourth parameters set the shape'
6323s width and height. If\nno height is specified, the value of width is used for both the width and\nheight. If a negative height or width is specified, the absolute value is taken.\nThe origin may be changed with the <a href=\"#/p5/ellipseMode\">ellipseMode()</a> function.</p>\n", 6324 "itemtype": "method", 6325 "name": "ellipse", 6326 "chainable": 1, 6327 "example": ["\n<div>\n<code>\nellipse(56, 46, 55, 55);\n</code>\n</div>"], 6328 "alt": "white ellipse with black outline in middle-right of canvas that is 55x55.", 6329 "class": "p5", 6330 "module": "Shape", 6331 "submodule": "2D Primitives", 6332 "overloads": [{ 6333 "line": 149, 6334 "params": [{ 6335 "name": "x", 6336 "description": "<p>x-coordinate of the ellipse.</p>\n", 6337 "type": "Number" 6338 }, { 6339 "name": "y", 6340 "description": "<p>y-coordinate of the ellipse.</p>\n", 6341 "type": "Number" 6342 }, { 6343 "name": "w", 6344 "description": "<p>width of the ellipse.</p>\n", 6345 "type": "Number" 6346 }, { 6347 "name": "h", 6348 "description": "<p>height of the ellipse.</p>\n", 6349 "type": "Number", 6350 "optional": true 6351 }], 6352 "chainable": 1 6353 }, { 6354 "line": 174, 6355 "params": [{ 6356 "name": "x", 6357 "description": "", 6358 "type": "Number" 6359 }, { 6360 "name": "y", 6361 "description": "", 6362 "type": "Number" 6363 }, { 6364 "name": "w", 6365 "description": "", 6366 "type": "Number" 6367 }, { 6368 "name": "h", 6369 "description": "", 6370 "type": "Number" 6371 }, { 6372 "name": "detail", 6373 "description": "<p>number of radial sectors to draw (for WebGL mode)</p>\n", 6374 "type": "Integer" 6375 }] 6376 }] 6377 }, { 6378 "file": "src/core/shape/2d_primitives.js", 6379 "line": 209, 6380 "description": "<p>Draws a circle to the screen. A circle is a simple closed shape.\nIt is the set of all points in a plane that are at a given distance from a given point, the centre.\nThis function is a special case of the ellipse() function, where the width and height of the ellipse are the same.\nHeight and width of the ellipse is equal to twice the radius of the circle..\nBy default, the first two parameters set the location of the centre of the circle, the third sets the radius of the circle.</p>\n", 6381 "itemtype": "method", 6382 "name": "circle", 6383 "params": [{ 6384 "name": "x", 6385 "description": "<p>x-coordinate of the centre of the circle.</p>\n", 6386 "type": "Number" 6387 }, { 6388 "name": "y", 6389 "description": "<p>y-coordinate of the centre of the circle.</p>\n", 6390 "type": "Number" 6391 }, { 6392 "name": "r", 6393 "description": "<p>radius of the circle.</p>\n", 6394 "type": "Number" 6395 }], 6396 "chainable": 1, 6397 "example": ["\n<div>\n<code>\n// Draw a circle at location (30, 30) with a radius of 20.\ncircle(30, 30, 20);\n</code>\n</div>"], 6398 "alt": "white circle with black outline in mid of canvas that is 55x55.", 6399 "class": "p5", 6400 "module": "Shape", 6401 "submodule": "2D Primitives" 6402 }, { 6403 "file": "src/core/shape/2d_primitives.js", 6404 "line": 239, 6405 "description": "<p>Draws a line (a direct path between two points) to the screen. The version\nof <a href=\"#/p5/line\">line()</a> with four parameters draws the line in 2D. To color a line, use\nthe <a href=\"#/p5/stroke\">stroke()</a> function. A line cannot be filled, therefore the <a href=\"#/p5/fill\">fill()</a>\nfunction will not affect the color of a line. 2D lines are drawn with a\nwidth of one pixel by default, but this can be changed with the\n<a href=\"#/p5/strokeWeight\">
6405strokeWeight()</a> function.</p>\n", 6406 "itemtype": "method", 6407 "name": "line", 6408 "chainable": 1, 6409 "example": ["\n<div>\n<code>\nline(30, 20, 85, 75);\n</code>\n</div>\n\n<div>\n<code>\nline(30, 20, 85, 20);\nstroke(126);\nline(85, 20, 85, 75);\nstroke(255);\nline(85, 75, 30, 75);\n</code>\n</div>"], 6410 "alt": "line 78 pixels long running from mid-top to bottom-right of canvas.\n3 lines of various stroke sizes. Form top, bottom and right sides of a square.", 6411 "class": "p5", 6412 "module": "Shape", 6413 "submodule": "2D Primitives", 6414 "overloads": [{ 6415 "line": 239, 6416 "params": [{ 6417 "name": "x1", 6418 "description": "<p>the x-coordinate of the first point</p>\n", 6419 "type": "Number" 6420 }, { 6421 "name": "y1", 6422 "description": "<p>the y-coordinate of the first point</p>\n", 6423 "type": "Number" 6424 }, { 6425 "name": "x2", 6426 "description": "<p>the x-coordinate of the second point</p>\n", 6427 "type": "Number" 6428 }, { 6429 "name": "y2", 6430 "description": "<p>the y-coordinate of the second point</p>\n", 6431 "type": "Number" 6432 }], 6433 "chainable": 1 6434 }, { 6435 "line": 275, 6436 "params": [{ 6437 "name": "x1", 6438 "description": "", 6439 "type": "Number" 6440 }, { 6441 "name": "y1", 6442 "description": "", 6443 "type": "Number" 6444 }, { 6445 "name": "z1", 6446 "description": "<p>the z-coordinate of the first point</p>\n", 6447 "type": "Number" 6448 }, { 6449 "name": "x2", 6450 "description": "", 6451 "type": "Number" 6452 }, { 6453 "name": "y2", 6454 "description": "", 6455 "type": "Number" 6456 }, { 6457 "name": "z2", 6458 "description": "<p>the z-coordinate of the second point</p>\n", 6459 "type": "Number" 6460 }], 6461 "chainable": 1 6462 }] 6463 }, { 6464 "file": "src/core/shape/2d_primitives.js", 6465 "line": 295, 6466 "description": "<p>Draws a point, a coordinate in space at the dimension of one pixel.\nThe first parameter is the horizontal value for the point, the second\nvalue is the vertical value for the point. The color of the point is\ndetermined by the current stroke.</p>\n", 6467 "itemtype": "method", 6468 "name": "point", 6469 "params": [{ 6470 "name": "x", 6471 "description": "<p>the x-coordinate</p>\n", 6472 "type": "Number" 6473 }, { 6474 "name": "y", 6475 "description": "<p>the y-coordinate</p>\n", 6476 "type": "Number" 6477 }, { 6478 "name": "z", 6479 "description": "<p>the z-coordinate (for WebGL mode)</p>\n", 6480 "type": "Number", 6481 "optional": true 6482 }], 6483 "chainable": 1, 6484 "example": ["\n<div>\n<code>\npoint(30, 20);\npoint(85, 20);\npoint(85, 75);\npoint(30, 75);\n</code>\n</div>"], 6485 "alt": "4 points centered in the middle-right of the canvas.", 6486 "class": "p5", 6487 "module": "Shape", 6488 "submodule": "2D Primitives" 6489 }, { 6490 "file": "src/core/shape/2d_primitives.js", 6491 "line": 330, 6492 "description": "<p>Draw a quad. A quad is a quadrilateral, a four sided polygon. It is\nsimilar to a rectangle, but the angles between its edges are not\nconstrained to ninety degrees. The first pair of parameters (x1,y1)\nsets the first vertex and the subsequent pairs should proceed\nclockwise or counter-clockwise around the defined shape.</p>\n", 6493 "itemtype": "method", 6494 "name": "quad", 6495 "chainable": 1, 6496 "example": ["\n<div>\n<code>\nquad(38, 31, 86, 20, 69, 63, 30, 76);\n</code>\n</div>"], 6497 "alt": "irregular white quadrilateral shape with black outline mid-right of canvas.", 6498 "class": "p5", 6499 "module": "Shape", 6500 "submodule": "2D Primitives", 6501 "overloads": [{ 6502 "line": 330, 6503 "params": [{ 6504 "name": "x1", 6505 "description": "<p>the x-coordinate of the first point</p>\n", 6506 "type": "Number" 6507 }, { 6508 "name": "y1", 6509 "description": "<p>the y-coordinate of the first point</p>\n", 6510 "type": "Number" 6511 }, { 6512 "name": "x2", 6513 "description": "<p>the x-coordinate of the second point</p>\n", 6514 "type": "Number" 6515 }, { 6516 "name": "y2", 6517 "description": "<p>the y-coordinate of the second point</p>\n", 6518 "type": "Number" 6519 }, { 6520 "name": "x3", 6521 "description": "<p>the x-coordinate of the third point</p>\n", 6522 "type": "Number" 6523 }, { 6524 "name": "y3", 6525 "description": "<p>the y-coordinate of the third point</p>\n", 6526 "type": "Number" 6527 }, { 6528 "name": "x4", 6529 "description": "<p>the x-coordinate of the fourth point</p>\n", 6530 "type": "Number" 6531 }, { 6532 "name": "y4", 6533 "description": "<p>the y-coordinate of the fourth point</p>\n", 6534 "type": "Number" 6535 }], 6536 "chainable": 1 6537 }, { 6538 "line": 358, 6539 "params": [{ 6540 "name": "x1", 6541 "description": "", 6542 "type": "Number" 6543 }, { 6544 "name": "y1", 6545 "description": "", 6546 "type": "Number" 6547 }, { 6548 "name": "z1", 6549 "description": "<p>the z-coordinate of the first point</p>\n", 6550 "type": "Number" 6551 }, { 6552 "name": "x2", 6553 "description": "", 6554 "type": "Number" 6555 }, { 6556 "name": "y2", 6557 "description": "", 6558 "type": "Number" 6559 }, { 6560 "name": "z2", 6561 "description": "<p>the z-coordinate of the second point</p>\n", 6562 "type": "Number" 6563 }, { 6564 "name": "x3", 6565 "description": "", 6566 "type": "Number" 6567 }, { 6568 "name": "y3", 6569 "description": "", 6570 "type": "Number" 6571 }, { 6572 "name": "z3", 6573 "description": "<p>the z-coordinate of the third point</p>\n", 6574 "type": "Number" 6575 }, { 6576 "name": "x4", 6577 "description": "", 6578 "type": "Number" 6579 }, { 6580 "name": "y4", 6581 "description": "", 6582 "type": "Number" 6583 }, { 6584 "name": "z4", 6585 "description": "<p>the z-coordinate of the fourth point</p>\n", 6586 "type": "Number" 6587 }], 6588 "chainable": 1 6589 }] 6590 }, { 6591 "file": "src/core/shape/2d_primitives.js", 6592 "line": 384, 6593 "description": "<p>Draws a rectangle to the screen. A rectangle is a four-sided shape with\nevery angle at ninety degrees. By default, the first two parameters set\nthe location of the upper-left corner, the third sets the width, and the\nfourth sets the height. The way these parameters are interpreted, however,\nmay be changed with the <a href=\"#/p5/rectMode\">rectMode()</a> function.\n<br><br>\nThe fifth, sixth, seventh and eighth parameters, if specified,\ndetermine corner radius for the top-left, top-right, lower-right and\nlower-left corners, respectively. An omitted corner radius parameter is set\nto the value of the previously specified radius value in the parameter list.</p>\n", 6594 "itemtype": "method", 6595 "name": "rect", 6596 "chainable": 1, 6597 "example": ["\n<div>\n<code>\n// Draw a rectangle at location (30, 20) with a width and height of 55.\nrect(30, 20, 55, 55);\n</code>\n</div>\n\n<div>\n<code>\n// Draw a rectangle with rounded corners, each having a radius of 20.\nrect(30, 20, 55, 55, 20);\n</code>\n</div>\n\n<div>\n<code>\n// Draw a rectangle with rounded corners having the following radii:\n// top-left = 20, top-right = 15, bottom-right = 10, bottom-left = 5.\nrect(30, 20, 55, 55, 20, 15, 10, 5);\n</code>\n</div>"], 6598 "alt": "55x55 white rect with black outline in mid-right of canvas.\n55x55 white rect with black outline and rounded edges in mid-right of canvas.\n55x55 white rect with black outline and rounded edges of different radii.", 6599 "class": "p5", 6600 "module": "Shape", 6601 "submodule": "2D Primitives", 6602 "overloads": [{ 6603 "line": 384, 6604 "params": [{ 6605 "name": "x", 6606 "description": "<p>x-coordinate of the rectangle.</p>\n", 6607 "type": "Number" 6608 }, { 6609 "name": "y", 6610 "description": "<p>y-coordinate of the rectangle.</p>\n", 6611 "type": "Number" 6612 }, { 6613 "name": "w", 6614 "description": "<p>width of the rectangle.</p>\n", 6615 "type": "Number" 6616 }, { 6617 "name": "h", 6618 "description": "<p>height of the rectangle.</p>\n", 6619 "type": "Number" 6620 }, { 6621 "name": "tl", 6622 "description": "<p>optional radius of top-left corner.</p>\n", 6623 "type": "Number", 6624 "optional": true 6625 }, { 6626 "name": "tr", 6627 "description": "<p>optional radius of top-right corner.</p>\n", 6628 "type": "Number", 6629 "optional": true 6630 }, { 6631 "name": "br", 6632 "description": "<p>optional radius of bottom-right corner.</p>\n", 6633 "type": "Number", 6634 "optional": true 6635 }, { 6636 "name": "bl", 6637 "description": "<p>optional radius of bottom-left corner.</p>\n", 6638 "type": "Number", 6639 "optional": true 6640 }], 6641 "chainable": 1 6642 }, { 6643 "line": 434, 6644 "params": [{ 6645 "name": "x", 6646 "description": "", 6647 "type": "Number" 6648 }, { 6649 "name": "y", 6650 "description": "", 6651 "type": "Number" 6652 }, { 6653 "name": "w", 6654 "description": "", 6655 "type": "Number" 6656 }, { 6657 "name": "h", 6658 "description": "", 6659 "type": "Number" 6660 }, { 6661 "name": "detailX", 6662 "description": "<p>number of segments in the x-direction (for WebGL mode)</p>\n", 6663 "type": "Integer", 6664 "optional": true 6665 }, { 6666 "name": "detailY", 6667 "description": "<p>number of segments in the y-direction (for WebGL mode)</p>\n", 6668 "type": "Integer", 6669 "optional": true 6670 }], 6671 "chainable": 1 6672 }] 6673 }, { 6674 "file": "src/core/shape/2d_primitives.js", 6675 "line": 467, 6676 "description": "<p>Draws a square to the screen. A square is a four-sided shape with\nevery angle at ninety degrees, and equal side size.\nThis function is a special case of the rect() function, where the width and height are the same, and the parameter is called "s" for side size.\nBy default, the first two parameters set the location of the upper-left corner, the third sets the side size of the square.\nThe way these parameters are interpreted, however,\nmay be changed with the <a href=\"#/p5/rectMode\">rectMode()</a> function.\n<br><br>\nThe fourth, fifth, sixth and seventh parameters, if specified,\ndetermine corner radius for the top-left, top-right, lower-right and\nlower-left corners, respectively. An omitted corner radius parameter is set\nto the value of the previously specified radius value in the parameter list.</p>\n", 6677 "itemtype": "method", 6678 "name": "square", 6679 "params": [{ 6680 "name": "x", 6681 "description": "<p>x-coordinate of the square.</p>\n", 6682 "type": "Number" 6683 }, { 6684 "name": "y", 6685 "description": "<p>y-coordinate of the square.</p>\n", 6686 "type": "Number" 6687 }, { 6688 "name": "s", 6689 "description": "<p>side size of the square.</p>\n", 6690 "type": "Number" 6691 }, { 6692 "name": "tl", 6693 "description": "<p>optional radius of top-left corner.</p>\n", 6694 "type": "Number", 6695 "optional": true 6696 }, { 6697 "name": "tr", 6698 "description": "<p>optional radius of top-right corner.</p>\n", 6699 "type": "Number", 6700 "optional": true 6701 }, { 6702 "name": "br", 6703 "description": "<p>optional radius of bottom-right corner.</p>\n", 6704 "type": "Number", 6705 "optional": true 6706 }, { 6707 "name": "bl", 6708 "description": "<p>optional radius of bottom-left corner.</p>\n", 6709 "type": "Number", 6710 "optional": true 6711 }], 6712 "chainable": 1, 6713 "example": ["\n<div>\n<code>\n// Draw a square at location (30, 20) with a side size of 55.\nsquare(30, 20, 55);\n</code>\n</div>\n\n<div>\n<code>\n// Draw a square with rounded corners, each having a radius of 20.\nsquare(30, 20, 55, 20);\n</code>\n</div>\n\n<div>\n<code>\n// Draw a square with rounded corners having the following radii:\n// top-left = 20, top-right = 15, bottom-right = 10, bottom-left = 5.\nsquare(30, 20, 55, 20, 15, 10, 5);\n</code>\n</div>"], 6714 "alt": "55x55 white square with black outline in mid-right of canvas.\n55x55 white square with black outline and rounded edges in mid-right of canvas.\n55x55 white square with black outline and rounded edges of different radii.", 6715 "class": "p5", 6716 "module": "Shape", 6717 "submodule": "2D Primitives" 6718 }, { 6719 "file": "src/core/shape/2d_primitives.js", 6720 "line": 524, 6721 "description": "<p>A triangle is a plane created by connecting three points. The first two\narguments specify the first point, the middle two arguments specify the\nsecond point, and the last two arguments specify the third point.</p>\n", 6722 "itemtype": "method", 6723 "name": "triangle", 6724 "params": [{ 6725 "name": "x1", 6726 "description": "<p>x-coordinate of the first point</p>\n", 6727 "type": "Number" 6728 }, { 6729 "name": "y1", 6730 "description": "<p>y-coordinate of the first point</p>\n", 6731 "type": "Number" 6732 }, { 6733 "name": "x2", 6734 "description": "<p>x-coordinate of the second point</p>\n", 6735 "type": "Number" 6736 }, { 6737 "name": "y2", 6738 "description": "<p>y-coordinate of the second point</p>\n", 6739 "type": "Number" 6740 }, { 6741 "name": "x3", 6742 "description": "<p>x-coordinate of the third point</p>\n", 6743 "type": "Number" 6744 }, { 6745 "name": "y3", 6746 "description": "<p>y-coordinate of the third point</p>\n", 6747 "type": "Number" 6748 }], 6749 "chainable": 1, 6750 "example": ["\n<div>\n<code>\ntriangle(30, 75, 58, 20, 86, 75);\n</code>\n</div>"], 6751 "alt": "white triangle with black outline in mid-right of canvas.", 6752 "class": "p5", 6753 "module": "Shape", 6754 "submodule": "2D Primitives" 6755 }, { 6756 "file": "src/core/shape/attributes.js", 6757 "line": 14, 6758 "description": "<p>Modifies the location from which ellipses are drawn by changing the way\nin which parameters given to <a href=\"#/p5/ellipse\">ellipse()</a> are interpreted.\n<br><br>\nThe default mode is ellipseMode(CENTER), which interprets the first two\nparameters of <a href=\"#/p5/ellipse\">ellipse()</a> as the shape's center point, while the third and\nfourth parameters are its width and height.\n<br><br>\nellipseMode(RADIUS) also uses the first two parameters of <a href=\"#/p5/ellipse\">ellipse()</a> as\nthe shape's center point, but uses the
6758 third and fourth parameters to\nspecify half of the shapes's width and height.\n<br><br>\nellipseMode(CORNER) interprets the first two parameters of <a href=\"#/p5/ellipse\">ellipse()</a> as\nthe upper-left corner of the shape, while the third and fourth parameters\nare its width and height.\n<br><br>\nellipseMode(CORNERS) interprets the first two parameters of <a href=\"#/p5/ellipse\">ellipse()</a> as\nthe location of one corner of the ellipse's bounding box, and the third\nand fourth parameters as the location of the opposite corner.\n<br><br>\nThe parameter must be written in ALL CAPS because Javascript is a\ncase-sensitive language.</p>\n", 6759 "itemtype": "method", 6760 "name": "ellipseMode", 6761 "params": [{ 6762 "name": "mode", 6763 "description": "<p>either CENTER, RADIUS, CORNER, or CORNERS</p>\n", 6764 "type": "Constant" 6765 }], 6766 "chainable": 1, 6767 "example": ["\n<div>\n<code>\nellipseMode(RADIUS); // Set ellipseMode to RADIUS\nfill(255); // Set fill to white\nellipse(50, 50, 30, 30); // Draw white ellipse using RADIUS mode\n\nellipseMode(CENTER); // Set ellipseMode to CENTER\nfill(100); // Set fill to gray\nellipse(50, 50, 30, 30); // Draw gray ellipse using CENTER mode\n</code>\n</div>\n\n<div>\n<code>\nellipseMode(CORNER); // Set ellipseMode is CORNER\nfill(255); // Set fill to white\nellipse(25, 25, 50, 50); // Draw white ellipse using CORNER mode\n\nellipseMode(CORNERS); // Set ellipseMode to CORNERS\nfill(100); // Set fill to gray\nellipse(25, 25, 50, 50); // Draw gray ellipse using CORNERS mode\n</code>\n</div>"], 6768 "alt": "60x60 white ellipse and 30x30 grey ellipse with black outlines at center.\n60x60 white ellipse @center and 30x30 grey ellipse top-right, black outlines.", 6769 "class": "p5", 6770 "module": "Shape", 6771 "submodule": "Attributes"
6772 }, { 6773 "file": "src/core/shape/attributes.js", 6774 "line": 83, 6775 "description": "<p>Draws all geometry with jagged (aliased) edges. Note that <a href=\"#/p5/smooth\">smooth()</a> is\nactive by default in 2D mode, so it is necessary to call <a href=\"#/p5/noSmooth\">noSmooth()</a> to disable\nsmoothing of geometry, images, and fonts. In 3D mode, <a href=\"#/p5/noSmooth\">noSmooth()</a> is enabled\nby default, so it is necessary to call <a href=\"#/p5/smooth\">smooth()</a> if you would like\nsmooth (antialiased) edges on your geometry.</p>\n", 6776 "itemtype": "method", 6777 "name": "noSmooth", 6778 "chainable": 1, 6779 "example": ["\n<div>\n<code>\nbackground(0);\nnoStroke();\nsmooth();\nellipse(30, 48, 36, 36);\nnoSmooth();\nellipse(70, 48, 36, 36);\n</code>\n</div>"], 6780 "alt": "2 pixelated 36x36 white ellipses to left & right of center, black background", 6781 "class": "p5", 6782 "module": "Shape", 6783 "submodule": "Attributes" 6784 }, { 6785 "file": "src/core/shape/attributes.js", 6786 "line": 113, 6787 "description": "<p>Modifies the location from which rectangles are drawn by changing the way\nin which parameters given to <a href=\"#/p5/rect\">rect()</a> are interpreted.\n<br><br>\nThe default mode is rectMode(CORNER), which interprets the first two\nparameters of <a href=\"#/p5/rect\">rect()</a> as the upper-left corner of the shape, while the\nthird and fourth parameters are its width and height.\n<br><br>\nrectMode(CORNERS) interprets the first two parameters of <a href=\"#/p5/rect\">rect()</a> as the\nlocation of one corner, and the third and fourth parameters as the\nlocation of the opposite corner.\n<br><br>\nrectMode(CENTER) interprets the first two parameters of <a href=\"#/p5/rect\">rect()</a> as the\nshape's center point, while the third and fourth parameters are its\nwidth and height.\n<br><br>\nrectMode(RADIUS) also uses the first two parameters of <a href=\"#/p5/rect\">rect()</a> as the\nshape's center point, but uses the third and fourth parameters to specify\nhalf of the shapes's width and height.\n<br><br>\nThe parameter must be written in ALL CAPS because Javascript is a\ncase-sensitive language.</p>\n", 6788 "itemtype": "method", 6789 "name": "rectMode", 6790 "params": [{ 6791 "name": "mode", 6792 "description": "<p>either CORNER, CORNERS, CENTER, or RADIUS</p>\n", 6793 "type": "Constant" 6794 }], 6795 "chainable": 1, 6796 "example": ["\n<div>\n<code>\nrectMode(CORNER); // Default rectMode is CORNER\nfill(255); // Set fill to white\nrect(25, 25, 50, 50); // Draw white rect using CORNER mode\n\nrectMode(CORNERS); // Set rectMode to CORNERS\nfill(100); // Set fill to gray\nrect(25, 25, 50, 50); // Draw gray rect using CORNERS mode\n</code>\n</div>\n\n<div>\n<code>\nrectMode(RADIUS); // Set rectMode to RADIUS\nfill(255); // Set fill to white\nrect(50, 50, 30, 30); // Draw white rect using RADIUS mode\n\nrectMode(CENTER); // Set rectMode to CENTER\nfill(100); // Set fill to gray\nrect(50, 50, 30, 30); // Draw gray rect using CENTER mode\n</code>\n</div>"], 6797 "alt": "50x50 white rect at center and 25x25 grey rect in the top left of the other.\n50x50 white rect at center and 25x25 grey rect in the center of the other.", 6798 "class": "p5", 6799 "module": "Shape", 6800 "submodule": "Attributes"
6801 }, { 6802 "file": "src/core/shape/attributes.js", 6803 "line": 182, 6804 "description": "<p>Draws all geometry with smooth (anti-aliased) edges. <a href=\"#/p5/smooth\">smooth()</a> will also\nimprove image quality of resized images. Note that <a href=\"#/p5/smooth\">smooth()</a> is active by\ndefault in 2D mode; <a href=\"#/p5/noSmooth\">noSmooth()</a> can be used to disable smoothing of geometry,\nimages, and fonts. In 3D mode, <a href=\"#/p5/noSmooth\">noSmooth()</a> is enabled\nby default, so it is necessary to call <a href=\"#/p5/smooth\">smooth()</a> if you would like\nsmooth (antialiased) edges on your geometry.</p>\n", 6805 "itemtype": "method", 6806 "name": "smooth", 6807 "chainable": 1, 6808 "example": ["\n<div>\n<code>\nbackground(0);\nnoStroke();\nsmooth();\nellipse(30, 48, 36, 36);\nnoSmooth();\nellipse(70, 48, 36, 36);\n</code>\n</div>"], 6809 "alt": "2 pixelated 36x36 white ellipses one left one right of center. On black.", 6810 "class": "p5", 6811 "module": "Shape", 6812 "submodule": "Attributes"
6813 }, { 6814 "file": "src/core/shape/attributes.js", 6815 "line": 213, 6816 "description": "<p>Sets the style for rendering line endings. These ends are either squared,\nextended, or rounded, each of which specified with the corresponding\nparameters: SQUARE, PROJECT, and ROUND. The default cap is ROUND.</p>\n", 6817 "itemtype": "method", 6818 "name": "strokeCap", 6819 "params": [{ 6820 "name": "cap", 6821 "description": "<p>either SQUARE, PROJECT, or ROUND</p>\n", 6822 "type": "Constant" 6823 }], 6824 "chainable": 1, 6825 "example": ["\n<div>\n<code>\nstrokeWeight(12.0);\nstrokeCap(ROUND);\nline(20, 30, 80, 30);\nstrokeCap(SQUARE);\nline(20, 50, 80, 50);\nstrokeCap(PROJECT);\nline(20, 70, 80, 70);\n</code>\n</div>"], 6826 "alt": "3 lines. Top line: rounded ends, mid: squared, bottom:longer squared ends.", 6827 "class": "p5", 6828 "module": "Shape", 6829 "submodule": "Attributes" 6830 }, { 6831 "file": "src/core/shape/attributes.js", 6832 "line": 250, 6833 "description": "<p>Sets the style of the joints which connect line segments. These joints\nare either mitered, beveled, or rounded and specified with the\ncorresponding parameters MITER, BEVEL, and ROUND. The default joint is\nMITER.</p>\n", 6834 "itemtype": "method", 6835 "name": "strokeJoin", 6836 "params": [{ 6837 "name": "join", 6838 "description": "<p>either MITER, BEVEL, ROUND</p>\n", 6839 "type": "Constant" 6840 }], 6841 "chainable": 1, 6842 "example": ["\n<div>\n<code>\nnoFill();\nstrokeWeight(10.0);\nstrokeJoin(MITER);\nbeginShape();\nvertex(35, 20);\nvertex(65, 50);\nvertex(35, 80);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nnoFill();\nstrokeWeight(10.0);\nstrokeJoin(BEVEL);\nbeginShape();\nvertex(35, 20);\nvertex(65, 50);\nvertex(35, 80);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nnoFill();\nstrokeWeight(10.0);\nstrokeJoin(ROUND);\nbeginShape();\nvertex(35, 20);\nvertex(65, 50);\nvertex(35, 80);\nendShape();\n</code>\n</div>"], 6843 "alt": "Right-facing arrowhead shape with pointed tip in center of canvas.\nRight-facing arrowhead shape with flat tip in center of canvas.\nRight-facing arrowhead shape with rounded tip in center of canvas.", 6844 "class": "p5", 6845 "module": "Shape", 6846 "submodule": "Attributes"
6847 }, { 6848 "file": "src/core/shape/attributes.js", 6849 "line": 317, 6850 "description": "<p>Sets the width of the stroke used for lines, points, and the border\naround shapes. All widths are set in units of pixels.</p>\n", 6851 "itemtype": "method", 6852 "name": "strokeWeight", 6853 "params": [{ 6854 "name": "weight", 6855 "description": "<p>the weight (in pixels) of the stroke</p>\n", 6856 "type": "Number" 6857 }], 6858 "chainable": 1, 6859 "example": ["\n<div>\n<code>\nstrokeWeight(1); // Default\nline(20, 20, 80, 20);\nstrokeWeight(4); // Thicker\nline(20, 40, 80, 40);\nstrokeWeight(10); // Beastly\nline(20, 70, 80, 70);\n</code>\n</div>"], 6860 "alt": "3 horizontal black lines. Top line: thin, mid: medium, bottom:thick.", 6861 "class": "p5", 6862 "module": "Shape", 6863 "submodule": "Attributes" 6864 }, { 6865 "file": "src/core/shape/curves.js", 6866 "line": 13, 6867 "description": "<p>Draws a cubic Bezier curve on the screen. These curves are defined by a\nseries of anchor and control points. The first two parameters specify\nthe first anchor point and the last two parameters specify the other\nanchor point, which become the first and last points on the curve. The\nmiddle parameters specify the two control points which define the shape\nof the curve. Approximately speaking, control points "pull" the curve\ntowards them.<br /><br />Bezier curves were developed by French\nautomotive engineer Pierre Bezier, and are commonly used in computer\ngraphics to define gently sloping curves. See also <a href=\"#/p5/curve\">curve()</a>.</p>\n", 6868 "itemtype": "method", 6869 "name": "bezier", 6870 "chainable": 1, 6871 "example": ["\n<div>\n<code>\nnoFill();\nstroke(255, 102, 0);\nline(85, 20, 10, 10);\nline(90, 90, 15, 80);\nstroke(0, 0, 0);\nbezier(85, 20, 10, 10, 90, 90, 15, 80);\n</code>\n</div>\n\n<div>\n<code>\nbackground(0, 0, 0);\nnoFill();\nstroke(255);\nbezier(250, 250, 0, 100, 100, 0, 100, 0, 0, 0, 100, 0);\n</code>\n</div>"], 6872 "alt": "stretched black s-shape in center with orange lines extending from end points.\nstretched black s-shape with 10 5x5 white ellipses along the shape.\nstretched black s-shape with 7 5x5 ellipses and orange lines along the shape.\nstretched black s-shape with 17 small orange lines extending from under shape.\nhorseshoe shape with orange ends facing left and black curved center.\nhorseshoe shape with orange ends facing left and black curved center.\nLine shaped like right-facing arrow,points move with mouse-x and warp shape.\nhorizontal line that hooks downward on the right and 13 5x5 ellipses along it.\nright curving line mid-right of canvas with 7 short lines radiating from it.", 6873 "class": "p5", 6874 "module": "Shape", 6875 "submodule": "Curves", 6876 "overloads": [{ 6877 "line": 13, 6878 "params": [{ 6879 "name": "x1", 6880 "description": "<p>x-coordinate for the first anchor point</p>\n", 6881 "type": "Number" 6882 }, { 6883 "name": "y1", 6884 "description": "<p>y-coordinate for the first anchor point</p>\n", 6885 "type": "Number" 6886 }, { 6887 "name": "x2", 6888 "description": "<p>x-coordinate for the first control point</p>\n", 6889 "type": "Number" 6890 }, { 6891 "name": "y2", 6892 "description": "<p>y-coordinate for the first control point</p>\n", 6893 "type": "Number" 6894 }, { 6895 "name": "x3", 6896 "description": "<p>x-coordinate for the second control point</p>\n", 6897 "type": "Number" 6898 }, { 6899 "name": "y3", 6900 "description": "<p>y-coordinate for the second control point</p>\n", 6901 "type": "Number" 6902 }, { 6903 "name": "x4", 6904 "description": "<p>x-coordinate for the second anchor point</p>\n", 6905 "type": "Number" 6906 }, { 6907 "name": "y4", 6908 "description": "<p>y-coordinate for the second anchor point</p>\n", 6909 "type": "Number" 6910 }], 6911 "chainable": 1 6912 }, { 6913 "line": 66, 6914 "params": [{ 6915 "name": "x1", 6916 "description": "", 6917 "type": "Number" 6918 }, { 6919 "name": "y1", 6920 "description": "", 6921 "type": "Number" 6922 }, { 6923 "name": "z1", 6924 "description": "<p>z-coordinate for the first anchor point</p>\n", 6925 "type": "Number" 6926 }, { 6927 "name": "x2", 6928 "description": "", 6929 "type": "Number" 6930 }, { 6931 "name": "y2", 6932 "description": "", 6933 "type": "Number" 6934 }, { 6935 "name": "z2", 6936 "description": "<p>z-coordinate for the first control point</p>\n", 6937 "type": "Number" 6938 }, { 6939 "name": "x3", 6940 "description": "", 6941 "type": "Number" 6942 }, { 6943 "name": "y3", 6944 "description": "", 6945 "type": "Number" 6946 }, { 6947 "name": "z3", 6948 "description": "<p>z-coordinate for the second control point</p>\n", 6949 "type": "Number" 6950 }, { 6951 "name": "x4", 6952 "description": "", 6953 "type": "Number" 6954 }, { 6955 "name": "y4", 6956 "description": "", 6957 "type": "Number" 6958 }, { 6959 "name": "z4", 6960 "description": "<p>z-coordinate for the second anchor point</p>\n", 6961 "type": "Number" 6962 }], 6963 "chainable": 1 6964 }] 6965 }, { 6966 "file": "src/core/shape/curves.js", 6967 "line": 96, 6968 "description": "<p>Sets the resolution at which Beziers display.</p>\n<p>The default value is 20.</p>\n<p>This function is only useful when using the WEBGL renderer\nas the default canvas renderer does not use this information.</p>\n", 6969 "itemtype": "method", 6970 "name": "bezierDetail", 6971 "params": [{ 6972 "name": "detail", 6973 "description": "<p>resolution of the curves</p>\n", 6974 "type": "Number" 6975 }], 6976 "chainable": 1, 6977 "example": ["\n<div modernizr='webgl'>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n noFill();\n\n bezierDetail(5);\n}\n\nfunction draw() {\n background(200);\n\n // prettier-ignore\n bezier(-40, -40, 0,\n 90, -40, 0,\n -90, 40, 0,\n 40, 40, 0);\n}\n</code>\n</div>"], 6978 "alt": "stretched black s-shape with a low level of bezier detail", 6979 "class": "p5", 6980 "module": "Shape", 6981 "submodule": "Curves" 6982 }, { 6983 "file": "src/core/shape/curves.js", 6984 "line": 139, 6985 "description": "<p>Evaluates the Bezier at position t for points a, b, c, d.\nThe parameters a and d are the first and last points\non the curve, and b and c are the control points.\
6985nThe final parameter t varies between 0 and 1.\nThis can be done once with the x coordinates and a second time\nwith the y coordinates to get the location of a bezier curve at t.</p>\n", 6986 "itemtype": "method", 6987 "name": "bezierPoint", 6988 "params": [{ 6989 "name": "a", 6990 "description": "<p>coordinate of first point on the curve</p>\n", 6991 "type": "Number" 6992 }, { 6993 "name": "b", 6994 "description": "<p>coordinate of first control point</p>\n", 6995 "type": "Number" 6996 }, { 6997 "name": "c", 6998 "description": "<p>coordinate of second control point</p>\n", 6999 "type": "Number" 7000 }, { 7001 "name": "d", 7002 "description": "<p>coordinate of second point on the curve</p>\n", 7003 "type": "Number" 7004 }, { 7005 "name": "t", 7006 "description": "<p>value between 0 and 1</p>\n", 7007 "type": "Number" 7008 }], 7009 "return": { 7010 "description": "the value of the Bezier at position t", 7011 "type": "Number" 7012 }, 7013 "example": ["\n<div>\n<code>\nnoFill();\nlet x1 = 85,\n x2 = 10,\n x3 = 90,\n x4 = 15;\nlet y1 = 20,\n y2 = 10,\n y3 = 90,\n y4 = 80;\nbezier(x1, y1, x2, y2, x3, y3, x4, y4);\nfill(255);\nlet steps = 10;\nfor (let i = 0; i <= steps; i++) {\n let t = i / steps;\n let x = bezierPoint(x1, x2, x3, x4, t);\n let y = bezierPoint(y1, y2, y3, y4, t);\n ellipse(x, y, 5, 5);\n}\n</code>\n</div>"], 7014 "alt": "stretched black s-shape with 17 small orange lines extending from under shape.", 7015 "class": "p5", 7016 "module": "Shape", 7017 "submodule": "Curves" 7018 }, { 7019 "file": "src/core/shape/curves.js", 7020 "line": 194, 7021 "description": "<p>Evaluates the tangent to the Bezier at position t for points a, b, c, d.\nThe parameters a and d are the first and last points\non the curve, and b and c are the control points.\nThe final parameter t varies between 0 and 1.</p>\n", 7022 "itemtype": "method", 7023 "name": "bezierTangent", 7024 "params": [{ 7025 "name": "a", 7026 "description": "<p>coordinate of first point on the curve</p>\n", 7027 "type": "Number" 7028 }, { 7029 "name": "b", 7030 "description": "<p>coordinate of first control point</p>\n", 7031 "type": "Number" 7032 }, { 7033 "name": "c", 7034 "description": "<p>coordinate of second control point</p>\n", 7035 "type": "Number" 7036 }, { 7037 "name": "d", 7038 "description": "<p>coordinate of second point on the curve</p>\n", 7039 "type": "Number" 7040 }, { 7041 "name": "t", 7042 "description": "<p>value between 0 and 1</p>\n", 7043 "type": "Number" 7044 }], 7045 "return": { 7046 "description": "the tangent at position t", 7047 "type": "Number" 7048 }, 7049 "example": ["\n<div>\n<code>\nnoFill();\nbezier(85, 20, 10, 10, 90, 90, 15, 80);\nlet steps = 6;\nfill(255);\nfor (let i = 0; i <= steps; i++) {\n let t = i / steps;\n // Get the location of the point\n let x = bezierPoint(85, 10, 90, 15, t);\n let y = bezierPoint(20, 10, 90, 80, t);\n // Get the tangent points\n let tx = bezierTangent(85, 10, 90, 15, t);\n let ty = bezierTangent(20, 10, 90, 80, t);\n // Calculate an angle from the tangent points\n let a = atan2(ty, tx);\n a += PI;\n stroke(255, 102, 0);\n line(x, y, cos(a) * 30 + x, sin(a) * 30 + y);\n // The following line of code makes a line\n // inverse of the above line\n //line(x, y, cos(a)*-30 + x, sin(a)*-30 + y);\n stroke(0);\n ellipse(x, y, 5, 5);\n}\n</code>\n</div>\n\n<div>\n<code>\nnoFill();\nbezier(85, 20, 10, 10, 90, 90, 15, 80);\nstroke(255, 102, 0);\nlet steps = 16;\nfor (let i = 0; i <= steps; i++) {\n let t = i / steps;\n let x = bezierPoint(85, 10, 90, 15, t);\n let y = bezierPoint(20, 10, 90, 80, t);\n let tx = bezierTangent(85, 10, 90, 15, t);\n let ty = bezierTangent(20, 10, 90, 80, t);\n let a = atan2(ty, tx);\n a -= HALF_PI;\n line(x, y, cos(a) * 8 + x, sin(a) * 8 + y);\n}\n</code>\n</div>"], 7050 "alt": "s-shaped line with 17 short orange lines extending from underside of shape", 7051 "class": "p5", 7052 "module": "Shape", 7053 "submodule": "Curves" 7054 }, { 7055 "file": "src/core/shape/curves.js", 7056 "line": 273, 7057 "description": "<p>Draws a curved line on the screen between two points, given as the\nmiddle four parameters. The first two parameters are a control point, as\nif the curve came from this point even though it'
7057s not drawn. The last\ntwo parameters similarly describe the other control point. <br /><br />\nLonger curves can be created by putting a series of <a href=\"#/p5/curve\">curve()</a> functions\ntogether or using <a href=\"#/p5/curveVertex\">curveVertex()</a>. An additional function called\n<a href=\"#/p5/curveTightness\">curveTightness()</a> provides control for the visual quality of the curve.\nThe <a href=\"#/p5/curve\">curve()</a> function is an implementation of Catmull-Rom splines.</p>\n", 7058 "itemtype": "method", 7059 "name": "curve", 7060 "chainable": 1, 7061 "example": ["\n<div>\n<code>\nnoFill();\nstroke(255, 102, 0);\ncurve(5, 26, 5, 26, 73, 24, 73, 61);\nstroke(0);\ncurve(5, 26, 73, 24, 73, 61, 15, 65);\nstroke(255, 102, 0);\ncurve(73, 24, 73, 61, 15, 65, 15, 65);\n</code>\n</div>\n<div>\n<code>\n// Define the curve points as JavaScript objects\nlet p1 = { x: 5, y: 26 },\n p2 = { x: 73, y: 24 };\nlet p3 = { x: 73, y: 61 },\n p4 = { x: 15, y: 65 };\nnoFill();\nstroke(255, 102, 0);\ncurve(p1.x, p1.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);\nstroke(0);\ncurve(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);\nstroke(255, 102, 0);\ncurve(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, p4.x, p4.y);\n</code>\n</div>\n<div>\n<code>\nnoFill();\nstroke(255, 102, 0);\ncurve(5, 26, 0, 5, 26, 0, 73, 24, 0, 73, 61, 0);\nstroke(0);\ncurve(5, 26, 0, 73, 24, 0, 73, 61, 0, 15, 65, 0);\nstroke(255, 102, 0);\ncurve(73, 24, 0, 73, 61, 0, 15, 65, 0, 15, 65, 0);\n</code>\n</div>"], 7062 "alt": "horseshoe shape with orange ends facing left and black curved center.\nhorseshoe shape with orange ends facing left and black curved center.\ncurving black and orange lines.", 7063 "class": "p5", 7064 "module": "Shape", 7065 "submodule": "Curves", 7066 "overloads": [{ 7067 "line": 273, 7068 "params": [{ 7069 "name": "x1", 7070 "description": "<p>x-coordinate for the beginning control point</p>\n", 7071 "type": "Number" 7072 }, { 7073 "name": "y1", 7074 "description": "<p>y-coordinate for the beginning control point</p>\n", 7075 "type": "Number" 7076 }, { 7077 "name": "x2", 7078 "description": "<p>x-coordinate for the first point</p>\n", 7079 "type": "Number" 7080 }, { 7081 "name": "y2", 7082 "description": "<p>y-coordinate for the first point</p>\n", 7083 "type": "Number" 7084 }, { 7085 "name": "x3", 7086 "description": "<p>x-coordinate for the second point</p>\n", 7087 "type": "Number" 7088 }, { 7089 "name": "y3", 7090 "description": "<p>y-coordinate for the second point</p>\n", 7091 "type": "Number" 7092 }, { 7093 "name": "x4", 7094 "description": "<p>x-coordinate for the ending control point</p>\n", 7095 "type": "Number" 7096 }, { 7097 "name": "y4", 7098 "description": "<p>y-coordinate for the ending control point</p>\n", 7099 "type": "Number" 7100 }], 7101 "chainable": 1 7102 }, { 7103 "line": 338, 7104 "params": [{ 7105 "name": "x1", 7106 "description": "", 7107 "type": "Number" 7108 }, { 7109 "name": "y1", 7110 "description": "", 7111 "type": "Number" 7112 }, { 7113 "name": "z1", 7114 "description": "<p>z-coordinate for the beginning control point</p>\n", 7115 "type": "Number" 7116 }, { 7117 "name": "x2", 7118 "description": "", 7119 "type": "Number" 7120 }, { 7121 "name": "y2", 7122 "description": "", 7123 "type": "Number" 7124 }, { 7125 "name": "z2", 7126 "description": "<p>z-coordinate for the first point</p>\n", 7127 "type": "Number" 7128 }, { 7129 "name": "x3", 7130 "description": "", 7131 "type": "Number" 7132 }, { 7133 "name": "y3", 7134 "description": "", 7135 "type": "Number" 7136 }, { 7137 "name": "z3", 7138 "description": "<p>z-coordinate for the second point</p>\n", 7139 "type": "Number" 7140 }, { 7141 "name": "x4", 7142 "description": "", 7143 "type": "Number" 7144 }, { 7145 "name": "y4", 7146 "description": "", 7147 "type": "Number" 7148 }, { 7149 "name": "z4", 7150 "description": "<p>z-coordinate for the ending control point</p>\n", 7151 "type": "Number" 7152 }], 7153 "chainable": 1 7154 }] 7155 }, { 7156 "file": "src/core/shape/curves.js", 7157 "line": 364, 7158 "description": "<p>Sets the resolution at which curves display.</p>\n<p>The default value is 20 while the minimum value is 3.</p>\n<p>This function is only useful when using the WEBGL renderer\nas the default canvas renderer does not use this\ninformation.</p>\n", 7159 "itemtype": "method", 7160 "name": "curveDetail", 7161 "params": [{ 7162 "name": "resolution", 7163 "description": "<p>resolution of the curves</p>\n", 7164 "type": "Number" 7165 }], 7166 "chainable": 1, 7167 "example": ["\n<div modernizr='webgl'>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n\n curveDetail(5);\n}\nfunction draw() {\n background(200);\n\n curve(250, 600, 0, -30, 40, 0, 30, 30, 0, -250, 600, 0);\n}\n</code>\n</div>"], 7168 "alt": "white arch shape with a low level of curve detail.", 7169 "class": "p5", 7170 "module": "Shape", 7171 "submodule": "Curves" 7172 }, { 7173 "file": "src/core/shape/curves.js", 7174 "line": 406, 7175 "description": "<p>Modifies the quality of forms created with <a href=\"#/p5/curve\">curve()</a> and <a href=\"#/p5/curveVertex\">curveVertex()</a>.\nThe parameter tightness determines how the curve fits to the vertex\npoints. The value 0.0 is the default value for tightness (this value\
7175ndefines the curves to be Catmull-Rom splines) and the value 1.0 connects\nall the points with straight lines. Values within the range -5.0 and 5.0\nwill deform the curves but will leave them recognizable and as values\nincrease in magnitude, they will continue to deform.</p>\n", 7176 "itemtype": "method", 7177 "name": "curveTightness", 7178 "params": [{ 7179 "name": "amount", 7180 "description": "<p>amount of deformation from the original vertices</p>\n", 7181 "type": "Number" 7182 }], 7183 "chainable": 1, 7184 "example": ["\n<div>\n<code>\n// Move the mouse left and right to see the curve change\n\nfunction setup() {\n createCanvas(100, 100);\n noFill();\n}\n\nfunction draw() {\n background(204);\n let t = map(mouseX, 0, width, -5, 5);\n curveTightness(t);\n beginShape();\n curveVertex(10, 26);\n curveVertex(10, 26);\n curveVertex(83, 24);\n curveVertex(83, 61);\n curveVertex(25, 65);\n curveVertex(25, 65);\n endShape();\n}\n</code>\n</div>"], 7185 "alt": "Line shaped like right-facing arrow,points move with mouse-x and warp shape.", 7186 "class": "p5", 7187 "module": "Shape", 7188 "submodule": "Curves" 7189 }, { 7190 "file": "src/core/shape/curves.js", 7191 "line": 453, 7192 "description": "<p>Evaluates the curve at position t for points a, b, c, d.\nThe parameter t varies between 0 and 1, a and d are control points\nof the curve, and b and c are the start and end points of the curve.\nThis can be done once with the x coordinates and a second time\nwith the y coordinates to get the location of a curve at t.</p>\n", 7193 "itemtype": "method", 7194 "name": "curvePoint", 7195 "params": [{ 7196 "name": "a", 7197 "description": "<p>coordinate of first control point of the curve</p>\n", 7198 "type": "Number" 7199 }, { 7200 "name": "b", 7201 "description": "<p>coordinate of first point</p>\n", 7202 "type": "Number" 7203 }, { 7204 "name": "c", 7205 "description": "<p>coordinate of second point</p>\n", 7206 "type": "Number" 7207 }, { 7208 "name": "d", 7209 "description": "<p>coordinate of second control point</p>\n", 7210 "type": "Number" 7211 }, { 7212 "name": "t", 7213 "description": "<p>value between 0 and 1</p>\n", 7214 "type": "Number" 7215 }], 7216 "return": { 7217 "description": "bezier value at position t", 7218 "type": "Number" 7219 }, 7220 "example": ["\n<div>\n<code>\nnoFill();\ncurve(5, 26, 5, 26, 73, 24, 73, 61);\ncurve(5, 26, 73, 24, 73, 61, 15, 65);\nfill(255);\nellipseMode(CENTER);\nlet steps = 6;\nfor (let i = 0; i <= steps; i++) {\n let t = i / steps;\n let x = curvePoint(5, 5, 73, 73, t);\n let y = curvePoint(26, 26, 24, 61, t);\n ellipse(x, y, 5, 5);\n x = curvePoint(5, 73, 73, 15, t);\n y = curvePoint(26, 24, 61, 65, t);\n ellipse(x, y, 5, 5);\n}\n</code>\n</div>\n\nline hooking down to right-bottom with 13 5x5 white ellipse points"], 7221 "class": "p5", 7222 "module": "Shape", 7223 "submodule": "Curves" 7224 }, { 7225 "file": "src/core/shape/curves.js", 7226 "line": 502, 7227 "description": "<p>Evaluates the tangent to the curve at position t for points a, b, c, d.\nThe parameter t varies between 0 and 1, a and d are points on the curve,\nand b and c are the control points.</p>\n", 7228 "itemtype": "method", 7229 "name": "curveTangent", 7230 "params": [{ 7231 "name": "a", 7232 "description": "<p>coordinate of first point on the curve</p>\n", 7233 "type": "Number" 7234 }, { 7235 "name": "b", 7236 "description": "<p>coordinate of first control point</p>\n", 7237 "type": "Number" 7238 }, { 7239 "name": "c", 7240 "description": "<p>coordinate of second control point</p>\n", 7241 "type": "Number" 7242 }, { 7243 "name": "d", 7244 "description": "<p>coordinate of second point on the curve</p>\n", 7245 "type": "Number" 7246 }, { 7247 "name": "t", 7248 "description": "<p>value between 0 and 1</p>\n", 7249 "type": "Number" 7250 }], 7251 "return": { 7252 "description": "the tangent at position t", 7253 "type": "Number" 7254 }, 7255 "example": ["\n<div>\n<code>\nnoFill();\ncurve(5, 26, 73, 24, 73, 61, 15, 65);\nlet steps = 6;\nfor (let i = 0; i <= steps;
7255 i++) {\n let t = i / steps;\n let x = curvePoint(5, 73, 73, 15, t);\n let y = curvePoint(26, 24, 61, 65, t);\n //ellipse(x, y, 5, 5);\n let tx = curveTangent(5, 73, 73, 15, t);\n let ty = curveTangent(26, 24, 61, 65, t);\n let a = atan2(ty, tx);\n a -= PI / 2.0;\n line(x, y, cos(a) * 8 + x, sin(a) * 8 + y);\n}\n</code>\n</div>"], 7256 "alt": "right curving line mid-right of canvas with 7 short lines radiating from it.", 7257 "class": "p5", 7258 "module": "Shape", 7259 "submodule": "Curves" 7260 }, { 7261 "file": "src/core/shape/vertex.js", 7262 "line": 22, 7263 "description": "<p>Use the <a href=\"#/p5/beginContour\">beginContour()</a> and <a href=\"#/p5/endContour\">endContour()</a> functions to create negative\nshapes within shapes such as the center of the letter 'O'. <a href=\"#/p5/beginContour\">beginContour()</a>\nbegins recording vertices for the shape and <a href=\"#/p5/endContour\">endContour()</a> stops recording.\nThe vertices that define a negative shape must "wind" in the opposite\ndirection from the exterior shape. First draw vertices for the exterior\nclockwise order, then for internal shapes, draw vertices\nshape in counter-clockwise.\n<br><br>\nThese functions can only be used within a <a href=\"#/p5/beginShape\">beginShape()</a>/<a href=\"#/p5/endShape\">endShape()</a> pair and\ntransformations such as <a href=\"#/p5/translate\">translate()</a>, <a href=\"#/p5/rotate\">rotate()</a>, and <a href=\"#/p5/scale\">scale()</a> do not work\nwithin a <a href=\"#/p5/beginContour\">beginContour()</a>/<a href=\"#/p5/endContour\">endContour()</a> pair. It is also not possible to use\nother shapes, such as <a href=\"#/p5/ellipse\">ellipse()</a> or <a href=\"#/p5/rect\">rect()</a> within.</p>\n", 7264 "itemtype": "method", 7265 "name": "beginContour", 7266 "chainable": 1, 7267 "example": ["\n<div>\n<code>\ntranslate(50, 50);\nstroke(255, 0, 0);\nbeginShape();\n// Exterior part of shape, clockwise winding\nvertex(-40, -40);\nvertex(40, -40);\nvertex(40, 40);\nvertex(-40, 40);\n// Interior part of shape, counter-clockwise winding\nbeginContour();\nvertex(-20, -20);\nvertex(-20, 20);\nvertex(20, 20);\nvertex(20, -20);\nendContour();\nendShape(CLOSE);\n</code>\n</div>"], 7268 "alt": "white rect and smaller grey rect with red outlines in center of canvas.", 7269 "class": "p5", 7270 "module": "Shape", 7271 "submodule": "Vertex" 7272 }, { 7273 "file": "src/core/shape/vertex.js", 7274 "line": 70, 7275 "description": "<p>Using the <a href=\"#/p5/beginShape\">beginShape()</a> and <a href=\"#/p5/endShape\">endShape()</a> functions allow creating more\ncomplex forms. <a href=\"#/p5/beginShape\">beginShape()</a> begins recording vertices for a shape and\n<a href=\"#/p5/endShape\">endShape()</a> stops recording. The value of the kind parameter tells it which\ntypes of shapes to create from the provided vertices. With no mode\nspecified, the shape can be any irregular polygon.\n<br><br>\nThe parameters available for <a href=\"#/p5/beginShape\">beginShape()</a> are POINTS, LINES, TRIANGLES,\nTRIANGLE_FAN, TRIANGLE_STRIP, QUADS, and QUAD_STRIP. After calling the\n<a href=\"#/p5/beginShape\">beginShape()</a> function, a series of <a href=\"#/p5/vertex\">vertex()</a> commands must follow. To stop\ndrawing the shape, call <a href=\"#/p5/endShape\">endShape()</a>. Each shape will be outlined with the\ncurrent stroke color and filled with the fill color.\n<br><br>\nTransformations such as <a href=\"#/p5/translate\">translate()</a>, <a href=\"#/p5/rotate\">rotate()</a>, and <a href=\"#/p5/scale\">scale()</a> do not work\nwithin <a href=\"#/p5/beginShape\">beginShape()</a>. It is also not possible to use other shapes, such as\n<a href=\"#/p5/ellipse\">ellipse()</a> or <a href=\"#/p5/rect\">rect()</a> within <a href=\"#/p5/beginShape\">beginShape()</a>.</p>\n", 7276 "itemtype": "method", 7277 "name": "beginShape", 7278 "params": [{ 7279 "name": "kind", 7280 "description": "<p>either POINTS, LINES, TRIANGLES, TRIANGLE_FAN\n TRIANGLE_STRIP, QUADS, or QUAD_STRIP</p>\n", 7281 "type": "Constant", 7282 "optional": true 7283 }], 7284 "chainable": 1, 7285 "example": ["\n<div>\n<code>\nbeginShape();\nvertex(30, 20);\nvertex(85, 20);
7285\nvertex(85, 75);\nvertex(30, 75);\nendShape(CLOSE);\n</code>\n</div>\n\n<div>\n<code>\nbeginShape(POINTS);\nvertex(30, 20);\nvertex(85, 20);\nvertex(85, 75);\nvertex(30, 75);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nbeginShape(LINES);\nvertex(30, 20);\nvertex(85, 20);\nvertex(85, 75);\nvertex(30, 75);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nnoFill();\nbeginShape();\nvertex(30, 20);\nvertex(85, 20);\nvertex(85, 75);\nvertex(30, 75);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nnoFill();\nbeginShape();\nvertex(30, 20);\nvertex(85, 20);\nvertex(85, 75);\nvertex(30, 75);\nendShape(CLOSE);\n</code>\n</div>\n\n<div>\n<code>\nbeginShape(TRIANGLES);\nvertex(30, 75);\nvertex(40, 20);\nvertex(50, 75);\nvertex(60, 20);\nvertex(70, 75);\nvertex(80, 20);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nbeginShape(TRIANGLE_STRIP);\nvertex(30, 75);\nvertex(40, 20);\nvertex(50, 75);\nvertex(60, 20);\nvertex(70, 75);\nvertex(80, 20);\nvertex(90, 75);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nbeginShape(TRIANGLE_FAN);\nvertex(57.5, 50);\nvertex(57.5, 15);\nvertex(92, 50);\nvertex(57.5, 85);\nvertex(22, 50);\nvertex(57.5, 15);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nbeginShape(QUADS);\nvertex(30, 20);\nvertex(30, 75);\nvertex(50, 75);\nvertex(50, 20);\nvertex(65, 20);\nvertex(65, 75);\nvertex(85, 75);\nvertex(85, 20);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nbeginShape(QUAD_STRIP);\nvertex(30, 20);\nvertex(30, 75);\nvertex(50, 20);\nvertex(50, 75);\nvertex(65, 20);\nvertex(65, 75);\nvertex(85, 20);\nvertex(85, 75);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nbeginShape();\nvertex(20, 20);\nvertex(40, 20);\nvertex(40, 40);\nvertex(60, 40);\nvertex(60, 60);\nvertex(20, 60);\nendShape(CLOSE);\n</code>\n</div>"], 7286 "alt": "white square-shape with black outline in middle-right of canvas.\n4 black points in a square shape in middle-right of canvas.\n2 horizontal black lines. In the top-right and bottom-right of canvas.\n3 line shape with horizontal on top, vertical in middle and horizontal bottom.\nsquare line shape in middle-right of canvas.\n2 white triangle shapes mid-right canvas. left one pointing up and right down.\n5 horizontal interlocking and alternating white triangles in mid-right canvas.\n4 interlocking white triangles in 45 degree rotated square-shape.\n2 white rectangle shapes in mid-right canvas. Both 20x55.\n3 side-by-side white rectangles center rect is smaller in mid-right canvas.\nThick white l-shape with black outline mid-top-left of canvas.", 7287 "class": "p5", 7288 "module": "Shape", 7289 "submodule": "Vertex" 7290 }, { 7291 "file": "src/core/shape/vertex.js", 7292 "line": 270, 7293 "description": "<p>Specifies vertex coordinates for Bezier curves. Each call to\nbezierVertex() defines the position of two control points and\none anchor point of a Bezier curve, adding a new segment to a\nline or shape. For WebGL mode bezierVertex() can be used in 2D\nas well as 3D mode. 2D mode expects 6 parameters, while 3D mode\nexpects 9 parameters (including z coordinates).\n<br><br>\nThe first time bezierVertex() is used within a <a href=\"#/p5/beginShape\">beginShape()</a>\ncall, it must be prefaced with a call to <a href=\"#/p5/vertex\">vertex()</a> to set the first anchor\npoint. This function must be used between <a href=\"#/p5/beginShape\">beginShape()</a> and <a href=\"#/p5/endShape\">endShape()</a>\nand only when there is no MODE or POINTS parameter specified to\n<a href=\"#/p5/beginShape\">beginShape()</a>.</p>\n", 7294 "itemtype": "method", 7295 "name": "bezierVertex", 7296 "chainable": 1, 7297 "example": ["\n<div>\n<code>\nnoFill();\nbeginShape();\nvertex(30, 20);\nbezierVertex(80, 0, 80, 75, 30, 75);\nendShape();\n</code>\n</div>", "\n<div>\n<code>\nbeginShape();\nvertex(30, 20);\nbezierVertex(80, 0, 80, 75, 30, 75);\nbezierVertex(50, 80, 60, 25, 30, 20);\nendShape();\n</code>\n</div>", "\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n setAttributes('antialias', true);\n}\nfunction draw() {\n orbitControl();\n background(50);\n strokeWeight(4);
7297\n stroke(255);\n point(-25, 30);\n point(25, 30);\n point(25, -30);\n point(-25, -30);\n\n strokeWeight(1);\n noFill();\n\n beginShape();\n vertex(-25, 30);\n bezierVertex(25, 30, 25, -30, -25, -30);\n endShape();\n\n beginShape();\n vertex(-25, 30, 20);\n bezierVertex(25, 30, 20, 25, -30, 20, -25, -30, 20);\n endShape();\n}\n</code>\n</div>"], 7298 "alt": "crescent shape in middle of canvas with another crescent shape on positive z-axis.", 7299 "class": "p5", 7300 "module": "Shape", 7301 "submodule": "Vertex", 7302 "overloads": [{ 7303 "line": 270, 7304 "params": [{ 7305 "name": "x2", 7306 "description": "<p>x-coordinate for the first control point</p>\n", 7307 "type": "Number" 7308 }, { 7309 "name": "y2", 7310 "description": "<p>y-coordinate for the first control point</p>\n", 7311 "type": "Number" 7312 }, { 7313 "name": "x3", 7314 "description": "<p>x-coordinate for the second control point</p>\n", 7315 "type": "Number" 7316 }, { 7317 "name": "y3", 7318 "description": "<p>y-coordinate for the second control point</p>\n", 7319 "type": "Number" 7320 }, { 7321 "name": "x4", 7322 "description": "<p>x-coordinate for the anchor point</p>\n", 7323 "type": "Number" 7324 }, { 7325 "name": "y4", 7326 "description": "<p>y-coordinate for the anchor point</p>\n", 7327 "type": "Number" 7328 }], 7329 "chainable": 1 7330 }, { 7331 "line": 358, 7332 "params": [{ 7333 "name": "x2", 7334 "description": "", 7335 "type": "Number" 7336 }, { 7337 "name": "y2", 7338 "description": "", 7339 "type": "Number" 7340 }, { 7341 "name": "z2", 7342 "description": "<p>z-coordinate for the first control point (for WebGL mode)</p>\n", 7343 "type": "Number" 7344 }, { 7345 "name": "x3", 7346 "description": "", 7347 "type": "Number" 7348 }, { 7349 "name": "y3", 7350 "description": "", 7351 "type": "Number" 7352 }, { 7353 "name": "z3", 7354 "description": "<p>z-coordinate for the second control point (for WebGL mode)</p>\n", 7355 "type": "Number" 7356 }, { 7357 "name": "x4", 7358 "description": "", 7359 "type": "Number" 7360 }, { 7361 "name": "y4", 7362 "description": "", 7363 "type": "Number" 7364 }, { 7365 "name": "z4", 7366 "description": "<p>z-coordinate for the anchor point (for WebGL mode)</p>\n", 7367 "type": "Number" 7368 }], 7369 "chainable": 1 7370 }] 7371 }, { 7372 "file": "src/core/shape/vertex.js", 7373 "line": 398, 7374 "description": "<p>Specifies vertex coordinates for curves. This function may only\nbe used between <a href=\"#/p5/beginShape\">beginShape()</a> and <a href=\"#/p5/endShape\">endShape()</a> and only when there\nis no MODE parameter specified to <a href=\"#/p5/beginShape\">beginShape()</a>.\nFor WebGL mode curveVertex() can be used in 2D as well as 3D mode.\n2D mode expects 2 parameters, while 3D mode expects 3 parameters.\n<br><br>\nThe first and last points in a series of curveVertex() lines will be used to\nguide the beginning and end of a the curve. A minimum of four\npoints is required to draw a tiny curve between the second and\nthird points. Adding a fifth point with curveVertex() will draw\nthe curve between the second, third, and fourth points. The\ncurveVertex() function is an implementation of Catmull-Rom\nsplines.</p>\n", 7375 "itemtype": "method", 7376 "name": "curveVertex", 7377 "chainable": 1, 7378 "example": ["\n<div>\n<code>\nstrokeWeight(5);\npoint(84, 91);\npoint(68, 19);\npoint(21, 17);\npoint(32, 91);\nstrokeWeight(1);\n\nnoFill();\nbeginShape();\ncurveVertex(84, 91);\ncurveVertex(84, 91);
7378\ncurveVertex(68, 19);\ncurveVertex(21, 17);\ncurveVertex(32, 91);\ncurveVertex(32, 91);\nendShape();\n</code>\n</div>"], 7379 "alt": "Upside-down u-shape line, mid canvas. left point extends beyond canvas view.", 7380 "class": "p5", 7381 "module": "Shape", 7382 "submodule": "Vertex", 7383 "overloads": [{ 7384 "line": 398, 7385 "params": [{ 7386 "name": "x", 7387 "description": "<p>x-coordinate of the vertex</p>\n", 7388 "type": "Number" 7389 }, { 7390 "name": "y", 7391 "description": "<p>y-coordinate of the vertex</p>\n", 7392 "type": "Number" 7393 }], 7394 "chainable": 1 7395 }, { 7396 "line": 443, 7397 "params": [{ 7398 "name": "x", 7399 "description": "", 7400 "type": "Number" 7401 }, { 7402 "name": "y", 7403 "description": "", 7404 "type": "Number" 7405 }, { 7406 "name": "z", 7407 "description": "<p>z-coordinate of the vertex (for WebGL mode)</p>\n", 7408 "type": "Number", 7409 "optional": true 7410 }], 7411 "chainable": 1 7412 }] 7413 }, { 7414 "file": "src/core/shape/vertex.js", 7415 "line": 508, 7416 "description": "<p>Use the <a href=\"#/p5/beginContour\">beginContour()</a> and <a href=\"#/p5/endContour\">endContour()</a> functions to create negative\nshapes within shapes such as the center of the letter 'O'. <a href=\"#/p5/beginContour\">beginContour()</a>\nbegins recording vertices for the shape and <a href=\"#/p5/endContour\">endContour()</a> stops recording.\nThe vertices that define a negative shape must "wind" in the opposite\ndirection from the exterior shape. First draw vertices for the exterior\nclockwise order, then for internal shapes, draw vertices\nshape in counter-clockwise.\n<br><br>\nThese functions can only be used within a <a href=\"#/p5/beginShape\">beginShape()</a>/<a href=\"#/p5/endShape\">endShape()</a> pair and\ntransformations such as <a href=\"#/p5/translate\">translate()</a>, <a href=\"#/p5/rotate\">rotate()</a>, and <a href=\"#/p5/scale\">scale()</a> do not work\nwithin a <a href=\"#/p5/beginContour\">beginContour()</a>/<a href=\"#/p5/endContour\">endContour()</a> pair. It is also not possible to use\nother shapes, such as <a href=\"#/p5/ellipse\">ellipse()</a> or <a href=\"#/p5/rect\">rect()</a> within.</p>\n", 7417 "itemtype": "method", 7418 "name": "endContour", 7419 "chainable": 1, 7420 "example": ["\n<div>\n<code>\ntranslate(50, 50);\nstroke(255, 0, 0);\nbeginShape();\n// Exterior part of shape, clockwise winding\nvertex(-40, -40);\nvertex(40, -40);\nvertex(40, 40);\nvertex(-40, 40);\n// Interior part of shape, counter-clockwise winding\nbeginContour();\nvertex(-20, -20);\nvertex(-20, 20);\nvertex(20, 20);\nvertex(20, -20);\nendContour();\nendShape(CLOSE);\n</code>\n</div>"], 7421 "alt": "white rect and smaller grey rect with red outlines in center of canvas.", 7422 "class": "p5", 7423 "module": "Shape", 7424 "submodule": "Vertex" 7425 }, { 7426 "file": "src/core/shape/vertex.js", 7427 "line": 568, 7428 "description": "<p>The <a href=\"#/p5/endShape\">endShape()</a> function is the companion to <a href=\"#/p5/beginShape\">beginShape()</a> and may only be\ncalled after <a href=\"#/p5/beginShape\">beginShape()</a>. When <a href=\"#/p5/endshape\">endshape()</a> is called, all of image data\ndefined since the previous call to <a href=\"#/p5/beginShape\">beginShape()</a> is written into the image\nbuffer. The constant CLOSE as the value for the MODE parameter to close\nthe shape (to connect the beginning and the end).</p>\n", 7429 "itemtype": "method", 7430 "name": "endShape", 7431 "params": [{ 7432 "name": "mode", 7433 "description": "<p>use CLOSE to close the shape</p>\n", 7434 "type": "Constant", 7435 "optional": true 7436 }], 7437 "chainable": 1, 7438 "example": ["\n<div>\n<code>\nnoFill();\n\nbeginShape();\nvertex(20, 20);\nvertex(45, 20);\nvertex(45, 80);\nendShape(CLOSE);\n\nbeginShape();\nvertex(50, 20);\nvertex(75, 20);\nvertex(75, 80);\nendShape();\n</code>\n</div>"], 7439 "alt": "Triangle line shape with smallest interior angle on bottom and upside-
7439down L.", 7440 "class": "p5", 7441 "module": "Shape", 7442 "submodule": "Vertex" 7443 }, { 7444 "file": "src/core/shape/vertex.js", 7445 "line": 654, 7446 "description": "<p>Specifies vertex coordinates for quadratic Bezier curves. Each call to\nquadraticVertex() defines the position of one control points and one\nanchor point of a Bezier curve, adding a new segment to a line or shape.\nThe first time quadraticVertex() is used within a <a href=\"#/p5/beginShape\">beginShape()</a> call, it\nmust be prefaced with a call to <a href=\"#/p5/vertex\">vertex()</a> to set the first anchor point.\nFor WebGL mode quadraticVertex() can be used in 2D as well as 3D mode.\n2D mode expects 4 parameters, while 3D mode expects 6 parameters\n(including z coordinates).\n<br><br>\nThis function must be used between <a href=\"#/p5/beginShape\">beginShape()</a> and <a href=\"#/p5/endShape\">endShape()</a>\nand only when there is no MODE or POINTS parameter specified to\n<a href=\"#/p5/beginShape\">beginShape()</a>.</p>\n", 7447 "itemtype": "method", 7448 "name": "quadraticVertex", 7449 "chainable": 1, 7450 "example": ["\n<div>\n<code>\nstrokeWeight(5);\npoint(20, 20);\npoint(80, 20);\npoint(50, 50);\n\nnoFill();\nstrokeWeight(1);\nbeginShape();\nvertex(20, 20);\nquadraticVertex(80, 20, 50, 50);\nendShape();\n</code>\n</div>\n\n<div>\n<code>\nstrokeWeight(5);\npoint(20, 20);\npoint(80, 20);\npoint(50, 50);\n\npoint(20, 80);\npoint(80, 80);\npoint(80, 60);\n\nnoFill();\nstrokeWeight(1);\nbeginShape();\nvertex(20, 20);\nquadraticVertex(80, 20, 50, 50);\nquadraticVertex(20, 80, 80, 80);\nvertex(80, 60);\nendShape();\n</code>\n</div>"], 7451 "alt": "arched-shaped black line with 4 pixel thick stroke weight.\nbackwards s-shaped black line with 4 pixel thick stroke weight.", 7452 "class": "p5", 7453 "module": "Shape", 7454 "submodule": "Vertex", 7455 "overloads": [{ 7456 "line": 654, 7457 "params": [{ 7458 "name": "cx", 7459 "description": "<p>x-coordinate for the control point</p>\n", 7460 "type": "Number" 7461 }, { 7462 "name": "cy", 7463 "description": "<p>y-coordinate for the control point</p>\n", 7464 "type": "Number" 7465 }, { 7466 "name": "x3", 7467 "description": "<p>x-coordinate for the anchor point</p>\n", 7468 "type": "Number" 7469 }, { 7470 "name": "y3", 7471 "description": "<p>y-coordinate for the anchor point</p>\n", 7472 "type": "Number" 7473 }], 7474 "chainable": 1 7475 }, { 7476 "line": 720, 7477 "params": [{ 7478 "name": "cx", 7479 "description": "", 7480 "type": "Number" 7481 }, { 7482 "name": "cy", 7483 "description": "", 7484 "type": "Number" 7485 }, { 7486 "name": "cz", 7487 "description": "<p>z-coordinate for the control point (for WebGL mode)</p>\n", 7488 "type": "Number" 7489 }, { 7490 "name": "x3", 7491 "description": "", 7492 "type": "Number" 7493 }, { 7494 "name": "y3", 7495 "description": "", 7496 "type": "Number" 7497 }, { 7498 "name": "z3", 7499 "description": "<p>z-coordinate for the anchor point (for WebGL mode)</p>\n", 7500 "type": "Number" 7501 }], 7502 "chainable": 1 7503 }] 7504 }, { 7505 "file": "src/core/shape/vertex.js", 7506 "line": 813, 7507 "description": "<p>All shapes are constructed by connecting a series of vertices. <a href=\"#/p5/vertex\">vertex()</a>\nis used to specify the vertex coordinates for points, lines, triangles,\nquads, and polygons. It is used exclusively within the <a href=\"#/p5/beginShape\">beginShape()</a> and\n<a href=\"#/p5/endShape\">endShape()</a> functions.</p>\n", 7508 "itemtype": "method", 7509 "name": "vertex", 7510 "chainable": 1, 7511 "example": ["\n<div>\n<code>\nstrokeWeight(3);\nbeginShape(POINTS);\nvertex(30, 20);\nvertex(85, 20);
7511\nvertex(85, 75);\nvertex(30, 75);\nendShape();\n</code>\n</div>"], 7512 "alt": "8 points making 4 lines", 7513 "class": "p5", 7514 "module": "Shape", 7515 "submodule": "Vertex", 7516 "overloads": [{ 7517 "line": 813, 7518 "params": [{ 7519 "name": "x", 7520 "description": "<p>x-coordinate of the vertex</p>\n", 7521 "type": "Number" 7522 }, { 7523 "name": "y", 7524 "description": "<p>y-coordinate of the vertex</p>\n", 7525 "type": "Number" 7526 }], 7527 "chainable": 1 7528 }, { 7529 "line": 900, 7530 "params": [{ 7531 "name": "x", 7532 "description": "", 7533 "type": "Number" 7534 }, { 7535 "name": "y", 7536 "description": "", 7537 "type": "Number" 7538 }, { 7539 "name": "z", 7540 "description": "<p>z-coordinate of the vertex</p>\n", 7541 "type": "Number" 7542 }, { 7543 "name": "u", 7544 "description": "<p>the vertex's texture u-coordinate</p>\n", 7545 "type": "Number", 7546 "optional": true 7547 }, { 7548 "name": "v", 7549 "description": "<p>the vertex's texture v-coordinate</p>\n", 7550 "type": "Number", 7551 "optional": true 7552 }], 7553 "chainable": 1 7554 }] 7555 }, { 7556 "file": "src/core/constants.js", 7557 "line": 13, 7558 "itemtype": "property", 7559 "name": "P2D", 7560 "type": "String", 7561 "final": 1, 7562 "class": "p5", 7563 "module": "Constants", 7564 "submodule": "Constants" 7565 }, { 7566 "file": "src/core/constants.js", 7567 "line": 18, 7568 "itemtype": "property", 7569 "name": "WEBGL", 7570 "type": "String", 7571 "final": 1, 7572 "class": "p5", 7573 "module": "Constants", 7574 "submodule": "Constants" 7575 }, { 7576 "file": "src/core/constants.js", 7577 "line": 25, 7578 "itemtype": "property", 7579 "name": "ARROW", 7580 "type": "String", 7581 "final": 1, 7582 "class": "p5", 7583 "module": "Constants", 7584 "submodule": "Constants" 7585 }, { 7586 "file": "src/core/constants.js", 7587 "line": 30, 7588 "itemtype": "property", 7589 "name": "CROSS", 7590 "type": "String", 7591 "final": 1, 7592 "class": "p5", 7593 "module": "Constants", 7594 "submodule": "Constants" 7595 }, { 7596 "file": "src/core/constants.js", 7597 "line": 35, 7598 "itemtype": "property", 7599 "name": "HAND", 7600 "type": "String", 7601 "final": 1, 7602 "class": "p5", 7603 "module": "Constants", 7604 "submodule": "Constants" 7605 }, { 7606 "file": "src/core/constants.js", 7607 "line": 40, 7608 "itemtype": "property", 7609 "name": "MOVE", 7610 "type": "String", 7611 "final": 1, 7612 "class": "p5", 7613 "module": "Constants", 7614 "submodule": "Constants" 7615 }, { 7616 "file": "src/core/constants.js", 7617 "line": 45, 7618 "itemtype": "property", 7619 "name": "TEXT", 7620 "type": "String", 7621 "final": 1, 7622 "class": "p5", 7623 "module": "Constants", 7624 "submodule": "Constants" 7625 }, { 7626 "file": "src/core/constants.js", 7627 "line": 50, 7628 "itemtype": "property", 7629 "name": "WAIT", 7630 "type": "String", 7631 "final": 1, 7632 "class": "p5", 7633 "module": "Constants", 7634 "submodule": "Constants" 7635 }, { 7636 "file": "src/core/constants.js", 7637 "line": 58, 7638 "description": "<p>HALF_PI is a mathematical constant with the value\n1.57079632679489661923. It is half the ratio of the\ncircumference of a circle to its diameter. It is useful in\ncombination with the trigonometric functions <a href=\"#/p5/sin\">sin()</a> and <a href=\"#/p5/cos\">cos()</a>.</p>\n", 7639 "itemtype": "property", 7640 "name": "HALF_PI", 7641 "type": "Number", 7642 "final": 1, 7643 "example": ["\n<div><code>\narc(50, 50, 80, 80, 0, HALF_PI);\n</code></div>"], 7644 "alt": "80x80 white quarter-circle with curve toward bottom right of canvas.", 7645 "class": "p5", 7646 "module": "Constants", 7647 "submodule": "Constants" 7648 }, { 7649 "file": "src/core/constants.js", 7650 "line": 77, 7651 "description": "<p>PI is a mathematical constant with the value\n3.14159265358979323846. It is the ratio of the circumference\nof a circle to its diameter. It is useful in combination with\nthe trigonometric functions <a href=\"#/p5/sin\">sin()</a> and <a href=\"#/p5/cos\">cos()</a>.</p>\n", 7652 "itemtype": "property", 7653 "name": "PI", 7654 "type": "Number", 7655 "final": 1, 7656 "example": ["\n<div><code>\narc(50, 50, 80, 80, 0, PI);\n</code></div>"], 7657 "alt": "white half-circle with curve toward bottom of canvas.", 7658 "class": "p5", 7659 "module": "Constants", 7660 "submodule": "Constants" 7661 }, { 7662 "file": "src/core/constants.js", 7663 "line": 96, 7664 "description": "<p>QUARTER_PI is a mathematical constant with the value 0.7853982.\nIt is one quarter the ratio of the circumference of a circle to\nits diameter. It is useful in combination with the trigonometric\nfunctions <a href=\"#/p5/sin\">sin()</a> and <a href=\"#/p5/cos\">cos()</a>.</p>\n", 7665 "itemtype": "property", 7666 "name": "QUARTER_PI", 7667 "type": "Number", 7668 "final": 1, 7669 "example": ["\n<div><code>\narc(50, 50, 80, 80, 0, QUARTER_PI);\n</code></div>"], 7670 "alt": "white eighth-circle rotated about 40 degrees with curve bottom right canvas.", 7671 "class": "p5", 7672 "module": "Constants", 7673 "submodule": "Constants" 7674 }, { 7675 "file": "src/core/constants.js", 7676 "line": 115, 7677 "description": "<p>TAU is an alias for TWO_PI, a mathematical constant with the\nvalue 6.28318530717958647693. It is twice the ratio of the\ncircumference of a circle to its diameter. It is useful in\ncombination with the trigonometric functions <a href=\"#/p5/sin\">sin()</a> and <a href=\"#/p5/cos\">cos()</a>.</p>\n", 7678 "itemtype": "property", 7679 "name": "TAU", 7680 "type": "Number", 7681 "final": 1, 7682 "example": ["\n<div><code>\narc(50, 50, 80, 80, 0, TAU);\n</code></div>"], 7683 "alt": "80x80 white ellipse shape in center of canvas.", 7684 "class": "p5", 7685 "module": "Constants", 7686 "submodule": "Constants" 7687 }, { 7688 "file": "src/core/constants.js", 7689 "line": 134, 7690 "description": "<p>TWO_PI is a mathematical constant with the value\n6.28318530717958647693. It is twice the ratio of the\ncircumference of a circle to its diameter. It is useful in\ncombination with the trigonometric functions <a href=\"#/p5/sin\">sin()</a> and <a href=\"#/p5/cos\">cos()</a>.</p>\n", 7691 "itemtype": "property", 7692 "name": "TWO_PI", 7693 "type": "Number", 7694 "final": 1, 7695 "example": ["\n<div><code>\narc(50, 50, 80, 80, 0, TWO_PI);\n</code></div>"], 7696 "alt": "80x80 white ellipse shape in center of canvas.", 7697 "class": "p5", 7698 "module": "Constants", 7699 "submodule": "Constants" 7700 }, { 7701 "file": "src/core/constants.js", 7702 "line": 153, 7703 "description": "<p>Constant to be used with <a href=\"#/p5/angleMode\">angleMode()</a> function, to set the mode which\np5.js interprates and calculates angles (either DEGREES or RADIANS).</p>\n", 7704 "itemtype": "property", 7705 "name": "DEGREES", 7706 "type": "String", 7707 "final": 1, 7708 "example": ["\n<div class='norender'><code>\nfunction setup() {\n angleMode(DEGREES);\n}\n</code></div>"], 7709 "class": "p5", 7710 "module": "Constants", 7711 "submodule": "Constants" 7712 }, { 7713 "file": "src/core/constants.js", 7714 "line": 167, 7715 "description": "<p>Constant to be used with <a href=\"#/p5/angleMode\">angleMode()</a> function, to set the mode which\np5.js interprates and calculates angles (either RADIANS or DEGREES).</p>\n", 7716 "itemtype": "property", 7717 "name": "RADIANS", 7718 "type": "String", 7719 "final": 1, 7720 "example": ["\n<div class='norender'><code>\nfunction setup() {\n angleMode(RADIANS);\n}\n</code></div>"], 7721 "class": "p5", 7722 "module": "Constants", 7723 "submodule": "Constants" 7724 }, { 7725 "file": "src/core/constants.js", 7726 "line": 185, 7727 "itemtype": "property", 7728 "name": "CORNER", 7729 "type": "String", 7730 "final": 1, 7731 "class": "p5", 7732 "module": "Constants", 7733 "submodule": "Constants" 7734 }, { 7735 "file": "src/core/constants.js", 7736 "line": 190, 7737 "itemtype": "property", 7738 "name": "CORNERS", 7739 "type": "String", 7740 "final": 1, 7741 "class": "p5", 7742 "module": "Constants", 7743 "submodule": "Constants" 7744 }, { 7745 "file": "src/core/constants.js", 7746 "line": 195, 7747 "itemtype": "property", 7748 "name": "RADIUS", 7749 "type": "String", 7750 "final": 1, 7751 "class": "p5", 7752 "module": "Constants", 7753 "submodule": "Constants" 7754 }, { 7755 "file": "src/core/constants.js", 7756 "line": 200, 7757 "itemtype": "property", 7758 "name": "RIGHT", 7759 "type": "String", 7760 "final": 1, 7761 "class": "p5", 7762 "module": "Constants", 7763 "submodule": "Constants" 7764 }, { 7765 "file": "src/core/constants.js", 7766 "line": 205, 7767 "itemtype": "property", 7768 "name": "LEFT", 7769 "type": "String", 7770 "final": 1, 7771 "class": "p5", 7772 "module": "Constants", 7773 "submodule": "Constants" 7774 }, { 7775 "file": "src/core/constants.js", 7776 "line": 210, 7777 "itemtype": "property", 7778 "name": "CENTER", 7779 "type": "String", 7780 "final": 1, 7781 "class": "p5", 7782 "module": "Constants", 7783 "submodule": "Constants" 7784 }, { 7785 "file": "src/core/constants.js", 7786 "line": 215, 7787 "itemtype": "property", 7788 "name": "TOP", 7789 "type": "String", 7790 "final": 1, 7791 "class": "p5", 7792 "module": "Constants", 7793 "submodule": "Constants" 7794 }, { 7795 "file": "src/core/constants.js", 7796 "line": 220, 7797 "itemtype": "property", 7798 "name": "BOTTOM", 7799 "type": "String", 7800 "final": 1, 7801 "class": "p5", 7802 "module": "Constants", 7803 "submodule": "Constants" 7804 }, { 7805 "file": "src/core/constants.js", 7806 "line": 225, 7807 "itemtype": "property", 7808 "name": "BASELINE", 7809 "type": "String", 7810 "final": 1, 7811 "default": "alphabetic", 7812 "class": "p5", 7813 "module": "Constants", 7814 "submodule": "Constants" 7815 }, { 7816 "file": "src/core/constants.js", 7817 "line": 231, 7818 "itemtype": "property", 7819 "name": "POINTS", 7820 "type": "Number", 7821 "final": 1, 7822 "default": "0x0000", 7823 "class": "p5", 7824 "module": "Constants", 7825 "submodule": "Constants" 7826 }, { 7827 "file": "src/core/constants.js", 7828 "line": 237, 7829 "itemtype": "property", 7830 "name": "LINES", 7831 "type": "Number", 7832 "final": 1, 7833 "default": "0x0001", 7834 "class": "p5", 7835 "module": "Constants", 7836 "submodule": "Constants" 7837 }, { 7838 "file": "src/core/constants.js", 7839 "line": 243, 7840 "itemtype": "property", 7841 "name": "LINE_STRIP", 7842 "type": "Number", 7843 "final": 1, 7844 "default": "0x0003", 7845 "class": "p5", 7846 "module": "Constants", 7847 "submodule": "Constants" 7848 }, { 7849 "file": "src/core/constants.js", 7850 "line": 249, 7851 "itemtype": "property", 7852 "name": "LINE_LOOP", 7853 "type": "Number", 7854 "final": 1, 7855 "default": "0x0002", 7856 "class": "p5", 7857 "module": "Constants", 7858 "submodule": "Constants" 7859 }, { 7860 "file": "src/core/constants.js", 7861 "line": 255, 7862 "itemtype": "property", 7863 "name": "TRIANGLES", 7864 "type": "Number", 7865 "final": 1, 7866 "default": "0x0004", 7867 "class": "p5", 7868 "module": "Constants", 7869 "submodule": "Constants" 7870 }, { 7871 "file": "src/core/constants.js", 7872 "line": 261, 7873 "itemtype": "property", 7874 "name": "TRIANGLE_FAN", 7875 "type": "Number", 7876 "final": 1, 7877 "default": "0x0006", 7878 "class": "p5", 7879 "module": "Constants", 7880 "submodule": "Constants" 7881 }, { 7882 "file": "src/core/constants.js", 7883 "line": 267, 7884 "itemtype": "property", 7885 "name": "TRIANGLE_STRIP", 7886 "type": "Number", 7887 "final": 1, 7888 "default": "0x0005", 7889 "class": "p5", 7890 "module": "Constants", 7891 "submodule": "Constants" 7892 }, { 7893 "file": "src/core/constants.js", 7894 "line": 273, 7895 "itemtype": "property", 7896 "name": "QUADS", 7897 "type": "String", 7898 "final": 1, 7899 "class": "p5", 7900 "module": "Constants", 7901 "submodule": "Constants" 7902 }, { 7903 "file": "src/core/constants.js", 7904 "line": 278, 7905 "itemtype": "property", 7906 "name": "QUAD_STRIP", 7907 "type": "String", 7908 "final": 1, 7909 "default": "quad_strip", 7910 "class": "p5", 7911 "module": "Constants", 7912 "submodule": "Constants" 7913 }, { 7914 "file": "src/core/constants.js", 7915 "line": 284, 7916 "itemtype": "property", 7917 "name": "CLOSE", 7918 "type": "String", 7919 "final": 1, 7920 "class": "p5", 7921 "module": "Constants", 7922 "submodule": "Constants" 7923 }, { 7924 "file": "src/core/constants.js", 7925 "line": 289, 7926 "itemtype": "property", 7927 "name": "OPEN", 7928 "type": "String", 7929 "final": 1, 7930 "class": "p5", 7931 "module": "Constants", 7932 "submodule": "Constants" 7933 }, { 7934 "file": "src/core/constants.js", 7935 "line": 294, 7936 "itemtype": "property", 7937 "name": "CHORD", 7938 "type": "String", 7939 "final": 1, 7940 "class": "p5", 7941 "module": "Constants", 7942 "submodule": "Constants" 7943 }, { 7944 "file": "src/core/constants.js", 7945 "line": 299, 7946 "itemtype": "property", 7947 "name": "PIE", 7948 "type": "String", 7949 "final": 1, 7950 "class": "p5", 7951 "module": "Constants", 7952 "submodule": "Constants" 7953 }, { 7954 "file": "src/core/constants.js", 7955 "line": 304, 7956 "itemtype": "property", 7957 "name": "PROJECT", 7958 "type": "String", 7959 "final": 1, 7960 "default": "square", 7961 "class": "p5", 7962 "module": "Constants", 7963 "submodule": "Constants" 7964 }, { 7965 "file": "src/core/constants.js", 7966 "line": 310, 7967 "itemtype": "property", 7968 "name": "SQUARE", 7969 "type": "String", 7970 "final": 1, 7971 "default": "butt", 7972 "class": "p5", 7973 "module": "Constants", 7974 "submodule": "Constants" 7975 }, { 7976 "file": "src/core/constants.js", 7977 "line": 316, 7978 "itemtype": "property", 7979 "name": "ROUND", 7980 "type": "String", 7981 "final": 1, 7982 "class": "p5", 7983 "module": "Constants", 7984 "submodule": "Constants" 7985 }, { 7986 "file": "src/core/constants.js", 7987 "line": 321, 7988 "itemtype": "property", 7989 "name": "BEVEL", 7990 "type": "String", 7991 "final": 1, 7992 "class": "p5
7992", 7993 "module": "Constants", 7994 "submodule": "Constants" 7995 }, { 7996 "file": "src/core/constants.js", 7997 "line": 326, 7998 "itemtype": "property", 7999 "name": "MITER", 8000 "type": "String", 8001 "final": 1, 8002 "class": "p5", 8003 "module": "Constants", 8004 "submodule": "Constants" 8005 }, { 8006 "file": "src/core/constants.js", 8007 "line": 333, 8008 "itemtype": "property", 8009 "name": "RGB", 8010 "type": "String", 8011 "final": 1, 8012 "class": "p5", 8013 "module": "Constants", 8014 "submodule": "Constants" 8015 }, { 8016 "file": "src/core/constants.js", 8017 "line": 338, 8018 "itemtype": "property", 8019 "name": "HSB", 8020 "type": "String", 8021 "final": 1, 8022 "class": "p5", 8023 "module": "Constants", 8024 "submodule": "Constants" 8025 }, { 8026 "file": "src/core/constants.js", 8027 "line": 343, 8028 "itemtype": "property", 8029 "name": "HSL", 8030 "type": "String", 8031 "final": 1, 8032 "class": "p5", 8033 "module": "Constants", 8034 "submodule": "Constants" 8035 }, { 8036 "file": "src/core/constants.js", 8037 "line": 350, 8038 "itemtype": "property", 8039 "name": "AUTO", 8040 "type": "String", 8041 "final": 1, 8042 "class": "p5", 8043 "module": "Constants", 8044 "submodule": "Constants" 8045 }, { 8046 "file": "src/core/constants.js", 8047 "line": 373, 8048 "itemtype": "property", 8049 "name": "BLEND", 8050 "type": "String", 8051 "final": 1, 8052 "default": "source-over", 8053 "class": "p5", 8054 "module": "Constants", 8055 "submodule": "Constants" 8056 }, { 8057 "file": "src/core/constants.js", 8058 "line": 379, 8059 "itemtype": "property", 8060 "name": "ADD", 8061 "type": "String", 8062 "final": 1, 8063 "default": "lighter", 8064 "class": "p5", 8065 "module": "Constants", 8066 "submodule": "Constants" 8067 }, { 8068 "file": "src/core/constants.js", 8069 "line": 387, 8070 "itemtype": "property", 8071 "name": "DARKEST", 8072 "type": "String", 8073 "final": 1, 8074 "class": "p5", 8075 "module": "Constants", 8076 "submodule": "Constants" 8077 }, { 8078 "file": "src/core/constants.js", 8079 "line": 392, 8080 "itemtype": "property", 8081 "name": "LIGHTEST", 8082 "type": "String", 8083 "final": 1, 8084 "default": "lighten", 8085 "class": "p5", 8086 "module": "Constants", 8087 "submodule": "Constants" 8088 }, { 8089 "file": "src/core/constants.js", 8090 "line": 398, 8091 "itemtype": "property", 8092 "name": "DIFFERENCE", 8093 "type": "String", 8094 "final": 1, 8095 "class": "p5", 8096 "module": "Constants", 8097 "submodule": "Constants" 8098 }, { 8099 "file": "src/core/constants.js", 8100 "line": 403, 8101 "itemtype": "property", 8102 "name": "EXCLUSION", 8103 "type": "String", 8104 "final": 1, 8105 "class": "p5", 8106 "module": "Constants", 8107 "submodule": "Constants" 8108 }, { 8109 "file": "src/core/constants.js", 8110 "line": 408, 8111 "itemtype": "property", 8112 "name": "MULTIPLY", 8113 "type": "String", 8114 "final": 1, 8115 "class": "p5", 8116 "module": "Constants", 8117 "submodule": "Constants" 8118 }, { 8119 "file": "src/core/constants.js", 8120 "line": 413, 8121 "itemtype": "property", 8122 "name": "SCREEN", 8123 "type": "String", 8124 "final": 1, 8125 "class": "p5", 8126 "module": "Constants", 8127 "submodule": "Constants" 8128 }, { 8129 "file": "src/core/constants.js", 8130 "line": 418, 8131 "itemtype": "property", 8132 "name": "REPLACE", 8133 "type": "String", 8134 "final": 1, 8135 "default": "copy", 8136 "class": "p5", 8137 "module": "Constants", 8138 "submodule": "Constants" 8139 }, { 8140 "file": "src/core/constants.js", 8141 "line": 424, 8142 "itemtype": "property", 8143 "name": "OVERLAY", 8144 "type": "String", 8145 "final": 1, 8146 "class": "p5", 8147 "module": "Constants", 8148 "submodule": "Constants" 8149 }, { 8150 "file": "src/core/constants.js", 8151 "line": 429, 8152 "itemtype": "property", 8153 "name": "HARD_LIGHT", 8154 "type": "String", 8155 "final": 1, 8156 "class": "p5", 8157 "module": "Constants", 8158 "submodule": "Constants" 8159 }, { 8160 "file": "src/core/constants.js", 8161 "line": 434, 8162 "itemtype": "property", 8163 "name": "SOFT_LIGHT", 8164 "type": "String", 8165 "final": 1, 8166 "class": "p5", 8167 "module": "Constants", 8168 "submodule": "Constants" 8169 }, { 8170 "file": "src/core/constants.js", 8171 "line": 439, 8172 "itemtype": "property", 8173 "name": "DODGE", 8174 "type": "String", 8175 "final": 1, 8176 "default": "color-dodge", 8177 "class": "p5", 8178 "module": "Constants", 8179 "submodule": "Constants" 8180 }, { 8181 "file": "src/core/constants.js", 8182 "line": 445, 8183 "itemtype": "property", 8184 "name": "BURN", 8185 "type": "String", 8186 "final": 1, 8187 "default": "color-burn", 8188 "class": "p5", 8189 "module": "Constants", 8190 "submodule": "Constants" 8191 }, { 8192 "file": "src/core/constants.js", 8193 "line": 453, 8194 "itemtype": "property", 8195 "name": "THRESHOLD", 8196 "type": "String", 8197 "final": 1, 8198 "class": "p5", 8199 "module": "Constants", 8200 "submodule": "Constants" 8201 }, { 8202 "file": "src/core/constants.js", 8203 "line": 458, 8204 "itemtype": "property", 8205 "name": "GRAY", 8206 "type": "String", 8207 "final": 1, 8208 "class": "p5", 8209 "module": "Constants", 8210 "submodule": "Constants" 8211 }, { 8212 "file": "src/core/constants.js", 8213 "line": 463, 8214 "itemtype": "property", 8215 "name": "OPAQUE", 8216 "type": "String", 8217 "final": 1, 8218 "class": "p5", 8219 "module": "Constants", 8220 "submodule": "Constants" 8221 }, { 8222 "file": "src/core/constants.js", 8223 "line": 468, 8224 "itemtype": "property", 8225 "name": "INVERT", 8226 "type": "String", 8227 "final": 1, 8228 "class": "p5", 8229 "module": "Constants", 8230 "submodule": "Constants" 8231 }, { 8232 "file": "src/core/constants.js", 8233 "line": 473, 8234 "itemtype": "property", 8235 "name": "POSTERIZE", 8236 "type": "String", 8237 "final": 1, 8238 "class": "p5", 8239 "module": "Constants", 8240 "submodule": "Constants" 8241 }, { 8242 "file": "src/core/constants.js", 8243 "line": 478, 8244 "itemtype": "property", 8245 "name": "DILATE", 8246 "type": "String", 8247 "final": 1, 8248 "class": "p5", 8249 "module": "Constants", 8250 "submodule": "Constants" 8251 }, { 8252 "file": "src/core/constants.js", 8253 "line": 483, 8254 "itemtype": "property", 8255 "name": "ERODE", 8256 "type": "String", 8257 "final": 1, 8258 "class": "p5", 8259 "module": "Constants", 8260 "submodule": "Constants" 8261 }, { 8262 "file": "src/core/constants.js", 8263 "line": 488, 8264 "itemtype": "property", 8265 "name": "BLUR", 8266 "type": "String", 8267 "final": 1, 8268 "class": "p5", 8269 "module": "Constants", 8270 "submodule": "Constants" 8271 }, { 8272 "file": "src/core/constants.js", 8273 "line": 495, 8274 "itemtype": "property", 8275 "name": "NORMAL", 8276 "type": "String", 8277 "final": 1, 8278 "class": "p5", 8279 "module": "Constants", 8280 "submodule": "Constants" 8281 }, { 8282 "file": "src/core/constants.js", 8283 "line": 500, 8284 "itemtype": "property", 8285 "name": "ITALIC", 8286 "type": "String", 8287 "final": 1, 8288 "class": "p5", 8289 "module": "Constants", 8290 "submodule": "Constants" 8291 }, { 8292 "file": "src/core/constants.js", 8293 "line": 505, 8294 "itemtype": "property", 8295 "name": "BOLD", 8296 "type": "String", 8297 "final": 1, 8298 "class": "p5", 8299 "module": "Constants", 8300 "submodule": "Constants" 8301 }, { 8302 "file": "src/core/constants.js", 8303 "line": 510, 8304 "itemtype": "property", 8305 "name": "BOLDITALIC", 8306 "type": "String", 8307 "final": 1, 8308 "class": "p5", 8309 "module": "Constants", 8310 "submodule": "Constants" 8311 }, { 8312 "file": "src/core/constants.js", 8313 "line": 545, 8314 "itemtype": "property", 8315 "name": "LANDSCAPE", 8316 "type": "String", 8317 "final": 1, 8318 "class": "p5", 8319 "module": "Constants", 8320 "submodule": "Constants" 8321 }, { 8322 "file": "src/core/constants.js", 8323 "line": 550, 8324 "itemtype": "property", 8325 "name": "PORTRAIT", 8326 "type": "String", 8327 "final": 1, 8328 "class": "p5", 8329 "module": "Constants", 8330 "submodule": "Constants" 8331 }, { 8332 "file": "src/core/constants.js", 8333 "line": 560, 8334 "itemtype": "property", 8335 "name": "GRID", 8336 "type": "String", 8337 "final": 1, 8338 "class": "p5", 8339 "module": "Constants", 8340 "submodule": "Constants" 8341 }, { 8342 "file": "src/core/constants.js", 8343 "line": 566, 8344 "itemtype": "property", 8345 "name": "AXES", 8346 "type": "String", 8347 "final": 1, 8348 "class": "p5", 8349 "module": "Constants", 8350 "submodule": "Constants" 8351 }, { 8352 "file": "src/core/environment.js", 8353 "line": 22, 8354 "description": "<p>The <a href=\"#/p5/print\">print()</a> function writes to the console area of your browser.\nThis function is often helpful for looking at the data a program is\nproducing. This function creates a new line of text for each call to\nthe function. Individual elements can be\nseparated with quotes ("") and joined with the addition operator (+).</p>\n<p>Note that calling print() without any arguments invokes the window.print()\nfunction which opens the browser's print dialog. To print a blank line\nto console you can write print('\\n').</p>\n", 8355 "itemtype": "method", 8356 "name": "print", 8357 "params": [{ 8358 "name": "contents", 8359 "description": "<p>any combination of Number, String, Object, Boolean,\n Array to print</p>\n", 8360 "type": "Any" 8361 }], 8362 "example": ["\n<div><code class='norender'>\nlet x = 10;\nprint('The value of x is ' + x);\n// prints \"The value of x is 10\"\n</code></div>"], 8363 "alt": "default grey canvas", 8364 "class": "p5", 8365 "module": "Environment", 8366 "submodule": "Environment" 8367 }, { 8368 "file": "src/core/environment.js", 8369 "line": 53, 8370 "description": "<p>The system variable <a href=\"#/p5/frameCount\">frameCount</a> contains the number of frames that have\nbeen displayed since the program started. Inside <a href=\"#/p5/setup\">setup()</a> the value is 0,\nafter the first iteration of draw it is 1, etc.</p>\n", 8371 "itemtype": "property", 8372 "name": "frameCount", 8373 "type": "Integer", 8374 "readonly": "", 8375 "example": ["\n <div><code>\nfunction setup() {\n frameRate(30);\n textSize(30);\n textAlign(CENTER);\n}\n\nfunction draw() {\n background(200);\n text(frameCount, width / 2, height / 2);\n}\n</code></div>"], 8376 "alt": "numbers rapidly counting upward with frame count set to 30.", 8377 "class": "p5", 8378 "module": "Environment", 8379 "submodule": "Environment" 8380 }, { 8381 "file": "src/core/environment.js", 8382 "line": 80, 8383 "description": "<p>Confirms if the window a p5.js program is in is "focused," meaning that\nthe sketch will accept mouse or keyboard input. This variable is\n"true" if the window is focused and "false" if not.</p>\n", 8384 "itemtype": "property", 8385 "name": "focused", 8386 "type": "Boolean", 8387 "readonly": "", 8388 "example": ["\n<div><code>\n// To demonstrate, put two windows side by side.\n// Click on the window that the p5 sketch isn't in!\nfunction draw() {\n background(200);\n noStroke();\n fill(0, 200, 0);\n ellipse(25, 25, 50, 50);\n\n if (!focused) {\n // or \"if (focused === false)\"\n stroke(200, 0, 0);\n line(0, 0, 100, 100);\n line(100, 0, 0, 100);\n }\n}\n</code></div>"], 8389 "alt": "green 50x50 ellipse at top left. Red X covers canvas when page focus changes", 8390 "class": "p5", 8391 "module": "Environment", 8392 "submodule": "Environment" 8393 }, { 8394 "file": "src/core/environment.js", 8395 "line": 112, 8396 "description": "<p>Sets the cursor to a predefined symbol or an image, or makes it visible\nif already hidden. If you are trying to set an image as the cursor, the\nrecommended size is 16x16 or 32x32 pixels. The values for parameters x and y\nmust be less than the dimensions of the image.</p>\n", 8397 "itemtype": "method", 8398 "name": "cursor", 8399 "params": [{ 8400 "name": "type", 8401 "description": "<p>Built-In: either ARROW, CROSS, HAND, MOVE, TEXT and WAIT\n Native CSS properties: 'grab', 'progress', 'cell' etc.\n External: path for cursor's images\n (Allowed File extensions: .cur, .gif, .jpg, .jpeg, .png)\n For more information on Native CSS cursors and url visit:\n <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/cursor\">https://developer.mozilla.org/en-US/docs/Web/CSS/cursor</a></p>\n", 8402 "type": "String|Constant" 8403 }, { 8404 "name": "x", 8405 "description": "<p>the horizontal active spot of the cursor (must be less than 32)</p>\n", 8406 "type": "Number", 8407 "optional": true 8408 }, { 8409 "name": "y", 8410 "description": "<p>the vertical active spot of the cursor (must be less than 32)</p>\n", 8411 "type": "Number", 8412 "optional": true 8413 }], 8414 "example": ["\n<div><code>
8414\n// Move the mouse across the quadrants\n// to see the cursor change\nfunction draw() {\n line(width / 2, 0, width / 2, height);\n line(0, height / 2, width, height / 2);\n if (mouseX < 50 && mouseY < 50) {\n cursor(CROSS);\n } else if (mouseX > 50 && mouseY < 50) {\n cursor('progress');\n } else if (mouseX > 50 && mouseY > 50) {\n cursor('https://s3.amazonaws.com/mupublicdata/cursor.cur');\n } else {\n cursor('grab');\n }\n}\n</code></div>"], 8415 "alt": "canvas is divided into four quadrants. cursor on first is a cross, second is a progress,\nthird is a custom cursor using path to the cursor and fourth is a grab.", 8416 "class": "p5", 8417 "module": "Environment", 8418 "submodule": "Environment" 8419 }, { 8420 "file": "src/core/environment.js", 8421 "line": 181, 8422 "description": "<p>Specifies the number of frames to be displayed every second. For example,\nthe function call frameRate(30) will attempt to refresh 30 times a second.\nIf the processor is not fast enough to maintain the specified rate, the\nframe rate will not be achieved. Setting the frame rate within <a href=\"#/p5/setup\">setup()</a> is\nrecommended. The default frame rate is based on the frame rate of the display\n(here also called "refresh rate"), which is set to 60 frames per second on most\ncomputers. A frame rate of 24 frames per second (usual for movies) or above\nwill be enough for smooth animations\nThis is the same as setFrameRate(val).\n<br><br>\nCalling <a href=\"#/p5/frameRate\">frameRate()</a> with no arguments returns the current framerate. The\ndraw function must run at least once before it will return a value. This\nis the same as <a href=\"#/p5/getFrameRate\">getFrameRate()</a>.\n<br><br>\nCalling <a href=\"#/p5/frameRate\">frameRate()</a> with arguments that are not of the type numbers\nor are non positive also returns current framerate.</p>\n", 8423 "itemtype": "method", 8424 "name": "frameRate", 8425 "chainable": 1, 8426 "example": ["\n\n<div><code>\nlet rectX = 0;\nlet fr = 30; //starting FPS\nlet clr;\n\nfunction setup() {\n background(200);\n frameRate(fr); // Attempt to refresh at starting FPS\n clr = color(255, 0, 0);\n}\n\nfunction draw() {\n background(200);\n rectX = rectX += 1; // Move Rectangle\n\n if (rectX >= width) {\n // If you go off screen.\n if (fr === 30) {\n clr = color(0, 0, 255);\n fr = 10;\n frameRate(fr); // make frameRate 10 FPS\n } else {\n clr = color(255, 0, 0);\n fr = 30;\n frameRate(fr); // make frameRate 30 FPS\n }\n rectX = 0;\n }\n fill(clr);\n rect(rectX, 40, 20, 20);\n}\n</code></div>"], 8427 "alt": "blue rect moves left to right, followed by red rect moving faster. Loops.", 8428 "class": "p5", 8429 "module": "Environment", 8430 "submodule": "Environment", 8431 "overloads": [{ 8432 "line": 181, 8433 "params": [{ 8434 "name": "fps", 8435 "description": "<p>number of frames to be displayed every second</p>\n", 8436 "type": "Number" 8437 }], 8438 "chainable": 1 8439 }, { 8440 "line": 242, 8441 "params": [], 8442 "return": { 8443 "description": "current frameRate", 8444 "type": "Number" 8445 } 8446 }] 8447 }, { 8448 "file": "src/core/environment.js", 8449 "line": 281, 8450 "description": "<p>Hides the cursor from view.</p>\n", 8451 "itemtype": "method", 8452 "name": "noCursor", 8453 "example": ["\n<div><code>\nfunction setup() {\n noCursor();\n}\n\nfunction draw() {\n background(200);\n ellipse(mouseX, mouseY, 10, 10);\n}\n</code></div>"], 8454 "alt": "cursor becomes 10x 10 white ellipse the moves with mouse x and y.", 8455 "class": "p5", 8456 "module": "Environment", 8457 "submodule": "Environment" 8458 }, { 8459 "file": "src/core/environment.js", 8460 "line": 306, 8461 "description": "<p>System variable that stores the width of the screen display according to The\ndefault <a href=\"#/p5/pixelDensity\">pixelDensity</a>. This is used to run a\nfull-screen program on any display size. To return actual screen size,\nmultiply this by pixelDensity.</p>\n", 8462 "itemtype": "property", 8463 "name": "displayWidth", 8464 "type": "Number", 8465 "readonly": "", 8466 "example": ["\n<div class=\"norender\"><code>\ncreateCanvas(displayWidth, displayHeight);\n</code></div>"], 8467 "alt": "cursor becomes 10x 10 white ellipse the moves with mouse x and y.", 8468 "class": "p5", 8469 "module": "Environment", 8470 "submodule": "Environment" 8471 }, { 8472 "file": "src/core/environment.js", 8473 "line": 325, 8474 "description": "<p>System variable that stores the height of the screen display according to The\ndefault <a href=\"#/p5/pixelDensity\">pixelDensity</a>. This is used to run a\nfull-screen program on any display size. To return actual screen size,\nmultiply this by pixelDensity.</p>\n", 8475 "itemtype": "property", 8476 "name": "displayHeight", 8477 "type": "Number", 8478 "readonly": "", 8479 "example": ["\n<div class=\"norender\"><code>\ncreateCanvas(displayWidth, displayHeight);\n</code></div>"],
8480 "alt": "no display.", 8481 "class": "p5", 8482 "module": "Environment", 8483 "submodule": "Environment" 8484 }, { 8485 "file": "src/core/environment.js", 8486 "line": 344, 8487 "description": "<p>System variable that stores the width of the inner window, it maps to\nwindow.innerWidth.</p>\n", 8488 "itemtype": "property", 8489 "name": "windowWidth", 8490 "type": "Number", 8491 "readonly": "", 8492 "example": ["\n<div class=\"norender\"><code>\ncreateCanvas(windowWidth, windowHeight);\n</code></div>"], 8493 "alt": "no display.", 8494 "class": "p5", 8495 "module": "Environment", 8496 "submodule": "Environment" 8497 }, { 8498 "file": "src/core/environment.js", 8499 "line": 360, 8500 "description": "<p>System variable that stores the height of the inner window, it maps to\nwindow.innerHeight.</p>\n", 8501 "itemtype": "property", 8502 "name": "windowHeight", 8503 "type": "Number", 8504 "readonly": "", 8505 "example": ["\n<div class=\"norender\"><code>\ncreateCanvas(windowWidth, windowHeight);\n</code></div>"], 8506 "alt": "no display.", 8507 "class": "p5", 8508 "module": "Environment", 8509 "submodule": "Environment" 8510 }, { 8511 "file": "src/core/environment.js", 8512 "line": 376, 8513 "description": "<p>The <a href=\"#/p5/windowResized\">windowResized()</a> function is called once every time the browser window\nis resized. This is a good place to resize the canvas or do any other\nadjustments to accommodate the new window size.</p>\n", 8514 "itemtype": "method", 8515 "name": "windowResized", 8516 "example": ["\n<div class=\"norender\"><code>\nfunction setup() {\n createCanvas(windowWidth, windowHeight);\n}\n\nfunction draw() {\n background(0, 100, 200);\n}\n\nfunction windowResized() {\n resizeCanvas(windowWidth, windowHeight);\n}\n</code></div>"], 8517 "alt": "no display.", 8518 "class": "p5", 8519 "module": "Environment", 8520 "submodule": "Environment" 8521 }, { 8522 "file": "src/core/environment.js", 8523 "line": 430, 8524 "description": "<p>System variable that stores the width of the drawing canvas. This value\nis set by the first parameter of the <a href=\"#/p5/createCanvas\">createCanvas()</a> function.\nFor example, the function call createCanvas(320, 240) sets the width\nvariable to the value 320. The value of width defaults to 100 if\n<a href=\"#/p5/createCanvas\">createCanvas()</a> is not used in a program.</p>\n", 8525 "itemtype": "property", 8526 "name": "width", 8527 "type": "Number", 8528 "readonly": "", 8529 "class": "p5", 8530 "module": "Environment", 8531 "submodule": "Environment" 8532 }, { 8533 "file": "src/core/environment.js", 8534 "line": 442, 8535 "description": "<p>System variable that stores the height of the drawing canvas. This value\nis set by the second parameter of the <a href=\"#/p5/createCanvas\">createCanvas()</a> function. For\nexample, the function call createCanvas(320, 240) sets the height\nvariable to the value 240. The value of height defaults to 100 if\n<a href=\"#/p5/createCanvas\">createCanvas()</a> is not used in a program.</p>\n", 8536 "itemtype": "property", 8537 "name": "height", 8538 "type": "Number", 8539 "readonly": "", 8540 "class": "p5", 8541 "module": "Environment", 8542 "submodule": "Environment" 8543 }, { 8544 "file": "src/core/environment.js", 8545 "line": 454, 8546 "description": "<p>If argument is given, sets the sketch to fullscreen or not based on the\nvalue of the argument. If no argument is given, returns the current\nfullscreen state. Note that due to browser restrictions this can only\nbe called on user input, for example, on mouse press like the example\nbelow.</p>\n", 8547 "itemtype": "method", 8548 "name": "fullscreen", 8549 "params": [{ 8550 "name": "val", 8551 "description": "<p>whether the sketch should be in fullscreen mode\nor not</p>\n", 8552 "type": "Boolean", 8553 "optional": true 8554 }], 8555 "return": { 8556 "description": "current fullscreen state", 8557 "type": "Boolean" 8558 }, 8559 "example": ["\n<div>\n<code>\n// Clicking in the box toggles fullscreen on and off.\nfunction setup() {\n background(200);\n}\nfunction mousePressed() {\n if (mouseX > 0 && mouseX < 100 && mouseY > 0 && mouseY < 100) {\n let fs = fullscreen();\n fullscreen(!fs);\n }\n}\n</code>\n</div>"],
8560 "alt": "no display.", 8561 "class": "p5", 8562 "module": "Environment", 8563 "submodule": "Environment" 8564 }, { 8565 "file": "src/core/environment.js", 8566 "line": 505, 8567 "description": "<p>Sets the pixel scaling for high pixel density displays. By default\npixel density is set to match display density, call pixelDensity(1)\nto turn this off. Calling <a href=\"#/p5/pixelDensity\">pixelDensity()</a> with no arguments returns\nthe current pixel density of the sketch.</p>\n", 8568 "itemtype": "method", 8569 "name": "pixelDensity", 8570 "chainable": 1, 8571 "example": ["\n<div>\n<code>\nfunction setup() {\n pixelDensity(1);\n createCanvas(100, 100);\n background(200);\n ellipse(width / 2, height / 2, 50, 50);\n}\n</code>\n</div>\n<div>\n<code>\nfunction setup() {\n pixelDensity(3.0);\n createCanvas(100, 100);\n background(200);\n ellipse(width / 2, height / 2, 50, 50);\n}\n</code>\n</div>"], 8572 "alt": "fuzzy 50x50 white ellipse with black outline in center of canvas.\nsharp 50x50 white ellipse with black outline in center of canvas.", 8573 "class": "p5", 8574 "module": "Environment", 8575 "submodule": "Environment", 8576 "overloads": [{ 8577 "line": 505, 8578 "params": [{ 8579 "name": "val", 8580 "description": "<p>whether or how much the sketch should scale</p>\n", 8581 "type": "Number" 8582 }], 8583 "chainable": 1 8584 }, { 8585 "line": 540, 8586 "params": [], 8587 "return": { 8588 "description": "current pixel density of the sketch", 8589 "type": "Number" 8590 } 8591 }] 8592 }, { 8593 "file": "src/core/environment.js", 8594 "line": 560, 8595 "description": "<p>Returns the pixel density of the current display the sketch is running on.</p>\n", 8596 "itemtype": "method", 8597 "name": "displayDensity", 8598 "return": { 8599 "description": "current pixel density of the display", 8600 "type": "Number" 8601 }, 8602 "example": ["\n<div>\n<code>\nfunction setup() {\n let density = displayDensity();\n pixelDensity(density);\n createCanvas(100, 100);\n background(200);\n ellipse(width / 2, height / 2, 50, 50);\n}\n</code>\n</div>"], 8603 "alt": "50x50 white ellipse with black outline in center of canvas.", 8604 "class": "p5", 8605 "module": "Environment", 8606 "submodule": "Environment" 8607 }, { 8608 "file": "src/core/environment.js", 8609 "line": 617, 8610 "description": "<p>Gets the current URL.</p>\n", 8611 "itemtype": "method", 8612 "name": "getURL", 8613 "return": { 8614 "description": "url", 8615 "type": "String" 8616 }, 8617 "example": ["\n<div>\n<code>\nlet url;\nlet x = 100;\n\nfunction setup() {\n fill(0);\n noStroke();\n url = getURL();\n}\n\nfunction draw() {\n background(200);\n text(url, x, height / 2);\n x--;\n}\n</code>\n</div>"], 8618 "alt": "current url (http://p5js.org/reference/#/p5/getURL) moves right to left.", 8619 "class": "p5", 8620 "module": "Environment", 8621 "submodule": "Environment" 8622 }, { 8623 "file": "src/core/environment.js", 8624 "line": 648, 8625 "description": "<p>Gets the current URL path as an array.</p>\n", 8626 "itemtype": "method", 8627 "name": "getURLPath", 8628 "return": { 8629 "description": "path components", 8630 "type": "String[]" 8631 }, 8632 "example": ["\n<div class='norender'><code>\nfunction setup() {\n let urlPath = getURLPath();\n for (let i = 0; i < urlPath.length; i++) {\n text(urlPath[i], 10, i * 20 + 20);\n }\n}\n</code></div>"], 8633 "alt": "no display", 8634 "class": "p5", 8635 "module": "Environment", 8636 "submodule": "Environment" 8637 }, { 8638 "file": "src/core/environment.js", 8639 "line": 671, 8640 "description": "<p>Gets the current URL params as an Object.</p>\n", 8641 "itemtype": "method", 8642 "name": "getURLParams", 8643 "return": { 8644 "description": "URL params", 8645 "type": "Object" 8646 }, 8647 "example": ["\n<div class='norender notest'>\n<code>\n// Example: http://p5js.org?year=2014&month=May&day=15\n\nfunction setup() {\n let params = getURLParams();\n text(params.day, 10, 20);\n text(params.month, 10, 40);\n text(params.year, 10, 60);\n}\n</code>\n</div>"],
8648 "alt": "no display.", 8649 "class": "p5", 8650 "module": "Environment", 8651 "submodule": "Environment" 8652 }, { 8653 "file": "src/core/error_helpers.js", 8654 "line": 1, 8655 "requires": ["core"], 8656 "class": "p5", 8657 "module": "Environment" 8658 }, { 8659 "file": "src/core/error_helpers.js", 8660 "line": 584, 8661 "description": "<p>Validates parameters\nparam {String} func the name of the function\nparam {Array} args user input arguments</p>\n<p>example:\n var a;\n ellipse(10,10,a,5);\nconsole ouput:\n "It looks like ellipse received an empty variable in spot #2."</p>\n<p>example:\n ellipse(10,"foo",5,5);\nconsole output:\n "ellipse was expecting a number for parameter #1,\n received "foo" instead."</p>\n", 8662 "class": "p5", 8663 "module": "Environment" 8664 }, { 8665 "file": "src/core/error_helpers.js", 8666 "line": 645, 8667 "description": "<p>Prints out all the colors in the color pallete with white text.\nFor color blindness testing.</p>\n", 8668 "class": "p5", 8669 "module": "Environment" 8670 }, { 8671 "file": "src/core/helpers.js", 8672 "line": 1, 8673 "requires": ["constants"], 8674 "class": "p5", 8675 "module": "Environment" 8676 }, { 8677 "file": "src/core/legacy.js", 8678 "line": 1, 8679 "requires": ["core\nThese are functions that are part of the Processing API but are not part of\nthe p5.js API. In some cases they have a new name", "in others", "they are\nremoved completely. Not all unsupported Processing functions are listed here\nbut we try to include ones that a user coming from Processing might likely\ncall."], 8680 "class": "p5", 8681 "module": "Environment" 8682 }, { 8683 "file": "src/core/main.js", 8684 "line": 49, 8685 "description": "<p>Called directly before <a href=\"#/p5/setup\">setup()</a>, the <a href=\"#/p5/preload\">preload()</a> function is used to handle\nasynchronous loading of external files in a blocking way. If a preload\nfunction is defined, <a href=\"#/p5/setup\">setup()</a> will wait until any load calls within have\nfinished. Nothing besides load calls (<a href=\"#/p5/loadImage\">loadImage</a>, <a href=\"#/p5/loadJSON\">loadJSON</a>, <a href=\"#/p5/loadFont\">loadFont</a>,\n<a href=\"#/p5/loadStrings\">loadStrings</a>, etc.) should be inside the preload function. If asynchronous\nloading is preferred, the load methods can instead be called in <a href=\"#/p5/setup\">setup()</a>\nor anywhere else with the use of a callback parameter.\n<br><br>\nBy default the text "loading..." will be displayed. To make your own\nloading page, include an HTML element with id "p5_loading" in your\npage. More information <a href=\"http://bit.ly/2kQ6Nio\">here</a>.</p>\n", 8686 "itemtype": "method", 8687 "name": "preload", 8688 "example": ["\n<div><code>\nlet img;\nlet c;\nfunction preload() {\n // preload() runs once\n img = loadImage('assets/laDefense.jpg');\n}\n\nfunction setup() {\n // setup() waits until preload() is done\n img.loadPixels();\n // get color of middle pixel\n c = img.get(img.width / 2, img.height / 2);\n}\n\nfunction draw() {\n background(c);\n image(img, 25, 25, 50, 50);\n}\n</code></div>"], 8689 "alt": "nothing displayed", 8690 "class": "p5", 8691 "module": "Structure", 8692 "submodule": "Structure" 8693 }, { 8694 "file": "src/core/main.js", 8695 "line": 90, 8696 "description": "<p>The <a href=\"#/p5/setup\">setup()</a> function is called once when the program starts. It's used to\ndefine initial environment properties such as screen size and background\ncolor and to load media such as images and fonts as the program starts.\nThere can only be one <a href=\"#/p5/setup\">setup()</a> function for each program and it shouldn't\nbe called again after its initial execution.\n<br><br>\nNote: Variables declared within <a href=\"#/p5/setup\">setup()</a> are not accessible within other\nfunctions, including <a href=\"#/p5/draw\">draw()</a>.</p>\n", 8697 "itemtype": "method", 8698 "name": "setup", 8699 "example": ["\n<div><code>\nlet a = 0;\n\nfunction setup() {\n background(0);\n noStroke();\n fill(102);\n}\n\nfunction draw() {\n rect(a++ % width, 10, 2, 80);\n}\n</code></div>"], 8700 "alt": "nothing displayed", 8701 "class": "p5", 8702 "module": "Structure", 8703 "submodule": "Structure" 8704 }, { 8705 "file": "src/core/main.js", 8706 "line": 121, 8707 "description": "<p>Called directly after <a href=\"#/p5/setup\">setup()</a>, the <a href=\"#/p5/draw\">draw()</a> function continuously executes\nthe lines of code contained inside its block until the program is stopped\nor <a href=\"#/p5/noLoop\">noLoop()</a> is called. Note if <a href=\"#/p5/noLoop\">noLoop()</a>
8707 is called in <a href=\"#/p5/setup\">setup()</a>, <a href=\"#/p5/draw\">draw()</a> will\nstill be executed once before stopping. <a href=\"#/p5/draw\">draw()</a> is called automatically and\nshould never be called explicitly.\n<br><br>\nIt should always be controlled with <a href=\"#/p5/noLoop\">noLoop()</a>, <a href=\"#/p5/redraw\">redraw()</a> and <a href=\"#/p5/loop\">loop()</a>. After\n<a href=\"#/p5/noLoop\">noLoop()</a> stops the code in <a href=\"#/p5/draw\">draw()</a> from executing, <a href=\"#/p5/redraw\">redraw()</a> causes the\ncode inside <a href=\"#/p5/draw\">draw()</a> to execute once, and <a href=\"#/p5/loop\">loop()</a> will cause the code\ninside <a href=\"#/p5/draw\">draw()</a> to resume executing continuously.\n<br><br>\nThe number of times <a href=\"#/p5/draw\">draw()</a> executes in each second may be controlled with\nthe <a href=\"#/p5/frameRate\">frameRate()</a> function.\n<br><br>\nThere can only be one <a href=\"#/p5/draw\">draw()</a> function for each sketch, and <a href=\"#/p5/draw\">draw()</a> must\nexist if you want the code to run continuously, or to process events such\nas <a href=\"#/p5/mousePressed\">mousePressed()</a>. Sometimes, you might have an empty call to <a href=\"#/p5/draw\">draw()</a> in\nyour program, as shown in the above example.\n<br><br>\nIt is important to note that the drawing coordinate system will be reset\nat the beginning of each <a href=\"#/p5/draw\">draw()</a> call. If any transformations are performed\nwithin <a href=\"#/p5/draw\">draw()</a> (ex: scale, rotate, translate), their effects will be\nundone at the beginning of <a href=\"#/p5/draw\">draw()</a>, so transformations will not accumulate\nover time. On the other hand, styling applied (ex: fill, stroke, etc) will\nremain in effect.</p>\n", 8708 "itemtype": "method", 8709 "name": "draw", 8710 "example": ["\n<div><code>\nlet yPos = 0;\nfunction setup() {\n // setup() runs once\n frameRate(30);\n}\nfunction draw() {\n // draw() loops forever, until stopped\n background(204);\n yPos = yPos - 1;\n if (yPos < 0) {\n yPos = height;\n }\n line(0, yPos, width, yPos);\n}\n</code></div>"], 8711 "alt": "nothing displayed", 8712 "class": "p5", 8713 "module": "Structure", 8714 "submodule": "Structure" 8715 }, { 8716 "file": "src/core/main.js", 8717 "line": 400, 8718 "description": "<p>Removes the entire p5 sketch. This will remove the canvas and any\nelements created by p5.js. It will also stop the draw loop and unbind\nany properties or methods from the window global scope. It will\nleave a variable p5 in case you wanted to create a new p5 sketch.\nIf you like, you can set p5 = null to erase it. While all functions and\nvariables and objects created by the p5 library will be removed, any\nother global variables created by your code will remain.</p>\n", 8719 "itemtype": "method", 8720 "name": "remove", 8721 "example": ["\n<div class='norender'><code>\nfunction draw() {\n ellipse(50, 50, 10, 10);\n}\n\nfunction mousePressed() {\n remove(); // remove whole sketch on mouse press\n}\n</code></div>"], 8722 "alt": "nothing displayed", 8723 "class": "p5", 8724 "module": "Structure", 8725 "submodule": "Structure" 8726 }, { 8727 "file": "src/core/p5.Element.js", 8728 "line": 26, 8729 "description": "<p>Underlying HTML element. All normal HTML methods can be called on this.</p>\n", 8730 "example": ["\n<div>\n<code>\nfunction setup() {\n var c = createCanvas(50, 50);\n c.elt.style.border = '5px solid red';\n}\n\nfunction draw() {\n background(220);\n}\n</code>\n</div>"], 8731 "itemtype": "property", 8732 "name": "elt", 8733 "readonly": "", 8734 "class": "p5.Element", 8735 "module": "DOM", 8736 "submodule": "DOM" 8737 }, { 8738 "file": "src/core/p5.Element.js", 8739 "line": 52, 8740 "description": "<p>Attaches the element to the parent specified. A way of setting\n the container for the element. Accepts either a string ID, DOM\n node, or <a href=\"#/p5.Element\">p5.Element</a>. If no arguments given, parent node is returned.\n For more ways to position the canvas, see the\n <a href='https://github.com/processing/p5.js/wiki/Positioning-your-canvas'>\n positioning the canvas</a> wiki page.\nAll above examples except for the first one require the inclusion of\n the p5.dom library in your index.html. See the\n <a href='http://p5js.org/libraries/#using-a-library'>using a library</a>\n section for information on how to include this library.</p>\n", 8741 "itemtype": "method", 8742 "name": "parent", 8743 "chainable": 1, 8744 "example": ["\n <div class=\"norender notest\"><code>\n // in the html file:\n // <div id=\"myContainer\"></div>\n// in the js file:\n var cnv = createCanvas(100, 100);\n cnv.parent('myContainer');\n </code></div>\n <div class='norender'><code>\n var div0 = createDiv('this is the parent');\n var div1 = createDiv('this is the child');\n div1.parent(div0); // use p5.Element\n </code></div>\n <div class='norender'><code>\n var div0 = createDiv('this is the parent');\n div0.id('apples');\n var div1 = createDiv('this is the child');\n div1.parent('apples'); // use id\n </code></div>\n <div class='norender notest'><code>\n var elt = document.getElementById('myParentDiv');\n var div1 = createDiv('this is the child');\n div1.parent(elt);
8744 // use element from page\n </code></div>"], 8745 "alt": "no display.", 8746 "class": "p5.Element", 8747 "module": "DOM", 8748 "submodule": "DOM", 8749 "overloads": [{ 8750 "line": 52, 8751 "params": [{ 8752 "name": "parent", 8753 "description": "<p>the ID, DOM node, or <a href=\"#/p5.Element\">p5.Element</a>\n of desired parent element</p>\n", 8754 "type": "String|p5.Element|Object" 8755 }], 8756 "chainable": 1 8757 }, { 8758 "line": 100, 8759 "params": [], 8760 "return": { 8761 "description": "", 8762 "type": "p5.Element" 8763 } 8764 }] 8765 }, { 8766 "file": "src/core/p5.Element.js", 8767 "line": 122, 8768 "description": "<p>Sets the ID of the element. If no ID argument is passed in, it instead\n returns the current ID of the element.</p>\n", 8769 "itemtype": "method", 8770 "name": "id", 8771 "chainable": 1, 8772 "example": ["\n <div class='norender'><code>\n function setup() {\n var cnv = createCanvas(100, 100);\n // Assigns a CSS selector ID to\n // the canvas element.\n cnv.id('mycanvas');\n }\n </code></div>"], 8773 "alt": "no display.", 8774 "class": "p5.Element", 8775 "module": "DOM", 8776 "submodule": "DOM", 8777 "overloads": [{ 8778 "line": 122, 8779 "params": [{ 8780 "name": "id", 8781 "description": "<p>ID of the element</p>\n", 8782 "type": "String" 8783 }], 8784 "chainable": 1 8785 }, { 8786 "line": 144, 8787 "params": [], 8788 "return": { 8789 "description": "the id of the element", 8790 "type": "String" 8791 } 8792 }] 8793 }, { 8794 "file": "src/core/p5.Element.js", 8795 "line": 159, 8796 "description": "<p>Adds given class to the element. If no class argument is passed in, it\n instead returns a string containing the current class(es) of the element.</p>\n", 8797 "itemtype": "method", 8798 "name": "class", 8799 "chainable": 1, 8800 "example": ["\n <div class='norender'><code>\n function setup() {\n var cnv = createCanvas(100, 100);\n // Assigns a CSS selector class 'small'\n // to the canvas element.\n cnv.class('small');\n }\n </code></div>"], 8801 "alt": "no display.", 8802 "class": "p5.Element", 8803 "module": "DOM", 8804 "submodule": "DOM", 8805 "overloads": [{ 8806 "line": 159, 8807 "params": [{ 8808 "name": "class", 8809 "description": "<p>class to add</p>\n", 8810 "type": "String" 8811 }], 8812 "chainable": 1 8813 }, { 8814 "line": 181, 8815 "params": [], 8816 "return": { 8817 "description": "the class of the element", 8818 "type": "String" 8819 } 8820 }] 8821 }, { 8822 "file": "src/core/p5.Element.js", 8823 "line": 194, 8824 "description": "<p>The .<a href=\"#/p5.Element/mousePressed\">mousePressed()</a> function is called once after every time a\nmouse button is pressed over the element.\nSome mobile browsers may also trigger this event on a touch screen,\nif the user performs a quick tap.\nThis can be used to attach element specific event listeners.</p>\n", 8825 "itemtype": "method", 8826 "name": "mousePressed", 8827 "params": [{ 8828 "name": "fxn", 8829 "description": "<p>function to be fired when mouse is\n pressed over the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8830 "type": "Function|Boolean" 8831 }], 8832 "chainable": 1, 8833 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar d;\nvar g;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.mousePressed(changeGray); // attach listener for\n // canvas click only\n d = 10;\n g = 100;\n}\n\nfunction draw() {\n background(g);\n ellipse(width / 2, height / 2, d, d);\n}
8833\n\n// this function fires with any click anywhere\nfunction mousePressed() {\n d = d + 10;\n}\n\n// this function fires only when cnv is clicked\nfunction changeGray() {\n g = random(0, 255);\n}\n</code></div>"], 8834 "alt": "no display.", 8835 "class": "p5.Element", 8836 "module": "DOM", 8837 "submodule": "DOM" 8838 }, { 8839 "file": "src/core/p5.Element.js", 8840 "line": 255, 8841 "description": "<p>The .<a href=\"#/p5.Element/doubleClicked\">doubleClicked()</a> function is called once after every time a\nmouse button is pressed twice over the element. This can be used to\nattach element and action specific event listeners.</p>\n", 8842 "itemtype": "method", 8843 "name": "doubleClicked", 8844 "params": [{ 8845 "name": "fxn", 8846 "description": "<p>function to be fired when mouse is\n double clicked over the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8847 "type": "Function|Boolean" 8848 }], 8849 "return": { 8850 "description": "", 8851 "type": "p5.Element" 8852 }, 8853 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar d;\nvar g;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.doubleClicked(changeGray); // attach listener for\n // canvas double click only\n d = 10;\n g = 100;\n}\n\nfunction draw() {\n background(g);\n ellipse(width / 2, height / 2, d, d);\n}\n\n// this function fires with any double click anywhere\nfunction doubleClicked() {\n d = d + 10;\n}\n\n// this function fires only when cnv is double clicked\nfunction changeGray() {\n g = random(0, 255);\n}\n</code></div>"], 8854 "alt": "no display.", 8855 "class": "p5.Element", 8856 "module": "DOM", 8857 "submodule": "DOM" 8858 }, { 8859 "file": "src/core/p5.Element.js", 8860 "line": 304, 8861 "description": "<p>The .<a href=\"#/p5.Element/mouseWheel\">mouseWheel()</a> function is called once after every time a\nmouse wheel is scrolled over the element. This can be used to\nattach element specific event listeners.\n<br><br>\nThe function accepts a callback function as argument which will be executed\nwhen the <code>wheel</code> event is triggered on the element, the callback function is\npassed one argument <code>event</code>. The <code>event.deltaY</code> property returns negative\nvalues if the mouse wheel is rotated up or away from the user and positive\nin the other direction. The <code>event.deltaX</code> does the same as <code>event.deltaY</code>\nexcept it reads the horizontal wheel scroll of the mouse wheel.\n<br><br>\nOn OS X with "natural" scrolling enabled, the <code>event.deltaY</code> values are\nreversed.</p>\n", 8862 "itemtype": "method", 8863 "name": "mouseWheel", 8864 "params": [{ 8865 "name": "fxn", 8866 "description": "<p>function to be fired when mouse is\n scrolled over the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8867 "type": "Function|Boolean" 8868 }], 8869 "chainable": 1, 8870 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar d;\nvar g;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.mouseWheel(changeSize); // attach listener for\n // activity on canvas only\n d = 10;\n g = 100;\n}\n\nfunction draw() {\n background(g);\n ellipse(width / 2, height / 2, d, d);\n}\n\n// this function fires with mousewheel movement\n// anywhere on screen\nfunction mouseWheel() {\n g = g + 10;\n}\n\n// this function fires with mousewheel movement\n// over canvas only\nfunction changeSize(event) {\n if (event.deltaY > 0) {\n d = d + 10;\n } else {\n d = d - 10;\n }\n}\n</code></div>"], 8871 "alt": "no display.", 8872 "class": "p5.Element", 8873 "module": "DOM", 8874 "submodule": "DOM" 8875 }, { 8876 "file": "src/core/p5.Element.js", 8877 "line": 370, 8878 "description": "<p>The .<a href=\"#/p5.Element/mouseReleased\">mouseReleased()</a> function is called once after every time a\nmouse button is released over the element.\nSome mobile browsers may also trigger this event on a touch screen,\nif the user performs a quick tap.\nThis can be used to attach element specific event listeners.</p>\n", 8879 "itemtype": "method", 8880 "name": "mouseReleased", 8881 "params": [{ 8882 "name": "fxn", 8883 "description": "<p>function to be fired when mouse is\n released over the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8884 "type": "Function|Boolean" 8885 }], 8886 "chainable": 1, 8887 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar d;\nvar g;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.mouseReleased(changeGray); // attach listener for\n // activity on canvas only\n d = 10;\n g = 100;\n}\n\nfunction draw() {\n background(g);\n ellipse(width / 2, height / 2, d, d);\n}\n\n// this function fires after the mouse has been\n// released\nfunction mouseReleased() {\n d = d + 10;\n}\n\n// this function fires after the mouse has been\n// released while on canvas\nfunction changeGray() {\n g = random(0, 255);\n}\n</code></div>"],
8888 "alt": "no display.", 8889 "class": "p5.Element", 8890 "module": "DOM", 8891 "submodule": "DOM" 8892 }, { 8893 "file": "src/core/p5.Element.js", 8894 "line": 424, 8895 "description": "<p>The .<a href=\"#/p5.Element/mouseClicked\">mouseClicked()</a> function is called once after a mouse button is\npressed and released over the element.\nSome mobile browsers may also trigger this event on a touch screen,\nif the user performs a quick tap.\nThis can be used to attach element specific event listeners.</p>\n", 8896 "itemtype": "method", 8897 "name": "mouseClicked", 8898 "params": [{ 8899 "name": "fxn", 8900 "description": "<p>function to be fired when mouse is\n clicked over the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8901 "type": "Function|Boolean" 8902 }], 8903 "chainable": 1, 8904 "example": ["\n<div class=\"norender\">\n<code>\nvar cnv;\nvar d;\nvar g;\n\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.mouseClicked(changeGray); // attach listener for\n // activity on canvas only\n d = 10;\n g = 100;\n}\n\nfunction draw() {\n background(g);\n ellipse(width / 2, height / 2, d, d);\n}\n\n// this function fires after the mouse has been\n// clicked anywhere\nfunction mouseClicked() {\n d = d + 10;\n}\n\n// this function fires after the mouse has been\n// clicked on canvas\nfunction changeGray() {\n g = random(0, 255);\n}\n</code>\n</div>"], 8905 "alt": "no display.", 8906 "class": "p5.Element", 8907 "module": "DOM", 8908 "submodule": "DOM" 8909 }, { 8910 "file": "src/core/p5.Element.js", 8911 "line": 480, 8912 "description": "<p>The .<a href=\"#/p5.Element/mouseMoved\">mouseMoved()</a> function is called once every time a\nmouse moves over the element. This can be used to attach an\nelement specific event listener.</p>\n", 8913 "itemtype": "method", 8914 "name": "mouseMoved", 8915 "params": [{ 8916 "name": "fxn", 8917 "description": "<p>function to be fired when a mouse moves\n over the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8918 "type": "Function|Boolean" 8919 }], 8920 "chainable": 1, 8921 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar d = 30;\nvar g;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.mouseMoved(changeSize); // attach listener for\n // activity on canvas only\n d = 10;\n g = 100;\n}\n\nfunction draw() {\n background(g);\n fill(200);\n ellipse(width / 2, height / 2, d, d);\n}\n\n// this function fires when mouse moves anywhere on\n// page\nfunction mouseMoved() {\n g = g + 5;\n if (g > 255) {\n g = 0;\n }\n}\n\n// this function fires when mouse moves over canvas\nfunction changeSize() {\n d = d + 2;\n if (d > 100) {\n d = 0;\n }\n}\n</code></div>"], 8922 "alt": "no display.", 8923 "class": "p5.Element", 8924 "module": "DOM", 8925 "submodule": "DOM" 8926 }, { 8927 "file": "src/core/p5.Element.js", 8928 "line": 538, 8929 "description": "<p>The .<a href=\"#/p5.Element/mouseOver\">mouseOver()</a> function is called once after every time a\nmouse moves onto the element. This can be used to attach an\nelement specific event listener.</p>\n", 8930 "itemtype": "method", 8931 "name": "mouseOver", 8932 "params": [{ 8933 "name": "fxn", 8934 "description": "<p>function to be fired when a mouse moves\n onto the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8935 "type": "Function|Boolean" 8936 }], 8937 "chainable": 1, 8938 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar d;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.mouseOver(changeGray);\n d = 10;\n}\n\nfunction draw() {\n ellipse(width / 2, height / 2, d, d);\n}\n\nfunction changeGray() {\n d = d + 10;\n if (d > 100) {\n d = 0;\n }\n}\n</code></div>"],
8939 "alt": "no display.", 8940 "class": "p5.Element", 8941 "module": "DOM", 8942 "submodule": "DOM" 8943 }, { 8944 "file": "src/core/p5.Element.js", 8945 "line": 581, 8946 "description": "<p>The .<a href=\"#/p5.Element/mouseOut\">mouseOut()</a> function is called once after every time a\nmouse moves off the element. This can be used to attach an\nelement specific event listener.</p>\n", 8947 "itemtype": "method", 8948 "name": "mouseOut", 8949 "params": [{ 8950 "name": "fxn", 8951 "description": "<p>function to be fired when a mouse\n moves off of an element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8952 "type": "Function|Boolean" 8953 }], 8954 "chainable": 1, 8955 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar d;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.mouseOut(changeGray);\n d = 10;\n}\n\nfunction draw() {\n ellipse(width / 2, height / 2, d, d);\n}\n\nfunction changeGray() {\n d = d + 10;\n if (d > 100) {\n d = 0;\n }\n}\n</code></div>"], 8956 "alt": "no display.", 8957 "class": "p5.Element", 8958 "module": "DOM", 8959 "submodule": "DOM" 8960 }, { 8961 "file": "src/core/p5.Element.js", 8962 "line": 623, 8963 "description": "<p>The .<a href=\"#/p5.Element/touchStarted\">touchStarted()</a> function is called once after every time a touch is\nregistered. This can be used to attach element specific event listeners.</p>\n", 8964 "itemtype": "method", 8965 "name": "touchStarted", 8966 "params": [{ 8967 "name": "fxn", 8968 "description": "<p>function to be fired when a touch\n starts over the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8969 "type": "Function|Boolean" 8970 }], 8971 "chainable": 1, 8972 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar d;\nvar g;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.touchStarted(changeGray); // attach listener for\n // canvas click only\n d = 10;\n g = 100;\n}\n\nfunction draw() {\n background(g);\n ellipse(width / 2, height / 2, d, d);\n}\n\n// this function fires with any touch anywhere\nfunction touchStarted() {\n d = d + 10;\n}\n\n// this function fires only when cnv is clicked\nfunction changeGray() {\n g = random(0, 255);\n}\n</code></div>"], 8973 "alt": "no display.", 8974 "class": "p5.Element", 8975 "module": "DOM", 8976 "submodule": "DOM" 8977 }, { 8978 "file": "src/core/p5.Element.js", 8979 "line": 671, 8980 "description": "<p>The .<a href=\"#/p5.Element/touchMoved\">touchMoved()</a> function is called once after every time a touch move is\nregistered. This can be used to attach element specific event listeners.</p>\n", 8981 "itemtype": "method", 8982 "name": "touchMoved", 8983 "params": [{ 8984 "name": "fxn", 8985 "description": "<p>function to be fired when a touch moves over\n the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 8986 "type": "Function|Boolean" 8987 }], 8988 "chainable": 1, 8989 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar g;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.touchMoved(changeGray); // attach listener for\n // canvas click only\n g = 100;\n}\n\nfunction draw() {\n background(g);\n}\n\n// this function fires only when cnv is clicked\nfunction changeGray() {\n g = random(0, 255);\n}\n</code></div>"], 8990 "alt": "no display.", 8991 "class": "p5.Element", 8992 "module": "DOM", 8993 "submodule": "DOM" 8994 }, { 8995 "file": "src/core/p5.Element.js", 8996 "line": 711, 8997 "description": "<p>The .<a href=\"#/p5.Element/touchEnded\">touchEnded()</a> function is called once after every time a touch is\nregistered. This can be used to attach element specific event listeners.</p>\n", 8998 "itemtype": "method", 8999 "name": "touchEnded", 9000 "params": [{ 9001 "name": "fxn", 9002 "description": "<p>function to be fired when a touch ends\n over the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 9003 "type": "Function|Boolean" 9004 }], 9005 "chainable": 1, 9006 "example": ["\n<div class='norender'><code>\nvar cnv;\nvar d;\nvar g;\nfunction setup() {\n cnv = createCanvas(100, 100);\n cnv.touchEnded(changeGray); // attach listener for\n // canvas click only\n d = 10;\n g = 100;\n}\n\nfunction draw() {\n background(g);\n ellipse(width / 2, height / 2, d, d);\n}\n\n// this function fires with any touch anywhere\nfunction touchEnded() {\n d = d + 10;\n}\n\n// this function fires only when cnv is clicked\nfunction changeGray() {\n g = random(0, 255);\n}\n</code></div>"],
9007 "alt": "no display.", 9008 "class": "p5.Element", 9009 "module": "DOM", 9010 "submodule": "DOM" 9011 }, { 9012 "file": "src/core/p5.Element.js", 9013 "line": 760, 9014 "description": "<p>The .<a href=\"#/p5.Element/dragOver\">dragOver()</a> function is called once after every time a\nfile is dragged over the element. This can be used to attach an\nelement specific event listener.</p>\n", 9015 "itemtype": "method", 9016 "name": "dragOver", 9017 "params": [{ 9018 "name": "fxn", 9019 "description": "<p>function to be fired when a file is\n dragged over the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 9020 "type": "Function|Boolean" 9021 }], 9022 "chainable": 1, 9023 "example": ["\n<div><code>\n// To test this sketch, simply drag a\n// file over the canvas\nfunction setup() {\n var c = createCanvas(100, 100);\n background(200);\n textAlign(CENTER);\n text('Drag file', width / 2, height / 2);\n c.dragOver(dragOverCallback);\n}\n\n// This function will be called whenever\n// a file is dragged over the canvas\nfunction dragOverCallback() {\n background(240);\n text('Dragged over', width / 2, height / 2);\n}\n</code></div>"], 9024 "alt": "nothing displayed", 9025 "class": "p5.Element", 9026 "module": "DOM", 9027 "submodule": "DOM" 9028 }, { 9029 "file": "src/core/p5.Element.js", 9030 "line": 798, 9031 "description": "<p>The .dragLeave() function is called once after every time a\ndragged file leaves the element area. This can be used to attach an\nelement specific event listener.</p>\n", 9032 "itemtype": "method", 9033 "name": "dragLeave", 9034 "params": [{ 9035 "name": "fxn", 9036 "description": "<p>function to be fired when a file is\n dragged off the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 9037 "type": "Function|Boolean" 9038 }], 9039 "chainable": 1, 9040 "example": ["\n<div><code>\n// To test this sketch, simply drag a file\n// over and then out of the canvas area\nfunction setup() {\n var c = createCanvas(100, 100);\n background(200);\n textAlign(CENTER);\n text('Drag file', width / 2, height / 2);\n c.dragLeave(dragLeaveCallback);\n}\n\n// This function will be called whenever\n// a file is dragged out of the canvas\nfunction dragLeaveCallback() {\n background(240);\n text('Dragged off', width / 2, height / 2);\n}\n</code></div>"], 9041 "alt": "nothing displayed", 9042 "class": "p5.Element", 9043 "module": "DOM", 9044 "submodule": "DOM" 9045 }, { 9046 "file": "src/core/p5.Element.js", 9047 "line": 836, 9048 "description": "<p>Registers a callback that gets called every time a file that is\ndropped on the element has been loaded.\np5 will load every dropped file into memory and pass it as a p5.File object to the callback.\nMultiple files dropped at the same time will result in multiple calls to the callback.</p>\n<p>You can optionally pass a second callback which will be registered to the raw\n<a href=\"https://developer.mozilla.org/en-US/docs/Web/Events/drop\">drop</a> event.\nThe callback will thus be provided the original\n<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/DragEvent\">DragEvent</a>.\nDropping multiple files at the same time will trigger the second callback once per drop,\nwhereas the first callback will trigger for each loaded file.</p>\n", 9049 "itemtype": "method", 9050 "name": "drop", 9051 "params": [{ 9052 "name": "callback", 9053 "description": "<p>callback to receive loaded file.</p>\n", 9054 "type": "Function" 9055 }, { 9056 "name": "fxn", 9057 "description": "<p>callback triggered when files are dropped.</p>\n", 9058 "type": "Function", 9059 "optional": true 9060 }], 9061 "chainable": 1, 9062 "example": ["\n<div><code>\nfunction setup() {\n var c = createCanvas(100, 100);\n background(200);\n textAlign(CENTER);\n text('drop file', width / 2, height / 2);\n c.drop(gotFile);\n}\n\nfunction gotFile(file) {\n background(200);\n text('received file:', width / 2, height / 2);\n text(file.name, width / 2, height / 2 + 50);\n}\n</code></div>\n\n<div><code>\nvar img;\n\nfunction setup() {\n var c = createCanvas(100, 100);\n background(200);\n textAlign(CENTER);\n text('drop image', width / 2, height / 2);\n c.drop(gotFile);\n}\n\nfunction draw() {\n if (img) {\n image(img, 0, 0, width, height);\n }\n}\n\nfunction gotFile(file) {\n img = createImg(file.data).hide();\n}\n</code></div>"], 9063 "alt": "Canvas turns into whatever image is dragged/dropped onto it.", 9064 "class": "p5.Element", 9065 "module": "DOM", 9066 "submodule": "DOM" 9067 }, { 9068 "file": "src/core/p5.Element.js", 9069 "line": 969, 9070 "description": "<p>Helper fxn for sharing pixel methods</p>\n", 9071 "class": "p5.Element", 9072 "module": "DOM", 9073 "submodule": "DOM" 9074 }, { 9075 "file": "src/core/p5.Graphics.js", 9076 "line": 65, 9077 "description": "<p>Removes a Graphics object from the page and frees any resources\nassociated with it.</p>\n", 9078 "itemtype": "method", 9079 "name": "remove", 9080 "example": ["\n<div class='norender'><code>\nlet bg;\nfunction setup() {\n bg = createCanvas(100, 100);\n bg.background(0);\n image(bg, 0, 0);\n bg.remove();\n}\n</code></div>\n\n<div><code>\nlet bg;\nfunction setup() {\n pixelDensity(1);\n createCanvas(100, 100);
9080\n stroke(255);\n fill(0);\n\n // create and draw the background image\n bg = createGraphics(100, 100);\n bg.background(200);\n bg.ellipse(50, 50, 80, 80);\n}\nfunction draw() {\n let t = millis() / 1000;\n // draw the background\n if (bg) {\n image(bg, frameCount % 100, 0);\n image(bg, frameCount % 100 - 100, 0);\n }\n // draw the foreground\n let p = p5.Vector.fromAngle(t, 35).add(50, 50);\n ellipse(p.x, p.y, 30);\n}\nfunction mouseClicked() {\n // remove the background\n if (bg) {\n bg.remove();\n bg = null;\n }\n}\n</code></div>"], 9081 "alt": "no image\na multi-colored circle moving back and forth over a scrolling background.", 9082 "class": "p5.Graphics", 9083 "module": "Rendering", 9084 "submodule": "Rendering" 9085 }, { 9086 "file": "src/core/p5.Renderer.js", 9087 "line": 96, 9088 "description": "<p>Resize our canvas element.</p>\n", 9089 "class": "p5.Renderer", 9090 "module": "Rendering", 9091 "submodule": "Rendering" 9092 }, { 9093 "file": "src/core/p5.Renderer.js", 9094 "line": 301, 9095 "description": "<p>Helper fxn to check font type (system or otf)</p>\n", 9096 "class": "p5.Renderer", 9097 "module": "Rendering", 9098 "submodule": "Rendering" 9099 }, { 9100 "file": "src/core/p5.Renderer.js", 9101 "line": 354, 9102 "description": "<p>Helper fxn to measure ascent and descent.\nAdapted from <a href=\"http://stackoverflow.com/a/25355178\">http://stackoverflow.com/a/25355178</a></p>\n", 9103 "class": "p5.Renderer", 9104 "module": "Rendering", 9105 "submodule": "Rendering" 9106 }, { 9107 "file": "src/core/p5.Renderer2D.js", 9108 "line": 9, 9109 "description": "<p>p5.Renderer2D\nThe 2D graphics canvas renderer class.\nextends p5.Renderer</p>\n", 9110 "class": "p5", 9111 "module": "Rendering" 9112 }, { 9113 "file": "src/core/p5.Renderer2D.js", 9114 "line": 392, 9115 "description": "<p>Generate a cubic Bezier representing an arc on the unit circle of total\nangle <code>size</code> radians, beginning <code>start</code> radians above the x-axis. Up to\nfour of these curves are combined to make a full arc.</p>\n<p>See www.joecridge.me/bezier.pdf for an explanation of the method.</p>\n", 9116 "class": "p5", 9117 "module": "Rendering" 9118 }, { 9119 "file": "src/core/rendering.js", 9120 "line": 17, 9121 "description": "<p>Creates a canvas element in the document, and sets the dimensions of it\nin pixels. This method should be called only once at the start of setup.\nCalling <a href=\"#/p5/createCanvas\">createCanvas</a> more than once in a sketch will result in very\nunpredictable behavior. If you want more than one drawing canvas\nyou could use <a href=\"#/p5/createGraphics\">createGraphics</a> (hidden by default but it can be shown).\n<br><br>\nThe system variables width and height are set by the parameters passed\nto this function. If <a href=\"#/p5/createCanvas\">createCanvas()</a> is not used, the window will be\ngiven a default size of 100x100 pixels.\n<br><br>\nFor more ways to position the canvas, see the\n<a href='https://github.com/processing/p5.js/wiki/Positioning-your-canvas'>\npositioning the canvas</a> wiki page.</p>\n", 9122 "itemtype": "method", 9123 "name": "createCanvas", 9124 "params": [{ 9125 "name": "w", 9126 "description": "<p>width of the canvas</p>\n", 9127 "type": "Number" 9128 }, { 9129 "name": "h", 9130 "description": "<p>height of the canvas</p>\n", 9131 "type": "Number" 9132 }, { 9133 "name": "renderer", 9134 "description": "<p>either P2D or WEBGL</p>\n", 9135 "type": "Constant", 9136 "optional": true 9137 }], 9138 "return": { 9139 "description": "", 9140 "type": "p5.Renderer" 9141 }, 9142 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 50);\n background(153);\n line(0, 0, width, height);\n}\n</code>\n</div>"], 9143 "alt": "Black line extending from top-left of canvas to bottom right.", 9144 "class": "p5", 9145 "module": "Rendering", 9146 "submodule": "Rendering" 9147 }, { 9148 "file": "src/core/rendering.js", 9149 "line": 119, 9150 "description": "<p>Resizes the canvas to given width and height. The canvas will be cleared\nand draw will be called immediately, allowing the sketch to re-render itself\nin the resized canvas.</p>\n", 9151 "itemtype": "method", 9152 "name": "resizeCanvas", 9153 "params": [{ 9154 "name": "w", 9155 "description": "<p>width of the canvas</p>\n", 9156 "type": "Number" 9157 }, { 9158 "name": "h", 9159 "description": "<p>height of the canvas</p>\n", 9160 "type": "Number" 9161 }, { 9162 "name": "noRedraw", 9163 "description": "<p>don't redraw the canvas immediately</p>\n", 9164 "type": "Boolean", 9165 "optional": true 9166 }], 9167 "example": ["\n<div class=\"norender\"><code>\nfunction setup() {\n createCanvas(windowWidth, windowHeight);\n}\n\nfunction draw() {\n background(0, 100, 200);\n}\n\nfunction windowResized() {\n resizeCanvas(windowWidth, windowHeight);\n}\n</code></div>"], 9168 "alt": "No image displayed.", 9169 "class": "p5", 9170 "module": "Rendering", 9171 "submodule": "Rendering" 9172 }, { 9173 "file": "src/core/rendering.js", 9174 "line": 174, 9175 "description": "<p>Removes the default canvas for a p5 sketch that doesn't\nrequire a canvas</p>\n", 9176 "itemtype": "method", 9177 "name": "noCanvas", 9178 "example": ["\n<div>\n<code>\nfunction setup() {\n noCanvas();\n}\n</code>\n</div>"], 9179 "alt": "no image displayed", 9180 "class": "p5", 9181 "module": "Rendering", 9182 "submodule": "Rendering" 9183 }, { 9184 "file": "src/core/rendering.js", 9185 "line": 197, 9186 "description": "<p>Creates and returns a new p5.Renderer object. Use this class if you need\nto draw into an off-screen graphics buffer. The two parameters define the\nwidth and height in pixels.</p>\n", 9187 "itemtype": "method", 9188 "name": "createGraphics", 9189 "params": [{ 9190 "name": "w", 9191 "description": "<p>width of the offscreen graphics buffer</p>\n", 9192 "type": "Number" 9193 }, { 9194 "name": "h", 9195 "description": "<p>height of the offscreen graphics buffer</p>\n", 9196 "type": "Number" 9197 }, { 9198 "name": "renderer", 9199 "description": "<p>either P2D or WEBGL\nundefined defaults to p2d</p>\n", 9200 "type": "Constant", 9201 "optional": true 9202 }], 9203 "return": { 9204 "description": "offscreen graphics buffer", 9205 "type": "p5.Graphics" 9206 }, 9207 "example": ["\n<div>\n<code>\nlet pg;\nfunction setup() {\n createCanvas(100, 100);\n pg = createGraphics(100, 100);\n}\nfunction draw() {\n background(200);\n pg.background(100);\n pg.noStroke();\n pg.ellipse(pg.width / 2, pg.height / 2, 50, 50);\n image(pg, 50, 50);\n image(pg, 0, 0, 50, 50);\n}\n</code>\n</div>"], 9208 "alt": "4 grey squares alternating light and dark grey. White quarter circle mid-left.", 9209 "class": "p5", 9210 "module": "Rendering", 9211 "submodule": "Rendering" 9212 }, { 9213 "file": "src/core/rendering.js", 9214 "line": 236, 9215 "description": "<p>Blends the pixels in the display window according to the defined mode.\nThere is a choice of the following modes to blend the source pixels (A)\nwith the ones of pixels already in the display window (B):</p>\n<ul>\n<li><code>BLEND</code> - linear interpolation of colours: C =\nA*factor + B. This is the default blending mode.</li>\n<li><code>ADD</code> - sum of A and B</li>\n<li><code>DARKEST</code> - only the darkest colour succeeds: C =\nmin(A*factor, B).</li>\n<li><code>LIGHTEST</code> - only the lightest colour succeeds: C =\nmax(A*factor, B).</li>\n<li><code>DIFFERENCE</code> - subtract colors from underlying image.</li>\n<li><code>EXCLUSION</code> - similar to <code>DIFFERENCE</code>, but less\nextreme.</li>\n<li><code>MULTIPLY</code> - multiply the colors, result will always be\ndarker.</li>\n<li><code>SCREEN</code> - opposite multiply, uses inverse values of the\ncolors.</li>\n<li><code>REPLACE</code> - the pixels entirely replace the others and\ndon'
9215t utilize alpha (transparency) values.</li>\n<li><code>OVERLAY</code> - mix of <code>MULTIPLY</code> and <code>SCREEN\n</code>. Multiplies dark values, and screens light values.</li>\n<li><code>HARD_LIGHT</code> - <code>SCREEN</code> when greater than 50%\ngray, <code>MULTIPLY</code> when lower.</li>\n<li><code>SOFT_LIGHT</code> - mix of <code>DARKEST</code> and\n<code>LIGHTEST</code>. Works like <code>OVERLAY</code>, but not as harsh.\n</li>\n<li><code>DODGE</code> - lightens light tones and increases contrast,\nignores darks.</li>\n<li><code>BURN</code> - darker areas are applied, increasing contrast,\nignores lights.</li>\n</ul>", 9216 "itemtype": "method", 9217 "name": "blendMode", 9218 "params": [{ 9219 "name": "mode", 9220 "description": "<p>blend mode to set for canvas.\n either BLEND, DARKEST, LIGHTEST, DIFFERENCE, MULTIPLY,\n EXCLUSION, SCREEN, REPLACE, OVERLAY, HARD_LIGHT,\n SOFT_LIGHT, DODGE, BURN, ADD or NORMAL</p>\n", 9221 "type": "Constant" 9222 }], 9223 "example": ["\n<div>\n<code>\nblendMode(LIGHTEST);\nstrokeWeight(30);\nstroke(80, 150, 255);\nline(25, 25, 75, 75);\nstroke(255, 50, 50);\nline(75, 25, 25, 75);\n</code>\n</div>\n<div>\n<code>\nblendMode(MULTIPLY);\nstrokeWeight(30);\nstroke(80, 150, 255);\nline(25, 25, 75, 75);\nstroke(255, 50, 50);\nline(75, 25, 25, 75);\n</code>\n</div>"], 9224 "alt": "translucent image thick red & blue diagonal rounded lines intersecting center\nThick red & blue diagonal rounded lines intersecting center. dark at overlap", 9225 "class": "p5", 9226 "module": "Rendering", 9227 "submodule": "Rendering" 9228 }, { 9229 "file": "src/core/shim.js", 9230 "line": 23, 9231 "description": "<p>shim for Uint8ClampedArray.slice\n(allows arrayCopy to work with pixels[])\nwith thanks to <a href=\"http://halfpapstudios.com/blog/tag/html5-canvas/\">http://halfpapstudios.com/blog/tag/html5-canvas/</a>\nEnumerable set to false to protect for...in from\nUint8ClampedArray.prototype pollution.</p>\n", 9232 "class": "p5", 9233 "module": "Rendering" 9234 }, { 9235 "file": "src/core/shim.js", 9236 "line": 45, 9237 "description": "<p>this is implementation of Object.assign() which is unavailable in\nIE11 and (non-Chrome) Android browsers.\nThe assign() method is used to copy the values of all enumerable\nown properties from one or more source objects to a target object.\nIt will return the target object.\nModified from <a href=\"https://github.com/ljharb/object.assign\">https://github.com/ljharb/object.assign</a></p>\n", 9238 "class": "p5", 9239 "module": "Rendering" 9240 }, { 9241 "file": "src/core/structure.js", 9242 "line": 12, 9243 "description": "<p>Stops p5.js from continuously executing the code within <a href=\"#/p5/draw\">draw()</a>.\nIf <a href=\"#/p5/loop\">loop()</a> is called, the code in <a href=\"#/p5/draw\">draw()</a>
9243 begins to run continuously again.\nIf using <a href=\"#/p5/noLoop\">noLoop()</a> in <a href=\"#/p5/setup\">setup()</a>, it should be the last line inside the block.\n<br><br>\nWhen <a href=\"#/p5/noLoop\">noLoop()</a> is used, it's not possible to manipulate or access the\nscreen inside event handling functions such as <a href=\"#/p5/mousePressed\">mousePressed()</a> or\n<a href=\"#/p5/keyPressed\">keyPressed()</a>. Instead, use those functions to call <a href=\"#/p5/redraw\">redraw()</a> or <a href=\"#/p5/loop\">loop()</a>,\nwhich will run <a href=\"#/p5/draw\">draw()</a>, which can update the screen properly. This means\nthat when <a href=\"#/p5/noLoop\">noLoop()</a> has been called, no drawing can happen, and functions\nlike <a href=\"#/p5/saveFrame\">saveFrame()</a> or <a href=\"#/p5/loadPixels\">loadPixels()</a> may not be used.\n<br><br>\nNote that if the sketch is resized, <a href=\"#/p5/redraw\">redraw()</a> will be called to update\nthe sketch, even after <a href=\"#/p5/noLoop\">noLoop()</a> has been specified. Otherwise, the sketch\nwould enter an odd state until <a href=\"#/p5/loop\">loop()</a> was called.</p>\n", 9244 "itemtype": "method", 9245 "name": "noLoop", 9246 "example": ["\n<div><code>\nfunction setup() {\n createCanvas(100, 100);\n background(200);\n noLoop();\n}\n\nfunction draw() {\n line(10, 10, 90, 90);\n}\n</code></div>\n\n<div><code>\nlet x = 0;\nfunction setup() {\n createCanvas(100, 100);\n}\n\nfunction draw() {\n background(204);\n x = x + 0.1;\n if (x > width) {\n x = 0;\n }\n line(x, 0, x, height);\n}\n\nfunction mousePressed() {\n noLoop();\n}\n\nfunction mouseReleased() {\n loop();\n}\n</code></div>"], 9247 "alt": "113 pixel long line extending from top-left to bottom right of canvas.\nhorizontal line moves slowly from left. Loops but stops on mouse press.", 9248 "class": "p5", 9249 "module": "Structure", 9250 "submodule": "Structure" 9251 }, { 9252 "file": "src/core/structure.js", 9253 "line": 74, 9254 "description": "<p>By default, p5.js loops through draw() continuously, executing the code\nwithin it. However, the <a href=\"#/p5/draw\">draw()</a> loop may be stopped by calling <a href=\"#/p5/noLoop\">noLoop()</a>.\nIn that case, the <a href=\"#/p5/draw\">draw()</a> loop can be resumed with loop().</p>\n", 9255 "itemtype": "method", 9256 "name": "loop", 9257 "example": ["\n<div><code>\nlet x = 0;\nfunction setup() {\n createCanvas(100, 100);\n noLoop();\n}\n\nfunction draw() {\n background(204);\n x = x + 0.1;\n if (x > width) {\n x = 0;\n }\n line(x, 0, x, height);\n}\n\nfunction mousePressed() {\n loop();\n}\n\nfunction mouseReleased() {\n noLoop();\n}\n</code></div>"], 9258 "alt": "horizontal line moves slowly from left. Loops but stops on mouse press.", 9259 "class": "p5", 9260 "module": "Structure", 9261 "submodule": "Structure" 9262 }, { 9263 "file": "src/core/structure.js", 9264 "line": 116, 9265 "description": "<p>The <a href=\"#/p5/push\">push()</a> function saves the current drawing style settings and\ntransformations, while <a href=\"#/p5/pop\">pop()</a> restores these settings. Note that these\nfunctions are always used together. They allow you to change the style\nand transformation settings and later return to what you had. When a new\nstate is started with <a href=\"#/p5/push\">push()</a>, it builds on the current style and transform\ninformation. The <a href=\"#/p5/push\">push()</a> and <a href=\"#/p5/pop\">pop()</a> functions can be embedded to provide\nmore control. (See the second example for a demonstration.)\n<br><br>\n<a href=\"#/p5/push\">push()</a> stores information related to the current transformation state\nand style settings controlled by the following functions: <a href=\"#/p5/fill\">fill()</a>,\n<a href=\"#/p5/stroke\">stroke()</a>, <a href=\"#/p5/tint\">tint()</a>, <a href=\"#/p5/strokeWeight\">
9265strokeWeight()</a>, <a href=\"#/p5/strokeCap\">strokeCap()</a>, <a href=\"#/p5/strokeJoin\">strokeJoin()</a>,\n<a href=\"#/p5/imageMode\">imageMode()</a>, <a href=\"#/p5/rectMode\">rectMode()</a>, <a href=\"#/p5/ellipseMode\">ellipseMode()</a>, <a href=\"#/p5/colorMode\">colorMode()</a>, <a href=\"#/p5/textAlign\">textAlign()</a>,\n<a href=\"#/p5/textFont\">textFont()</a>, <a href=\"#/p5/textMode\">textMode()</a>, <a href=\"#/p5/textSize\">textSize()</a>, <a href=\"#/p5/textLeading\">textLeading()</a>.</p>\n", 9266 "itemtype": "method", 9267 "name": "push", 9268 "example": ["\n<div>\n<code>\nellipse(0, 50, 33, 33); // Left circle\n\npush(); // Start a new drawing state\nstrokeWeight(10);\nfill(204, 153, 0);\ntranslate(50, 0);\nellipse(0, 50, 33, 33); // Middle circle\npop(); // Restore original state\n\nellipse(100, 50, 33, 33); // Right circle\n</code>\n</div>\n<div>\n<code>\nellipse(0, 50, 33, 33); // Left circle\n\npush(); // Start a new drawing state\nstrokeWeight(10);\nfill(204, 153, 0);\nellipse(33, 50, 33, 33); // Left-middle circle\n\npush(); // Start another new drawing state\nstroke(0, 102, 153);\nellipse(66, 50, 33, 33); // Right-middle circle\npop(); // Restore previous state\n\npop(); // Restore original state\n\nellipse(100, 50, 33, 33); // Right circle\n</code>\n</div>"], 9269 "alt": "Gold ellipse + thick black outline @center 2 white ellipses on left and right.\n2 Gold ellipses left black right blue stroke. 2 white ellipses on left+right.", 9270 "class": "p5", 9271 "module": "Structure", 9272 "submodule": "Structure" 9273 }, { 9274 "file": "src/core/structure.js", 9275 "line": 181, 9276 "description": "<p>The <a href=\"#/p5/push\">push()</a> function saves the current drawing style settings and\ntransformations, while <a href=\"#/p5/pop\">pop()</a> restores these settings. Note that these\nfunctions are always used together. They allow you to change the style\nand transformation settings and later return to what you had. When a new\nstate is started with <a href=\"#/p5/push\">push()</a>, it builds on the current style and transform\ninformation. The <a href=\"#/p5/push\">push()</a> and <a href=\"#/p5/pop\">pop()</a> functions can be embedded to provide\nmore control. (See the second example for a demonstration.)\n<br><br>\n<a href=\"#/p5/push\">push()</a> stores information related to the current transformation state\nand style settings controlled by the following functions: <a href=\"#/p5/fill\">fill()</a>,\n<a href=\"#/p5/stroke\">stroke()</a>, <a href=\"#/p5/tint\">tint()</a>, <a href=\"#/p5/strokeWeight\">
9276strokeWeight()</a>, <a href=\"#/p5/strokeCap\">strokeCap()</a>, <a href=\"#/p5/strokeJoin\">strokeJoin()</a>,\n<a href=\"#/p5/imageMode\">imageMode()</a>, <a href=\"#/p5/rectMode\">rectMode()</a>, <a href=\"#/p5/ellipseMode\">ellipseMode()</a>, <a href=\"#/p5/colorMode\">colorMode()</a>, <a href=\"#/p5/textAlign\">textAlign()</a>,\n<a href=\"#/p5/textFont\">textFont()</a>, <a href=\"#/p5/textMode\">textMode()</a>, <a href=\"#/p5/textSize\">textSize()</a>, <a href=\"#/p5/textLeading\">textLeading()</a>.</p>\n", 9277 "itemtype": "method", 9278 "name": "pop", 9279 "example": ["\n<div>\n<code>\nellipse(0, 50, 33, 33); // Left circle\n\npush(); // Start a new drawing state\ntranslate(50, 0);\nstrokeWeight(10);\nfill(204, 153, 0);\nellipse(0, 50, 33, 33); // Middle circle\npop(); // Restore original state\n\nellipse(100, 50, 33, 33); // Right circle\n</code>\n</div>\n<div>\n<code>\nellipse(0, 50, 33, 33); // Left circle\n\npush(); // Start a new drawing state\nstrokeWeight(10);\nfill(204, 153, 0);\nellipse(33, 50, 33, 33); // Left-middle circle\n\npush(); // Start another new drawing state\nstroke(0, 102, 153);\nellipse(66, 50, 33, 33); // Right-middle circle\npop(); // Restore previous state\n\npop(); // Restore original state\n\nellipse(100, 50, 33, 33); // Right circle\n</code>\n</div>"], 9280 "alt": "Gold ellipse + thick black outline @center 2 white ellipses on left and right.\n2 Gold ellipses left black right blue stroke. 2 white ellipses on left+right.", 9281 "class": "p5", 9282 "module": "Structure", 9283 "submodule": "Structure" 9284 }, { 9285 "file": "src/core/structure.js", 9286 "line": 247, 9287 "description": "<p>Executes the code within <a href=\"#/p5/draw\">draw()</a> one time. This functions allows the\n program to update the display window only when necessary, for example\n when an event registered by <a href=\"#/p5/mousePressed\">mousePressed()</a> or <a href=\"#/p5/keyPressed\">keyPressed()</a> occurs.\n <br><br>\n In structuring a program, it only makes sense to call <a href=\"#/p5/redraw\">redraw()</a> within\n events such as <a href=\"#/p5/mousePressed\">mousePressed()</a>. This is because <a href=\"#/p5/redraw\">redraw()</a> does not run\n <a href=\"#/p5/draw\">draw()</a> immediately (it only sets a flag that indicates an update is\n needed).\n <br><br>\n The <a href=\"#/p5/redraw\">redraw()</a> function does not work properly when called inside <a href=\"#/p5/draw\">draw()</a>.\n To enable/disable animations, use <a href=\"#/p5/loop\">loop()</a> and <a href=\"#/p5/noLoop\">noLoop()</a>.\n <br><br>\n In addition you can set the number of redraws per method call. Just\n add an integer as single parameter for the number of redraws.</p>\n", 9288 "itemtype": "method", 9289 "name": "redraw", 9290 "params": [{ 9291 "name": "n", 9292 "description": "<p>Redraw for n-times. The default value is 1.</p>\n", 9293 "type": "Integer", 9294 "optional": true 9295 }], 9296 "example": ["\n <div><code>\n let x = 0;\nfunction setup() {\n createCanvas(100, 100);\n noLoop();\n }\nfunction draw() {\n background(204);\n line(x, 0, x, height);\n }\nfunction mousePressed() {\n x += 1;\n redraw();\n }\n </code></div>\n<div class='norender'><code>\n let x = 0;\nfunction setup() {\n createCanvas(100, 100);\n noLoop();\n }\nfunction draw() {\n background(204);\n x += 1;\n line(x, 0, x, height);\n }\nfunction mousePressed() {\n redraw(5);\n }\n </code></div>"], 9297 "alt": "black line on far left of canvas\n black line on far left of canvas", 9298 "class": "p5", 9299 "module": "Structure", 9300 "submodule": "Structure" 9301 }, { 9302 "file": "src/core/transform.js", 9303 "line": 13, 9304 "description": "<p>Multiplies the current matrix by the one specified through the parameters.\nThis is a powerful operation that can perform the equivalent of translate,\nscale, shear and rotate all at once. You can learn more about transformation\nmatrices on <a href=\"https://en.wikipedia.org/wiki/Transformation_matrix\">\nWikipedia</a>.</p>\n<p>The naming of the arguments here follows the naming of the <a href=\n\"https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-transform\">\nWHATWG specification</a> and corresponds to a\ntransformation matrix of the\nform:</p>\n<blockquote>\n<p><img style=\"max-width: 150px\" src=\"assets/transformation-matrix.png\"\nalt=\"The transformation matrix used when applyM
9304atrix is called\"/></p>\n</blockquote>\n", 9305 "itemtype": "method", 9306 "name": "applyMatrix", 9307 "params": [{ 9308 "name": "a", 9309 "description": "<p>numbers which define the 2x3 matrix to be multiplied</p>\n", 9310 "type": "Number" 9311 }, { 9312 "name": "b", 9313 "description": "<p>numbers which define the 2x3 matrix to be multiplied</p>\n", 9314 "type": "Number" 9315 }, { 9316 "name": "c", 9317 "description": "<p>numbers which define the 2x3 matrix to be multiplied</p>\n", 9318 "type": "Number" 9319 }, { 9320 "name": "d", 9321 "description": "<p>numbers which define the 2x3 matrix to be multiplied</p>\n", 9322 "type": "Number" 9323 }, { 9324 "name": "e", 9325 "description": "<p>numbers which define the 2x3 matrix to be multiplied</p>\n", 9326 "type": "Number" 9327 }, { 9328 "name": "f", 9329 "description": "<p>numbers which define the 2x3 matrix to be multiplied</p>\n", 9330 "type": "Number" 9331 }], 9332 "chainable": 1, 9333 "example": ["\n<div>\n<code>\nfunction setup() {\n frameRate(10);\n rectMode(CENTER);\n}\n\nfunction draw() {\n var step = frameCount % 20;\n background(200);\n // Equivalent to translate(x, y);\n applyMatrix(1, 0, 0, 1, 40 + step, 50);\n rect(0, 0, 50, 50);\n}\n</code>\n</div>\n<div>\n<code>\nfunction setup() {\n frameRate(10);\n rectMode(CENTER);\n}\n\nfunction draw() {\n var step = frameCount % 20;\n background(200);\n translate(50, 50);\n // Equivalent to scale(x, y);\n applyMatrix(1 / step, 0, 0, 1 / step, 0, 0);\n rect(0, 0, 50, 50);\n}\n</code>\n</div>\n<div>\n<code>\nfunction setup() {\n frameRate(10);\n rectMode(CENTER);\n}\n\nfunction draw() {\n var step = frameCount % 20;\n var angle = map(step, 0, 20, 0, TWO_PI);\n var cos_a = cos(angle);\n var sin_a = sin(angle);\n background(200);\n translate(50, 50);\n // Equivalent to rotate(angle);\n applyMatrix(cos_a, sin_a, -sin_a, cos_a, 0, 0);\n rect(0, 0, 50, 50);\n}\n</code>\n</div>\n<div>\n<code>\nfunction setup() {\n frameRate(10);\n rectMode(CENTER);\n}\n\nfunction draw() {\n var step = frameCount % 20;\n var angle = map(step, 0, 20, -PI / 4, PI / 4);\n background(200);\n translate(50, 50);\n // equivalent to shearX(angle);\n var shear_factor = 1 / tan(PI / 2 - angle);\n applyMatrix(1, 0, shear_factor, 1, 0, 0);\n rect(0, 0, 50, 50);\n}\n</code>\n</div>"], 9334 "alt": "A rectangle translating to the right\nA rectangle shrinking to the center\nA rectangle rotating clockwise about the center\nA rectangle shearing", 9335 "class": "p5", 9336 "module": "Transform", 9337 "submodule": "Transform" 9338 }, { 9339 "file": "src/core/transform.js", 9340 "line": 135, 9341 "description": "<p>Replaces the current matrix with the identity matrix.</p>\n", 9342 "itemtype": "method", 9343 "name": "resetMatrix", 9344 "chainable": 1, 9345 "example": ["\n<div>\n<code>\ntranslate(50, 50);\napplyMatrix(0.5, 0.5, -0.5, 0.5, 0, 0);\nrect(0, 0, 20, 20);\n// Note that the translate is also reset.\nresetMatrix();\nrect(0, 0, 20, 20);\n</code>\n</div>"], 9346 "alt": "A rotated retangle in the center with another at the top left corner", 9347 "class": "p5", 9348 "module": "Transform", 9349 "submodule": "Transform" 9350 }, { 9351 "file": "src/core/transform.js", 9352 "line": 161, 9353 "description": "<p>Rotates a shape the amount specified by the angle parameter. This\nfunction accounts for <a href=\"#/p5/angleMode\">angleMode</a>, so angles can be entered in either\nRADIANS or DEGREES.\n<br><br>\nObjects are always rotated around their relative position to the\norigin and positive numbers rotate objects in a clockwise direction.\nTransformations apply to everything that happens after and subsequent\ncalls to the function accumulates the effect. For example, calling\nrotate(HALF_PI) and then rotate(HALF_PI) is the same as rotate(PI).\nAll tranformations are reset when <a href=\"#/p5/draw\">draw()</a> begins again.\n<br><br>
9353\nTechnically, <a href=\"#/p5/rotate\">rotate()</a> multiplies the current transformation matrix\nby a rotation matrix. This function can be further controlled by\nthe <a href=\"#/p5/push\">push()</a> and <a href=\"#/p5/pop\">pop()</a>.</p>\n", 9354 "itemtype": "method", 9355 "name": "rotate", 9356 "params": [{ 9357 "name": "angle", 9358 "description": "<p>the angle of rotation, specified in radians\n or degrees, depending on current angleMode</p>\n", 9359 "type": "Number" 9360 }, { 9361 "name": "axis", 9362 "description": "<p>(in 3d) the axis to rotate around</p>\n", 9363 "type": "p5.Vector|Number[]", 9364 "optional": true 9365 }], 9366 "chainable": 1, 9367 "example": ["\n<div>\n<code>\ntranslate(width / 2, height / 2);\nrotate(PI / 3.0);\nrect(-26, -26, 52, 52);\n</code>\n</div>"], 9368 "alt": "white 52x52 rect with black outline at center rotated counter 45 degrees", 9369 "class": "p5", 9370 "module": "Transform", 9371 "submodule": "Transform" 9372 }, { 9373 "file": "src/core/transform.js", 9374 "line": 201, 9375 "description": "<p>Rotates around X axis.</p>\n", 9376 "itemtype": "method", 9377 "name": "rotateX", 9378 "params": [{ 9379 "name": "angle", 9380 "description": "<p>the angle of rotation, specified in radians\n or degrees, depending on current angleMode</p>\n", 9381 "type": "Number" 9382 }], 9383 "chainable": 1, 9384 "example": ["\n<div modernizr='webgl'>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\nfunction draw() {\n background(255);\n rotateX(millis() / 1000);\n box();\n}\n</code>\n</div>"], 9385 "alt": "3d box rotating around the x axis.", 9386 "class": "p5", 9387 "module": "Transform", 9388 "submodule": "Transform" 9389 }, { 9390 "file": "src/core/transform.js", 9391 "line": 231, 9392 "description": "<p>Rotates around Y axis.</p>\n", 9393 "itemtype": "method", 9394 "name": "rotateY", 9395 "params": [{ 9396 "name": "angle", 9397 "description": "<p>the angle of rotation, specified in radians\n or degrees, depending on current angleMode</p>\n", 9398 "type": "Number" 9399 }], 9400 "chainable": 1, 9401 "example": ["\n<div modernizr='webgl'>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\nfunction draw() {\n background(255);\n rotateY(millis() / 1000);\n box();\n}\n</code>\n</div>"], 9402 "alt": "3d box rotating around the y axis.", 9403 "class": "p5", 9404 "module": "Transform", 9405 "submodule": "Transform" 9406 }, { 9407 "file": "src/core/transform.js", 9408 "line": 261, 9409 "description": "<p>Rotates around Z axis. Webgl mode only.</p>\n", 9410 "itemtype": "method", 9411 "name": "rotateZ", 9412 "params": [{ 9413 "name": "angle", 9414 "description": "<p>the angle of rotation, specified in radians\n or degrees, depending on current angleMode</p>\n", 9415 "type": "Number" 9416 }], 9417 "chainable": 1, 9418 "example": ["\n<div modernizr='webgl'>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\nfunction draw() {\n background(255);\n rotateZ(millis() / 1000);\n box();\n}\n</code>\n</div>"], 9419 "alt": "3d box rotating around the z axis.", 9420 "class": "p5", 9421 "module": "Transform", 9422 "submodule": "Transform" 9423 }, { 9424 "file": "src/core/transform.js", 9425 "line": 291, 9426 "description": "<p>Increases or decreases the size of a shape by expanding and contracting\nvertices. Objects always scale from their relative origin to the\ncoordinate system. Scale values are specified as decimal percentages.\nFor example, the function call scale(2.0) increases the dimension of a\nshape by 200%.\n<br><br>\nTransformations apply to everything that happens after and subsequent\ncalls to the function multiply the effect. For example, calling scale(2.0)\nand then scale(1.5) is the same as scale(3.0). If <a href=\"#/p5/scale\">scale()</a> is called\nwithin <a href=\"#/p5/draw\">draw()</a>, the transformation is reset when the loop begins again.\n<br><br>\nUsing this function with the z parameter is only available in WEBGL mode.\nThis function can be further controlled with <a href=\"#/p5/push\">push()</a> and <a href=\"#/p5/pop\">pop()</a>.</p>\n", 9427 "itemtype": "method", 9428 "name": "scale", 9429 "chainable": 1, 9430 "example": ["\n<div>\n<code>\nrect(30, 20, 50, 50);\nscale(0.5);\nrect(30, 20, 50, 50);\n</code>\n</div>\n\n<div>\n<code>\nrect(30, 20, 50, 50);\nscale(0.5, 1.3);\nrect(30, 20, 50, 50);\n</code>\n</div>"], 9431 "alt": "white 52x52 rect with black outline at center rotated counter 45 degrees\n2 white rects with black outline- 1 50x50 at center. other 25x65 bottom left", 9432 "class": "p5", 9433 "module": "Transform", 9434 "submodule": "Transform", 9435 "overloads": [{ 9436 "line": 291, 9437 "params": [{ 9438 "name": "s", 9439 "description": "<p>percent to scale the object, or percentage to\n scale the object in the x-axis if multiple arguments\n are given</p>\n", 9440 "type": "Number|p5.Vector|Number[]" 9441 }, { 9442 "name": "y", 9443 "description": "<p>percent to scale the object in the y-axis</p>\n", 9444 "type": "Number", 9445 "optional": true 9446 }, { 9447 "name": "z", 9448 "description": "<p>percent to scale the object in the z-axis (webgl only)</p>\n", 9449 "type": "Number", 9450 "optional": true 9451 }], 9452 "chainable": 1 9453 }, { 9454 "line": 336, 9455 "params": [{ 9456 "name": "scales", 9457 "description": "<p>per-axis percents to scale the object</p>\n", 9458 "type": "p5.Vector|Number[]" 9459 }], 9460 "chainable": 1 9461 }] 9462 }, { 9463 "file": "src/core/transform.js", 9464 "line": 366, 9465 "description": "<p>Shears a shape around the x-axis the amount specified by the angle\nparameter. Angles should be specified in the current angleMode.\nObjects are always sheared around their relative position to the origin\nand positive numbers shear objects in a clockwise direction.\n<br><br>\nTransformations apply to everything that happens after and subsequent\ncalls to the function accumulates the effect. For example, calling\nshearX(PI/2) and then shearX(PI/2) is the same as shearX(PI).\nIf <a href=\"#/p5/shearX\">shearX()</a> is called within the <a href=\"#/p5/draw\">draw()</a>, the transformation is reset when\nthe loop begins again.\n<br><br>
9465\nTechnically, <a href=\"#/p5/shearX\">shearX()</a> multiplies the current transformation matrix by a\nrotation matrix. This function can be further controlled by the\n<a href=\"#/p5/push\">push()</a> and <a href=\"#/p5/pop\">pop()</a> functions.</p>\n", 9466 "itemtype": "method", 9467 "name": "shearX", 9468 "params": [{ 9469 "name": "angle", 9470 "description": "<p>angle of shear specified in radians or degrees,\n depending on current angleMode</p>\n", 9471 "type": "Number" 9472 }], 9473 "chainable": 1, 9474 "example": ["\n<div>\n<code>\ntranslate(width / 4, height / 4);\nshearX(PI / 4.0);\nrect(0, 0, 30, 30);\n</code>\n</div>"], 9475 "alt": "white irregular quadrilateral with black outline at top middle.", 9476 "class": "p5", 9477 "module": "Transform", 9478 "submodule": "Transform" 9479 }, { 9480 "file": "src/core/transform.js", 9481 "line": 405, 9482 "description": "<p>Shears a shape around the y-axis the amount specified by the angle\nparameter. Angles should be specified in the current angleMode. Objects\nare always sheared around their relative position to the origin and\npositive numbers shear objects in a clockwise direction.\n<br><br>\nTransformations apply to everything that happens after and subsequent\ncalls to the function accumulates the effect. For example, calling\nshearY(PI/2) and then shearY(PI/2) is the same as shearY(PI). If\n<a href=\"#/p5/shearY\">shearY()</a> is called within the <a href=\"#/p5/draw\">draw()</a>, the transformation is reset when\nthe loop begins again.\n<br><br>\nTechnically, <a href=\"#/p5/shearY\">shearY()</a> multiplies the current transformation matrix by a\nrotation matrix. This function can be further controlled by the\n<a href=\"#/p5/push\">push()</a> and <a href=\"#/p5/pop\">pop()</a> functions.</p>\n", 9483 "itemtype": "method", 9484 "name": "shearY", 9485 "params": [{ 9486 "name": "angle", 9487 "description": "<p>angle of shear specified in radians or degrees,\n depending on current angleMode</p>\n", 9488 "type": "Number" 9489 }], 9490 "chainable": 1, 9491 "example": ["\n<div>\n<code>\ntranslate(width / 4, height / 4);\nshearY(PI / 4.0);\nrect(0, 0, 30, 30);\n</code>\n</div>"], 9492 "alt": "white irregular quadrilateral with black outline at middle bottom.", 9493 "class": "p5", 9494 "module": "Transform", 9495 "submodule": "Transform" 9496 }, { 9497 "file": "src/core/transform.js", 9498 "line": 444, 9499 "description": "<p>Specifies an amount to displace objects within the display window.\nThe x parameter specifies left/right translation, the y parameter\nspecifies up/down translation.\n<br><br>\nTransformations are cumulative and apply to everything that happens after\nand subsequent calls to the function accumulates the effect. For example,\ncalling translate(50, 0) and then translate(20, 0) is the same as\ntranslate(70, 0). If <a href=\"#/p5/translate\">translate()</a> is called within <a href=\"#/p5/draw\">draw()</a>, the\ntransformation is reset when the loop begins again. This function can be\nfurther controlled by using <a href=\"#/p5/push\">push()</a> and <a href=\"#/p5/pop\">pop()</a>.</p>\n", 9500 "itemtype": "method", 9501 "name": "translate", 9502 "chainable": 1, 9503 "example": ["\n<div>\n<code>\ntranslate(30, 20);\nrect(0, 0, 55, 55);\n</code>\n</div>\n\n<div>\n<code>\nrect(0, 0, 55, 55); // Draw rect at original 0,0\ntranslate(30, 20);\nrect(0, 0, 55, 55); // Draw rect at new 0,0\ntranslate(14, 14);\nrect(0, 0, 55, 55); // Draw rect at new 0,0\n</code>\n</div>\n\n\n<div>\n<code>\nfunction draw() {\n background(200);\n rectMode(CENTER);\n translate(width / 2, height / 2);\n translate(p5.Vector.fromAngle(millis() / 1000, 40));\n rect(0, 0, 20, 20);\n}\n</code>\n</div>"], 9504 "alt": "white 55x55 rect with black outline at center right.\n3 white 55x55 rects with black outlines at top-l, center-r and bottom-r.\na 20x20 white rect moving in a circle around the canvas", 9505 "class": "p5", 9506 "module": "Transform", 9507 "submodule": "Transform", 9508 "overloads": [{ 9509 "line": 444, 9510 "params": [{ 9511 "name": "x", 9512 "description": "<p>left/right translation</p>\n", 9513 "type": "Number" 9514 }, { 9515 "name": "y", 9516 "description": "<p>up/down translation</p>\n", 9517 "type": "Number" 9518 }, { 9519 "name": "z", 9520 "description": "<p>forward/backward translation (webgl only)</p>\n", 9521 "type": "Number", 9522 "optional": true 9523 }], 9524 "chainable": 1 9525 }, { 9526 "line": 498, 9527 "params": [{ 9528 "name": "vector", 9529 "description": "<p>the vector to translate by</p>\n", 9530 "type": "p5.Vector" 9531 }], 9532 "chainable": 1 9533 }] 9534 }, { 9535 "file": "src/data/p5.TypedDict.js", 9536 "line": 16, 9537 "description": "<p>Creates a new instance of p5.StringDict using the key-value pair\n or the object you provide.</p>\n", 9538 "itemtype": "method", 9539 "name": "createStringDict", 9540 "return": { 9541 "description": "", 9542 "type": "p5.StringDict" 9543 }, 9544 "example": ["\n <div class=\"norender\">\n <code>\n function setup() {\n var myDictionary = createStringDict('p5', 'js');\n print(myDictionary.hasKey('p5')); // logs true to console\n var anotherDictionary = createStringDict({ happy: 'coding' });\n print(anotherDictionary.hasKey('happy')); // logs true to console\n }\n </code></div>"], 9545 "class": "p5", 9546 "module": "Data", 9547 "submodule": "Dictionary", 9548 "overloads": [{ 9549 "line": 16, 9550 "params": [{ 9551 "name": "key", 9552 "description": "", 9553 "type": "String" 9554 }, { 9555 "name": "value", 9556 "description": "", 9557 "type": "String" 9558 }], 9559 "return": { 9560 "description": "", 9561 "type": "p5.StringDict" 9562 } 9563 }, { 9564 "line": 39, 9565 "params": [{ 9566 "name": "object", 9567 "description": "<p>object</p>\n", 9568 "type": "Object" 9569 }], 9570 "return": { 9571 "description": "", 9572 "type": "p5.StringDict" 9573 } 9574 }] 9575 }, { 9576 "file": "src/data/p5.TypedDict.js", 9577 "line": 50, 9578 "description": "<p>Creates a new instance of <a href=\"#/p5.NumberDict\">p5.NumberDict</a> using the key-value pair\n or object you provide.</p>\n", 9579 "itemtype": "method", 9580 "name": "createNumberDict", 9581 "return": { 9582 "description": "", 9583 "type": "p5.NumberDict" 9584 }, 9585 "example": ["\n <div class=\"norender\">\n <code>\n function setup() {\n var myDictionary = createNumberDict(100, 42);\n print(myDictionary.hasKey(100)); // logs true to console\n var anotherDictionary = createNumberDict({ 200: 84 });\n print(anotherDictionary.hasKey(200)); // logs true to console\n }\n </code></div>"], 9586 "class": "p5", 9587 "module": "Data", 9588 "submodule": "Dictionary", 9589 "overloads": [{ 9590 "line": 50, 9591 "params": [{ 9592 "name": "key", 9593 "description": "", 9594 "type": "Number" 9595 }, { 9596 "name": "value", 9597 "description": "", 9598 "type": "Number" 9599 }], 9600 "return": { 9601 "description": "", 9602 "type": "p5.NumberDict" 9603 } 9604 }, { 9605 "line": 73, 9606 "params": [{ 9607 "name": "object", 9608 "description": "<p>object</p>\n", 9609 "type": "Object" 9610 }], 9611 "return": { 9612 "description": "", 9613 "type": "p5.NumberDict" 9614 } 9615 }] 9616 }, { 9617 "file": "src/data/p5.TypedDict.js", 9618 "line": 103, 9619 "description": "<p>Returns the number of key-value pairs currently stored in the Dictionary.</p>\n", 9620 "itemtype": "method", 9621 "name": "size", 9622 "return": { 9623 "description": "the number of key-value pairs in the Dictionary", 9624 "type": "Integer" 9625 }, 9626 "example": ["\n<div class=\"norender\">\n<code>\nfunction setup() {\n var myDictionary = createNumberDict(1, 10);\n myDictionary.create(2, 20);\n myDictionary.create(3, 30);\n print(myDictionary.size()); // logs 3 to the console\n}\n</code></div>\n"], 9627 "class": "p5.TypedDict", 9628 "module": "Data", 9629 "submodule": "Dictionary" 9630 }, { 9631 "file": "src/data/p5.TypedDict.js", 9632 "line": 125, 9633 "description": "<p>Returns true if the given key exists in the Dictionary,\notherwise returns false.</p>\n", 9634 "itemtype": "method", 9635 "name": "hasKey", 9636 "params": [{ 9637 "name": "key", 9638 "description": "<p>that you want to look up</p>\n", 9639 "type": "Number|String" 9640 }], 9641 "return": { 9642 "description": "whether that key exists in Dictionary", 9643 "type": "Boolean" 9644 }, 9645 "example": ["\n<div class=\"norender\">\n<code>\nfunction setup() {\n var myDictionary = createStringDict('p5', 'js');\n print(myDictionary.hasKey('p5')); // logs true to console\n}\n</code></div>\n"], 9646 "class": "p5.TypedDict", 9647 "module": "Data", 9648 "submodule": "Dictionary" 9649 }, { 9650 "file": "src/data/p5.TypedDict.js", 9651 "line": 148, 9652 "description": "<p>Returns the value stored at the given key.</p>\n", 9653 "itemtype": "method", 9654 "name": "get", 9655 "params": [{ 9656 "name": "the", 9657 "description": "<p>key you want to access</p>\n", 9658 "type": "Number|String" 9659 }], 9660 "return": { 9661 "description": "the value stored at that key", 9662 "type": "Number|String" 9663 }, 9664 "example": ["\n<div class=\"norender\">\n<code>\nfunction setup() {\n var myDictionary = createStringDict('p5', 'js');\n var myValue = myDictionary.get('p5');\n print(myValue === 'js'); // logs true to console\n}\n</code></div>\n"], 9665 "class": "p5.TypedDict", 9666 "module": "Data", 9667 "submodule": "Dictionary" 9668 }, { 9669 "file": "src/data/p5.TypedDict.js", 9670 "line": 175, 9671 "description": "<p>Updates the value associated with the given key in case it already exists\nin the Dictionary. Otherwise a new key-value pair is added.</p>\n", 9672 "itemtype": "method", 9673 "name": "set", 9674 "params": [{ 9675 "name": "key", 9676 "description": "", 9677 "type": "Number|String" 9678 }, { 9679 "name": "value", 9680 "description": "", 9681 "type": "Number|String" 9682 }], 9683 "example": ["\n<div class=\"norender\">\n<code>\nfunction setup() {\n var myDictionary = createStringDict('p5', 'js');\n myDictionary.set('p5', 'JS');\n myDictionary.print(); // logs \"key: p5 - value: JS\" to console\n}\n</code></div>\n"], 9684 "class": "p5.TypedDict", 9685 "module": "Data", 9686 "submodule": "Dictionary" 9687 }, { 9688 "file": "src/data/p5.TypedDict.js", 9689 "line": 203, 9690 "description": "<p>private helper function to handle the user passing in objects\nduring construction or calls to create()</p>\n", 9691 "class": "p5.TypedDict", 9692 "module": "Data", 9693 "submodule": "Dictionary" 9694 }, { 9695 "file": "src/data/p5.TypedDict.js", 9696 "line": 214, 9697 "description": "<p>Creates a new key-value pair in the Dictionary.</p>\n", 9698 "itemtype": "method", 9699 "name": "create", 9700 "example": ["\n<div class=\"norender\">\n<code>\nfunction setup() {\n var myDictionary = createStringDict('p5', 'js');\n myDictionary.create('happy', 'coding');\n myDictionary.print();\n // above logs \"key: p5 - value: js, key: happy - value: coding\" to console\n}\n</code></div>"], 9701 "class": "p5.TypedDict", 9702 "module": "Data", 9703 "submodule": "Dictionary", 9704 "overloads": [{ 9705 "line": 214, 9706 "params": [{ 9707 "name": "key", 9708 "description": "", 9709 "type": "Number|String" 9710 }, { 9711 "name": "value", 9712 "description": "", 9713 "type": "Number|String" 9714 }] 9715 }, { 9716 "line": 232, 9717 "params": [{ 9718 "name": "obj", 9719 "description": "<p>key/value pair</p>\n", 9720 "type": "Object" 9721 }] 9722 }] 9723 }, { 9724 "file": "src/data/p5.TypedDict.js", 9725 "line": 250, 9726 "description": "<p>Removes all previously stored key-value pairs from the Dictionary.</p>\n", 9727 "itemtype": "method", 9728 "name": "clear", 9729 "example": ["\n<div class=\"norender\">\n<code>\nfunction setup() {\n var myDictionary = createStringDict('p5', 'js');\n print(myDictionary.hasKey('p5')); // prints 'true'\n myDictionary.clear();\n print(myDictionary.hasKey('p5')); // prints 'false'\n}\n</code>\n</div>"], 9730 "class": "p5.TypedDict", 9731 "module": "Data", 9732 "submodule": "Dictionary" 9733 }, { 9734 "file": "src/data/p5.TypedDict.js", 9735 "line": 271, 9736 "description": "<p>Removes the key-value pair stored at the given key from the Dictionary.</p>\n", 9737 "itemtype": "method", 9738 "name": "remove", 9739 "params": [{ 9740 "name": "key", 9741 "description": "<p>for the pair to remove</p>\n", 9742 "type": "Number|String" 9743 }], 9744 "example": ["\n<div class=\"norender\">\n<code>\nfunction setup() {\n var myDictionary = createStringDict('p5', 'js');\n myDictionary.create('happy', 'coding');\n myDictionary.print();\n // above logs \"key: p5 - value: js, key: happy - value: coding\" to console\n myDictionary.remove('p5');\n myDictionary.print();\n // above logs \"key: happy value: coding\" to console\n}\n</code></div>\n"], 9745 "class": "p5.TypedDict", 9746 "module": "Data", 9747 "submodule": "Dictionary" 9748 }, { 9749 "file": "src/data/p5.TypedDict.js", 9750 "line": 301, 9751 "description": "<p>Logs the set of items currently stored in the Dictionary to the console.</p>\n", 9752 "itemtype": "method", 9753 "name": "print", 9754 "example": ["\n<div class=\"norender\">\n<code>\nfunction setup() {\n var myDictionary = createStringDict('p5', 'js');\n myDictionary.create('happy', 'coding');\n myDictionary.print();\n // above logs \"key: p5 - value: js, key: happy - value: coding\" to console\n}\n</code>\n</div>"], 9755 "class": "p5.TypedDict", 9756 "module": "Data", 9757 "submodule": "Dictionary" 9758 }, { 9759 "file": "src/data/p5.TypedDict.js", 9760 "line": 325, 9761 "description": "<p>Converts the Dictionary into a CSV file for local download.</p>\n", 9762 "itemtype": "method", 9763 "name": "saveTable", 9764 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100);\n background(200);\n text('click here to save', 10, 10, 70, 80);\n}\n\nfunction mousePressed() {\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n createStringDict({\n john: 1940,\n paul: 1942,\n george: 1943,\n ringo: 1940\n }).saveTable('beatles');\n }\n}\n</code>\n</div>"], 9765 "class": "p5.TypedDict", 9766 "module": "Data", 9767 "submodule": "Dictionary" 9768 }, { 9769 "file": "src/data/p5.TypedDict.js", 9770 "line": 363, 9771 "description": "<p>Converts the Dictionary into a JSON file for local download.</p>\n", 9772 "itemtype": "method", 9773 "name": "saveJSON", 9774 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100);\n background(200);\n text('click here to save', 10, 10,
9774 70, 80);\n}\n\nfunction mousePressed() {\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n createStringDict({\n john: 1940,\n paul: 1942,\n george: 1943,\n ringo: 1940\n }).saveJSON('beatles');\n }\n}\n</code>\n</div>"], 9775 "class": "p5.TypedDict", 9776 "module": "Data", 9777 "submodule": "Dictionary" 9778 }, { 9779 "file": "src/data/p5.TypedDict.js", 9780 "line": 394, 9781 "description": "<p>private helper function to ensure that the user passed in valid\nvalues for the Dictionary type</p>\n", 9782 "class": "p5.TypedDict", 9783 "module": "Data", 9784 "submodule": "Dictionary" 9785 }, { 9786 "file": "src/data/p5.TypedDict.js", 9787 "line": 437, 9788 "description": "<p>private helper function to ensure that the user passed in valid\nvalues for the Dictionary type</p>\n", 9789 "class": "p5.NumberDict", 9790 "module": "Data", 9791 "submodule": "Dictionary" 9792 }, { 9793 "file": "src/data/p5.TypedDict.js", 9794 "line": 446, 9795 "description": "<p>Add the given number to the value currently stored at the given key.\nThe sum then replaces the value previously stored in the Dictionary.</p>\n", 9796 "itemtype": "method", 9797 "name": "add", 9798 "params": [{ 9799 "name": "Key", 9800 "description": "<p>for the value you wish to add to</p>\n", 9801 "type": "Number" 9802 }, { 9803 "name": "Number", 9804 "description": "<p>to add to the value</p>\n", 9805 "type": "Number" 9806 }], 9807 "example": ["\n<div class='norender'>\n<code>\nfunction setup() {\n var myDictionary = createNumberDict(2, 5);\n myDictionary.add(2, 2);\n print(myDictionary.get(2)); // logs 7 to console.\n}\n</code></div>\n\n"], 9808 "class": "p5.NumberDict", 9809 "module": "Data", 9810 "submodule": "Dictionary" 9811 }, { 9812 "file": "src/data/p5.TypedDict.js", 9813 "line": 474, 9814 "description": "<p>Subtract the given number from the value currently stored at the given key.\nThe difference then replaces the value previously stored in the Dictionary.</p>\n", 9815 "itemtype": "method", 9816 "name": "sub", 9817 "params": [{ 9818 "name": "Key", 9819 "description": "<p>for the value you wish to subtract from</p>\n", 9820 "type": "Number" 9821 }, { 9822 "name": "Number", 9823 "description": "<p>to subtract from the value</p>\n", 9824 "type": "Number" 9825 }], 9826 "example": ["\n<div class='norender'>\n<code>\nfunction setup() {\n var myDictionary = createNumberDict(2, 5);\n myDictionary.sub(2, 2);\n print(myDictionary.get(2)); // logs 3 to console.\n}\n</code></div>\n\n"], 9827 "class": "p5.NumberDict", 9828 "module": "Data", 9829 "submodule": "Dictionary" 9830 }, { 9831 "file": "src/data/p5.TypedDict.js", 9832 "line": 498, 9833 "description": "<p>Multiply the given number with the value currently stored at the given key.\nThe product then replaces the value previously stored in the Dictionary.</p>\n", 9834 "itemtype": "method", 9835 "name": "mult", 9836 "params": [{ 9837 "name": "Key", 9838 "description": "<p>for value you wish to multiply</p>\n", 9839 "type": "Number" 9840 }, { 9841 "name": "Amount", 9842 "description": "<p>to multiply the value by</p>\n", 9843 "type": "Number" 9844 }], 9845 "example": ["\n<div class='norender'>\n<code>\nfunction setup() {\n var myDictionary = createNumberDict(2, 4);\n myDictionary.mult(2, 2);\n print(myDictionary.get(2)); // logs 8 to console.\n}\n</code></div>\n\n"], 9846 "class": "p5.NumberDict", 9847 "module": "Data", 9848 "submodule": "Dictionary" 9849 }, { 9850 "file": "src/data/p5.TypedDict.js", 9851 "line": 526, 9852 "description": "<p>Divide the given number with the value currently stored at the given key.\nThe quotient then replaces the value previously stored in the Dictionary.</p>\n", 9853 "itemtype": "method", 9854 "name": "div", 9855 "params": [{ 9856 "name": "Key", 9857 "description": "<p>for value you wish to divide</p>\n", 9858 "type": "Number" 9859 }, { 9860 "name": "Amount", 9861 "description": "<p>to divide the value by</p>\n", 9862 "type": "Number" 9863 }], 9864 "example": ["\n<div class='norender'>\n<code>\nfunction setup() {\n var myDictionary = createNumberDict(2, 8);\n myDictionary.div(2, 2);\n print(myDictionary.get(2)); // logs 4 to console.\n}\n</code></div>\n\n"], 9865 "class": "p5.NumberDict", 9866 "module": "Data", 9867 "submodule": "Dictionary" 9868 }, { 9869 "file": "src/data/p5.TypedDict.js", 9870 "line": 554, 9871 "description": "<p>private helper function for finding lowest or highest value\nthe argument 'flip' is used to flip the comparison arrow\nfrom 'less than' to 'greater than'</p>\n", 9872 "class": "p5.NumberDict", 9873 "module": "Data", 9874 "submodule": "Dictionary" 9875 }, { 9876 "file": "src/data/p5.TypedDict.js", 9877 "line": 579, 9878 "description": "<p>Return the lowest number currently stored in the Dictionary.</p>\n", 9879 "itemtype": "method", 9880 "name": "minValue", 9881 "return": { 9882 "description": "", 9883 "type": "Number" 9884 }, 9885 "example": ["\n<div class='norender'>\n<code>\nfunction setup() {\n var myDictionary = createNumberDict({ 2: -10, 4: 0.65, 1.2: 3 });\n var lowestValue = myDictionary.minValue(); // value is -10\n print(lowestValue);\n}\n</code></div>\n"], 9886 "class": "p5.NumberDict", 9887 "module": "Data", 9888 "submodule": "Dictionary" 9889 }, { 9890 "file": "src/data/p5.TypedDict.js", 9891 "line": 600, 9892 "description": "<p>Return the highest number currently stored in the Dictionary.</p>\n", 9893 "itemtype": "method", 9894 "name": "maxValue", 9895 "return": { 9896 "description": "", 9897 "type": "Number" 9898 }, 9899 "example": ["\n<div class='norender'>\n<code>\nfunction setup() {\n var myDictionary = createNumberDict({ 2: -10, 4: 0.65, 1.2: 3 });\n var highestValue = myDictionary.maxValue(); // value is 3\n print(highestValue);\n}\n</code></div>\n"], 9900 "class": "p5.NumberDict", 9901 "module": "Data", 9902 "submodule": "Dictionary" 9903 }, { 9904 "file": "src/data/p5.TypedDict.js", 9905 "line": 621, 9906 "description": "<p>private helper function for finding lowest or highest key\nthe argument 'flip' is used to flip the comparison arrow\nfrom 'less than' to 'greater than'</p>\n", 9907 "class": "p5.NumberDict", 9908 "module": "Data", 9909 "submodule": "Dictionary" 9910 }, { 9911 "file": "src/data/p5.TypedDict.js", 9912 "line": 644, 9913 "description": "<p>Return the lowest key currently used in the Dictionary.</p>\n", 9914 "itemtype": "method", 9915 "name": "minKey", 9916 "return": { 9917 "description": "", 9918 "type": "Number" 9919 }, 9920 "example": ["\n<div class='norender'>\n<code>\nfunction setup() {\n var myDictionary = createNumberDict({ 2: 4, 4: 6, 1.2: 3 });\n var lowestKey = myDictionary.minKey(); // value is 1.2\n print(lowestKey);\n}\n</code></div>\n"], 9921 "class": "p5.NumberDict", 9922 "module": "Data", 9923 "submodule": "Dictionary" 9924 }, { 9925 "file": "src/data/p5.TypedDict.js", 9926 "line": 665, 9927 "description": "<p>Return the highest key currently used in the Dictionary.</p>\n", 9928 "itemtype": "method", 9929 "name": "maxKey", 9930 "return": { 9931 "description": "", 9932 "type": "Number" 9933 }, 9934 "example": ["\n<div class='norender'>\n<code>\nfunction setup() {\n var myDictionary = createNumberDict({ 2: 4, 4: 6, 1.2: 3 });\n var highestKey = myDictionary.maxKey(); // value is 4\n print(highestKey);\n}\n</code></div>\n"], 9935 "class": "p5.NumberDict", 9936 "module": "Data", 9937 "submodule": "Dictionary" 9938 }, { 9939 "file": "src/events/acceleration.js", 9940 "line": 12, 9941 "description": "<p>The system variable deviceOrientation always contains the orientation of\nthe device. The value of this variable will either be set 'landscape'
9941\nor 'portrait'. If no data is available it will be set to 'undefined'.\neither LANDSCAPE or PORTRAIT.</p>\n", 9942 "itemtype": "property", 9943 "name": "deviceOrientation", 9944 "type": "Constant", 9945 "readonly": "", 9946 "class": "p5", 9947 "module": "Events", 9948 "submodule": "Acceleration" 9949 }, { 9950 "file": "src/events/acceleration.js", 9951 "line": 23, 9952 "description": "<p>The system variable accelerationX always contains the acceleration of the\ndevice along the x axis. Value is represented as meters per second squared.</p>\n", 9953 "itemtype": "property", 9954 "name": "accelerationX", 9955 "type": "Number", 9956 "readonly": "", 9957 "example": ["\n<div>\n<code>\n// Move a touchscreen device to register\n// acceleration changes.\nfunction draw() {\n background(220, 50);\n fill('magenta');\n ellipse(width / 2, height / 2, accelerationX);\n}\n</code>\n</div>"], 9958 "alt": "Magnitude of device acceleration is displayed as ellipse size", 9959 "class": "p5", 9960 "module": "Events", 9961 "submodule": "Acceleration" 9962 }, { 9963 "file": "src/events/acceleration.js", 9964 "line": 46, 9965 "description": "<p>The system variable accelerationY always contains the acceleration of the\ndevice along the y axis. Value is represented as meters per second squared.</p>\n", 9966 "itemtype": "property", 9967 "name": "accelerationY", 9968 "type": "Number", 9969 "readonly": "", 9970 "example": ["\n<div>\n<code>\n// Move a touchscreen device to register\n// acceleration changes.\nfunction draw() {\n background(220, 50);\n fill('magenta');\n ellipse(width / 2, height / 2, accelerationY);\n}\n</code>\n</div>"], 9971 "alt": "Magnitude of device acceleration is displayed as ellipse size", 9972 "class": "p5", 9973 "module": "Events", 9974 "submodule": "Acceleration" 9975 }, { 9976 "file": "src/events/acceleration.js", 9977 "line": 69, 9978 "description": "<p>The system variable accelerationZ always contains the acceleration of the\ndevice along the z axis. Value is represented as meters per second squared.</p>\n", 9979 "itemtype": "property", 9980 "name": "accelerationZ", 9981 "type": "Number", 9982 "readonly": "", 9983 "example": ["\n<div>\n<code>\n// Move a touchscreen device to register\n// acceleration changes.\nfunction draw() {\n background(220, 50);\n fill('magenta');\n ellipse(width / 2, height / 2, accelerationZ);\n}\n</code>\n</div>"], 9984 "alt": "Magnitude of device acceleration is displayed as ellipse size", 9985 "class": "p5", 9986 "module": "Events", 9987 "submodule": "Acceleration" 9988 }, { 9989 "file": "src/events/acceleration.js", 9990 "line": 94, 9991 "description": "<p>The system variable pAccelerationX always contains the acceleration of the\ndevice along the x axis in the frame previous to the current frame. Value\nis represented as meters per second squared.</p>\n", 9992 "itemtype": "property", 9993 "name": "pAccelerationX", 9994 "type": "Number", 9995 "readonly": "", 9996 "class": "p5", 9997 "module": "Events", 9998 "submodule": "Acceleration" 9999 }, { 10000 "file": "src/events/acceleration.js", 10001 "line": 104, 10002 "description": "<p>The system variable pAccelerationY always contains the acceleration of the\ndevice along the y axis in the frame previous to the current frame. Value\nis represented as meters per second squared.</p>\n", 10003 "itemtype": "property", 10004 "name": "pAccelerationY", 10005 "type": "Number", 10006 "readonly": "", 10007 "class": "p5", 10008 "module": "Events", 10009 "submodule": "Acceleration" 10010 }, { 10011 "file": "src/events/acceleration.js", 10012 "line": 114, 10013 "description": "<p>The system variable pAccelerationZ always contains the acceleration of the\ndevice along the z axis in the frame previous to the current frame. Value\nis represented as meters per second squared.</p>\n", 10014 "itemtype": "property", 10015 "name": "pAccelerationZ", 10016 "type": "Number", 10017 "readonly": "", 10018 "class": "p5", 10019 "module": "Events", 10020 "submodule": "Acceleration" 10021 }, { 10022 "file": "src/events/acceleration.js", 10023 "line": 135, 10024 "description": "<p>The system variable rotationX always contains the rotation of the\ndevice along the x axis. V
10024alue is represented as 0 to +/-180 degrees.\n<br><br>\nNote: The order the rotations are called is important, ie. if used\ntogether, it must be called in the order Z-X-Y or there might be\nunexpected behaviour.</p>\n", 10025 "itemtype": "property", 10026 "name": "rotationX", 10027 "type": "Number", 10028 "readonly": "", 10029 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n //rotateZ(radians(rotationZ));\n rotateX(radians(rotationX));\n //rotateY(radians(rotationY));\n box(200, 200, 200);\n}\n</code>\n</div>"], 10030 "alt": "red horizontal line right, green vertical line bottom. black background.", 10031 "class": "p5", 10032 "module": "Events", 10033 "submodule": "Acceleration" 10034 }, { 10035 "file": "src/events/acceleration.js", 10036 "line": 166, 10037 "description": "<p>The system variable rotationY always contains the rotation of the\ndevice along the y axis. Value is represented as 0 to +/-90 degrees.\n<br><br>\nNote: The order the rotations are called is important, ie. if used\ntogether, it must be called in the order Z-X-Y or there might be\nunexpected behaviour.</p>\n", 10038 "itemtype": "property", 10039 "name": "rotationY", 10040 "type": "Number", 10041 "readonly": "", 10042 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n //rotateZ(radians(rotationZ));\n //rotateX(radians(rotationX));\n rotateY(radians(rotationY));\n box(200, 200, 200);\n}\n</code>\n</div>"], 10043 "alt": "red horizontal line right, green vertical line bottom. black background.", 10044 "class": "p5", 10045 "module": "Events", 10046 "submodule": "Acceleration" 10047 }, { 10048 "file": "src/events/acceleration.js", 10049 "line": 197, 10050 "description": "<p>The system variable rotationZ always contains the rotation of the\ndevice along the z axis. Value is represented as 0 to 359 degrees.\n<br><br>\nUnlike rotationX and rotationY, this variable is available for devices\nwith a built-in compass only.\n<br><br>\nNote: The order the rotations are called is important, ie. if used\ntogether, it must be called in the order Z-X-Y or there might be\nunexpected behaviour.</p>\n", 10051 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n rotateZ(radians(rotationZ));\n //rotateX(radians(rotationX));\n //rotateY(radians(rotationY));\n box(200, 200, 200);\n}\n</code>\n</div>"], 10052 "itemtype": "property", 10053 "name": "rotationZ", 10054 "type": "Number", 10055 "readonly": "", 10056 "alt": "red horizontal line right, green vertical line bottom. black background.", 10057 "class": "p5", 10058 "module": "Events", 10059 "submodule": "Acceleration" 10060 }, { 10061 "file": "src/events/acceleration.js", 10062 "line": 233, 10063 "description": "<p>The system variable pRotationX always contains the rotation of the\ndevice along the x axis in the frame previous to the current frame. Value\nis represented as 0 to +/-180 degrees.\n<br><br>\npRotationX can also be used with rotationX to determine the rotate\ndirection of the device along the X-axis.</p>\n", 10064 "example": ["\n<div class='norender'>\n<code>\n// A simple if statement looking at whether\n// rotationX - pRotationX < 0 is true or not will be\n// sufficient for determining the rotate direction\n// in most cases.\n\n// Some extra logic is needed to account for cases where\n// the angles wrap around.\nlet rotateDirection = 'clockwise';\n\n// Simple range conversion to make things simpler.\n// This is not absolutely necessary but the logic\n// will be different in that case.\n\nlet rX = rotationX + 180;\nlet pRX = pRotationX + 180;\n\nif ((rX - pRX > 0 && rX - pRX < 270) || rX - pRX < -270) {\n rotateDirection = 'clockwise';\n} else if (rX - pRX < 0 || rX - pRX > 270) {\n rotateDirection = 'counter-clockwise';\n}\n\nprint(rotateDirection);\n</code>\n</div>"], 10065 "alt": "no image to display.", 10066 "itemtype": "property", 10067 "name": "pRotationX", 10068 "type": "Number", 10069 "readonly": "", 10070 "class": "p5", 10071 "module": "Events", 10072 "submodule": "Acceleration" 10073 }, { 10074 "file": "src/events/acceleration.js", 10075 "line": 278, 10076 "description": "<p>The system variable pRotationY always contains the rotation of the\ndevice along the y axis in the frame previous to the current frame. Value\nis represented as 0 to +/-90 degrees.\n<br><br>\npRotationY can also be used with rotationY to determine the rotate\ndirection of the device along the Y-axis.</p>\n", 10077 "example": ["\n<div class='norender'>\n<code>\n// A simple if statement looking at whether\n// rotationY - pRotationY < 0 is true or not will be\n// sufficient for determining the rotate direction\n// in most cases.\n\n// Some extra logic is needed to account for cases where\n// the angles wrap around.\nlet rotateDirection = 'clockwise';\n\n// Simple range conversion to make things simpler.\n// This is not absolutely necessary but the logic\n// will be different in that case.\n\nlet rY = rotationY + 180;\nlet pRY = pRotationY + 180;\n\nif ((rY - pRY > 0 && rY - pRY < 270) || rY - pRY < -270) {\n rotateDirection = 'clockwise';\n} else if (rY - pRY < 0 || rY - pRY > 270) {\n rotateDirection = 'counter-clockwise';\n}\nprint(rotateDirection);\n</code>\n</div>"], 10078 "alt": "no image to display.", 10079 "itemtype": "property", 10080 "name": "pRotationY", 10081 "type": "Number", 10082 "readonly": "", 10083 "class": "p5", 10084 "module": "Events", 10085 "submodule": "Acceleration" 10086 }, { 10087 "file": "src/events/acceleration.js", 10088 "line": 322, 10089 "description": "<p>The system variable pRotationZ always contains the rotation of the\ndevice along the z axis in the frame previous to the current frame. Value\nis represented as 0 to 359 degrees.\n<br><br>\npRotationZ can also be used with rotationZ to determine the rotate\ndirection of the device along the Z-axis.</p>\n", 10090 "example": ["\n<div class='norender'>\n<code>\n// A simple if statement looking at whether\n// rotationZ - pRotationZ < 0 is true or not will be\n// sufficient for determining the rotate direction\n// in most cases.\n\n// Some extra logic is needed to account for cases where\n// the angles wrap around.\nlet rotateDirection = 'clockwise';\n\nif (\n (rotationZ - pRotationZ > 0 && rotationZ - pRotationZ < 270) ||\n rotationZ - pRotationZ < -270\n) {\n rotateDirection = 'clockwise';\n} else if (rotationZ - pRotationZ < 0 || rotationZ - pRotationZ > 270) {\n rotateDirection = 'counter-clockwise';\n}\nprint(rotateDirection);\n</code>\n</div>"], 10091 "alt": "no image to display.", 10092 "itemtype": "property", 10093 "name": "pRotationZ", 10094 "type": "Number", 10095 "readonly": "", 10096 "class": "p5", 10097 "module": "Events", 10098 "submodule": "Acceleration" 10099 }, { 10100 "file": "src/events/acceleration.js", 10101 "line": 380, 10102 "description": "<p>When a device is rotated, the axis that triggers the <a href=\"#/p5/deviceTurned\">deviceTurned()</a>\nmethod is stored in the turnAxis variable. The turnAxis variable is only defined within\nthe scope of deviceTurned().</p>\n", 10103 "itemtype": "property", 10104 "name": "turnAxis", 10105 "type": "String", 10106 "readonly": "", 10107 "example": ["\n<div>\n<code>\n// Run this example on a mobile device\n// Rotate the device by 90 degrees in the\n// X-axis to change the value.\n\nvar value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction deviceTurned() {\n if (turnAxis === 'X') {\n if (value === 0) {\n value = 255;\n }
10107 else if (value === 255) {\n value = 0;\n }\n }\n}\n</code>\n</div>"], 10108 "alt": "50x50 black rect in center of canvas. turns white on mobile when device turns\n50x50 black rect in center of canvas. turns white on mobile when x-axis turns", 10109 "class": "p5", 10110 "module": "Events", 10111 "submodule": "Acceleration" 10112 }, { 10113 "file": "src/events/acceleration.js", 10114 "line": 419, 10115 "description": "<p>The <a href=\"#/p5/setMoveThreshold\">setMoveThreshold()</a> function is used to set the movement threshold for\nthe <a href=\"#/p5/deviceMoved\">deviceMoved()</a> function. The default threshold is set to 0.5.</p>\n", 10116 "itemtype": "method", 10117 "name": "setMoveThreshold", 10118 "params": [{ 10119 "name": "value", 10120 "description": "<p>The threshold value</p>\n", 10121 "type": "Number" 10122 }], 10123 "example": ["\n<div class=\"norender\">\n<code>\n// Run this example on a mobile device\n// You will need to move the device incrementally further\n// the closer the square's color gets to white in order to change the value.\n\nlet value = 0;\nlet threshold = 0.5;\nfunction setup() {\n setMoveThreshold(threshold);\n}\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction deviceMoved() {\n value = value + 5;\n threshold = threshold + 0.1;\n if (value > 255) {\n value = 0;\n threshold = 30;\n }\n setMoveThreshold(threshold);\n}\n</code>\n</div>"], 10124 "alt": "50x50 black rect in center of canvas. turns white on mobile when device moves", 10125 "class": "p5", 10126 "module": "Events", 10127 "submodule": "Acceleration" 10128 }, { 10129 "file": "src/events/acceleration.js", 10130 "line": 462, 10131 "description": "<p>The <a href=\"#/p5/setShakeThreshold\">setShakeThreshold()</a> function is used to set the movement threshold for\nthe <a href=\"#/p5/deviceShaken\">deviceShaken()</a> function. The default threshold is set to 30.</p>\n", 10132 "itemtype": "method", 10133 "name": "setShakeThreshold", 10134 "params": [{ 10135 "name": "value", 10136 "description": "<p>The threshold value</p>\n", 10137 "type": "Number" 10138 }], 10139 "example": ["\n<div class=\"norender\">\n<code>\n// Run this example on a mobile device\n// You will need to shake the device more firmly\n// the closer the box's fill gets to white in order to change the value.\n\nlet value = 0;\nlet threshold = 30;\nfunction setup() {\n setShakeThreshold(threshold);\n}\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction deviceMoved() {\n value = value + 5;\n threshold = threshold + 5;\n if (value > 255) {\n value = 0;\n threshold = 30;\n }\n setShakeThreshold(threshold);\n}\n</code>\n</div>"], 10140 "alt": "50x50 black rect in center of canvas. turns white on mobile when device\nis being shaked", 10141 "class": "p5", 10142 "module": "Events", 10143 "submodule": "Acceleration" 10144 }, { 10145 "file": "src/events/acceleration.js", 10146 "line": 506, 10147 "description": "<p>The <a href=\"#/p5/deviceMoved\">deviceMoved()</a> function is called when the device is moved by more than\nthe threshold value along X, Y or Z axis. The default threshold is set to 0.5.\nThe threshold value can be changed using <a href=\"https://p5js.org/reference/#/p5/setMoveThreshold\">setMoveThreshold()</a>.</p>\n", 10148 "itemtype": "method", 10149 "name": "deviceMoved", 10150 "example": ["\n<div class=\"norender\">\n<code>\n// Run this example on a mobile device\n// Move the device around\n// to change the value.\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction deviceMoved() {\n value = value + 5;\n if (value > 255) {\n value = 0;\n }\n}\n</code>\n</div>"], 10151 "alt": "50x50 black rect in center of canvas. turns white on mobile when device moves", 10152 "class": "p5", 10153 "module": "Events", 10154 "submodule": "Acceleration" 10155 }, { 10156 "file": "src/events/acceleration.js", 10157 "line": 538, 10158 "description": "<p>The <a href=\"#/p5/deviceTurned\">deviceTurned()</a> function is called when the device rotates by\nmore than 90 degrees continuously.\n<br><br>\nThe axis that triggers the <a href=\"#/p5/deviceTurned\">deviceTurned()</a> method is stored in the turnAxis\nvariable. The <a href=\"#/p5/deviceTurned\">deviceTurned()</a> method can be locked to trigger on any axis:\nX, Y or Z by comparing the turnAxis variable to 'X', 'Y' or 'Z'.</p>\n", 10159 "itemtype": "method", 10160 "name": "deviceTurned", 10161 "example": ["\n<div class=\"norender\">\n<code>\n// Run this example on a mobile device\n// Rotate the device by 90 degrees\n// to change the value.\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction deviceTurned() {\n if (value === 0) {\n value = 255;\n }
10161 else if (value === 255) {\n value = 0;\n }\n}\n</code>\n</div>\n<div>\n<code>\n// Run this example on a mobile device\n// Rotate the device by 90 degrees in the\n// X-axis to change the value.\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction deviceTurned() {\n if (turnAxis === 'X') {\n if (value === 0) {\n value = 255;\n } else if (value === 255) {\n value = 0;\n }\n }\n}\n</code>\n</div>"], 10162 "alt": "50x50 black rect in center of canvas. turns white on mobile when device turns\n50x50 black rect in center of canvas. turns white on mobile when x-axis turns", 10163 "class": "p5", 10164 "module": "Events", 10165 "submodule": "Acceleration" 10166 }, { 10167 "file": "src/events/acceleration.js", 10168 "line": 597, 10169 "description": "<p>The <a href=\"#/p5/deviceShaken\">deviceShaken()</a> function is called when the device total acceleration\nchanges of accelerationX and accelerationY values is more than\nthe threshold value. The default threshold is set to 30.\nThe threshold value can be changed using <a href=\"https://p5js.org/reference/#/p5/setShakeThreshold\">setShakeThreshold()</a>.</p>\n", 10170 "itemtype": "method", 10171 "name": "deviceShaken", 10172 "example": ["\n<div class=\"norender\">\n<code>\n// Run this example on a mobile device\n// Shake the device to change the value.\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction deviceShaken() {\n value = value + 5;\n if (value > 255) {\n value = 0;\n }\n}\n</code>\n</div>"], 10173 "alt": "50x50 black rect in center of canvas. turns white on mobile when device shakes", 10174 "class": "p5", 10175 "module": "Events", 10176 "submodule": "Acceleration" 10177 }, { 10178 "file": "src/events/keyboard.js", 10179 "line": 18, 10180 "description": "<p>The boolean system variable <a href=\"#/p5/keyIsPressed\">keyIsPressed</a> is true if any key is pressed\nand false if no keys are pressed.</p>\n", 10181 "itemtype": "property", 10182 "name": "keyIsPressed", 10183 "type": "Boolean", 10184 "readonly": "", 10185 "example": ["\n<div>\n<code>\nfunction draw() {\n if (keyIsPressed === true) {\n fill(0);\n } else {\n fill(255);\n }\n rect(25, 25, 50, 50);\n}\n</code>\n</div>"], 10186 "alt": "50x50 white rect that turns black on keypress.", 10187 "class": "p5", 10188 "module": "Events", 10189 "submodule": "Keyboard" 10190 }, { 10191 "file": "src/events/keyboard.js", 10192 "line": 45, 10193 "description": "<p>The system variable key always contains the value of the most recent\nkey on the keyboard that was typed. To get the proper capitalization, it\nis best to use it within <a href=\"#/p5/keyTyped\">keyTyped()</a>. For non-ASCII keys, use the <a href=\"#/p5/keyCode\">keyCode</a>\nvariable.</p>\n", 10194 "itemtype": "property", 10195 "name": "key", 10196 "type": "String", 10197 "readonly": "", 10198 "example": ["\n<div><code>\n// Click any key to display it!\n// (Not Guaranteed to be Case Sensitive)\nfunction setup() {\n fill(245, 123, 158);\n textSize(50);\n}\n\nfunction draw() {\n background(200);\n text(key, 33, 65); // Display last key pressed.\n}\n</code></div>"], 10199 "alt": "canvas displays any key value that is pressed in pink font.", 10200 "class": "p5", 10201 "module": "Events", 10202 "submodule": "Keyboard" 10203 }, { 10204 "file": "src/events/keyboard.js", 10205 "line": 74, 10206 "description": "<p>The variable keyCode is used to detect special keys such as BACKSPACE,\nDELETE, ENTER, RETURN, TAB, ESCAPE, SHIFT, CONTROL, OPTION, ALT, UP_ARROW,\nDOWN_ARROW, LEFT_ARROW, RIGHT_ARROW.\nYou can also check for custom keys by looking up the keyCode of any key\non a site like this: <a href=\"http://keycode.info/\">keycode.info</a>.</p>\n", 10207 "itemtype": "property", 10208 "name": "keyCode", 10209 "type": "Integer", 10210 "readonly": "", 10211 "example": ["\n<div><code>\nlet fillVal = 126;\nfunction draw() {\n fill(fillVal);\n rect(25, 25, 50, 50);\n}\n\nfunction keyPressed() {\n if (keyCode === UP_ARROW) {\n fillVal = 255;\n } else if (keyCode === DOWN_ARROW) {\n fillVal = 0;\n }\n return false; // prevent default\n}\n</code></div>"], 10212 "alt": "Grey rect center. turns white when up arrow pressed and black when down", 10213 "class": "p5", 10214 "module": "Events", 10215 "submodule": "Keyboard" 10216 }, { 10217 "file": "src/events/keyboard.js", 10218 "line": 107, 10219 "description": "<p>The <a href=\"#/p5/keyPressed\">keyPressed()</a> function is called once every time a key is pressed. The\nkeyCode for the key that was pressed is stored in the <a href=\"#/p5/keyCode\">keyCode</a> variable.\n<br><br>\nFor non-ASCII keys, use the keyCode variable. You can check if the keyCode\nequals BACKSPACE, DELETE, ENTE
10219R, RETURN, TAB, ESCAPE, SHIFT, CONTROL,\nOPTION, ALT, UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW.\n<br><br>\nFor ASCII keys, the key that was pressed is stored in the key variable. However, it\ndoes not distinguish between uppercase and lowercase. For this reason, it\nis recommended to use <a href=\"#/p5/keyTyped\">keyTyped()</a> to read the key variable, in which the\ncase of the variable will be distinguished.\n<br><br>\nBecause of how operating systems handle key repeats, holding down a key\nmay cause multiple calls to <a href=\"#/p5/keyTyped\">keyTyped()</a> (and <a href=\"#/p5/keyReleased\">keyReleased()</a> as well). The\nrate of repeat is set by the operating system and how each computer is\nconfigured.<br><br>\nBrowsers may have different default\nbehaviors attached to various key events. To prevent any default\nbehavior for this event, add "return false" to the end of the method.</p>\n", 10220 "itemtype": "method", 10221 "name": "keyPressed", 10222 "example": ["\n<div>\n<code>\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction keyPressed() {\n if (value === 0) {\n value = 255;\n } else {\n value = 0;\n }\n}\n</code>\n</div>\n<div>\n<code>\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction keyPressed() {\n if (keyCode === LEFT_ARROW) {\n value = 255;\n } else if (keyCode === RIGHT_ARROW) {\n value = 0;\n }\n}\n</code>\n</div>\n<div class=\"norender\">\n<code>\nfunction keyPressed() {\n // Do something\n return false; // prevent any default behaviour\n}\n</code>\n</div>"], 10223 "alt": "black rect center. turns white when key pressed and black when released\nblack rect center. turns white when left arrow pressed and black when right.", 10224 "class": "p5", 10225 "module": "Events", 10226 "submodule": "Keyboard" 10227 }, { 10228 "file": "src/events/keyboard.js", 10229 "line": 194, 10230 "description": "<p>The <a href=\"#/p5/keyReleased\">keyReleased()</a> function is called once every time a key is released.\nSee <a href=\"#/p5/key\">key</a> and <a href=\"#/p5/keyCode\">keyCode</a> for more information.<br><br>\nBrowsers may have different default\nbehaviors attached to various key events. To prevent any default\nbehavior for this event, add "return false" to the end of the method.</p>\n", 10231 "itemtype": "method", 10232 "name": "keyReleased", 10233 "example": ["\n<div>\n<code>\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction keyReleased() {\n if (value === 0) {\n value = 255;\n } else {\n value = 0;\n }\n return false; // prevent any default behavior\n}\n</code>\n</div>"], 10234 "alt": "black rect center. turns white when key pressed and black when pressed again", 10235 "class": "p5", 10236 "module": "Events", 10237 "submodule": "Keyboard" 10238 }, { 10239 "file": "src/events/keyboard.js", 10240 "line": 246, 10241 "description": "<p>The <a href=\"#/p5/keyTyped\">keyTyped()</a> function is called once every time a key is pressed, but\naction keys such as Ctrl, Shift, and Alt are ignored. The most recent\nkey pressed will be stored in the key variable.\n<br><br>\nBecause of how operating systems handle key repeats, holding down a key\nwill cause multiple calls to <a href=\"#/p5/keyTyped\">keyTyped()</a> (and <a href=\"#/p5/keyReleased\">keyReleased()</a> as well). The\nrate of repeat is set by the operating system and how each computer is\nconfigured.<br><br>\nBrowsers may have different default behaviors attached to various key\nevents. To prevent any default behavior for this event, add "return false"\nto the end of the method.</p>\n", 10242 "itemtype": "method", 10243 "name": "keyTyped", 10244 "example": ["\n<div>\n<code>\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction keyTyped() {\n if (key === 'a') {\n value = 255;\n } else if (key === 'b') {\n value = 0;\n }\n // uncomment to prevent any default behavior\n // return false;\n}\n</code>\n</div>"], 10245 "alt": "black rect center. turns white when 'a' key typed and black when 'b' pressed", 10246 "class": "p5", 10247 "module": "Events", 10248 "submodule": "Keyboard" 10249 }, { 10250 "file": "src/events/keyboard.js", 10251 "line": 300, 10252 "description": "<p>The onblur function is called when the user is no longer focused\non the p5 element. Because the keyup events will not fire if the user is\nnot focused on the element we must assume all keys currently down have\nbeen released.</p>\n", 10253 "class": "p5", 10254 "module": "Events", 10255 "submodule": "Keyboard" 10256 }, { 10257 "file": "src/events/keyboard.js", 10258 "line": 310, 10259 "description": "<p>The <a href=\"#/p5/keyIsDown\">keyIsDown()</a> function checks if the key is currently down, i.e. pressed.\nIt can be used if you have an object that moves, and you want several keys\nto be able to affect its behaviour simultaneously, such as moving a\nsprite diagonally. You can put in any number representing the keyCode of\nthe key, or use any of the variable <a href=\"#/p5/keyCode\">keyCode</a> names listed\n<a href=\"http://p5js.org/reference/#p5/keyCode\">here</a>.</p>\n", 10260 "itemtype": "method", 10261 "name": "keyIsDown", 10262 "params": [{ 10263 "name": "code", 10264 "description": "<p>The key to check for.</p>\n", 10265 "type": "Number" 10266 }], 10267 "return": { 10268 "description": "whether key is down or not", 10269 "type": "Boolean" 10270 }, 10271 "example": ["\n<div><code>\nlet x = 100;\nlet y = 100;\n\nfunction setup() {\n createCanvas(512, 512);\n}\n\nfunction draw() {\n if (keyIsDown(LEFT_ARROW)) {\n x -= 5;\n }\n\n if (keyIsDown(RIGHT_ARROW)) {\n x += 5;\n }\n\n if (keyIsDown(UP_ARROW)) {\n y -= 5;\n }\n\n if (keyIsDown(DOWN_ARROW)) {\n y += 5;\n }\n\n clear();\n fill(255, 0, 0);\n ellipse(x, y, 50, 50);\n}\n</code></div>\n\n<div><code>\nlet diameter = 50;\n\nfunction setup() {\n createCanvas(512, 512);\n}\n\nfunction draw() {\n // 107 and 187 are keyCodes for \"+\"\n if (keyIsDown(107) || keyIsDown(187)) {\n diameter += 1;\n }
10271\n\n // 109 and 189 are keyCodes for \"-\"\n if (keyIsDown(109) || keyIsDown(189)) {\n diameter -= 1;\n }\n\n clear();\n fill(255, 0, 0);\n ellipse(50, 50, diameter, diameter);\n}\n</code></div>"], 10272 "alt": "50x50 red ellipse moves left, right, up and down with arrow presses.\n50x50 red ellipse gets bigger or smaller when + or - are pressed.", 10273 "class": "p5", 10274 "module": "Events", 10275 "submodule": "Keyboard" 10276 }, { 10277 "file": "src/events/mouse.js", 10278 "line": 22, 10279 "description": "<p>The system variable mouseX always contains the current horizontal\nposition of the mouse, relative to (0, 0) of the canvas. If touch is\nused instead of mouse input, mouseX will hold the x value of the most\nrecent touch point.</p>\n", 10280 "itemtype": "property", 10281 "name": "mouseX", 10282 "type": "Number", 10283 "readonly": "", 10284 "example": ["\n<div>\n<code>\n// Move the mouse across the canvas\nfunction draw() {\n background(244, 248, 252);\n line(mouseX, 0, mouseX, 100);\n}\n</code>\n</div>"], 10285 "alt": "horizontal black line moves left and right with mouse x-position", 10286 "class": "p5", 10287 "module": "Events", 10288 "submodule": "Mouse" 10289 }, { 10290 "file": "src/events/mouse.js", 10291 "line": 48, 10292 "description": "<p>The system variable mouseY always contains the current vertical position\nof the mouse, relative to (0, 0) of the canvas. If touch is\nused instead of mouse input, mouseY will hold the y value of the most\nrecent touch point.</p>\n", 10293 "itemtype": "property", 10294 "name": "mouseY", 10295 "type": "Number", 10296 "readonly": "", 10297 "example": ["\n<div>\n<code>\n// Move the mouse across the canvas\nfunction draw() {\n background(244, 248, 252);\n line(0, mouseY, 100, mouseY);\n}\n</code>\n</div>"], 10298 "alt": "vertical black line moves up and down with mouse y-position", 10299 "class": "p5", 10300 "module": "Events", 10301 "submodule": "Mouse" 10302 }, { 10303 "file": "src/events/mouse.js", 10304 "line": 74, 10305 "description": "<p>The system variable pmouseX always contains the horizontal position of\nthe mouse or finger in the frame previous to the current frame, relative to\n(0, 0) of the canvas. Note: pmouseX will be reset to the current mouseX\nvalue at the start of each touch event.</p>\n", 10306 "itemtype": "property", 10307 "name": "pmouseX", 10308 "type": "Number", 10309 "readonly": "", 10310 "example": ["\n<div>\n<code>\n// Move the mouse across the canvas to leave a trail\nfunction setup() {\n //slow down the frameRate to make it more visible\n frameRate(10);\n}\n\nfunction draw() {\n background(244, 248, 252);\n line(mouseX, mouseY, pmouseX, pmouseY);\n print(pmouseX + ' -> ' + mouseX);\n}\n</code>\n</div>"], 10311 "alt": "line trail is created from cursor movements. faster movement make longer line.", 10312 "class": "p5", 10313 "module": "Events", 10314 "submodule": "Mouse" 10315 }, { 10316 "file": "src/events/mouse.js", 10317 "line": 106, 10318 "description": "<p>The system variable pmouseY always contains the vertical position of the\nmouse or finger in the frame previous to the current frame, relative to\n(0, 0) of the canvas. Note: pmouseY will be reset to the current mouseY\nvalue at the start of each touch event.</p>\n", 10319 "itemtype": "property", 10320 "name": "pmouseY", 10321 "type": "Number", 10322 "readonly": "", 10323 "example": ["\n<div>\n<code>\nfunction draw() {\n background(237, 34, 93);\n fill(0);\n //draw a square only if the mouse is not moving\n if (mouseY === pmouseY && mouseX === pmouseX) {\n rect(20, 20, 60, 60);\n }\n\n print(pmouseY + ' -> ' + mouseY);\n}\n</code>\n</div>"], 10324 "alt": "60x60 black rect center, fuschia background. rect flickers on mouse movement", 10325 "class": "p5", 10326 "module": "Events", 10327 "submodule": "Mouse" 10328 }, { 10329 "file": "src/events/mouse.js", 10330 "line": 137, 10331 "description": "<p>The system variable winMouseX always contains the current horizontal\nposition of the mouse, relative to (0, 0) of the window.</p>\n", 10332 "itemtype": "property", 10333 "name": "winMouseX", 10334 "type": "Number", 10335 "readonly": "", 10336 "example": ["\n<div>\n<code>\nlet myCanvas;\n\nfunction setup() {\n //use a variable to store a pointer to the canvas\n myCanvas = createCanvas(100, 100);\n}\n\nfunction draw() {\n background(237, 34, 93);\n fill(0);\n\n //move the canvas to the horizontal mouse position\n //rela tive to the window\n myCanvas.position(winMouseX + 1, windowHeight / 2);\n\n //the y of the square is relative to the canvas\n rect(20, mouseY, 60, 60);\n}\n</code>\n</div>"], 10337 "alt": "60x60 black rect y moves with mouse y and fuschia canvas moves with mouse x", 10338 "class": "p5", 10339 "module": "Events", 10340 "submodule": "Mouse" 10341 }, { 10342 "file": "src/events/mouse.js", 10343 "line": 174, 10344 "description": "<p>The system variable winMouseY always contains the current vertical\nposition of the mouse, relative to (0, 0) of the window.</p>\n", 10345 "itemtype": "property", 10346 "name": "winMouseY", 10347 "type": "Number", 10348 "readonly": "", 10349 "example": ["\n<div>\n<code>\nlet myCanvas;\n\nfunction setup() {\n //use a variable to store a pointer to the canvas\n myCanvas = createCanvas(100, 100);\n}\n\nfunction draw() {\n background(237, 34, 93);\n fill(0);\n\n //move the canvas to the vertical mouse position\n //rel ative to the window\n myCanvas.position(windowWidth / 2, winMouseY
10349+ 1);\n\n //the x of the square is relative to the canvas\n rect(mouseX, 20, 60, 60);\n}\n</code>\n</div>"], 10350 "alt": "60x60 black rect x moves with mouse x and fuschia canvas y moves with mouse y", 10351 "class": "p5", 10352 "module": "Events", 10353 "submodule": "Mouse" 10354 }, { 10355 "file": "src/events/mouse.js", 10356 "line": 211, 10357 "description": "<p>The system variable pwinMouseX always contains the horizontal position\nof the mouse in the frame previous to the current frame, relative to\n(0, 0) of the window. Note: pwinMouseX will be reset to the current winMouseX\nvalue at the start of each touch event.</p>\n", 10358 "itemtype": "property", 10359 "name": "pwinMouseX", 10360 "type": "Number", 10361 "readonly": "", 10362 "example": ["\n<div>\n<code>\nlet myCanvas;\n\nfunction setup() {\n //use a variable to store a pointer to the canvas\n myCanvas = createCanvas(100, 100);\n noStroke();\n fill(237, 34, 93);\n}\n\nfunction draw() {\n clear();\n //the difference between previous and\n //current x position is the horizontal mouse speed\n let speed = abs(winMouseX - pwinMouseX);\n //change the size of the circle\n //according to the horizontal speed\n ellipse(50, 50, 10 + speed * 5, 10 + speed * 5);\n //move the canvas to the mouse position\n myCanvas.position(winMouseX + 1, winMouseY + 1);\n}\n</code>\n</div>"], 10363 "alt": "fuschia ellipse moves with mouse x and y. Grows and shrinks with mouse speed", 10364 "class": "p5", 10365 "module": "Events", 10366 "submodule": "Mouse" 10367 }, { 10368 "file": "src/events/mouse.js", 10369 "line": 252, 10370 "description": "<p>The system variable pwinMouseY always contains the vertical position of\nthe mouse in the frame previous to the current frame, relative to (0, 0)\nof the window. Note: pwinMouseY will be reset to the current winMouseY\nvalue at the start of each touch event.</p>\n", 10371 "itemtype": "property", 10372 "name": "pwinMouseY", 10373 "type": "Number", 10374 "readonly": "", 10375 "example": ["\n<div>\n<code>\nlet myCanvas;\n\nfunction setup() {\n //use a variable to store a pointer to the canvas\n myCanvas = createCanvas(100, 100);\n noStroke();\n fill(237, 34, 93);\n}\n\nfunction draw() {\n clear();\n //the difference between previous and\n //current y position is the vertical mouse speed\n let speed = abs(winMouseY - pwinMouseY);\n //change the size of the circle\n //according to the vertical speed\n ellipse(50, 50, 10 + speed * 5, 10 + speed * 5);\n //move the canvas to the mouse position\n myCanvas.position(winMouseX + 1, winMouseY + 1);\n}\n</code>\n</div>"], 10376 "alt": "fuschia ellipse moves with mouse x and y. Grows and shrinks with mouse speed", 10377 "class": "p5", 10378 "module": "Events", 10379 "submodule": "Mouse" 10380 }, { 10381 "file": "src/events/mouse.js", 10382 "line": 294, 10383 "description": "<p>Processing automatically tracks if the mouse button is pressed and which\nbutton is pressed. The value of the system variable mouseButton is either\nLEFT, RIGHT, or CENTER depending on which button was pressed last.\nWarning: different browsers may track mouseButton differently.</p>\n", 10384 "itemtype": "property", 10385 "name": "mouseButton", 10386 "type": "Constant", 10387 "readonly": "", 10388 "example": ["\n<div>\n<code>\nfunction draw() {\n background(237, 34, 93);\n fill(0);\n\n if (mouseIsPressed) {\n if (mouseButton === LEFT) {\n ellipse(50, 50, 50, 50);\n }\n if (mouseButton === RIGHT) {\n rect(25, 25, 50, 50);\n }\n if (mouseButton === CENTER) {\n triangle(23, 75, 50, 20, 78, 75);\n }\n }\n\n print(mouseButton);\n}\n</code>\n</div>"], 10389 "alt": "50x50 black ellipse appears on center of fuschia canvas on mouse click/press.", 10390 "class": "p5", 10391 "module": "Events", 10392 "submodule": "Mouse" 10393 }, { 10394 "file": "src/events/mouse.js", 10395 "line": 333, 10396 "description": "<p>The boolean system variable mouseIsPressed is true if the mouse is pressed\nand false if not.</p>\n", 10397 "itemtype": "property", 10398 "name": "mouseIsPressed", 10399 "type": "Boolean", 10400 "readonly": "", 10401 "example": ["\n<div>\n<code>\nfunction draw() {\n background(237, 34, 93);\n fill(0);\n\n if (mouseIsPressed) {\n ellipse(50, 50, 50, 50);\n } else {\n rect(25, 25, 50, 50);\n }\n\n print(mouseIsPressed);\n}\n</code>\n</div>"],
10402 "alt": "black 50x50 rect becomes ellipse with mouse click/press. fuschia background.", 10403 "class": "p5", 10404 "module": "Events", 10405 "submodule": "Mouse" 10406 }, { 10407 "file": "src/events/mouse.js", 10408 "line": 424, 10409 "description": "<p>The <a href=\"#/p5/mouseMoved\">mouseMoved()</a> function is called every time the mouse moves and a mouse\nbutton is not pressed.<br><br>\nBrowsers may have different default\nbehaviors attached to various mouse events. To prevent any default\nbehavior for this event, add "return false" to the end of the method.</p>\n", 10410 "itemtype": "method", 10411 "name": "mouseMoved", 10412 "params": [{ 10413 "name": "event", 10414 "description": "<p>optional MouseEvent callback argument.</p>\n", 10415 "type": "Object", 10416 "optional": true 10417 }], 10418 "example": ["\n<div>\n<code>\n// Move the mouse across the page\n// to change its value\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction mouseMoved() {\n value = value + 5;\n if (value > 255) {\n value = 0;\n }\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nfunction mouseMoved() {\n ellipse(mouseX, mouseY, 5, 5);\n // prevent default\n return false;\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// returns a MouseEvent object\n// as a callback argument\nfunction mouseMoved(event) {\n console.log(event);\n}\n</code>\n</div>"], 10419 "alt": "black 50x50 rect becomes lighter with mouse movements until white then resets\nno image displayed", 10420 "class": "p5", 10421 "module": "Events", 10422 "submodule": "Mouse" 10423 }, { 10424 "file": "src/events/mouse.js", 10425 "line": 479, 10426 "description": "<p>The <a href=\"#/p5/mouseDragged\">mouseDragged()</a> function is called once every time the mouse moves and\na mouse button is pressed. If no <a href=\"#/p5/mouseDragged\">mouseDragged()</a> function is defined, the\n<a href=\"#/p5/touchMoved\">touchMoved()</a> function will be called instead if it is defined.<br><br>\nBrowsers may have different default\nbehaviors attached to various mouse events. To prevent any default\nbehavior for this event, add "return false" to the end of the method.</p>\n", 10427 "itemtype": "method", 10428 "name": "mouseDragged", 10429 "params": [{ 10430 "name": "event", 10431 "description": "<p>optional MouseEvent callback argument.</p>\n", 10432 "type": "Object", 10433 "optional": true 10434 }], 10435 "example": ["\n<div>\n<code>\n// Drag the mouse across the page\n// to change its value\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction mouseDragged() {\n value = value + 5;\n if (value > 255) {\n value = 0;\n }\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nfunction mouseDragged() {\n ellipse(mouseX, mouseY, 5, 5);\n // prevent default\n return false;\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// returns a MouseEvent object\n// as a callback argument\nfunction mouseDragged(event) {\n console.log(event);\n}\n</code>\n</div>"], 10436 "alt": "black 50x50 rect turns lighter with mouse click and drag until white, resets\nno image displayed", 10437 "class": "p5", 10438 "module": "Events", 10439 "submodule": "Mouse" 10440 }, { 10441 "file": "src/events/mouse.js", 10442 "line": 560, 10443 "description": "<p>The <a href=\"#/p5/mousePressed\">mousePressed()</a> function is called once after every time a mouse button\nis pressed. The mouseButton variable (see the related reference entry)\ncan be used to determine which button has been pressed. If no\n<a href=\"#/p5/mousePressed\">mousePressed()</a> function is defined, the <a href=\"#/p5/touchStarted\">touchStarted()</a> function will be\ncalled instead if it is defined.<br><br>\nBrowsers may have different default\nbehaviors attached to various mouse events. To prevent any default\nbehavior for this event, add "return false" to the end of the method.</p>\n", 10444 "itemtype": "method", 10445 "name": "mousePressed", 10446 "params": [{ 10447 "name": "event", 10448 "description": "<p>optional MouseEvent callback argument.</p>\n", 10449 "type": "Object", 10450 "optional": true 10451 }], 10452 "example": ["\n<div>\n<code>\n// Click within the image to change\n// the value of the rectangle\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction mousePressed() {\n if (value === 0) {\n value = 255;\n } else {\n value = 0;\n }\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nfunction mousePressed() {\n ellipse(mouseX, mouseY, 5, 5);\n // prevent default\n return false;\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// returns a MouseEvent object\n// as a callback argument\nfunction mousePressed(event) {\n console.log(event);\n}\n</code>\n</div>"],
10453 "alt": "black 50x50 rect turns white with mouse click/press.\nno image displayed", 10454 "class": "p5", 10455 "module": "Events", 10456 "submodule": "Mouse" 10457 }, { 10458 "file": "src/events/mouse.js", 10459 "line": 637, 10460 "description": "<p>The <a href=\"#/p5/mouseReleased\">mouseReleased()</a> function is called every time a mouse button is\nreleased. If no <a href=\"#/p5/mouseReleased\">mouseReleased()</a> function is defined, the <a href=\"#/p5/touchEnded\">touchEnded()</a>\nfunction will be called instead if it is defined.<br><br>\nBrowsers may have different default\nbehaviors attached to various mouse events. To prevent any default\nbehavior for this event, add "return false" to the end of the method.</p>\n", 10461 "itemtype": "method", 10462 "name": "mouseReleased", 10463 "params": [{ 10464 "name": "event", 10465 "description": "<p>optional MouseEvent callback argument.</p>\n", 10466 "type": "Object", 10467 "optional": true 10468 }], 10469 "example": ["\n<div>\n<code>\n// Click within the image to change\n// the value of the rectangle\n// after the mouse has been clicked\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction mouseReleased() {\n if (value === 0) {\n value = 255;\n } else {\n value = 0;\n }\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nfunction mouseReleased() {\n ellipse(mouseX, mouseY, 5, 5);\n // prevent default\n return false;\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// returns a MouseEvent object\n// as a callback argument\nfunction mouseReleased(event) {\n console.log(event);\n}\n</code>\n</div>"], 10470 "alt": "black 50x50 rect turns white with mouse click/press.\nno image displayed", 10471 "class": "p5", 10472 "module": "Events", 10473 "submodule": "Mouse" 10474 }, { 10475 "file": "src/events/mouse.js", 10476 "line": 715, 10477 "description": "<p>The <a href=\"#/p5/mouseClicked\">mouseClicked()</a> function is called once after a mouse button has been\npressed and then released.<br><br>\nBrowsers handle clicks differently, so this function is only guaranteed to be\nrun when the left mouse button is clicked. To handle other mouse buttons\nbeing pressed or released, see <a href=\"#/p5/mousePressed\">mousePressed()</a> or <a href=\"#/p5/mouseReleased\">mouseReleased()</a>.<br><br>\nBrowsers may have different default\nbehaviors attached to various mouse events. To prevent any default\nbehavior for this event, add "return false" to the end of the method.</p>\n", 10478 "itemtype": "method", 10479 "name": "mouseClicked", 10480 "params": [{ 10481 "name": "event", 10482 "description": "<p>optional MouseEvent callback argument.</p>\n", 10483 "type": "Object", 10484 "optional": true 10485 }], 10486 "example": ["\n<div>\n<code>\n// Click within the image to change\n// the value of the rectangle\n// after the mouse has been clicked\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\n\nfunction mouseClicked() {\n if (value === 0) {\n value = 255;\n } else {\n value = 0;\n }\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nfunction mouseClicked() {\n ellipse(mouseX, mouseY, 5, 5);\n // prevent default\n return false;\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// returns a MouseEvent object\n// as a callback argument\nfunction mouseClicked(event) {\n console.log(event);\n}\n</code>\n</div>"], 10487 "alt": "black 50x50 rect turns white with mouse click/press.\nno image displayed", 10488 "class": "p5", 10489 "module": "Events", 10490 "submodule": "Mouse" 10491 }, { 10492 "file": "src/events/mouse.js", 10493 "line": 785, 10494 "description": "<p>The <a href=\"#/p5/doubleClicked\">doubleClicked()</a> function is executed every time a event\nlistener has detected a dblclick event which is a part of the\nDOM L3 specification. The doubleClicked event is fired when a\npointing device button (usually a mouse's primary button)\nis clicked twice on a single element. For more info on the\ndblclick event refer to mozilla's documentation here:\n<a href=\"https://developer.mozilla.org/en-US/docs/Web/Events/dblclick\">https://developer.mozilla.org/en-US/docs/Web/Events/dblclick</a></p>\n", 10495 "itemtype": "method", 10496 "name": "doubleClicked", 10497 "params": [{ 10498 "name": "event", 10499 "description": "<p>optional MouseEvent callback argument.</p>\n", 10500 "type": "Object", 10501 "optional": true 10502 }], 10503 "example": ["\n<div>\n<code>\n// Click within the image to change\n// the value of the rectangle\n/
10503/ after the mouse has been double clicked\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\n\nfunction doubleClicked() {\n if (value === 0) {\n value = 255;\n } else {\n value = 0;\n }\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nfunction doubleClicked() {\n ellipse(mouseX, mouseY, 5, 5);\n // prevent default\n return false;\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// returns a MouseEvent object\n// as a callback argument\nfunction doubleClicked(event) {\n console.log(event);\n}\n</code>\n</div>"], 10504 "alt": "black 50x50 rect turns white with mouse doubleClick/press.\nno image displayed", 10505 "class": "p5", 10506 "module": "Events", 10507 "submodule": "Mouse" 10508 }, { 10509 "file": "src/events/mouse.js", 10510 "line": 870, 10511 "description": "<p>The function <a href=\"#/p5/mouseWheel\">mouseWheel()</a> is executed every time a vertical mouse wheel\nevent is detected either triggered by an actual mouse wheel or by a\ntouchpad.<br><br>\nThe event.delta property returns the amount the mouse wheel\nhave scrolled. The values can be positive or negative depending on the\nscroll direction (on OS X with "natural" scrolling enabled, the signs\nare inverted).<br><br>\nBrowsers may have different default behaviors attached to various\nmouse events. To prevent any default behavior for this event, add\n"return false" to the end of the method.<br><br>\nDue to the current support of the "wheel" event on Safari, the function\nmay only work as expected if "return false" is included while using Safari.</p>\n", 10512 "itemtype": "method", 10513 "name": "mouseWheel", 10514 "params": [{ 10515 "name": "event", 10516 "description": "<p>optional WheelEvent callback argument.</p>\n", 10517 "type": "Object", 10518 "optional": true 10519 }], 10520 "example": ["\n<div>\n<code>\nlet pos = 25;\n\nfunction draw() {\n background(237, 34, 93);\n fill(0);\n rect(25, pos, 50, 50);\n}\n\nfunction mouseWheel(event) {\n print(event.delta);\n //move the square according to the vertical scroll amount\n pos += event.delta;\n //uncomment to block page scrolling\n //return false;\n}\n</code>\n</div>"], 10521 "alt": "black 50x50 rect moves up and down with vertical scroll. fuschia background", 10522 "class": "p5", 10523 "module": "Events", 10524 "submodule": "Mouse" 10525 }, { 10526 "file": "src/events/touch.js", 10527 "line": 12, 10528 "description": "<p>The system variable touches[] contains an array of the positions of all\ncurrent touch points, relative to (0, 0) of the canvas, and IDs identifying a\nunique touch as it moves. Each element in the array is an object with x, y,\nand id properties.</p>\n<p>The touches[] array is not supported on Safari and IE on touch-based\ndesktops (laptops).</p>\n", 10529 "itemtype": "property", 10530 "name": "touches", 10531 "type": "Object[]", 10532 "readonly": "", 10533 "example": ["\n<div>\n<code>\n// On a touchscreen device, touch\n// the canvas using one or more fingers\n// at the same time\nfunction draw() {\n clear();\n let display = touches.length + ' touches';\n text(display, 5, 10);\n}\n</code>\n</div>"], 10534 "alt": "Number of touches currently registered are displayed on the canvas", 10535 "class": "p5", 10536 "module": "Events", 10537 "submodule": "Touch" 10538 }, { 10539 "file": "src/events/touch.js", 10540 "line": 74, 10541 "description": "<p>The touchStarted() function is called once after every time a touch is\nregistered. If no <a href=\"#/p5/touchStarted\">touchStarted()</a> function is defined, the <a href=\"#/p5/mousePressed\">mousePressed()</a>\nfunction will be called instead if it is defined.<br><br>\nBrowsers may have different default behaviors attached to various touch\nevents. To prevent any default behavior for this event, add "return false"\nto the end of the method.</p>\n", 10542 "itemtype": "method", 10543 "name": "touchStarted", 10544 "params": [{ 10545 "name": "event", 10546 "description": "<p>optional TouchEvent callback argument.</p>\n", 10547 "type": "Object", 10548 "optional": true 10549 }], 10550 "example": ["\n<div>\n<code>\n// Touch within the image to change\n// the value of the rectangle\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}
10550\nfunction touchStarted() {\n if (value === 0) {\n value = 255;\n } else {\n value = 0;\n }\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nfunction touchStarted() {\n ellipse(mouseX, mouseY, 5, 5);\n // prevent default\n return false;\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// returns a TouchEvent object\n// as a callback argument\nfunction touchStarted(event) {\n console.log(event);\n}\n</code>\n</div>"], 10551 "alt": "50x50 black rect turns white with touch event.\nno image displayed", 10552 "class": "p5", 10553 "module": "Events", 10554 "submodule": "Touch" 10555 }, { 10556 "file": "src/events/touch.js", 10557 "line": 149, 10558 "description": "<p>The <a href=\"#/p5/touchMoved\">touchMoved()</a> function is called every time a touch move is registered.\nIf no <a href=\"#/p5/touchMoved\">touchMoved()</a> function is defined, the <a href=\"#/p5/mouseDragged\">mouseDragged()</a> function will\nbe called instead if it is defined.<br><br>\nBrowsers may have different default behaviors attached to various touch\nevents. To prevent any default behavior for this event, add "return false"\nto the end of the method.</p>\n", 10559 "itemtype": "method", 10560 "name": "touchMoved", 10561 "params": [{ 10562 "name": "event", 10563 "description": "<p>optional TouchEvent callback argument.</p>\n", 10564 "type": "Object", 10565 "optional": true 10566 }], 10567 "example": ["\n<div>\n<code>\n// Move your finger across the page\n// to change its value\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction touchMoved() {\n value = value + 5;\n if (value > 255) {\n value = 0;\n }\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nfunction touchMoved() {\n ellipse(mouseX, mouseY, 5, 5);\n // prevent default\n return false;\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// returns a TouchEvent object\n// as a callback argument\nfunction touchMoved(event) {\n console.log(event);\n}\n</code>\n</div>"], 10568 "alt": "50x50 black rect turns lighter with touch until white. resets\nno image displayed", 10569 "class": "p5", 10570 "module": "Events", 10571 "submodule": "Touch" 10572 }, { 10573 "file": "src/events/touch.js", 10574 "line": 222, 10575 "description": "<p>The <a href=\"#/p5/touchEnded\">touchEnded()</a> function is called every time a touch ends. If no\n<a href=\"#/p5/touchEnded\">touchEnded()</a> function is defined, the <a href=\"#/p5/mouseReleased\">mouseReleased()</a> function will be\ncalled instead if it is defined.<br><br>\nBrowsers may have different default behaviors attached to various touch\nevents. To prevent any default behavior for this event, add "return false"\nto the end of the method.</p>\n", 10576 "itemtype": "method", 10577 "name": "touchEnded", 10578 "params": [{ 10579 "name": "event", 10580 "description": "<p>optional TouchEvent callback argument.</p>\n", 10581 "type": "Object", 10582 "optional": true 10583 }], 10584 "example": ["\n<div>\n<code>\n// Release touch within the image to\n// change the value of the rectangle\n\nlet value = 0;\nfunction draw() {\n fill(value);\n rect(25, 25, 50, 50);\n}\nfunction touchEnded() {\n if (value === 0) {\n value = 255;\n } else {\n value = 0;\n }\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nfunction touchEnded() {\n ellipse(mouseX, mouseY, 5, 5);\n // prevent default\n return false;\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// returns a TouchEvent object\n// as a callback argument\nfunction touchEnded(event) {\n console.log(event);\n}\n</code>\n</div>"], 10585 "alt": "50x50 black rect turns white with touch.\nno image displayed", 10586 "class": "p5", 10587 "module": "Events", 10588 "submodule": "Touch" 10589 }, { 10590 "file": "src/image/filters.js", 10591 "line": 3, 10592 "description": "<p>This module defines the filters for use with image buffers.</p>\n<p>This module is basically a collection of functions stored in an object\nas opposed to modules. The functions are destructive, modifying\nthe passed in canvas rather than creating a copy.</p>\n<p>Generally speaking users of this module will use the Filters.apply method\non a canvas to create an effect.</p>\n<p>A number of functions are borrowed/adapted from\n<a href=\"http://www.html5rocks.com/en/tutorials/canvas/imagefilters/\">http://www.html5rocks.com/en/tutorials/canvas/imagefilters/</a>\nor the java processing implementation.</p>\n", 10593 "class": "p5", 10594 "module": "Events" 10595 }, { 10596 "file": "src/image/image.js", 10597 "line": 8, 10598 "description": "<p>This module defines the p5 methods for the <a href=\"#/p5.Image\">p5.Image</a> class\nfor drawing images to the main display canvas.</p>\n", 10599 "class": "p5", 10600 "module": "Image", 10601 "submodule": "Image" 10602 }, { 10603 "file": "src/image/image.js", 10604 "line": 22, 10605 "description": "<p>Creates a new <a href=\"#/p5.Image\">p5.Image</a> (the datatype for storing images). This provides a\nfresh buffer of pixels to play with. Set the size of the buffer with the\nwidth and height parameters.\n<br><br>\n.<a href=\"#/p5.Image/pixels\">pixels</a> gives access to an array containing the values for all the pixels\nin the display window.\nThese values are numbers. This array is the size (including an appropriate\nfactor for the <a href=\"#/p5/pixelDensity\">pixelDensity</a>) of the display window x4,\nrepresenting the R, G, B, A values in order for each pixel, mov
10605ing from\nleft to right across each row, then down each column. See .<a href=\"#/p5.Image/pixels\">pixels</a> for\nmore info. It may also be simpler to use <a href=\"#/p5.Image/set\">set()</a> or <a href=\"#/p5.Image/get\">get()</a>.\n<br><br>\nBefore accessing the pixels of an image, the data must loaded with the\n<a href=\"#/p5.Image/loadPixels\">loadPixels()</a> function. After the array data has been modified, the\n<a href=\"#/p5.Image/updatePixels\">updatePixels()</a> function must be run to update the changes.</p>\n", 10606 "itemtype": "method", 10607 "name": "createImage", 10608 "params": [{ 10609 "name": "width", 10610 "description": "<p>width in pixels</p>\n", 10611 "type": "Integer" 10612 }, { 10613 "name": "height", 10614 "description": "<p>height in pixels</p>\n", 10615 "type": "Integer" 10616 }], 10617 "return": { 10618 "description": "the <a href=\"#/p5.Image\">p5.Image</a> object", 10619 "type": "p5.Image" 10620 }, 10621 "example": ["\n<div>\n<code>\nlet img = createImage(66, 66);\nimg.loadPixels();\nfor (let i = 0; i < img.width; i++) {\n for (let j = 0; j < img.height; j++) {\n img.set(i, j, color(0, 90, 102));\n }\n}\nimg.updatePixels();\nimage(img, 17, 17);\n</code>\n</div>\n\n<div>\n<code>\nlet img = createImage(66, 66);\nimg.loadPixels();\nfor (let i = 0; i < img.width; i++) {\n for (let j = 0; j < img.height; j++) {\n img.set(i, j, color(0, 90, 102, (i % img.width) * 2));\n }\n}\nimg.updatePixels();\nimage(img, 17, 17);\nimage(img, 34, 34);\n</code>\n</div>\n\n<div>\n<code>\nlet pink = color(255, 102, 204);\nlet img = createImage(66, 66);\nimg.loadPixels();\nlet d = pixelDensity();\nlet halfImage = 4 * (img.width * d) * (img.height / 2 * d);\nfor (let i = 0; i < halfImage; i += 4) {\n img.pixels[i] = red(pink);\n img.pixels[i + 1] = green(pink);\n img.pixels[i + 2] = blue(pink);\n img.pixels[i + 3] = alpha(pink);\n}\nimg.updatePixels();\nimage(img, 17, 17);\n</code>\n</div>"], 10622 "alt": "66x66 dark turquoise rect in center of canvas.\n2 gradated dark turquoise rects fade left. 1 center 1 bottom right of canvas\nno image displayed", 10623 "class": "p5", 10624 "module": "Image", 10625 "submodule": "Image" 10626 }, { 10627 "file": "src/image/image.js", 10628 "line": 102, 10629 "description": "<p>Save the current canvas as an image. The browser will either save the\nfile immediately, or prompt the user with a dialogue window.</p>\n", 10630 "itemtype": "method", 10631 "name": "saveCanvas", 10632 "example": ["\n <div class='norender notest'><code>\n function setup() {\n let c = createCanvas(100, 100);\n background(255, 0, 0);\n saveCanvas(c, 'myCanvas', 'jpg');\n }\n </code></div>\n <div class='norender notest'><code>\n // note that this example has the same result as above\n // if no canvas is specified, defaults to main canvas\n function setup() {\n let c = createCanvas(100, 100);\n background(255, 0, 0);\n saveCanvas('myCanvas', 'jpg');\n\n // all of the following are valid\n saveCanvas(c, 'myCanvas', 'jpg');\n saveCanvas(c, 'myCanvas.jpg');\n saveCanvas(c, 'myCanvas');\n saveCanvas(c);\n saveCanvas('myCanvas', 'png');\n saveCanvas('myCanvas');\n saveCanvas();\n }\n </code></div>"], 10633 "alt": "no image displayed\n no image displayed\n no image displayed", 10634 "class": "p5", 10635 "module": "Image", 10636 "submodule": "Image", 10637 "overloads": [{ 10638 "line": 102, 10639 "params": [{ 10640 "name": "selectedCanvas", 10641 "description": "<p>a variable\n representing a specific html5 canvas (optional)</p>\n", 10642 "type": "p5.Element|HTMLCanvasElement" 10643 }, { 10644 "name": "filename", 10645 "description": "", 10646 "type": "String", 10647 "optional": true 10648 }, { 10649 "name": "extension", 10650 "description": "<p>'jpg' or 'png'</p>\n", 10651 "type": "String", 10652 "optional": true 10653 }] 10654 }, { 10655 "line": 144, 10656 "params": [{ 10657 "name": "filename", 10658 "description": "", 10659 "type": "String", 10660 "optional": true 10661 }, { 10662 "name": "extension", 10663 "description": "", 10664 "type": "String", 10665 "optional": true 10666 }] 10667 }] 10668 }, { 10669 "file": "src/image/image.js", 10670 "line": 195, 10671 "description": "<p>Capture a sequence of frames that can be used to create a movie.\nAccepts a callback. For example, you may wish to
10671send the frames\nto a server where they can be stored or converted into a movie.\nIf no callback is provided, the browser will pop up save dialogues in an\nattempt to download all of the images that have just been created. With the\ncallback provided the image data isn't saved by default but instead passed\nas an argument to the callback function as an array of objects, with the\nsize of array equal to the total number of frames.</p>\n<p>Note that <a href=\"#/p5.Image/saveFrames\">saveFrames()</a> will only save the first 15 frames of an animation.\nTo export longer animations, you might look into a library like\n<a href=\"https://github.com/spite/ccapture.js/\">ccapture.js</a>.</p>\n", 10672 "itemtype": "method", 10673 "name": "saveFrames", 10674 "params": [{ 10675 "name": "filename", 10676 "description": "", 10677 "type": "String" 10678 }, { 10679 "name": "extension", 10680 "description": "<p>'jpg' or 'png'</p>\n", 10681 "type": "String" 10682 }, { 10683 "name": "duration", 10684 "description": "<p>Duration in seconds to save the frames for.</p>\n", 10685 "type": "Number" 10686 }, { 10687 "name": "framerate", 10688 "description": "<p>Framerate to save the frames in.</p>\n", 10689 "type": "Number" 10690 }, { 10691 "name": "callback", 10692 "description": "<p>A callback function that will be executed\n to handle the image data. This function\n should accept an array as argument. The\n array will contain the specified number of\n frames of objects. Each object has three\n properties: imageData - an\n image/octet-stream, filename and extension.</p>\n", 10693 "type": "Function(Array)", 10694 "optional": true 10695 }], 10696 "example": ["\n<div><code>\n function draw() {\n background(mouseX);\n }\n\n function mousePressed() {\n saveFrames('out', 'png', 1, 25, data => {\n print(data);\n });\n }\n</code></div>"], 10697 "alt": "canvas background goes from light to dark with mouse x.", 10698 "class": "p5", 10699 "module": "Image", 10700 "submodule": "Image" 10701 }, { 10702 "file": "src/image/loading_displaying.js", 10703 "line": 17, 10704 "description": "<p>Loads an image from a path and creates a <a href=\"#/p5.Image\">p5.Image</a> from it.\n<br><br>\nThe image may not be immediately available for rendering\nIf you want to ensure that the image is ready before doing\nanything with it, place the <a href=\"#/p5/loadImage\">loadImage()</a> call in <a href=\"#/p5/preload\">preload()</a>.\nYou may also supply a callback function to handle the image when it's ready.\n<br><br>\nThe path to the image should be relative to the HTML file\nthat links in your sketch. Loading an image from a URL or other\nremote location may be blocked due to your browser's built-in\nsecurity.</p>\n", 10705 "itemtype": "method", 10706 "name": "loadImage", 10707 "params": [{ 10708 "name": "path", 10709 "description": "<p>Path of the image to be loaded</p>\n", 10710 "type": "String" 10711 }, { 10712 "name": "successCallback", 10713 "description": "<p>Function to be called once\n the image is loaded. Will be passed the\n <a href=\"#/p5.Image\">p5.Image</a>.</p>\n", 10714 "type": "function(p5.Image)", 10715 "optional": true 10716 }, { 10717 "name": "failureCallback", 10718 "description": "<p>called with event error if\n the image fails to load.</p>\n", 10719 "type": "Function(Event)", 10720 "optional": true 10721 }], 10722 "return": { 10723 "description": "the <a href=\"#/p5.Image\">p5.Image</a> object", 10724 "type": "p5.Image" 10725 }, 10726 "example": ["\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/laDefense.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n}\n</code>\n</div>\n<div>\n<code>\nfunction setup() {\n // here we use a callback to display the image after loading\n loadImage('assets/laDefense.jpg', img => {\n image(img, 0, 0);\n });\n}\n</code>\n</div>"], 10727 "alt": "image of the underside of a white umbrella and grided ceililng above\nimage of the underside of a white umbrella and grided ceililng above", 10728 "class": "p5", 10729 "module": "Image", 10730 "submodule": "Loading & Displaying" 10731 }, { 10732 "file": "src/image/loading_displaying.js", 10733 "line": 127, 10734 "description": "<p>Draw an image to the p5.js canvas.</p>\n<p>This function can be used with different numbers of parameters. The\nsimplest use requires only three parameters: img, x, and
10734yâwhere (x, y) is\nthe position of the image. Two more parameters can optionally be added to\nspecify the width and height of the image.</p>\n<p>This function can also be used with all eight Number parameters. To\ndifferentiate between all these parameters, p5.js uses the language of\n"destination rectangle" (which corresponds to "dx", "dy", etc.) and "source\nimage" (which corresponds to "sx", "sy", etc.) below. Specifying the\n"source image" dimensions can be useful when you want to display a\nsubsection of the source image instead of the whole thing. Here's a diagram\nto explain further:\n<img src=\"assets/drawImage.png\"></img></p>\n", 10735 "itemtype": "method", 10736 "name": "image", 10737 "example": ["\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/laDefense.jpg');\n}\nfunction setup() {\n // Top-left corner of the img is at (0, 0)\n // Width and height are the img's original width and height\n image(img, 0, 0);\n}\n</code>\n</div>\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/laDefense.jpg');\n}\nfunction setup() {\n background(50);\n // Top-left corner of the img is at (10, 10)\n // Width and height are 50 x 50\n image(img, 10, 10, 50, 50);\n}\n</code>\n</div>\n<div>\n<code>\nfunction setup() {\n // Here, we use a callback to display the image after loading\n loadImage('assets/laDefense.jpg', img => {\n image(img, 0, 0);\n });\n}\n</code>\n</div>\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/gradient.png');\n}\nfunction setup() {\n // 1. Background image\n // Top-left corner of the img is at (0, 0)\n // Width and height are the img's original width and height, 100 x 100\n image(img, 0, 0);\n // 2. Top right image\n // Top-left corner of destination rectangle is at (50, 0)\n // Destination rectangle width and height are 40 x 20\n // The next parameters are relative to the source image:\n // - Starting at position (50, 50) on the source image, capture a 50 x 50\n // subsection\n // - Draw this subsection to fill the dimensions of the destination rectangle\n image(img, 50, 0, 40, 20, 50, 50, 50, 50);\n}\n</code>\n</div>"], 10738 "alt": "image of the underside of a white umbrella and gridded ceiling above\nimage of the underside of a white umbrella and gridded ceiling above", 10739 "class": "p5", 10740 "module": "Image", 10741 "submodule": "Loading & Displaying", 10742 "overloads": [{ 10743 "line": 127, 10744 "params": [{ 10745 "name": "img", 10746 "description": "<p>the image to display</p>\n", 10747 "type": "p5.Image|p5.Element" 10748 }, { 10749 "name": "x", 10750 "description": "<p>the x-coordinate of the top-left corner of the image</p>\n", 10751 "type": "Number" 10752 }, { 10753 "name": "y", 10754 "description": "<p>the y-coordinate of the top-left corner of the image</p>\n", 10755 "type": "Number" 10756 }, { 10757 "name": "width", 10758 "description": "<p>the width to draw the image</p>\n", 10759 "type": "Number", 10760 "optional": true 10761 }, { 10762 "name": "height", 10763 "description": "<p>the height to draw the image</p>\n", 10764 "type": "Number", 10765 "optional": true 10766 }] 10767 }, { 10768 "line": 215, 10769 "params": [{ 10770 "name": "img", 10771 "description": "", 10772 "type": "p5.Image|p5.Element" 10773 }, { 10774 "name": "dx", 10775 "description": "<p>the x-coordinate of the destination\n rectangle in which to draw the source image</p>\n", 10776 "type": "Number" 10777 }, { 10778 "name": "dy", 10779 "description": "<p>the y-coordinate of the destination\n rectangle in which to draw the source image</p>\n", 10780 "type": "Number" 10781 }, { 10782 "name": "dWidth", 10783 "description": "<p>the width of the destination rectangle</p>\n", 10784 "type": "Number" 10785 }, { 10786 "name": "dHeight", 10787 "description": "<p>the height of the destination rectangle</p>\n", 10788 "type": "Number" 10789 }, { 10790 "name": "sx", 10791 "description": "<p>the x-coordinate of the subsection of the source\nimage to draw into the destination rectangle</p>\n", 10792 "type": "Number" 10793 }, { 10794 "name": "sy", 10795 "description": "<p>the y-coordinate of the subsection of the source\nimage to draw into the destination rectangle</p>\n", 10796 "type": "Number" 10797 }, { 10798 "name": "sWidth", 10799 "description": "<p>the width of the subsection of the\n source image to draw into the destination\n rectangle</p>\n", 10800 "type": "Number", 10801 "optional": true 10802 }, { 10803 "name": "sHeight", 10804 "description": "<p>the height of the subsection of the\n source image to draw into the destination rectangle</p>\n", 10805 "type": "Number", 10806 "optional": true 10807 }] 10808 }] 10809 }, { 10810 "file": "src/image/loading_displaying.js", 10811 "line": 298, 10812 "description": "<p>Sets the fill value for displaying images. Images can be tinted to\nspecified colors or made transparent by including an alpha value.\n<br><br>\nTo apply transparency to an image without affecting its color, use\nwhite as the tint color and specify an alpha value. For instance,\ntint(255, 128) will make an image 50% transparent (assuming the default\nalpha range of 0-255, which can be changed with <a href=\"#/p5/colorMode\">colorMode()</a>).\n<br><br>\nThe value for the gray parameter must be less than or equal to the current\nmaximum value as specified by <a href=\"#/p5/colorMode\">colorMode()</a>. The default maximum value is\n255.</p>\n", 10813 "itemtype": "method", 10814 "name": "tint", 10815 "example": ["\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/laDefense.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n tint(0, 153, 204); // Tint blue\n image(img, 50, 0);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/laDefense.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n tint(0, 153, 204, 126); // Tint blue and set transparency\n image(img, 50, 0);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/laDefense.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n tint(255, 126); // Apply transparency without changing color\n image(img, 50, 0);\n}\n</code>\n</div>"], 10816 "alt": "2 side by side images of umbrella and ceiling, one image with blue tint\nImages of umbrella and ceiling, one half of image with blue tint\n2 side by side images of umbrella and ceiling, one image translucent", 10817 "class": "p5", 10818 "module": "Image", 10819 "submodule": "Loading & Displaying", 10820 "overloads": [{ 10821 "line": 298, 10822 "params": [{ 10823 "name": "v1", 10824 "description": "<p>red or hue value relative to\n the current color range</p>\n", 10825 "type": "Number" 10826 }, { 10827 "name": "v2", 10828 "description": "<p>
10828green or saturation value\n relative to the current color range</p>\n", 10829 "type": "Number" 10830 }, { 10831 "name": "v3", 10832 "description": "<p>blue or brightness value\n relative to the current color range</p>\n", 10833 "type": "Number" 10834 }, { 10835 "name": "alpha", 10836 "description": "", 10837 "type": "Number", 10838 "optional": true 10839 }] 10840 }, { 10841 "line": 371, 10842 "params": [{ 10843 "name": "value", 10844 "description": "<p>a color string</p>\n", 10845 "type": "String" 10846 }] 10847 }, { 10848 "line": 376, 10849 "params": [{ 10850 "name": "gray", 10851 "description": "<p>a gray value</p>\n", 10852 "type": "Number" 10853 }, { 10854 "name": "alpha", 10855 "description": "", 10856 "type": "Number", 10857 "optional": true 10858 }] 10859 }, { 10860 "line": 382, 10861 "params": [{ 10862 "name": "values", 10863 "description": "<p>an array containing the red,green,blue &\n and alpha components of the color</p>\n", 10864 "type": "Number[]" 10865 }] 10866 }, { 10867 "line": 388, 10868 "params": [{ 10869 "name": "color", 10870 "description": "<p>the tint color</p>\n", 10871 "type": "p5.Color" 10872 }] 10873 }] 10874 }, { 10875 "file": "src/image/loading_displaying.js", 10876 "line": 398, 10877 "description": "<p>Removes the current fill value for displaying images and reverts to\ndisplaying images with their original hues.</p>\n", 10878 "itemtype": "method", 10879 "name": "noTint", 10880 "example": ["\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n tint(0, 153, 204); // Tint blue\n image(img, 0, 0);\n noTint(); // Disable tint\n image(img, 50, 0);\n}\n</code>\n</div>"], 10881 "alt": "2 side by side images of bricks, left image with blue tint", 10882 "class": "p5", 10883 "module": "Image", 10884 "submodule": "Loading & Displaying" 10885 }, { 10886 "file": "src/image/loading_displaying.js", 10887 "line": 464, 10888 "description": "<p>Set image mode. Modifies the location from which images are drawn by\nchanging the way in which parameters given to <a href=\"#/p5/image\">image()</a> are interpreted.\nThe default mode is imageMode(CORNER), which interprets the second and\nthird parameters of <a href=\"#/p5/image\">image()</a> as the upper-left corner of the image. If\ntwo additional parameters are specified, they are used to set the image's\nwidth and height.\n<br><br>\nimageMode(CORNERS) interprets the second and third parameters of <a href=\"#/p5/image\">image()</a>\nas the location of one corner, and the fourth and fifth parameters as the\nopposite corner.\n<br><br>\nimageMode(CENTER) interprets the second and third parameters of <a href=\"#/p5/image\">image()</a>\nas the image's center point. If two additional parameters are specified,\nthey are used to set the image's width and height.</p>\n", 10889 "itemtype": "method", 10890 "name": "imageMode", 10891 "params": [{ 10892 "name": "mode", 10893 "description": "<p>either CORNER, CORNERS, or CENTER</p>\n", 10894 "type": "Constant" 10895 }], 10896 "example": ["\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n imageMode(CORNER);\n image(img, 10, 10, 50, 50);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n imageMode(CORNERS);\n image(img, 10, 10, 90, 40);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n imageMode(CENTER);\n image(img, 50, 50, 80, 80);\n}\n</code>\n</div>"], 10897 "alt": "small square image of bricks\nhorizontal rectangle image of bricks\nlarge square image of bricks", 10898 "class": "p5", 10899 "module": "Image", 10900 "submodule": "Loading & Displaying" 10901 }, { 10902 "file": "src/image/p5.Image.js", 10903 "line": 9, 10904 "description": "<p>This module defines the <a href=\"#/p5.Image\">p5.Image</a> class and P5 methods for\ndrawing images to the main display canvas.</p>\n", 10905 "class": "p5.Image", 10906 "module": "Image", 10907 "submodule": "Image" 10908 }, { 10909 "file": "src/image/p5.Image.js", 10910 "line": 90, 10911 "description": "<p>Image width.</p>\n", 10912 "itemtype": "property", 10913 "name": "width", 10914 "type": "Number", 10915 "readonly": "", 10916 "example": ["\n<div><code>\nlet img;\nfunction preload() {\n img = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n createCanvas(100, 100);\n image(img, 0, 0);\n for (let i = 0; i < img.width;
10916 i++) {\n let c = img.get(i, img.height / 2);\n stroke(c);\n line(i, height / 2, i, height);\n }\n}\n</code></div>"], 10917 "alt": "rocky mountains in top and horizontal lines in corresponding colors in bottom.", 10918 "class": "p5.Image", 10919 "module": "Image", 10920 "submodule": "Image" 10921 }, { 10922 "file": "src/image/p5.Image.js", 10923 "line": 117, 10924 "description": "<p>Image height.</p>\n", 10925 "itemtype": "property", 10926 "name": "height", 10927 "type": "Number", 10928 "readonly": "", 10929 "example": ["\n<div><code>\nlet img;\nfunction preload() {\n img = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n createCanvas(100, 100);\n image(img, 0, 0);\n for (let i = 0; i < img.height; i++) {\n let c = img.get(img.width / 2, i);\n stroke(c);\n line(0, i, width / 2, i);\n }\n}\n</code></div>"], 10930 "alt": "rocky mountains on right and vertical lines in corresponding colors on left.", 10931 "class": "p5.Image", 10932 "module": "Image", 10933 "submodule": "Image" 10934 }, { 10935 "file": "src/image/p5.Image.js", 10936 "line": 152, 10937 "description": "<p>Array containing the values for all the pixels in the display window.\nThese values are numbers. This array is the size (include an appropriate\nfactor for pixelDensity) of the display window x4,\nrepresenting the R, G, B, A values in order for each pixel, moving from\nleft to right across each row, then down each column. Retina and other\nhigh denisty displays may have more pixels (by a factor of\npixelDensity^2).\nFor example, if the image is 100x100 pixels, there will be 40,000. With\npixelDensity = 2, there will be 160,000. The first four values\n(indices 0-3) in the array will be the R, G, B, A values of the pixel at\n(0, 0). The second four values (indices 4-7) will contain the R, G, B, A\nvalues of the pixel at (1, 0). More generally, to set values for a pixel\nat (x, y):</p>\n<pre><code class=\"lang-javascript\">let d = pixelDensity();\nfor (let i = 0; i < d; i++) {\n for (let j = 0; j < d; j++) {\n // loop over\n index = 4 * ((y * d + j) * width * d + (x * d + i
10937));\n pixels[index] = r;\n pixels[index+1] = g;\n pixels[index+2] = b;\n pixels[index+3] = a;\n }\n}\n</code></pre>\n<p><br><br>\nBefore accessing this array, the data must loaded with the <a href=\"#/p5.Image/loadPixels\">loadPixels()</a>\nfunction. After the array data has been modified, the <a href=\"#/p5.Image/updatePixels\">updatePixels()</a>\nfunction must be run to update the changes.</p>\n", 10938 "itemtype": "property", 10939 "name": "pixels", 10940 "type": "Number[]", 10941 "example": ["\n<div>\n<code>\nlet img = createImage(66, 66);\nimg.loadPixels();\nfor (let i = 0; i < img.width; i++) {\n for (let j = 0; j < img.height; j++) {\n img.set(i, j, color(0, 90, 102));\n }\n}\nimg.updatePixels();\nimage(img, 17, 17);\n</code>\n</div>\n<div>\n<code>\nlet pink = color(255, 102, 204);\nlet img = createImage(66, 66);\nimg.loadPixels();\nfor (let i = 0; i < 4 * (width * height / 2); i += 4) {\n img.pixels[i] = red(pink);\n img.pixels[i + 1] = green(pink);\n img.pixels[i + 2] = blue(pink);\n img.pixels[i + 3] = alpha(pink);\n}\nimg.updatePixels();\nimage(img, 17, 17);\n</code>\n</div>"], 10942 "alt": "66x66 turquoise rect in center of canvas\n66x66 pink rect in center of canvas", 10943 "class": "p5.Image", 10944 "module": "Image", 10945 "submodule": "Image" 10946 }, { 10947 "file": "src/image/p5.Image.js", 10948 "line": 222, 10949 "description": "<p>Helper fxn for sharing pixel methods</p>\n", 10950 "class": "p5.Image", 10951 "module": "Image", 10952 "submodule": "Image" 10953 }, { 10954 "file": "src/image/p5.Image.js", 10955 "line": 231, 10956 "description": "<p>Loads the pixels data for this image into the [pixels] attribute.</p>\n", 10957 "itemtype": "method", 10958 "name": "loadPixels", 10959 "example": ["\n<div><code>\nlet myImage;\nlet halfImage;\n\nfunction preload() {\n myImage = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n myImage.loadPixels();\n halfImage = 4 * width * height / 2;\n for (let i = 0; i < halfImage; i++) {\n myImage.pixels[i + halfImage] = myImage.pixels[i];\n }\n myImage.updatePixels();\n}\n\nfunction draw() {\n image(myImage, 0, 0);\n}\n</code></div>"], 10960 "alt": "2 images of rocky mountains vertically stacked", 10961 "class": "p5.Image", 10962 "module": "Image", 10963 "submodule": "Image" 10964 }, { 10965 "file": "src/image/p5.Image.js", 10966 "line": 267, 10967 "description": "<p>Updates the backing canvas for this image with the contents of\nthe [pixels] array.</p>\n", 10968 "itemtype": "method", 10969 "name": "updatePixels", 10970 "example": ["\n<div><code>\nlet myImage;\nlet halfImage;\n\nfunction preload() {\n myImage = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n myImage.loadPixels();\n halfImage = 4 * width * height / 2;\n for (let i = 0; i < halfImage; i++) {\n myImage.pixels[i + halfImage] = myImage.pixels[i];\n }\n myImage.updatePixels();\n}\n\nfunction draw() {\n image(myImage, 0, 0);\n}\n</code></div>"], 10971 "alt": "2 images of rocky mountains vertically stacked", 10972 "class": "p5.Image", 10973 "module": "Image", 10974 "submodule": "Image", 10975 "overloads": [{ 10976 "line": 267, 10977 "params": [{ 10978 "name": "x", 10979 "description": "<p>x-offset of the target update area for the\n underlying canvas</p>\n", 10980 "type": "Integer" 10981 }, { 10982 "name": "y", 10983 "description": "<p>y-offset of the target update area for the\n underlying canvas</p>\n", 10984 "type": "Integer" 10985 }, { 10986 "name": "w", 10987 "description": "<p>height of the target update area for the\n underlying canvas</p>\n", 10988 "type": "Integer" 10989 }, { 10990 "name": "h", 10991 "description": "<p>height of the target update area for the\n underlying canvas</p>\n", 10992 "type": "Integer" 10993 }] 10994 }, { 10995 "line": 307, 10996 "params": [] 10997 }] 10998 }, { 10999 "file": "src/image/p5.Image.js", 11000 "line": 315, 11001 "description": "<p>Get a region of pixels from an image.</p>\n<p>If no params are passed, those whole image is returned,\nif x and y are the only params passed a single pixel is extracted\nif all params are passed a rectangle region is extracted and a <a href=\"#/p5.Image\">p5.Image</a>\nis returned.</p>\n<p>Returns undefined if the region is outside the bounds of the image</p>\n", 11002 "itemtype": "method", 11003 "name": "get", 11004 "params": [{ 11005 "name": "x", 11006 "description": "<p>x-coordinate of the pixel</p>\n", 11007 "type": "Number", 11008 "optional": true 11009 }, { 11010 "name": "y", 11011 "description": "<p>y-coordinate of the pixel</p>\n", 11012 "type": "Number", 11013 "optional": true 11014 }, { 11015 "name": "w", 11016 "description": "<p>width</p>\n", 11017 "type": "Number", 11018 "optional": true 11019 }, { 11020 "name": "h", 11021 "description": "<p>height</p>\n", 11022 "type": "Number", 11023 "optional": true 11024 }], 11025 "return": { 11026 "description": "color of pixel at x,y in array format\n [R, G, B, A] or <a href=\"#/p5.Image\">p5.Image</a>", 11027 "type": "Number[]|Color|p5.Image" 11028 }, 11029 "example": ["\n<div><code>\nlet myImage;\nlet c;\n\nfunction preload() {\n myImage = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n background(myImage);\n noStroke();\n c = myImage.get(60, 90);\n fill(c);\n rect(25, 25, 50, 50);\n}\n\n//get() returns color here\n</code></div>"], 11030 "alt": "image of rocky mountains with 50x50 green rect in front", 11031 "class": "p5.Image", 11032 "module": "Image", 11033 "submodule": "Image" 11034 }, { 11035 "file": "src/image/p5.Image.js", 11036 "line": 360, 11037 "description": "<p>Set the color of a single pixel or write an image into\nthis <a href=\"#/p5.Image\">p5.Image</a>.</p>\n<p>Note that for a large number of pixels this will\nbe slower than directly manipulating the pixels array\nand then calling <a href=\"#/p5.Image/updatePixels\">updatePixels()</a>.</p>\n", 11038 "itemtype": "method", 11039 "name": "set", 11040 "params": [{ 11041 "name": "x", 11042 "description": "<p>x-coordinate of the pixel</p>\n", 11043 "type": "Number" 11044 }, { 11045 "name": "y", 11046 "description": "<p>y-coordinate of the pixel</p>\n", 11047 "type": "Number" 11048 }, { 11049 "name": "a", 11050 "description": "<p>grayscale value | pixel array |\n a <a href=\"#/p5.Color\">p5.Color</a> | image to copy</p>\n", 11051 "type": "Number|Number[]|Object" 11052 }], 11053 "example": ["\n<div>\n<code>\nlet img = createImage(66, 66);\nimg.loadPixels();\nfor (let i = 0; i < img.width;
11053 i++) {\n for (let j = 0; j < img.height; j++) {\n img.set(i, j, color(0, 90, 102, (i % img.width) * 2));\n }\n}\nimg.updatePixels();\nimage(img, 17, 17);\nimage(img, 34, 34);\n</code>\n</div>"], 11054 "alt": "2 gradated dark turquoise rects fade left. 1 center 1 bottom right of canvas", 11055 "class": "p5.Image", 11056 "module": "Image", 11057 "submodule": "Image" 11058 }, { 11059 "file": "src/image/p5.Image.js", 11060 "line": 398, 11061 "description": "<p>Resize the image to a new width and height. To make the image scale\nproportionally, use 0 as the value for the wide or high parameter.\nFor instance, to make the width of an image 150 pixels, and change\nthe height using the same proportion, use resize(150, 0).</p>\n", 11062 "itemtype": "method", 11063 "name": "resize", 11064 "params": [{ 11065 "name": "width", 11066 "description": "<p>the resized image width</p>\n", 11067 "type": "Number" 11068 }, { 11069 "name": "height", 11070 "description": "<p>the resized image height</p>\n", 11071 "type": "Number" 11072 }], 11073 "example": ["\n<div><code>\nlet img;\n\nfunction preload() {\n img = loadImage('assets/rockies.jpg');\n}\n\nfunction draw() {\n image(img, 0, 0);\n}\n\nfunction mousePressed() {\n img.resize(50, 100);\n}\n</code></div>"], 11074 "alt": "image of rocky mountains. zoomed in", 11075 "class": "p5.Image", 11076 "module": "Image", 11077 "submodule": "Image" 11078 }, { 11079 "file": "src/image/p5.Image.js", 11080 "line": 483, 11081 "description": "<p>Copies a region of pixels from one image to another. If no\nsrcImage is specified this is used as the source. If the source\nand destination regions aren't the same size, it will\nautomatically resize source pixels to fit the specified\ntarget region.</p>\n", 11082 "itemtype": "method", 11083 "name": "copy", 11084 "example": ["\n<div><code>\nlet photo;\nlet bricks;\nlet x;\nlet y;\n\nfunction preload() {\n photo = loadImage('assets/rockies.jpg');\n bricks = loadImage('assets/bricks.jpg');\n}\n\nfunction setup() {\n x = bricks.width / 2;\n y = bricks.height / 2;\n photo.copy(bricks, 0, 0, x, y, 0, 0, x, y);\n image(photo, 0, 0);\n}\n</code></div>"], 11085 "alt": "image of rocky mountains and smaller image on top of bricks at top left", 11086 "class": "p5.Image", 11087 "module": "Image", 11088 "submodule": "Image", 11089 "overloads": [{ 11090 "line": 483, 11091 "params": [{ 11092 "name": "srcImage", 11093 "description": "<p>source image</p>\n", 11094 "type": "p5.Image|p5.Element" 11095 }, { 11096 "name": "sx", 11097 "description": "<p>X coordinate of the source's upper left corner</p>\n", 11098 "type": "Integer" 11099 }, { 11100 "name": "sy", 11101 "description": "<p>Y coordinate of the source's upper left corner</p>\n", 11102 "type": "Integer" 11103 }, { 11104 "name": "sw", 11105 "description": "<p>source image width</p>\n", 11106 "type": "Integer" 11107 }, { 11108 "name": "sh", 11109 "description": "<p>source image height</p>\n", 11110 "type": "Integer" 11111 }, { 11112 "name": "dx", 11113 "description": "<p>X coordinate of the destination's upper left corner</p>\n", 11114 "type": "Integer" 11115 }, { 11116 "name": "dy", 11117 "description": "<p>Y coordinate of the destination's upper left corner</p>\n", 11118 "type": "Integer" 11119 }, { 11120 "name": "dw", 11121 "description": "<p>destination image width</p>\n", 11122 "type": "Integer" 11123 }, { 11124 "name": "dh", 11125 "description": "<p>destination image height</p>\n", 11126 "type": "Integer" 11127 }] 11128 }, { 11129 "line": 524, 11130 "params": [{ 11131 "name": "sx", 11132 "description": "", 11133 "type": "Integer" 11134 }, { 11135 "name": "sy", 11136 "description": "", 11137 "type": "Integer" 11138 }, { 11139 "name": "sw", 11140 "description": "", 11141 "type": "Integer" 11142 }, { 11143 "name": "sh", 11144 "description": "", 11145 "type": "Integer" 11146 }, { 11147 "name": "dx", 11148 "description": "", 11149 "type": "Integer" 11150 }, { 11151 "name": "dy", 11152 "description": "", 11153 "type": "Integer" 11154 }, { 11155 "name": "dw", 11156 "description": "", 11157 "type": "Integer" 11158 }, { 11159 "name": "dh", 11160 "description": "", 11161 "type": "Integer" 11162 }] 11163 }] 11164 }, { 11165 "file": "src/image/p5.Image.js", 11166 "line": 564, 11167 "description": "<p>Masks part of an image from displaying by loading another\nimage and using it's alpha channel as an alpha channel for\nthis image.</p>\n", 11168 "itemtype": "method", 11169 "name": "mask", 11170 "params": [{ 11171 "name": "srcImage", 11172 "description": "<p>source image</p>\n", 11173 "type": "p5.Image" 11174 }], 11175 "example": ["\n<div><code>\nlet photo, maskImage;\nfunction preload() {\n photo = loadImage('assets/rockies.jpg');\n maskImage = loadImage('assets/mask2.png');\n}\n\nfunction setup() {\n createCanvas(100, 100);\n photo.mask(maskImage);\n image(photo, 0, 0);\n}\n</code></div>"], 11176 "alt": "image of rocky mountains with white at right\n\n\nhttp://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/", 11177 "class": "p5.Image", 11178 "module": "Image", 11179 "submodule": "Image" 11180 }, { 11181 "file": "src/image/p5.Image.js", 11182 "line": 627, 11183 "description": "<p>Applies an image filter to a <a href=\"#/p5.Image\">p5.Image</a></p>\n", 11184 "itemtype": "method", 11185 "name": "filter", 11186 "params": [{ 11187 "name": "filterType", 11188 "description": "<p>either THRESHOLD, GRAY, OPAQUE, INVERT,\n POSTERIZE, BLUR, ERODE, DILATE or BLUR.\
11188n See Filters.js for docs on\n each available filter</p>\n", 11189 "type": "Constant" 11190 }, { 11191 "name": "filterParam", 11192 "description": "<p>an optional parameter unique\n to each filter, see above</p>\n", 11193 "type": "Number", 11194 "optional": true 11195 }], 11196 "example": ["\n<div><code>\nlet photo1;\nlet photo2;\n\nfunction preload() {\n photo1 = loadImage('assets/rockies.jpg');\n photo2 = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n photo2.filter('gray');\n image(photo1, 0, 0);\n image(photo2, width / 2, 0);\n}\n</code></div>"], 11197 "alt": "2 images of rocky mountains left one in color, right in black and white", 11198 "class": "p5.Image", 11199 "module": "Image", 11200 "submodule": "Image" 11201 }, { 11202 "file": "src/image/p5.Image.js", 11203 "line": 663, 11204 "description": "<p>Copies a region of pixels from one image to another, using a specified\nblend mode to do the operation.</p>\n", 11205 "itemtype": "method", 11206 "name": "blend", 11207 "example": ["\n<div><code>\nlet mountains;\nlet bricks;\n\nfunction preload() {\n mountains = loadImage('assets/rockies.jpg');\n bricks = loadImage('assets/bricks_third.jpg');\n}\n\nfunction setup() {\n mountains.blend(bricks, 0, 0, 33, 100, 67, 0, 33, 100, ADD);\n image(mountains, 0, 0);\n image(bricks, 0, 0);\n}\n</code></div>\n<div><code>\nlet mountains;\nlet bricks;\n\nfunction preload() {\n mountains = loadImage('assets/rockies.jpg');\n bricks = loadImage('assets/bricks_third.jpg');\n}\n\nfunction setup() {\n mountains.blend(bricks, 0, 0, 33, 100, 67, 0, 33, 100, DARKEST);\n image(mountains, 0, 0);\n image(bricks, 0, 0);\n}\n</code></div>\n<div><code>\nlet mountains;\nlet bricks;\n\nfunction preload() {\n mountains = loadImage('assets/rockies.jpg');\n bricks = loadImage('assets/bricks_third.jpg');\n}\n\nfunction setup() {\n mountains.blend(bricks, 0, 0, 33, 100, 67, 0, 33, 100, LIGHTEST);\n image(mountains, 0, 0);\n image(bricks, 0, 0);\n}\n</code></div>"], 11208 "alt": "image of rocky mountains. Brick images on left and right. Right overexposed\nimage of rockies. Brickwall images on left and right. Right mortar transparent\nimage of rockies. Brickwall images on left and right. Right translucent", 11209 "class": "p5.Image", 11210 "module": "Image", 11211 "submodule": "Image", 11212 "overloads": [{ 11213 "line": 663, 11214 "params": [{ 11215 "name": "srcImage", 11216 "description": "<p>source image</p>\n", 11217 "type": "p5.Image" 11218 }, { 11219 "name": "sx", 11220 "description": "<p>X coordinate of the source's upper left corner</p>\n", 11221 "type": "Integer" 11222 }, { 11223 "name": "sy", 11224 "description": "<p>Y coordinate of the source's upper left corner</p>\n", 11225 "type": "Integer" 11226 }, { 11227 "name": "sw", 11228 "description": "<p>source image width</p>\n", 11229 "type": "Integer" 11230 }, { 11231 "name": "sh", 11232 "description": "<p>source image height</p>\n", 11233 "type": "Integer" 11234 }, { 11235 "name": "dx", 11236 "description": "<p>X coordinate of the destination's upper left corner</p>\n", 11237 "type": "Integer" 11238 }, { 11239 "name": "dy", 11240 "description": "<p>Y coordinate of the destination's upper left corner</p>\n", 11241 "type": "Integer" 11242 }, { 11243 "name": "dw", 11244 "description": "<p>destination image width</p>\n", 11245 "type": "Integer" 11246 }, { 11247 "name": "dh", 11248 "description": "<p>destination image height</p>\n", 11249 "type": "Integer" 11250 }, { 11251 "name": "blendMode", 11252 "description": "<p>the blend mode. either\n BLEND, DARKEST, LIGHTEST, DIFFERENCE,\n MULTIPLY, EXCLUSION, SCREEN, REPLACE, OVERLAY, HARD_LIGHT,\n SOFT_LIGHT, DODGE, BURN, ADD or NORMAL.</p>\n<p>Available blend modes are: normal | multiply | screen | overlay |\n darken | lighten | color-dodge | color-burn | hard-light |\n soft-light | difference | exclusion | hue | saturation |\n color | luminosity</p>\n<p><a href=\"http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/\">http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/</a></p>\n", 11253 "type": "Constant" 11254 }] 11255 }, { 11256 "line": 742, 11257 "params": [{ 11258 "name": "sx", 11259 "description": "", 11260 "type": "Integer" 11261 }, { 11262 "name": "sy", 11263 "description": "", 11264 "type": "Integer" 11265 }, { 11266 "name": "sw", 11267 "description": "", 11268 "type": "Integer" 11269 }, { 11270 "name": "sh", 11271 "description": "", 11272 "type": "Integer" 11273 }, { 11274 "name": "dx", 11275 "description": "", 11276 "type": "Integer" 11277 }, { 11278 "name": "dy", 11279 "description": "", 11280 "type": "Integer" 11281 }, { 11282 "name": "dw", 11283 "description": "", 11284 "type": "Integer" 11285 }, { 11286 "name": "dh", 11287 "description": "", 11288 "type": "Integer" 11289 }, { 11290 "name": "blendMode", 11291 "description": "", 11292 "type": "Constant" 11293 }] 11294 }] 11295 }, { 11296 "file": "src/image/p5.Image.js", 11297 "line": 785, 11298 "description": "<p>Saves the image to a file and force the browser to download it.\nAccepts two strings for filename and file extension\nSupports png (default) and jpg.</p>\n", 11299 "itemtype": "method", 11300 "name": "save", 11301 "params": [{ 11302 "name": "filename", 11303 "description": "<p>give your file a name</p>\n", 11304 "type": "String" 11305 }, { 11306 "name": "extension", 11307 "description": "<p>'png' or 'jpg'</p>\n", 11308 "type": "String" 11309 }], 11310 "example": ["\n<div><code>\nlet photo;\n\nfunction preload() {\n photo = loadImage('assets/rockies.jpg');\n}\n\nfunction draw() {\n image(photo, 0, 0);\n}\n\nfunction keyTyped() {\n if (key === 's') {\n photo.save('photo', 'png');\n }\n}\n</code></div>"], 11311 "alt": "image of rocky mountains.", 11312 "class": "p5.Image", 11313 "module": "Image", 11314 "submodule": "Image" 11315 }, { 11316 "file": "src/image/pixels.js", 11317 "line": 14, 11318 "description": "<p><a href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference\n/Global_Objects/Uint8ClampedArray' target='_blank'>Uint8ClampedArray</a>\ncontaining the values for all the pixels in the display window.\nThese values are numbers. This array is the size (include an appropriate\nfactor for <a href=\"#/p5/pixelDensity\">pixelDensity</a>) of the display window x4,\nrepresenting the R, G, B, A values in order for each pixel, mov
11318ing from\nleft to right across each row, then down each column. Retina and other\nhigh density displays will have more pixels[] (by a factor of\npixelDensity^2).\nFor example, if the image is 100x100 pixels, there will be 40,000. On a\nretina display, there will be 160,000.\n<br><br>\nThe first four values (indices 0-3) in the array will be the R, G, B, A\nvalues of the pixel at (0, 0). The second four values (indices 4-7) will\ncontain the R, G, B, A values of the pixel at (1, 0). More generally, to\nset values for a pixel at (x, y):</p>\n<pre><code class=\"lang-javascript\">let d = pixelDensity();\nfor (let i = 0; i < d; i++) {\n for (let j = 0; j < d; j++) {\n // loop over\n index = 4 * ((y * d + j) * width * d + (x * d + i));\n pixels[index] = r;\n pixels[index+1] = g;\n pixels[index+2] = b;\n pixels[index+3] = a;\n }\n}\n</code></pre>\n<p>While the above method is complex, it is flexible enough to work with\nany pixelDensity. Note that <a href=\"#/p5/set\">set()</a> will automatically take care of\nsetting all the appropriate values in <a href=\"#/p5/pixels\">pixels[]</a> for a given (x, y) at\nany pixelDensity, but the performance may not be as fast when lots of\nmodifications are made to the pixel array.\n<br><br>\nBefore accessing this array, the data must loaded with the <a href=\"#/p5/loadPixels\">loadPixels()</a>\nfunction. After the array data has been modified, the <a href=\"#/p5/updatePixels\">updatePixels()</a>\nfunction must be run to update the changes.\n<br><br>\nNote that this is not a standard javascript array. This means that\nstandard javascript functions such as <a href=\"#/p5/slice\">slice()</a> or\n<a href=\"#/p5/arrayCopy\">arrayCopy()</a> do not\nwork.</p>", 11319 "itemtype": "property", 11320 "name": "pixels", 11321 "type": "Number[]", 11322 "example": ["\n<div>\n<code>\nlet pink = color(255, 102, 204);\nloadPixels();\nlet d = pixelDensity();\nlet halfImage = 4 * (width * d) * (height / 2 * d);\nfor (let i = 0; i < halfImage; i += 4) {\n pixels[i] = red(pink);\n pixels[i + 1] = green(pink);\n pixels[i + 2] = blue(pink);\n pixels[i + 3] = alpha(pink);\n}\nupdatePixels();\n</code>\n</div>"], 11323 "alt": "top half of canvas pink, bottom grey", 11324 "class": "p5", 11325 "module": "Image", 11326 "submodule": "Pixels" 11327 }, { 11328 "file": "src/image/pixels.js", 11329 "line": 83, 11330 "description": "<p>Copies a region of pixels from one image to another, using a specified\nblend mode to do the operation.</p>\n", 11331 "itemtype": "method", 11332 "name": "blend", 11333 "example": ["\n<div><code>\nlet img0;\nlet img1;\n\nfunction preload() {\n img0 = loadImage('assets/rockies.jpg');\n img1 = loadImage('assets/bricks_third.jpg');\n}\n\nfunction setup() {\n background(img0);\n image(img1, 0, 0);\n blend(img1, 0, 0, 33, 100, 67, 0, 33, 100, LIGHTEST);\n}\n</code></div>\n<div><code>\nlet img0;\nlet img1;\n\nfunction preload() {\n img0 = loadImage('assets/rockies.jpg');\n img1 = loadImage('assets/bricks_third.jpg');\n}\n\nfunction setup() {\n background(img0);\n image(img1, 0, 0);\n blend(img1, 0, 0, 33, 100, 67, 0, 33, 100, DARKEST);\n}\n</code></div>\n<div><code>\nlet img0;\nlet img1;\n\nfunction preload() {\n img0 = loadImage('assets/rockies.jpg');\n img1 = loadImage('assets/bricks_third.jpg');\n}\n\nfunction setup() {\n background(img0);\n image(img1, 0, 0);\n blend(img1, 0, 0, 33, 100, 67, 0, 33, 100, ADD);\n}\n</code></div>"], 11334 "alt": "image of rocky mountains. Brick images on left and right. Right overexposed\nimage of rockies. Brickwall images on left and right. Right mortar transparent\nimage of rockies. Brickwall images on left and right. Right translucent", 11335 "class": "p5", 11336 "module": "Image", 11337 "submodule": "Pixels", 11338 "overloads": [{ 11339 "line": 83, 11340 "params": [{ 11341 "name": "srcImage", 11342 "description": "<p>source image</p>\n", 11343 "type": "p5.Image" 11344 }, { 11345 "name": "sx", 11346 "description": "<p>X coordinate of the source's upper left corner</p>\n", 11347 "type": "Integer" 11348 }, { 11349 "name": "sy", 11350 "description": "<p>Y coordinate of the source's upper left corner</p>\n", 11351 "type": "Integer" 11352 }, { 11353 "name": "sw", 11354 "description": "<p>source image width</p>\n", 11355 "type": "Integer" 11356 }, { 11357 "name": "sh", 11358 "description": "<p>source image height</p>\n", 11359 "type": "Integer" 11360 }, { 11361 "name": "dx", 11362 "description": "<p>X coordinate of the destination's upper left corner</p>\n", 11363 "type": "Integer" 11364 }, { 11365 "name": "dy", 11366 "description": "<p>Y coordinate of the destination's upper left corner</p>\n", 11367 "type": "Integer" 11368 }, { 11369 "name": "dw", 11370 "description": "<p>destination image width</p>\n", 11371 "type": "Integer" 11372 }, { 11373 "name": "dh", 11374 "description": "<p>destination image height</p>\n", 11375 "type": "Integer" 11376 }, { 11377 "name": "blendMode", 11378 "description": "<p>the blend mode. either\n BLEND, DARKEST, LIGHTEST, DIFFERENCE,\n MULTIPLY, EXCLUSION, SCREEN, REPLACE, OVERLAY, HARD_LIGHT,\n SOFT_LIGHT, DODGE, BURN, ADD or NORMAL.</p>\n", 11379 "type": "Constant" 11380 }] 11381 }, { 11382 "line": 156, 11383 "params": [{ 11384 "name": "sx", 11385 "description": "", 11386 "type": "Integer" 11387 }, { 11388 "name": "sy", 11389 "description": "", 11390 "type": "Integer" 11391 }, { 11392 "name": "sw", 11393 "description": "", 11394 "type": "Integer" 11395 }, { 11396 "name": "sh", 11397 "description": "", 11398 "type": "Integer" 11399 }, { 11400 "name": "dx", 11401 "description": "", 11402 "type": "Integer" 11403 }, { 11404 "name": "dy", 11405 "description": "", 11406 "type": "Integer" 11407 }, { 11408 "name": "dw", 11409 "description": "", 11410 "type": "Integer" 11411 }, { 11412 "name": "dh", 11413 "description": "", 11414 "type": "Integer" 11415 }, { 11416 "name": "blendMode", 11417 "description": "", 11418 "type": "Constant" 11419 }] 11420 }] 11421 }, { 11422 "file": "src/image/pixels.js", 11423 "line": 177, 11424 "description": "<p>Copies a region of the canvas to another region of the canvas\nand copies a region of pixels from an image used as the srcImg parameter\ninto the canvas srcImage is specified this is used as the source. If\nthe source and destination regions aren't the same size, it will\nautomatically resize source pixels to fit the specified\ntarget region.</p>\n", 11425 "itemtype": "method", 11426 "name": "copy", 11427 "example": ["\n<div><code>\nlet img;\n\nfunction preload() {\n img = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n background(img);\n copy(img, 7, 22, 10, 10, 35, 25, 50, 50);
11427\n stroke(255);\n noFill();\n // Rectangle shows area being copied\n rect(7, 22, 10, 10);\n}\n</code></div>"], 11428 "alt": "image of rocky mountains. Brick images on left and right. Right overexposed\nimage of rockies. Brickwall images on left and right. Right mortar transparent\nimage of rockies. Brickwall images on left and right. Right translucent", 11429 "class": "p5", 11430 "module": "Image", 11431 "submodule": "Pixels", 11432 "overloads": [{ 11433 "line": 177, 11434 "params": [{ 11435 "name": "srcImage", 11436 "description": "<p>source image</p>\n", 11437 "type": "p5.Image|p5.Element" 11438 }, { 11439 "name": "sx", 11440 "description": "<p>X coordinate of the source's upper left corner</p>\n", 11441 "type": "Integer" 11442 }, { 11443 "name": "sy", 11444 "description": "<p>Y coordinate of the source's upper left corner</p>\n", 11445 "type": "Integer" 11446 }, { 11447 "name": "sw", 11448 "description": "<p>source image width</p>\n", 11449 "type": "Integer" 11450 }, { 11451 "name": "sh", 11452 "description": "<p>source image height</p>\n", 11453 "type": "Integer" 11454 }, { 11455 "name": "dx", 11456 "description": "<p>X coordinate of the destination's upper left corner</p>\n", 11457 "type": "Integer" 11458 }, { 11459 "name": "dy", 11460 "description": "<p>Y coordinate of the destination's upper left corner</p>\n", 11461 "type": "Integer" 11462 }, { 11463 "name": "dw", 11464 "description": "<p>destination image width</p>\n", 11465 "type": "Integer" 11466 }, { 11467 "name": "dh", 11468 "description": "<p>destination image height</p>\n", 11469 "type": "Integer" 11470 }] 11471 }, { 11472 "line": 220, 11473 "params": [{ 11474 "name": "sx", 11475 "description": "", 11476 "type": "Integer" 11477 }, { 11478 "name": "sy", 11479 "description": "", 11480 "type": "Integer" 11481 }, { 11482 "name": "sw", 11483 "description": "", 11484 "type": "Integer" 11485 }, { 11486 "name": "sh", 11487 "description": "", 11488 "type": "Integer" 11489 }, { 11490 "name": "dx", 11491 "description": "", 11492 "type": "Integer" 11493 }, { 11494 "name": "dy", 11495 "description": "", 11496 "type": "Integer" 11497 }, { 11498 "name": "dw", 11499 "description": "", 11500 "type": "Integer" 11501 }, { 11502 "name": "dh", 11503 "description": "", 11504 "type": "Integer" 11505 }] 11506 }] 11507 }, { 11508 "file": "src/image/pixels.js", 11509 "line": 236, 11510 "description": "<p>Applies a filter to the canvas.\n<br><br></p>\n<p>The presets options are:\n<br><br></p>\n<p>THRESHOLD\nConverts the image to black and white pixels depending if they are above or\nbelow the threshold defined by the level parameter. The parameter must be\nbetween 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is used.\n<br><br></p>\n<p>GRAY\nConverts any colors in the image to grayscale equivalents. No parameter\nis used.\n<br><br></p>\n<p>OPAQUE\nSets the alpha channel to entirely opaque. No parameter is used.\n<br><br></p>\n<p>INVERT\nSets each pixel to its inverse value. No parameter is used.\n<br><br></p>\n<p>POSTERIZE\nLimits each channel of the image to the number of colors specified as the\nparameter. The parameter can be set to values between 2 and 255, but\nresults are most noticeable in the lower ranges.\n<br><br></p>\n<p>BLUR\nExecutes a Gaussian blur with the level parameter specifying the extent\nof the blurring. If no parameter is used, the blur is equivalent to\nGaussian blur of radius 1. Larger values increase the blur.\n<br><br></p>\n<p>ERODE\nReduces the light areas. No parameter is used.\n<br><br></p>\n<p>DILATE\nIncreases the light areas. No parameter is used.</p>\n", 11511 "itemtype": "method", 11512 "name": "filter", 11513 "params": [{ 11514 "name": "filterType", 11515 "description": "<p>either THRESHOLD, GRAY, OPAQUE, INVERT,\n POSTERIZE, BLUR, ERODE, DILATE or BLUR.\
11515n See Filters.js for docs on\n each available filter</p>\n", 11516 "type": "Constant" 11517 }, { 11518 "name": "filterParam", 11519 "description": "<p>an optional parameter unique\n to each filter, see above</p>\n", 11520 "type": "Number", 11521 "optional": true 11522 }], 11523 "example": ["\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n filter(THRESHOLD);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n filter(GRAY);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n filter(OPAQUE);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n filter(INVERT);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n filter(POSTERIZE, 3);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n filter(DILATE);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n image(img, 0, 0);
11523\n filter(BLUR, 3);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/bricks.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n filter(ERODE);\n}\n</code>\n</div>"], 11524 "alt": "black and white image of a brick wall.\ngreyscale image of a brickwall\nimage of a brickwall\njade colored image of a brickwall\nred and pink image of a brickwall\nimage of a brickwall\nblurry image of a brickwall\nimage of a brickwall\nimage of a brickwall with less detail", 11525 "class": "p5", 11526 "module": "Image", 11527 "submodule": "Pixels" 11528 }, { 11529 "file": "src/image/pixels.js", 11530 "line": 415, 11531 "description": "<p>Returns an array of [R,G,B,A] values for any pixel or grabs a section of\nan image. If no parameters are specified, the entire image is returned.\nUse the x and y parameters to get the value of one pixel. Get a section of\nthe display window by specifying additional w and h parameters. When\ngetting an image, the x and y parameters define the coordinates for the\nupper-left corner of the image, regardless of the current <a href=\"#/p5/imageMode\">imageMode()</a>.\n<br><br>\nIf the pixel requested is outside of the image window, [0,0,0,255] is\nreturned. To get the numbers scaled according to the current color ranges\nand taking into account <a href=\"#/p5/colorMode\">colorMode</a>, use <a href=\"#/p5/getColor\">getColor</a> instead of get.\n<br><br>\nGetting the color of a single pixel with get(x, y) is easy, but not as fast\nas grabbing the data directly from <a href=\"#/p5/pixels\">pixels[]</a>. The equivalent statement to\nget(x, y) using <a href=\"#/p5/pixels\">pixels[]</a> with pixel density d is</p>\n<pre><code class=\"lang-javascript\">let x, y, d; // set these to the coordinates\nlet off = (y * width + x) * d * 4;\nlet components = [\n pixels[off],\n pixels[off + 1],\n pixels[off + 2],\n pixels[off + 3]\n];\nprint(components);\n</code></pre>\n<p><br><br>\nSee the reference for <a href=\"#/p5/pixels\">pixels[]</a> for more information.</p>\n<p>If you want to extract an array of colors or a subimage from an p5.Image object,\ntake a look at <a href=\"#/p5.Image/get\">p5.Image.get()</a></p>\n", 11532 "itemtype": "method", 11533 "name": "get", 11534 "params": [{ 11535 "name": "x", 11536 "description": "<p>x-coordinate of the pixel</p>\n", 11537 "type": "Number", 11538 "optional": true 11539 }, { 11540 "name": "y", 11541 "description": "<p>y-coordinate of the pixel</p>\n", 11542 "type": "Number", 11543 "optional": true 11544 }, { 11545 "name": "w", 11546 "description": "<p>width</p>\n", 11547 "type": "Number", 11548 "optional": true 11549 }, { 11550 "name": "h", 11551 "description": "<p>height</p>\n", 11552 "type": "Number", 11553 "optional": true 11554 }], 11555 "return": { 11556 "description": "values of pixel at x,y in array format\n [R, G, B, A] or <a href=\"#/p5.Image\">p5.Image</a>", 11557 "type": "Number[]|p5.Image" 11558 }, 11559 "example": ["\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/rockies.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n let c = get();\n image(c, width / 2, 0);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/rockies.jpg');\n}\nfunction setup() {\n image(img, 0, 0);\n let c = get(50, 90);\n fill(c);\n noStroke();\n rect(25, 25, 50, 50);\n}\n</code>\n</div>"], 11560 "alt": "2 images of the rocky mountains, side-by-side\nImage of the rocky mountains with 50x50 green rect in center of canvas", 11561 "class": "p5", 11562 "module": "Image", 11563 "submodule": "Pixels" 11564 }, { 11565 "file": "src/image/pixels.js", 11566 "line": 520, 11567 "description": "<p>Loads the pixel data for the display window into the <a href=\"#/p5/pixels\">pixels[]</a> array. This\nfunction must always be called before reading from or writing to <a href=\"#/p5/pixels\">pixels[]</a>.\nNote that only changes made with <a href=\"#/p5/set\">set()</a> or direct manipulation of <a href=\"#/p5/pixels\">pixels[]</a>\nwill occur.</p>\n", 11568 "itemtype": "method", 11569 "name": "loadPixels", 11570 "example": ["\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n image(img, 0, 0);\n let d = pixelDensity();\n let halfImage = 4 * (img.width * d) * (img.height * d / 2);\n loadPixels();\n for (let i = 0; i < halfImage;
11570 i++) {\n pixels[i + halfImage] = pixels[i];\n }\n updatePixels();\n}\n</code>\n</div>"], 11571 "alt": "two images of the rocky mountains. one on top, one on bottom of canvas.", 11572 "class": "p5", 11573 "module": "Image", 11574 "submodule": "Pixels" 11575 }, { 11576 "file": "src/image/pixels.js", 11577 "line": 557, 11578 "description": "<p>Changes the color of any pixel, or writes an image directly to the\ndisplay window.</p>\n<p>The x and y parameters specify the pixel to change and the c parameter\nspecifies the color value. This can be a <a href=\"#/p5.Color\">p5.Color</a> object, or [R, G, B, A]\npixel array. It can also be a single grayscale value.\nWhen setting an image, the x and y parameters define the coordinates for\nthe upper-left corner of the image, regardless of the current <a href=\"#/p5/imageMode\">imageMode()</a>.\n</p>\n<p>\nAfter using <a href=\"#/p5/set\">set()</a>, you must call <a href=\"#/p5/updatePixels\">updatePixels()</a> for your changes to appear.\nThis should be called once all pixels have been set, and must be called before\ncalling .<a href=\"#/p5/get\">get()</a> or drawing the image.\n</p>\n<p>Setting the color of a single pixel with set(x, y) is easy, but not as\nfast as putting the data directly into <a href=\"#/p5/pixels\">pixels[]</a>. Setting the <a href=\"#/p5/pixels\">pixels[]</a>\nvalues directly may be complicated when working with a retina display,\nbut will perform better when lots of pixels need to be set directly on\nevery loop.</p>\n<p>See the reference for <a href=\"#/p5/pixels\">pixels[]</a> for more information.</p>", 11579 "itemtype": "method", 11580 "name": "set", 11581 "params": [{ 11582 "name": "x", 11583 "description": "<p>x-coordinate of the pixel</p>\n", 11584 "type": "Number" 11585 }, { 11586 "name": "y", 11587 "description": "<p>y-coordinate of the pixel</p>\n", 11588 "type": "Number" 11589 }, { 11590 "name": "c", 11591 "description": "<p>insert a grayscale value | a pixel array |\n a <a href=\"#/p5.Color\">p5.Color</a> object | a <a href=\"#/p5.Image\">p5.Image</a> to copy</p>\n", 11592 "type": "Number|Number[]|Object" 11593 }], 11594 "example": ["\n<div>\n<code>\nlet black = color(0);\nset(30, 20, black);\nset(85, 20, black);\nset(85, 75, black);\nset(30, 75, black);\nupdatePixels();\n</code>\n</div>\n\n<div>\n<code>\nfor (let i = 30; i < width - 15; i++) {\n for (let j = 20; j < height - 25; j++) {\n let c = color(204 - j, 153 - i, 0);\n set(i, j, c);\n }\n}\nupdatePixels();\n</code>\n</div>\n\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n set(0, 0, img);\n updatePixels();\n line(0, 0, width, height);\n line(0, height, width, 0);\n}\n</code>\n</div>"], 11595 "alt": "4 black points in the shape of a square middle-right of canvas.\nsquare with orangey-brown gradient lightening at bottom right.\nimage of the rocky mountains. with lines like an 'x' through the center.", 11596 "class": "p5", 11597 "module": "Image", 11598 "submodule": "Pixels" 11599 }, { 11600 "file": "src/image/pixels.js", 11601 "line": 631, 11602 "description": "<p>Updates the display window with the data in the <a href=\"#/p5/pixels\">pixels[]</a> array.\nUse in conjunction with <a href=\"#/p5/loadPixels\">loadPixels()</a>. If you're only reading pixels from\nthe array, there's no need to call <a href=\"#/p5/updatePixels\">updatePixels()</a> â updating is only\nnecessary to apply changes. <a href=\"#/p5/updatePixels\">updatePixels()</a> should be called anytime the\npixels array is manipulated or <a href=\"#/p5/set\">set()</a> is called, and only changes made with\n<a href=\"#/p5/set\">set()</a> or direct changes to <a href=\"#/p5/pixels\">pixels[]</a> will occur.</p>\n", 11603 "itemtype": "method", 11604 "name": "updatePixels", 11605 "params": [{ 11606 "name": "x", 11607 "description": "<p>x-coordinate of the upper-left corner of region\n to update</p>\n", 11608 "type": "Number", 11609 "optional": true 11610 }, { 11611 "name": "y", 11612 "description": "<p>y-coordinate of the upper-left corner of region\n to update</p>\n", 11613 "type": "Number", 11614 "optional": true 11615 }, { 11616 "name": "w", 11617 "description": "<p>width of region to update</p>\n", 11618 "type": "Number", 11619 "optional": true 11620 }, { 11621 "name": "h", 11622 "description": "<p>height of region to update</p>\n", 11623 "type": "Number", 11624 "optional": true 11625 }], 11626 "example": ["\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/rockies.jpg');\n}\n\nfunction setup() {\n image(img, 0, 0);\n let d = pixelDensity();\n let halfImage = 4 * (img.width * d) * (img.height * d / 2);\n loadPixels();\n for (let i = 0; i < halfImage;
11626 i++) {\n pixels[i + halfImage] = pixels[i];\n }\n updatePixels();\n}\n</code>\n</div>"], 11627 "alt": "two images of the rocky mountains. one on top, one on bottom of canvas.", 11628 "class": "p5", 11629 "module": "Image", 11630 "submodule": "Pixels" 11631 }, { 11632 "file": "src/io/files.js", 11633 "line": 19, 11634 "description": "<p>Loads a JSON file from a file or a URL, and returns an Object.\nNote that even if the JSON file contains an Array, an Object will be\nreturned with index numbers as keys.</p>\n<p>This method is asynchronous, meaning it may not finish before the next\nline in your sketch is executed. JSONP is supported via a polyfill and you\ncan pass in as the second argument an object with definitions of the json\ncallback following the syntax specified <a href=\"https://github.com/camsong/\nfetch-jsonp\">here</a>.</p>\n<p>This method is suitable for fetching files up to size of 64MB.</p>\n", 11635 "itemtype": "method", 11636 "name": "loadJSON", 11637 "return": { 11638 "description": "JSON data", 11639 "type": "Object|Array" 11640 }, 11641 "example": ["\n\n<p>Calling <a href=\"#/p5/loadJSON\">loadJSON()</a> inside <a href=\"#/p5/preload\">preload()</a> guarantees to complete the\noperation before <a href=\"#/p5/setup\">setup()</a> and <a href=\"#/p5/draw\">draw()</a> are called.</p>\n\n<div><code>\n// Examples use USGS Earthquake API:\n// https://earthquake.usgs.gov/fdsnws/event/1/#methods\nlet earthquakes;\nfunction preload() {\n // Get the most recent earthquake in the database\n let url =\n 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/' +\n 'summary/all_day.geojson';\n earthquakes = loadJSON(url);\n}\n\nfunction setup() {\n noLoop();\n}\n\nfunction draw() {\n background(200);\n // Get the magnitude and name of the earthquake out of the loaded JSON\n let earthquakeMag = earthquakes.features[0].properties.mag;\n let earthquakeName = earthquakes.features[0].properties.place;\n ellipse(width / 2, height / 2, earthquakeMag * 10, earthquakeMag * 10);\n textAlign(CENTER);\n text(earthquakeName, 0, height - 30, width, 30);\n}\n</code></div>\n\n\n<p>Outside of preload(), you may supply a callback function to handle the\nobject:</p>\n<div><code>\nfunction setup() {\n noLoop();\n let url =\n 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/' +\n 'summary/all_day.geojson';\n loadJSON(url, drawEarthquake);\n}\n\nfunction draw() {\n background(200);\n}\n\nfunction drawEarthquake(earthquakes) {\n // Get the magnitude and name of the earthquake out of the loaded JSON\n let earthquakeMag = earthquakes.features[0].properties.mag;\n let earthquakeName = earthquakes.features[0].properties.place;\n ellipse(width / 2, height / 2, earthquakeMag * 10, earthquakeMag * 10);\n textAlign(CENTER);\n text(earthquakeName, 0, height - 30, width, 30);\n}\n</code></div>"], 11642 "alt": "50x50 ellipse that changes from black to white depending on the current humidity\n50x50 ellipse that changes from black to white depending on the current humidity", 11643 "class": "p5", 11644 "module": "IO", 11645 "submodule": "Input", 11646 "overloads": [{ 11647 "line": 19, 11648 "params": [{ 11649 "name": "path", 11650 "description": "<p>name of the file or url to load</p>\n", 11651 "type": "String" 11652 }, { 11653 "name": "jsonpOptions", 11654 "description": "<p>options object for jsonp related settings</p>\n", 11655 "type": "Object", 11656 "optional": true 11657 }, { 11658 "name": "datatype", 11659 "description": "<p>"json" or "jsonp"</p>\n", 11660 "type": "String", 11661 "optional": true 11662 }, { 11663 "name": "callback", 11664 "description": "<p>function to be executed after\n <a href=\"#/p5/loadJSON\">loadJSON()</a> completes, data is passed\n in as first argument</p>\n", 11665 "type": "Function", 11666 "optional": true 11667 }, { 11668 "name": "errorCallback", 11669 "description": "<p>function to be executed if\n there is an error, response is passed\n in as first argument</p>\n", 11670 "type": "Function", 11671 "optional": true 11672 }], 11673 "return": { 11674 "description": "JSON data", 11675 "type": "Object|Array" 11676 } 11677 }, { 11678 "line": 105, 11679 "params": [{ 11680 "name": "path", 11681 "description": "", 11682 "type": "String" 11683 }, { 11684 "name": "datatype", 11685 "description": "", 11686 "type": "String" 11687 }, { 11688 "name": "callback", 11689 "description": "", 11690 "type": "Function", 11691 "optional": true 11692 }, { 11693 "name": "errorCallback", 11694 "description": "", 11695 "type": "Function", 11696 "optional": true 11697 }], 11698 "return": { 11699 "description": "", 11700 "type": "Object|Array" 11701 } 11702 }, { 11703 "line": 113, 11704 "params": [{ 11705 "name": "path", 11706 "description": "", 11707 "type": "String" 11708 }, { 11709 "name": "callback", 11710 "description": "", 11711 "type": "Function" 11712 }, { 11713 "name": "errorCallback", 11714 "description": "", 11715 "type": "Function", 11716 "optional": true 11717 }], 11718 "return": { 11719 "description": "", 11720 "type": "Object|Array" 11721 } 11722 }] 11723 }, { 11724 "file": "src/io/files.js", 11725 "line": 180, 11726 "description": "<p>Reads the contents of a file and creates a String array of its individual\nlines. If the name of the file is used as the parameter, as in the above\nexample, the file must be located in the sketch directory/folder.\n<br><br>\nAlternatively, the file maybe be loaded from anywhere on the local\ncomputer using an absolute path (something that starts with / on Unix and\nLinux, or a drive letter on Windows), or the filename parameter can be a\nURL for a file found on a network.\n<br><br>\nThis method is asynchronous, meaning it may not finish before the next\nline in your sketch is executed.</p>\n<p>This method is suitable for fetching files up to size of 64MB.</p>\n", 11727 "itemtype": "method", 11728 "name": "loadStrings", 11729 "params": [{ 11730 "name": "filename", 11731 "description": "<p>name of the file or url to load</p>\n", 11732 "type": "String" 11733 }, { 11734 "name": "callback", 11735 "description": "<p>function to be executed after <a href=\"#/p5/loadStrings\">loadStrings()</a>\n completes, Array is passed in as first\n argument</p>\n", 11736 "type": "Function", 11737 "optional": true 11738 }, { 11739 "name": "errorCallback", 11740 "description": "<p>function to be executed if\n there is an error, response is passed\n in as first argument</p>\n", 11741 "type": "Function", 11742 "optional": true 11743 }], 11744 "return": { 11745 "description": "Array of Strings", 11746 "type": "String[]" 11747 }, 11748 "example": ["\n\n<p>Calling loadStrings() inside <a href=\"#/p5/preload\">preload()</a> guarantees to complete the\noperation before <a href=\"#/p5/setup\">setup()</a> and <a href=\"#/p5/draw\">draw()</a> are called.</p>\n\n<div><code>\nlet result;\nfunction preload() {\n result = loadStrings('assets/test.txt');\n}\n\nfunction setup() {\n background(200);\n let ind = floor(random(result.length));\n text(result[ind], 10, 10, 80, 80);\n}\n</code></div>\n\n<p>Outside of preload(), you may supply a callback function to handle the\nobject:</p>\n\n<div><code>\nfunction setup() {\n loadStrings('assets/test.txt', pickString);\n}\n\nfunction pickString(result) {\n background(200);\n let ind = floor(random(result.length));\n text(result[ind], 10, 10, 80, 80);\n}\n</code></div>"], 11749 "alt": "randomly generated text from a file, for example \"i smell like butter\"\nrandomly generated text from a file, for example \"i have three feet\"", 11750 "class": "p5", 11751 "module": "IO", 11752 "submodule": "Input" 11753 }, { 11754 "file": "src/io/files.js", 11755 "line": 293, 11756 "description": "<p>Reads the contents of a file or URL and creates a <a href=\"#/p5.Table\">p5.Table</a> object with\nits values. If a file is specified, it must be located in the sketch's\n"data" folder. The filename parameter can also be a URL to a file found\nonline. By default, the file is assumed to be comma-separated (in CSV\nformat). Table only looks for a header row if the 'header' option is\nincluded.</p>\n\n<p>Possible options include:\n<ul>\n<li>csv - parse the table as comma-separated values</li>\n<li>tsv - parse the table as tab-separated values</li>\n<li>header - this table has a header (title) row</li>\n</ul>\n</p>\n\n<p>When passing in multiple options, pass them in as separate parameters,\nseperated by commas. For example:\n<br><br>\n<code>\nloadTable('my_csv_file.csv', 'csv', 'header');\n</code>\n</p>\n\n<p> All files loaded and saved use UTF-8 encoding.</p>\n\n<p>This method is asynchronous, meaning it may not finish before the next\nline in your sketch is executed. Calling <a href=\"#/p5/loadTable\">loadTable()</a> inside <a href=\"#/p5/preload\">preload()</a>\nguarantees to complete the operation before <a href=\"#/p5/setup\">setup()</a> and <a href=\"#/p5/draw\">draw()</a> are called.\n<p>Outside of <a href=\"#/p5/preload\">preload()</a>, you may supply a callback function to handle the\nobject:</p>\n</p>\n\n<p>This method is suitable for fetching files up to size of 64MB.</p>\n", 11757 "itemtype": "method", 11758 "name": "loadTable", 11759 "return": { 11760 "description": "<a href=\"#/p5.Table\">Table</a>
11760 object containing data", 11761 "type": "Object" 11762 }, 11763 "example": ["\n<div class='norender'>\n<code>\n// Given the following CSV file called \"mammals.csv\"\n// located in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n //the file can be remote\n //table = loadTable(\"http://p5js.org/reference/assets/mammals.csv\",\n // \"csv\", \"header\");\n}\n\nfunction setup() {\n //count the columns\n print(table.getRowCount() + ' total rows in table');\n print(table.getColumnCount() + ' total columns in table');\n\n print(table.getColumn('name'));\n //[\"Goat\", \"Leopard\", \"Zebra\"]\n\n //cycle through the table\n for (let r = 0; r < table.getRowCount(); r++)\n for (let c = 0; c < table.getColumnCount(); c++) {\n print(table.getString(r, c));\n }\n}\n</code>\n</div>"], 11764 "alt": "randomly generated text from a file, for example \"i smell like butter\"\nrandomly generated text from a file, for example \"i have three feet\"", 11765 "class": "p5", 11766 "module": "IO", 11767 "submodule": "Input", 11768 "overloads": [{ 11769 "line": 293, 11770 "params": [{ 11771 "name": "filename", 11772 "description": "<p>name of the file or URL to load</p>\n", 11773 "type": "String" 11774 }, { 11775 "name": "options", 11776 "description": "<p>"header" "csv" "tsv"</p>\n", 11777 "type": "String" 11778 }, { 11779 "name": "callback", 11780 "description": "<p>function to be executed after\n <a href=\"#/p5/loadTable\">loadTable()</a> completes. On success, the\n <a href=\"#/p5.Table\">Table</a> object is passed in as the\n first argument.</p>\n", 11781 "type": "Function", 11782 "optional": true 11783 }, { 11784 "name": "errorCallback", 11785 "description": "<p>function to be executed if\n there is an error, response is passed\n in as first argument</p>\n", 11786 "type": "Function", 11787 "optional": true 11788 }], 11789 "return": { 11790 "description": "<a href=\"#/p5.Table\">Table</a> object containing data", 11791 "type": "Object" 11792 } 11793 }, { 11794 "line": 383, 11795 "params": [{ 11796 "name": "filename", 11797 "description": "", 11798 "type": "String" 11799 }, { 11800 "name": "callback", 11801 "description": "", 11802 "type": "Function", 11803 "optional": true 11804 }, { 11805 "name": "errorCallback", 11806 "description": "", 11807 "type": "Function", 11808 "optional": true 11809 }], 11810 "return": { 11811 "description": "", 11812 "type": "Object" 11813 } 11814 }] 11815 }, { 11816 "file": "src/io/files.js", 11817 "line": 603, 11818 "description": "<p>Reads the contents of a file and creates an XML object with its values.\nIf the name of the file is used as the parameter, as in the above example,\nthe file must be located in the sketch directory/folder.</p>\n<p>Alternatively, the file maybe be loaded from anywhere on the local\ncomputer using an absolute path (something that starts with / on Unix and\nLinux, or a drive letter on Windows), or the filename parameter can be a\nURL for a file found on a network.</p>\n<p>This method is asynchronous, meaning it may not finish before the next\nline in your sketch is executed. Calling <a href=\"#/p5/loadXML\">loadXML()</a> inside <a href=\"#/p5/preload\">preload()</a>\nguarantees to complete the operation before <a href=\"#/p5/setup\">setup()</a> and <a href=\"#/p5/draw\">draw()</a> are called.</p>\n<p>Outside of <a href=\"#/p5/preload\">preload()</a>, you may supply a callback function to handle the\nobject.</p>\n<p>This method is suitable for fetching files up to size of 64MB.</p>\n", 11819 "itemtype": "method", 11820 "name": "loadXML", 11821 "params": [{ 11822 "name": "filename", 11823 "description": "<p>name of the file or URL to load</p>\n", 11824 "type": "String" 11825 }, { 11826 "name": "callback", 11827 "description": "<p>function to be executed after <a href=\"#/p5/loadXML\">loadXML()</a>\n completes, XML object is passed in as\n first argument</p>\n", 11828 "type": "Function", 11829 "optional": true 11830 }, { 11831 "name": "errorCallback", 11832 "description": "<p>function to be executed if\n there is an error, response is passed\n in as first argument</p>\n", 11833 "type": "Function", 11834 "optional": true 11835 }], 11836 "return": {
11837 "description": "XML object containing data", 11838 "type": "Object" 11839 }, 11840 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let children = xml.getChildren('animal');\n\n for (let i = 0; i < children.length; i++) {\n let id = children[i].getNum('id');\n let coloring = children[i].getString('species');\n let name = children[i].getContent();\n print(id + ', ' + coloring + ', ' + name);\n }\n}\n\n// Sketch prints:\n// 0, Capra hircus, Goat\n// 1, Panthera pardus, Leopard\n// 2, Equus zebra, Zebra\n</code></div>"], 11841 "alt": "no image displayed", 11842 "class": "p5", 11843 "module": "IO", 11844 "submodule": "Input" 11845 }, { 11846 "file": "src/io/files.js", 11847 "line": 714, 11848 "description": "<p>This method is suitable for fetching files up to size of 64MB.</p>\n", 11849 "itemtype": "method", 11850 "name": "loadBytes", 11851 "params": [{ 11852 "name": "file", 11853 "description": "<p>name of the file or URL to load</p>\n", 11854 "type": "String" 11855 }, { 11856 "name": "callback", 11857 "description": "<p>function to be executed after <a href=\"#/p5/loadBytes\">loadBytes()</a>\n completes</p>\n", 11858 "type": "Function", 11859 "optional": true 11860 }, { 11861 "name": "errorCallback", 11862 "description": "<p>function to be executed if there\n is an error</p>\n", 11863 "type": "Function", 11864 "optional": true 11865 }], 11866 "return": { 11867 "description": "an object whose 'bytes' property will be the loaded buffer", 11868 "type": "Object" 11869 }, 11870 "example": ["\n<div class='norender'><code>\nlet data;\n\nfunction preload() {\n data = loadBytes('assets/mammals.xml');\n}\n\nfunction setup() {\n for (let i = 0; i < 5; i++) {\n console.log(data.bytes[i].toString(16));\n }\n}\n</code></div>"], 11871 "alt": "no image displayed", 11872 "class": "p5", 11873 "module": "IO", 11874 "submodule": "Input" 11875 }, { 11876 "file": "src/io/files.js", 11877 "line": 774, 11878 "description": "<p>Method for executing an HTTP GET request. If data type is not specified,\np5 will try to guess based on the URL, defaulting to text. This is equivalent to\ncalling <code>httpDo(path, 'GET')</code>. The 'binary' datatype will return\na Blob object, and the 'arrayBuffer' datatype will return an ArrayBuffer\nwhich can be used to initialize typed arrays (such as Uint8Array).</p>\n", 11879 "itemtype": "method", 11880 "name": "httpGet", 11881 "return": { 11882 "description": "A promise that resolves with the data when the operation\n completes successfully or rejects with the error after\n one occurs.", 11883 "type": "Promise" 11884 }, 11885 "example": ["\n<div class='norender'><code>\n// Examples use USGS Earthquake API:\n// https://earthquake.usgs.gov/fdsnws/event/1/#methods\nlet earthquakes;\nfunction preload() {\n // Get the most recent earthquake in the database\n let url =\n 'https://earthquake.usgs.gov/fdsnws/event/1/query?' +\n 'format=geojson&limit=1&orderby=time';\n httpGet(url, 'jsonp', false, function(response) {\n // when the HTTP request completes, populate the variable that holds the\n // earthquake data used in the visualization.\n earthquakes = response;\n });\n}\n\nfunction draw() {\n if (!earthquakes) {\n // Wait until the earthquake data has loaded before drawing.\n return;\n }\n background(200);\n // Get the magnitude and name of the earthquake out of the loaded JSON\n let earthquakeMag = earthquakes.features[0].properties.mag;\n let earthquakeName = earthquakes.features[0].properties.place;\n ellipse(width / 2, height / 2, earthquakeMag * 10, earthquakeMag * 10);\n textAlign(CENTER);
11885\n text(earthquakeName, 0, height - 30, width, 30);\n noLoop();\n}\n</code></div>"], 11886 "class": "p5", 11887 "module": "IO", 11888 "submodule": "Input", 11889 "overloads": [{ 11890 "line": 774, 11891 "params": [{ 11892 "name": "path", 11893 "description": "<p>name of the file or url to load</p>\n", 11894 "type": "String" 11895 }, { 11896 "name": "datatype", 11897 "description": "<p>"json", "jsonp", "binary", "arrayBuffer",\n "xml", or "text"</p>\n", 11898 "type": "String", 11899 "optional": true 11900 }, { 11901 "name": "data", 11902 "description": "<p>param data passed sent with request</p>\n", 11903 "type": "Object|Boolean", 11904 "optional": true 11905 }, { 11906 "name": "callback", 11907 "description": "<p>function to be executed after\n <a href=\"#/p5/httpGet\">httpGet()</a> completes, data is passed in\n as first argument</p>\n", 11908 "type": "Function", 11909 "optional": true 11910 }, { 11911 "name": "errorCallback", 11912 "description": "<p>function to be executed if\n there is an error, response is passed\n in as first argument</p>\n", 11913 "type": "Function", 11914 "optional": true 11915 }], 11916 "return": { 11917 "description": "A promise that resolves with the data when the operation\n completes successfully or rejects with the error after\n one occurs.", 11918 "type": "Promise" 11919 } 11920 }, { 11921 "line": 828, 11922 "params": [{ 11923 "name": "path", 11924 "description": "", 11925 "type": "String" 11926 }, { 11927 "name": "data", 11928 "description": "", 11929 "type": "Object|Boolean" 11930 }, { 11931 "name": "callback", 11932 "description": "", 11933 "type": "Function", 11934 "optional": true 11935 }, { 11936 "name": "errorCallback", 11937 "description": "", 11938 "type": "Function", 11939 "optional": true 11940 }], 11941 "return": { 11942 "description": "", 11943 "type": "Promise" 11944 } 11945 }, { 11946 "line": 836, 11947 "params": [{ 11948 "name": "path", 11949 "description": "", 11950 "type": "String" 11951 }, { 11952 "name": "callback", 11953 "description": "", 11954 "type": "Function" 11955 }, { 11956 "name": "errorCallback", 11957 "description": "", 11958 "type": "Function", 11959 "optional": true 11960 }], 11961 "return": { 11962 "description": "", 11963 "type": "Promise" 11964 } 11965 }] 11966 }, { 11967 "file": "src/io/files.js", 11968 "line": 851, 11969 "description": "<p>Method for executing an HTTP POST request. If data type is not specified,\np5 will try to guess based on the URL, defaulting to text. This is equivalent to\ncalling <code>httpDo(path, 'POST')</code>.</p>\n", 11970 "itemtype": "method", 11971 "name": "httpPost", 11972 "return": { 11973 "description": "A promise that resolves with the data when the operation\n completes successfully or rejects with the error after\n one occurs.", 11974 "type": "Promise" 11975 }, 11976 "example": ["\n<div>\n<code>\n// Examples use jsonplaceholder.typicode.com for a Mock Data API\n\nlet url = 'https://jsonplaceholder.typicode.com/posts';\nlet postData = { userId: 1, title: 'p5 Clicked!', body: 'p5.js is way cool.' };\n\nfunction setup() {\n createCanvas(800, 800);\n}\n\nfunction mousePressed() {\n // Pick new random color values\n let r = random(255);\n let g = random(255);\n let b = random(255);\n\n httpPost(url, 'json', postData, function(result) {\n strokeWeight(2);\n stroke(r, g, b);\n fill(r, g, b, 127);\n ellipse(mouseX, mouseY, 200, 200);\n text(result.body, mouseX, mouseY);\n });\n}\n</code>\n</div>\n\n\n<div><code>\nlet url = 'https://invalidURL'; // A bad URL that will cause errors\nlet postData = { title: 'p5 Clicked!', body: 'p5.js is way cool.' };\n\nfunction setup() {\n createCanvas(800, 800);\n}\n\nfunction mousePressed() {\n // Pick new random color values\n let r = random(255);\n let g = random(255);\n let b = random(255);\n\n httpPost(\n url,\n 'json',\n postData,\n function(result) {\n // ... won't be called\n },\n function(error) {\n strokeWeight(2);\n stroke(r, g, b);\n fill(r, g, b, 127);\n text(error.toString(), mouseX, mouseY);\n }\n );\n}\n</code></div>\n"], 11977 "class": "p5", 11978 "module": "IO", 11979 "submodule": "Input", 11980 "overloads": [{ 11981 "line": 851, 11982 "params": [{ 11983 "name": "path", 11984 "description": "<p>name of the file or url to load</p>\n", 11985 "type": "String" 11986 }, { 11987 "name": "datatype", 11988 "description": "<p>"json", "jsonp", "xml", or "text".\n If omitted, <a href=\"#/p5/httpPost\">httpPost()</a> will guess.</p>\n", 11989 "type": "String", 11990 "optional": true 11991 }, { 11992 "name": "data", 11993 "description": "<p>param data passed sent with request</p>\n", 11994 "type": "Object|Boolean", 11995 "optional": true 11996 }, { 11997 "name": "callback", 11998 "description": "<p>function to be executed after\n <a href=\"#/p5/httpPost\">httpPost()</a> completes, data is passed in\n as first argument</p>\n", 11999 "type": "Function", 12000 "optional": true 12001 }, { 12002 "name": "errorCallback", 12003 "description": "<p>function to be executed if\n there is an error, response is passed\n in as first argument</p>\n", 12004 "type": "Function", 12005 "optional": true 12006 }], 12007 "return": { 12008 "description": "A promise that resolves with the data when the operation\n completes successfully or rejects with the error after\n one occurs.", 12009 "type": "Promise" 12010 } 12011 }, { 12012 "line": 933, 12013 "params": [{ 12014 "name": "path", 12015 "description": "", 12016 "type": "String" 12017 }, { 12018 "name": "data", 12019 "description": "", 12020 "type": "Object|Boolean" 12021 }, { 12022 "name": "callback", 12023 "description": "", 12024 "type": "Function", 12025 "optional": true 12026 }, { 12027 "name": "errorCallback", 12028 "description": "", 12029 "type": "Function", 12030 "optional": true 12031 }], 12032 "return": { 12033 "description": "", 12034 "type": "Promise" 12035 } 12036 }, { 12037 "line": 941, 12038 "params": [{ 12039 "name": "path", 12040 "description": "", 12041 "type": "String" 12042 }, { 12043 "name": "callback", 12044 "description": "", 12045 "type": "Function" 12046 }, { 12047 "name": "errorCallback", 12048 "description": "", 12049 "type": "Function", 12050 "optional": true 12051 }], 12052 "return": { 12053 "description": "", 12054 "type": "Promise" 12055 } 12056 }] 12057 }, { 12058 "file": "src/io/files.js", 12059 "line": 956, 12060 "description": "<p>Method for executing an HTTP request. If data type is not specified,\np5 will try to guess based on the URL, defaulting to text.<br><br>\nFor more advanced use, you may also pass in the path as the first argument\nand a object as the second argument, the signature follows the one specified\nin the Fetch API specification.\nThis method is suitable for fetching files up to size of 64MB when "GET" is used.</p>\n", 12061 "itemtype": "method", 12062 "name": "httpDo", 12063 "return": { 12064 "description": "A promise that resolves with the data when the operation\n completes successfully or rejects with the error after\n one occurs.", 12065 "type": "Promise" 12066 }, 12067 "example": ["\n<div>\n<code>\n// Examples use USGS Earthquake API:\n// https://earthquake.usgs.gov/fdsnws/event/1/#methods\n\n// dis
12067plays an animation of all USGS earthquakes\nlet earthquakes;\nlet eqFeatureIndex = 0;\n\nfunction preload() {\n let url = 'https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson';\n httpDo(\n url,\n {\n method: 'GET',\n // Other Request options, like special headers for apis\n headers: { authorization: 'Bearer secretKey' }\n },\n function(res) {\n earthquakes = res;\n }\n );\n}\n\nfunction draw() {\n // wait until the data is loaded\n if (!earthquakes || !earthquakes.features[eqFeatureIndex]) {\n return;\n }\n clear();\n\n let feature = earthquakes.features[eqFeatureIndex];\n let mag = feature.properties.mag;\n let rad = mag / 11 * ((width + height) / 2);\n fill(255, 0, 0, 100);\n ellipse(width / 2 + random(-2, 2), height / 2 + random(-2, 2), rad, rad);\n\n if (eqFeatureIndex >= earthquakes.features.length) {\n eqFeatureIndex = 0;\n } else {\n eqFeatureIndex += 1;\n }\n}\n</code>\n</div>"], 12068 "class": "p5", 12069 "module": "IO", 12070 "submodule": "Input", 12071 "overloads": [{ 12072 "line": 956, 12073 "params": [{ 12074 "name": "path", 12075 "description": "<p>name of the file or url to load</p>\n", 12076 "type": "String" 12077 }, { 12078 "name": "method", 12079 "description": "<p>either "GET", "POST", or "PUT",\n defaults to "GET"</p>\n", 12080 "type": "String", 12081 "optional": true 12082 }, { 12083 "name": "datatype", 12084 "description": "<p>"json", "jsonp", "xml", or "text"</p>\n", 12085 "type": "String", 12086 "optional": true 12087 }, { 12088 "name": "data", 12089 "description": "<p>param data passed sent with request</p>\n", 12090 "type": "Object", 12091 "optional": true 12092 }, { 12093 "name": "callback", 12094 "description": "<p>function to be executed after\n <a href=\"#/p5/httpGet\">httpGet()</a> completes, data is passed in\n as first argument</p>\n", 12095 "type": "Function", 12096 "optional": true 12097 }, { 12098 "name": "errorCallback", 12099 "description": "<p>function to be executed if\n there is an error, response is passed\n in as first argument</p>\n", 12100 "type": "Function", 12101 "optional": true 12102 }], 12103 "return": { 12104 "description": "A promise that resolves with the data when the operation\n completes successfully or rejects with the error after\n one occurs.", 12105 "type": "Promise" 12106 } 12107 }, { 12108 "line": 1027, 12109 "params": [{ 12110 "name": "path", 12111 "description": "", 12112 "type": "String" 12113 }, { 12114 "name": "options", 12115 "description": "<p>Request object options as documented in the\n "fetch" API\n<a href=\"https://developer.mozilla.org/en/docs/Web/API/Fetch_API\">reference</a></p>\n", 12116 "type": "Object" 12117 }, { 12118 "name": "callback", 12119 "description": "", 12120 "type": "Function", 12121 "optional": true 12122 }, { 12123 "name": "errorCallback", 12124 "description": "", 12125 "type": "Function", 12126 "optional": true 12127 }], 12128 "return": { 12129 "description": "", 12130 "type": "Promise" 12131 } 12132 }] 12133 }, { 12134 "file": "src/io/files.js", 12135 "line": 1183, 12136 "itemtype": "method", 12137 "name": "createWriter", 12138 "params": [{ 12139 "name": "name", 12140 "description": "<p>name of the file to be created</p>\n", 12141 "type": "String" 12142 }, { 12143 "name": "extension", 12144 "description": "", 12145 "type": "String", 12146 "optional": true 12147 }], 12148 "return": { 12149 "description": "", 12150 "type": "p5.PrintWriter" 12151 }, 12152 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100);\n background(200);\n text('click here to save', 10, 10, 70, 80);\n}\n\nfunction mousePressed() {\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n var writer = createWriter('squares.txt');\n for (let i = 0; i < 10;
12152 i++) {\n writer.print(i * i);\n }\n writer.close();\n writer.clear();\n }\n}\n</code>\n</div>"], 12153 "class": "p5", 12154 "module": "IO", 12155 "submodule": "Output" 12156 }, { 12157 "file": "src/io/files.js", 12158 "line": 1238, 12159 "description": "<p>Writes data to the PrintWriter stream</p>\n", 12160 "itemtype": "method", 12161 "name": "write", 12162 "params": [{ 12163 "name": "data", 12164 "description": "<p>all data to be written by the PrintWriter</p>\n", 12165 "type": "Array" 12166 }], 12167 "example": ["\n<div class=\"norender notest\">\n<code>\n// creates a file called 'newFile.txt'\nlet writer = createWriter('newFile.txt');\n// write 'Hello world!'' to the file\nwriter.write(['Hello world!']);\n// close the PrintWriter and save the file\nwriter.close();\n</code>\n</div>\n<div class='norender notest'>\n<code>\n// creates a file called 'newFile2.txt'\nlet writer = createWriter('newFile2.txt');\n// write 'apples,bananas,123' to the file\nwriter.write(['apples', 'bananas', 123]);\n// close the PrintWriter and save the file\nwriter.close();\n</code>\n</div>\n<div class='norender notest'>\n<code>\n// creates a file called 'newFile3.txt'\nlet writer = createWriter('newFile3.txt');\n// write 'My name is: Teddy' to the file\nwriter.write('My name is:');\nwriter.write(' Teddy');\n// close the PrintWriter and save the file\nwriter.close();\n</code>\n</div>"], 12168 "class": "p5.PrintWriter", 12169 "module": "IO", 12170 "submodule": "Output" 12171 }, { 12172 "file": "src/io/files.js", 12173 "line": 1278, 12174 "description": "<p>Writes data to the PrintWriter stream, and adds a new line at the end</p>\n", 12175 "itemtype": "method", 12176 "name": "print", 12177 "params": [{ 12178 "name": "data", 12179 "description": "<p>all data to be printed by the PrintWriter</p>\n", 12180 "type": "Array" 12181 }], 12182 "example": ["\n<div class='norender notest'>\n<code>\n// creates a file called 'newFile.txt'\nlet writer = createWriter('newFile.txt');\n// creates a file containing\n// My name is:\n// Teddy\nwriter.print('My name is:');\nwriter.print('Teddy');\n// close the PrintWriter and save the file\nwriter.close();\n</code>\n</div>\n<div class='norender notest'>\n<code>\nlet writer;\n\nfunction setup() {\n createCanvas(400, 400);\n // create a PrintWriter\n writer = createWriter('newFile.txt');\n}\n\nfunction draw() {\n // print all mouseX and mouseY coordinates to the stream\n writer.print([mouseX, mouseY]);\n}\n\nfunction mouseClicked() {\n // close the PrintWriter and save the file\n writer.close();\n}\n</code>\n</div>"], 12183 "class": "p5.PrintWriter", 12184 "module": "IO", 12185 "submodule": "Output" 12186 }, { 12187 "file": "src/io/files.js", 12188 "line": 1321, 12189 "description": "<p>Clears the data already written to the PrintWriter object</p>\n", 12190 "itemtype": "method", 12191 "name": "clear", 12192 "example": ["\n<div class =\"norender notest\"><code>\n// create writer object\nlet writer = createWriter('newFile.txt');\nwriter.write(['clear me']);\n// clear writer object here\nwriter.clear();\n// close writer\nwriter.close();\n</code></div>\n"], 12193 "class": "p5.PrintWriter", 12194 "module": "IO", 12195 "submodule": "Output" 12196 }, { 12197 "file": "src/io/files.js", 12198 "line": 1339, 12199 "description": "<p>Closes the PrintWriter</p>\n", 12200 "itemtype": "method", 12201 "name": "close", 12202 "example": ["\n<div class=\"norender notest\">\n<code>\n// create a file called 'newFile.txt'\nlet writer = createWriter('newFile.txt');\n// close the PrintWriter and save the file\nwriter.close();\n</code>\n</div>\n<div class='norender notest'>\n<code>\n// create a file called 'newFile2.txt'\nlet writer = createWriter('newFile2.txt');\n// write some data to the file\nwriter.write([100, 101, 102]);\n// close the PrintWriter and save the file\nwriter.close();\n</code>\n</div>"], 12203 "class": "p5.PrintWriter", 12204 "module": "IO", 12205 "submodule": "Output" 12206 }, { 12207 "file": "src/io/files.js", 12208 "line": 1388, 12209 "description": "<p>Save an image, text, json, csv, wav, or html. Prompts download to\nthe client's computer. <b>Note that it is not recommended to call <a href=\"#/p5/save\">save()</a>\nwithin draw if it's looping, as the <a href=\"#/p5/save\">save()</a> function will open a new save\ndialog every frame.</b></p>\n<p>The default behavior is to save the canvas as an image. You can\noptionally specify a filename.\nFor example:</p>\n <pre class='language-javascript'><code>\n save();
12209\n save('myCanvas.jpg'); // save a specific canvas with a filename\n </code></pre>\n\n<p>Alternately, the first parameter can be a pointer to a canvas\n<a href=\"#/p5.Element\">p5.Element</a>, an Array of Strings,\nan Array of JSON, a JSON object, a <a href=\"#/p5.Table\">p5.Table</a>, a <a href=\"#/p5.Image\">p5.Image</a>, or a\np5.SoundFile (requires p5.sound). The second parameter is a filename\n(including extension). The third parameter is for options specific\nto this type of object. This method will save a file that fits the\ngiven parameters. For example:</p>\n\n <pre class='language-javascript'><code>\n // Saves canvas as an image\n save('myCanvas.jpg');\n\n // Saves pImage as a png image\n let img = createImage(10, 10);\n save(img, 'my.png');\n\n // Saves canvas as an image\n let cnv = createCanvas(100, 100);\n save(cnv, 'myCanvas.jpg');\n\n // Saves p5.Renderer object as an image\n let gb = createGraphics(100, 100);\n save(gb, 'myGraphics.jpg');\n\n let myTable = new p5.Table();\n\n // Saves table as html file\n save(myTable, 'myTable.html');\n\n // Comma Separated Values\n save(myTable, 'myTable.csv');\n\n // Tab Separated Values\n save(myTable, 'myTable.tsv');\n\n let myJSON = { a: 1, b: true };\n\n // Saves pretty JSON\n save(myJSON, 'my.json');\n\n // Optimizes JSON filesize\n save(myJSON, 'my.json', true);\n\n // Saves array of strings to a text file with line breaks after each item\n let arrayOfStrings = ['a', 'b'];\n save(arrayOfStrings, 'my.txt');\n </code></pre>", 12210 "itemtype": "method", 12211 "name": "save", 12212 "params": [{ 12213 "name": "objectOrFilename", 12214 "description": "<p>If filename is provided, will\n save canvas as an image with\n either png or jpg extension\n depending on the filename.\n If object is provided, will\n save depending on the object\n and filename (see examples\n above).</p>\n", 12215 "type": "Object|String", 12216 "optional": true 12217 }, { 12218 "name": "filename", 12219 "description": "<p>If an object is provided as the first\n parameter, then the second parameter\n indicates the filename,\n and should include an appropriate\n file extension (see examples above).</p>\n", 12220 "type": "String", 12221 "optional": true 12222 }, { 12223 "name": "options", 12224 "description": "<p>Additional options depend on\n filetype. For example, when saving JSON,\n <code>true</code> indicates that the\n output will be optimized for filesize,\n rather than readability.</p>\n", 12225 "type": "Boolean|String", 12226 "optional": true 12227 }], 12228 "class": "p5", 12229 "module": "IO", 12230 "submodule": "Output" 12231 }, { 12232 "file": "src/io/files.js", 12233 "line": 1516, 12234 "description": "<p>Writes the contents of an Array or a JSON object to a .json file.\nThe file saving process and location of the saved file will\nvary between web browsers.</p>\n", 12235 "itemtype": "method", 12236 "name": "saveJSON", 12237 "params": [{ 12238 "name": "json", 12239 "description": "", 12240 "type": "Array|Object" 12241 }, { 12242 "name": "filename", 12243 "description": "", 12244 "type": "String" 12245 }, { 12246 "name": "optimize", 12247 "description": "<p>If true, removes line breaks\n and spaces from the output\n file to optimize filesize\n (but not readability).</p>\n", 12248 "type": "Boolean", 12249 "optional": true 12250 }], 12251 "example": ["\n <div><code>\n let json = {}; // new JSON Object\n\n json.id = 0;\n json.species = 'Panthera leo';\n json.name = 'Lion';\n\n function setup() {\n createCanvas(100, 100);\n background(200);\n text('click here to save', 10, 10, 70, 80);\n }\n\n function mousePressed() {\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n saveJSON(json, 'lion.json');\n }\n }\n\n // saves the following to a file called \"lion.json\":\n // {\n // \"id\": 0,\n // \"species\": \"Panthera leo\",\n // \"name\": \"Lion\"\n // }\n </code></div>"], 12252 "alt": "no image displayed", 12253 "class": "p5", 12254 "module": "IO", 12255 "submodule": "Output" 12256 }, { 12257 "file": "src/io/files.js", 12258 "line": 1574, 12259 "description": "<p>Writes an array of Strings to a text file, one line per String.\nThe file saving process and location of the saved file will\nvary between web browsers.</p>\n", 12260 "itemtype": "method", 12261 "name": "saveStrings", 12262 "params": [{ 12263 "name": "list", 12264 "description": "<p>string array to be written</p>\n", 12265 "type": "String[]" 12266 }, { 12267 "name": "filename", 12268 "description": "<p>filename for output</p>\n", 12269 "type": "String" 12270 }, { 12271 "name": "extension", 12272 "description": "<p>the filename's extension</p>\n", 12273 "type": "String", 12274 "optional": true 12275 }], 12276 "example": ["\n <div><code>\n let words = 'apple bear cat dog';\n\n // .split() outputs an Array\n let list = split(words, ' ');\n\n function setup() {\n createCanvas(100, 100);\n background(200);\n text('click here to save', 10, 10, 70, 80);\n }\n\n function mousePressed() {\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n saveStrings(list, 'nouns.txt');\n }\n }\n\n // Saves the following to a file called 'nouns.txt':\n //\n // apple\n // bear\n // cat\n // dog\n </code></div>"], 12277 "alt": "no image displayed", 12278 "class": "p5", 12279 "module": "IO", 12280 "submodule": "Output" 12281 }, { 12282 "file": "src/io/files.js", 12283 "line": 1642, 12284 "description": "<p>Writes the contents of a <a href=\"#/p5.Table\">Table</a> object to a file. Defaults to a\ntext file with comma-separated-values ('csv') but can also\nuse tab separation ('tsv'), or generate an HTML table ('html').\nThe file saving process and location of the saved file will\nvary between web browsers.</p>\n", 12285 "itemtype": "method", 12286 "name": "saveTable", 12287 "params": [{ 12288 "name": "Table", 12289 "description": "<p>the <a href=\"#/p5.Table\">Table</a> object to save to a file</p>\n", 12290 "type": "p5.Table" 12291 }, { 12292 "name": "filename", 12293 "description": "<p>the filename to which the Table should be saved</p>\n", 12294 "type": "String" 12295 }, { 12296 "name": "options", 12297 "description": "<p>can be one of "tsv", "csv", or "html"</p>\n", 12298 "type": "String", 12299 "optional": true 12300 }], 12301 "example": ["\n<div><code>\n let table;\n\n function setup() {\n table = new p5.Table();\n\n table.addColumn('id');\n table.addColumn('species');\n table.addColumn('name');\n\n let newRow = table.addRow();\n newRow.setNum('id', table.getRowCount() - 1);\n newRow.setString('species', 'Panthera leo');\n newRow.setString('name', 'Lion');\n\n // To save, un-comment next line then click 'run'\n // saveTable(table, 'new.csv');\n }\n\n // Saves the following to a file called 'new.csv':\n // id,species,name\n // 0,Panthera leo,Lion\n </code></div>"], 12302 "alt": "no image displayed", 12303 "class": "p5", 12304 "module": "IO", 12305 "submodule": "Output" 12306 }, { 12307 "file": "src/io/p5.Table.js", 12308 "line": 11, 12309 "description": "<p>Table Options</p>\n<p>Generic class for handling tabular data, typically from a\nCSV, TSV, or other sort of spreadsheet file.</p>\n<p>CSV files are\n<a href=\"http://en.wikipedia.org/wiki/Comma-separated_values\">\ncomma separated values</a>, often with the data in quotes. TSV\nfiles use tabs as separators, and usually don't bother with the\nquotes.</p>\n<p>File names should end with .csv if they're comma separated.</p>\n<p>A rough "spec" for CSV can be found\n<a href=\"http://tools.ietf.org/html/rfc4180\">here</a>.</p>\n<p>To load files, use the <a href=\"#/p5/loadTable\">loadTable</a> method.</p>\n<p>To save tables to your computer, use the <a href=\"#/p5/save\">save</a> method\n or the <a href=\"#/p5/saveTable\">saveTable</a> method.</p>\n\n<p>Possible options include:</p>\n<ul>\n<li>csv - parse the table as comma-separated values\n<li>tsv - parse the table as tab-separated values\n<li>header - this table has a header (title) row\n</ul>", 12310 "class": "p5.Table", 12311 "module": "IO", 12312 "submodule": "Table" 12313 }, { 12314 "file": "src/io/p5.Table.js", 12315 "line": 45, 12316 "itemtype": "property", 12317 "name": "columns", 12318 "type": "String[]", 12319 "class": "p5.Table", 12320 "module": "IO", 12321 "submodule": "Table" 12322 }, { 12323 "file": "src/io/p5.Table.js", 12324 "line": 50, 12325 "itemtype": "property", 12326 "name": "rows", 12327 "type": "p5.TableRow[]", 12328 "class": "p5.Table", 12329 "module": "IO", 12330 "submodule": "Table" 12331 }, { 12332 "file": "src/io/p5.Table.js", 12333 "line": 56, 12334 "description": "<p>Use <a href=\"#/p5/addRow\">addRow()</a> to add a new row of data to a <a href=\"#/p5.Table\">p5.Table</a> object. By default,\nan empty row is created. Typically, you would store a reference to\nthe new row in a TableRow object (see newRow in the example above),\nand then set individual values using <a href=\"#/p5/set\">set()</a>.</p>\n<p>If a <a href=\"#/p5.TableRow\">p5.TableRow</a> object is included as a parameter, then that row is\nduplicated and added to the table.</p>\n", 12335 "itemtype": "method", 12336 "name": "addRow", 12337 "params": [{ 12338 "name": "row", 12339 "description": "<p>row to be added to the table</p>\n", 12340 "type": "p5.TableRow", 12341 "optional": true 12342 }], 12343 "return": { 12344 "description": "the row that was added", 12345 "type": "p5.TableRow" 12346 }, 12347 "example": ["\n <div class=\"norender\">\n <code>\n // Given the CSV file \"mammals.csv\"\n // in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n //add a row\n let newRow = table.addRow();\n newRow.setString('id', table.getRowCount() - 1);\n newRow.setString('species', 'Canis Lupus');\n newRow.setString('name', 'Wolf');\n\n //print the results\n for (let r = 0; r < table.getRowCount(); r++)\n for (let c = 0; c < table.getColumnCount(); c++)\n print(table.getString(r, c));\n }\n </code>\n </div>"], 12348 "alt": "no image displayed", 12349 "class": "p5.Table", 12350 "module": "IO", 12351 "submodule": "Table" 12352 }, { 12353 "file": "src/io/p5.Table.js", 12354 "line": 120, 12355 "description": "<p>Removes a row from the table object.</p>\n", 12356 "itemtype": "method", 12357 "name": "removeRow", 12358 "params": [{ 12359 "name": "id", 12360 "description": "<p>ID number of the row to remove</p>\n", 12361 "type": "Integer" 12362 }], 12363 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n //remove the first row\n table.removeRow(0);\n\n //print the results\n for (let r = 0; r < table.getRowCount(); r++)\n for (let c = 0; c < table.getColumnCount(); c++)\n print(table.getString(r, c));\n}\n</code>\n</div>"], 12364 "alt": "no image displayed", 12365 "class": "p5.Table", 12366 "module": "IO", 12367 "submodule": "Table" 12368 }, { 12369 "file": "src/io/p5.Table.js", 12370 "line": 168, 12371 "description": "<p>Returns a reference to the specified <a href=\"#/p5.TableRow\">p5.TableRow</a>. The reference\ncan then be used to get and set values of the selected row.</p>\n", 12372 "itemtype": "method", 12373 "name": "getRow", 12374 "params": [{ 12375 "name": "rowID", 12376 "description": "<p>ID number of the row to get</p>\n", 12377 "type": "Integer" 12378 }], 12379 "return": { 12380 "description": "<a href=\"#/p5.TableRow\">p5.TableRow</a> object", 12381 "type": "p5.TableRow" 12382 }, 12383 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n let row = table.getRow(1);\n //print it column by column\n //note: a row is an object, not an array\n for (let c = 0; c < table.getColumnCount(); c++) {\n print(row.getString(c));\n }\n}\n</code>\n</div>"], 12384 "alt": "no image displayed", 12385 "class": "p5.Table", 12386 "module": "IO", 12387 "submodule": "Table" 12388 }, { 12389 "file": "src/io/p5.Table.js", 12390 "line": 214, 12391 "description": "<p>Gets all rows from the table. Returns an array of <a href=\"#/p5.TableRow\">p5.TableRow</a>s.</p>\n", 12392 "itemtype": "method", 12393 "name": "getRows", 12394 "return": { 12395 "description": "Array of <a href=\"#/p5.TableRow\">p5.TableRow</a>s", 12396 "type": "p5.TableRow[]" 12397 }, 12398 "example": ["\n <div class=\"norender\">\n <code>\n // Given the CSV file \"mammals.csv\"\n // in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n let rows = table.getRows();\n\n //warning: rows is an array of objects\n for (let r = 0; r < rows.length; r++) {\n rows[r].set('name', 'Unicorn');\n }\n\n //print the results\n for (let r = 0; r < table.getRowCount(); r++)\n for (let c = 0; c < table.getColumnCount(); c++)\n print(table.getString(r, c));\n }\n </code>\n </div>"], 12399 "alt": "no image displayed", 12400 "class": "p5.Table", 12401 "module": "IO", 12402 "submodule": "Table" 12403 }, { 12404 "file": "src/io/p5.Table.js", 12405 "line": 263, 12406 "description": "<p>Finds the first row in the Table that contains the value\nprovided, and returns a reference to that row. Even if\nmultiple rows are possible matches, only the first matching\nrow is returned. The column to search may be specified by\neither its ID or title.</p>\n", 12407 "itemtype": "method", 12408 "name": "findRow", 12409 "params": [{ 12410 "name": "value", 12411 "description": "<p>The value to match</p>\n", 12412 "type": "String" 12413 }, { 12414 "name": "column", 12415 "description": "<p>ID number or title of the\n column to search</p>\n"
12415, 12416 "type": "Integer|String" 12417 }], 12418 "return": { 12419 "description": "", 12420 "type": "p5.TableRow" 12421 }, 12422 "example": ["\n <div class=\"norender\">\n <code>\n // Given the CSV file \"mammals.csv\"\n // in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n //find the animal named zebra\n let row = table.findRow('Zebra', 'name');\n //find the corresponding species\n print(row.getString('species'));\n }\n </code>\n </div>"], 12423 "alt": "no image displayed", 12424 "class": "p5.Table", 12425 "module": "IO", 12426 "submodule": "Table" 12427 }, { 12428 "file": "src/io/p5.Table.js", 12429 "line": 328, 12430 "description": "<p>Finds the rows in the Table that contain the value\nprovided, and returns references to those rows. Returns an\nArray, so for must be used to iterate through all the rows,\nas shown in the example above. The column to search may be\nspecified by either its ID or title.</p>\n", 12431 "itemtype": "method", 12432 "name": "findRows", 12433 "params": [{ 12434 "name": "value", 12435 "description": "<p>The value to match</p>\n", 12436 "type": "String" 12437 }, { 12438 "name": "column", 12439 "description": "<p>ID number or title of the\n column to search</p>\n", 12440 "type": "Integer|String" 12441 }], 12442 "return": { 12443 "description": "An Array of TableRow objects", 12444 "type": "p5.TableRow[]" 12445 }, 12446 "example": ["\n <div class=\"norender\">\n <code>\n // Given the CSV file \"mammals.csv\"\n // in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n //add another goat\n let newRow = table.addRow();\n newRow.setString('id', table.getRowCount() - 1);\n newRow.setString('species', 'Scape Goat');\n newRow.setString('name', 'Goat');\n\n //find the rows containing animals named Goat\n let rows = table.findRows('Goat', 'name');\n print(rows.length + ' Goats found');\n }\n </code>\n </div>"], 12447 "alt": "no image displayed", 12448 "class": "p5.Table", 12449 "module": "IO", 12450 "submodule": "Table" 12451 }, { 12452 "file": "src/io/p5.Table.js", 12453 "line": 397, 12454 "description": "<p>Finds the first row in the Table that matches the regular\nexpression provided, and returns a reference to that row.\nEven if multiple rows are possible matches, only the first\nmatching row is returned. The column to search may be\nspecified by either its ID or title.</p>\n", 12455 "itemtype": "method", 12456 "name": "matchRow", 12457 "params": [{ 12458 "name": "regexp", 12459 "description": "<p>The regular expression to match</p>\n", 12460 "type": "String|RegExp" 12461 }, { 12462 "name": "column", 12463 "description": "<p>The column ID (number) or\n title (string)</p>\n", 12464 "type": "String|Integer" 12465 }], 12466 "return": { 12467 "description": "TableRow object", 12468 "type": "p5.TableRow" 12469 }, 12470 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n //Search using specified regex on a given column, return TableRow object\n let mammal = table.matchRow(new RegExp('ant'), 1);\n print(mammal.getString(1));\n //Output \"Panthera pardus\"\n}\n</code>\n</div>\n"], 12471 "class": "p5.Table", 12472 "module": "IO", 12473 "submodule": "Table" 12474 }, { 12475 "file": "src/io/p5.Table.js", 12476 "line": 456, 12477 "description": "<p>Finds the rows in the Table that match the regular expression provided,\nand returns references to those rows. Returns an array, so for must be\nused to iterate through all the rows, as shown in the example. The\ncolumn to search may be specified by either its ID or title.</p>\n", 12478 "itemtype": "method", 12479 "name": "matchRows", 12480 "params": [{ 12481 "name": "regexp", 12482 "description": "<p>The regular expression to match</p>\n", 12483 "type": "String" 12484 }, { 12485 "name": "column", 12486 "description": "<p>The column ID (number) or\n title (string)</p>\n", 12487 "type": "String|Integer", 12488 "optional": true 12489 }], 12490 "return": { 12491 "description": "An Array of TableRow objects", 12492 "type": "p5.TableRow[]" 12493 }, 12494 "example": ["\n<div class=\"norender\">\n<code>\nlet table;\n\nfunction setup() {\n table = new p5.Table();\n\n table.addColumn('name');\n table.addColumn('type');\n\n let newRow = table.addRow();\n newRow.setString('name', 'Lion');\n newRow.setString('type', 'Mammal');\n\n newRow = table.addRow();\n newRow.setString('name', 'Snake');\n newRow.setString('type', 'Reptile');\n\n newRow = table.addRow();\n newRow.setString('name', 'Mosquito');\n newRow.setString('type', 'Insect');\n\n newRow = table.addRow();\n newRow.setString('name', 'Lizard');\n newRow.setString('type', 'Reptile');\n\n let rows = table.matchRows('R.*', 'type');\n for (let i = 0; i < rows.length;
12494 i++) {\n print(rows[i].getString('name') + ': ' + rows[i].getString('type'));\n }\n}\n// Sketch prints:\n// Snake: Reptile\n// Lizard: Reptile\n</code>\n</div>"], 12495 "class": "p5.Table", 12496 "module": "IO", 12497 "submodule": "Table" 12498 }, { 12499 "file": "src/io/p5.Table.js", 12500 "line": 523, 12501 "description": "<p>Retrieves all values in the specified column, and returns them\nas an array. The column may be specified by either its ID or title.</p>\n", 12502 "itemtype": "method", 12503 "name": "getColumn", 12504 "params": [{ 12505 "name": "column", 12506 "description": "<p>String or Number of the column to return</p>\n", 12507 "type": "String|Number" 12508 }], 12509 "return": { 12510 "description": "Array of column values", 12511 "type": "Array" 12512 }, 12513 "example": ["\n <div class=\"norender\">\n <code>\n // Given the CSV file \"mammals.csv\"\n // in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n //getColumn returns an array that can be printed directly\n print(table.getColumn('species'));\n //outputs [\"Capra hircus\", \"Panthera pardus\", \"Equus zebra\"]\n }\n </code>\n </div>"], 12514 "alt": "no image displayed", 12515 "class": "p5.Table", 12516 "module": "IO", 12517 "submodule": "Table" 12518 }, { 12519 "file": "src/io/p5.Table.js", 12520 "line": 576, 12521 "description": "<p>Removes all rows from a Table. While all rows are removed,\ncolumns and column titles are maintained.</p>\n", 12522 "itemtype": "method", 12523 "name": "clearRows", 12524 "example": ["\n <div class=\"norender\">\n <code>\n // Given the CSV file \"mammals.csv\"\n // in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n table.clearRows();\n print(table.getRowCount() + ' total rows in table');\n print(table.getColumnCount() + ' total columns in table');\n }\n </code>\n </div>"], 12525 "alt": "no image displayed", 12526 "class": "p5.Table", 12527 "module": "IO", 12528 "submodule": "Table" 12529 }, { 12530 "file": "src/io/p5.Table.js", 12531 "line": 618, 12532 "description": "<p>Use <a href=\"#/p5/addColumn\">addColumn()</a> to add a new column to a <a href=\"#/p5.Table\">Table</a> object.\nTypically, you will want to specify a title, so the column\nmay be easily referenced later by name. (If no title is\nspecified, the new column's title will be null.)</p>\n", 12533 "itemtype": "method", 12534 "name": "addColumn", 12535 "params": [{ 12536 "name": "title", 12537 "description": "<p>title of the given column</p>\n", 12538 "type": "String", 12539 "optional": true 12540 }], 12541 "example": ["\n <div class=\"norender\">\n <code>\n // Given the CSV file \"mammals.csv\"\n // in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n table.addColumn('carnivore');\n table.set(0, 'carnivore', 'no');\n table.set(1, 'carnivore', 'yes');\n table.set(2, 'carnivore', 'no');\n\n //print the results\n for (let r = 0; r < table.getRowCount(); r++)\n for (let c = 0; c < table.getColumnCount(); c++)\n print(table.getString(r, c));\n }\n </code>\n </div>"], 12542 "alt": "no image displayed", 12543 "class": "p5.Table", 12544 "module": "IO", 12545 "submodule": "Table" 12546 }, { 12547 "file": "src/io/p5.Table.js", 12548 "line": 669, 12549 "description": "<p>Returns the total number of columns in a Table.</p>\n", 12550 "itemtype": "method", 12551 "name": "getColumnCount", 12552 "return": { 12553 "description": "Number of columns in this table", 12554 "type": "Integer" 12555 }, 12556 "example": ["\n <div>\n <code>\n // given the cvs file \"blobs.csv\" in /assets directory\n // ID, Name, Flavor, Shape, Color\n // Blob1, Blobby, Sweet, Blob, Pink\n // Blob2, Saddy, Savory, Blob, Blue\n\n let table;\n\n function preload() {\n table = loadTable('assets/blobs.csv');\n }\n\n function setup() {\n createCanvas(200, 100);\n textAlign(CENTER);\n background(255);\n }\n\n function draw() {\n let numOfColumn = table.getColumnCount();\n text('There are ' + numOfColumn + ' columns in the table.', 100, 50);\n }\n </code>\n </div>"], 12557 "class": "p5.Table", 12558 "module": "IO", 12559 "submodule": "Table" 12560 }, { 12561 "file": "src/io/p5.Table.js", 12562 "line": 705, 12563 "description": "<p>Returns the total number of rows in a Table.</p>\n", 12564 "itemtype": "method", 12565 "name": "getRowCount", 12566 "return": { 12567 "description": "Number of rows in this table", 12568 "type": "Integer" 12569 }, 12570 "example": ["\n <div>\n <code>\n // given the cvs file \"blobs.csv\" in /assets directory\n //\n // ID, Name, Flavor, Shape, Color\n // Blob1, Blobby, Sweet, Blob, Pink\n // Blob2, Saddy, Savory, Blob, Blue\n\n let table;\n\n function preload() {\n table = loadTable('assets/blobs.csv');\n }\n\n function setup() {\n createCanvas(200, 100);\n textAlign(CENTER);\n background(255);\n }\n\n function draw() {\n text('There are ' + table.getRowCount() + ' rows in the table.', 100, 50);\n }\n </code>\n </div>"], 12571 "class": "p5.Table", 12572 "module": "IO", 12573 "submodule": "Table" 12574 }, { 12575 "file": "src/io/p5.Table.js", 12576 "line": 741, 12577 "description": "<p>Removes any of the specified characters (or "tokens").</p>\n\n<p>If no column is specified, then the values in all columns and\nrows are processed. A specific column may be referenced by\neither its ID or title.</p>", 12578 "itemtype": "method", 12579 "name": "removeTokens", 12580 "params": [{ 12581 "name": "chars", 12582 "description": "<p>String listing characters to be removed</p>\n", 12583 "type": "String" 12584 }, { 12585 "name": "column", 12586 "description": "<p>Column ID (number)\n or name (string)</p>\n", 12587 "type": "String|Integer", 12588 "optional": true 12589 }], 12590 "example": ["\n <div class=\"norender\"><code>\n function setup() {\n let table = new p5.Table();\n\n table.addColumn('name');\n table.addColumn('type');\n\n let newRow = table.addRow();\n newRow.setString('name', ' $Lion ,');\n newRow.setString('type', ',,,Mammal');\n\n newRow = table.addRow();\n newRow.setString('name', '$Snake ');\n newRow.setString('type', ',,,Reptile');\n\n table.removeTokens(',$ ');\n print(table.getArray());\n }\n\n // prints:\n // 0 \"Lion\" \"Mamal\"\n // 1 \"Snake\" \"Reptile\"\n </code></div>"], 12591 "class": "p5.Table", 12592 "module": "IO", 12593 "submodule": "Table" 12594 }, { 12595 "file": "src/io/p5.Table.js", 12596 "line": 815, 12597 "description": "<p>Trims leading and trailing whitespace, such as spaces and tabs,\nfrom String table values. If no column is specified, then the\nvalues in all columns and rows are trimmed. A specific column\nmay be referenced by either its ID or title.</p>\n", 12598 "itemtype": "method", 12599 "name": "trim", 12600 "params": [{ 12601 "name": "column", 12602 "description": "<p>Column ID (number)\n or name (string)</p>\n", 12603 "type": "String|Integer", 12604 "optional": true 12605 }], 12606 "example": ["\n <div class=\"norender\"><code>\n function setup() {\n let table = new p5.Table();\n\n table.addColumn('name');\n table.addColumn('type');\n\n let newRow = table.addRow();\n newRow.setString('name', ' Lion ,');\n newRow.setString('type', ' Mammal ');\n\n newRow = table.addRow();\n newRow.setString('name', ' Snake ');\n newRow.setString('type', ' Reptile ');\n\n table.trim();\n print(table.getArray());\n }\n\n // prints:\n // 0 \"Lion\" \"Mamal\"\n // 1 \"Snake\" \"Reptile\"\n </code></div>"], 12607 "class": "p5.Table", 12608 "module": "IO", 12609 "submodule": "Table" 12610 }, { 12611 "file": "src/io/p5.Table.js", 12612 "line": 879, 12613 "description": "<p>
12613Use <a href=\"#/p5/removeColumn\">removeColumn()</a> to remove an existing column from a Table\nobject. The column to be removed may be identified by either\nits title (a String) or its index value (an int).\nremoveColumn(0) would remove the first column, removeColumn(1)\nwould remove the second column, and so on.</p>\n", 12614 "itemtype": "method", 12615 "name": "removeColumn", 12616 "params": [{ 12617 "name": "column", 12618 "description": "<p>columnName (string) or ID (number)</p>\n", 12619 "type": "String|Integer" 12620 }], 12621 "example": ["\n <div class=\"norender\">\n <code>\n // Given the CSV file \"mammals.csv\"\n // in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n table.removeColumn('id');\n print(table.getColumnCount());\n }\n </code>\n </div>"], 12622 "alt": "no image displayed", 12623 "class": "p5.Table", 12624 "module": "IO", 12625 "submodule": "Table" 12626 }, { 12627 "file": "src/io/p5.Table.js", 12628 "line": 944, 12629 "description": "<p>Stores a value in the Table's specified row and column.\nThe row is specified by its ID, while the column may be specified\nby either its ID or title.</p>\n", 12630 "itemtype": "method", 12631 "name": "set", 12632 "params": [{ 12633 "name": "row", 12634 "description": "<p>row ID</p>\n", 12635 "type": "Integer" 12636 }, { 12637 "name": "column", 12638 "description": "<p>column ID (Number)\n or title (String)</p>\n", 12639 "type": "String|Integer" 12640 }, { 12641 "name": "value", 12642 "description": "<p>value to assign</p>\n", 12643 "type": "String|Number" 12644 }], 12645 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n table.set(0, 'species', 'Canis Lupus');\n table.set(0, 'name', 'Wolf');\n\n //print the results\n for (let r = 0; r < table.getRowCount(); r++)\n for (let c = 0; c < table.getColumnCount(); c++)\n print(table.getString(r, c));\n}\n</code>\n</div>"], 12646 "alt": "no image displayed", 12647 "class": "p5.Table", 12648 "module": "IO", 12649 "submodule": "Table" 12650 }, { 12651 "file": "src/io/p5.Table.js", 12652 "line": 994, 12653 "description": "<p>Stores a Float value in the Table's specified row and column.\nThe row is specified by its ID, while the column may be specified\nby either its ID or title.</p>\n", 12654 "itemtype": "method", 12655 "name": "setNum", 12656 "params": [{ 12657 "name": "row", 12658 "description": "<p>row ID</p>\n", 12659 "type": "Integer" 12660 }, { 12661 "name": "column", 12662 "description": "<p>column ID (Number)\n or title (String)</p>\n", 12663 "type": "String|Integer" 12664 }, { 12665 "name": "value", 12666 "description": "<p>value to assign</p>\n", 12667 "type": "Number" 12668 }], 12669 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n table.setNum(1, 'id', 1);\n\n print(table.getColumn(0));\n //[\"0\", 1, \"2\"]\n}\n</code>\n</div>"], 12670 "alt": "no image displayed", 12671 "class": "p5.Table", 12672 "module": "IO", 12673 "submodule": "Table" 12674 }, { 12675 "file": "src/io/p5.Table.js", 12676 "line": 1040, 12677 "description": "<p>Stores a String value in the Table's specified row and column.\nThe row is specified by its ID, while the column may be specified\nby either its ID or title.</p>\n", 12678 "itemtype": "method", 12679 "name": "setString", 12680 "params": [{ 12681 "name": "row", 12682 "description": "<p>row ID</p>\n", 12683 "type": "Integer" 12684 }, { 12685 "name": "column", 12686 "description": "<p>column ID (Number)\n or title (String)</p>\n", 12687 "type": "String|Integer" 12688 }, { 12689 "name": "value", 12690 "description": "<p>value to assign</p>\n", 12691 "type": "String" 12692 }], 12693 "example": ["\n<div class=\"norender\"><code>\n// Given the CSV file \"mammals.csv\" in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n //add a row\n let newRow = table.addRow();\n newRow.setString('id', table.getRowCount() - 1);\n newRow.setString('species', 'Canis Lupus');\n newRow.setString('name', 'Wolf');\n\n print(table.getArray());\n}\n</code></div>"], 12694 "alt": "no image displayed", 12695 "class": "p5.Table", 12696 "module": "IO", 12697 "submodule": "Table" 12698 }, { 12699 "file": "src/io/p5.Table.js", 12700 "line": 1085,
12701 "description": "<p>Retrieves a value from the Table's specified row and column.\nThe row is specified by its ID, while the column may be specified by\neither its ID or title.</p>\n", 12702 "itemtype": "method", 12703 "name": "get", 12704 "params": [{ 12705 "name": "row", 12706 "description": "<p>row ID</p>\n", 12707 "type": "Integer" 12708 }, { 12709 "name": "column", 12710 "description": "<p>columnName (string) or\n ID (number)</p>\n", 12711 "type": "String|Integer" 12712 }], 12713 "return": { 12714 "description": "", 12715 "type": "String|Number" 12716 }, 12717 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n print(table.get(0, 1));\n //Capra hircus\n print(table.get(0, 'species'));\n //Capra hircus\n}\n</code>\n</div>"], 12718 "alt": "no image displayed", 12719 "class": "p5.Table", 12720 "module": "IO", 12721 "submodule": "Table" 12722 }, { 12723 "file": "src/io/p5.Table.js", 12724 "line": 1132, 12725 "description": "<p>Retrieves a Float value from the Table's specified row and column.\nThe row is specified by its ID, while the column may be specified by\neither its ID or title.</p>\n", 12726 "itemtype": "method", 12727 "name": "getNum", 12728 "params": [{ 12729 "name": "row", 12730 "description": "<p>row ID</p>\n", 12731 "type": "Integer" 12732 }, { 12733 "name": "column", 12734 "description": "<p>columnName (string) or\n ID (number)</p>\n", 12735 "type": "String|Integer" 12736 }], 12737 "return": { 12738 "description": "", 12739 "type": "Number" 12740 }, 12741 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n print(table.getNum(1, 0) + 100);\n //id 1 + 100 = 101\n}\n</code>\n</div>"], 12742 "alt": "no image displayed", 12743 "class": "p5.Table", 12744 "module": "IO", 12745 "submodule": "Table" 12746 }, { 12747 "file": "src/io/p5.Table.js", 12748 "line": 1177, 12749 "description": "<p>Retrieves a String value from the Table's specified row and column.\nThe row is specified by its ID, while the column may be specified by\neither its ID or title.</p>\n", 12750 "itemtype": "method", 12751 "name": "getString", 12752 "params": [{ 12753 "name": "row", 12754 "description": "<p>row ID</p>\n", 12755 "type": "Integer" 12756 }, { 12757 "name": "column", 12758 "description": "<p>columnName (string) or\n ID (number)</p>\n", 12759 "type": "String|Integer" 12760 }], 12761 "return": { 12762 "description": "", 12763 "type": "String" 12764 }, 12765 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n // table is comma separated value \"CSV\"\n // and has specifiying header for column labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n print(table.getString(0, 0)); // 0\n print(table.getString(0, 1)); // Capra hircus\n print(table.getString(0, 2)); // Goat\n print(table.getString(1, 0)); // 1\n print(table.getString(1, 1)); // Panthera pardus\n print(table.getString(1, 2)); // Leopard\n print(table.getString(2, 0)); // 2\n print(table.getString(2, 1)); // Equus zebra\n print(table.getString(2, 2)); // Zebra\n}\n</code>\n</div>"], 12766 "alt": "no image displayed", 12767 "class": "p5.Table", 12768 "module": "IO", 12769 "submodule": "Table" 12770 }, { 12771 "file": "src/io/p5.Table.js", 12772 "line": 1230, 12773 "description": "<p>Retrieves all table data and returns as an object. If a column name is\npassed in, each row object will be stored with that attribute as its\ntitle.</p>\n", 12774 "itemtype": "method", 12775 "name": "getObject", 12776 "params": [{ 12777 "name": "headerColumn", 12778 "description": "<p>Name of the column which should be used to\n title each row object (optional)</p>\n", 12779 "type": "String", 12780 "optional": true 12781 }], 12782 "return": { 12783 "description": "", 12784 "type": "Object" 12785 }, 12786 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder:\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leopard\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n let tableObject = table.getObject();\n\n print(tableObject);\n //outputs an object\n}\n</code>\n</div>"], 12787 "alt": "no image displayed", 12788 "class": "p5.Table", 12789 "module": "IO", 12790 "submodule": "Table" 12791 }, { 12792 "file": "src/io/p5.Table.js", 12793 "line": 1296, 12794 "description": "<p>Retrieves all table data and returns it as a multidimensional array.</p>\n", 12795 "itemtype": "method", 12796 "name": "getArray", 12797 "return": { 12798 "description": "", 12799 "type": "Array" 12800 }, 12801 "example": ["\n<div class=\"norender\">\n<code>\n// Given the CSV file \"mammals.csv\"\n// in the project's \"assets\" folder\n//\n// id,species,name\n// 0,Capra hircus,Goat\n// 1,Panthera pardus,Leoperd\n// 2,Equus zebra,Zebra\n\nlet table;\n\nfunction preload() {\n // table is comma separated value \"CSV\"\n // and has specifiying header for column labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n}\n\nfunction setup() {\n let tableArray = table.getArray();\n for (let i = 0; i < tableArray.length;
12801 i++) {\n print(tableArray[i]);\n }\n}\n</code>\n</div>"], 12802 "alt": "no image displayed", 12803 "class": "p5.Table", 12804 "module": "IO", 12805 "submodule": "Table" 12806 }, { 12807 "file": "src/io/p5.TableRow.js", 12808 "line": 42, 12809 "description": "<p>Stores a value in the TableRow's specified column.\nThe column may be specified by either its ID or title.</p>\n", 12810 "itemtype": "method", 12811 "name": "set", 12812 "params": [{ 12813 "name": "column", 12814 "description": "<p>Column ID (Number)\n or Title (String)</p>\n", 12815 "type": "String|Integer" 12816 }, { 12817 "name": "value", 12818 "description": "<p>The value to be stored</p>\n", 12819 "type": "String|Number" 12820 }], 12821 "example": ["\n <div class=\"norender\"><code>\n // Given the CSV file \"mammals.csv\" in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n let rows = table.getRows();\n for (let r = 0; r < rows.length; r++) {\n rows[r].set('name', 'Unicorn');\n }\n\n //print the results\n print(table.getArray());\n }\n </code></div>"], 12822 "alt": "no image displayed", 12823 "class": "p5.TableRow", 12824 "module": "IO", 12825 "submodule": "Table" 12826 }, { 12827 "file": "src/io/p5.TableRow.js", 12828 "line": 106, 12829 "description": "<p>Stores a Float value in the TableRow's specified column.\nThe column may be specified by either its ID or title.</p>\n", 12830 "itemtype": "method", 12831 "name": "setNum", 12832 "params": [{ 12833 "name": "column", 12834 "description": "<p>Column ID (Number)\n or Title (String)</p>\n", 12835 "type": "String|Integer" 12836 }, { 12837 "name": "value", 12838 "description": "<p>The value to be stored\n as a Float</p>\n", 12839 "type": "Number|String" 12840 }], 12841 "example": ["\n <div class=\"norender\"><code>\n // Given the CSV file \"mammals.csv\" in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n let rows = table.getRows();\n for (let r = 0; r < rows.length; r++) {\n rows[r].setNum('id', r + 10);\n }\n\n print(table.getArray());\n }\n </code></div>"], 12842 "alt": "no image displayed", 12843 "class": "p5.TableRow", 12844 "module": "IO", 12845 "submodule": "Table" 12846 }, { 12847 "file": "src/io/p5.TableRow.js", 12848 "line": 150, 12849 "description": "<p>Stores a String value in the TableRow's specified column.\nThe column may be specified by either its ID or title.</p>\n", 12850 "itemtype": "method", 12851 "name": "setString", 12852 "params": [{ 12853 "name": "column", 12854 "description": "<p>Column ID (Number)\n or Title (String)</p>\n", 12855 "type": "String|Integer" 12856 }, { 12857 "name": "value", 12858 "description": "<p>The value to be stored\n as a String</p>\n", 12859 "type": "String|Number|Boolean|Object" 12860 }], 12861 "example": ["\n <div class=\"norender\"><code>\n // Given the CSV file \"mammals.csv\" in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n let rows = table.getRows();\n for (let r = 0; r < rows.length; r++) {\n let name = rows[r].getString('name');\n rows[r].setString('name', 'A ' + name + ' named George');\n }\n\n print(table.getArray());\n }\n </code></div>"], 12862 "alt": "no image displayed", 12863 "class": "p5.TableRow", 12864 "module": "IO", 12865 "submodule": "Table" 12866 }, { 12867 "file": "src/io/p5.TableRow.js", 12868 "line": 195, 12869 "description": "<p>Retrieves a value from the TableRow's specified column.\nThe column may be specified by either its ID or title.</p>\n", 12870 "itemtype": "method", 12871 "name": "get", 12872 "params": [{ 12873 "name": "column", 12874 "description": "<p>columnName (string) or\n ID (number)</p>\n", 12875 "type": "String|Integer" 12876 }], 12877 "return": { 12878 "description": "", 12879 "type": "String|Number" 12880 }, 12881 "example": ["\n <div class=\"norender\"><code>\n // Given the CSV file \"mammals.csv\" in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n let names = [];\n let rows = table.getRows();\n for (let r = 0; r < rows.length; r++) {\n names.push(rows[r].get('name'));\n }\n\n print(names);\n }\n </code></div>"], 12882 "alt": "no image displayed", 12883 "class": "p5.TableRow", 12884 "module": "IO", 12885 "submodule": "Table" 12886 }, { 12887 "file": "src/io/p5.TableRow.js", 12888 "line": 243, 12889 "description": "<p>Retrieves a Float value from the TableRow's specified\ncolumn. The column may be specified by either its ID or\ntitle.</p>\n", 12890 "itemtype": "method", 12891 "name": "getNum", 12892 "params": [{ 12893 "name": "column", 12894 "description": "<p>columnName (string) or\n ID (number)</p>\n", 12895 "type": "String|Integer" 12896 }], 12897 "return": { 12898 "description": "Float Floating point number", 12899 "type": "Number" 12900 }, 12901 "example": ["\n <div class=\"norender\"><code>\n // Given the CSV file \"mammals.csv\" in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n let rows = table.getRows();\n let minId = Infinity;\n let maxId = -Infinity;\n for (let r = 0; r < rows.length; r++) {\n let id = rows[r].getNum('id');\n minId = min(minId, id);\n maxId = min(maxId, id);\n }\n print('minimum id = ' + minId + ', maximum id = ' + maxId);\n }\n </code></div>"], 12902 "alt": "no image displayed", 12903 "class": "p5.TableRow", 12904 "module": "IO", 12905 "submodule": "Table" 12906 }, { 12907 "file": "src/io/p5.TableRow.js", 12908 "line": 299, 12909 "description": "<p>Retrieves an String value from the TableRow's specified\ncolumn. The column may be specified by either its ID or\ntitle.</p>\n", 12910 "itemtype": "method", 12911 "name": "getString", 12912 "params": [{ 12913 "name": "column", 12914 "description": "<p>columnName (string) or\n ID (number)</p>\n", 12915 "type": "String|Integer" 12916 }], 12917 "return": { 12918 "description": "String", 12919 "type": "String" 12920 }, 12921 "example": ["\n <div class=\"norender\"><code>\n // Given the CSV file \"mammals.csv\" in the project's \"assets\" folder:\n //\n // id,species,name\n // 0,Capra hircus,Goat\n // 1,Panthera pardus,Leopard\n // 2,Equus zebra,Zebra\n\n let table;\n\n function preload() {\n //my table is comma separated value \"csv\"\n //and has a header specifying the columns labels\n table = loadTable('assets/mammals.csv', 'csv', 'header');\n }\n\n function setup() {\n let rows = table.getRows();\n let longest = '';\n for (let r = 0; r < rows.length; r++) {\n let species = rows[r].getString('species');\n if (longest.length < species.length) {\n longest = species;\n }\n }\n\n print('longest: ' + longest);\n }\n </code></div>"], 12922 "alt": "no image displayed", 12923 "class": "p5.TableRow", 12924 "module": "IO", 12925 "submodule": "Table" 12926 }, { 12927 "file": "src/io/p5.XML.js", 12928 "line": 65, 12929 "description": "<p>Gets a copy of the element's parent. Returns the parent as another\n<a href=\"#/p5.XML\">p5.XML</a> object.</p>\n", 12930 "itemtype": "method", 12931 "name": "getParent", 12932 "return": { 12933 "description": "element parent", 12934 "type": "p5.XML" 12935 }, 12936 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let children = xml.getChildren('animal');\n let parent = children[1].getParent();\n print(parent.getName());\n}\n\n// Sketch prints:\n// mammals\n</code></div>"], 12937 "class": "p5.XML", 12938 "module": "IO", 12939 "submodule": "XML" 12940 }, { 12941 "file": "src/io/p5.XML.js", 12942 "line": 103, 12943 "description": "<p>Gets the element's full name, which is returned as a String.</p>\n", 12944 "itemtype": "method", 12945 "name": "getName", 12946 "return": { 12947 "description": "the name of the node", 12948 "type": "String" 12949 }, 12950 "example": ["<animal\n <div class='norender'><code>\n // The following short XML file called \"mammals.xml\" is parsed\n // in the code below.\n //\n // <?xml version=\"1.0\"?>\n // <mammals>\n // <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n // <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n // <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n // </mammals>\n\n let xml;\n\n function preload() {\n xml = loadXML('assets/mammals.xml');\n }\n\n function setup() {\n print(xml.getName());\n }\n\n // Sketch prints:\n // mammals\n </code></div>"], 12951 "class": "p5.XML", 12952 "module": "IO", 12953 "submodule": "XML" 12954 }, { 12955 "file": "src/io/p5.XML.js", 12956 "line": 138, 12957 "description": "<p>Sets the element's name, which is specified as a String.</p>\n", 12958 "itemtype": "method", 12959 "name": "setName", 12960 "params": [{ 12961 "name": "the", 12962 "description": "<p>new name of the node</p>\n", 12963 "type": "String" 12964 }], 12965 "example": ["<animal\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n print(xml.getName());\n xml.setName('fish');\n print(xml.getName());\n}\n\n// Sketch prints:\n// mammals\n// fish\n</code></div>"], 12966 "class": "p5.XML", 12967 "module": "IO", 12968 "submodule": "XML" 12969 }, { 12970 "file": "src/io/p5.XML.js", 12971 "line": 184, 12972 "description": "<p>Checks whether or not the element has any children, and returns the result\nas a boolean.</p>\n", 12973 "itemtype": "method", 12974 "name": "hasChildren", 12975 "return": { 12976 "description": "", 12977 "type": "Boolean" 12978 }, 12979 "example": ["<animal\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n print(xml.hasChildren());\n}\n\n// Sketch prints:\n// true\n</code></div>"], 12980 "class": "p5.XML", 12981 "module": "IO", 12982 "submodule": "XML" 12983 }, { 12984 "file": "src/io/p5.XML.js", 12985 "line": 220, 12986 "description": "<p>Get the names of all of the element's children, and returns the names as an\narray of Strings. This is the same as looping through and calling <a href=\"#/p5.XML/getName\">getName()</a>\non each child element individually.</p>\n", 12987 "itemtype": "method", 12988 "name": "listChildren", 12989 "return": { 12990 "description": "names of the children of the element", 12991 "type": "String[]" 12992 }, 12993 "example": ["<animal\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n print(xml.listChildren());\n}\n\n// Sketch prints:\n// [\"animal\", \"animal\", \"animal\"]\n</code></div>"], 12994 "class": "p5.XML", 12995 "module": "IO", 12996 "submodule": "XML" 12997 }, { 12998 "file": "src/io/p5.XML.js", 12999 "line": 261, 13000 "description": "<p>Returns all of the element's children as an array of <a href=\"#/p5.XML\">p5.XML</a> objects. When\nthe name parameter is specified, then it will return all children that match\nthat name.</p>\n", 13001 "itemtype": "method", 13002 "name": "getChildren", 13003 "params": [{ 13004 "name": "name", 13005 "description": "<p>element name</p>\n", 13006 "type": "String", 13007 "optional": true 13008 }], 13009 "return": { 13010 "description": "children of the element", 13011 "type": "p5.XML[]" 13012 }, 13013 "example": ["<animal\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let animals = xml.getChildren('animal');\n\n for (let i = 0; i < animals.length;
13013 i++) {\n print(animals[i].getContent());\n }\n}\n\n// Sketch prints:\n// \"Goat\"\n// \"Leopard\"\n// \"Zebra\"\n</code></div>"], 13014 "class": "p5.XML", 13015 "module": "IO", 13016 "submodule": "XML" 13017 }, { 13018 "file": "src/io/p5.XML.js", 13019 "line": 317, 13020 "description": "<p>Returns the first of the element's children that matches the name parameter\nor the child of the given index.It returns undefined if no matching\nchild is found.</p>\n", 13021 "itemtype": "method", 13022 "name": "getChild", 13023 "params": [{ 13024 "name": "name", 13025 "description": "<p>element name or index</p>\n", 13026 "type": "String|Integer" 13027 }], 13028 "return": { 13029 "description": "", 13030 "type": "p5.XML" 13031 }, 13032 "example": ["<animal\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let firstChild = xml.getChild('animal');\n print(firstChild.getContent());\n}\n\n// Sketch prints:\n// \"Goat\"\n</code></div>\n<div class='norender'><code>\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let secondChild = xml.getChild(1);\n print(secondChild.getContent());\n}\n\n// Sketch prints:\n// \"Leopard\"\n</code></div>"], 13033 "class": "p5.XML", 13034 "module": "IO", 13035 "submodule": "XML" 13036 }, { 13037 "file": "src/io/p5.XML.js", 13038 "line": 378, 13039 "description": "<p>Appends a new child to the element. The child can be specified with\neither a String, which will be used as the new tag's name, or as a\nreference to an existing <a href=\"#/p5.XML\">p5.XML</a> object.\nA reference to the newly created child is returned as an <a href=\"#/p5.XML\">p5.XML</a> object.</p>\n", 13040 "itemtype": "method", 13041 "name": "addChild", 13042 "params": [{ 13043 "name": "node", 13044 "description": "<p>a <a href=\"#/p5.XML\">p5.XML</a> Object which will be the child to be added</p>\n", 13045 "type": "p5.XML" 13046 }], 13047 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let child = new p5.XML();\n child.setName('animal');\n child.setAttribute('id', '3');\n child.setAttribute('species', 'Ornithorhynchus anatinus');\n child.setContent('Platypus');\n xml.addChild(child);\n\n let animals = xml.getChildren('animal');\n print(animals[animals.length - 1].getContent());\n}\n\n// Sketch prints:\n// \"Goat\"\n// \"Leopard\"\n// \"Zebra\"\n</code></div>"], 13048 "class": "p5.XML", 13049 "module": "IO", 13050 "submodule": "XML" 13051 }, { 13052 "file": "src/io/p5.XML.js", 13053 "line": 430, 13054 "description": "<p>Removes the element specified by name or index.</p>\n", 13055 "itemtype": "method", 13056 "name": "removeChild", 13057 "params": [{ 13058 "name": "name", 13059 "description": "<p>element name or index</p>\n", 13060 "type": "String|Integer" 13061 }], 13062 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n xml.removeChild('animal');\n let children = xml.getChildren();\n for (let i = 0; i < children.length;
13062 i++) {\n print(children[i].getContent());\n }\n}\n\n// Sketch prints:\n// \"Leopard\"\n// \"Zebra\"\n</code></div>\n<div class='norender'><code>\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n xml.removeChild(1);\n let children = xml.getChildren();\n for (let i = 0; i < children.length; i++) {\n print(children[i].getContent());\n }\n}\n\n// Sketch prints:\n// \"Goat\"\n// \"Zebra\"\n</code></div>"], 13063 "class": "p5.XML", 13064 "module": "IO", 13065 "submodule": "XML" 13066 }, { 13067 "file": "src/io/p5.XML.js", 13068 "line": 502, 13069 "description": "<p>Counts the specified element's number of attributes, returned as an Number.</p>\n", 13070 "itemtype": "method", 13071 "name": "getAttributeCount", 13072 "return": { 13073 "description": "", 13074 "type": "Integer" 13075 }, 13076 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let firstChild = xml.getChild('animal');\n print(firstChild.getAttributeCount());\n}\n\n// Sketch prints:\n// 2\n</code></div>"], 13077 "class": "p5.XML", 13078 "module": "IO", 13079 "submodule": "XML" 13080 }, { 13081 "file": "src/io/p5.XML.js", 13082 "line": 538, 13083 "description": "<p>Gets all of the specified element's attributes, and returns them as an\narray of Strings.</p>\n", 13084 "itemtype": "method", 13085 "name": "listAttributes", 13086 "return": { 13087 "description": "an array of strings containing the names of attributes", 13088 "type": "String[]" 13089 }, 13090 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let firstChild = xml.getChild('animal');\n print(firstChild.listAttributes());\n}\n\n// Sketch prints:\n// [\"id\", \"species\"]\n</code></div>"], 13091 "class": "p5.XML", 13092 "module": "IO", 13093 "submodule": "XML" 13094 }, { 13095 "file": "src/io/p5.XML.js", 13096 "line": 580, 13097 "description": "<p>Checks whether or not an element has the specified attribute.</p>\n", 13098 "itemtype": "method", 13099 "name": "hasAttribute", 13100 "params": [{ 13101 "name": "the", 13102 "description": "<p>attribute to be checked</p>\n", 13103 "type": "String" 13104 }], 13105 "return": { 13106 "description": "true if attribute found else false", 13107 "type": "Boolean" 13108 }, 13109 "example": ["\n <div class='norender'><code>\n // The following short XML file called \"mammals.xml\" is parsed\n // in the code below.\n //\n // <?xml version=\"1.0\"?>\n // <mammals>\n // <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n // <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n // <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n // </mammals>\n\n let xml;\n\n function preload() {\n xml = loadXML('assets/mammals.xml');\n }\n\n function setup() {\n let firstChild = xml.getChild('animal');\n print(firstChild.hasAttribute('species'));\n print(firstChild.hasAttribute('color'));\n }\n\n // Sketch prints:\n // true\n // false\n </code></div>"], 13110 "class": "p5.XML", 13111 "module": "IO", 13112 "submodule": "XML" 13113 }, { 13114 "file": "src/io/p5.XML.js", 13115 "line": 624, 13116 "description": "<p>Returns an attribute value of the element as an Number. If the defaultValue\nparameter is specified and the attribute doesn't exist, then defaultValue\nis returned. If no defaultValue is specified and the attribute doesn't\nexist, the value 0 is returned.</p>\n", 13117 "itemtype": "method", 13118 "name": "getNum", 13119 "params": [{ 13120 "name": "name", 13121 "description": "<p>the non-null full name of the attribute</p>\n", 13122 "type": "String" 13123 }, { 13124 "name": "defaultValue", 13125 "description": "<p>the default value of the attribute</p>\n", 13126 "type": "Number", 13127 "optional": true 13128 }], 13129 "return": { 13130 "description": "", 13131 "type": "Number" 13132 }, 13133 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let firstChild = xml.getChild('animal');\n print(firstChild.getNum('id'));\n}\n\n// Sketch prints:\n// 0\n</code></div>"], 13134 "class": "p5.XML", 13135 "module": "IO", 13136 "submodule": "XML" 13137 }, { 13138 "file": "src/io/p5.XML.js", 13139 "line": 670, 13140 "description": "<p>Returns an attribute value of the element as an String. If the defaultValue\nparameter is specified and the attribute doesn't exist, then defaultValue\nis returned. If no defaultValue is specified and the attribute doesn't\nexist, null is returned.</p>\n", 13141 "itemtype": "method", 13142 "name": "getString", 13143 "params": [{ 13144 "name": "name", 13145 "description": "<p>the non-null full name of the attribute</p>\n", 13146 "type": "String" 13147 }, { 13148 "name": "defaultValue", 13149 "description": "<p>the default value of the attribute</p>\n", 13150 "type": "Number", 13151 "optional": true 13152 }], 13153 "return": { 13154 "description": "", 13155 "type": "String" 13156 }, 13157 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let firstChild = xml.getChild('animal');
13157\n print(firstChild.getString('species'));\n}\n\n// Sketch prints:\n// \"Capra hircus\"\n</code></div>"], 13158 "class": "p5.XML", 13159 "module": "IO", 13160 "submodule": "XML" 13161 }, { 13162 "file": "src/io/p5.XML.js", 13163 "line": 716, 13164 "description": "<p>Sets the content of an element's attribute. The first parameter specifies\nthe attribute name, while the second specifies the new content.</p>\n", 13165 "itemtype": "method", 13166 "name": "setAttribute", 13167 "params": [{ 13168 "name": "name", 13169 "description": "<p>the full name of the attribute</p>\n", 13170 "type": "String" 13171 }, { 13172 "name": "value", 13173 "description": "<p>the value of the attribute</p>\n", 13174 "type": "Number|String|Boolean" 13175 }], 13176 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let firstChild = xml.getChild('animal');\n print(firstChild.getString('species'));\n firstChild.setAttribute('species', 'Jamides zebra');\n print(firstChild.getString('species'));\n}\n\n// Sketch prints:\n// \"Capra hircus\"\n// \"Jamides zebra\"\n</code></div>"], 13177 "class": "p5.XML", 13178 "module": "IO", 13179 "submodule": "XML" 13180 }, { 13181 "file": "src/io/p5.XML.js", 13182 "line": 757, 13183 "description": "<p>Returns the content of an element. If there is no such content,\ndefaultValue is returned if specified, otherwise null is returned.</p>\n", 13184 "itemtype": "method", 13185 "name": "getContent", 13186 "params": [{ 13187 "name": "defaultValue", 13188 "description": "<p>value returned if no content is found</p>\n", 13189 "type": "String", 13190 "optional": true 13191 }], 13192 "return": { 13193 "description": "", 13194 "type": "String" 13195 }, 13196 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let firstChild = xml.getChild('animal');\n print(firstChild.getContent());\n}\n\n// Sketch prints:\n// \"Goat\"\n</code></div>"], 13197 "class": "p5.XML", 13198 "module": "IO", 13199 "submodule": "XML" 13200 }, { 13201 "file": "src/io/p5.XML.js", 13202 "line": 798, 13203 "description": "<p>Sets the element's content.</p>\n", 13204 "itemtype": "method", 13205 "name": "setContent", 13206 "params": [{ 13207 "name": "text", 13208 "description": "<p>the new content</p>\n", 13209 "type": "String" 13210 }], 13211 "example": ["\n<div class='norender'><code>\n// The following short XML file called \"mammals.xml\" is parsed\n// in the code below.\n//\n// <?xml version=\"1.0\"?>\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n let firstChild = xml.getChild('animal');\n print(firstChild.getContent());\n firstChild.setContent('Mountain Goat');\n print(firstChild.getContent());\n}\n\n// Sketch prints:\n// \"Goat\"\n// \"Mountain Goat\"\n</code></div>"], 13212 "class": "p5.XML", 13213 "module": "IO", 13214 "submodule": "XML" 13215 }, { 13216 "file": "src/io/p5.XML.js", 13217 "line": 839, 13218 "description": "<p>Serializes the element into a string. This function is useful for preparing\nthe content to be sent over a http request or saved to file.</p>\n", 13219 "itemtype": "method", 13220 "name": "serialize", 13221 "return": { 13222 "description": "Serialized string of the element", 13223 "type": "String" 13224 }, 13225 "example": ["\n<div class='norender'><code>\nlet xml;\n\nfunction preload() {\n xml = loadXML('assets/mammals.xml');\n}\n\nfunction setup() {\n print(xml.serialize());\n}\n\n// Sketch prints:\n// <mammals>\n// <animal id=\"0\" species=\"Capra hircus\">Goat</animal>\n// <animal id=\"1\" species=\"Panthera pardus\">Leopard</animal>\n// <animal id=\"2\" species=\"Equus zebra\">Zebra</animal>\n// </mammals>\n</code></div>"], 13226 "class": "p5.XML", 13227 "module": "IO", 13228 "submodule": "XML" 13229 }, { 13230 "file": "src/math/calculation.js", 13231 "line": 12, 13232 "description": "<p>Calculates the absolute value (magnitude) of a number. Maps to Math.abs().\nThe absolute value of a number is always positive.</p>\n", 13233 "itemtype": "method", 13234 "name": "abs", 13235 "params": [{ 13236 "name": "n", 13237 "description": "<p>number to compute</p>\n", 13238 "type": "Number" 13239 }], 13240 "return": { 13241 "description": "absolute value of given number", 13242 "type": "Number" 13243 }, 13244 "example": ["\n<div class = \"norender\"><code>\nfunction setup() {\n let x = -3;\n let y = abs(x);\n\n print(x); // -3\n print(y); // 3\n}\n</code></div>"], 13245 "alt": "no image displayed", 13246 "class": "p5", 13247 "module": "Math", 13248 "submodule": "Calculation" 13249 }, { 13250 "file": "src/math/calculation.js", 13251 "line": 36, 13252 "description": "<p>Calculates the closest int value that is greater than or equal to the\nvalue of the parameter. Maps to Math.ceil(). For example, ceil(9.03)\nreturns the value 10.</p>\n", 13253 "itemtype": "method", 13254 "name": "ceil", 13255 "params": [{ 13256 "name": "n", 13257 "description": "<p>number to round up</p>\n", 13258 "type": "Number" 13259 }], 13260 "return": { 13261 "description": "rounded up number", 13262 "type": "Integer" 13263 }, 13264 "example": ["\n<div><code>\nfunction draw() {\n background(200);\n // map, mouseX between 0 and 5.\n let ax = map(mouseX, 0, 100, 0, 5);\n let ay = 66;\n\n //Get the ceiling of the mapped number.\n let bx = ceil(map(mouseX, 0, 100, 0, 5));\n let by = 33;\n\n // Multiply the mapped numbers by 20 to more easily\n // see the changes.\n stroke(0);\n fill(0);\n line(0, ay, ax * 20, ay);\n line(0, by, bx * 20, by);\n\n // Reformat the float returned by map and draw it.\n noStroke();\n text(nfc(ax, 2), ax, ay - 5);\n text(nfc(bx, 1), bx, by - 5);\n}\n</code></div>"], 13265 "alt": "2 horizontal lines & number sets. increase with mouse x. bottom to 2 decimals", 13266 "class": "p5", 13267 "module": "Math", 13268 "submodule": "Calculation" 13269 }, { 13270 "file": "src/math/calculation.js", 13271 "line": 76, 13272 "description": "<p>Constrains a value between a minimum and maximum value.</p>\n", 13273 "itemtype": "method", 13274 "name": "constrain", 13275 "params": [{ 13276 "name": "n", 13277 "description": "<p>number to constrain</p>\n", 13278 "type": "Number" 13279 }, { 13280 "name": "low", 13281 "description": "<p>minimum limit</p>\n", 13282 "type": "Number" 13283 }, { 13284 "name": "high", 13285 "description": "<p>maximum limit</p>\n", 13286 "type": "Number" 13287 }], 13288 "return": { 13289 "description": "constrained number", 13290 "type": "Number" 13291 }, 13292 "example": ["\n<div><code>\nfunction draw() {\n background(200);\n\n let leftWall = 25;\n let rightWall = 75;\n\n // xm is just the mouseX, while\n // xc is the mouseX, but constrained\n // between the leftWall and rightWall!\n let xm = mouseX;\n let xc = constrain(mouseX, leftWall, rightWall);\n\n // Draw the walls.\n stroke(150);\n line(leftWall, 0, leftWall, height);\n line(rightWall, 0, rightWall, height);\n\n // Draw xm and xc as circles.\n noStroke();\n fill(150);\n ellipse(xm, 33, 9, 9); // Not Constrained\n fill(0);\n ellipse(xc, 66, 9, 9); // Constrained\n}\n</code></div>"], 13293 "alt": "2 vertical lines. 2 ellipses move with mouse X 1 does not move passed lines", 13294 "class": "p5", 13295 "module": "Math", 13296 "submodule": "Calculation" 13297 }, { 13298 "file": "src/math/calculation.js", 13299 "line": 121, 13300 "description": "<p>Calculates the distance between two points.</p>\n", 13301 "itemtype": "method", 13302 "name": "dist", 13303 "return": { 13304 "description": "distance between the two points", 13305 "type": "Number" 13306 }, 13307 "example": ["\n<div><code>\n// Move your mouse inside the canvas to see the\n// change in distance between two points!\nfunction draw() {\n background(200);\n fill(0);\n\n let x1 = 10;\n let y1 = 90;\n let x2 = mouseX;\n let y2 = mouseY;\n\n line(x1, y1, x2, y2);\n ellipse(x1, y1, 7, 7);\n ellipse(x2, y2, 7, 7);\n\n // d is the length of the line\n // the distance from point 1 to point 2.\n let d = int(dist(x1, y1, x2, y2));\n\n // Let's write d along the line we are drawing!\n push();\n translate((x1 + x2) / 2, (y1 + y2) / 2);\n rotate(atan2(y2 - y1, x2 - x1));
13307\n text(nfc(d, 1), 0, -5);\n pop();\n // Fancy!\n}\n</code></div>"], 13308 "alt": "2 ellipses joined by line. 1 ellipse moves with mouse X&Y. Distance displayed.", 13309 "class": "p5", 13310 "module": "Math", 13311 "submodule": "Calculation", 13312 "overloads": [{ 13313 "line": 121, 13314 "params": [{ 13315 "name": "x1", 13316 "description": "<p>x-coordinate of the first point</p>\n", 13317 "type": "Number" 13318 }, { 13319 "name": "y1", 13320 "description": "<p>y-coordinate of the first point</p>\n", 13321 "type": "Number" 13322 }, { 13323 "name": "x2", 13324 "description": "<p>x-coordinate of the second point</p>\n", 13325 "type": "Number" 13326 }, { 13327 "name": "y2", 13328 "description": "<p>y-coordinate of the second point</p>\n", 13329 "type": "Number" 13330 }], 13331 "return": { 13332 "description": "distance between the two points", 13333 "type": "Number" 13334 } 13335 }, { 13336 "line": 165, 13337 "params": [{ 13338 "name": "x1", 13339 "description": "", 13340 "type": "Number" 13341 }, { 13342 "name": "y1", 13343 "description": "", 13344 "type": "Number" 13345 }, { 13346 "name": "z1", 13347 "description": "<p>z-coordinate of the first point</p>\n", 13348 "type": "Number" 13349 }, { 13350 "name": "x2", 13351 "description": "", 13352 "type": "Number" 13353 }, { 13354 "name": "y2", 13355 "description": "", 13356 "type": "Number" 13357 }, { 13358 "name": "z2", 13359 "description": "<p>z-coordinate of the second point</p>\n", 13360 "type": "Number" 13361 }], 13362 "return": { 13363 "description": "distance between the two points", 13364 "type": "Number" 13365 } 13366 }] 13367 }, { 13368 "file": "src/math/calculation.js", 13369 "line": 190, 13370 "description": "<p>Returns Euler's number e (2.71828...) raised to the power of the n\nparameter. Maps to Math.exp().</p>\n", 13371 "itemtype": "method", 13372 "name": "exp", 13373 "params": [{ 13374 "name": "n", 13375 "description": "<p>exponent to raise</p>\n", 13376 "type": "Number" 13377 }], 13378 "return": { 13379 "description": "e^n", 13380 "type": "Number" 13381 }, 13382 "example": ["\n<div><code>\nfunction draw() {\n background(200);\n\n // Compute the exp() function with a value between 0 and 2\n let xValue = map(mouseX, 0, width, 0, 2);\n let yValue = exp(xValue);\n\n let y = map(yValue, 0, 8, height, 0);\n\n let legend = 'exp (' + nfc(xValue, 3) + ')\\n= ' + nf(yValue, 1, 4);\n stroke(150);\n line(mouseX, y, mouseX, height);\n fill(0);\n text(legend, 5, 15);\n noStroke();\n ellipse(mouseX, y, 7, 7);\n\n // Draw the exp(x) curve,\n // over the domain of x from 0 to 2\n noFill();\n stroke(0);\n beginShape();\n for (let x = 0; x < width; x++) {\n xValue = map(x, 0, width, 0, 2);\n yValue = exp(xValue);\n y = map(yValue, 0, 8, height, 0);\n vertex(x, y);\n }\n\n endShape();\n line(0, 0, 0, height);\n line(0, height - 1, width, height - 1);\n}\n</code></div>"], 13383 "alt": "ellipse moves along a curve with mouse x. e^n displayed.", 13384 "class": "p5", 13385 "module": "Math", 13386 "submodule": "Calculation" 13387 }, { 13388 "file": "src/math/calculation.js", 13389 "line": 240, 13390 "description": "<p>Calculates the closest int value that is less than or equal to the\nvalue of the parameter. Maps to Math.floor().</p>\n", 13391 "itemtype": "method", 13392 "name": "floor", 13393 "params": [{ 13394 "name": "n", 13395 "description": "<p>number to round down</p>\n", 13396 "type": "Number" 13397 }], 13398 "return": { 13399 "description": "rounded down number", 13400 "type": "Integer" 13401 }, 13402 "example": ["\n<div><code>\nfunction draw() {\n background(200);\n //map, mouseX between 0 and 5.\n let ax = map(mouseX, 0, 100, 0, 5);\n let ay = 66;\n\n //Get the floor of the mapped number.\n let bx = floor(map(mouseX, 0, 100, 0, 5));\n let by = 33;\n\n // Multiply the mapped numbers by 20 to more easily\n // see the changes.\n stroke(0);\n fill(0);\n line(0, ay, ax * 20, ay);\n line(0, by, bx * 20, by);\n\n // Reformat the float returned by map and draw it.\n noStroke();\n text(nfc(ax, 2), ax, ay - 5);\n text(nfc(bx, 1), bx, by - 5);\n}\n</code></div>"], 13403 "alt": "2 horizontal lines & number sets. increase with mouse x. bottom to 2 decimals", 13404 "class": "p5", 13405 "module": "Math", 13406 "submodule": "Calculation" 13407 }, { 13408 "file": "src/math/calculation.js", 13409 "line": 279, 13410 "description": "<p>Calculates a number between two numbers at a specific increment. The amt\nparameter is the amount to interpolate between the two values where 0.0\nequal to the first point, 0.1 is very near the first point, 0.5 is\nhalf-way in between, and 1.0 is equal to the second point. If the\nvalue of amt is more than 1.0 or less than 0.0, the number will be\ncalculated accordingly in the ratio of the two given numbers. The lerp\nfunction is convenient for creating motion along a straight\npath and for drawing dotted lines.</p>\n", 13411 "itemtype": "method", 13412 "name": "lerp", 13413 "params": [{ 13414 "name": "start", 13415 "description": "<p>first value</p>\n", 13416 "type": "Number" 13417 }, { 13418 "name": "stop", 13419 "description": "<p>second value</p>\n", 13420 "type": "Number" 13421 }, { 13422 "name": "amt", 13423 "description": "<p>number</p>\n", 13424 "type": "Number" 13425 }], 13426 "return": { 13427 "description": "lerped value", 13428 "type": "Number" 13429 }, 13430 "example": ["\n<div><code>\nfunction setup() {\n background(200);\n let a = 20;\n let b = 80;\n let c = lerp(a, b, 0.2);\n let d = lerp(a, b, 0.5);\n let e = lerp(a, b, 0.8);\n\n let y = 50;\n\n strokeWeight(5);\n stroke(0); // Draw the original points in black\n point(a, y);\n point(b, y);\n\n stroke(100); // Draw the lerp points in gray\n point(c, y);\n point(d, y);\n point(e, y);\n}\n</code></div>"], 13431 "alt": "5 points horizontally staggered mid-canvas. mid 3 are grey, outer black", 13432 "class": "p5", 13433 "module": "Math", 13434 "submodule": "Calculation" 13435 }, { 13436 "file": "src/math/calculation.js", 13437 "line": 327, 13438 "description": "<p>Calculates the natural logarithm (the base-e logarithm) of a number. This\nfunction expects the n parameter to be a value greater than 0.0. Maps to\nMath.log().</p>\n", 13439 "itemtype": "method", 13440 "name": "log", 13441 "params": [{ 13442 "name": "n", 13443 "description": "<p>number greater than 0</p>\n", 13444 "type": "Number" 13445 }], 13446 "return": { 13447 "description": "natural logarithm of n", 13448 "type": "Number" 13449 }, 13450 "example": ["\n<div><code>\nfunction draw() {\n background(200);\n let maxX = 2.8;\n let maxY = 1.5;\n\n // Compute the natural log of a value between 0 and maxX\n let xValue = map(mouseX, 0, width, 0, maxX);\n let yValue, y;\n if (xValue > 0) {\n // Cannot take the log of a negative number.\n yValue = log(xValue);\n y = map(yValue, -maxY, maxY, height, 0);\n\n // Display the calculation occurring.\n let legend = 'log(' + nf(xValue, 1, 2) + ')\\n= ' + nf(yValue, 1, 3);\n stroke(150);\n line(mouseX, y, mouseX, height);\n fill(0);\n text(legend, 5, 15);\n noStroke();\n ellipse(mouseX, y, 7, 7);\n }\n\n // Draw the log(x) curve,\n // over the domain of x from 0 to maxX\n noFill();\n stroke(0);\n beginShape();\n for (let x = 0; x < width; x++) {\n xValue = map(x, 0, width, 0, maxX);\n yValue = log(xValue);\n y = map(yValue, -maxY, maxY, height, 0);\n vertex(x, y);\n }\n endShape();\n line(0, 0, 0, height);\n line(0, height / 2, width, height / 2);\n}\n</code></div>"], 13451 "alt": "ellipse moves along a curve with mouse x. natural logarithm of n displayed.", 13452 "class": "p5", 13453 "module": "Math", 13454 "submodule": "Calculation" 13455 }, { 13456 "file": "src/math/calculation.js", 13457 "line": 383, 13458 "description": "<p>Calculates the magnitude (or length) of a vector. A vector is a direction\nin space commonly used in computer graphics and linear algebra. Because it\nhas no "start" position, the magnitude of a vector can be thought of as\nthe distance from the coordinate 0,0 to its x,y value. Therefore, <a href=\"#/p5/mag\">mag()</a> is\na shortcut for writing dist(0, 0, x, y).</p>\n", 13459 "itemtype": "method", 13460 "name": "mag", 13461 "params": [{ 13462 "name": "a", 13463 "description": "<p>first value</p>\n", 13464 "type": "Number" 13465 }, { 13466 "name": "b", 13467 "description": "<p>second value</p>\n", 13468 "type": "Number" 13469 }], 13470 "return": { 13471 "description": "magnitude of vector from (0,0) to (a,b)", 13472 "type": "Number" 13473 }, 13474 "example": ["\n<div><code>\nfunction setup() {\n let x1 = 20;\n let x2 = 80;\n let y1 = 30;\n let y2 = 70;\n\n line(0, 0, x1, y1);\n print(mag(x1, y1)); // Prints \"36.05551275463989\"\n line(0, 0, x2, y1);\n print(mag(x2, y1)); // Prints \"85.44003745317531\"\n line(0, 0, x1, y2);\n print(mag(x1, y2)); // Prints \"72.80109889280519\"\n line(0, 0, x2, y2);\n print(mag(x2, y2)); // Prints \"106.3014581273465\"\n}\n</code></div>"], 13475 "alt": "4 lines of different length radiate from top left of canvas.", 13476 "class": "p5", 13477 "module": "Math", 13478 "submodule": "Calculation" 13479 }, { 13480 "file": "src/math/calculation.js", 13481 "line": 422, 13482 "description": "<p>Re-maps a number from one range to another.\n<br><br>\nIn the first example above, the number 25 is converted from a value in the\nrange of 0 to 100 into a value that ranges from the left edge of the\nwindow (0) to the right edge (width).</p>\n", 13483 "itemtype": "method", 13484 "name": "map", 13485 "params": [{ 13486 "name": "value", 13487 "description": "<p>the incoming value to be converted</p>\n", 13488 "type": "Number" 13489 }, { 13490 "name": "start1", 13491 "description": "<p>lower bound of the value's current range</p>\n", 13492 "type": "Number" 13493 }, { 13494 "name": "stop1", 13495 "description": "<p>upper bound of the value's current range</p>\n", 13496 "type": "Number" 13497 }, { 13498 "name": "start2", 13499 "description": "<p>lower bound of the value's target range</p>\n", 13500 "type": "Number" 13501 }, { 13502 "name": "stop2", 13503 "description": "<p>upper bound of the value's target range</p>\n", 13504 "type": "Number" 13505 }, { 13506 "name": "withinBounds", 13507 "description": "<p>constrain the value to the newly mapped range</p>\n", 13508 "type": "Boolean", 13509 "optional": true 13510 }], 13511 "return": { 13512 "description": "remapped number", 13513 "type": "Number" 13514 }, 13515 "example": ["\n <div><code>\nlet value = 25;\nlet m = map(value, 0, 100, 0, width);\nellipse(m, 50, 10, 10);\n</code></div>\n\n <div><code>\nfunction setup() {\n noStroke();\n}\n\nfunction draw() {\n background(204);\n let x1 = map(mouseX, 0, width, 25, 75);\n ellipse(x1, 25, 25, 25);\n //This ellipse is constrained to the 0-100 range\n //after setting withinBounds to true\n let x2 = map(mouseX, 0, width, 0, 100, true);\n ellipse(x2, 75, 25, 25);\n}\n</code></div>"], 13516 "alt": "10 by 10 white ellipse with in mid left canvas\n2 25 by 25 white ellipses move with mouse x. Bottom has more range from X", 13517 "class": "p5", 13518 "module": "Math", 13519 "submodule": "Calculation" 13520 }, { 13521 "file": "src/math/calculation.js", 13522 "line": 478, 13523 "description": "<p>Determines the largest value in a sequence of numbers, and then returns\nthat value. <a href=\"#/p5/max\">max()</a> accepts any number of Number parameters, or an Array\nof any length.</p>\n", 13524 "itemtype": "method", 13525 "name": "max", 13526 "return": { 13527 "description": "maximum Number", 13528 "type": "Number" 13529 }, 13530 "example": ["\n<div><code>\nfunction setup() {\n // Change the elements in the array and run the sketch\n // to show how max() works!\n let numArray = [2, 1, 5, 4, 8, 9];\n fill(0);\n noStroke();\n text('Array Elements', 0, 10);\n // Draw all numbers in the array\n let spacing = 15;\n let elemsY = 25;\n for (let i = 0; i < numArray.length;
13530 i++) {\n text(numArray[i], i * spacing, elemsY);\n }\n let maxX = 33;\n let maxY = 80;\n // Draw the Maximum value in the array.\n textSize(32);\n text(max(numArray), maxX, maxY);\n}\n</code></div>"], 13531 "alt": "Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 9", 13532 "class": "p5", 13533 "module": "Math", 13534 "submodule": "Calculation", 13535 "overloads": [{ 13536 "line": 478, 13537 "params": [{ 13538 "name": "n0", 13539 "description": "<p>Number to compare</p>\n", 13540 "type": "Number" 13541 }, { 13542 "name": "n1", 13543 "description": "<p>Number to compare</p>\n", 13544 "type": "Number" 13545 }], 13546 "return": { 13547 "description": "maximum Number", 13548 "type": "Number" 13549 } 13550 }, { 13551 "line": 514, 13552 "params": [{ 13553 "name": "nums", 13554 "description": "<p>Numbers to compare</p>\n", 13555 "type": "Number[]" 13556 }], 13557 "return": { 13558 "description": "", 13559 "type": "Number" 13560 } 13561 }] 13562 }, { 13563 "file": "src/math/calculation.js", 13564 "line": 528, 13565 "description": "<p>Determines the smallest value in a sequence of numbers, and then returns\nthat value. <a href=\"#/p5/min\">min()</a> accepts any number of Number parameters, or an Array\nof any length.</p>\n", 13566 "itemtype": "method", 13567 "name": "min", 13568 "return": { 13569 "description": "minimum Number", 13570 "type": "Number" 13571 }, 13572 "example": ["\n<div><code>\nfunction setup() {\n // Change the elements in the array and run the sketch\n // to show how min() works!\n let numArray = [2, 1, 5, 4, 8, 9];\n fill(0);\n noStroke();\n text('Array Elements', 0, 10);\n // Draw all numbers in the array\n let spacing = 15;\n let elemsY = 25;\n for (let i = 0; i < numArray.length; i++) {\n text(numArray[i], i * spacing, elemsY);\n }\n let maxX = 33;\n let maxY = 80;\n // Draw the Minimum value in the array.\n textSize(32);\n text(min(numArray), maxX, maxY);\n}\n</code></div>"], 13573 "alt": "Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 1", 13574 "class": "p5", 13575 "module": "Math", 13576 "submodule": "Calculation", 13577 "overloads": [{ 13578 "line": 528, 13579 "params": [{ 13580 "name": "n0", 13581 "description": "<p>Number to compare</p>\n", 13582 "type": "Number" 13583 }, { 13584 "name": "n1", 13585 "description": "<p>Number to compare</p>\n", 13586 "type": "Number" 13587 }], 13588 "return": { 13589 "description": "minimum Number", 13590 "type": "Number" 13591 } 13592 }, { 13593 "line": 564, 13594 "params": [{ 13595 "name": "nums", 13596 "description": "<p>Numbers to compare</p>\n", 13597 "type": "Number[]" 13598 }], 13599 "return": { 13600 "description": "", 13601 "type": "Number" 13602 } 13603 }] 13604 }, { 13605 "file": "src/math/calculation.js", 13606 "line": 578, 13607 "description": "<p>Normalizes a number from another range into a value between 0 and 1.\nIdentical to map(value, low, high, 0, 1).\nNumbers outside of the range are not clamped to 0 and 1, because\nout-of-range values are often intentional and useful. (See the second\nexample above.)</p>\n", 13608 "itemtype": "method", 13609 "name": "norm", 13610 "params": [{ 13611 "name": "value", 13612 "description": "<p>incoming value to be normalized</p>\n", 13613 "type": "Number" 13614 }, { 13615 "name": "start", 13616 "description": "<p>lower bound of the value's current range</p>\n", 13617 "type": "Number" 13618 }, { 13619 "name": "stop", 13620 "description": "<p>upper bound of the value's current range</p>\n", 13621 "type": "Number" 13622 }], 13623 "return": { 13624 "description": "normalized number", 13625 "type": "Number" 13626 }, 13627 "example": ["\n<div><code>\nfunction draw() {\n background(200);\n let currentNum = mouseX;\n let lowerBound = 0;\n let upperBound = width; //100;\n let normalized = norm(currentNum, lowerBound, upperBound);\n let lineY = 70;\n line(0, lineY, width, lineY);\n //Draw an ellipse mapped to the non-normalized value.\n noStroke();\n fill(50);\n let s = 7; // ellipse size\n ellipse(currentNum, lineY, s, s);\n\n // Draw the guide\n let guideY = lineY + 15;\n text('0', 0, guideY);\n textAlign(RIGHT);\n text('100', width, guideY);
13627\n\n // Draw the normalized value\n textAlign(LEFT);\n fill(0);\n textSize(32);\n let normalY = 40;\n let normalX = 20;\n text(normalized, normalX, normalY);\n}\n</code></div>"], 13628 "alt": "ellipse moves with mouse. 0 shown left & 100 right and updating values center", 13629 "class": "p5", 13630 "module": "Math", 13631 "submodule": "Calculation" 13632 }, { 13633 "file": "src/math/calculation.js", 13634 "line": 631, 13635 "description": "<p>Facilitates exponential expressions. The <a href=\"#/p5/pow\">pow()</a> function is an efficient\nway of multiplying numbers by themselves (or their reciprocals) in large\nquantities. For example, pow(3, 5) is equivalent to the expression\n3<em>3</em>3<em>3</em>3 and pow(3, -5) is equivalent to 1 / 3<em>3</em>3<em>3</em>3. Maps to\nMath.pow().</p>\n", 13636 "itemtype": "method", 13637 "name": "pow", 13638 "params": [{ 13639 "name": "n", 13640 "description": "<p>base of the exponential expression</p>\n", 13641 "type": "Number" 13642 }, { 13643 "name": "e", 13644 "description": "<p>power by which to raise the base</p>\n", 13645 "type": "Number" 13646 }], 13647 "return": { 13648 "description": "n^e", 13649 "type": "Number" 13650 }, 13651 "example": ["\n<div><code>\nfunction setup() {\n //Exponentially increase the size of an ellipse.\n let eSize = 3; // Original Size\n let eLoc = 10; // Original Location\n\n ellipse(eLoc, eLoc, eSize, eSize);\n\n ellipse(eLoc * 2, eLoc * 2, pow(eSize, 2), pow(eSize, 2));\n\n ellipse(eLoc * 4, eLoc * 4, pow(eSize, 3), pow(eSize, 3));\n\n ellipse(eLoc * 8, eLoc * 8, pow(eSize, 4), pow(eSize, 4));\n}\n</code></div>"], 13652 "alt": "small to large ellipses radiating from top left of canvas", 13653 "class": "p5", 13654 "module": "Math", 13655 "submodule": "Calculation" 13656 }, { 13657 "file": "src/math/calculation.js", 13658 "line": 665, 13659 "description": "<p>Calculates the integer closest to the n parameter. For example,\nround(133.8) returns the value 134. Maps to Math.round().</p>\n", 13660 "itemtype": "method", 13661 "name": "round", 13662 "params": [{ 13663 "name": "n", 13664 "description": "<p>number to round</p>\n", 13665 "type": "Number" 13666 }], 13667 "return": { 13668 "description": "rounded number", 13669 "type": "Integer" 13670 }, 13671 "example": ["\n<div><code>\nfunction draw() {\n background(200);\n //map, mouseX between 0 and 5.\n let ax = map(mouseX, 0, 100, 0, 5);\n let ay = 66;\n\n // Round the mapped number.\n let bx = round(map(mouseX, 0, 100, 0, 5));\n let by = 33;\n\n // Multiply the mapped numbers by 20 to more easily\n // see the changes.\n stroke(0);\n fill(0);\n line(0, ay, ax * 20, ay);\n line(0, by, bx * 20, by);\n\n // Reformat the float returned by map and draw it.\n noStroke();\n text(nfc(ax, 2), ax, ay - 5);\n text(nfc(bx, 1), bx, by - 5);\n}\n</code></div>"], 13672 "alt": "horizontal center line squared values displayed on top and regular on bottom.", 13673 "class": "p5", 13674 "module": "Math", 13675 "submodule": "Calculation" 13676 }, { 13677 "file": "src/math/calculation.js", 13678 "line": 704, 13679 "description": "<p>Squares a number (multiplies a number by itself). The result is always a\npositive number, as multiplying two negative numbers always yields a\npositive result. For example, -1 * -1 = 1.</p>\n", 13680 "itemtype": "method", 13681 "name": "sq", 13682 "params": [{ 13683 "name": "n", 13684 "description": "<p>number to square</p>\n", 13685 "type": "Number" 13686 }], 13687 "return": { 13688 "description": "squared number", 13689 "type": "Number" 13690 }, 13691 "example": ["\n<div><code>\nfunction draw() {\n background(200);\n let eSize = 7;\n let x1 = map(mouseX, 0, width, 0, 10);\n let y1 = 80;\n let x2 = sq(x1);\n let y2 = 20;\n\n // Draw the non-squared.\n line(0, y1, width, y1);\n ellipse(x1, y1, eSize, eSize);\n\n // Draw the squared.\n line(0, y2, width, y2);\n ellipse(x2, y2, eSize, eSize);\n\n // Draw dividing line.\n stroke(100);\n line(0, height / 2, width, height / 2);\n\n // Draw text.\n let spacing = 15;\n noStroke();\n fill(0);\n text('x = ' + x1, 0, y1 + spacing);\n text('sq(x) = ' + x2, 0, y2 + spacing);\n}\n</code></div>"], 13692 "alt": "horizontal center line squared values displayed on top and regular on bottom.", 13693 "class": "p5", 13694 "module": "Math", 13695 "submodule": "Calculation" 13696 }, { 13697 "file": "src/math/calculation.js", 13698 "line": 751, 13699 "description": "<p>Calculates the square root of a number. The square root of a number is\nalways positive, even though there may be a valid negative root. The\nsquare root s of number a is such that s*s = a. It is the opposite of\nsquaring. Maps to Math.sqrt().</p>\n", 13700 "itemtype": "method", 13701 "name": "sqrt", 13702 "params": [{ 13703 "name": "n", 13704 "description": "<p>non-negative number to square root</p>\n", 13705 "type": "Number" 13706 }], 13707 "return": { 13708 "description": "square root of number", 13709 "type": "Number" 13710 }, 13711 "example": ["\n<div><code>\nfunction draw() {\n background(200);\n let eSize = 7;\n let x1 = mouseX;\n let y1 = 80;\n let x2 = sqrt(x1);\n let y2 = 20;\n\n // Draw the non-squared.\n line(0, y1, width, y1);\n ellipse(x1, y1, eSize, eSize);\n\n // Draw the squared.\n line(0, y2, width, y2);\n ellipse(x2, y2, eSize, eSize);\n\n // Draw dividing line.\n stroke(100);\n line(0, height / 2, width, height / 2);\n\n // Draw text.\n noStroke();\n fill(0);\n let spacing = 15;\n text('x = ' + x1, 0, y1 + spacing);\n text('sqrt(x) = ' + x2, 0, y2 + spacing);\n}\n</code></div>"], 13712 "alt": "horizontal center line squareroot values displayed on top and regular on bottom.", 13713 "class": "p5", 13714 "module": "Math", 13715 "submodule": "Calculation" 13716 }, { 13717 "file": "src/math/math.js", 13718 "line": 12, 13719 "description": "<p>Creates a new <a href=\"#/p5.Vector\">p5.Vector</a> (the datatype for storing vectors). This provides a\ntwo or three dimensional vector, specifically a Euclidean (also known as\ngeometric) vector. A vector is an entity that has both magnitude and\ndirection.</p>\n", 13720 "itemtype": "method", 13721 "name": "createVector", 13722 "params": [{ 13723 "name": "x", 13724 "description": "<p>x component of the vector</p>\n", 13725 "type": "Number", 13726 "optional": true 13727 }, { 13728 "name": "y", 13729 "description": "<p>y component of the vector</p>\n", 13730 "type": "Number", 13731 "optional": true 13732 }, { 13733 "name": "z", 13734 "description": "<p>z component of the vector</p>\n", 13735 "type": "Number", 13736 "optional": true 13737 }], 13738 "return": { 13739 "description": "", 13740 "type": "p5.Vector" 13741 }, 13742 "example": ["\n<div modernizr='webgl'><code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n noStroke();\n fill(255, 102, 204);\n}\n\nfunction draw() {\n background(255);\n pointLight(color(255), createVector(sin(millis() / 1000) * 20, -40, -10));\n scale(0.75);\n sphere();\n}\n</code></div>"], 13743 "alt": "a purple sphere lit by a point light oscillating horizontally", 13744 "class": "p5", 13745 "module": "Math", 13746 "submodule": "Math" 13747 }, { 13748 "file": "src/math/noise.js", 13749 "line": 40, 13750 "description": "<p>Returns the Perlin noise value at specified coordinates. Perlin noise is\na random sequence generator producing a more natural ordered, harmonic\nsuccession of numbers compared to the standard <b>random()</b>
13750 function.\nIt was invented by Ken Perlin in the 1980s and been used since in\ngraphical applications to produce procedural textures, natural motion,\nshapes, terrains etc.<br /><br /> The main difference to the\n<b>random()</b> function is that Perlin noise is defined in an infinite\nn-dimensional space where each pair of coordinates corresponds to a\nfixed semi-random value (fixed only for the lifespan of the program; see\nthe <a href=\"#/p5/noiseSeed\">noiseSeed()</a> function). p5.js can compute 1D, 2D and 3D noise,\ndepending on the number of coordinates given. The resulting value will\nalways be between 0.0 and 1.0. The noise value can be animated by moving\nthrough the noise space as demonstrated in the example above. The 2nd\nand 3rd dimension can also be interpreted as time.<br /><br />The actual\nnoise is structured similar to an audio signal, in respect to the\nfunction's use of frequencies. Similar to the concept of harmonics in\nphysics, perlin noise is computed over several octaves which are added\ntogether for the final result. <br /><br />Another way to adjust the\ncharacter of the resulting sequence is the scale of the input\ncoordinates. As the function works within an infinite space the value of\nthe coordinates doesn't matter as such, only the distance between\nsuccessive coordinates does (eg. when using <b>noise()</b> within a\nloop). As a general rule the smaller the difference between coordinates,\nthe smoother the resulting noise sequence will be. Steps of 0.005-0.03\nwork best for most applications, but this will differ depending on use.</p>\n", 13751 "itemtype": "method", 13752 "name": "noise", 13753 "params": [{ 13754 "name": "x", 13755 "description": "<p>x-coordinate in noise space</p>\n", 13756 "type": "Number" 13757 }, { 13758 "name": "y", 13759 "description": "<p>y-coordinate in noise space</p>\n", 13760 "type": "Number", 13761 "optional": true 13762 }, { 13763 "name": "z", 13764 "description": "<p>z-coordinate in noise space</p>\n", 13765 "type": "Number", 13766 "optional": true 13767 }], 13768 "return": { 13769 "description": "Perlin noise value (between 0 and 1) at specified\n coordinates", 13770 "type": "Number" 13771 }, 13772 "example": ["\n<div>\n<code>\nlet xoff = 0.0;\n\nfunction draw() {\n background(204);\n xoff = xoff + 0.01;\n let n = noise(xoff) * width;\n line(n, 0, n, height);\n}\n</code>\n</div>\n<div>\n<code>let noiseScale=0.02;\n\nfunction draw() {\n background(0);\n for (let x=0; x < width; x++) {\n let noiseVal = noise((mouseX+x)*noiseScale, mouseY*noiseScale);\n stroke(noiseVal*255);\n line(x, mouseY+noiseVal*80, x, height);\n }\n}\n</code>\n</div>"], 13773 "alt": "vertical line moves left to right with updating noise values.\nhorizontal wave pattern effected by mouse x-position & updating noise values.", 13774 "class": "p5", 13775 "module": "Math", 13776 "submodule": "Noise" 13777 }, { 13778 "file": "src/math/noise.js", 13779 "line": 187, 13780 "description": "<p>Adjusts the character and level of detail produced by the Perlin noise\n function. Similar to harmonics in physics, noise is computed over\n several octaves. Lower octaves contribute more to the output signal and\n as such define the overall intensity of the noise, whereas higher octaves\n create finer grained details in the noise sequence.\n <br><br>\n By default, noise is computed over 4 octaves with each octave contributing\n exactly half than its predecessor, starting at 50% strength for the 1st\n octave. This falloff amount can be changed by adding an additional function\n parameter. Eg. a falloff factor of 0.75 means each octave will now have\n 75% impact (25% less) of the previous lower octave. Any value between\n 0.0 and 1.0 is valid, however note that values greater than 0.5 might\n result in greater than 1.0 values returned by <b>noise()</b>.\n <br><br>\n By changing these parameters, the signal created by the <b>noise()</b>\n function can be adapted to fit very specific needs and characteristics.</p>\n", 13781 "itemtype": "method", 13782 "name": "noiseDetail", 13783 "params": [{ 13784 "name": "lod", 13785 "description": "<p>number of octaves to be used by the noise</p>\n", 13786 "type": "Number" 13787 }, { 13788 "name": "falloff", 13789 "description": "<p>falloff factor for each octave</p>\n", 13790 "type": "Number" 13791 }], 13792 "example": ["\n <div>\n <code>\n let noiseVal;\n let noiseScale = 0.02;\nfunction setup() {\n createCanvas(100, 100);\n }\nfunction draw() {\n background(0);\n for (let y = 0; y < height;
13792 y++) {\n for (let x = 0; x < width / 2; x++) {\n noiseDetail(2, 0.2);\n noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale);\n stroke(noiseVal * 255);\n point(x, y);\n noiseDetail(8, 0.65);\n noiseVal = noise(\n (mouseX + x + width / 2) * noiseScale,\n (mouseY + y) * noiseScale\n );\n stroke(noiseVal * 255);\n point(x + width / 2, y);\n }\n }\n }\n </code>\n </div>"], 13793 "alt": "2 vertical grey smokey patterns affected my mouse x-position and noise.", 13794 "class": "p5", 13795 "module": "Math", 13796 "submodule": "Noise" 13797 }, { 13798 "file": "src/math/noise.js", 13799 "line": 253, 13800 "description": "<p>Sets the seed value for <b>noise()</b>. By default, <b>noise()</b>\nproduces different results each time the program is run. Set the\n<b>value</b> parameter to a constant to return the same pseudo-random\nnumbers each time the software is run.</p>\n", 13801 "itemtype": "method", 13802 "name": "noiseSeed", 13803 "params": [{ 13804 "name": "seed", 13805 "description": "<p>the seed value</p>\n", 13806 "type": "Number" 13807 }], 13808 "example": ["\n<div>\n<code>let xoff = 0.0;\n\nfunction setup() {\n noiseSeed(99);\n stroke(0, 10);\n}\n\nfunction draw() {\n xoff = xoff + .01;\n let n = noise(xoff) * width;\n line(n, 0, n, height);\n}\n</code>\n</div>"], 13809 "alt": "vertical grey lines drawing in pattern affected by noise.", 13810 "class": "p5", 13811 "module": "Math", 13812 "submodule": "Noise" 13813 }, { 13814 "file": "src/math/p5.Vector.js", 13815 "line": 67, 13816 "description": "<p>The x component of the vector</p>\n", 13817 "itemtype": "property", 13818 "name": "x", 13819 "type": "Number", 13820 "class": "p5.Vector", 13821 "module": "Math", 13822 "submodule": "Math" 13823 }, { 13824 "file": "src/math/p5.Vector.js", 13825 "line": 72, 13826 "description": "<p>The y component of the vector</p>\n", 13827 "itemtype": "property", 13828 "name": "y", 13829 "type": "Number", 13830 "class": "p5.Vector", 13831 "module": "Math", 13832 "submodule": "Math" 13833 }, { 13834 "file": "src/math/p5.Vector.js", 13835 "line": 77, 13836 "description": "<p>The z component of the vector</p>\n", 13837 "itemtype": "property", 13838 "name": "z", 13839 "type": "Number", 13840 "class": "p5.Vector", 13841 "module": "Math", 13842 "submodule": "Math" 13843 }, { 13844 "file": "src/math/p5.Vector.js", 13845 "line": 84, 13846 "description": "<p>Returns a string representation of a vector v by calling String(v)\nor v.toString(). This method is useful for logging vectors in the\nconsole.</p>\n", 13847 "itemtype": "method", 13848 "name": "toString", 13849 "return": { 13850 "description": "", 13851 "type": "String" 13852 }, 13853 "example": ["\n<div class = \"norender\">\n<code>\nfunction setup() {\n let v = createVector(20, 30);\n print(String(v)); // prints \"p5.Vector Object : [20, 30, 0]\"\n}\n</code>\n</div>\n\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(0, 0);\n let v1 = createVector(mouseX, mouseY);\n drawArrow(v0, v1, 'black');\n\n noStroke();\n text(v1.toString(), 10, 25, 90, 75);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 13854 "class": "p5.Vector", 13855 "module": "Math", 13856 "submodule": "Math" 13857 }, { 13858 "file": "src/math/p5.Vector.js", 13859 "line": 134, 13860 "description": "<p>Sets the x, y, and z component of the vector using two or three separate\nvariables, the data from a <a href=\"#/p5.Vector\">p5.Vector</a>, or the values from a float array.</p>\n", 13861 "itemtype": "method", 13862 "name": "set", 13863 "chainable": 1, 13864 "example": ["\n<div class=\"norender\">\n<code>\nfunction setup() {\n let v = createVector(1, 2, 3);
13864\n v.set(4, 5, 6); // Sets vector to [4, 5, 6]\n\n let v1 = createVector(0, 0, 0);\n let arr = [1, 2, 3];\n v1.set(arr); // Sets vector to [1, 2, 3]\n}\n</code>\n</div>\n\n<div>\n<code>\nlet v0, v1;\nfunction setup() {\n createCanvas(100, 100);\n\n v0 = createVector(0, 0);\n v1 = createVector(50, 50);\n}\n\nfunction draw() {\n background(240);\n\n drawArrow(v0, v1, 'black');\n v1.set(v1.x + random(-1, 1), v1.y + random(-1, 1));\n\n noStroke();\n text('x: ' + round(v1.x) + ' y: ' + round(v1.y), 20, 90);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 13865 "class": "p5.Vector", 13866 "module": "Math", 13867 "submodule": "Math", 13868 "overloads": [{ 13869 "line": 134, 13870 "params": [{ 13871 "name": "x", 13872 "description": "<p>the x component of the vector</p>\n", 13873 "type": "Number", 13874 "optional": true 13875 }, { 13876 "name": "y", 13877 "description": "<p>the y component of the vector</p>\n", 13878 "type": "Number", 13879 "optional": true 13880 }, { 13881 "name": "z", 13882 "description": "<p>the z component of the vector</p>\n", 13883 "type": "Number", 13884 "optional": true 13885 }], 13886 "chainable": 1 13887 }, { 13888 "line": 193, 13889 "params": [{ 13890 "name": "value", 13891 "description": "<p>the vector to set</p>\n", 13892 "type": "p5.Vector|Number[]" 13893 }], 13894 "chainable": 1 13895 }] 13896 }, { 13897 "file": "src/math/p5.Vector.js", 13898 "line": 217, 13899 "description": "<p>Gets a copy of the vector, returns a <a href=\"#/p5.Vector\">p5.Vector</a> object.</p>\n", 13900 "itemtype": "method", 13901 "name": "copy", 13902 "return": { 13903 "description": "the copy of the <a href=\"#/p5.Vector\">p5.Vector</a> object", 13904 "type": "p5.Vector" 13905 }, 13906 "example": ["\n<div class=\"norender\">\n<code>\nlet v1 = createVector(1, 2, 3);\nlet v2 = v1.copy();\nprint(v1.x === v2.x && v1.y === v2.y && v1.z === v2.z);\n// Prints \"true\"\n</code>\n</div>"], 13907 "class": "p5.Vector", 13908 "module": "Math", 13909 "submodule": "Math" 13910 }, { 13911 "file": "src/math/p5.Vector.js", 13912 "line": 240, 13913 "description": "<p>Adds x, y, and z components to a vector, adds one vector to another, or\nadds two independent vectors together. The version of the method that adds\ntwo vectors together is a static method and returns a <a href=\"#/p5.Vector\">p5.Vector</a>, the others\nacts directly on the vector. See the examples for more context.</p>\n", 13914 "itemtype": "method", 13915 "name": "add", 13916 "chainable": 1, 13917 "example": ["\n<div class=\"norender\">\n<code>\nlet v = createVector(1, 2, 3);\nv.add(4, 5, 6);\n// v's components are set to [5, 7, 9]\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// Static method\nlet v1 = createVector(1, 2, 3);\nlet v2 = createVector(2, 3, 4);\n\nlet v3 = p5.Vector.add(v1, v2);\n// v3 has components [3, 5, 7]\nprint(v3);\n</code>\n</div>\n\n<div>\n<code>\n// red vector + blue vector = purple vector\nfunction draw() {\n background(240);\n\n let v0 = createVector(0, 0);\n let v1 = createVector(mouseX, mouseY);\n drawArrow(v0, v1, 'red');\n\n let v2 = createVector(-30, 20);\n drawArrow(v1, v2, 'blue');\n\n let v3 = p5.Vector.add(v1, v2);\n drawArrow(v0, v3, 'purple');\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 13918 "class": "p5.Vector", 13919 "module": "Math", 13920 "submodule": "Math", 13921 "overloads": [{ 13922 "line": 240, 13923 "params": [{ 13924 "name": "x", 13925 "description": "<p>the x component of the vector to be added</p>\n", 13926 "type": "Number" 13927 }, { 13928 "name": "y", 13929 "description": "<p>the y component of the vector to be added</p>\n", 13930 "type": "Number", 13931 "optional": true 13932 }, { 13933 "name": "z", 13934 "description": "<p>the z component of the vector to be added</p>\n", 13935 "type": "Number", 13936 "optional": true 13937 }], 13938 "chainable": 1 13939 }, { 13940 "line": 306, 13941 "params": [{ 13942 "name": "value", 13943 "description": "<p>the vector to add</p>\n", 13944 "type": "p5.Vector|Number[]" 13945 }], 13946 "chainable": 1 13947 }, { 13948 "line": 1556, 13949 "params": [{ 13950 "name": "v1", 13951 "description": "<p>a <a href=\"#/p5.Vector\">p5.Vector</a> to add</p>\n", 13952 "type": "p5.Vector" 13953 }, { 13954 "name": "v2", 13955 "description": "<p>a <a href=\"#/p5.Vector\">p5.Vector</a> to add</p>\n", 13956 "type": "p5.Vector" 13957 }, { 13958 "name": "target", 13959 "description": "<p>the vector to receive the result</p>\n", 13960 "type": "p5.Vector" 13961 }], 13962 "static": 1 13963 }, { 13964 "line": 1563, 13965 "params": [{ 13966 "name": "v1", 13967 "description": "", 13968 "type": "p5.Vector" 13969 }, { 13970 "name": "v2", 13971 "description": "", 13972 "type": "p5.Vector" 13973 }], 13974 "static": 1, 13975 "return": { 13976 "description": "the resulting <a href=\"#/p5.Vector\">p5.Vector</a>", 13977 "type": "p5.Vector" 13978 } 13979 }] 13980 }, { 13981 "file": "src/math/p5.Vector.js", 13982 "line": 330, 13983 "description": "<p>Subtracts x, y, and z components from a vector, subtracts one vector from\nanother, or subtracts two independent vectors. The version of the method\nthat subtracts two vectors is a static method and returns a <a href=\"#/p5.Vector\">p5.Vector</a>, the\nother acts directly on the vector. See the examples for more context.</p>\n", 13984 "itemtype": "method", 13985 "name": "sub", 13986 "chainable": 1, 13987 "example": ["\n<div class=\"norender\">\n<code>
13987\nlet v = createVector(4, 5, 6);\nv.sub(1, 1, 1);\n// v's components are set to [3, 4, 5]\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// Static method\nlet v1 = createVector(2, 3, 4);\nlet v2 = createVector(1, 2, 3);\n\nlet v3 = p5.Vector.sub(v1, v2);\n// v3 has components [1, 1, 1]\nprint(v3);\n</code>\n</div>\n\n<div>\n<code>\n// red vector - blue vector = purple vector\nfunction draw() {\n background(240);\n\n let v0 = createVector(0, 0);\n let v1 = createVector(70, 50);\n drawArrow(v0, v1, 'red');\n\n let v2 = createVector(mouseX, mouseY);\n drawArrow(v0, v2, 'blue');\n\n let v3 = p5.Vector.sub(v1, v2);\n drawArrow(v2, v3, 'purple');\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 13988 "class": "p5.Vector", 13989 "module": "Math", 13990 "submodule": "Math", 13991 "overloads": [{ 13992 "line": 330, 13993 "params": [{ 13994 "name": "x", 13995 "description": "<p>the x component of the vector to subtract</p>\n", 13996 "type": "Number" 13997 }, { 13998 "name": "y", 13999 "description": "<p>the y component of the vector to subtract</p>\n", 14000 "type": "Number", 14001 "optional": true 14002 }, { 14003 "name": "z", 14004 "description": "<p>the z component of the vector to subtract</p>\n", 14005 "type": "Number", 14006 "optional": true 14007 }], 14008 "chainable": 1 14009 }, { 14010 "line": 396, 14011 "params": [{ 14012 "name": "value", 14013 "description": "<p>the vector to subtract</p>\n", 14014 "type": "p5.Vector|Number[]" 14015 }], 14016 "chainable": 1 14017 }, { 14018 "line": 1586, 14019 "params": [{ 14020 "name": "v1", 14021 "description": "<p>a <a href=\"#/p5.Vector\">p5.Vector</a> to subtract from</p>\n", 14022 "type": "p5.Vector" 14023 }, { 14024 "name": "v2", 14025 "description": "<p>a <a href=\"#/p5.Vector\">p5.Vector</a> to subtract</p>\n", 14026 "type": "p5.Vector" 14027 }, { 14028 "name": "target", 14029 "description": "<p>if undefined a new vector will be created</p>\n", 14030 "type": "p5.Vector" 14031 }], 14032 "static": 1 14033 }, { 14034 "line": 1593, 14035 "params": [{ 14036 "name": "v1", 14037 "description": "", 14038 "type": "p5.Vector" 14039 }, { 14040 "name": "v2", 14041 "description": "", 14042 "type": "p5.Vector" 14043 }], 14044 "static": 1, 14045 "return": { 14046 "description": "the resulting <a href=\"#/p5.Vector\">p5.Vector</a>", 14047 "type": "p5.Vector" 14048 } 14049 }] 14050 }, { 14051 "file": "src/math/p5.Vector.js", 14052 "line": 420, 14053 "description": "<p>Multiply the vector by a scalar. The static version of this method\ncreates a new <a href=\"#/p5.Vector\">p5.Vector</a> while the non static version acts on the vector\ndirectly. See the examples for more context.</p>\n", 14054 "itemtype": "method", 14055 "name": "mult", 14056 "chainable": 1, 14057 "example": ["\n<div class=\"norender\">\n<code>\nlet v = createVector(1, 2, 3);\nv.mult(2);\n// v's components are set to [2, 4, 6]\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// Static method\nlet v1 = createVector(1, 2, 3);\nlet v2 = p5.Vector.mult(v1, 2);\n// v2 has components [2, 4, 6]\nprint(v2);\n</code>\n</div>\n\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(50, 50);\n let v1 = createVector(25, -25);\n drawArrow(v0, v1, 'red');\n\n let num = map(mouseX, 0, width, -2, 2, true);\n let v2 = p5.Vector.mult(v1, num);\n drawArrow(v0, v2, 'blue');\n\n noStroke();\n text('multiplied by ' + num.toFixed(2), 5, 90);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14058 "class": "p5.Vector", 14059 "module": "Math", 14060 "submodule": "Math", 14061 "overloads": [{ 14062 "line": 420, 14063 "params": [{ 14064 "name": "n", 14065 "description": "<p>the number to multiply with the vector</p>\n", 14066 "type": "Number" 14067 }], 14068 "chainable": 1 14069 }, { 14070 "line": 1614, 14071 "params": [{ 14072 "name": "v", 14073 "description": "<p>the vector to multiply</p>\n", 14074 "type": "p5.Vector" 14075 }, { 14076 "name": "n", 14077 "description": "", 14078 "type": "Number" 14079 }, { 14080 "name": "target", 14081 "description": "<p>if undefined a new vector will be created</p>\n", 14082 "type": "p5.Vector" 14083 }], 14084 "static": 1 14085 }, { 14086 "line": 1621, 14087 "params": [{ 14088 "name": "v", 14089 "description": "", 14090 "type": "p5.Vector" 14091 }, { 14092 "name": "n", 14093 "description": "", 14094 "type": "Number" 14095 }], 14096 "static": 1, 14097 "return": { 14098 "description": "the resulting new <a href=\"#/p5.Vector\">p5.Vector</a>", 14099 "type": "p5.Vector" 14100 } 14101 }] 14102 }, { 14103 "file": "src/math/p5.Vector.js", 14104 "line": 495, 14105 "description": "<p>Divide the vector by a scalar. The static version of this method creates a\nnew <a href=\"#/p5.Vector\">p5.Vector</a> while the non static version acts on the vector directly.\nSee the examples for more context.</p>\n", 14106 "itemtype": "method", 14107 "name": "div", 14108 "chainable": 1, 14109 "example": ["\n<div class=\"norender\">\n<code>\nlet v = createVector(6, 4, 2);\nv.div(2); //v's components are set to [3, 2, 1]\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// Static method\nlet v1 = createVector(6, 4, 2);\nlet v2 = p5.Vector.div(v1, 2);\n// v2 has components [3, 2, 1]\nprint(v2);\n</code>\n</div>\n\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(0, 100);\n let v1 = createVector(50, -50);\n drawArrow(v0, v1, 'red');\n\n let num = map(mouseX, 0, width, 10, 0.5, true);\n let v2 = p5.Vector.div(v1, num);\n drawArrow(v0, v2, 'blue');\n\n noStroke();\n text('divided by ' + num.toFixed(2), 10, 90);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14110 "class": "p5.Vector", 14111 "module": "Math", 14112 "submodule": "Math", 14113 "overloads": [{ 14114 "line": 495, 14115 "params": [{ 14116 "name": "n", 14117 "description": "<p>the number to divide the vector by</p>\n", 14118 "type": "Number" 14119 }], 14120 "chainable": 1 14121 }, { 14122 "line": 1641, 14123 "params": [{ 14124 "name": "v", 14125 "description": "<p>the vector to divide</p>\n", 14126 "type": "p5.Vector" 14127 }, { 14128 "name": "n", 14129 "description": "", 14130 "type": "Number" 14131 }, { 14132 "name": "target", 14133 "description": "<p>if undefined a new vector will be created</p>\n", 14134 "type": "p5.Vector" 14135 }], 14136 "static": 1 14137 }, { 14138 "line": 1648, 14139 "params": [{ 14140 "name": "v", 14141 "description": "", 14142 "type": "p5.Vector" 14143 }, { 14144 "name": "n", 14145 "description": "", 14146 "type": "Number" 14147 }], 14148 "static": 1, 14149 "return": { 14150 "description": "the resulting new <a href=\"#/p5.Vector\">p5.Vector</a>", 14151 "type": "p5.Vector" 14152 } 14153 }] 14154 }, { 14155 "file": "src/math/p5.Vector.js", 14156 "line": 573, 14157 "description": "<p>Calculates the magnitude (length) of the vector and returns the result as\na float (this is simply the equation sqrt(x<em>x + y</em>y + z*z).)</p>\n", 14158 "itemtype": "method", 14159 "name": "mag", 14160 "return": { 14161 "description": "magnitude of the vector", 14162 "type": "Number" 14163 }, 14164 "example": ["\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(0, 0);\n let v1 = createVector(mouseX, mouseY);\n drawArrow(v0, v1, 'black');\n\n noStroke();
14164\n text('vector length: ' + v1.mag().toFixed(2), 10, 70, 90, 30);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>\n<div class=\"norender\">\n<code>\nlet v = createVector(20.0, 30.0, 40.0);\nlet m = v.mag();\nprint(m); // Prints \"53.85164807134504\"\n</code>\n</div>"], 14165 "class": "p5.Vector", 14166 "module": "Math", 14167 "submodule": "Math", 14168 "overloads": [{ 14169 "line": 573, 14170 "params": [], 14171 "return": { 14172 "description": "magnitude of the vector", 14173 "type": "Number" 14174 } 14175 }, { 14176 "line": 1738, 14177 "params": [{ 14178 "name": "vecT", 14179 "description": "<p>the vector to return the magnitude of</p>\n", 14180 "type": "p5.Vector" 14181 }], 14182 "static": 1, 14183 "return": { 14184 "description": "the magnitude of vecT", 14185 "type": "Number" 14186 } 14187 }] 14188 }, { 14189 "file": "src/math/p5.Vector.js", 14190 "line": 621, 14191 "description": "<p>Calculates the squared magnitude of the vector and returns the result\nas a float (this is simply the equation <em>(x<em>x + y</em>y + z*z)</em>.)\nFaster if the real length is not required in the\ncase of comparing vectors, etc.</p>\n", 14192 "itemtype": "method", 14193 "name": "magSq", 14194 "return": { 14195 "description": "squared magnitude of the vector", 14196 "type": "Number" 14197 }, 14198 "example": ["\n<div class=\"norender\">\n<code>\n// Static method\nlet v1 = createVector(6, 4, 2);\nprint(v1.magSq()); // Prints \"56\"\n</code>\n</div>\n\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(0, 0);\n let v1 = createVector(mouseX, mouseY);\n drawArrow(v0, v1, 'black');\n\n noStroke();\n text('vector length squared: ' + v1.magSq().toFixed(2), 10, 45, 90, 55);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14199 "class": "p5.Vector", 14200 "module": "Math", 14201 "submodule": "Math" 14202 }, { 14203 "file": "src/math/p5.Vector.js", 14204 "line": 675, 14205 "description": "<p>Calculates the dot product of two vectors. The version of the method\nthat computes the dot product of two independent vectors is a static\nmethod. See the examples for more context.</p>\n", 14206 "itemtype": "method", 14207 "name": "dot", 14208 "return": { 14209 "description": "the dot product", 14210 "type": "Number" 14211 }, 14212 "example": ["\n<div class=\"norender\">\n<code>\nlet v1 = createVector(1, 2, 3);\nlet v2 = createVector(2, 3, 4);\n\nprint(v1.dot(v2)); // Prints \"20\"\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n//Static method\nlet v1 = createVector(1, 2, 3);\nlet v2 = createVector(3, 2, 1);\nprint(p5.Vector.dot(v1, v2)); // Prints \"10\"\n</code>\n</div>"], 14213 "class": "p5.Vector", 14214 "module": "Math", 14215 "submodule": "Math", 14216 "overloads": [{ 14217 "line": 675, 14218 "params": [{ 14219 "name": "x", 14220 "description": "<p>x component of the vector</p>\n", 14221 "type": "Number" 14222 }, { 14223 "name": "y", 14224 "description": "<p>y component of the vector</p>\n", 14225 "type": "Number", 14226 "optional": true 14227 }, { 14228 "name": "z", 14229 "description": "<p>z component of the vector</p>\n", 14230 "type": "Number", 14231 "optional": true 14232 }], 14233 "return": { 14234 "description": "the dot product", 14235 "type": "Number" 14236 } 14237 }, { 14238 "line": 706, 14239 "params": [{ 14240 "name": "value", 14241 "description": "<p>value component of the vector or a <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14242 "type": "p5.Vector" 14243 }], 14244 "return": { 14245 "description": "", 14246 "type": "Number" 14247 } 14248 }, { 14249 "line": 1668, 14250 "params": [{ 14251 "name": "v1", 14252 "description": "<p>the first <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14253 "type": "p5.Vector" 14254 }, { 14255 "name": "v2", 14256 "description": "<p>the second <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14257 "type": "p5.Vector" 14258 }], 14259 "static": 1, 14260 "return": { 14261 "description": "the dot product", 14262 "type": "Number" 14263 } 14264 }] 14265 }, { 14266 "file": "src/math/p5.Vector.js", 14267 "line": 718, 14268 "description": "<p>Calculates and returns a vector composed of the cross product between\ntwo vectors. Both the static and non static methods return a new <a href=\"#/p5.Vector\">p5.Vector</a>.\nSee the examples for more context.</p>\n", 14269 "itemtype": "method", 14270 "name": "cross", 14271 "return": { 14272 "description": "<a href=\"#/p5.Vector\">p5.Vector</a> composed of cross product", 14273 "type": "p5.Vector" 14274 }, 14275 "example": ["\n<div class=\"norender\">\n<code>\nlet v1 = createVector(1, 2, 3);\nlet v2 = createVector(1, 2, 3);\n\nv1.cross(v2); // v's components are [0, 0, 0]\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// Static method\nlet v1 = createVector(1, 0, 0);\nlet v2 = createVector(0, 1, 0);
14275\n\nlet crossProduct = p5.Vector.cross(v1, v2);\n// crossProduct has components [0, 0, 1]\nprint(crossProduct);\n</code>\n</div>"], 14276 "class": "p5.Vector", 14277 "module": "Math", 14278 "submodule": "Math", 14279 "overloads": [{ 14280 "line": 718, 14281 "params": [{ 14282 "name": "v", 14283 "description": "<p><a href=\"#/p5.Vector\">p5.Vector</a> to be crossed</p>\n", 14284 "type": "p5.Vector" 14285 }], 14286 "return": { 14287 "description": "<a href=\"#/p5.Vector\">p5.Vector</a> composed of cross product", 14288 "type": "p5.Vector" 14289 } 14290 }, { 14291 "line": 1682, 14292 "params": [{ 14293 "name": "v1", 14294 "description": "<p>the first <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14295 "type": "p5.Vector" 14296 }, { 14297 "name": "v2", 14298 "description": "<p>the second <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14299 "type": "p5.Vector" 14300 }], 14301 "static": 1, 14302 "return": { 14303 "description": "the cross product", 14304 "type": "Number" 14305 } 14306 }] 14307 }, { 14308 "file": "src/math/p5.Vector.js", 14309 "line": 759, 14310 "description": "<p>Calculates the Euclidean distance between two points (considering a\npoint as a vector object).</p>\n", 14311 "itemtype": "method", 14312 "name": "dist", 14313 "return": { 14314 "description": "the distance", 14315 "type": "Number" 14316 }, 14317 "example": ["\n<div class=\"norender\">\n<code>\nlet v1 = createVector(1, 0, 0);\nlet v2 = createVector(0, 1, 0);\n\nlet distance = v1.dist(v2); // distance is 1.4142...\nprint(distance);\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\n// Static method\nlet v1 = createVector(1, 0, 0);\nlet v2 = createVector(0, 1, 0);\n\nlet distance = p5.Vector.dist(v1, v2);\n// distance is 1.4142...\nprint(distance);\n</code>\n</div>\n\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(0, 0);\n\n let v1 = createVector(70, 50);\n drawArrow(v0, v1, 'red');\n\n let v2 = createVector(mouseX, mouseY);\n drawArrow(v0, v2, 'blue');\n\n noStroke();\n text('distance between vectors: ' + v2.dist(v1).toFixed(2), 5, 50, 95, 50);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14318 "class": "p5.Vector", 14319 "module": "Math", 14320 "submodule": "Math", 14321 "overloads": [{ 14322 "line": 759, 14323 "params": [{ 14324 "name": "v", 14325 "description": "<p>the x, y, and z coordinates of a <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14326 "type": "p5.Vector" 14327 }], 14328 "return": { 14329 "description": "the distance", 14330 "type": "Number" 14331 } 14332 }, { 14333 "line": 1697, 14334 "params": [{ 14335 "name": "v1", 14336 "description": "<p>the first <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14337 "type": "p5.Vector" 14338 }, { 14339 "name": "v2", 14340 "description": "<p>the second <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14341 "type": "p5.Vector" 14342 }], 14343 "static": 1, 14344 "return": { 14345 "description": "the distance", 14346 "type": "Number" 14347 } 14348 }] 14349 }, { 14350 "file": "src/math/p5.Vector.js", 14351 "line": 830, 14352 "description": "<p>Normalize the vector to length 1 (make it a unit vector).</p>\n", 14353 "itemtype": "method", 14354 "name": "normalize", 14355 "return": { 14356 "description": "normalized <a href=\"#/p5.Vector\">p5.Vector</a>", 14357 "type": "p5.Vector" 14358 }, 14359 "example": ["\n<div class=\"norender\">\n<code>\nlet v = createVector(10, 20, 2);\n// v has components [10.0, 20.0, 2.0]\nv.normalize();\n// v's components are set to\n// [0.4454354, 0.8908708, 0.089087084]\n</code>\n</div>\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(50, 50);\n let v1 = createVector(mouseX - 50, mouseY - 50);\n\n drawArrow(v0, v1, 'red');\n v1.normalize();\n drawArrow(v0, v1.mult(35), 'blue');\n\n noFill();\n ellipse(50, 50, 35 * 2);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14360 "class": "p5.Vector", 14361 "module": "Math", 14362 "submodule": "Math" 14363 }, { 14364 "file": "src/math/p5.Vector.js", 14365 "line": 886, 14366 "description": "<p>Limit the magnitude of this vector to the value used for the <b>max</b>\nparameter.</p>\n", 14367 "itemtype": "method", 14368 "name": "limit", 14369 "params": [{ 14370 "name": "max", 14371 "description": "<p>the maximum magnitude for the vector</p>\n", 14372 "type": "Number" 14373 }], 14374 "chainable": 1, 14375 "example": ["\n<div class=\"norender\">\n<code>\nlet v = createVector(10, 20, 2);\n// v has components [10.0, 20.0, 2.0]\nv.limit(5);\n// v's components are set to\n// [2.2271771, 4.4543543, 0.4454354]\n</code>\n</div>\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(50, 50);\n let v1 = createVector(mouseX - 50, mouseY - 50);\n\n drawArrow(v0, v1, 'red');\n drawArrow(v0, v1.limit(35), 'blue');\n\n noFill();\n ellipse(50, 50, 35 * 2);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14376 "class": "p5.Vector", 14377 "module": "Math", 14378 "submodule": "Math" 14379 }, { 14380 "file": "src/math/p5.Vector.js", 14381 "line": 944, 14382 "description": "<p>Set the magnitude of this vector to the value used for the <b>len</b>\nparameter.</p>\n", 14383 "itemtype": "method", 14384 "name": "setMag", 14385 "params": [{ 14386 "name": "len", 14387 "description": "<p>the new length for this vector</p>\n", 14388 "type": "Number" 14389 }], 14390 "chainable": 1, 14391 "example": ["\n<div class=\"norender\">\n<code>\nlet v = createVector(10, 20, 2);\n// v has components [10.0, 20.0, 2.0]\nv.setMag(10);\n// v's components are set to [6.0, 8.0, 0.0]\n</code>\n</div>\n\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(0, 0);\n let v1 = createVector(50, 50);\n\n drawArrow(v0, v1, 'red');\n\n let length = map(mouseX, 0, width, 0, 141, true);\n v1.setMag(length);\n drawArrow(v0, v1, 'blue');\n\n noStroke();\n text('magnitude set to: ' + length.toFixed(2), 10, 70, 90, 30);\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14392 "class": "p5.Vector", 14393 "module": "Math", 14394 "submodule": "Math" 14395 }, { 14396 "file": "src/math/p5.Vector.js", 14397 "line": 1000, 14398 "description": "<p>Calculate the angle of rotation for this vector (only 2D vectors)</p>\n", 14399 "itemtype": "method", 14400 "name": "heading", 14401 "return": { 14402 "description": "the angle of rotation", 14403 "type": "Number" 14404 }, 14405 "example": ["\n<div class = \"norender\">\n<code>\nfunction setup() {\n let v1 = createVector(30, 50);\n print(v1.heading()); // 1.0303768265243125\n\n v1 = createVector(40, 50);\n print(v1.heading());
14405 // 0.8960553845713439\n\n v1 = createVector(30, 70);\n print(v1.heading()); // 1.1659045405098132\n}\n</code>\n</div>\n\n<div>\n<code>\nfunction draw() {\n background(240);\n\n let v0 = createVector(50, 50);\n let v1 = createVector(mouseX - 50, mouseY - 50);\n\n drawArrow(v0, v1, 'black');\n\n let myHeading = v1.heading();\n noStroke();\n text(\n 'vector heading: ' +\n myHeading.toFixed(2) +\n ' radians or ' +\n degrees(myHeading).toFixed(2) +\n ' degrees',\n 10,\n 50,\n 90,\n 50\n );\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14406 "class": "p5.Vector", 14407 "module": "Math", 14408 "submodule": "Math" 14409 }, { 14410 "file": "src/math/p5.Vector.js", 14411 "line": 1069, 14412 "description": "<p>Rotate the vector by an angle (only 2D vectors), magnitude remains the\nsame</p>\n", 14413 "itemtype": "method", 14414 "name": "rotate", 14415 "params": [{ 14416 "name": "angle", 14417 "description": "<p>the angle of rotation</p>\n", 14418 "type": "Number" 14419 }], 14420 "chainable": 1, 14421 "example": ["\n<div class=\"norender\">\n<code>\nlet v = createVector(10.0, 20.0);\n// v has components [10.0, 20.0, 0.0]\nv.rotate(HALF_PI);\n// v's components are set to [-20.0, 9.999999, 0.0]\n</code>\n</div>\n\n<div>\n<code>\nlet angle = 0;\nfunction draw() {\n background(240);\n\n let v0 = createVector(50, 50);\n let v1 = createVector(50, 0);\n\n drawArrow(v0, v1.rotate(angle), 'black');\n angle += 0.01;\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14422 "class": "p5.Vector", 14423 "module": "Math", 14424 "submodule": "Math" 14425 }, { 14426 "file": "src/math/p5.Vector.js", 14427 "line": 1125, 14428 "description": "<p>Calculates and returns the angle (in radians) between two vectors.</p>\n", 14429 "itemtype": "method", 14430 "name": "angleBetween", 14431 "params": [{ 14432 "name": "the", 14433 "description": "<p>x, y, and z components of a <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14434 "type": "p5.Vector" 14435 }], 14436 "return": { 14437 "description": "the angle between (in radians)", 14438 "type": "Number" 14439 }, 14440 "example": ["\n<div class=\"norender\">\n<code>\nlet v1 = createVector(1, 0, 0);\nlet v2 = createVector(0, 1, 0);\n\nlet angle = v1.angleBetween(v2);\n// angle is PI/2\nprint(angle);\n</code>\n</div>\n\n<div>\n<code>\nfunction draw() {\n background(240);\n let v0 = createVector(50, 50);\n\n let v1 = createVector(50, 0);\n drawArrow(v0, v1, 'red');\n\n let v2 = createVector(mouseX - 50, mouseY - 50);\n drawArrow(v0, v2, 'blue');\n\n let angleBetween = v1.angleBetween(v2);\n noStroke();\n text(\n 'angle between: ' +\n angleBetween.toFixed(2) +\n ' radians or ' +\n degrees(angleBetween).toFixed(2) +\n ' degrees',\n 10,\n 50,\n 90,\n 50\n );\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14441 "class": "p5.Vector", 14442 "module": "Math", 14443 "submodule": "Math" 14444 }, { 14445 "file": "src/math/p5.Vector.js", 14446 "line": 1198, 14447 "description": "<p>Linear interpolate the vector to another vector</p>\n", 14448 "itemtype": "method", 14449 "name": "lerp", 14450 "chainable": 1, 14451 "example": ["\n<div class=\"norender\">\n<code>\nlet v = createVector(1, 1, 0);\n\nv.lerp(3, 3, 0, 0.5); // v now has components [2,2,0]\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nlet v1 = createVector(0, 0, 0);\nlet v2 = createVector(100, 100, 0);\n\nlet v3 = p5.Vector.lerp(v1, v2, 0.5);\n// v3 has components [50,50,0]\nprint(v3);\n</code>\n</div>\n\n<div>\n<code>\nlet step = 0.01;\nlet amount = 0;\n\nfunction draw() {\n background(240);\n let v0 = createVector(0, 0);\n\n let v1 = createVector(mouseX, mouseY);\n drawArrow(v0, v1, 'red');\n\n let v2 = createVector(90, 90);\n drawArrow(v0, v2, 'blue');\n\n if (amount > 1 || amount < 0) {\n step *= -1;\n }\n amount += step;\n let v3 = p5.Vector.lerp(v1, v2, amount);\n\n drawArrow(v0, v3, 'purple');\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14452 "class": "p5.Vector", 14453 "module": "Math", 14454 "submodule": "Math", 14455 "overloads": [{ 14456 "line": 1198, 14457 "params": [{ 14458 "name": "x", 14459 "description": "<p>the x component</p>\n", 14460 "type": "Number" 14461 }, { 14462 "name": "y", 14463 "description": "<p>the y component</p>\n", 14464 "type": "Number" 14465 }, { 14466 "name": "z", 14467 "description": "<p>the z component</p>\n", 14468 "type": "Number" 14469 }, { 14470 "name": "amt", 14471 "description": "<p>the amount of interpolation; some value between 0.0\n (old vector) and 1.0 (new vector). 0.9 is very near\n the new vector. 0.5 is halfway in between.</p>\n", 14472 "type": "Number" 14473 }], 14474 "chainable": 1 14475 }, { 14476 "line": 1271, 14477 "params": [{ 14478 "name": "v", 14479 "description": "<p>the <a href=\"#/p5.Vector\">p5.Vector</a> to lerp to</p>\n", 14480 "type": "p5.Vector" 14481 }, { 14482 "name": "amt", 14483 "description": "", 14484 "type": "Number" 14485 }], 14486 "chainable": 1 14487 }, { 14488 "line": 1712, 14489 "params": [{ 14490 "name": "v1", 14491 "description": "", 14492 "type": "p5.Vector" 14493 }, { 14494 "name": "v2", 14495 "description": "", 14496 "type": "p5.Vector" 14497 }, { 14498 "name": "amt", 14499 "description": "", 14500 "type": "Number" 14501 }, { 14502 "name": "target", 14503 "description": "<p>if undefined a new vector will be created</p>\n", 14504 "type": "p5.Vector" 14505 }], 14506 "static": 1 14507 }, { 14508 "line": 1720, 14509 "params": [{ 14510 "name": "v1", 14511 "description": "", 14512 "type": "p5.Vector" 14513 }, { 14514 "name": "v2", 14515 "description": "", 14516 "type": "p5.Vector" 14517 }, { 14518 "name": "amt", 14519 "description": "", 14520 "type": "Number" 14521 }], 14522 "static": 1, 14523 "return": { 14524 "description": "the lerped value", 14525 "type": "Number" 14526 } 14527 }] 14528 }, { 14529 "file": "src/math/p5.Vector.js", 14530 "line": 1287, 14531 "description": "<p>Return a representation of this vector as a float array. This is only\nfor temporary use. If used in any other fashion, the contents should be\ncopied by using the <b>p5.Vector.<a href=\"#/p5.Vector/copy\">copy()</a></b>
14531 method to copy into your own\narray.</p>\n", 14532 "itemtype": "method", 14533 "name": "array", 14534 "return": { 14535 "description": "an Array with the 3 values", 14536 "type": "Number[]" 14537 }, 14538 "example": ["\n<div class = \"norender\">\n<code>\nfunction setup() {\n let v = createVector(20, 30);\n print(v.array()); // Prints : Array [20, 30, 0]\n}\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nlet v = createVector(10.0, 20.0, 30.0);\nlet f = v.array();\nprint(f[0]); // Prints \"10.0\"\nprint(f[1]); // Prints \"20.0\"\nprint(f[2]); // Prints \"30.0\"\n</code>\n</div>"], 14539 "class": "p5.Vector", 14540 "module": "Math", 14541 "submodule": "Math" 14542 }, { 14543 "file": "src/math/p5.Vector.js", 14544 "line": 1319, 14545 "description": "<p>Equality check against a <a href=\"#/p5.Vector\">p5.Vector</a></p>\n", 14546 "itemtype": "method", 14547 "name": "equals", 14548 "return": { 14549 "description": "whether the vectors are equals", 14550 "type": "Boolean" 14551 }, 14552 "example": ["\n<div class = \"norender\">\n<code>\nlet v1 = createVector(5, 10, 20);\nlet v2 = createVector(5, 10, 20);\nlet v3 = createVector(13, 10, 19);\n\nprint(v1.equals(v2.x, v2.y, v2.z)); // true\nprint(v1.equals(v3.x, v3.y, v3.z)); // false\n</code>\n</div>\n\n<div class=\"norender\">\n<code>\nlet v1 = createVector(10.0, 20.0, 30.0);\nlet v2 = createVector(10.0, 20.0, 30.0);\nlet v3 = createVector(0.0, 0.0, 0.0);\nprint(v1.equals(v2)); // true\nprint(v1.equals(v3)); // false\n</code>\n</div>"], 14553 "class": "p5.Vector", 14554 "module": "Math", 14555 "submodule": "Math", 14556 "overloads": [{ 14557 "line": 1319, 14558 "params": [{ 14559 "name": "x", 14560 "description": "<p>the x component of the vector</p>\n", 14561 "type": "Number", 14562 "optional": true 14563 }, { 14564 "name": "y", 14565 "description": "<p>the y component of the vector</p>\n", 14566 "type": "Number", 14567 "optional": true 14568 }, { 14569 "name": "z", 14570 "description": "<p>the z component of the vector</p>\n", 14571 "type": "Number", 14572 "optional": true 14573 }], 14574 "return": { 14575 "description": "whether the vectors are equals", 14576 "type": "Boolean" 14577 } 14578 }, { 14579 "line": 1349, 14580 "params": [{ 14581 "name": "value", 14582 "description": "<p>the vector to compare</p>\n", 14583 "type": "p5.Vector|Array" 14584 }], 14585 "return": { 14586 "description": "", 14587 "type": "Boolean" 14588 } 14589 }] 14590 }, { 14591 "file": "src/math/p5.Vector.js", 14592 "line": 1374, 14593 "description": "<p>Make a new 2D vector from an angle</p>\n", 14594 "itemtype": "method", 14595 "name": "fromAngle", 14596 "static": 1, 14597 "params": [{ 14598 "name": "angle", 14599 "description": "<p>the desired angle, in radians</p>\n", 14600 "type": "Number" 14601 }, { 14602 "name": "length", 14603 "description": "<p>the length of the new vector (defaults to 1)</p>\n", 14604 "type": "Number", 14605 "optional": true 14606 }], 14607 "return": { 14608 "description": "the new <a href=\"#/p5.Vector\">p5.Vector</a> object", 14609 "type": "p5.Vector" 14610 }, 14611 "example": ["\n<div>\n<code>\nfunction draw() {\n background(200);\n\n // Create a variable, proportional to the mouseX,\n // varying from 0-360, to represent an angle in degrees.\n angleMode(DEGREES);\n let myDegrees = map(mouseX, 0, width, 0, 360);\n\n // Display that variable in an onscreen text.\n // (Note the nfc() function to truncate additional decimal places,\n // and the \"\\xB0\" character for the degree symbol.)\n let readout = 'angle = ' + nfc(myDegrees, 1) + '\\xB0';\n noStroke();\n fill(0);\n text(readout, 5, 15);\n\n // Create a p5.Vector using the fromAngle function,\n // and extract its x and y components.\n let v = p5.Vector.fromAngle(radians(myDegrees), 30);\n let vx = v.x;\n let vy = v.y;\n\n push();\n translate(width / 2, height / 2);\n noFill();\n stroke(150);\n line(0, 0, 30, 0);\n stroke(0);\n line(0, 0, vx, vy);\n pop();\n}\n</code>\n</div>"], 14612 "class": "p5.Vector", 14613 "module": "Math", 14614 "submodule": "Math" 14615 }, { 14616 "file": "src/math/p5.Vector.js", 14617 "line": 1426, 14618 "description": "<p>Make a new 3D vector from a pair of ISO spherical angles</p>\n", 14619 "itemtype": "method", 14620 "name": "fromAngles", 14621 "static": 1, 14622 "params": [{ 14623 "name": "theta", 14624 "description": "<p>the polar angle, in radians (zero is up)</p>\n", 14625 "type": "Number" 14626 }, { 14627 "name": "phi", 14628 "description": "<p>the azimuthal angle, in radians\n (zero is out of the screen)</p>\n", 14629 "type": "Number" 14630 }, { 14631 "name": "length", 14632 "description": "<p>the length of the new vector (defaults to 1)</p>\n", 14633 "type": "Number", 14634 "optional": true 14635 }], 14636 "return": { 14637 "description": "the new <a href=\"#/p5.Vector\">p5.Vector</a> object", 14638 "type": "p5.Vector" 14639 }, 14640 "example": ["\n<div modernizr='webgl'>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n fill(255);\n noStroke();\n}\nfunction draw() {\n background(255);\n\n let t = millis() / 1000;\n\n // add three point lights\n pointLight(color('#f00'), p5.Vector.fromAngles(t * 1.0, t * 1.3, 100));\n pointLight(color('#0f0'), p5.Vector.fromAngles(t * 1.1, t * 1.2, 100));\n pointLight(color('#00f'), p5.Vector.fromAngles(t * 1.2, t * 1.1, 100));\n\n sphere(35);\n}\n</code>\n</div>"], 14641 "class": "p5.Vector", 14642 "module": "Math", 14643 "submodule": "Math" 14644 }, { 14645 "file": "src/math/p5.Vector.js", 14646 "line": 1475, 14647 "description": "<p>Make a new 2D unit vector from a random angle</p>\n", 14648 "itemtype": "method", 14649 "name": "random2D", 14650 "static": 1, 14651 "return": { 14652 "description": "the new <a href=\"#/p5.Vector\">p5.Vector</a> object", 14653 "type": "p5.Vector" 14654 }, 14655 "example": ["\n<div class=\"norender\">\n<code>\nlet v = p5.Vector.random2D();\n// May make v's attributes something like:\n// [0.61554617, -0.51195765, 0.0] or\n// [-0.4695841, -0.
1465514366731, 0.0] or\n// [0.6091097, -0.22805278, 0.0]\nprint(v);\n</code>\n</div>\n\n<div>\n<code>\nfunction setup() {\n frameRate(1);\n}\n\nfunction draw() {\n background(240);\n\n let v0 = createVector(50, 50);\n let v1 = p5.Vector.random2D();\n drawArrow(v0, v1.mult(50), 'black');\n}\n\n// draw an arrow for a vector at a given base position\nfunction drawArrow(base, vec, myColor) {\n push();\n stroke(myColor);\n strokeWeight(3);\n fill(myColor);\n translate(base.x, base.y);\n line(0, 0, vec.x, vec.y);\n rotate(vec.heading());\n let arrowSize = 7;\n translate(vec.mag() - arrowSize, 0);\n triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);\n pop();\n}\n</code>\n</div>"], 14656 "class": "p5.Vector", 14657 "module": "Math", 14658 "submodule": "Math" 14659 }, { 14660 "file": "src/math/p5.Vector.js", 14661 "line": 1528, 14662 "description": "<p>Make a new random 3D unit vector.</p>\n", 14663 "itemtype": "method", 14664 "name": "random3D", 14665 "static": 1, 14666 "return": { 14667 "description": "the new <a href=\"#/p5.Vector\">p5.Vector</a> object", 14668 "type": "p5.Vector" 14669 }, 14670 "example": ["\n<div class=\"norender\">\n<code>\nlet v = p5.Vector.random3D();\n// May make v's attributes something like:\n// [0.61554617, -0.51195765, 0.599168] or\n// [-0.4695841, -0.14366731, -0.8711202] or\n// [0.6091097, -0.22805278, -0.7595902]\nprint(v);\n</code>\n</div>"], 14671 "class": "p5.Vector", 14672 "module": "Math", 14673 "submodule": "Math" 14674 }, { 14675 "file": "src/math/p5.Vector.js", 14676 "line": 1611, 14677 "description": "<p>Multiplies a vector by a scalar and returns a new vector.</p>\n", 14678 "class": "p5.Vector", 14679 "module": "Math", 14680 "submodule": "Math" 14681 }, { 14682 "file": "src/math/p5.Vector.js", 14683 "line": 1638, 14684 "description": "<p>Divides a vector by a scalar and returns a new vector.</p>\n", 14685 "class": "p5.Vector", 14686 "module": "Math", 14687 "submodule": "Math" 14688 }, { 14689 "file": "src/math/p5.Vector.js", 14690 "line": 1665, 14691 "description": "<p>Calculates the dot product of two vectors.</p>\n", 14692 "class": "p5.Vector", 14693 "module": "Math", 14694 "submodule": "Math" 14695 }, { 14696 "file": "src/math/p5.Vector.js", 14697 "line": 1679, 14698 "description": "<p>Calculates the cross product of two vectors.</p>\n", 14699 "class": "p5.Vector", 14700 "module": "Math", 14701 "submodule": "Math" 14702 }, { 14703 "file": "src/math/p5.Vector.js", 14704 "line": 1693, 14705 "description": "<p>Calculates the Euclidean distance between two points (considering a\npoint as a vector object).</p>\n", 14706 "class": "p5.Vector", 14707 "module": "Math", 14708 "submodule": "Math" 14709 }, { 14710 "file": "src/math/p5.Vector.js", 14711 "line": 1708, 14712 "description": "<p>Linear interpolate a vector to another vector and return the result as a\nnew vector.</p>\n", 14713 "class": "p5.Vector", 14714 "module": "Math", 14715 "submodule": "Math" 14716 }, { 14717 "file": "src/math/random.js", 14718 "line": 48, 14719 "description": "<p>Sets the seed value for <a href=\"#/p5/random\">random()</a>.</p>\n<p>By default, <a href=\"#/p5/random\">random()</a> produces different results each time the program\nis run. Set the seed parameter to a constant to return the same\npseudo-random numbers each time the software is run.</p>\n", 14720 "itemtype": "method", 14721 "name": "randomSeed", 14722 "params": [{ 14723 "name": "seed", 14724 "description": "<p>the seed value</p>\n", 14725 "type": "Number" 14726 }], 14727 "example": ["\n<div>\n<code>\nrandomSeed(99);\nfor (let i = 0; i < 100; i++) {\n let r = random(0, 255);\n stroke(r);\n line(i, 0, i, 100);\n}\n</code>\n</div>"], 14728 "alt": "many vertical lines drawn in white, black or grey.", 14729 "class": "p5", 14730 "module": "Math", 14731 "submodule": "Random" 14732 }, { 14733 "file": "src/math/random.js", 14734 "line": 79, 14735 "description": "<p>Return a random floating-point number.</p>\n<p>Takes either 0, 1 or 2 arguments.</p>\n<p>If no argument is given, returns a random number from 0\nup to (but not including) 1.</p>\n<p>If one argument is given and it is a number, returns a random number from 0\nup to (but not including) the number.</p>\n<p>If one argument is given and it is an array, returns a random element from\nthat array.</p>\n<p>If two arguments are given, returns a random number from the\nfirst argument up to (but not including) the second argument.</p>\n", 14736 "itemtype": "method", 14737 "name": "random", 14738 "return": { 14739 "description": "the random number", 14740 "type": "Number" 14741 }, 14742 "example": ["\n<div>\n<code>\nfor (let i = 0; i < 100;
14742 i++) {\n let r = random(50);\n stroke(r * 5);\n line(50, i, 50 + r, i);\n}\n</code>\n</div>\n<div>\n<code>\nfor (let i = 0; i < 100; i++) {\n let r = random(-50, 50);\n line(50, i, 50 + r, i);\n}\n</code>\n</div>\n<div>\n<code>\n// Get a random element from an array using the random(Array) syntax\nlet words = ['apple', 'bear', 'cat', 'dog'];\nlet word = random(words); // select random word\ntext(word, 10, 50); // draw the word\n</code>\n</div>"], 14743 "alt": "100 horizontal lines from center canvas to right. size+fill change each time\n100 horizontal lines from center of canvas. height & side change each render\nword displayed at random. Either apple, bear, cat, or dog", 14744 "class": "p5", 14745 "module": "Math", 14746 "submodule": "Random", 14747 "overloads": [{ 14748 "line": 79, 14749 "params": [{ 14750 "name": "min", 14751 "description": "<p>the lower bound (inclusive)</p>\n", 14752 "type": "Number", 14753 "optional": true 14754 }, { 14755 "name": "max", 14756 "description": "<p>the upper bound (exclusive)</p>\n", 14757 "type": "Number", 14758 "optional": true 14759 }], 14760 "return": { 14761 "description": "the random number", 14762 "type": "Number" 14763 } 14764 }, { 14765 "line": 133, 14766 "params": [{ 14767 "name": "choices", 14768 "description": "<p>the array to choose from</p>\n", 14769 "type": "Array" 14770 }], 14771 "return": { 14772 "description": "the random element from the array", 14773 "type": "*" 14774 } 14775 }] 14776 }, { 14777 "file": "src/math/random.js", 14778 "line": 166, 14779 "description": "<p>Returns a random number fitting a Gaussian, or\n normal, distribution. There is theoretically no minimum or maximum\n value that <a href=\"#/p5/randomGaussian\">randomGaussian()</a> might return. Rather, there is\n just a very low probability that values far from the mean will be\n returned; and a higher probability that numbers near the mean will\n be returned.\n <br><br>\n Takes either 0, 1 or 2 arguments.<br>\n If no args, returns a mean of 0 and standard deviation of 1.<br>\n If one arg, that arg is the mean (standard deviation is 1).<br>\n If two args, first is mean, second is standard deviation.</p>\n", 14780 "itemtype": "method", 14781 "name": "randomGaussian", 14782 "params": [{ 14783 "name": "mean", 14784 "description": "<p>the mean</p>\n", 14785 "type": "Number" 14786 }, { 14787 "name": "sd", 14788 "description": "<p>the standard deviation</p>\n", 14789 "type": "Number" 14790 }], 14791 "return": { 14792 "description": "the random number", 14793 "type": "Number" 14794 }, 14795 "example": ["\n <div>\n <code>\n for (let y = 0; y < 100; y++) {\n let x = randomGaussian(50, 15);\n line(50, y, x, y);\n }\n </code>\n </div>\n <div>\n <code>\n let distribution = new Array(360);\nfunction setup() {\n createCanvas(100, 100);\n for (let i = 0; i < distribution.length; i++) {\n distribution[i] = floor(randomGaussian(0, 15));\n }\n }\nfunction draw() {\n background(204);\n translate(width / 2, width / 2);\n for (let i = 0; i < distribution.length; i++) {\n rotate(TWO_PI / distribution.length);\n stroke(0);\n let dist = abs(distribution[i]);\n line(0, 0, dist, 0);\n }\n }\n </code>\n </div>"], 14796 "alt": "100 horizontal lines from center of canvas. height & side change each render\n black lines radiate from center of canvas. size determined each render", 14797 "class": "p5", 14798 "module": "Math", 14799 "submodule": "Random" 14800 }, { 14801 "file": "src/math/trigonometry.js", 14802 "line": 20, 14803 "description": "<p>The inverse of <a href=\"#/p5/cos\">cos()</a>, returns the arc cosine of a value. This function\nexpects the values in the range of -1 to 1 and values are returned in\nthe range 0 to PI (3.1415927).</p>\n", 14804 "itemtype": "method", 14805 "name": "acos", 14806 "params": [{ 14807 "name": "value", 14808 "description": "<p>the value whose arc cosine is to be returned</p>\n", 14809 "type": "Number" 14810 }], 14811 "return": { 14812 "description": "the arc cosine of the given value", 14813 "type": "Number" 14814 }, 14815 "example": ["\n<div class= ânorender\">\n<code>\nlet a = PI;\nlet c = cos(a);\nlet ac = acos(c);\n// Prints: \"3.1415927 : -1.0 : 3.1415927\"\nprint(a + ' : ' + c + ' : ' + ac);\n</code>\n</div>\n\n<div class= ânorender\">\n<code>\nlet a = PI + PI / 4.0;\nlet c = cos(a);\nlet ac = acos(c);\n// Prints: \"3.926991 : -0.70710665 : 2.3561943\"\nprint(a + ' : ' + c + ' : ' + ac);\n</code>\n</div>"], 14816 "class": "p5", 14817 "module": "Math", 14818 "submodule": "Trigonometry" 14819 }, { 14820 "file": "src/math/trigonometry.js", 14821 "line": 54, 14822 "description": "<p>The inverse of <a href=\"#/p5/sin\">sin()</a>, returns the arc sine of a value. This function\nexpects the values in the range of -1 to 1 and values are returned\nin the range -PI/2 to PI/2.</p>\n", 14823 "itemtype": "method", 14824 "name": "asin", 14825 "params": [{ 14826 "name": "value", 14827 "description": "<p>the value whose arc sine is to be returned</p>\n", 14828 "type": "Number" 14829 }], 14830 "return": { 14831 "description": "the arc sine of the given value", 14832 "type": "Number" 14833 }, 14834 "example": ["\n<div class= ânorender\">\n<code>\nlet a = PI + PI / 3;\nlet s = sin(a);\nlet as = asin(s);\n// Prints: \"1.0471976 : 0.86602545 : 1.0471976\"\nprint(a + ' : ' + s + ' : ' + as);\n</code>\n</div>\n\n<div class= ânorender\">\n<code>\nlet a = PI + PI / 3.0;\nlet s = sin(a);\nlet as = asin(s);\n// Prints: \"4.1887903 : -0.86602545 : -1.0471976\"\nprint(a + ' : ' + s + ' : ' + as);\n</code>\n</div>\n"], 14835 "class": "p5", 14836 "module": "Math", 14837 "submodule": "Trigonometry" 14838 }, { 14839 "file": "src/math/trigonometry.js", 14840 "line": 89, 14841 "description": "<p>The inverse of <a href=\"#/p5/tan\">tan()</a>, returns the arc tangent of a value. This function\nexpects the values in the range of -Infinity to Infinity (exclusive) and\nvalues are returned in the range -PI/2 to PI/2.</p>\n", 14842 "itemtype": "method", 14843 "name": "atan", 14844 "params": [{ 14845 "name": "value", 14846 "description": "<p>the value whose arc tangent is to be returned</p>\n", 14847 "type": "Number" 14848 }], 14849 "return": { 14850 "description": "the arc tangent of the given value", 14851 "type": "Number" 14852 }, 14853 "example": ["\n<div class= ânorender\">\n<code>\nlet a = PI + PI / 3;\nlet t = tan(a);\nlet at = atan(t);\n// Prints: \"1.0471976 : 1.7320509 : 1.0471976\"\nprint(a + ' : ' + t + ' : ' + at);\n</code>\n</div>\n\n<div class= ânorender\">\n<code>\nlet a = PI + PI / 3.0;\nlet t = tan(a);\nlet at = atan(t);\n// Prints: \"4.1887903 : 1.7320513 : 1.0471977\"\nprint(a + ' : ' + t + ' : ' + at);\n</code>\n</div>\n"], 14854 "class": "p5", 14855 "module": "Math", 14856 "submodule": "Trigonometry" 14857 }, { 14858 "file": "src/math/trigonometry.js", 14859 "line": 124, 14860 "description": "<p>Calculates the angle (in radians) from a specified point to the coordinate\norigin as measured from the positive x-axis. Values are returned as a\nfloat in the range from PI to -PI. The atan2<a href=\"#/p5/\">()</a> function is most often used\nfor orienting geometry to the position of the cursor.\n<br><br>\nNote: The y-coordinate of the point is the first parameter, and the\nx-coordinate is the second parameter, due the the structure of calculating\nthe tangent.</p>\n", 14861 "itemtype": "method", 14862 "name": "atan2", 14863 "params": [{ 14864 "name": "y", 14865 "description": "<p>y-coordinate of the point</p>\n", 14866 "type": "Number" 14867 }, { 14868 "name": "x", 14869 "description": "<p>x-coordinate of the point</p>\n", 14870 "type": "Number" 14871 }], 14872 "return": { 14873 "description": "the arc tangent of the given point", 14874 "type": "Number" 14875 }, 14876 "example": ["\n<div>\n<code>\nfunction draw() {\n background(204);\n translate(width / 2, height / 2);
14876\n let a = atan2(mouseY - height / 2, mouseX - width / 2);\n rotate(a);\n rect(-30, -5, 60, 10);\n}\n</code>\n</div>"], 14877 "alt": "60 by 10 rect at center of canvas rotates with mouse movements", 14878 "class": "p5", 14879 "module": "Math", 14880 "submodule": "Trigonometry" 14881 }, { 14882 "file": "src/math/trigonometry.js", 14883 "line": 160, 14884 "description": "<p>Calculates the cosine of an angle. This function takes into account the\ncurrent <a href=\"#/p5/angleMode\">angleMode</a>. Values are returned in the range -1 to 1.</p>\n", 14885 "itemtype": "method", 14886 "name": "cos", 14887 "params": [{ 14888 "name": "angle", 14889 "description": "<p>the angle</p>\n", 14890 "type": "Number" 14891 }], 14892 "return": { 14893 "description": "the cosine of the angle", 14894 "type": "Number" 14895 }, 14896 "example": ["\n<div>\n<code>\nlet a = 0.0;\nlet inc = TWO_PI / 25.0;\nfor (let i = 0; i < 25; i++) {\n line(i * 4, 50, i * 4, 50 + cos(a) * 40.0);\n a = a + inc;\n}\n</code>\n</div>"], 14897 "alt": "vertical black lines form wave patterns, extend-down on left and right side", 14898 "class": "p5", 14899 "module": "Math", 14900 "submodule": "Trigonometry" 14901 }, { 14902 "file": "src/math/trigonometry.js", 14903 "line": 188, 14904 "description": "<p>Calculates the sine of an angle. This function takes into account the\ncurrent <a href=\"#/p5/angleMode\">angleMode</a>. Values are returned in the range -1 to 1.</p>\n", 14905 "itemtype": "method", 14906 "name": "sin", 14907 "params": [{ 14908 "name": "angle", 14909 "description": "<p>the angle</p>\n", 14910 "type": "Number" 14911 }], 14912 "return": { 14913 "description": "the sine of the angle", 14914 "type": "Number" 14915 }, 14916 "example": ["\n<div>\n<code>\nlet a = 0.0;\nlet inc = TWO_PI / 25.0;\nfor (let i = 0; i < 25; i++) {\n line(i * 4, 50, i * 4, 50 + sin(a) * 40.0);\n a = a + inc;\n}\n</code>\n</div>"], 14917 "alt": "vertical black lines extend down and up from center to form wave pattern", 14918 "class": "p5", 14919 "module": "Math", 14920 "submodule": "Trigonometry" 14921 }, { 14922 "file": "src/math/trigonometry.js", 14923 "line": 216, 14924 "description": "<p>Calculates the tangent of an angle. This function takes into account\nthe current <a href=\"#/p5/angleMode\">angleMode</a>. Values are returned in the range -1 to 1.</p>\n", 14925 "itemtype": "method", 14926 "name": "tan", 14927 "params": [{ 14928 "name": "angle", 14929 "description": "<p>the angle</p>\n", 14930 "type": "Number" 14931 }], 14932 "return": { 14933 "description": "the tangent of the angle", 14934 "type": "Number" 14935 }, 14936 "example": ["\n<div>\n<code>\nlet a = 0.0;\nlet inc = TWO_PI / 50.0;\nfor (let i = 0; i < 100; i = i + 2) {\n line(i, 50, i, 50 + tan(a) * 2.0);\n a = a + inc;\n}\n</code>"], 14937 "alt": "vertical black lines end down and up from center to form spike pattern", 14938 "class": "p5", 14939 "module": "Math", 14940 "submodule": "Trigonometry" 14941 }, { 14942 "file": "src/math/trigonometry.js", 14943 "line": 244, 14944 "description": "<p>Converts a radian measurement to its corresponding value in degrees.\nRadians and degrees are two ways of measuring the same thing. There are\n360 degrees in a circle and 2*PI radians in a circle. For example,\n90° = PI/2 = 1.5707964. This function does not take into account the\ncurrent <a href=\"#/p5/angleMode\">angleMode</a>.</p>\n", 14945 "itemtype": "method", 14946 "name": "degrees", 14947 "params": [{ 14948 "name": "radians", 14949 "description": "<p>the radians value to convert to degrees</p>\n", 14950 "type": "Number" 14951 }], 14952 "return": { 14953 "description": "the converted angle", 14954 "type": "Number" 14955 }, 14956 "example": ["\n<div class= ânorender\">\n<code>\nlet rad = PI / 4;\nlet deg = degrees(rad);\nprint(rad + ' radians is ' + deg + ' degrees');\n// Prints: 0.7853981633974483 radians is 45 degrees\n</code>\n</div>\n"], 14957 "class": "p5", 14958 "module": "Math", 14959 "submodule": "Trigonometry" 14960 }, { 14961 "file": "src/math/trigonometry.js", 14962 "line": 271, 14963 "description": "<p>Converts a degree measurement to its corresponding value in radians.\nRadians and degrees are two ways of measuring the same thing. There are\n360 degrees in a circle and 2*PI radians in a circle. For example,\n90° = PI/2 = 1.5707964. This function does not take into account the\ncurrent <a href=\"#/p5/angleMode\">angleMode</a>.</p>\n", 14964 "itemtype": "method", 14965 "name": "radians", 14966 "params": [{ 14967 "name": "degrees", 14968 "description": "<p>the degree value to convert to radians</p>\n", 14969 "type": "Number" 14970 }], 14971 "return": { 14972 "description": "the converted angle", 14973 "type": "Number" 14974 }, 14975 "example": ["\n<div class= ânorender\">\n<code>\nlet deg = 45.0;\nlet rad = radians(deg);\nprint(deg + ' degrees is ' + rad + ' radians');\n// Prints: 45 degrees is 0.7853981633974483 radians\n</code>\n</div>"], 14976 "class": "p5", 14977 "module": "Math", 14978 "submodule": "Trigonometry" 14979 }, { 14980 "file": "src/math/trigonometry.js", 14981 "line": 296, 14982 "description": "<p>Sets the current mode of p5 to given mode. Default mode is RADIANS.</p>\n", 14983 "itemtype": "method", 14984 "name": "angleMode", 14985 "params": [{ 14986 "name": "mode", 14987 "description": "<p>either RADIANS or DEGREES</p>\n", 14988 "type": "Constant" 14989 }], 14990 "example": ["\n<div>\n<code>\nfunction draw() {\n background(204);\n angleMode(DEGREES);
14990 // Change the mode to DEGREES\n let a = atan2(mouseY - height / 2, mouseX - width / 2);\n translate(width / 2, height / 2);\n push();\n rotate(a);\n rect(-20, -5, 40, 10); // Larger rectangle is rotating in degrees\n pop();\n angleMode(RADIANS); // Change the mode to RADIANS\n rotate(a); // variable a stays the same\n rect(-40, -5, 20, 10); // Smaller rectangle is rotating in radians\n}\n</code>\n</div>"], 14991 "alt": "40 by 10 rect in center rotates with mouse moves. 20 by 10 rect moves faster.", 14992 "class": "p5", 14993 "module": "Math", 14994 "submodule": "Trigonometry" 14995 }, { 14996 "file": "src/typography/attributes.js", 14997 "line": 13, 14998 "description": "<p>Sets the current alignment for drawing text. Accepts two\narguments: horizAlign (LEFT, CENTER, or RIGHT) and\nvertAlign (TOP, BOTTOM, CENTER, or BASELINE).</p>\n<p>The horizAlign parameter is in reference to the x value\nof the <a href=\"#/p5/text\">text()</a> function, while the vertAlign parameter is\nin reference to the y value.</p>\n<p>So if you write textAlign(LEFT), you are aligning the left\nedge of your text to the x value you give in <a href=\"#/p5/text\">text()</a>. If you\nwrite textAlign(RIGHT, TOP), you are aligning the right edge\nof your text to the x value and the top of edge of the text\nto the y value.</p>\n", 14999 "itemtype": "method", 15000 "name": "textAlign", 15001 "chainable": 1, 15002 "example": ["\n<div>\n<code>\ntextSize(16);\ntextAlign(RIGHT);\ntext('ABCD', 50, 30);\ntextAlign(CENTER);\ntext('EFGH', 50, 50);\ntextAlign(LEFT);\ntext('IJKL', 50, 70);\n</code>\n</div>\n\n<div>\n<code>\ntextSize(16);\nstrokeWeight(0.5);\n\nline(0, 12, width, 12);\ntextAlign(CENTER, TOP);\ntext('TOP', 0, 12, width);\n\nline(0, 37, width, 37);\ntextAlign(CENTER, CENTER);\ntext('CENTER', 0, 37, width);\n\nline(0, 62, width, 62);\ntextAlign(CENTER, BASELINE);\ntext('BASELINE', 0, 62, width);\n\nline(0, 87, width, 87);\ntextAlign(CENTER, BOTTOM);\ntext('BOTTOM', 0, 87, width);\n</code>\n</div>"], 15003 "alt": "Letters ABCD displayed at top right, EFGH at center and IJKL at bottom left.\nThe names of the four vertical alignments rendered each showing that alignment's placement relative to a horizontal line.", 15004 "class": "p5", 15005 "module": "Typography", 15006 "submodule": "Attributes", 15007 "overloads": [{ 15008 "line": 13, 15009 "params": [{ 15010 "name": "horizAlign", 15011 "description": "<p>horizontal alignment, either LEFT,\n CENTER, or RIGHT</p>\n", 15012 "type": "Constant" 15013 }, { 15014 "name": "vertAlign", 15015 "description": "<p>vertical alignment, either TOP,\n BOTTOM, CENTER, or BASELINE</p>\n", 15016 "type": "Constant", 15017 "optional": true 15018 }], 15019 "chainable": 1 15020 }, { 15021 "line": 75, 15022 "params": [], 15023 "return": { 15024 "description": "", 15025 "type": "Object" 15026 } 15027 }] 15028 }, { 15029 "file": "src/typography/attributes.js", 15030 "line": 84, 15031 "description": "<p>Sets/gets the spacing, in pixels, between lines of text. This\nsetting will be used in all subsequent calls to the <a href=\"#/p5/text\">text()</a> function.</p>\n", 15032 "itemtype": "method", 15033 "name": "textLeading", 15034 "chainable": 1, 15035 "example": ["\n<div>\n<code>\n// Text to display. The \"\\n\" is a \"new line\" character\nlet lines = 'L1\\nL2\\nL3';\ntextSize(12);\n\ntextLeading(10); // Set leading to 10\ntext(lines, 10, 25);\n\ntextLeading(20); // Set leading to 20\ntext(lines, 40, 25);\n\ntextLeading(30); // Set leading to 30\ntext(lines, 70, 25);\n</code>\n</div>"], 15036 "alt": "set L1 L2 & L3 displayed vertically 3 times. spacing increases for each set", 15037 "class": "p5", 15038 "module": "Typography", 15039 "submodule": "Attributes", 15040 "overloads": [{ 15041 "line": 84, 15042 "params": [{ 15043 "name": "leading", 15044 "description": "<p>the size in pixels for spacing between lines</p>\n", 15045 "type": "Number" 15046 }], 15047 "chainable": 1 15048 }, { 15049 "line": 113, 15050 "params": [], 15051 "return": { 15052 "description": "", 15053 "type": "Number" 15054 } 15055 }] 15056 }, { 15057 "file": "src/typography/attributes.js", 15058 "line": 122, 15059 "description": "<p>Sets/gets the current font size. This size will be used in all subsequent\ncalls to the <a href=\"#/p5/text\">text()</a> function. Font size is measured in pixels.</p>\n", 15060 "itemtype": "method", 15061 "name": "textSize", 15062 "chainable": 1, 15063 "example": ["\n<div>\n<code>\ntextSize(12);\ntext('Font Size 12', 10, 30);\ntextSize(14);\ntext('Font Size 14', 10, 60);\ntextSize(16);\ntext('Font Size 16', 10, 90);\n</code>\n</div>"], 15064 "alt": "Font Size 12 displayed small, Font Size 14 medium & Font Size 16 large", 15065 "class": "p5", 15066 "module": "Typography", 15067 "submodule": "Attributes", 15068 "overloads": [{ 15069 "line": 122, 15070 "params": [{ 15071 "name": "theSize", 15072 "description": "<p>the size of the letters in units of pixels</p>\n", 15073 "type": "Number" 15074 }], 15075 "chainable": 1 15076 }, { 15077 "line": 145, 15078 "params": [], 15079 "return": { 15080 "description": "", 15081 "type": "Number" 15082 } 15083 }] 15084 }, { 15085 "file": "src/typography/attributes.js", 15086 "line": 154, 15087 "description": "<p>Sets/gets the style of the text for system fonts to NORMAL, ITALIC, BOLD or BOLDITALIC.\nNote: this may be is overridden by CSS styling. For non-system fonts\n(opentype, truetype, etc.) please load styled fonts instead.</p>\n", 15088 "itemtype": "method", 15089 "name": "textStyle", 15090 "chainable": 1, 15091 "example": ["\n<div>\n<code>\nstrokeWeight(0);\ntextSize(12);\ntextStyle(NORMAL);\ntext('Font Style Normal', 10, 15);\ntextStyle(ITALIC);\ntext('Font Style Italic', 10, 40);\ntextStyle(BOLD);\ntext('Font Style Bold', 10, 65);\ntextStyle(BOLDITALIC);\ntext('Font Style Bold Italic', 10, 90);\n</code>\n</div>"], 15092 "alt": "words Font Style Normal displayed normally, Italic in italic, bold in bold and bold italic in bold italics.", 15093 "class": "p5", 15094 "module": "Typography", 15095 "submodule": "Attributes", 15096 "overloads": [{ 15097 "line": 154, 15098 "params": [{ 15099 "name": "theStyle", 15100 "description": "<p>styling for text, either NORMAL,\n ITALIC, BOLD or BOLDITALIC</p>\n", 15101 "type": "Constant" 15102 }], 15103 "chainable": 1 15104 }, { 15105 "line": 182, 15106 "params": [], 15107 "return": { 15108 "description": "", 15109 "type": "String" 15110 } 15111 }] 15112 }, { 15113 "file": "src/typography/attributes.js", 15114 "line": 191, 15115 "description": "<p>
15115Calculates and returns the width of any character or text string.</p>\n", 15116 "itemtype": "method", 15117 "name": "textWidth", 15118 "params": [{ 15119 "name": "theText", 15120 "description": "<p>the String of characters to measure</p>\n", 15121 "type": "String" 15122 }], 15123 "return": { 15124 "description": "", 15125 "type": "Number" 15126 }, 15127 "example": ["\n<div>\n<code>\ntextSize(28);\n\nlet aChar = 'P';\nlet cWidth = textWidth(aChar);\ntext(aChar, 0, 40);\nline(cWidth, 0, cWidth, 50);\n\nlet aString = 'p5.js';\nlet sWidth = textWidth(aString);\ntext(aString, 0, 85);\nline(sWidth, 50, sWidth, 100);\n</code>\n</div>"], 15128 "alt": "Letter P and p5.js are displayed with vertical lines at end. P is wide", 15129 "class": "p5", 15130 "module": "Typography", 15131 "submodule": "Attributes" 15132 }, { 15133 "file": "src/typography/attributes.js", 15134 "line": 226, 15135 "description": "<p>Returns the ascent of the current font at its current size. The ascent\nrepresents the distance, in pixels, of the tallest character above\nthe baseline.</p>\n", 15136 "itemtype": "method", 15137 "name": "textAscent", 15138 "return": { 15139 "description": "", 15140 "type": "Number" 15141 }, 15142 "example": ["\n<div>\n<code>\nlet base = height * 0.75;\nlet scalar = 0.8; // Different for each font\n\ntextSize(32); // Set initial text size\nlet asc = textAscent() * scalar; // Calc ascent\nline(0, base - asc, width, base - asc);\ntext('dp', 0, base); // Draw text on baseline\n\ntextSize(64); // Increase text size\nasc = textAscent() * scalar; // Recalc ascent\nline(40, base - asc, width, base - asc);\ntext('dp', 40, base); // Draw text on baseline\n</code>\n</div>"], 15143 "class": "p5", 15144 "module": "Typography", 15145 "submodule": "Attributes"
15146 }, { 15147 "file": "src/typography/attributes.js", 15148 "line": 255, 15149 "description": "<p>Returns the descent of the current font at its current size. The descent\nrepresents the distance, in pixels, of the character with the longest\ndescender below the baseline.</p>\n", 15150 "itemtype": "method", 15151 "name": "textDescent", 15152 "return": { 15153 "description": "", 15154 "type": "Number" 15155 }, 15156 "example": ["\n<div>\n<code>\nlet base = height * 0.75;\nlet scalar = 0.8; // Different for each font\n\ntextSize(32); // Set initial text size\nlet desc = textDescent() * scalar; // Calc ascent\nline(0, base + desc, width, base + desc);\ntext('dp', 0, base); // Draw text on baseline\n\ntextSize(64); // Increase text size\ndesc = textDescent() * scalar; // Recalc ascent\nline(40, base + desc, width, base + desc);\ntext('dp', 40, base); // Draw text on baseline\n</code>\n</div>"], 15157 "class": "p5", 15158 "module": "Typography", 15159 "submodule": "Attributes"
15160 }, { 15161 "file": "src/typography/attributes.js", 15162 "line": 284, 15163 "description": "<p>Helper function to measure ascent and descent.</p>\n", 15164 "class": "p5", 15165 "module": "Typography", 15166 "submodule": "Attributes" 15167 }, { 15168 "file": "src/typography/loading_displaying.js", 15169 "line": 16, 15170 "description": "<p>Loads an opentype font file (.otf, .ttf) from a file or a URL,\nand returns a PFont Object. This method is asynchronous,\nmeaning it may not finish before the next line in your sketch\nis executed.\n<br><br>\nThe path to the font should be relative to the HTML file\nthat links in your sketch. Loading fonts from a URL or other\nremote location may be blocked due to your browser's built-in\nsecurity.</p>\n", 15171 "itemtype": "method", 15172 "name": "loadFont", 15173 "params": [{ 15174 "name": "path", 15175 "description": "<p>name of the file or url to load</p>\n", 15176 "type": "String" 15177 }, { 15178 "name": "callback", 15179 "description": "<p>function to be executed after\n <a href=\"#/p5/loadFont\">loadFont()</a> completes</p>\n", 15180 "type": "Function", 15181 "optional": true 15182 }, { 15183 "name": "onError", 15184 "description": "<p>function to be executed if\n an error occurs</p>\n", 15185 "type": "Function", 15186 "optional": true 15187 }], 15188 "return": { 15189 "description": "<a href=\"#/p5.Font\">p5.Font</a> object", 15190 "type": "p5.Font" 15191 }, 15192 "example": ["\n\n<p>Calling loadFont() inside <a href=\"#/p5/preload\">preload()</a> guarantees that the load\noperation will have completed before <a href=\"#/p5/setup\">setup()</a> and <a href=\"#/p5/draw\">draw()</a> are called.</p>\n\n<div><code>\nlet myFont;\nfunction preload() {\n myFont = loadFont('assets/AvenirNextLTPro-Demi.otf');\n}\n\nfunction setup() {\n fill('#ED225D');\n textFont(myFont);\n textSize(36);\n text('p5*js', 10, 50);\n}\n</code></div>\n\nOutside of <a href=\"#/p5/preload\">preload()</a>, you may supply a callback function to handle the\nobject:\n\n<div><code>\nfunction setup() {\n loadFont('assets/AvenirNextLTPro-Demi.otf', drawText);\n}\n\nfunction drawText(font) {\n fill('#ED225D');\n textFont(font, 36);\n text('p5*js', 10, 50);\n}\n</code></div>\n\n<p>You can also use the font filename string (without the file extension) to style other HTML\nelements.</p>\n\n<div><code>\nfunction preload() {\n loadFont('assets/Avenir.otf');\n}\n\nfunction setup() {\n let myDiv = createDiv('hello there');\n myDiv.style('font-family', 'Avenir');\n}\n</code></div>"], 15193 "alt": "p5*js in p5's theme dark pink\np5*js in p5's theme dark pink", 15194 "class": "p5", 15195 "module": "Typography", 15196 "submodule": "Loading & Displaying" 15197 }, { 15198 "file": "src/typography/loading_displaying.js", 15199 "line": 143, 15200 "description": "<p>Draws text to the screen. Displays the information specified in the first\nparameter on the screen in the position specified by the additional\nparameters. A default font will be used unless a font is set with the\n<a href=\"#/p5/textFont\">textFont()</a> function and a default size will be used unless a font is set\nwith <a href=\"#/p5/textSize\">textSize()</a>. Change the color of the text with the <a href=\"#/p5/fill\">fill()</a> function.\nChange the outline of the text with the <a href=\"#/p5/stroke\">stroke()</a> and <a href=\"#/p5/strokeWeight\">
15200strokeWeight()</a>\nfunctions.\n<br><br>\nThe text displays in relation to the <a href=\"#/p5/textAlign\">textAlign()</a> function, which gives the\noption to draw to the left, right, and center of the coordinates.\n<br><br>\nThe x2 and y2 parameters define a rectangular area to display within and\nmay only be used with string data. When these parameters are specified,\nthey are interpreted based on the current <a href=\"#/p5/rectMode\">rectMode()</a> setting. Text that\ndoes not fit completely within the rectangle specified will not be drawn\nto the screen. If x2 and y2 are not specified, the baseline alignment is the\ndefault, which means that the text will be drawn upwards from x and y.\n<br><br>\n<b>WEBGL</b>: Only opentype/truetype fonts are supported. You must load a font using the\n<a href=\"#/p5/loadFont\">loadFont()</a> method (see the example above).\n<a href=\"#/p5/stroke\">stroke()</a> currently has no effect in webgl mode.</p>\n", 15201 "itemtype": "method", 15202 "name": "text", 15203 "params": [{ 15204 "name": "str", 15205 "description": "<p>the alphanumeric\n symbols to be displayed</p>\n", 15206 "type": "String|Object|Array|Number|Boolean" 15207 }, { 15208 "name": "x", 15209 "description": "<p>x-coordinate of text</p>\n", 15210 "type": "Number" 15211 }, { 15212 "name": "y", 15213 "description": "<p>y-coordinate of text</p>\n", 15214 "type": "Number" 15215 }, { 15216 "name": "x2", 15217 "description": "<p>by default, the width of the text box,\n see <a href=\"#/p5/rectMode\">rectMode()</a> for more info</p>\n", 15218 "type": "Number", 15219 "optional": true 15220 }, { 15221 "name": "y2", 15222 "description": "<p>by default, the height of the text box,\n see <a href=\"#/p5/rectMode\">rectMode()</a> for more info</p>\n", 15223 "type": "Number", 15224 "optional": true 15225 }], 15226 "chainable": 1, 15227 "example": ["\n<div>\n<code>\ntextSize(32);\ntext('word', 10, 30);\nfill(0, 102, 153);\ntext('word', 10, 60);\nfill(0, 102, 153, 51);\ntext('word', 10, 90);\n</code>\n</div>\n<div>\n<code>\nlet s = 'The quick brown fox jumped over the lazy dog.';\nfill(50);\ntext(s, 10, 10, 70, 80); // Text wraps within text box\n</code>\n</div>\n\n<div modernizr='webgl'>\n<code>\nlet avenir;\nfunction preload() {\n avenir = loadFont('assets/Avenir.otf');\n}\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n textFont(avenir);\n textSize(width / 3);\n textAlign(CENTER, CENTER);\n}\nfunction draw() {\n background(0);\n let time = millis();\n rotateX(time / 1000);\n rotateZ(time / 1234);\n text('p5.js', 0, 0);\n}\n</code>\n</div>"], 15228 "alt": "'word' displayed 3 times going from black, blue to translucent blue\nThe quick brown fox jumped over the lazy dog.\nthe text 'p5.js' spinning in 3d", 15229 "class": "p5", 15230 "module": "Typography", 15231 "submodule": "Loading & Displaying" 15232 }, { 15233 "file": "src/typography/loading_displaying.js", 15234 "line": 230, 15235 "description": "<p>Sets the current font that will be drawn with the <a href=\"#/p5/text\">text()</a> function.\n<br><br>\n<b>WEBGL</b>: Only fonts loaded via <a href=\"#/p5/loadFont\">loadFont()</a> are supported.</p>\n", 15236 "itemtype": "method", 15237 "name": "textFont", 15238 "return": { 15239 "description": "the current font", 15240 "type": "Object" 15241 }, 15242 "example": ["\n<div>\n<code>\nfill(0);\ntextSize(12);\ntextFont('Georgia');\ntext('Georgia', 12, 30);\ntextFont('Helvetica');\ntext('Helvetica', 12, 60);\n</code>\n</div>\n<div>\n<code>\nlet fontRegular, fontItalic, fontBold;\nfunction preload() {\n fontRegular = loadFont('assets/Regular.otf');\n fontItalic = loadFont('assets/Italic.ttf');\n fontBold = loadFont('assets/Bold.ttf');\n}\nfunction setup() {\n background(210);\n fill(0)\n .strokeWeight(0)\n .textSize(10);\n textFont(fontRegular);\n text('Font Style Normal', 10, 30);\n textFont(fontItalic);\n text('Font Style Italic', 10, 50);\n textFont(fontBold);\n text('Font Style Bold', 10, 70);\n}\n</code>\n</div>"], 15243 "alt": "words Font Style Normal displayed normally, Italic in italic and bold in bold", 15244 "class": "p5", 15245 "module": "Typography", 15246 "submodule": "Loading & Displaying", 15247 "overloads": [{ 15248 "line": 230, 15249 "params": [], 15250 "return": { 15251 "description": "the current font", 15252 "type": "Object" 15253 } 15254 }, { 15255 "line": 275, 15256 "params": [{ 15257 "name": "font", 15258 "description": "<p>a font loaded via <a href=\"#/p5/loadFont\">loadFont()</a>, or a String\nrepresenting a <a href=\"https://mzl.la/2dOw8WD\">web safe font</a> (a font\nthat is generally available across all systems)</p>\n", 15259 "type": "Object|String" 15260 }, { 15261 "name": "size", 15262 "description": "<p>the font size to use</p>\n", 15263 "type": "Number", 15264 "optional": true 15265 }], 15266 "chainable": 1 15267 }] 15268 }, { 15269 "file": "src/typography/p5.Font.js", 15270 "line": 25, 15271 "description": "<p>Underlying opentype font implementation</p>\n", 15272 "itemtype": "property", 15273 "name": "font", 15274 "class": "p5.Font", 15275 "module": "Typography", 15276 "submodule": "Font" 15277 }, { 15278 "file": "src/typography/p5.Font.js", 15279 "line": 32, 15280 "description": "<p>
15280Returns a tight bounding box for the given text string using this\nfont (currently only supports single lines)</p>\n", 15281 "itemtype": "method", 15282 "name": "textBounds", 15283 "params": [{ 15284 "name": "line", 15285 "description": "<p>a line of text</p>\n", 15286 "type": "String" 15287 }, { 15288 "name": "x", 15289 "description": "<p>x-position</p>\n", 15290 "type": "Number" 15291 }, { 15292 "name": "y", 15293 "description": "<p>y-position</p>\n", 15294 "type": "Number" 15295 }, { 15296 "name": "fontSize", 15297 "description": "<p>font size to use (optional) Default is 12.</p>\n", 15298 "type": "Number", 15299 "optional": true 15300 }, { 15301 "name": "options", 15302 "description": "<p>opentype options (optional)\n opentype fonts contains alignment and baseline options.\n Default is 'LEFT' and 'alphabetic'</p>\n", 15303 "type": "Object", 15304 "optional": true 15305 }], 15306 "return": { 15307 "description": "a rectangle object with properties: x, y, w, h", 15308 "type": "Object" 15309 }, 15310 "example": ["\n<div>\n<code>\nlet font;\nlet textString = 'Lorem ipsum dolor sit amet.';\nfunction preload() {\n font = loadFont('./assets/Regular.otf');\n}\nfunction setup() {\n background(210);\n\n let bbox = font.textBounds(textString, 10, 30, 12);\n fill(255);\n stroke(0);\n rect(bbox.x, bbox.y, bbox.w, bbox.h);\n fill(0);\n noStroke();\n\n textFont(font);\n textSize(12);\n text(textString, 10, 30);\n}\n</code>\n</div>"], 15311 "alt": "words Lorem ipsum dol go off canvas and contained by white bounding box", 15312 "class": "p5.Font", 15313 "module": "Typography", 15314 "submodule": "Font" 15315 }, { 15316 "file": "src/typography/p5.Font.js", 15317 "line": 156, 15318 "description": "<p>Computes an array of points following the path for specified text</p>\n", 15319 "itemtype": "method", 15320 "name": "textToPoints", 15321 "params": [{ 15322 "name": "txt", 15323 "description": "<p>a line of text</p>\n", 15324 "type": "String" 15325 }, { 15326 "name": "x", 15327 "description": "<p>x-position</p>\n", 15328 "type": "Number" 15329 }, { 15330 "name": "y", 15331 "description": "<p>y-position</p>\n", 15332 "type": "Number" 15333 }, { 15334 "name": "fontSize", 15335 "description": "<p>font size to use (optional)</p>\n", 15336 "type": "Number" 15337 }, { 15338 "name": "options", 15339 "description": "<p>an (optional) object that can contain:</p>\n<p><br>sampleFactor - the ratio of path-length to number of samples\n(default=.25); higher values yield more points and are therefore\nmore precise</p>\n<p><br>simplifyThreshold - if set to a non-zero value, collinear points will be\nbe removed from the polygon; the value represents the threshold angle to use\nwhen determining whether two edges are collinear</p>\n", 15340 "type": "Object", 15341 "optional": true 15342 }], 15343 "return": { 15344 "description": "an array of points, each with x, y, alpha (the path angle)", 15345 "type": "Array" 15346 }, 15347 "example": ["\n<div>\n<code>\nlet font;\nfunction preload() {\n font = loadFont('./assets/Avenir.otf');\n}\n\nlet points;\nlet bounds;\nfunction setup() {\n createCanvas(100, 100);\n stroke(0);\n fill(255, 104, 204);\n\n points = font.textToPoints('p5', 0, 0, 10, {\n sampleFactor: 5,\n simplifyThreshold: 0\n });\n bounds = font.textBounds(' p5 ', 0, 0, 10);\n}\n\nfunction draw() {\n background(255);\n beginShape();\n translate(-bounds.x * width / bounds.w, -bounds.y * height / bounds.h);\n for (let i = 0; i < points.length; i++) {\n let p = points[i];\n vertex(\n p.x * width / bounds.w +\n sin(20 * p.y / bounds.h + millis() / 1000) * width / 30,\n p.y * height / bounds.h\n );\n }\n endShape(CLOSE);\n}\n</code>\n</div>\n"], 15348 "class": "p5.Font", 15349 "module": "Typography", 15350 "submodule": "Font" 15351 }, { 15352 "file": "src/utilities/array_functions.js", 15353 "line": 12, 15354 "description": "<p>Adds a value to the end of an array. Extends the length of\nthe array by one. Maps to Array.push().</p>\n", 15355 "itemtype": "method", 15356 "name": "append", 15357 "deprecated": true, 15358 "deprecationMessage": "Use <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push\">array.push(value)</a> instead.", 15359 "params": [{ 15360 "name": "array", 15361 "description": "<p>Array to append</p>\n", 15362 "type": "Array" 15363 }, { 15364 "name": "value", 15365 "description": "<p>to be added to the Array</p>\n", 15366 "type": "Any" 15367 }], 15368 "return": { 15369 "description": "the array that was appended to", 15370 "type": "Array" 15371 }, 15372 "example": ["\n<div class='norender'><code>\nfunction setup() {\n var myArray = ['Mango', 'Apple', 'Papaya'];\n print(myArray); // ['Mango', 'Apple', 'Papaya']\n\n append(myArray, 'Peach');\n print(myArray); // ['Mango', 'Apple', 'Papaya', 'Peach']\n}\n</code></div>"], 15373 "class": "p5", 15374 "module": "Data", 15375 "submodule": "Array Functions" 15376 }, { 15377 "file": "src/utilities/array_functions.js", 15378 "line": 37, 15379 "description": "<p>Copies an array (or part of an array) to another array. The src array is\ncopied to the dst array, beginning at the position specified by\nsrcPosition and into the position specified by dstPosition. The number of\nelements to copy is determined by length. Note that copying values\noverwrites existing values in the destination array. To append values\ninstead of overwriting them, use <a href=\"#/p5/concat\">concat()</a>.\n<br><br>\nThe simplified version with only two arguments, arrayCopy(src, dst),\ncopies an entire array to another of the same size. It is equivalent to\narrayCopy(src, 0, dst, 0, src.length).\n<br><br>\nUsing this function is far more efficient for copying array data than\niterating through a for() loop and copying each element individually.</p>\n", 15380 "itemtype": "method", 15381 "name": "arrayCopy", 15382 "deprecated": true, 15383 "example": ["\n<div class='norender'><code>\nvar src = ['A', 'B', 'C'];\nvar dst = [1, 2, 3];\nvar srcPosition = 1;\nvar dstPosition = 0;\nvar length = 2;\n\nprint(src); // ['A', 'B', 'C']\nprint(dst); // [ 1 , 2 , 3 ]\n\narrayCopy(src, srcPosition, dst, dstPosition, length);\nprint(dst); // ['B', 'C', 3]\n</code></div>"], 15384 "class": "p5", 15385 "module": "Data", 15386 "submodule": "Array Functions", 15387 "overloads": [{ 15388 "line": 37, 15389 "params": [{ 15390 "name": "src", 15391 "description": "<p>the source Array</p>\n", 15392 "type": "Array" 15393 }, { 15394 "name": "srcPosition", 15395 "description": "<p>starting position in the source Array</p>\n", 15396 "type": "Integer" 15397 }, { 15398 "name": "dst", 15399 "description": "<p>the destination Array</p>\n", 15400 "type": "Array" 15401 }, { 15402 "name": "dstPosition", 15403 "description": "<p>starting position in the destination Array</p>\n", 15404 "type": "Integer" 15405 }, { 15406 "name": "length", 15407 "description": "<p>number of Array elements to be copied</p>\n", 15408 "type": "Integer" 15409 }] 15410 }, { 15411 "line": 75, 15412 "params": [{ 15413 "name": "src", 15414 "description": "", 15415 "type": "Array" 15416 }, { 15417 "name": "dst", 15418 "description": "", 15419 "type": "Array" 15420 }, { 15421 "name": "length", 15422 "description": "", 15423 "type": "Integer", 15424 "optional": true 15425 }] 15426 }] 15427 }, { 15428 "file": "src/utilities/array_functions.js", 15429 "line": 114, 15430 "description": "<p>Concatenates two arrays, maps to Array.concat(). Does not modify the\ninput arrays.</p>\n", 15431 "itemtype": "method", 15432 "name": "concat", 15433 "deprecated": true, 15434 "deprecationMessage": "Use <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat\">arr1.concat(arr2)</a> instead.", 15435 "params": [{ 15436 "name": "a", 15437 "description": "<p>first Array to concatenate</p>\n", 15438 "type": "Array" 15439 }, { 15440 "name": "b", 15441 "description": "<p>second Array to concatenate</p>\n", 15442 "type": "Array" 15443 }], 15444 "return": { 15445 "description": "concatenated array", 15446 "type": "Array" 15447 }, 15448 "example": ["\n<div class = 'norender'><code>\nfunction setup() {\n var arr1 = ['A', 'B', 'C'];\n var arr2 = [1, 2, 3];\n\n print(arr1); // ['A','B','C']\n print(arr2); // [1,2,3]\n\n var arr3 = concat(arr1, arr2);\n\n print(arr1); // ['A','B','C']\n print(arr2); // [1, 2, 3]\n print(arr3); // ['A','B','C', 1, 2, 3]\n}\n</code></div>"], 15449 "class": "p5", 15450 "module": "Data", 15451 "submodule": "Array Functions" 15452 }, { 15453 "file": "src/utilities/array_functions.js", 15454 "line": 145, 15455 "description": "<p>Reverses the order of an array, maps to Array.reverse()</p>\n", 15456 "itemtype": "method", 15457 "name": "reverse", 15458 "deprecated": true, 15459 "deprecationMessage": "Use <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse\">array.reverse()</a> instead.", 15460 "params": [{ 15461 "name": "list", 15462 "description": "<p>Array to reverse</p>\n", 15463 "type": "Array" 15464 }], 15465 "return": { 15466 "description": "the reversed list", 15467 "type": "Array" 15468 }, 15469 "example": ["\n<div class='norender'><code>\nfunction setup() {\n var myArray = ['A', 'B', 'C'];\n print(myArray); // ['A','B','C']\n\n reverse(myArray);\n print(myArray); // ['C','B','A']\n}\n</code></div>"], 15470 "class": "p5", 15471 "module": "Data", 15472 "submodule": "Array Functions" 15473 }, { 15474 "file": "src/utilities/array_functions.js", 15475 "line": 167, 15476 "description": "<p>Decreases an array by one element and returns the shortened array,\nmaps to Array.pop().</p>\n", 15477 "itemtype": "method", 15478 "name": "shorten", 15479 "deprecated": true, 15480 "deprecationMessage": "Use <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop\">array.pop()</a> instead.", 15481 "params": [{ 15482 "name": "list", 15483 "description": "<p>Array to shorten</p>\n", 15484 "type": "Array" 15485 }], 15486 "return": { 15487 "description": "shortened Array", 15488 "type": "Array" 15489 }, 15490 "example": ["\n<div class = 'norender'><code>\nfunction setup() {\n var myArray = ['A', 'B', 'C'];\n print(myArray); // ['A', 'B', 'C']\n var newArray = shorten(myArray);\n print(myArray); // ['A','B','C']\n print(newArray); // ['A','B']\n}\n</code></div>"], 15491 "class": "p5", 15492 "module": "Data", 15493 "submodule": "Array Functions" 15494 }, { 15495 "file": "src/utilities/array_functions.js", 15496 "line": 191, 15497 "description": "<p>Randomizes the order of the elements of an array. Implements\n<a href='http://Bost.Ocks.org/mike/shuffle/' target=_blank>
15497\nFisher-Yates Shuffle Algorithm</a>.</p>\n", 15498 "itemtype": "method", 15499 "name": "shuffle", 15500 "params": [{ 15501 "name": "array", 15502 "description": "<p>Array to shuffle</p>\n", 15503 "type": "Array" 15504 }, { 15505 "name": "bool", 15506 "description": "<p>modify passed array</p>\n", 15507 "type": "Boolean", 15508 "optional": true 15509 }], 15510 "return": { 15511 "description": "shuffled Array", 15512 "type": "Array" 15513 }, 15514 "example": ["\n<div><code>\nfunction setup() {\n var regularArr = ['ABC', 'def', createVector(), TAU, Math.E];\n print(regularArr);\n shuffle(regularArr, true); // force modifications to passed array\n print(regularArr);\n\n // By default shuffle() returns a shuffled cloned array:\n var newArr = shuffle(regularArr);\n print(regularArr);\n print(newArr);\n}\n</code></div>"], 15515 "class": "p5", 15516 "module": "Data", 15517 "submodule": "Array Functions" 15518 }, { 15519 "file": "src/utilities/array_functions.js", 15520 "line": 233, 15521 "description": "<p>Sorts an array of numbers from smallest to largest, or puts an array of\nwords in alphabetical order. The original array is not modified; a\nre-ordered array is returned. The count parameter states the number of\nelements to sort. For example, if there are 12 elements in an array and\ncount is set to 5, only the first 5 elements in the array will be sorted.</p>\n", 15522 "itemtype": "method", 15523 "name": "sort", 15524 "deprecated": true, 15525 "deprecationMessage": "Use <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort\">array.sort()</a> instead.", 15526 "params": [{ 15527 "name": "list", 15528 "description": "<p>Array to sort</p>\n", 15529 "type": "Array" 15530 }, { 15531 "name": "count", 15532 "description": "<p>number of elements to sort, starting from 0</p>\n", 15533 "type": "Integer", 15534 "optional": true 15535 }], 15536 "return": { 15537 "description": "the sorted list", 15538 "type": "Array" 15539 }, 15540 "example": ["\n<div class = 'norender'><code>\nfunction setup() {\n var words = ['banana', 'apple', 'pear', 'lime'];\n print(words); // ['banana', 'apple', 'pear', 'lime']\n var count = 4; // length of array\n\n words = sort(words, count);\n print(words); // ['apple', 'banana', 'lime', 'pear']\n}\n</code></div>\n<div class = 'norender'><code>\nfunction setup() {\n var numbers = [2, 6, 1, 5, 14, 9, 8, 12];\n print(numbers); // [2, 6, 1, 5, 14, 9, 8, 12]\n var count = 5; // Less than the length of the array\n\n numbers = sort(numbers, count);\n print(numbers); // [1,2,5,6,14,9,8,12]\n}\n</code></div>"], 15541 "class": "p5", 15542 "module": "Data", 15543 "submodule": "Array Functions" 15544 }, { 15545 "file": "src/utilities/array_functions.js", 15546 "line": 281, 15547 "description": "<p>Inserts a value or an array of values into an existing array. The first\nparameter specifies the initial array to be modified, and the second\nparameter defines the data to be inserted. The third parameter is an index\nvalue which specifies the array position from which to insert data.\n(Remember that array index numbering starts at zero, so the first position\nis 0, the second position is 1, and so on.)</p>\n", 15548 "itemtype": "method", 15549 "name": "splice", 15550 "deprecated": true, 15551 "deprecationMessage": "Use <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice\">array.splice()</a> instead.", 15552 "params": [{ 15553 "name": "list", 15554 "description": "<p>Array to splice into</p>\n", 15555 "type": "Array" 15556 }, { 15557 "name": "value", 15558 "description": "<p>value to be spliced in</p>\n", 15559 "type": "Any" 15560 }, { 15561 "name": "position", 15562 "description": "<p>in the array from which to insert data</p>\n", 15563 "type": "Integer" 15564 }], 15565 "return": { 15566 "description": "the list", 15567 "type": "Array" 15568 }, 15569 "example": ["\n<div class = 'norender'><code>\nfunction setup() {\n var myArray = [0, 1, 2, 3, 4];\n var insArray = ['A', 'B', 'C'];\n print(myArray); // [0, 1, 2, 3, 4]\n print(insArray); // ['A','B','C']\n\n splice(myArray, insArray, 3);\n print(myArray); // [0,1,2,'A','B','C',3,4]\n}\n</code></div>"], 15570 "class": "p5", 15571 "module": "Data", 15572 "submodule": "Array Functions" 15573 }, { 15574 "file": "src/utilities/array_functions.js", 15575 "line": 316, 15576 "description": "<p>Extracts an array of elements from an existing array. The list parameter\ndefines the array from which the elements will be copied, and the start\nand count parameters specify which elements to extract. If no count is\ngiven, elements will be extracted from the start to the end of the array.\nWhen specifying the start, remember that the first array element is 0.\nThis function does not change the source array.</p>\n", 15577 "itemtype": "method", 15578 "name": "subset", 15579 "deprecated": true, 15580 "deprecationMessage": "Use <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice\">array.slice()</a> instead.", 15581 "params": [{ 15582 "name": "list", 15583 "description": "<p>Array to extract from</p>\n", 15584 "type": "Array" 15585 }, { 15586 "name": "start", 15587 "description": "<p>position to begin</p>\n", 15588 "type": "Integer" 15589 }, { 15590 "name": "count", 15591 "description": "<p>number of values to extract</p>\n", 15592 "type": "Integer", 15593 "optional": true 15594 }], 15595 "return": { 15596 "description": "Array of extracted elements", 15597 "type": "Array" 15598 }, 15599 "example": ["\n<div class = 'norender'><code>\nfunction setup() {\n var myArray = [1, 2, 3, 4, 5];\n print(myArray); // [1, 2, 3, 4, 5]\n\n var sub1 = subset(myArray, 0, 3);\n var sub2 = subset(myArray, 2, 2);\n print(sub1); // [1,2,3]\n print(sub2); // [3,4]\n}\n</code></div>"], 15600 "class": "p5", 15601 "module": "Data", 15602 "submodule": "Array Functions" 15603 }, { 15604 "file": "src/utilities/conversion.js", 15605 "line": 12, 15606 "description": "<p>Converts a string to its floating point representation. The contents of a\nstring must resemble a number, or NaN (not a number) will be returned.\nFor example, float("1234.56") evaluates to 1234.56, but float("giraffe")\nwill return NaN.</p>\n<p>When an array of values is passed in, then an array of floats of the same\nlength is returned.</p>\n", 15607 "itemtype": "method", 15608 "name": "float", 15609 "params": [{ 15610 "name": "str", 15611 "description": "<p>float string to parse</p>\n", 15612 "type": "String" 15613 }], 15614 "return": { 15615 "description": "floating point representation of str
15615ing", 15616 "type": "Number" 15617 }, 15618 "example": ["\n<div><code>\nvar str = '20';\nvar diameter = float(str);\nellipse(width / 2, height / 2, diameter, diameter);\n</code></div>"], 15619 "alt": "20 by 20 white ellipse in the center of the canvas", 15620 "class": "p5", 15621 "module": "Data", 15622 "submodule": "Conversion" 15623 }, { 15624 "file": "src/utilities/conversion.js", 15625 "line": 42, 15626 "description": "<p>Converts a boolean, string, or float to its integer representation.\nWhen an array of values is passed in, then an int array of the same length\nis returned.</p>\n", 15627 "itemtype": "method", 15628 "name": "int", 15629 "return": { 15630 "description": "integer representation of value", 15631 "type": "Number" 15632 }, 15633 "example": ["\n<div class='norender'><code>\nprint(int('10')); // 10\nprint(int(10.31)); // 10\nprint(int(-10)); // -10\nprint(int(true)); // 1\nprint(int(false)); // 0\nprint(int([false, true, '10.3', 9.8])); // [0, 1, 10, 9]\n</code></div>"], 15634 "class": "p5", 15635 "module": "Data", 15636 "submodule": "Conversion", 15637 "overloads": [{ 15638 "line": 42, 15639 "params": [{ 15640 "name": "n", 15641 "description": "<p>value to parse</p>\n", 15642 "type": "String|Boolean|Number" 15643 }, { 15644 "name": "radix", 15645 "description": "<p>the radix to convert to (default: 10)</p>\n", 15646 "type": "Integer", 15647 "optional": true 15648 }], 15649 "return": { 15650 "description": "integer representation of value", 15651 "type": "Number" 15652 } 15653 }, { 15654 "line": 62, 15655 "params": [{ 15656 "name": "ns", 15657 "description": "<p>values to parse</p>\n", 15658 "type": "Array" 15659 }], 15660 "return": { 15661 "description": "integer representation of values", 15662 "type": "Number[]" 15663 } 15664 }] 15665 }, { 15666 "file": "src/utilities/conversion.js", 15667 "line": 82, 15668 "description": "<p>Converts a boolean, string or number to its string representation.\nWhen an array of values is passed in, then an array of strings of the same\nlength is returned.</p>\n", 15669 "itemtype": "method", 15670 "name": "str", 15671 "params": [{ 15672 "name": "n", 15673 "description": "<p>value to parse</p>\n", 15674 "type": "String|Boolean|Number|Array" 15675 }], 15676 "return": { 15677 "description": "string representation of value", 15678 "type": "String" 15679 }, 15680 "example": ["\n<div class='norender'><code>\nprint(str('10')); // \"10\"\nprint(str(10.31)); // \"10.31\"\nprint(str(-10)); // \"-10\"\nprint(str(true)); // \"true\"\nprint(str(false)); // \"false\"\nprint(str([true, '10.3', 9.8])); // [ \"true\", \"10.3\", \"9.8\" ]\n</code></div>"], 15681 "class": "p5", 15682 "module": "Data", 15683 "submodule": "Conversion" 15684 }, { 15685 "file": "src/utilities/conversion.js", 15686 "line": 108, 15687 "description": "<p>Converts a number or string to its boolean representation.\nFor a number, any non-zero value (positive or negative) evaluates to true,\nwhile zero evaluates to false. For a string, the value "true" evaluates to\ntrue, while any other value evaluates to false. When an array of number or\nstring values is passed in, then a array of booleans of the same length is\nreturned.</p>\n", 15688 "itemtype": "method", 15689 "name": "boolean", 15690 "params": [{ 15691 "name": "n", 15692 "description": "<p>value to parse</p>\n", 15693 "type": "String|Boolean|Number|Array" 15694 }], 15695 "return": { 15696 "description": "boolean representation of value", 15697 "type": "Boolean" 15698 }, 15699 "example": ["\n<div class='norender'><code>\nprint(boolean(0)); // false\nprint(boolean(1)); // true\nprint(boolean('true')); // true\nprint(boolean('abcd')); // false\nprint(boolean([0, 12, 'true'])); // [false, true, false]\n</code></div>"], 15700 "class": "p5", 15701 "module": "Data", 15702 "submodule": "Conversion" 15703 }, { 15704 "file": "src/utilities/conversion.js", 15705 "line": 140, 15706 "description": "<p>Converts a number, string representation of a number, or boolean to its byte\nrepresentation. A b
15706yte can be only a whole number between -128 and 127, so\nwhen a value outside of this range is converted, it wraps around to the\ncorresponding byte representation. When an array of number, string or boolean\nvalues is passed in, then an array of bytes the same length is returned.</p>\n", 15707 "itemtype": "method", 15708 "name": "byte", 15709 "return": { 15710 "description": "byte representation of value", 15711 "type": "Number" 15712 }, 15713 "example": ["\n<div class='norender'><code>\nprint(byte(127)); // 127\nprint(byte(128)); // -128\nprint(byte(23.4)); // 23\nprint(byte('23.4')); // 23\nprint(byte('hello')); // NaN\nprint(byte(true)); // 1\nprint(byte([0, 255, '100'])); // [0, -1, 100]\n</code></div>"], 15714 "class": "p5", 15715 "module": "Data", 15716 "submodule": "Conversion", 15717 "overloads": [{ 15718 "line": 140, 15719 "params": [{ 15720 "name": "n", 15721 "description": "<p>value to parse</p>\n", 15722 "type": "String|Boolean|Number" 15723 }], 15724 "return": { 15725 "description": "byte representation of value", 15726 "type": "Number" 15727 } 15728 }, { 15729 "line": 162, 15730 "params": [{ 15731 "name": "ns", 15732 "description": "<p>values to parse</p>\n", 15733 "type": "Array" 15734 }], 15735 "return": { 15736 "description": "array of byte representation of values", 15737 "type": "Number[]" 15738 } 15739 }] 15740 }, { 15741 "file": "src/utilities/conversion.js", 15742 "line": 176, 15743 "description": "<p>Converts a number or string to its corresponding single-character\nstring representation. If a string parameter is provided, it is first\nparsed as an integer and then translated into a single-character string.\nWhen an array of number or string values is passed in, then an array of\nsingle-character strings of the same length is returned.</p>\n", 15744 "itemtype": "method", 15745 "name": "char", 15746 "return": { 15747 "description": "string representation of value", 15748 "type": "String" 15749 }, 15750 "example": ["\n<div class='norender'><code>\nprint(char(65)); // \"A\"\nprint(char('65')); // \"A\"\nprint(char([65, 66, 67])); // [ \"A\", \"B\", \"C\" ]\nprint(join(char([65, 66, 67]), '')); // \"ABC\"\n</code></div>"], 15751 "class": "p5", 15752 "module": "Data", 15753 "submodule": "Conversion", 15754 "overloads": [{ 15755 "line": 176, 15756 "params": [{ 15757 "name": "n", 15758 "description": "<p>value to parse</p>\n", 15759 "type": "String|Number" 15760 }], 15761 "return": { 15762 "description": "string representation of value", 15763 "type": "String" 15764 } 15765 }, { 15766 "line": 195, 15767 "params": [{ 15768 "name": "ns", 15769 "description": "<p>values to parse</p>\n", 15770 "type": "Array" 15771 }], 15772 "return": { 15773 "description": "array of string representation of values", 15774 "type": "String[]" 15775 } 15776 }] 15777 }, { 15778 "file": "src/utilities/conversion.js", 15779 "line": 210, 15780 "description": "<p>Converts a single-character string to its corresponding integer\nrepresentation. When an array of single-character string values is passed\nin, then an array of integers of the same length is returned.</p>\n", 15781 "itemtype": "method", 15782 "name": "unchar", 15783 "return": { 15784 "description": "integer representation of value", 15785 "type": "Number" 15786 }, 15787 "example": ["\n<div class='norender'><code>\nprint(unchar('A')); // 65\nprint(unchar(['A', 'B', 'C'])); // [ 65, 66, 67 ]\nprint(unchar(split('ABC', ''))); // [ 65, 66, 67 ]\n</code></div>"], 15788 "class": "p5", 15789 "module": "Data", 15790 "submodule": "Conversion", 15791 "overloads": [{ 15792 "line": 210, 15793 "params": [{ 15794 "name": "n", 15795 "description": "<p>value to parse</p>\n", 15796 "type": "String" 15797 }], 15798 "return": { 15799 "description": "integer representation of value", 15800 "type": "Number" 15801 } 15802 }, { 15803 "line": 226, 15804 "params": [{ 15805 "name": "ns", 15806 "description": "<p>values to parse</p>\n", 15807 "type": "Array" 15808 }], 15809 "return": { 15810 "description": "integer representation of values", 15811 "type": "Number[]" 15812 } 15813 }] 15814 }, { 15815 "file": "src/utilities/conversion.js", 15816 "line": 239, 15817 "description": "<p>Converts a number to a string in its equivalent hexadecimal notation. If a\nsecond parameter is passed, it is used to set the number of characters to\ngenerate in the hexadecimal notation. When an array is passed in, an\narray of str
15817ings in hexadecimal notation of the same length is returned.</p>\n", 15818 "itemtype": "method", 15819 "name": "hex", 15820 "return": { 15821 "description": "hexadecimal string representation of value", 15822 "type": "String" 15823 }, 15824 "example": ["\n<div class='norender'><code>\nprint(hex(255)); // \"000000FF\"\nprint(hex(255, 6)); // \"0000FF\"\nprint(hex([0, 127, 255], 6)); // [ \"000000\", \"00007F\", \"0000FF\" ]\n</code></div>"], 15825 "class": "p5", 15826 "module": "Data", 15827 "submodule": "Conversion", 15828 "overloads": [{ 15829 "line": 239, 15830 "params": [{ 15831 "name": "n", 15832 "description": "<p>value to parse</p>\n", 15833 "type": "Number" 15834 }, { 15835 "name": "digits", 15836 "description": "", 15837 "type": "Number", 15838 "optional": true 15839 }], 15840 "return": { 15841 "description": "hexadecimal string representation of value", 15842 "type": "String" 15843 } 15844 }, { 15845 "line": 257, 15846 "params": [{ 15847 "name": "ns", 15848 "description": "<p>array of values to parse</p>\n", 15849 "type": "Number[]" 15850 }, { 15851 "name": "digits", 15852 "description": "", 15853 "type": "Number", 15854 "optional": true 15855 }], 15856 "return": { 15857 "description": "hexadecimal string representation of values", 15858 "type": "String[]" 15859 } 15860 }] 15861 }, { 15862 "file": "src/utilities/conversion.js", 15863 "line": 286, 15864 "description": "<p>Converts a string representation of a hexadecimal number to its equivalent\ninteger value. When an array of strings in hexadecimal notation is passed\nin, an array of integers of the same length is returned.</p>\n", 15865 "itemtype": "method", 15866 "name": "unhex", 15867 "return": { 15868 "description": "integer representation of hexadecimal value", 15869 "type": "Number" 15870 }, 15871 "example": ["\n<div class='norender'><code>\nprint(unhex('A')); // 10\nprint(unhex('FF')); // 255\nprint(unhex(['FF', 'AA', '00'])); // [ 255, 170, 0 ]\n</code></div>"], 15872 "class": "p5", 15873 "module": "Data", 15874 "submodule": "Conversion", 15875 "overloads": [{ 15876 "line": 286, 15877 "params": [{ 15878 "name": "n", 15879 "description": "<p>value to parse</p>\n", 15880 "type": "String" 15881 }], 15882 "return": { 15883 "description": "integer representation of hexadecimal value", 15884 "type": "Number" 15885 } 15886 }, { 15887 "line": 302, 15888 "params": [{ 15889 "name": "ns", 15890 "description": "<p>values to parse</p>\n", 15891 "type": "Array" 15892 }], 15893 "return": { 15894 "description": "integer representations of hexadecimal value", 15895 "type": "Number[]" 15896 } 15897 }] 15898 }, { 15899 "file": "src/utilities/string_functions.js", 15900 "line": 15, 15901 "description": "<p>Combines an array of Strings into one String, each separated by the\ncharacter(s) used for the separator parameter. To join arrays of ints or\nfloats, it's necessary to first convert them to Strings using <a href=\"#/p5/nf\">nf()</a> or\nnfs().</p>\n", 15902 "itemtype": "method", 15903 "name": "join", 15904 "params": [{ 15905 "name": "list", 15906 "description": "<p>array of Strings to be joined</p>\n", 15907 "type": "Array" 15908 }, { 15909 "name": "separator", 15910 "description": "<p>String to be placed between each item</p>\n", 15911 "type": "String" 15912 }], 15913 "return": { 15914 "description": "joined String", 15915 "type": "String" 15916 }, 15917 "example": ["\n<div>\n<code>\nvar array = ['Hello', 'world!'];\nvar separator = ' ';\nvar message = join(array, separator);\ntext(message, 5, 50);\n</code>\n</div>"], 15918 "alt": "\"hello world!\" displayed middle left of canvas.", 15919 "class": "p5", 15920 "module": "Data", 15921 "submodule": "String Functions" 15922 }, { 15923 "file": "src/utilities/string_functions.js", 15924 "line": 44, 15925 "description": "<p>This function is used to apply a regular expression to a piece of text,\nand return matching groups (elements found inside parentheses) as a\nString array. If there are no matches, a null value will be returned.\nIf no groups are specified in the regular expression, but the sequence\nmatches, an array of length 1 (with the matched text as the first element\nof the array) will be returned.\n<br><br>\nTo use the function, first check to see if the result is null. If the\nresult is null, then the sequence did not match at all. If the sequence\ndid match, an array is returned.\n<br><br>\nIf there are groups (specified by sets of parentheses) in the regular\nexpression, then the contents of each will be returned in the array.\nElement [0] of a regular expression match returns the entire matching\nstring, and the match groups start at element [1] (the first group is [1],\nthe second [2], and so on).</p>\n", 15926 "itemtype": "method", 15927 "name": "match", 15928 "params": [{ 15929 "name": "str", 15930 "description": "<p>the String to be searched</p>\n", 15931 "type": "String" 15932 }, { 15933 "name": "regexp", 15934 "description": "<p>the regexp to be used for matching</p>\n", 15935 "type": "String" 15936 }], 15937 "return": { 15938 "description": "Array of Strings found", 15939 "type": "String[]" 15940 }, 15941 "example": ["\n<div>\n<code>\nvar string = 'Hello p5js*!';\nvar regexp = 'p5js\\\\*';\nvar m = match(string, regexp);\ntext(m, 5, 50);\n</code>\n</div>"], 15942 "alt": "\"p5js*\" displayed middle left of canvas.", 15943 "class": "p5", 15944 "module": "Data", 15945 "submodule": "String Functions" 15946 }, { 15947 "file": "src/utilities/string_functions.js", 15948 "line": 85, 15949 "description": "<p>This function is used to apply a regular expression to a piece of text,\nand return a list of matching groups (elements found inside parentheses)\nas a two-dimensional Str
15949ing array. If there are no matches, a null value\nwill be returned. If no groups are specified in the regular expression,\nbut the sequence matches, a two dimensional array is still returned, but\nthe second dimension is only of length one.\n<br><br>\nTo use the function, first check to see if the result is null. If the\nresult is null, then the sequence did not match at all. If the sequence\ndid match, a 2D array is returned.\n<br><br>\nIf there are groups (specified by sets of parentheses) in the regular\nexpression, then the contents of each will be returned in the array.\nAssuming a loop with counter variable i, element [i][0] of a regular\nexpression match returns the entire matching string, and the match groups\nstart at element [i][1] (the first group is [i][1], the second [i][2],\nand so on).</p>\n", 15950 "itemtype": "method", 15951 "name": "matchAll", 15952 "params": [{ 15953 "name": "str", 15954 "description": "<p>the String to be searched</p>\n", 15955 "type": "String" 15956 }, { 15957 "name": "regexp", 15958 "description": "<p>the regexp to be used for matching</p>\n", 15959 "type": "String" 15960 }], 15961 "return": { 15962 "description": "2d Array of Strings found", 15963 "type": "String[]" 15964 }, 15965 "example": ["\n<div class=\"norender\">\n<code>\nvar string = 'Hello p5js*! Hello world!';\nvar regexp = 'Hello';\nmatchAll(string, regexp);\n</code>\n</div>"], 15966 "class": "p5", 15967 "module": "Data", 15968 "submodule": "String Functions" 15969 }, { 15970 "file": "src/utilities/string_functions.js", 15971 "line": 132, 15972 "description": "<p>Utility function for formatting numbers into strings. There are two\nversions: one for formatting floats, and one for formatting ints.\nThe values for the digits, left, and right parameters should always\nbe positive integers.\n(NOTE): Be cautious when using left and right parameters as it prepends numbers of 0's if the parameter\nif greater than the current length of the number.\nFor example if number is 123.2 and left parameter passed is 4 which is greater than length of 123\n(integer part) i.e 3 than result will be 0123.2. Same case for right parameter i.e. if right is 3 than\nthe result will be 123.200.</p>\n", 15973 "itemtype": "method", 15974 "name": "nf", 15975 "return": { 15976 "description": "formatted String", 15977 "type": "String" 15978 }, 15979 "example": ["\n<div>\n<code>\nvar myFont;\nfunction preload() {\n myFont = loadFont('assets/fonts/inconsolata.ttf');\n}\nfunction setup() {\n background(200);\n var num1 = 321;\n var num2 = -1321;\n\n noStroke();\n fill(0);\n textFont(myFont);\n textSize(22);\n\n text(nf(num1, 4, 2), 10, 30);\n text(nf(num2, 4, 2), 10, 80);\n // Draw dividing line\n stroke(120);\n line(0, 50, width, 50);\n}\n</code>\n</div>"], 15980 "alt": "\"0321.00\" middle top, -1321.00\" middle bottom canvas", 15981 "class": "p5", 15982 "module": "Data", 15983 "submodule": "String Functions", 15984 "overloads": [{ 15985 "line": 132, 15986 "params": [{ 15987 "name": "num", 15988 "description": "<p>the Number to format</p>\n", 15989 "type": "Number|String" 15990 }, { 15991 "name": "left", 15992 "description": "<p>number of digits to the left of the\n decimal point</p>\n", 15993 "type": "Integer|String", 15994 "optional": true 15995 }, { 15996 "name": "right", 15997 "description": "<p>number of digits to the right of the\n decimal point</p>\n", 15998 "type": "Integer|String", 15999 "optional": true 16000 }], 16001 "return": { 16002 "description": "formatted String", 16003 "type": "String" 16004 } 16005 }, { 16006 "line": 180, 16007 "params": [{ 16008 "name": "nums", 16009 "description": "<p>the Numbers to format</p>\n", 16010 "type": "Array" 16011 }, { 16012 "name": "left", 16013 "description": "", 16014 "type": "Integer|String", 16015 "optional": true 16016 }, { 16017 "name": "right", 16018 "description": "", 16019 "type": "Integer|String", 16020 "optional": true 16021 }], 16022 "return": { 16023 "description": "formatted Strings", 16024 "type": "String[]" 16025 } 16026 }] 16027 }, { 16028 "file": "src/utilities/string_functions.js", 16029 "line": 243, 16030 "description": "<p>Utility function for formatting numbers into strings and placing\nappropriate commas to mark units of 1000. There are two versions: one\nfor formatting ints, and one for formatting an array of ints. The value\nfor the right parameter should always be a positive integer.</p>\n", 16031 "itemtype": "method", 16032 "name": "nfc", 16033 "return": { 16034 "description": "formatted String", 16035 "type": "String" 16036 }, 16037 "example": ["\n<div>\n<code>\nfunction setup() {\n background(200);\n var num = 11253106.115;\n var numArr = [1, 1, 2];\n\n noStroke();\n fill(0);\n textSize(12);\n\n // Draw formatted numbers\n text(nfc(num, 4), 10, 30);\n text(nfc(numArr, 2), 10, 80);\n\n // Draw dividing line\n stroke(120);\n line(0, 50, width, 50);\n}\n</code>\n</div>"], 16038 "alt": "\"11,253,106.115\" top middle and \"1.00,1.00,2.00\" displayed bottom mid", 16039 "class": "p5", 16040 "module": "Data", 16041 "submodule": "String Functions", 16042 "overloads": [{ 16043 "line": 243, 16044 "params": [{ 16045 "name": "num", 16046 "description": "<p>the Number to format</p>\n", 16047 "type": "Number|String" 16048 }, { 16049 "name": "right", 16050 "description": "<p>number of digits to the right of the\n decimal point</p>\n", 16051 "type": "Integer|String", 16052 "optional": true 16053 }], 16054 "return": { 16055 "description": "formatted String", 16056 "type": "String" 16057 } 16058 }, { 16059 "line": 281, 16060 "params": [{ 16061 "name": "nums", 16062 "description": "<p>the Numbers to format</p>\n", 16063 "type": "Array" 16064 }, { 16065 "name": "right", 16066 "description": "", 16067 "type": "Integer|String", 16068 "optional": true 16069 }], 16070 "return": { 16071 "description": "formatted Strings", 16072 "type": "String[]" 16073 } 16074 }] 16075 }, { 16076 "file": "src/utilities/string_functions.js", 16077 "line": 319, 16078 "description": "<p>Utility function for formatting numbers into strings. Similar to <a href=\"#/p5/nf\">nf()</a> but\nputs a "+" in front of positive numbers and a "-" in front of negative\nnumbers. There are two versions: one for formatting floats, and one for\nformatting ints. The values for left, and right parameters\nshould always be positive integers.</p>\n", 16079 "itemtype": "method", 16080 "name": "nfp", 16081 "return": { 16082 "description": "formatted String", 16083 "type": "String" 16084 }, 16085 "example": ["\n<div>\n<code>\nfunction setup() {\n background(200);\n var num1 = 11253106.115;\n var num2 = -11253106.115;\n\n noStroke();\n fill(0);\n textSize(12);\n\n // Draw formatted numbers\n text(nfp(num1, 4, 2), 10, 30);\n text(nfp(num2, 4, 2), 10, 80);\n\n // Draw dividing line\n stroke(120);\n line(0, 50, width, 50);\n}\n</code>\n</div>"], 16086 "alt": "\"+11253106.11\" top middle and \"-11253106.11\" displayed bottom middle", 16087 "class": "p5", 16088 "module": "Data", 16089 "submodule": "String Functions", 16090 "overloads": [{ 16091 "line": 319, 16092 "params": [{ 16093 "name": "num", 16094 "description": "<p>the Number to format</p>\n", 16095 "type": "Number" 16096 }, { 16097 "name": "left", 16098 "description": "<p>number of digits to the left of the decimal\n point</p>\n", 16099 "type": "Integer", 16100 "optional": true 16101 }, { 16102 "name": "right", 16103 "description": "<p>number of digits to the right of the\n decimal point</p>\n", 16104 "type": "Integer", 16105 "optional": true 16106 }], 16107 "return": { 16108 "description": "formatted String", 16109 "type": "String" 16110 } 16111 }, { 16112 "line": 360, 16113 "params": [{ 16114 "name": "nums", 16115 "description": "<p>the Numbers to format</p>\n", 16116 "type": "Number[]" 16117 }, { 16118 "name": "left", 16119 "description": "", 16120 "type": "Integer", 16121 "optional": true 16122 }, { 16123 "name": "right", 16124 "description": "", 16125 "type": "Integer", 16126 "optional": true 16127 }], 16128 "return": { 16129 "description": "formatted Strings", 16130 "type": "String[]" 16131 } 16132 }] 16133 }, { 16134 "file": "src/utilities/string_functions.js", 16135 "line": 381, 16136 "description": "<p>Utility function for formatting numbers into strings. Similar to <a href=\"#/p5/nf\">nf()</a> but\nputs an additional "_" (space) in front of positive numbers just in case to align it with negative\nnumbers which includes "-" (minus) sign.\nThe main usecase of nfs() can be seen when one wants to align the digits (place values) of a positive\nnumber with some negative number (See the example to get a clear picture).\nThere are two versions: one for formatting float, and one for formatting int.\nThe values for the digits, left, and right parameters should always be positive integers.\n(IMP): The result on the canvas basically the expected alignment can vary based on the typeface you are using.\n(NOTE): Be cautious when using left and right parameters as it prepends numbers of 0's if the parameter\nif greater than the current length of the number.\nFor example if number is 123.2 and left parameter passed is 4 which is greater than length of 123\n(integer part) i.e 3 than result will be 0123.2. Same case for right parameter i.e. if right is 3 than\nthe result will be 123.200.</p>\n", 16137 "itemtype": "method", 16138 "name": "nfs", 16139 "return": { 16140 "description": "formatted String", 16141 "type": "String" 16142 }, 16143 "example": ["\n<div>\n<code>\nvar myFont;\nfunction preload() {\n myFont = loadFont('assets/fonts/inconsolata.ttf');\n}\nfunction setup() {\n background(200);\n var num1 = 321;\n var num2 = -1321;\n\n noStroke();\n fill(0);\n textFont(myFont);\n textSize(22);
16143\n\n // nfs() aligns num1 (positive number) with num2 (negative number) by\n // adding a blank space in front of the num1 (positive number)\n // [left = 4] in num1 add one 0 in front, to align the digits with num2\n // [right = 2] in num1 and num2 adds two 0's after both numbers\n // To see the differences check the example of nf() too.\n text(nfs(num1, 4, 2), 10, 30);\n text(nfs(num2, 4, 2), 10, 80);\n // Draw dividing line\n stroke(120);\n line(0, 50, width, 50);\n}\n</code>\n</div>"], 16144 "alt": "\"0321.00\" top middle and \"-1321.00\" displayed bottom middle", 16145 "class": "p5", 16146 "module": "Data", 16147 "submodule": "String Functions", 16148 "overloads": [{ 16149 "line": 381, 16150 "params": [{ 16151 "name": "num", 16152 "description": "<p>the Number to format</p>\n", 16153 "type": "Number" 16154 }, { 16155 "name": "left", 16156 "description": "<p>number of digits to the left of the decimal\n point</p>\n", 16157 "type": "Integer", 16158 "optional": true 16159 }, { 16160 "name": "right", 16161 "description": "<p>number of digits to the right of the\n decimal point</p>\n", 16162 "type": "Integer", 16163 "optional": true 16164 }], 16165 "return": { 16166 "description": "formatted String", 16167 "type": "String" 16168 } 16169 }, { 16170 "line": 438, 16171 "params": [{ 16172 "name": "nums", 16173 "description": "<p>the Numbers to format</p>\n", 16174 "type": "Array" 16175 }, { 16176 "name": "left", 16177 "description": "", 16178 "type": "Integer", 16179 "optional": true 16180 }, { 16181 "name": "right", 16182 "description": "", 16183 "type": "Integer", 16184 "optional": true 16185 }], 16186 "return": { 16187 "description": "formatted Strings", 16188 "type": "String[]" 16189 } 16190 }] 16191 }, { 16192 "file": "src/utilities/string_functions.js", 16193 "line": 459, 16194 "description": "<p>The <a href=\"#/p5/split\">split()</a> function maps to String.split(), it breaks a String into\npieces using a character or string as the delimiter. The delim parameter\nspecifies the character or characters that mark the boundaries between\neach piece. A String[] array is returned that contains each of the pieces.</p>\n<p>The <a href=\"#/p5/splitTokens\">splitTokens()</a> function works in a similar fashion, except that it\nsplits using a range of characters instead of a specific character or\nsequence.</p>\n", 16195 "itemtype": "method", 16196 "name": "split", 16197 "params": [{ 16198 "name": "value", 16199 "description": "<p>the String to be split</p>\n", 16200 "type": "String" 16201 }, { 16202 "name": "delim", 16203 "description": "<p>the String used to separate the data</p>\n", 16204 "type": "String" 16205 }], 16206 "return": { 16207 "description": "Array of Strings", 16208 "type": "String[]" 16209 }, 16210 "example": ["\n<div>\n<code>\nvar names = 'Pat,Xio,Alex';\nvar splitString = split(names, ',');\ntext(splitString[0], 5, 30);\ntext(splitString[1], 5, 50);\ntext(splitString[2], 5, 70);\n</code>\n</div>"], 16211 "alt": "\"pat\" top left, \"Xio\" mid left and \"Alex\" displayed bottom left", 16212 "class": "p5", 16213 "module": "Data", 16214 "submodule": "String Functions" 16215 }, { 16216 "file": "src/utilities/string_functions.js", 16217 "line": 493, 16218 "description": "<p>The <a href=\"#/p5/splitTokens\">splitTokens()</a> function splits a String at one or many character\ndelimiters or "tokens." The delim parameter specifies the character or\ncharacters to be used as a boundary.\n<br><br>\nIf no delim characters are specified, any whitespace character is used to\nsplit. Whitespace characters include tab (\\t), line feed (\\n), carriage\nreturn (\\r), form feed (\\f), and space.</p>\n", 16219 "itemtype": "method", 16220 "name": "splitTokens", 16221 "params": [{ 16222 "name": "value", 16223 "description": "<p>the String to be split</p>\n", 16224 "type": "String" 16225 }, { 16226 "name": "delim", 16227 "description": "<p>list of individual Strings that will be used as\n separators</p>\n", 16228 "type": "String", 16229 "optional": true 16230 }], 16231 "return": { 16232 "description": "Array of Strings", 16233 "type": "String[]" 16234 }, 16235 "example": ["\n<div class = \"norender\">\n<code>\nfunction setup() {\n var myStr = 'Mango, Banana, Lime';\n var myStrArr = splitTokens(myStr, ',');\n\n print(myStrArr); // prints : [\"Mango\",\" Banana\",\" Lime\"]\n}\n</code>\n</div>"], 16236 "class": "p5", 16237 "module": "Data", 16238 "submodule": "String Functions" 16239 }, { 16240 "file": "src/utilities/string_functions.js", 16241 "line": 548, 16242 "description": "<p>Removes whitespace characters from the beginning and end of a String. In\naddition to standard whitespace characters such as space, carriage return,\nand tab, this function also removes the Unicode "nbsp" character.</p>\n", 16243 "itemtype": "method", 16244 "name": "trim", 16245 "return": { 16246 "description": "a trimmed String", 16247 "type": "String" 16248 }, 16249 "example": ["\n<div>\n<code>\nvar string = trim(' No new lines\\n ');\ntext(string + ' here', 2, 50);\n</code>\n</div>"], 16250 "alt": "\"No new lines here\" displayed center canvas", 16251 "class": "p5", 16252 "module": "Data", 16253 "submodule": "String Functions", 16254 "overloads": [{ 16255 "line": 548, 16256 "params": [{ 16257 "name": "str", 16258 "description": "<p>a String to be trimmed</p>\n", 16259 "type": "String" 16260 }], 16261 "return": { 16262 "description": "a trimmed String", 16263 "type": "String" 16264 } 16265 }, { 16266 "line": 568, 16267 "params": [{ 16268 "name": "strs", 16269 "description": "<p>an Array of Strings to be trimmed</p>\n", 16270 "type": "Array" 16271 }], 16272 "return": { 16273 "description": "an Array of trimmed Strings", 16274 "type": "String[]" 16275 } 16276 }] 16277 }, { 16278 "file": "src/utilities/time_date.js", 16279 "line": 12, 16280 "description": "<p>p5.js communicates with the clock on your computer. The <a href=\"#/p5/day\">day()</a> function\nreturns the current day as a value from 1 - 31.</p>\n", 16281 "itemtype": "method", 16282 "name": "day", 16283 "return": { 16284 "description": "the current day", 16285 "type": "Integer" 16286 }, 16287 "example": ["\n<div>\n<code>\nvar d = day();\ntext('Current day: \\n' + d, 5, 50);\n</code>\n</div>"], 16288 "alt": "Current day is displayed", 16289 "class": "p5", 16290 "module": "IO", 16291 "submodule": "Time & Date" 16292 }, { 16293 "file": "src/utilities/time_date.js", 16294 "line": 34, 16295 "description": "<p>p5.js communicates with the clock on your computer. The <a href=\"#/p5/hour\">hour()</a> function\nreturns the current hour as a value from 0 - 23.</p>\n", 16296 "itemtype": "method", 16297 "name": "hour", 16298 "return": { 16299 "description": "the current hour", 16300 "type": "Integer" 16301 }, 16302 "example": ["\n<div>\n<code>\nvar h = hour();\ntext('Current hour:\\n' + h, 5, 50);\n</code>\n</div>"], 16303 "alt": "Current hour is displayed", 16304 "class": "p5", 16305 "module": "IO", 16306 "submodule": "Time & Date" 16307 }, { 16308 "file": "src/utilities/time_date.js", 16309 "line": 56, 16310 "description": "<p>p5.js communicates with the clock on your computer. The <a href=\"#/p5/minute\">minute()</a> function\nreturns the current minute as a value from 0 - 59.</p>\n", 16311 "itemtype": "method", 16312 "name": "minute", 16313 "return": { 16314 "description": "the current minute", 16315 "type": "Integer" 16316 }, 16317 "example": ["\n<div>\n<code>\nvar m = minute();\ntext('Current minute: \\n' + m, 5, 50);\n</code>\n</div>"], 16318 "alt": "Current minute is displayed", 16319 "class": "p5", 16320 "module": "IO", 16321 "submodule": "Time & Date" 16322 }, { 16323 "file": "src/utilities/time_date.js", 16324 "line": 78, 16325 "description": "<p>Returns the number of milliseconds (thousandths of a second) since\nstarting the program. This information is often used for timing events and\nanimation sequences.</p>\n", 16326 "itemtype": "method", 16327 "name": "millis", 16328 "return": { 16329 "description": "the number of milliseconds since starting the program", 16330 "type": "Number" 16331 }, 16332 "example": ["\n<div>\n<code>\nvar millisecond = millis();\ntext('Milliseconds \\nrunning: \\n' + millisecond, 5, 40);\n</code>\n</div>"], 16333 "alt": "number of milliseconds since program has started displayed", 16334 "class": "p5", 16335 "module": "IO", 16336 "submodule": "Time & Date" 16337 }, { 16338 "file": "src/utilities/time_date.js", 16339 "line": 101, 16340 "description": "<p>p5.js communicates with the clock on your computer. The <a href=\"#/p5/month\">month()</a> function\nreturns the current month as a value from 1 - 12.</p>\n", 16341 "itemtype": "method", 16342 "name": "month", 16343 "return": { 16344 "description": "the current month", 16345 "type": "Integer" 16346 }, 16347 "example": ["\n<div>\n<code>\nvar m = month();\ntext('Current month: \\n' + m, 5, 50);\n</code>\n</div>"], 16348 "alt": "Current month is displayed", 16349 "class": "p5", 16350 "module": "IO", 16351 "submodule": "Time & Date" 16352 }, { 16353 "file": "src/utilities/time_date.js", 16354 "line": 123, 16355 "description": "<p>p5.js communicates with the clock on your computer. The <a href=\"#/p5/second\">second()</a> function\nreturns the current second as a value from 0 - 59.</p>\n", 16356 "itemtype": "method", 16357 "name": "second", 16358 "return": { 16359 "description": "the current second", 16360 "type": "Integer" 16361 }, 16362 "example": ["\n<div>\n<code>\nvar s = second();\ntext('Current second: \\n' + s, 5, 50);\n</code>\n</div>"], 16363 "alt": "Current second is displayed", 16364 "class": "p5", 16365 "module": "IO", 16366 "submodule": "Time & Date" 16367 }, { 16368 "file": "src/utilities/time_date.js", 16369 "line": 145, 16370 "description": "<p>p5.js communicates with the clock on your computer. The <a href=\"#/p5/year\">year()</a> function\nreturns the current year as an integer (2014, 2015, 2016, etc).</p>\n", 16371 "itemtype": "method", 16372 "name": "year", 16373 "return": { 16374 "description": "the current year", 16375 "type": "Integer" 16376 }, 16377 "example": ["\n<div>\n<code>\nvar y = year();\ntext('Current year: \\n' + y, 5, 50);\n</code>\n</div>"], 16378 "alt": "Current year is displayed", 16379 "class": "p5", 16380 "module": "IO", 16381 "submodule": "Time & Date" 16382 }, { 16383 "file": "src/webgl/3d_primitives.js", 16384 "line": 15, 16385 "description": "<p>Draw a plane with given a width and height</p>\n", 16386 "itemtype": "method", 16387 "name": "plane", 16388 "params": [{ 16389 "name": "width", 16390 "description": "<p>width of the plane</p>\n", 16391 "type": "Number", 16392 "optional": true 16393 }, { 16394 "name": "height", 16395 "description": "<p>height of the plane</p>\n", 16396 "type": "Number", 16397 "optional": true 16398 }, { 16399 "name": "detailX", 16400 "description": "<p>Optional number of triangle\n subdivisions in x-dimension</p>\n", 16401 "type": "Integer", 16402 "optional": true 16403 }, { 16404 "name": "detailY", 16405 "description": "<p>Optional number of triangle\n subdivisions in y-dimension</p>\n", 16406 "type": "Integer", 16407 "optional": true 16408 }], 16409 "chainable": 1, 16410 "example": ["\n<div>\n<code>
16410\n//draw a plane with width 50 and height 50\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n plane(50, 50);\n}\n</code>\n</div>"], 16411 "alt": "Nothing displayed on canvas\nRotating interior view of a box with sides that change color.\n3d red and green gradient.\nRotating interior view of a cylinder with sides that change color.\nRotating view of a cylinder with sides that change color.\n3d red and green gradient.\nrotating view of a multi-colored cylinder with concave sides.", 16412 "class": "p5", 16413 "module": "Shape", 16414 "submodule": "3D Primitives" 16415 }, { 16416 "file": "src/webgl/3d_primitives.js", 16417 "line": 98, 16418 "description": "<p>Draw a box with given width, height and depth</p>\n", 16419 "itemtype": "method", 16420 "name": "box", 16421 "params": [{ 16422 "name": "width", 16423 "description": "<p>width of the box</p>\n", 16424 "type": "Number", 16425 "optional": true 16426 }, { 16427 "name": "Height", 16428 "description": "<p>height of the box</p>\n", 16429 "type": "Number", 16430 "optional": true 16431 }, { 16432 "name": "depth", 16433 "description": "<p>depth of the box</p>\n", 16434 "type": "Number", 16435 "optional": true 16436 }, { 16437 "name": "detailX", 16438 "description": "<p>Optional number of triangle\n subdivisions in x-dimension</p>\n", 16439 "type": "Integer", 16440 "optional": true 16441 }, { 16442 "name": "detailY", 16443 "description": "<p>Optional number of triangle\n subdivisions in y-dimension</p>\n", 16444 "type": "Integer", 16445 "optional": true 16446 }], 16447 "chainable": 1, 16448 "example": ["\n<div>\n<code>\n//draw a spinning box with width, height and depth 200\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n rotateX(frameCount * 0.01);\n rotateY(frameCount * 0.01);\n box(50);\n}\n</code>\n</div>"], 16449 "class": "p5", 16450 "module": "Shape", 16451 "submodule": "3D Primitives" 16452 }, { 16453 "file": "src/webgl/3d_primitives.js", 16454 "line": 215, 16455 "description": "<p>Draw a sphere with given radius</p>\n", 16456 "itemtype": "method", 16457 "name": "sphere", 16458 "params": [{ 16459 "name": "radius", 16460 "description": "<p>radius of circle</p>\n", 16461 "type": "Number", 16462 "optional": true 16463 }, { 16464 "name": "detailX", 16465 "description": "<p>number of segments,\n the more segments the smoother geometry\n default is 24</p>\n", 16466 "type": "Integer", 16467 "optional": true 16468 }, { 16469 "name": "detailY", 16470 "description": "<p>number of segments,\n the more segments the smoother geometry\n default is 16</p>\n", 16471 "type": "Integer", 16472 "optional": true 16473 }], 16474 "chainable": 1, 16475 "example": ["\n<div>\n<code>\n// draw a sphere with radius 200\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n sphere(40);\n}\n</code>\n</div>"], 16476 "class": "p5", 16477 "module": "Shape", 16478 "submodule": "3D Primitives" 16479 }, { 16480 "file": "src/webgl/3d_primitives.js", 16481 "line": 393, 16482 "description": "<p>Draw a cylinder with given radius and height</p>\n", 16483 "itemtype": "method", 16484 "name": "cylinder", 16485 "params": [{ 16486 "name": "radius", 16487 "description": "<p>radius of the surface</p>\n", 16488 "type": "Number", 16489 "optional": true 16490 }, { 16491 "name": "height", 16492 "description": "<p>height of the cylinder</p>\n", 16493 "type": "Number", 16494 "optional": true 16495 }, { 16496 "name": "detailX", 16497 "description": "<p>number of segments,\n the more segments the smoother geometry\n default is 24</p>\n", 16498 "type": "Integer", 16499 "optional": true 16500 }, { 16501 "name": "detailY", 16502 "description": "<p>number of segments in y-dimension,\n the more segments the smoother geometry\n default is 1</p>\n", 16503 "type": "Integer", 16504 "optional": true 16505 }, { 16506 "name": "bottomCap", 16507 "description": "<p>whether to draw the bottom of the cylinder</p>\n", 16508 "type": "Boolean", 16509 "optional": true 16510 }, { 16511 "name": "topCap", 16512 "description": "<p>whether to draw the top of the cylinder</p>\n", 16513 "type": "Boolean", 16514 "optional": true 16515 }], 16516 "chainable": 1, 16517 "example": ["\n<div>\n<code>
16517\n//draw a spinning cylinder with radius 20 and height 50\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n rotateX(frameCount * 0.01);\n rotateZ(frameCount * 0.01);\n cylinder(20, 50);\n}\n</code>\n</div>"], 16518 "class": "p5", 16519 "module": "Shape", 16520 "submodule": "3D Primitives" 16521 }, { 16522 "file": "src/webgl/3d_primitives.js", 16523 "line": 484, 16524 "description": "<p>Draw a cone with given radius and height</p>\n", 16525 "itemtype": "method", 16526 "name": "cone", 16527 "params": [{ 16528 "name": "radius", 16529 "description": "<p>radius of the bottom surface</p>\n", 16530 "type": "Number", 16531 "optional": true 16532 }, { 16533 "name": "height", 16534 "description": "<p>height of the cone</p>\n", 16535 "type": "Number", 16536 "optional": true 16537 }, { 16538 "name": "detailX", 16539 "description": "<p>number of segments,\n the more segments the smoother geometry\n default is 24</p>\n", 16540 "type": "Integer", 16541 "optional": true 16542 }, { 16543 "name": "detailY", 16544 "description": "<p>number of segments,\n the more segments the smoother geometry\n default is 1</p>\n", 16545 "type": "Integer", 16546 "optional": true 16547 }, { 16548 "name": "cap", 16549 "description": "<p>whether to draw the base of the cone</p>\n", 16550 "type": "Boolean", 16551 "optional": true 16552 }], 16553 "chainable": 1, 16554 "example": ["\n<div>\n<code>\n//draw a spinning cone with radius 40 and height 70\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n rotateX(frameCount * 0.01);\n rotateZ(frameCount * 0.01);\n cone(40, 70);\n}\n</code>\n</div>"], 16555 "class": "p5", 16556 "module": "Shape", 16557 "submodule": "3D Primitives" 16558 }, { 16559 "file": "src/webgl/3d_primitives.js", 16560 "line": 555, 16561 "description": "<p>Draw an ellipsoid with given radius</p>\n", 16562 "itemtype": "method", 16563 "name": "ellipsoid", 16564 "params": [{ 16565 "name": "radiusx", 16566 "description": "<p>xradius of circle</p>\n", 16567 "type": "Number", 16568 "optional": true 16569 }, { 16570 "name": "radiusy", 16571 "description": "<p>yradius of circle</p>\n", 16572 "type": "Number", 16573 "optional": true 16574 }, { 16575 "name": "radiusz", 16576 "description": "<p>zradius of circle</p>\n", 16577 "type": "Number", 16578 "optional": true 16579 }, { 16580 "name": "detailX", 16581 "description": "<p>number of segments,\n the more segments the smoother geometry\n default is 24. Avoid detail number above\n 150, it may crash the browser.</p>\n", 16582 "type": "Integer", 16583 "optional": true 16584 }, { 16585 "name": "detailY", 16586 "description": "<p>number of segments,\n the more segments the smoother geometry\n default is 16. Avoid detail number above\n 150, it may crash the browser.</p>\n", 16587 "type": "Integer", 16588 "optional": true 16589 }], 16590 "chainable": 1, 16591 "example": ["\n<div>\n<code>\n// draw an ellipsoid with radius 20, 30 and 40.\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n ellipsoid(20, 30, 40);\n}\n</code>\n</div>"], 16592 "class": "p5", 16593 "module": "Shape", 16594 "submodule": "3D Primitives" 16595 }, { 16596 "file": "src/webgl/3d_primitives.js", 16597 "line": 645, 16598 "description": "<p>Draw a torus with given radius and tube radius</p>\n", 16599 "itemtype": "method", 16600 "name": "torus", 16601 "params": [{ 16602 "name": "radius", 16603 "description": "<p>radius of the whole ring</p>\n", 16604 "type": "Number", 16605 "optional": true 16606 }, { 16607 "name": "tubeRadius", 16608 "description": "<p>radius of the tube</p>\n", 16609 "type": "Number", 16610 "optional": true 16611 }, { 16612 "name": "detailX", 16613 "description": "<p>number of segments in x-dimension,\n the more segments the smoother geometry\n default is 24</p>\n", 16614 "type": "Integer", 16615 "optional": true 16616 }, { 16617 "name": "detailY", 16618 "description": "<p>number of segments in y-dimension,\n the more segments the smoother geometry\n default is 16</p>\n", 16619 "type": "Integer", 16620 "optional": true 16621 }], 16622 "chainable": 1, 16623 "example": ["\n<div>\n<code>
16623\n//draw a spinning torus with radius 200 and tube radius 60\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n rotateX(frameCount * 0.01);\n rotateY(frameCount * 0.01);\n torus(50, 15);\n}\n</code>\n</div>"], 16624 "class": "p5", 16625 "module": "Shape", 16626 "submodule": "3D Primitives" 16627 }, { 16628 "file": "src/webgl/interaction.js", 16629 "line": 13, 16630 "description": "<p>Allows movement around a 3D sketch using a mouse or trackpad. Left-clicking\nand dragging will rotate the camera position about the center of the sketch,\nright-clicking and dragging will pan the camera position without rotation,\nand using the mouse wheel (scrolling) will move the camera closer or further\nfrom the center of the sketch. This function can be called with parameters\ndictating sensitivity to mouse movement along the X and Y axes. Calling\nthis function without parameters is equivalent to calling orbitControl(1,1).\nTo reverse direction of movement in either axis, enter a negative number\nfor sensitivity.</p>\n", 16631 "itemtype": "method", 16632 "name": "orbitControl", 16633 "params": [{ 16634 "name": "sensitivityX", 16635 "description": "<p>sensitivity to mouse movement along X axis</p>\n", 16636 "type": "Number", 16637 "optional": true 16638 }, { 16639 "name": "sensitivityY", 16640 "description": "<p>sensitivity to mouse movement along Y axis</p>\n", 16641 "type": "Number", 16642 "optional": true 16643 }], 16644 "chainable": 1, 16645 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n normalMaterial();\n}\nfunction draw() {\n background(200);\n orbitControl();\n rotateY(0.5);\n box(30, 50);\n}\n</code>\n</div>"], 16646 "alt": "Camera orbits around a box when mouse is hold-clicked & then moved.", 16647 "class": "p5", 16648 "module": "Lights, Camera", 16649 "submodule": "Interaction" 16650 }, { 16651 "file": "src/webgl/interaction.js", 16652 "line": 146, 16653 "description": "<p>debugMode() helps visualize 3D space by adding a grid to indicate where the\nâgroundâ is in a sketch and an axes icon which indicates the +X, +Y, and +Z\ndirections. This function can be called without parameters to create a\ndefault grid and axes icon, or it can be called according to the examples\nabove to customize the size and position of the grid and/or axes icon. The\ngrid is drawn using the most recently set stroke color and weight. To\nspecify these parameters, add a call to stroke() and strokeWeight(
16653)\njust before the end of the draw() loop.</p>\n<p>By default, the grid will run through the origin (0,0,0) of the sketch\nalong the XZ plane\nand the axes icon will be offset from the origin. Both the grid and axes\nicon will be sized according to the current canvas size. Note that because the\ngrid runs parallel to the default camera view, it is often helpful to use\ndebugMode along with orbitControl to allow full view of the grid.</p>\n", 16654 "itemtype": "method", 16655 "name": "debugMode", 16656 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n camera(0, -30, 100, 0, 0, 0, 0, 1, 0);\n normalMaterial();\n debugMode();\n}\n\nfunction draw() {\n background(200);\n orbitControl();\n box(15, 30);\n // Press the spacebar to turn debugMode off!\n if (keyIsDown(32)) {\n noDebugMode();\n }\n}\n</code>\n</div>", "\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n camera(0, -30, 100, 0, 0, 0, 0, 1, 0);\n normalMaterial();\n debugMode(GRID);\n}\n\nfunction draw() {\n background(200);\n orbitControl();\n box(15, 30);\n}\n</code>\n</div>", "\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n camera(0, -30, 100, 0, 0, 0, 0, 1, 0);\n normalMaterial();\n debugMode(AXES);\n}\n\nfunction draw() {\n background(200);\n orbitControl();\n box(15, 30);\n}\n</code>\n</div>", "\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n camera(0, -30, 100, 0, 0, 0, 0, 1, 0);\n normalMaterial();\n debugMode(GRID, 100, 10, 0, 0, 0);\n}\n\nfunction draw() {\n background(200);\n orbitControl();\n box(15, 30);\n}\n</code>\n</div>", "\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n camera(0, -30, 100, 0, 0, 0, 0, 1, 0);\n normalMaterial();\n debugMode(100, 10, 0, 0, 0, 20, 0, -40, 0);\n}\n\nfunction draw() {\n noStroke();\n background(200);\n orbitControl();\n box(15, 30);\n // set the stroke color and weight for the grid!\n stroke(255, 0, 150);\n strokeWeight(0.8);\n}\n</code>\n</div>"], 16657 "alt": "a 3D box is centered on a grid in a 3D sketch. an icon\nindicates the direction of each axis: a red line points +X,\na green line +Y, and a blue line +Z.", 16658 "class": "p5", 16659 "module": "Lights, Camera", 16660 "submodule": "Interaction", 16661 "overloads": [{ 16662 "line": 146, 16663 "params": [] 16664 }, { 16665 "line": 279, 16666 "params": [{ 16667 "name": "mode", 16668 "description": "<p>either GRID or AXES</p>\n", 16669 "type": "Constant" 16670 }] 16671 }, { 16672 "line": 284, 16673 "params": [{ 16674 "name": "mode", 16675 "description": "", 16676 "type": "Constant" 16677 }, { 16678 "name": "gridSize", 16679 "description": "<p>size of one side of the grid</p>\n", 16680 "type": "Number", 16681 "optional": true 16682 }, { 16683 "name": "gridDivisions", 16684 "description": "<p>number of divisions in the grid</p>\n", 16685 "type": "Number", 16686 "optional": true 16687 }, { 16688 "name": "xOff", 16689 "description": "<p>X axis offset from origin (0,0,0)</p>\n", 16690 "type": "Number", 16691 "optional": true 16692 }, { 16693 "name": "yOff", 16694 "description": "<p>Y axis offset from origin (0,0,0)</p>\n", 16695 "type": "Number", 16696 "optional": true 16697 }, { 16698 "name": "zOff", 16699 "description": "<p>Z axis offset from origin (0,0,0)</p>\n", 16700 "type": "Number", 16701 "optional": true 16702 }] 16703 }, { 16704 "line": 294, 16705 "params": [{ 16706 "name": "mode", 16707 "description": "", 16708 "type": "Constant" 16709 }, { 16710 "name": "axesSize", 16711 "description": "<p>size of axes icon</p>\n", 16712 "type": "Number", 16713 "optional": true 16714 }, { 16715 "name": "xOff", 16716 "description": "", 16717 "type": "Number", 16718 "optional": true 16719 }, { 16720 "name": "yOff", 16721 "description": "", 16722 "type": "Number", 16723 "optional": true 16724 }, { 16725 "name": "zOff", 16726 "description": "", 16727 "type": "Number", 16728 "optional": true 16729 }] 16730 }, { 16731 "line": 303, 16732 "params": [{ 16733 "name": "gridSize", 16734 "description": "", 16735 "type": "Number", 16736 "optional": true 16737 }, { 16738 "name": "gridDivisions", 16739 "description": "", 16740 "type": "Number", 16741 "optional": true 16742 }, { 16743 "name": "gridXOff", 16744 "description": "", 16745 "type": "Number", 16746 "optional": true 16747 }, { 16748 "name": "gridYOff", 16749 "description": "", 16750 "type": "Number", 16751 "optional": true 16752 }, { 16753 "name": "gridZOff", 16754 "description": "", 16755 "type": "Number", 16756 "optional": true 16757 }, { 16758 "name": "axesSize", 16759 "description": "", 16760 "type": "Number", 16761 "optional": true 16762 }, { 16763 "name": "axesXOff", 16764 "description": "", 16765 "type": "Number", 16766 "optional": true 16767 }, { 16768 "name": "axesYOff", 16769 "description": "", 16770 "type": "Number", 16771 "optional": true 16772 }, { 16773 "name": "axesZOff", 16774 "description": "", 16775 "type": "Number", 16776 "optional": true 16777 }] 16778 }] 16779 }, { 16780 "file": "src/webgl/interaction.js", 16781 "line": 380, 16782 "description": "<p>Turns off debugMode() in a 3D sketch.</p>\n", 16783 "itemtype": "method", 16784 "name": "noDebugMode", 16785 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n camera(0, -30, 100, 0, 0, 0, 0, 1, 0);\n normalMaterial();\n debugMode();\n}\n\nfunction draw() {\n background(200);\n orbitControl();\n box(15, 30);\n // Press the spacebar to turn debugMode off!\n if (keyIsDown(32)) {\n noDebugMode();\n }\n}\n</code>\n</div>"], 16786 "alt": "a 3D box is centered on a grid in a 3D sketch. an icon\nindicates the direction of each axis: a red line points +X,\na green line +Y, and a blue line +Z. the grid and icon disappear when the\nspacebar is pressed.", 16787 "class": "p5", 16788 "module": "Lights, Camera", 16789 "submodule": "Interaction" 16790 }, { 16791 "file": "src/webgl/light.js", 16792 "line": 12, 16793 "description": "<p>Creates an ambient light with a color</p>\n", 16794 "itemtype": "method", 16795 "name": "ambientLight", 16796 "chainable": 1, 16797 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\nfunction draw() {\n background(0);\n ambientLight(150);\n ambientMaterial(250);\n noStroke();\n sphere(25);\n}\n</code>\n</div>"], 16798 "alt": "evenly distributed light across a sphere", 16799 "class": "p5", 16800 "module": "Lights, Camera", 16801 "submodule": "Lights", 16802 "overloads": [{ 16803 "line": 12, 16804 "params": [{ 16805 "name": "v1", 16806 "description": "<p>red or hue value relative to\n the current color range</p>\n", 16807 "type": "Number" 16808 }, { 16809 "name": "v2", 16810 "description": "<p>
16810green or saturation value\n relative to the current color range</p>\n", 16811 "type": "Number" 16812 }, { 16813 "name": "v3", 16814 "description": "<p>blue or brightness value\n relative to the current color range</p>\n", 16815 "type": "Number" 16816 }, { 16817 "name": "alpha", 16818 "description": "<p>the alpha value</p>\n", 16819 "type": "Number", 16820 "optional": true 16821 }], 16822 "chainable": 1 16823 }, { 16824 "line": 46, 16825 "params": [{ 16826 "name": "value", 16827 "description": "<p>a color string</p>\n", 16828 "type": "String" 16829 }], 16830 "chainable": 1 16831 }, { 16832 "line": 52, 16833 "params": [{ 16834 "name": "gray", 16835 "description": "<p>a gray value</p>\n", 16836 "type": "Number" 16837 }, { 16838 "name": "alpha", 16839 "description": "", 16840 "type": "Number", 16841 "optional": true 16842 }], 16843 "chainable": 1 16844 }, { 16845 "line": 59, 16846 "params": [{ 16847 "name": "values", 16848 "description": "<p>an array containing the red,green,blue &\n and alpha components of the color</p>\n", 16849 "type": "Number[]" 16850 }], 16851 "chainable": 1 16852 }, { 16853 "line": 66, 16854 "params": [{ 16855 "name": "color", 16856 "description": "<p>the ambient light color</p>\n", 16857 "type": "p5.Color" 16858 }], 16859 "chainable": 1 16860 }] 16861 }, { 16862 "file": "src/webgl/light.js", 16863 "line": 101, 16864 "description": "<p>Creates a directional light with a color and a direction</p>\n", 16865 "itemtype": "method", 16866 "name": "directionalLight", 16867 "chainable": 1, 16868 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\nfunction draw() {\n background(0);\n //move your mouse to change light direction\n let dirX = (mouseX / width - 0.5) * 2;\n let dirY = (mouseY / height - 0.5) * 2;\n directionalLight(250, 250, 250, -dirX, -dirY, 0.25);\n ambientMaterial(250);\n noStroke();\n sphere(25);\n}\n</code>\n</div>"], 16869 "alt": "light source on canvas changeable with mouse position", 16870 "class": "p5", 16871 "module": "Lights, Camera", 16872 "submodule": "Lights", 16873 "overloads": [{ 16874 "line": 101, 16875 "params": [{ 16876 "name": "v1", 16877 "description": "<p>red or hue value (depending on the current\ncolor mode),</p>\n", 16878 "type": "Number" 16879 }, { 16880 "name": "v2", 16881 "description": "<p>green or saturation value</p>\n", 16882 "type": "Number" 16883 }, { 16884 "name": "v3", 16885 "description": "<p>blue or brightness value</p>\n", 16886 "type": "Number" 16887 }, { 16888 "name": "position", 16889 "description": "<p>the direction of the light</p>\n", 16890 "type": "p5.Vector" 16891 }], 16892 "chainable": 1 16893 }, { 16894 "line": 134, 16895 "params": [{ 16896 "name": "color", 16897 "description": "<p>color Array, CSS color string,\n or <a href=\"#/p5.Color\">p5.Color</a> value</p>\n", 16898 "type": "Number[]|String|p5.Color" 16899 }, { 16900 "name": "x", 16901 "description": "<p>x axis direction</p>\n", 16902 "type": "Number" 16903 }, { 16904 "name": "y", 16905 "description": "<p>y axis direction</p>\n", 16906 "type": "Number" 16907 }, { 16908 "name": "z", 16909 "description": "<p>z axis direction</p>\n", 16910 "type": "Number" 16911 }], 16912 "chainable": 1 16913 }, { 16914 "line": 144, 16915 "params": [{ 16916 "name": "color", 16917 "description": "", 16918 "type": "Number[]|String|p5.Color" 16919 }, { 16920 "name": "position", 16921 "description": "", 16922 "type": "p5.Vector" 16923 }], 16924 "chainable": 1 16925 }, { 16926 "line": 151, 16927 "params": [{ 16928 "name": "v1", 16929 "description": "", 16930 "type": "Number" 16931 }, { 16932 "name": "v2", 16933 "description": "", 16934 "type": "Number" 16935 }, { 16936 "name": "v3", 16937 "description": "", 16938 "type": "Number" 16939 }, { 16940 "name": "x", 16941 "description": "", 16942 "type": "Number" 16943 }, { 16944 "name": "y", 16945 "description": "", 16946 "type": "Number" 16947 }, { 16948 "name": "z", 16949 "description": "", 16950 "type": "Number" 16951 }], 16952 "chainable": 1 16953 }] 16954 }, { 16955 "file": "src/webgl/light.js", 16956 "line": 212, 16957 "description": "<p>Creates a point light with a color and a light position</p>\n", 16958 "itemtype": "method", 16959 "name": "pointLight", 16960 "chainable": 1, 16961 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\nfunction draw() {\n background(0);\n //move your mouse to change light position\n let locX = mouseX - width / 2;
16961\n let locY = mouseY - height / 2;\n // to set the light position,\n // think of the world's coordinate as:\n // -width/2,-height/2 -------- width/2,-height/2\n // | |\n // | 0,0 |\n // | |\n // -width/2,height/2--------width/2,height/2\n pointLight(250, 250, 250, locX, locY, 50);\n ambientMaterial(250);\n noStroke();\n sphere(25);\n}\n</code>\n</div>"], 16962 "alt": "spot light on canvas changes position with mouse", 16963 "class": "p5", 16964 "module": "Lights, Camera", 16965 "submodule": "Lights", 16966 "overloads": [{ 16967 "line": 212, 16968 "params": [{ 16969 "name": "v1", 16970 "description": "<p>red or hue value (depending on the current\ncolor mode),</p>\n", 16971 "type": "Number" 16972 }, { 16973 "name": "v2", 16974 "description": "<p>green or saturation value</p>\n", 16975 "type": "Number" 16976 }, { 16977 "name": "v3", 16978 "description": "<p>blue or brightness value</p>\n", 16979 "type": "Number" 16980 }, { 16981 "name": "x", 16982 "description": "<p>x axis position</p>\n", 16983 "type": "Number" 16984 }, { 16985 "name": "y", 16986 "description": "<p>y axis position</p>\n", 16987 "type": "Number" 16988 }, { 16989 "name": "z", 16990 "description": "<p>z axis position</p>\n", 16991 "type": "Number" 16992 }], 16993 "chainable": 1 16994 }, { 16995 "line": 254, 16996 "params": [{ 16997 "name": "v1", 16998 "description": "", 16999 "type": "Number" 17000 }, { 17001 "name": "v2", 17002 "description": "", 17003 "type": "Number" 17004 }, { 17005 "name": "v3", 17006 "description": "", 17007 "type": "Number" 17008 }, { 17009 "name": "position", 17010 "description": "<p>the position of the light</p>\n", 17011 "type": "p5.Vector" 17012 }], 17013 "chainable": 1 17014 }, { 17015 "line": 263, 17016 "params": [{ 17017 "name": "color", 17018 "description": "<p>color Array, CSS color string,\nor <a href=\"#/p5.Color\">p5.Color</a> value</p>\n", 17019 "type": "Number[]|String|p5.Color" 17020 }, { 17021 "name": "x", 17022 "description": "", 17023 "type": "Number" 17024 }, { 17025 "name": "y", 17026 "description": "", 17027 "type": "Number" 17028 }, { 17029 "name": "z", 17030 "description": "", 17031 "type": "Number" 17032 }], 17033 "chainable": 1 17034 }, { 17035 "line": 273, 17036 "params": [{ 17037 "name": "color", 17038 "description": "", 17039 "type": "Number[]|String|p5.Color" 17040 }, { 17041 "name": "position", 17042 "description": "", 17043 "type": "p5.Vector" 17044 }], 17045 "chainable": 1 17046 }] 17047 }, { 17048 "file": "src/webgl/loading.js", 17049 "line": 14, 17050 "description": "<p>Load a 3d model from an OBJ file.\n<br><br>\nOne of the limitations of the OBJ format is that it doesn't have a built-in\nsense of scale. This means that models exported from different programs might\nbe very different sizes. If your model isn't displaying, try calling\n<a href=\"#/p5/loadModel\">loadModel()</a> with the normalized parameter set to true. This will resize the\nmodel to a scale appropriate for p5. You can also make additional changes to\nthe final size of your model with the <a href=\"#/p5/scale\">scale()</a> function.</p>\n", 17051 "itemtype": "method", 17052 "name": "loadModel", 17053 "return": { 17054 "description": "the <a href=\"#/p5.Geometry\">p5.Geometry</a> object", 17055 "type": "p5.Geometry" 17056 }, 17057 "example": ["\n<div>\n<code>\n//draw a spinning octahedron\nlet octahedron;\n\nfunction preload() {\n octahedron = loadModel('assets/octahedron.obj');\n}\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n rotateX(frameCount * 0.01);\n rotateY(frameCount * 0.01);\n model(octahedron);\n}\n</code>\n</div>", "\n<div>\n<code>
17057\n//draw a spinning teapot\nlet teapot;\n\nfunction preload() {\n // Load model with normalise parameter set to true\n teapot = loadModel('assets/teapot.obj', true);\n}\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n scale(0.4); // Scaled to make model fit into canvas\n rotateX(frameCount * 0.01);\n rotateY(frameCount * 0.01);\n normalMaterial(); // For effect\n model(teapot);\n}\n</code>\n</div>"], 17058 "alt": "Vertically rotating 3-d teapot with red, green and blue gradient.", 17059 "class": "p5", 17060 "module": "Shape", 17061 "submodule": "3D Models", 17062 "overloads": [{ 17063 "line": 14, 17064 "params": [{ 17065 "name": "path", 17066 "description": "<p>Path of the model to be loaded</p>\n", 17067 "type": "String" 17068 }, { 17069 "name": "normalize", 17070 "description": "<p>If true, scale the model to a\n standardized size when loading</p>\n", 17071 "type": "Boolean" 17072 }, { 17073 "name": "successCallback", 17074 "description": "<p>Function to be called\n once the model is loaded. Will be passed\n the 3D model object.</p>\n", 17075 "type": "function(p5.Geometry)", 17076 "optional": true 17077 }, { 17078 "name": "failureCallback", 17079 "description": "<p>called with event error if\n the image fails to load.</p>\n", 17080 "type": "Function(Event)", 17081 "optional": true 17082 }], 17083 "return": { 17084 "description": "the <a href=\"#/p5.Geometry\">p5.Geometry</a> object", 17085 "type": "p5.Geometry" 17086 } 17087 }, { 17088 "line": 90, 17089 "params": [{ 17090 "name": "path", 17091 "description": "", 17092 "type": "String" 17093 }, { 17094 "name": "successCallback", 17095 "description": "", 17096 "type": "function(p5.Geometry)", 17097 "optional": true 17098 }, { 17099 "name": "failureCallback", 17100 "description": "", 17101 "type": "Function(Event)", 17102 "optional": true 17103 }], 17104 "return": { 17105 "description": "the <a href=\"#/p5.Geometry\">p5.Geometry</a> object", 17106 "type": "p5.Geometry" 17107 } 17108 }] 17109 }, { 17110 "file": "src/webgl/loading.js", 17111 "line": 135, 17112 "description": "<p>Parse OBJ lines into model. For reference, this is what a simple model of a\nsquare might look like:</p>\n<p>v -0.5 -0.5 0.5\nv -0.5 -0.5 -0.5\nv -0.5 0.5 -0.5\nv -0.5 0.5 0.5</p>\n<p>f 4 3 2 1</p>\n", 17113 "class": "p5", 17114 "module": "Shape", 17115 "submodule": "3D Models" 17116 }, { 17117 "file": "src/webgl/loading.js", 17118 "line": 244, 17119 "description": "<p>Render a 3d model to the screen.</p>\n", 17120 "itemtype": "method", 17121 "name": "model", 17122 "params": [{ 17123 "name": "model", 17124 "description": "<p>Loaded 3d model to be rendered</p>\n", 17125 "type": "p5.Geometry" 17126 }], 17127 "example": ["\n<div>\n<code>\n//draw a spinning octahedron\nlet octahedron;\n\nfunction preload() {\n octahedron = loadModel('assets/octahedron.obj');\n}\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n rotateX(frameCount * 0.01);\n rotateY(frameCount * 0.01);\n model(octahedron);\n}\n</code>\n</div>"], 17128 "alt": "Vertically rotating 3-d octahedron.", 17129 "class": "p5", 17130 "module": "Shape", 17131 "submodule": "3D Models" 17132 }, { 17133 "file": "src/webgl/material.js", 17134 "line": 14, 17135 "description": "<p>Loads a custom shader from the provided vertex and fragment\nshader paths. The shader files are loaded asynchronously in the\nbackground, so this method should be used in <a href=\"#/p5/preload\">preload()</a>.</p>\n<p>For now, there are three main types of shaders. p5 will automatically\nsupply appropriate vertices, normals, colors, and lighting attributes\nif the parameters defined in the shader match the names.</p>\n", 17136 "itemtype": "method", 17137 "name": "loadShader", 17138 "params": [{ 17139 "name": "vertFilename", 17140 "description": "<p>path to file containing vertex shader\nsource code</p>\n", 17141 "type": "String", 17142 "optional": true 17143 }, { 17144 "name": "fragFilename", 17145 "description": "<p>path to file containing fragment shader\nsource code</p>\n", 17146 "type": "String", 17147 "optional": true 17148 }], 17149 "return": { 17150 "description": "a shader object created from the provided\nvertex and fragment shader files.", 17151 "type": "p5.Shader" 17152 }, 17153 "example": ["\n<div modernizr='webgl'>\n<code>\nlet mandel;\nfunction preload() {\n // load the shader definitions from files\n mandel = loadShader('assets/shader.vert', 'assets/shader.frag');\n}\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n // use the shader\n shader(mandel);\n noStroke();\n mandel.setUniform('p', [-0.74364388703, 0.13182590421]);\n}\n\nfunction draw() {\n mandel.setUniform('r', 1.5 * exp(-6.5 * (1 + sin(millis() / 2000))));\n quad(-1, -1, 1, -1, 1, 1, -1, 1);\n}\n</code>\n</div>"], 17154 "alt": "zooming Mandelbrot set. a colorful, infinitely detailed fractal.", 17155 "class": "p5", 17156 "module": "Lights, Camera", 17157 "submodule": "Material" 17158 }, { 17159 "file": "src/webgl/material.js", 17160 "line": 83, 17161 "itemtype": "method", 17162 "name": "createShader", 17163 "params": [{ 17164 "name": "vertSrc", 17165 "description": "<p>source code for the vertex shader</p>\n", 17166 "type": "String" 17167 }, { 17168 "name": "fragSrc", 17169 "description": "<p>source code for the fragment shader</p>\n", 17170 "type": "String" 17171 }], 17172 "return": { 17173 "description": "a shader object created from the provided\nvertex and fragment shaders.", 17174 "type": "p5.Shader" 17175 }, 17176 "example": ["\n<div modernizr='webgl'>\n<code>\n// the 'varying's are shared between both vertex & fragment shaders\nlet varying = 'precision highp float; varying vec2 vPos;';\n\n// the vertex shader is called for each vertex\nlet vs =\n varying +\n 'attribute vec3 aPosition;' +\n 'void main() { vPos = (gl_Position = vec4(aPosition,1.0)).xy; }';\n\n// the fragment shader is called for each pixel\nlet fs =\n varying +\n 'uniform vec2 p;' +\n 'uniform float r;' +\n 'const int I = 500;' +\n 'void main() {' +\n ' vec2 c = p + vPos * r, z = c;' +\n ' float n = 0.0;' +\n ' for (int i = I; i > 0; i --) {' +\n ' if(z.x*z.x+z.y*z.y > 4.0) {' +\n ' n = float(i)/float(I);' +\n ' break;' +\n ' }' +\n ' z = vec2(z.x*z.x-z.y*z.y, 2.0*z.x*z.y) + c;' +\n ' }
17176' +\n ' gl_FragColor = vec4(0.5-cos(n*17.0)/2.0,0.5-cos(n*13.0)/2.0,0.5-cos(n*23.0)/2.0,1.0);' +\n '}';\n\nlet mandel;\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n\n // create and initialize the shader\n mandel = createShader(vs, fs);\n shader(mandel);\n noStroke();\n\n // 'p' is the center point of the Mandelbrot image\n mandel.setUniform('p', [-0.74364388703, 0.13182590421]);\n}\n\nfunction draw() {\n // 'r' is the size of the image in Mandelbrot-space\n mandel.setUniform('r', 1.5 * exp(-6.5 * (1 + sin(millis() / 2000))));\n quad(-1, -1, 1, -1, 1, 1, -1, 1);\n}\n</code>\n</div>"], 17177 "alt": "zooming Mandelbrot set. a colorful, infinitely detailed fractal.", 17178 "class": "p5", 17179 "module": "Lights, Camera", 17180 "submodule": "Material" 17181 }, { 17182 "file": "src/webgl/material.js", 17183 "line": 151, 17184 "description": "<p>The <a href=\"#/p5/shader\">shader()</a> function lets the user provide a custom shader\nto fill in shapes in WEBGL mode. Users can create their\nown shaders by loading vertex and fragment shaders with\n<a href=\"#/p5/loadShader\">loadShader()</a>.</p>\n", 17185 "itemtype": "method", 17186 "name": "shader", 17187 "chainable": 1, 17188 "params": [{ 17189 "name": "s", 17190 "description": "<p>the desired <a href=\"#/p5.Shader\">p5.Shader</a> to use for rendering\nshapes.</p>\n", 17191 "type": "p5.Shader", 17192 "optional": true 17193 }], 17194 "class": "p5", 17195 "module": "Lights, Camera", 17196 "submodule": "Material" 17197 }, { 17198 "file": "src/webgl/material.js", 17199 "line": 176, 17200 "description": "<p>Normal material for geometry. You can view all\npossible materials in this\n<a href=\"https://p5js.org/examples/3d-materials.html\">example</a>.</p>\n", 17201 "itemtype": "method", 17202 "name": "normalMaterial", 17203 "chainable": 1, 17204 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(200);\n normalMaterial();\n sphere(50);\n}\n</code>\n</div>"], 17205 "alt": "Red, green and blue gradient.", 17206 "class": "p5", 17207 "module": "Lights, Camera", 17208 "submodule": "Material" 17209 }, { 17210 "file": "src/webgl/material.js", 17211 "line": 211, 17212 "description": "<p>Texture for geometry. You can view other possible materials in this\n<a href=\"https://p5js.org/examples/3d-materials.html\">example</a>.</p>\n", 17213 "itemtype": "method", 17214 "name": "texture", 17215 "params": [{ 17216 "name": "tex", 17217 "description": "<p>2-dimensional graphics\n to render as texture</p>\n", 17218 "type": "p5.Image|p5.MediaElement|p5.Graphics" 17219 }], 17220 "chainable": 1, 17221 "example": ["\n<div>\n<code>\nlet img;\nfunction preload() {\n img = loadImage('assets/laDefense.jpg');\n}\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(0);\n rotateZ(frameCount * 0.01);\n rotateX(frameCount * 0.01);\n rotateY(frameCount * 0.01);\n //pass image as texture\n texture(img);\n box(200, 200, 200);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet pg;\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n pg = createGraphics(200, 200);\n pg.textSize(100);\n}\n\nfunction draw() {\n background(0);\n pg.background(255);\n pg.text('hello!', 0, 100);\n //pass image as texture\n texture(pg);\n plane(200);\n}\n</code>\n</div>\n\n<div>\n<code>\nlet vid;\nfunction preload() {\n vid = createVideo('assets/fingers.mov');\n vid.hide();\n vid.loop();\n}\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(0);\n //pass video frame as texture\n texture(vid);\n plane(200);\n}\n</code>\n</div>"], 17222 "alt": "Rotating view of many images umbrella and grid roof on a 3d plane\nblack canvas\nblack canvas", 17223 "class": "p5", 17224 "module": "Lights, Camera", 17225 "submodule": "Material" 17226 }, { 17227 "file": "src/webgl/material.js", 17228 "line": 302, 17229 "description": "<p>Sets the coordinate space for texture mapping. The default mode is IMAGE\nwhich refers to the actual coordinates of the image.\nNORMAL refers to a normalized space of values ranging from 0 to 1.\
17229nThis function only works in WEBGL mode.</p>\n<p>With IMAGE, if an image is 100 x 200 pixels, mapping the image onto the entire\nsize of a quad would require the points (0,0) (100, 0) (100,200) (0,200).\nThe same mapping in NORMAL is (0,0) (1,0) (1,1) (0,1).</p>\n", 17230 "itemtype": "method", 17231 "name": "textureMode", 17232 "params": [{ 17233 "name": "mode", 17234 "description": "<p>either IMAGE or NORMAL</p>\n", 17235 "type": "Constant" 17236 }], 17237 "example": ["\n<div>\n<code>\nlet img;\n\nfunction preload() {\n img = loadImage('assets/laDefense.jpg');\n}\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n texture(img);\n textureMode(NORMAL);\n beginShape();\n vertex(-50, -50, 0, 0);\n vertex(50, -50, 1, 0);\n vertex(50, 50, 1, 1);\n vertex(-50, 50, 0, 1);\n endShape();\n}\n</code>\n</div>"], 17238 "alt": "the underside of a white umbrella and gridded ceiling above", 17239 "class": "p5", 17240 "module": "Lights, Camera", 17241 "submodule": "Material" 17242 }, { 17243 "file": "src/webgl/material.js", 17244 "line": 381, 17245 "description": "<p>Ambient material for geometry with a given color. You can view all\npossible materials in this\n<a href=\"https://p5js.org/examples/3d-materials.html\">example</a>.</p>\n", 17246 "itemtype": "method", 17247 "name": "ambientMaterial", 17248 "chainable": 1, 17249 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\nfunction draw() {\n background(0);\n ambientLight(100);\n pointLight(250, 250, 250, 100, 100, 0);\n ambientMaterial(250);\n sphere(50);\n}\n</code>\n</div>"], 17250 "alt": "radiating light source from top right of canvas", 17251 "class": "p5", 17252 "module": "Lights, Camera", 17253 "submodule": "Material", 17254 "overloads": [{ 17255 "line": 381, 17256 "params": [{ 17257 "name": "v1", 17258 "description": "<p>gray value, red or hue value\n (depending on the current color mode),</p>\n", 17259 "type": "Number" 17260 }, { 17261 "name": "v2", 17262 "description": "<p>green or saturation value</p>\n", 17263 "type": "Number", 17264 "optional": true 17265 }, { 17266 "name": "v3", 17267 "description": "<p>blue or brightness value</p>\n", 17268 "type": "Number", 17269 "optional": true 17270 }, { 17271 "name": "a", 17272 "description": "<p>opacity</p>\n", 17273 "type": "Number", 17274 "optional": true 17275 }], 17276 "chainable": 1 17277 }, { 17278 "line": 412, 17279 "params": [{ 17280 "name": "color", 17281 "description": "<p>color, color Array, or CSS color string</p>\n", 17282 "type": "Number[]|String|p5.Color" 17283 }], 17284 "chainable": 1 17285 }] 17286 }, { 17287 "file": "src/webgl/material.js", 17288 "line": 430, 17289 "description": "<p>Specular material for geometry with a given color. You can view all\npossible materials in this\n<a href=\"https://p5js.org/examples/3d-materials.html\">example</a>.</p>\n", 17290 "itemtype": "method", 17291 "name": "specularMaterial", 17292 "chainable": 1, 17293 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\nfunction draw() {\n background(0);\n ambientLight(100);\n pointLight(250, 250, 250, 100, 100, 0);\n specularMaterial(250);\n sphere(50);\n}\n</code>\n</div>"], 17294 "alt": "diffused radiating light source from top right of canvas", 17295 "class": "p5", 17296 "module": "Lights, Camera", 17297 "submodule": "Material", 17298 "overloads": [{ 17299 "line": 430, 17300 "params": [{ 17301 "name": "v1", 17302 "description": "<p>gray value, red or hue value\n (depending on the current color mode),</p>\n", 17303 "type": "Number" 17304 }, { 17305 "name": "v2", 17306 "description": "<p>green or saturation value</p>\n", 17307 "type": "Number", 17308 "optional": true 17309 }, { 17310 "name": "v3", 17311 "description": "<p>blue or brightness value</p>\n", 17312 "type": "Number", 17313 "optional": true 17314 }, { 17315 "name": "a", 17316 "description": "<p>opacity</p>\n", 17317 "type": "Number", 17318 "optional": true 17319 }], 17320 "chainable": 1 17321 }, { 17322 "line": 461, 17323 "params": [{ 17324 "name": "color", 17325 "description": "<p>color Array, or CSS color string</p>\n", 17326 "type": "Number[]|String|p5.Color" 17327 }], 17328 "chainable": 1 17329 }] 17330 }, { 17331 "file": "src/webgl/p5.Camera.js", 17332 "line": 15, 17333 "description": "<p>Sets the camera position for a 3D sketch. Parameters for this function define\nthe position for the camera, the center of the sketch (where the camera is\npointing), and an up direction (the orientation of the camera).</p>\n<p>When called with no arguments, this function creates a default camera\nequivalent to\ncamera(0, 0, (height/2.0) / tan(PI*30.0 / 180.0), 0, 0, 0, 0, 1, 0);</p>\n", 17334 "itemtype": "method", 17335 "name": "camera", 17336 "params": [{ 17337 "name": "x", 17338 "description": "<p>camera position value on x axis</p>\n", 17339 "type": "Number", 17340 "optional": true 17341 }, { 17342 "name": "y", 17343 "description": "<p>camera position value on y axis</p>\n", 17344 "type": "Number", 17345 "optional": true 17346 }, { 17347 "name": "z", 17348 "description": "<p>camera position value on z axis</p>\n", 17349 "type": "Number", 17350 "optional": true 17351 }, { 17352 "name": "centerX", 17353 "description": "<p>x coordinate representing center of the sketch</p>\n", 17354 "type": "Number", 17355 "optional": true 17356 }, { 17357 "name": "centerY", 17358 "description": "<p>y coordinate representing center of the sketch</p>\n", 17359 "type": "Number", 17360 "optional": true 17361 }, { 17362 "name": "centerZ", 17363 "description": "<p>z coordinate representing center of the sketch</p>\n", 17364 "type": "Number", 17365 "optional": true 17366 }, { 17367 "name": "upX", 17368 "description": "<p>x component of direction 'up' from camera</p>\n", 17369 "type": "Number", 17370 "optional": true 17371 }, { 17372 "name": "upY", 17373 "description": "<p>y component of direction 'up' from camera</p>\n", 17374 "type": "Number", 17375 "optional": true 17376 }, { 17377 "name": "upZ", 17378 "description": "<p>z component of direction 'up' from camera</p>\n", 17379 "type": "Number", 17380 "optional": true 17381 }], 17382 "chainable": 1, 17383 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\nfunction draw() {\n background(204);\n //move the camera away from the plane by a sin wave\n camera(0, 0, 20 + sin(frameCount * 0.01) * 10, 0, 0, 0, 0, 1, 0);\n plane(10, 10);\n}\n</code>\n</div>"], 17384 "alt": "White square repeatedly grows to fill canvas and then shrinks.", 17385 "class": "p5", 17386 "module": "Lights, Camera", 17387 "submodule": "Camera" 17388 }, { 17389 "file": "src/webgl/p5.Camera.js", 17390 "line": 61, 17391 "description": "<p>Sets a perspective projection for the camera in a 3D sketch. This projection\nrepresents depth through foreshortening: objects that are close to the camera\nappear their actual size while those that are further away from the camera\nappear smaller. The parameters to this function define the viewing frustum\n(the truncated pyramid within which objects are seen by the camera) through\nvertical field of view, aspect ratio (usually width/height), and near and far\nclipping planes.</p>\n<p>When called with no arguments, the defaults\nprovided are equivalent to\nperspective(PI/3.0, width/height, eyeZ/10.0, eyeZ<em>10.0), where eyeZ\nis equal to ((height/2.0) / tan(PI</em>60.0/360.0));</p>\n", 17392 "itemtype": "method", 17393 "name": "perspective", 17394 "params": [{ 17395 "name": "fovy", 17396 "description": "<p>camera frustum vertical field of view,\n from bottom to top of view, in <a href=\"#/p5/angleMode\">angleMode</a> units</p>\n", 17397 "type": "Number", 17398 "optional": true 17399 }, { 17400 "name": "aspect", 17401 "description": "<p>camera frustum aspect ratio</p>\n", 17402 "type": "Number", 17403 "optional": true 17404 }, { 17405 "name": "near", 17406 "description": "<p>frustum near plane length</p>\n", 17407 "type": "Number", 17408 "optional": true 17409 }, { 17410 "name": "far", 17411 "description": "<p>frustum far plane length</p>\n", 17412 "type": "Number", 17413 "optional": true 17414 }], 17415 "chainable": 1, 17416 "example": ["\n<div>\n<code>
17416\n//drag the mouse to look around!\n//you will see there's a vanishing point\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n perspective(PI / 3.0, width / height, 0.1, 500);\n}\nfunction draw() {\n background(200);\n orbitControl();\n normalMaterial();\n\n rotateX(-0.3);\n rotateY(-0.2);\n translate(0, 0, -50);\n\n push();\n translate(-15, 0, sin(frameCount / 30) * 95);\n box(30);\n pop();\n push();\n translate(15, 0, sin(frameCount / 30 + PI) * 95);\n box(30);\n pop();\n}\n</code>\n</div>"], 17417 "alt": "two colored 3D boxes move back and forth, rotating as mouse is dragged.", 17418 "class": "p5", 17419 "module": "Lights, Camera", 17420 "submodule": "Camera" 17421 }, { 17422 "file": "src/webgl/p5.Camera.js", 17423 "line": 126, 17424 "description": "<p>Sets an orthographic projection for the camera in a 3D sketch and defines a\nbox-shaped viewing frustum within which objects are seen. In this projection,\nall objects with the same dimension appear the same size, regardless of\nwhether they are near or far from the camera. The parameters to this\nfunction specify the viewing frustum where left and right are the minimum and\nmaximum x values, top and bottom are the minimum and maximum y values, and near\nand far are the minimum and maximum z values. If no parameters are given, the\ndefault is used: ortho(-width/2, width/2, -height/2, height/2).</p>\n", 17425 "itemtype": "method", 17426 "name": "ortho", 17427 "params": [{ 17428 "name": "left", 17429 "description": "<p>camera frustum left plane</p>\n", 17430 "type": "Number", 17431 "optional": true 17432 }, { 17433 "name": "right", 17434 "description": "<p>camera frustum right plane</p>\n", 17435 "type": "Number", 17436 "optional": true 17437 }, { 17438 "name": "bottom", 17439 "description": "<p>camera frustum bottom plane</p>\n", 17440 "type": "Number", 17441 "optional": true 17442 }, { 17443 "name": "top", 17444 "description": "<p>camera frustum top plane</p>\n", 17445 "type": "Number", 17446 "optional": true 17447 }, { 17448 "name": "near", 17449 "description": "<p>camera frustum near plane</p>\n", 17450 "type": "Number", 17451 "optional": true 17452 }, { 17453 "name": "far", 17454 "description": "<p>camera frustum far plane</p>\n", 17455 "type": "Number", 17456 "optional": true 17457 }], 17458 "chainable": 1, 17459 "example": ["\n<div>\n<code>\n//drag the mouse to look around!\n//there's no vanishing point\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n ortho(-width / 2, width / 2, height / 2, -height / 2, 0, 500);\n}\nfunction draw() {\n background(200);\n orbitControl();\n normalMaterial();\n\n rotateX(0.2);\n rotateY(-0.2);\n push();\n translate(-15, 0, sin(frameCount / 30) * 65);\n box(30);\n pop();\n push();\n translate(15, 0, sin(frameCount / 30 + PI) * 65);\n box(30);\n pop();\n}\n</code>\n</div>"], 17460 "alt": "two 3D boxes move back and forth along same plane, rotating as mouse is dragged.", 17461 "class": "p5", 17462 "module": "Lights, Camera", 17463 "submodule": "Camera" 17464 }, { 17465 "file": "src/webgl/p5.Camera.js", 17466 "line": 187, 17467 "description": "<p>Creates a new <a href=\"#/p5.Camera\">p5.Camera</a> object and tells the\nrenderer to use that camera.\nReturns the p5.Camera object.</p>\n", 17468 "itemtype": "method", 17469 "name": "createCamera", 17470 "return": { 17471 "description": "The newly created camera object.", 17472 "type": "p5.Camera" 17473 }, 17474 "class": "p5", 17475 "module": "Lights, Camera", 17476 "submodule": "Camera" 17477 }, { 17478 "file": "src/webgl/p5.Camera.js", 17479 "line": 298, 17480 "description": "<p>Sets a perspective projection for a p5.Camera object and sets parameters\nfor that projection according to <a href=\"#/p5/perspective\">perspective()</a>\nsyntax.</p>\n", 17481 "itemtype": "method", 17482 "name": "perspective", 17483 "class": "p5.Camera", 17484 "module": "Lights, Camera", 17485 "submodule": "Camera" 17486 }, { 17487 "file": "src/webgl/p5.Camera.js", 17488 "line": 379, 17489 "description": "<p>Sets an orthographic projection for a p5.Camera object and sets parameters\nfor that projection according to <a href=\"#/p5/ortho\">ortho()</a> syntax.</p>\n", 17490 "itemtype": "method", 17491 "name": "ortho", 17492 "class": "p5.Camera", 17493 "module": "Lights, Camera", 17494 "submodule": "Camera" 17495 }, { 17496 "file": "src/webgl/p5.Camera.js", 17497 "line": 486, 17498 "description": "<p>Panning rotates the camera view to the left and right.</p>\n", 17499 "itemtype": "method", 17500 "name": "pan", 17501 "params": [{ 17502 "name": "angle", 17503 "description": "<p>amount to rotate camera in current\n<a href=\"#/p5/angleMode\">angleMode</a> units.\nGreater than 0 values rotate counterclockwise (to the left).</p>\n", 17504 "type": "Number" 17505 }], 17506 "example": ["\n<div>\n<code>\nlet cam;\nlet delta = 0.01;\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n normalMaterial();\n cam = createCamera();\n // set initial pan angle\n cam.pan(-0.8);\n}\n\nfunction draw() {\n background(200);\n\n // pan camera according to angle 'delta'\n cam.pan(delta);\n\n // every 160 frames, switch direction\n if (frameCount % 160 === 0) {\n delta *= -1;\n }\n\n rotateX(frameCount * 0.01);\n translate(-100, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n}\n</code>\n</div>"], 17507 "alt": "camera view pans left and right across a series of rotating 3D boxes.", 17508 "class": "p5.Camera", 17509 "module": "Lights, Camera", 17510 "submodule": "Camera" 17511 }, { 17512 "file": "src/webgl/p5.Camera.js", 17513 "line": 545, 17514 "description": "<p>Tilting rotates the camera view up and down.</p>\n", 17515 "itemtype": "method", 17516 "name": "tilt", 17517 "params": [{ 17518 "name": "angle", 17519 "description": "<p>amount to rotate camera in current\n<a href=\"#/p5/angleMode\">angleMode</a> units.\nGreater than 0 values rotate counterclockwise (to the left).</p>\n", 17520 "type": "Number" 17521 }], 17522 "example": ["\n<div>\n<code>\nlet cam;\nlet delta = 0.01;\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n normalMaterial();\n cam = createCamera();\n // set initial tilt\n cam.tilt(-0.8);\n}\n\nfunction draw() {\n background(200);\n\n // pan camera according to angle 'delta'\n cam.tilt(delta);\n\n // every 160 frames, switch direction\n if (frameCount % 160 === 0) {\n delta *= -1;\n }\n\n rotateY(frameCount * 0.01);\n translate(0, -100, 0);\n box(20);\n translate(0, 35, 0);\n box(20);\n translate(0, 35, 0);\n box(20);\n translate(0, 35, 0);\n box(20);\n translate(0, 35, 0);\n box(20);\n translate(0, 35, 0);\n box(20);\n translate(0, 35, 0);\n box(20);\n}\n</code>\n</div>"], 17523 "alt": "camera view tilts up and down across a series of rotating 3D boxes.", 17524 "class": "p5.Camera", 17525 "module": "Lights, Camera", 17526 "submodule": "Camera" 17527 }, { 17528 "file": "src/webgl/p5.Camera.js", 17529 "line": 603, 17530 "description": "<p>Reorients the camera to look at a position in world space.</p>\n", 17531 "itemtype": "method", 17532 "name": "lookAt", 17533 "params": [{ 17534 "name": "x", 17535 "description": "<p>x position of a point in world space</p>\n", 17536 "type": "Number" 17537 }, { 17538 "name": "y", 17539 "description": "<p>y position of a point in world space</p>\n", 17540 "type": "Number" 17541 }, { 17542 "name": "z", 17543 "description": "<p>z position of a point in world space</p>\n", 17544 "type": "Number" 17545 }], 17546 "example": ["\n<div>\n<code>\nlet cam;\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n normalMaterial();\n cam = createCamera();\n}\n\nfunction draw() {\n background(200);\n\n // look at a new random point every 60 frames\n if (frameCount % 60 === 0) {\n cam.lookAt(random(-100, 100), random(-50, 50), 0);\n }\n\n rotateX(frameCount * 0.01);\n translate(-100, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n}\n</code>\n</div>"], 17547 "alt": "camera view of rotating 3D cubes changes to look at a new random\npoint every second .", 17548 "class": "p5.Camera", 17549 "module": "Lights, Camera", 17550 "submodule": "Camera" 17551 }, { 17552 "file": "src/webgl/p5.Camera.js", 17553 "line": 670, 17554 "description": "<p>Sets a camera's position and orientation. This is equivalent to calling\n<a href=\"#/p5/camera\">camera()</a> on a p5.Camera object.</p>\n", 17555 "itemtype": "method", 17556 "name": "camera", 17557 "class": "p5.Camera", 17558 "module": "Lights, Camera", 17559 "submodule": "Camera" 17560 }, { 17561 "file": "src/webgl/p5.Camera.js", 17562 "line": 751, 17563 "description": "<p>Move camera along its local axes while maintaining current camera orientation.</p>\n", 17564 "itemtype": "method", 17565 "name": "move", 17566 "params": [{ 17567 "name": "x", 17568 "description": "<p>amount to move along camera's left-right axis</p>\n", 17569 "type": "Number" 17570 }, { 17571 "name": "y", 17572 "description": "<p>amount to move along camera's up-down axis</p>\n", 17573 "type": "Number" 17574 }, { 17575 "name": "z", 17576 "description": "<p>amount to move along camera's forward-backward axis</p>\n", 17577 "type": "Number" 17578 }], 17579 "example": ["\n<div>\n<code>\n// see the camera move along its own axes while maintaining its orientation\nlet cam;\nlet delta = 0.5;\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n normalMaterial();\n cam = createCamera();\n}\n\nfunction draw() {\n background(200);\n\n // move the camera along its local axes\n cam.move(delta, delta, 0);\n\n // every 100 frames, switch direction\n if (frameCount % 150 === 0) {\n delta *= -1;\n }\n\n translate(-10, -10, 0);\n box(50, 8, 50);\n translate(15, 15, 0);\n box(50, 8, 50);\n translate(15, 15, 0);\n box(50, 8, 50);\n translate(15, 15, 0);\n box(50, 8, 50);\n translate(15, 15, 0);\n box(50, 8, 50);\n translate(15, 15, 0);\n box(50, 8, 50);\n}\n</code>\n</div>"], 17580 "alt": "camera view moves along a series of 3D boxes, maintaining the same\norientation throughout the move", 17581 "class": "p5.Camera", 17582 "module": "Lights, Camera", 17583 "submodule": "Camera" 17584 }, { 17585 "file": "src/webgl/p5.Camera.js", 17586 "line": 823, 17587 "description": "<p>Set camera position in world-space while maintaining current camera\norientation.</p>\n", 17588 "itemtype": "method", 17589 "name": "setPosition", 17590 "params": [{ 17591 "name": "x", 17592 "description": "<p>x position of a point in world space</p>\n", 17593 "type": "Number" 17594 }, { 17595 "name": "y", 17596 "description": "<p>y position of a point in world space</p>\n", 17597 "type": "Number" 17598 }, { 17599 "name": "z", 17600 "description": "<p>z position of a point in world space</p>\n", 17601 "type": "Number" 17602 }], 17603 "example": ["\n<div>\n<code>\n// press '1' '2' or '3' keys to set camera position\n\nlet cam;\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n normalMaterial();\n cam = createCamera();\n}\n\nfunction draw() {\n background(200);
17603\n\n // '1' key\n if (keyIsDown(49)) {\n cam.setPosition(30, 0, 80);\n }\n // '2' key\n if (keyIsDown(50)) {\n cam.setPosition(0, 0, 80);\n }\n // '3' key\n if (keyIsDown(51)) {\n cam.setPosition(-30, 0, 80);\n }\n\n box(20);\n}\n</code>\n</div>"], 17604 "alt": "camera position changes as the user presses keys, altering view of a 3D box", 17605 "class": "p5.Camera", 17606 "module": "Lights, Camera", 17607 "submodule": "Camera" 17608 }, { 17609 "file": "src/webgl/p5.Camera.js", 17610 "line": 1088, 17611 "description": "<p>Sets rendererGL's current camera to a p5.Camera object. Allows switching\nbetween multiple cameras.</p>\n", 17612 "itemtype": "method", 17613 "name": "setCamera", 17614 "params": [{ 17615 "name": "cam", 17616 "description": "<p>p5.Camera object</p>\n", 17617 "type": "p5.Camera" 17618 }], 17619 "example": ["\n<div>\n<code>\nlet cam1, cam2;\nlet currentCamera;\n\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n normalMaterial();\n\n cam1 = createCamera();\n cam2 = createCamera();\n cam2.setPosition(30, 0, 50);\n cam2.lookAt(0, 0, 0);\n cam2.ortho();\n\n // set variable for previously active camera:\n currentCamera = 1;\n}\n\nfunction draw() {\n background(200);\n\n // camera 1:\n cam1.lookAt(0, 0, 0);\n cam1.setPosition(sin(frameCount / 60) * 200, 0, 100);\n\n // every 100 frames, switch between the two cameras\n if (frameCount % 100 === 0) {\n if (currentCamera === 1) {\n setCamera(cam1);\n currentCamera = 0;\n } else {\n setCamera(cam2);\n currentCamera = 1;\n }\n }\n\n drawBoxes();\n}\n\nfunction drawBoxes() {\n rotateX(frameCount * 0.01);\n translate(-100, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n translate(35, 0, 0);\n box(20);\n}\n</code>\n</div>"], 17620 "alt": "Canvas switches between two camera views, each showing a series of spinning\n3D boxes.", 17621 "class": "p5", 17622 "module": "Lights, Camera", 17623 "submodule": "Camera" 17624 }, { 17625 "file": "src/webgl/p5.Geometry.js", 17626 "line": 50, 17627 "itemtype": "method", 17628 "name": "computeFaces", 17629 "chainable": 1, 17630 "class": "p5.Geometry", 17631 "module": "Lights, Camera" 17632 }, { 17633 "file": "src/webgl/p5.Geometry.js", 17634 "line": 92, 17635 "description": "<p>computes smooth normals per vertex as an average of each\nface.</p>\n", 17636 "itemtype": "method", 17637 "name": "computeNormals", 17638 "chainable": 1, 17639 "class": "p5.Geometry", 17640 "module": "Lights, Camera" 17641 }, { 17642 "file": "src/webgl/p5.Geometry.js", 17643 "line": 131, 17644 "description": "<p>Averages the vertex normals. Used in curved\nsurfaces</p>\n", 17645 "itemtype": "method", 17646 "name": "averageNormals", 17647 "chainable": 1, 17648 "class": "p5.Geometry", 17649 "module": "Lights, Camera" 17650 }, { 17651 "file": "src/webgl/p5.Geometry.js", 17652 "line": 152, 17653 "description": "<p>Averages pole normals. Used in spherical primitives</p>\n", 17654 "itemtype": "method", 17655 "name": "averagePoleNormals", 17656 "chainable": 1, 17657 "class": "p5.Geometry", 17658 "module": "Lights, Camera" 17659 }, { 17660 "file": "src/webgl/p5.Geometry.js", 17661 "line": 245, 17662 "description": "<p>Modifies all vertices to be centered within the range -100 to 100.</p>\n", 17663 "itemtype": "method", 17664 "name": "normalize", 17665 "chainable": 1, 17666 "class": "p5.Geometry", 17667 "module": "Lights, Camera" 17668 }, { 17669 "file": "src/webgl/p5.RendererGL.js", 17670 "line": 216, 17671 "description": "<p>Set attributes for the WebGL Drawing context.\nThis is a way of adjusting ways that the WebGL\nrenderer works to fine-tune the display and performance.\nThis should be put in setup().\nThe available attributes are:\n<br>\nalpha - indicates if the canvas contains an alpha buffer\ndefault is true\n<br><br>\ndepth - indicates whether the drawing buffer has a depth buffer\nof at least 16 bits - default is true\n<br><br>\nstencil - indicates whether the drawing buffer has a stencil buffer\nof at least 8 bits\n<br><br>
17671\nantialias - indicates whether or not to perform anti-aliasing\ndefault is false\n<br><br>\npremultipliedAlpha - indicates that the page compositor will assume\nthe drawing buffer contains colors with pre-multiplied alpha\ndefault is false\n<br><br>\npreserveDrawingBuffer - if true the buffers will not be cleared and\nand will preserve their values until cleared or overwritten by author\n(note that p5 clears automatically on draw loop)\ndefault is true\n<br><br>\nperPixelLighting - if true, per-pixel lighting will be used in the\nlighting shader.\ndefault is false\n<br><br></p>\n", 17672 "itemtype": "method", 17673 "name": "setAttributes", 17674 "example": ["\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n}\n\nfunction draw() {\n background(255);\n push();\n rotateZ(frameCount * 0.02);\n rotateX(frameCount * 0.02);\n rotateY(frameCount * 0.02);\n fill(0, 0, 0);\n box(50);\n pop();\n}\n</code>\n</div>\n<br>\nNow with the antialias attribute set to true.\n<br>\n<div>\n<code>\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n setAttributes('antialias', true);\n}\n\nfunction draw() {\n background(255);\n push();\n rotateZ(frameCount * 0.02);\n rotateX(frameCount * 0.02);\n rotateY(frameCount * 0.02);\n fill(0, 0, 0);\n box(50);\n pop();\n}\n</code>\n</div>\n\n<div>\n<code>\n// press the mouse button to enable perPixelLighting\nfunction setup() {\n createCanvas(100, 100, WEBGL);\n noStroke();\n fill(255);\n}\n\nvar lights = [\n { c: '#f00', t: 1.12, p: 1.91, r: 0.2 },\n { c: '#0f0', t: 1.21, p: 1.31, r: 0.2 },\n { c: '#00f', t: 1.37, p: 1.57, r: 0.2 },\n { c: '#ff0', t: 1.12, p: 1.91, r: 0.7 },\n { c: '#0ff', t: 1.21, p: 1.31, r: 0.7 },\n { c: '#f0f', t: 1.37, p: 1.57, r: 0.7 }\n];\n\nfunction draw() {\n var t = millis() / 1000 + 1000;\n background(0);\n directionalLight(color('#222'), 1, 1, 1);\n\n for (var i = 0; i < lights.length; i++) {\n var light = lights[i];\n pointLight(\n color(light.c),\n p5.Vector.fromAngles(t * light.t, t * light.p, width * light.r)\n );\n }\n\n specularMaterial(255);\n sphere(width * 0.1);\n\n rotateX(t * 0.77);\n rotateY(t * 0.83);\n rotateZ(t * 0.91);\n torus(width * 0.3, width * 0.07, 24, 10);\n}\n\nfunction mousePressed() {\n setAttributes('perPixelLighting', true);\n noStroke();\n fill(255);\n}\nfunction mouseReleased() {\n setAttributes('perPixelLighting', false);\n noStroke();\n fill(255);\n}\n</code>\n</div>"], 17675 "alt": "a rotating cube with smoother edges", 17676 "class": "p5", 17677 "module": "Rendering", 17678 "submodule": "Rendering", 17679 "overloads": [{ 17680 "line": 216, 17681 "params": [{ 17682 "name": "key", 17683 "description": "<p>Name of attribute</p>\n", 17684 "type": "String" 17685 }, { 17686 "name": "value", 17687 "description": "<p>New value of named attribute</p>\n", 17688 "type": "Boolean" 17689 }] 17690 }, { 17691 "line": 349, 17692 "params": [{ 17693 "name": "obj", 17694 "description": "<p>object with key-value pairs</p>\n", 17695 "type": "Object" 17696 }] 17697 }] 17698 }, { 17699 "file": "src/webgl/p5.Shader.js", 17700 "line": 274, 17701 "description": "<p>Wrapper around gl.uniform functions.\nAs we store uniform info in the shader we can use that\nto do type checking on the supplied data and call\nthe appropriate function.</p>\n", 17702 "itemtype": "method", 17703 "name": "setUniform", 17704 "chainable": 1, 17705 "params": [{ 17706 "name": "uniformName", 17707 "description": "<p>the name of the uniform in the\nshader program</p>\n", 17708 "type": "String" 17709 }, { 17710 "name": "data", 17711 "description": "<p>the data to be associated\nwith that uniform; type varies (could be a single numerical value, array,\nmatrix, or texture / sampler reference)</p>\n", 17712 "type": "Object|Number|Boolean|Number[]" 17713 }], 17714 "class": "p5.Shader", 17715 "module": "Lights, Camera", 17716 "submodule": "Shaders" 17717 }, { 17718 "file": "lib/addons/p5.dom.js", 17719 "line": 40, 17720 "description": "<p>Searches the page for an element with the given ID, class, or tag name (using the '#' or '.'\nprefixes to specify an ID or class respectively, and none for a tag) and returns it as\na <a href=\"#/p5.Element\">p5.Element</a>. If a class or tag name is given with more than 1 element,\nonly the first element will be returned.\nThe DOM node itself can be accessed with .elt.\nReturns null if none found. You can also specify a container to search within.</p>\n", 17721 "itemtype": "method", 17722 "name": "select", 17723 "params": [{ 17724 "name": "name", 17725 "description": "<p>id, class, or tag name of element to search for</p>\n", 17726 "type": "String" 17727 }, { 17728 "name": "container", 17729 "description": "<p>id, <a href=\"#/p5.Element\">p5.Element</a>, or\n HTML element to search within</p>\n", 17730 "type": "String|p5.Element|HTMLElement", 17731 "optional": true 17732 }], 17733 "return": { 17734 "description": "<a href=\"#/p5.Element\">p5.Element</a> containing node found", 17735 "type": "p5.Element|null" 17736 }, 17737 "example": ["\n<div ><code class='norender'>\nfunction setup() {\n createCanvas(100, 100);\n //translates canvas 50px down\n select('canvas').position(100, 100);\n}\n</code></div>\n<div><code class='norender'>\n// these are all valid calls to select()\nvar a = select('#moo');\nvar b = select('#blah', '#myContainer');\nvar c, e;\nif (b) {\n c = select('#foo', b);\n}\nvar d = document.getElementById('beep');\nif (d) {\n e = select('p', d);\n}\n[a, b, c, d, e]; // unused\n</code></div>\n"], 17738 "class": "p5", 17739 "module": "p5.dom", 17740 "submodule": "p5.dom" 17741 }, { 17742 "file": "lib/addons/p5.dom.js", 17743 "line": 107, 17744 "description": "<p>Searches the page for elements with the given class or tag name (using the '.' prefix\nto specify a class and no prefix for a tag) and returns them as <a href=\"#/p5.Element\">p5.Element</a>s\nin an array.\nThe DOM node itself can be accessed with .elt.\nReturns an empty array if none found.\nYou can also specify a container to search within.</p>\n", 17745 "itemtype": "method", 17746 "name": "selectAll", 17747 "params": [{ 17748 "name": "name", 17749 "description": "<p>class or tag name of elements to search for</p>\n", 17750 "type": "String" 17751 }, { 17752 "name": "container", 17753 "description": "<p>id, <a href=\"#/p5.Element\">p5.Element</a>, or HTML element to search within</p>\n", 17754 "type": "String", 17755 "optional": true 17756 }], 17757 "return": { 17758 "description": "Array of <a href=\"#/p5.Element\">p5.Element</a>s containing nodes found", 17759 "type": "p5.Element[]" 17760 }, 17761 "example": ["\n<div class='norender'><code>\nfunction setup() {\n createButton('btn');\n createButton('2nd btn');\n createButton('3rd btn');\n var buttons = selectAll('button');\n\n for (var i = 0; i < buttons.length;
17761 i++) {\n buttons[i].size(100, 100);\n }\n}\n</code></div>\n<div class='norender'><code>\n// these are all valid calls to selectAll()\nvar a = selectAll('.moo');\na = selectAll('div');\na = selectAll('button', '#myContainer');\n\nvar d = select('#container');\na = selectAll('p', d);\n\nvar f = document.getElementById('beep');\na = select('.blah', f);\n\na; // unused\n</code></div>\n"], 17762 "class": "p5", 17763 "module": "p5.dom", 17764 "submodule": "p5.dom" 17765 }, { 17766 "file": "lib/addons/p5.dom.js", 17767 "line": 168, 17768 "description": "<p>Helper function for select and selectAll</p>\n", 17769 "class": "p5", 17770 "module": "p5.dom", 17771 "submodule": "p5.dom" 17772 }, { 17773 "file": "lib/addons/p5.dom.js", 17774 "line": 184, 17775 "description": "<p>Helper function for getElement and getElements.</p>\n", 17776 "class": "p5", 17777 "module": "p5.dom", 17778 "submodule": "p5.dom" 17779 }, { 17780 "file": "lib/addons/p5.dom.js", 17781 "line": 218, 17782 "description": "<p>Removes all elements created by p5, except any canvas / graphics\nelements created by <a href=\"#/p5/createCanvas\">createCanvas</a> or <a href=\"#/p5/createGraphics\">createGraphics</a>.\nEvent handlers are removed, and element is removed from the DOM.</p>\n", 17783 "itemtype": "method", 17784 "name": "removeElements", 17785 "example": ["\n<div class='norender'><code>\nfunction setup() {\n createCanvas(100, 100);\n createDiv('this is some text');\n createP('this is a paragraph');\n}\nfunction mousePressed() {\n removeElements(); // this will remove the div and p, not canvas\n}\n</code></div>\n"], 17786 "class": "p5", 17787 "module": "p5.dom", 17788 "submodule": "p5.dom" 17789 }, { 17790 "file": "lib/addons/p5.dom.js", 17791 "line": 245, 17792 "description": "<p>The .<a href=\"#/p5.Element/changed\">changed()</a> function is called when the value of an\nelement changes.\nThis can be used to attach an element specific event listener.</p>\n", 17793 "itemtype": "method", 17794 "name": "changed", 17795 "params": [{ 17796 "name": "fxn", 17797 "description": "<p>function to be fired when the value of\n an element changes.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 17798 "type": "Function|Boolean" 17799 }], 17800 "chainable": 1, 17801 "example": ["\n<div><code>\nvar sel;\n\nfunction setup() {\n textAlign(CENTER);\n background(200);\n sel = createSelect();\n sel.position(10, 10);\n sel.option('pear');\n sel.option('kiwi');\n sel.option('grape');\n sel.changed(mySelectEvent);\n}\n\nfunction mySelectEvent() {\n var item = sel.value();\n background(200);\n text(\"it's a \" + item + '!', 50, 50);\n}\n</code></div>\n\n<div><code>\nvar checkbox;\nvar cnv;\n\nfunction setup() {\n checkbox = createCheckbox(' fill');\n checkbox.changed(changeFill);\n cnv = createCanvas(100, 100);\n cnv.position(0, 30);\n noFill();\n}\n\nfunction draw() {\n background(200);\n ellipse(50, 50, 50, 50);\n}\n\nfunction changeFill() {\n if (checkbox.checked()) {\n fill(0);\n } else {\n noFill();\n }\n}\n</code></div>"], 17802 "alt": "dropdown: pear, kiwi, grape. When selected text \"its a\" + selection shown.", 17803 "class": "p5", 17804 "module": "p5.dom", 17805 "submodule": "p5.dom" 17806 }, { 17807 "file": "lib/addons/p5.dom.js", 17808 "line": 313, 17809 "description": "<p>The .<a href=\"#/p5.Element/input\">input()</a> function is called when any user input is\ndetected with an element. The input event is often used\nto detect keystrokes in a input element, or changes on a\nslider element. This can be used to attach an element specific\nevent listener.</p>\n", 17810 "itemtype": "method", 17811 "name": "input", 17812 "params": [{ 17813 "name": "fxn", 17814 "description": "<p>function to be fired when any user input is\n detected within the element.\n if <code>false</code> is passed instead, the previously\n firing function will no longer fire.</p>\n", 17815 "type": "Function|Boolean" 17816 }], 17817 "chainable": 1, 17818 "example": ["\n<div class='norender'><code>\n// Open your console to see the output\nfunction setup() {\n var inp = createInput('');\n inp.input(myInputEvent);\n}\n\nfunction myInputEvent() {\n console.log('you are typing: ', this.value());\n}\n</code></div>"],
17819 "alt": "no display.", 17820 "class": "p5", 17821 "module": "p5.dom", 17822 "submodule": "p5.dom" 17823 }, { 17824 "file": "lib/addons/p5.dom.js", 17825 "line": 348, 17826 "description": "<p>Helpers for create methods.</p>\n", 17827 "class": "p5", 17828 "module": "p5.dom", 17829 "submodule": "p5.dom" 17830 }, { 17831 "file": "lib/addons/p5.dom.js", 17832 "line": 361, 17833 "description": "<p>Creates a <div></div> element in the DOM with given inner HTML.\nAppends to the container node if one is specified, otherwise\nappends to body.</p>\n", 17834 "itemtype": "method", 17835 "name": "createDiv", 17836 "params": [{ 17837 "name": "html", 17838 "description": "<p>inner HTML for element created</p>\n", 17839 "type": "String", 17840 "optional": true 17841 }], 17842 "return": { 17843 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 17844 "type": "p5.Element" 17845 }, 17846 "example": ["\n<div class='norender'><code>\ncreateDiv('this is some text');\n</code></div>"], 17847 "class": "p5", 17848 "module": "p5.dom", 17849 "submodule": "p5.dom" 17850 }, { 17851 "file": "lib/addons/p5.dom.js", 17852 "line": 375, 17853 "description": "<p>Creates a <p></p> element in the DOM with given inner HTML. Used\nfor paragraph length text.\nAppends to the container node if one is specified, otherwise\nappends to body.</p>\n", 17854 "itemtype": "method", 17855 "name": "createP", 17856 "params": [{ 17857 "name": "html", 17858 "description": "<p>inner HTML for element created</p>\n", 17859 "type": "String", 17860 "optional": true 17861 }], 17862 "return": { 17863 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 17864 "type": "p5.Element" 17865 }, 17866 "example": ["\n<div class='norender'><code>\ncreateP('this is some text');\n</code></div>"], 17867 "class": "p5", 17868 "module": "p5.dom", 17869 "submodule": "p5.dom" 17870 }, { 17871 "file": "lib/addons/p5.dom.js", 17872 "line": 390, 17873 "description": "<p>Creates a <span></span> element in the DOM with given inner HTML.\nAppends to the container node if one is specified, otherwise\nappends to body.</p>\n", 17874 "itemtype": "method", 17875 "name": "createSpan", 17876 "params": [{ 17877 "name": "html", 17878 "description": "<p>inner HTML for element created</p>\n", 17879 "type": "String", 17880 "optional": true 17881 }], 17882 "return": { 17883 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 17884 "type": "p5.Element" 17885 }, 17886 "example": ["\n<div class='norender'><code>\ncreateSpan('this is some text');\n</code></div>"], 17887 "class": "p5", 17888 "module": "p5.dom", 17889 "submodule": "p5.dom" 17890 }, { 17891 "file": "lib/addons/p5.dom.js", 17892 "line": 413, 17893 "description": "<p>Creates an <img> element in the DOM with given src and\nalternate text.\nAppends to the container node if one is specified, otherwise\nappends to body.</p>\n", 17894 "itemtype": "method", 17895 "name": "createImg", 17896 "return": { 17897 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 17898 "type": "p5.Element" 17899 }, 17900 "example": ["\n<div class='norender'><code>\ncreateImg('http://p5js.org/img/asterisk-01.png');\n</code></div>"], 17901 "class": "p5", 17902 "module": "p5.dom", 17903 "submodule": "p5.dom", 17904 "overloads": [{ 17905 "line": 413, 17906 "params": [{ 17907 "name": "src", 17908 "description": "<p>src path or url for image</p>\n", 17909 "type": "String" 17910 }, { 17911 "name": "alt", 17912 "description": "<p>alternate text to be used if image does not load</p>\n", 17913 "type": "String", 17914 "optional": true 17915 }, { 17916 "name": "successCallback", 17917 "description": "<p>callback to be called once image data is loaded</p>\n", 17918 "type": "Function", 17919 "optional": true 17920 }], 17921 "return": { 17922 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 17923 "type": "p5.Element" 17924 } 17925 }, { 17926 "line": 429, 17927 "params": [{ 17928 "name": "src", 17929 "description": "", 17930 "type": "String" 17931 }, { 17932 "name": "successCallback", 17933 "description": "", 17934 "type": "Function" 17935 }], 17936 "return": { 17937 "description": "", 17938 "type": "Object|p5.Element" 17939 } 17940 }] 17941 }, { 17942 "file": "lib/addons/p5.dom.js", 17943 "line": 462, 17944 "description": "<p>Creates an <a></a> element in the DOM for including a hyperlink.\nAppends to the container node if one is specified, otherwise\nappends to body.</p>\n", 17945 "itemtype": "method", 17946 "name": "createA", 17947 "params": [{ 17948 "name": "href", 17949 "description": "<p>url of page to link to</p>\n", 17950 "type": "String" 17951 }, { 17952 "name": "html", 17953 "description": "<p>inner html of link element to display</p>\n", 17954 "type": "String" 17955 }, { 17956 "name": "target", 17957 "description": "<p>target where new link should open,\n could be _blank, _self, _parent, _top.</p>\n", 17958 "type": "String", 17959 "optional": true 17960 }], 17961 "return": { 17962 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 17963 "type": "p5.Element" 17964 }, 17965 "example": ["\n<div class='norender'><code>\ncreateA('http://p5js.org/', 'this is a link');\n</code></div>"], 17966 "class": "p5", 17967 "module": "p5.dom", 17968 "submodule": "p5.dom" 17969 }, { 17970 "file": "lib/addons/p5.dom.js", 17971 "line": 487, 17972 "class": "p5", 17973 "module": "p5.dom", 17974 "submodule": "p5.dom" 17975 }, { 17976 "file": "lib/addons/p5.dom.js", 17977 "line": 489, 17978 "description": "<p>Creates a slider <input></input> element in the DOM.\nUse .size() to set the display length of the slider.\nAppends to the container node if one is specified, otherwise\nappends to body.</p>\n", 17979 "itemtype": "method", 17980 "name": "createSlider", 17981 "params": [{ 17982 "name": "min", 17983 "description": "<p>minimum value of the slider</p>\n", 17984 "type": "Number" 17985 }, { 17986 "name": "max", 17987 "description": "<p>maximum value of the slider</p>\n", 17988 "type": "Number" 17989 }, { 17990 "name": "value", 17991 "description": "<p>default value of the slider</p>\n", 17992 "type": "Number", 17993 "optional": true 17994 }, { 17995 "name": "step", 17996 "description": "<p>step size for each tick of the slider (if step is set to 0, the slider will move continuously from the minimum to the maximum value)</p>\n", 17997 "type": "Number", 17998 "optional": true 17999 }], 18000 "return": { 18001 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 18002 "type": "p5.Element" 18003 }, 18004 "example": ["\n<div><code>\nvar slider;\nfunction setup() {\n slider = createSlider(0, 255, 100);\n slider.position(10, 10);\n slider.style('width', '80px');\n}\n\nfunction draw() {\n var val = slider.value();\n background(val);\n}\n</code></div>\n\n<div><code>\nvar slider;\nfunction setup() {\n colorMode(HSB);\n slider = createSlider(0, 360, 60, 40);\n slider.position(10, 10);\n slider.style('width', '80px');\n}\n\nfunction draw() {\n var val = slider.value();
18004\n background(val, 100, 100, 1);\n}\n</code></div>"], 18005 "class": "p5", 18006 "module": "p5.dom", 18007 "submodule": "p5.dom" 18008 }, { 18009 "file": "lib/addons/p5.dom.js", 18010 "line": 546, 18011 "description": "<p>Creates a <button></button> element in the DOM.\nUse .size() to set the display size of the button.\nUse .mousePressed() to specify behavior on press.\nAppends to the container node if one is specified, otherwise\nappends to body.</p>\n", 18012 "itemtype": "method", 18013 "name": "createButton", 18014 "params": [{ 18015 "name": "label", 18016 "description": "<p>label displayed on the button</p>\n", 18017 "type": "String" 18018 }, { 18019 "name": "value", 18020 "description": "<p>value of the button</p>\n", 18021 "type": "String", 18022 "optional": true 18023 }], 18024 "return": { 18025 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 18026 "type": "p5.Element" 18027 }, 18028 "example": ["\n<div class='norender'><code>\nvar button;\nfunction setup() {\n createCanvas(100, 100);\n background(0);\n button = createButton('click me');\n button.position(19, 19);\n button.mousePressed(changeBG);\n}\n\nfunction changeBG() {\n var val = random(255);\n background(val);\n}\n</code></div>"], 18029 "class": "p5", 18030 "module": "p5.dom", 18031 "submodule": "p5.dom" 18032 }, { 18033 "file": "lib/addons/p5.dom.js", 18034 "line": 582, 18035 "description": "<p>Creates a checkbox <input></input> element in the DOM.\nCalling .checked() on a checkbox returns if it is checked or not</p>\n", 18036 "itemtype": "method", 18037 "name": "createCheckbox", 18038 "params": [{ 18039 "name": "label", 18040 "description": "<p>label displayed after checkbox</p>\n", 18041 "type": "String", 18042 "optional": true 18043 }, { 18044 "name": "value", 18045 "description": "<p>value of the checkbox; checked is true, unchecked is false</p>\n", 18046 "type": "Boolean", 18047 "optional": true 18048 }], 18049 "return": { 18050 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 18051 "type": "p5.Element" 18052 }, 18053 "example": ["\n<div class='norender'><code>\nvar checkbox;\n\nfunction setup() {\n checkbox = createCheckbox('label', false);\n checkbox.changed(myCheckedEvent);\n}\n\nfunction myCheckedEvent() {\n if (this.checked()) {\n console.log('Checking!');\n } else {\n console.log('Unchecking!');\n }\n}\n</code></div>"], 18054 "class": "p5", 18055 "module": "p5.dom", 18056 "submodule": "p5.dom" 18057 }, { 18058 "file": "lib/addons/p5.dom.js", 18059 "line": 650, 18060 "description": "<p>Creates a dropdown menu <select></select> element in the DOM.\nIt also helps to assign select-box methods to <a href=\"#/p5.Element\">p5.Element</a> when selecting existing select box</p>\n", 18061 "itemtype": "method", 18062 "name": "createSelect", 18063 "return": { 18064 "description": "", 18065 "type": "p5.Element" 18066 }, 18067 "example": ["\n<div><code>\nvar sel;\n\nfunction setup() {\n textAlign(CENTER);\n background(200);\n sel = createSelect();\n sel.position(10, 10);\n sel.option('pear');\n sel.option('kiwi');\n sel.option('grape');\n sel.changed(mySelectEvent);\n}\n\nfunction mySelectEvent() {\n var item = sel.value();\n background(200);\n text('it is a' + item + '!', 50, 50);\n}\n</code></div>"], 18068 "class": "p5", 18069 "module": "p5.dom", 18070 "submodule": "p5.dom", 18071 "overloads": [{ 18072 "line": 650, 18073 "params": [{ 18074 "name": "multiple", 18075 "description": "<p>true if dropdown should support multiple selections</p>\n", 18076 "type": "Boolean", 18077 "optional": true 18078 }], 18079 "return": { 18080 "description": "", 18081 "type": "p5.Element" 18082 } 18083 }, { 18084 "line": 678, 18085 "params": [{ 18086 "name": "existing", 18087 "description": "<p>DOM select element</p>\n", 18088 "type": "Object" 18089 }], 18090 "return": { 18091 "description": "", 18092 "type": "p5.Element" 18093 } 18094 }] 18095 }, { 18096 "file": "lib/addons/p5.dom.js", 18097 "line": 754, 18098 "description": "<p>Creates a radio button <input></input> element in the DOM.\nThe .option() method can be used to set options for the radio after it is\ncreated. The .value() method will return the currently selected option.</p>\n", 18099 "itemtype": "method", 18100 "name": "createRadio", 18101 "params": [{ 18102 "name": "divId", 18103 "description": "<p>the id and name of the created div and input field respectively</p>\n", 18104 "type": "String", 18105 "optional": true 18106 }], 18107 "return": { 18108 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 18109 "type": "p5.Element" 18110 }, 18111 "example": ["\n<div><code>\nvar radio;\n\nfunction setup() {\n radio = createRadio();\n radio.option('black');\n radio.option('white');\n radio.option('gray');\n radio.style('width', '60px');\n textAlign(CENTER);\n fill(255, 0, 0);\n}
18111\n\nfunction draw() {\n var val = radio.value();\n background(val);\n text(val, width / 2, height / 2);\n}\n</code></div>\n<div><code>\nvar radio;\n\nfunction setup() {\n radio = createRadio();\n radio.option('apple', 1);\n radio.option('bread', 2);\n radio.option('juice', 3);\n radio.style('width', '60px');\n textAlign(CENTER);\n}\n\nfunction draw() {\n background(200);\n var val = radio.value();\n if (val) {\n text('item cost is $' + val, width / 2, height / 2);\n }\n}\n</code></div>"], 18112 "class": "p5", 18113 "module": "p5.dom", 18114 "submodule": "p5.dom" 18115 }, { 18116 "file": "lib/addons/p5.dom.js", 18117 "line": 892, 18118 "description": "<p>Creates a colorPicker element in the DOM for color input.\nThe .value() method will return a hex string (#rrggbb) of the color.\nThe .color() method will return a p5.Color object with the current chosen color.</p>\n", 18119 "itemtype": "method", 18120 "name": "createColorPicker", 18121 "params": [{ 18122 "name": "value", 18123 "description": "<p>default color of element</p>\n", 18124 "type": "String|p5.Color", 18125 "optional": true 18126 }], 18127 "return": { 18128 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 18129 "type": "p5.Element" 18130 }, 18131 "example": ["\n<div>\n<code>\nvar inp1, inp2;\nfunction setup() {\n createCanvas(100, 100);\n background('grey');\n inp1 = createColorPicker('#ff0000');\n inp2 = createColorPicker(color('yellow'));\n inp1.input(setShade1);\n inp2.input(setShade2);\n setMidShade();\n}\n\nfunction setMidShade() {\n // Finding a shade between the two\n var commonShade = lerpColor(inp1.color(), inp2.color(), 0.5);\n fill(commonShade);\n rect(20, 20, 60, 60);\n}\n\nfunction setShade1() {\n setMidShade();
18131\n console.log('You are choosing shade 1 to be : ', this.value());\n}\nfunction setShade2() {\n setMidShade();\n console.log('You are choosing shade 2 to be : ', this.value());\n}\n</code>\n</div>"], 18132 "class": "p5", 18133 "module": "p5.dom", 18134 "submodule": "p5.dom" 18135 }, { 18136 "file": "lib/addons/p5.dom.js", 18137 "line": 966, 18138 "description": "<p>Creates an <input></input> element in the DOM for text input.\nUse .<a href=\"#/p5.Element/size\">size()</a> to set the display length of the box.\nAppends to the container node if one is specified, otherwise\nappends to body.</p>\n", 18139 "itemtype": "method", 18140 "name": "createInput", 18141 "params": [{ 18142 "name": "value", 18143 "description": "<p>default value of the input box</p>\n", 18144 "type": "String", 18145 "optional": true 18146 }, { 18147 "name": "type", 18148 "description": "<p>type of text, ie text, password etc. Defaults to text</p>\n", 18149 "type": "String", 18150 "optional": true 18151 }], 18152 "return": { 18153 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 18154 "type": "p5.Element" 18155 }, 18156 "example": ["\n<div class='norender'><code>\nfunction setup() {\n var inp = createInput('');\n inp.input(myInputEvent);\n}\n\nfunction myInputEvent() {\n console.log('you are typing: ', this.value());\n}\n</code></div>"], 18157 "class": "p5", 18158 "module": "p5.dom", 18159 "submodule": "p5.dom" 18160 }, { 18161 "file": "lib/addons/p5.dom.js", 18162 "line": 996, 18163 "description": "<p>Creates an <input></input> element in the DOM of type 'file'.\nThis allows users to select local files for use in a sketch.</p>\n", 18164 "itemtype": "method", 18165 "name": "createFileInput", 18166 "params": [{ 18167 "name": "callback", 18168 "description": "<p>callback function for when a file loaded</p>\n", 18169 "type": "Function", 18170 "optional": true 18171 }, { 18172 "name": "multiple", 18173 "description": "<p>optional to allow multiple files selected</p>\n", 18174 "type": "String", 18175 "optional": true 18176 }], 18177 "return": { 18178 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created DOM element", 18179 "type": "p5.Element" 18180 }, 18181 "example": ["\n<div class='norender'><code>\nvar input;\nvar img;\n\nfunction setup() {\n input = createFileInput(handleFile);\n input.position(0, 0);\n}\n\nfunction draw() {\n if (img) {\n image(img, 0, 0, width, height);\n }\n}\n\nfunction handleFile(file) {\n print(file);\n if (file.type === 'image') {\n img = createImg(file.data);\n img.hide();\n }\n}\n</code></div>"], 18182 "class": "p5", 18183 "module": "p5.dom", 18184 "submodule": "p5.dom" 18185 }, { 18186 "file": "lib/addons/p5.dom.js", 18187 "line": 1066, 18188 "class": "p5", 18189 "module": "p5.dom", 18190 "submodule": "p5.dom" 18191 }, { 18192 "file": "lib/addons/p5.dom.js", 18193 "line": 1108, 18194 "description": "<p>Creates an HTML5 <video> element in the DOM for simple playback\nof audio/video. Shown by default, can be hidden with .<a href=\"#/p5.Element/hide\">hide()</a>\nand drawn into canvas using video(). Appends to the container\nnode if one is specified, otherwise appends to body. The first parameter\ncan be either a single string path to a video file, or an array of string\npaths to different formats of the same video. This is useful for ensuring\nthat your video can play across different browsers, as each supports\ndifferent formats. See <a href='https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats'>this\npage</a> for further information about supported formats.</p>\n", 18195 "itemtype": "method", 18196 "name": "createVideo", 18197 "params": [{ 18198 "name": "src", 18199 "description": "<p>path to a video file, or array of paths for\n supporting different browsers</p>\n", 18200 "type": "String|String[]" 18201 }, { 18202 "name": "callback", 18203 "description": "<p>callback function to be called upon\n 'canplaythrough' event fire, that is, when the\n browser can play the media, and estimates that\n enough data has been loaded to play the media\n up to its end without having to stop for\n further buffering of content</p>\n", 18204 "type": "Function", 18205 "optional": true 18206 }], 18207 "return": { 18208 "description": "pointer to video <a href=\"#/p5.Element\">p5.Element</a>", 18209 "type": "p5.MediaElement" 18210 }, 18211 "example": ["\n<div><code>\nvar vid;\nfunction setup() {\n vid = createVideo(['small.mp4', 'small.ogv', 'small.webm'], vidLoad);\n}\n\n// This function is called when the video loads\nfunction vidLoad() {\n vid.play();\n}\n</code></div>"], 18212 "class": "p5", 18213 "module": "p5.dom", 18214 "submodule": "p5.dom" 18215 }, { 18216 "file": "lib/addons/p5.dom.js", 18217 "line": 1147, 18218 "class": "p5", 18219 "module": "p5.dom", 18220 "submodule": "p5.dom" 18221 }, { 18222 "file": "lib/addons/p5.dom.js", 18223 "line": 1149, 18224 "description": "<p>Creates a hidden HTML5 <audio> element in the DOM for simple audio\nplayback. Appends to the container node if one is specified,\notherwise appends to body. The first parameter\ncan be either a single str
18224ing path to a audio file, or an array of string\npaths to different formats of the same audio. This is useful for ensuring\nthat your audio can play across different browsers, as each supports\ndifferent formats. See <a href='https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats'>this\npage for further information about supported formats</a>.</p>\n", 18225 "itemtype": "method", 18226 "name": "createAudio", 18227 "params": [{ 18228 "name": "src", 18229 "description": "<p>path to an audio file, or array of paths\n for supporting different browsers</p>\n", 18230 "type": "String|String[]", 18231 "optional": true 18232 }, { 18233 "name": "callback", 18234 "description": "<p>callback function to be called upon\n 'canplaythrough' event fire, that is, when the\n browser can play the media, and estimates that\n enough data has been loaded to play the media\n up to its end without having to stop for\n further buffering of content</p>\n", 18235 "type": "Function", 18236 "optional": true 18237 }], 18238 "return": { 18239 "description": "pointer to audio <a href=\"#/p5.Element\">p5.Element</a>", 18240 "type": "p5.MediaElement" 18241 }, 18242 "example": ["\n<div><code>\nvar ele;\nfunction setup() {\n ele = createAudio('assets/beat.mp3');\n\n // here we set the element to autoplay\n // The element will play as soon\n // as it is able to do so.\n ele.autoplay(true);\n}\n</code></div>"], 18243 "class": "p5", 18244 "module": "p5.dom", 18245 "submodule": "p5.dom" 18246 }, { 18247 "file": "lib/addons/p5.dom.js", 18248 "line": 1187, 18249 "class": "p5", 18250 "module": "p5.dom", 18251 "submodule": "p5.dom" 18252 }, { 18253 "file": "lib/addons/p5.dom.js", 18254 "line": 1189, 18255 "itemtype": "property", 18256 "name": "VIDEO", 18257 "type": "String", 18258 "final": 1, 18259 "category": ["Constants"], 18260 "class": "p5", 18261 "module": "p5.dom", 18262 "submodule": "p5.dom" 18263 }, { 18264 "file": "lib/addons/p5.dom.js", 18265 "line": 1195, 18266 "itemtype": "property", 18267 "name": "AUDIO", 18268 "type": "String", 18269 "final": 1, 18270 "category": ["Constants"], 18271 "class": "p5", 18272 "module": "p5.dom", 18273 "submodule": "p5.dom" 18274 }, { 18275 "file": "lib/addons/p5.dom.js", 18276 "line": 1232, 18277 "description": "<p>Creates a new HTML5 <video> element that contains the audio/video\nfeed from a webcam. The element is separate from the canvas and is\ndisplayed by default. The element can be hidden using .<a href=\"#/p5.Element/hide\">hide()</a>. The feed\ncan be drawn onto the canvas using <a href=\"#/p5/image\">image()</a>. The loadedmetadata property can\nbe used to detect when the element has fully loaded (see second example).</p>\n<p>More specific properties of the feed can be passing in a Constraints object.\nSee the\n<a href='http://w3c.github.io/mediacapture-main/getusermedia.html#media-track-constraints'> W3C\nspec</a> for possible properties. Note that not all of these are supported\nby all browsers.</p>\n<p>Security note: A new browser security specification requires that getUserMedia,\nwhich is behind <a href=\"#/p5/createCapture\">createCapture()</a>, only works when you're running the code locally,\nor on HTTPS. Learn more <a href='http://stackoverflow.com/questions/34197653/getusermedia-in-chrome-47-without-using-https'>here</a>\nand <a href='https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia'>here</a>.</p>", 18278 "itemtype": "method", 18279 "name": "createCapture", 18280 "params": [{ 18281 "name": "type", 18282 "description": "<p>type of capture, either VIDEO or\n AUDIO if none specified, default both,\n or a Constraints object</p>\n", 18283 "type": "String|Constant|Object" 18284 }, { 18285 "name": "callback", 18286 "description": "<p>function to be called once\n stream has loaded</p>\n", 18287 "type": "Function", 18288 "optional": true 18289 }], 18290 "return": { 18291 "description": "capture video <a href=\"#/p5.Element\">p5.Element</a>", 18292 "type": "p5.Element" 18293 }, 18294 "example": ["\n<div class='norender notest'><code>\nvar capture;\n\nfunction setup() {\n createCanvas(480, 480);\n capture = createCapture(VIDEO);\n capture.hide();\n}\n\nfunction draw() {\n image(capture, 0, 0, width, width * capture.height / capture.width);\n filter(INVERT);\n}\n</code></div>\n<div class='norender notest'><code>\nfunction setup() {\n createCanvas(480, 120);\n var constraints = {\n video: {\n mandatory: {\n minWidth: 1280,\n minHeight: 720\n },\n optional: [{ maxFrameRate: 10 }]\n },\n audio: true\n };\n createCapture(constraints, function(stream) {\n console.log(stream);\n });\n}\n</code></div>\n<code><div class='norender notest'>\nvar capture;\n\nfunction setup() {\n createCanvas(640, 480);\n capture = createCapture(VIDEO);\n}\nfunction draw() {\n background(0);
18294\n if (capture.loadedmetadata) {\n var c = capture.get(0, 0, 100, 100);\n image(c, 0, 0);\n }\n}"], 18295 "class": "p5", 18296 "module": "p5.dom", 18297 "submodule": "p5.dom" 18298 }, { 18299 "file": "lib/addons/p5.dom.js", 18300 "line": 1368, 18301 "description": "<p>Creates element with given tag in the DOM with given content.\nAppends to the container node if one is specified, otherwise\nappends to body.</p>\n", 18302 "itemtype": "method", 18303 "name": "createElement", 18304 "params": [{ 18305 "name": "tag", 18306 "description": "<p>tag for the new element</p>\n", 18307 "type": "String" 18308 }, { 18309 "name": "content", 18310 "description": "<p>html content to be inserted into the element</p>\n", 18311 "type": "String", 18312 "optional": true 18313 }], 18314 "return": { 18315 "description": "pointer to <a href=\"#/p5.Element\">p5.Element</a> holding created node", 18316 "type": "p5.Element" 18317 }, 18318 "example": ["\n<div class='norender'><code>\ncreateElement('h2', 'im an h2 p5.element!');\n</code></div>"], 18319 "class": "p5", 18320 "module": "p5.dom", 18321 "submodule": "p5.dom" 18322 }, { 18323 "file": "lib/addons/p5.dom.js", 18324 "line": 1394, 18325 "description": "<p>Adds specified class to the element.</p>\n", 18326 "itemtype": "method", 18327 "name": "addClass", 18328 "params": [{ 18329 "name": "class", 18330 "description": "<p>name of class to add</p>\n", 18331 "type": "String" 18332 }], 18333 "chainable": 1, 18334 "example": ["\n <div class='norender'><code>\n var div = createDiv('div');\n div.addClass('myClass');\n </code></div>"], 18335 "class": "p5.Element", 18336 "module": "p5.dom", 18337 "submodule": "p5.dom" 18338 }, { 18339 "file": "lib/addons/p5.dom.js", 18340 "line": 1421, 18341 "description": "<p>Removes specified class from the element.</p>\n", 18342 "itemtype": "method", 18343 "name": "removeClass", 18344 "params": [{ 18345 "name": "class", 18346 "description": "<p>name of class to remove</p>\n", 18347 "type": "String" 18348 }], 18349 "chainable": 1, 18350 "example": ["\n <div class='norender'><code>\n // In this example, a class is set when the div is created\n // and removed when mouse is pressed. This could link up\n // with a CSS style rule to toggle style properties.\nvar div;\nfunction setup() {\n div = createDiv('div');\n div.addClass('myClass');\n }\nfunction mousePressed() {\n div.removeClass('myClass');\n }\n </code></div>"], 18351 "class": "p5.Element", 18352 "module": "p5.dom", 18353 "submodule": "p5.dom" 18354 }, { 18355 "file": "lib/addons/p5.dom.js", 18356 "line": 1453, 18357 "description": "<p>Attaches the element as a child to the parent specified.\n Accepts either a string ID, DOM node, or <a href=\"#/p5.Element\">p5.Element</a>.\n If no argument is specified, an array of children DOM nodes is returned.</p>\n", 18358 "itemtype": "method", 18359 "name": "child", 18360 "return": { 18361 "description": "an array of child nodes", 18362 "type": "Node[]" 18363 }, 18364 "example": ["\n <div class='norender'><code>\n var div0 = createDiv('this is the parent');\n var div1 = createDiv('this is the child');\n div0.child(div1); // use p5.Element\n </code></div>\n <div class='norender'><code>\n var div0 = createDiv('this is the parent');\n var div1 = createDiv('this is the child');\n div1.id('apples');\n div0.child('apples'); // use id\n </code></div>\n <div class='norender notest'><code>\n // this example assumes there is a div already on the page\n // with id \"myChildDiv\"\n var div0 = createDiv('this is the parent');\n var elt = document.getElementById('myChildDiv');\n div0.child(elt);
18364 // use element from page\n </code></div>"], 18365 "class": "p5.Element", 18366 "module": "p5.dom", 18367 "submodule": "p5.dom", 18368 "overloads": [{ 18369 "line": 1453, 18370 "params": [], 18371 "return": { 18372 "description": "an array of child nodes", 18373 "type": "Node[]" 18374 } 18375 }, { 18376 "line": 1481, 18377 "params": [{ 18378 "name": "child", 18379 "description": "<p>the ID, DOM node, or <a href=\"#/p5.Element\">p5.Element</a>\n to add to the current element</p>\n", 18380 "type": "String|p5.Element", 18381 "optional": true 18382 }], 18383 "chainable": 1 18384 }] 18385 }, { 18386 "file": "lib/addons/p5.dom.js", 18387 "line": 1503, 18388 "description": "<p>Centers a p5 Element either vertically, horizontally,\nor both, relative to its parent or according to\nthe body if the Element has no parent. If no argument is passed\nthe Element is aligned both vertically and horizontally.</p>\n", 18389 "itemtype": "method", 18390 "name": "center", 18391 "params": [{ 18392 "name": "align", 18393 "description": "<p>passing 'vertical', 'horizontal' aligns element accordingly</p>\n", 18394 "type": "String", 18395 "optional": true 18396 }], 18397 "chainable": 1, 18398 "example": ["\n<div><code>\nfunction setup() {\n var div = createDiv('').size(10, 10);\n div.style('background-color', 'orange');\n div.center();\n}\n</code></div>"], 18399 "class": "p5.Element", 18400 "module": "p5.dom", 18401 "submodule": "p5.dom" 18402 }, { 18403 "file": "lib/addons/p5.dom.js", 18404 "line": 1557, 18405 "description": "<p>If an argument is given, sets the inner HTML of the element,\n replacing any existing html. If true is included as a second\n argument, html is appended instead of replacing existing html.\n If no arguments are given, returns\n the inner HTML of the element.</p>\n", 18406 "itemtype": "method", 18407 "name": "html", 18408 "return": { 18409 "description": "the inner HTML of the element", 18410 "type": "String" 18411 }, 18412 "example": ["\n <div class='norender'><code>\n var div = createDiv('').size(100, 100);\n div.html('hi');\n </code></div>\n <div class='norender'><code>\n var div = createDiv('Hello ').size(100, 100);\n div.html('World', true);\n </code></div>"], 18413 "class": "p5.Element", 18414 "module": "p5.dom", 18415 "submodule": "p5.dom", 18416 "overloads": [{ 18417 "line": 1557, 18418 "params": [], 18419 "return": { 18420 "description": "the inner HTML of the element", 18421 "type": "String" 18422 } 18423 }, { 18424 "line": 1578, 18425 "params": [{ 18426 "name": "html", 18427 "description": "<p>the HTML to be placed inside the element</p>\n", 18428 "type": "String", 18429 "optional": true 18430 }, { 18431 "name": "append", 18432 "description": "<p>whether to append HTML to existing</p>\n", 18433 "type": "Boolean", 18434 "optional": true 18435 }], 18436 "chainable": 1 18437 }] 18438 }, { 18439 "file": "lib/addons/p5.dom.js", 18440 "line": 1596, 18441 "description": "<p>Sets the position of the element relative to (0, 0) of the\n window. Essentially, set
18441s position:absolute and left and top\n properties of style. If no arguments given returns the x and y position\n of the element in an object.</p>\n", 18442 "itemtype": "method", 18443 "name": "position", 18444 "return": { 18445 "description": "the x and y position of the element in an object", 18446 "type": "Object" 18447 }, 18448 "example": ["\n <div><code class='norender'>\n function setup() {\n var cnv = createCanvas(100, 100);\n // positions canvas 50px to the right and 100px\n // below upper left corner of the window\n cnv.position(50, 100);\n }\n </code></div>"], 18449 "class": "p5.Element", 18450 "module": "p5.dom", 18451 "submodule": "p5.dom", 18452 "overloads": [{ 18453 "line": 1596, 18454 "params": [], 18455 "return": { 18456 "description": "the x and y position of the element in an object", 18457 "type": "Object" 18458 } 18459 }, { 18460 "line": 1615, 18461 "params": [{ 18462 "name": "x", 18463 "description": "<p>x-position relative to upper left of window</p>\n", 18464 "type": "Number", 18465 "optional": true 18466 }, { 18467 "name": "y", 18468 "description": "<p>y-position relative to upper left of window</p>\n", 18469 "type": "Number", 18470 "optional": true 18471 }], 18472 "chainable": 1 18473 }] 18474 }, { 18475 "file": "lib/addons/p5.dom.js", 18476 "line": 1690, 18477 "description": "<p>Sets the given style (css) property (1st arg) of the element with the\ngiven value (2nd arg). If a single argument is given, .style()\nreturns the value of the given property; however, if the single argument\nis given in css syntax ('text-align:center'), .style() sets the css\nappropriatly. .style() also handles 2d and 3d css transforms. If\nthe 1st arg is 'rotate', 'translate', or 'position', the following arguments\naccept Numbers as values. ('translate', 10, 100, 50);</p>\n", 18478 "itemtype": "method", 18479 "name": "style", 18480 "return": { 18481 "description": "value of property", 18482 "type": "String" 18483 }, 18484 "example": ["\n<div><code class='norender'>\nvar myDiv = createDiv('I like pandas.');\nmyDiv.style('font-size', '18px');\nmyDiv.style('color', '#ff0000');\n</code></div>\n<div><code class='norender'>\nvar col = color(25, 23, 200, 50);\nvar button = createButton('button');\nbutton.style('background-color', col);\nbutton.position(10, 10);\n</code></div>\n<div><code class='norender'>\nvar myDiv = createDiv('I like lizards.');\nmyDiv.style('position', 20, 20);\nmyDiv.style('rotate', 45);\n</code></div>\n<div><code class='norender'>\nvar myDiv;\nfunction setup() {\n background(200);\n myDiv = createDiv('I like gray.');\n myDiv.position(20, 20);\n}\n\nfunction draw() {\n myDiv.style('font-size', mouseX + 'px');\n}\n</code></div>"], 18485 "class": "p5.Element", 18486 "module": "p5.dom", 18487 "submodule": "p5.dom", 18488 "overloads": [{ 18489 "line": 1690, 18490 "params": [{ 18491 "name": "property", 18492 "description": "<p>property to be set</p>\n", 18493 "type": "String" 18494 }], 18495 "return": { 18496 "description": "value of property", 18497 "type": "String" 18498 } 18499 }, { 18500 "line": 1732, 18501 "params": [{ 18502 "name": "property", 18503 "description": "", 18504 "type": "String" 18505 }, { 18506 "name": "value", 18507 "description": "<p>value to assign to property (only String|Number for rotate/translate)</p>\n", 18508 "type": "String|Number|p5.Color" 18509 }, { 18510 "name": "value2", 18511 "description": "<p>position can take a 2nd value</p>\n", 18512 "type": "String|Number|p5.Color", 18513 "optional": true 18514 }, { 18515 "name": "value3", 18516 "description": "<p>translate can take a 2nd & 3rd value</p>\n", 18517 "type": "String|Number|p5.Color", 18518 "optional": true 18519 }], 18520 "chainable": 1 18521 }] 18522 }, { 18523 "file": "lib/addons/p5.dom.js", 18524 "line": 1791, 18525 "description": "<p>Adds a new attribute or changes the value of an existing attribute\n on the specified element. If no value is specified, returns the\n value of the given attribute, or null if attribute is not set.</p>\n", 18526 "itemtype": "method", 18527 "name": "attribute", 18528 "return": { 18529 "description": "value of attribute", 18530 "type": "String" 18531 }, 18532 "example": ["\n <div class='norender'><code>\n var myDiv = createDiv('I like pandas.');\n myDiv.attribute('align', 'center');\n </code></div>"], 18533 "class": "p5.Element", 18534 "module": "p5.dom", 18535 "submodule": "p5.dom", 18536 "overloads": [{ 18537 "line": 1791, 18538 "params": [], 18539 "return": { 18540 "description": "value of attribute", 18541 "type": "String" 18542 } 18543 }, { 18544 "line": 1806, 18545 "params": [{ 18546 "name": "attr", 18547 "description": "<p>attribute to set</p>\n", 18548 "type": "String" 18549 }, { 18550 "name": "value", 18551 "description": "<p>value to assign to attribute</p>\n", 18552 "type": "String" 18553 }], 18554 "chainable": 1 18555 }] 18556 }, { 18557 "file": "lib/addons/p5.dom.js", 18558 "line": 1835, 18559 "description": "<p>Removes an attribute on the specified element.</p>\n", 18560 "itemtype": "method", 18561 "name": "removeAttribute", 18562 "params": [{ 18563 "name": "attr", 18564 "description": "<p>attribute to remove</p>\n", 18565 "type": "String" 18566 }], 18567 "chainable": 1, 18568 "example": ["\n <div><code>\n var button;\n var checkbox;\nfunction setup() {\n checkbox = createCheckbox('enable', true);\n checkbox.changed(enableButton);\n button = createButton('button');\n button.position(10, 10);\n }\nfunction enableButton() {\n if (this.checked()) {\n // Re-enable the button\n button.removeAttribute('disabled');\n } else {\n // Disable the button\n button.attribute('disabled', '');\n }\n }\n </code></div>"], 18569 "class": "p5.Element", 18570 "module": "p5.dom", 18571 "submodule": "p5.dom" 18572 }, { 18573 "file": "lib/addons/p5.dom.js", 18574 "line": 1880, 18575 "description": "<p>Either returns the value of the element if no arguments\ngiven, or sets the value of the element.</p>\n", 18576 "itemtype": "method", 18577 "name": "value", 18578 "return": { 18579 "description": "value of the element", 18580 "type": "String|Number" 18581 }, 18582 "example": ["\n<div class='norender'><code>\n// gets the value\nvar inp;\nfunction setup() {\n inp = createInput('');\n}
18582\n\nfunction mousePressed() {\n print(inp.value());\n}\n</code></div>\n<div class='norender'><code>\n// sets the value\nvar inp;\nfunction setup() {\n inp = createInput('myValue');\n}\n\nfunction mousePressed() {\n inp.value('myValue');\n}\n</code></div>"], 18583 "class": "p5.Element", 18584 "module": "p5.dom", 18585 "submodule": "p5.dom", 18586 "overloads": [{ 18587 "line": 1880, 18588 "params": [], 18589 "return": { 18590 "description": "value of the element", 18591 "type": "String|Number" 18592 } 18593 }, { 18594 "line": 1910, 18595 "params": [{ 18596 "name": "value", 18597 "description": "", 18598 "type": "String|Number" 18599 }], 18600 "chainable": 1 18601 }] 18602 }, { 18603 "file": "lib/addons/p5.dom.js", 18604 "line": 1926, 18605 "description": "<p>Shows the current element. Essentially, setting display:block for the style.</p>\n", 18606 "itemtype": "method", 18607 "name": "show", 18608 "chainable": 1, 18609 "example": ["\n <div class='norender'><code>\n var div = createDiv('div');\n div.style('display', 'none');\n div.show(); // turns display to block\n </code></div>"], 18610 "class": "p5.Element", 18611 "module": "p5.dom", 18612 "submodule": "p5.dom" 18613 }, { 18614 "file": "lib/addons/p5.dom.js", 18615 "line": 1944, 18616 "description": "<p>Hides the current element. Essentially, setting display:none for the style.</p>\n", 18617 "itemtype": "method", 18618 "name": "hide", 18619 "chainable": 1, 18620 "example": ["\n<div class='norender'><code>\nvar div = createDiv('this is a div');\ndiv.hide();\n</code></div>"], 18621 "class": "p5.Element", 18622 "module": "p5.dom", 18623 "submodule": "p5.dom" 18624 }, { 18625 "file": "lib/addons/p5.dom.js", 18626 "line": 1960, 18627 "description": "<p>Sets the width and height of the element. AUTO can be used to\n only adjust one dimension. If no arguments given returns the width and height\n of the element in an object.</p>\n", 18628 "itemtype": "method", 18629 "name": "size", 18630 "return": { 18631 "description": "the width and height of the element in an object", 18632 "type": "Object" 18633 }, 18634 "example": ["\n <div class='norender'><code>\n var div = createDiv('this is a div');\n div.size(100, 100);\n </code></div>"], 18635 "class": "p5.Element", 18636 "module": "p5.dom", 18637 "submodule": "p5.dom", 18638 "overloads": [{ 18639 "line": 1960, 18640 "params": [], 18641 "return": { 18642 "description": "the width and height of the element in an object", 18643 "type": "Object" 18644 } 18645 }, { 18646 "line": 1974, 18647 "params": [{ 18648 "name": "w", 18649 "description": "<p>width of the element, either AUTO, or a number</p>\n", 18650 "type": "Number|Constant" 18651 }, { 18652 "name": "h", 18653 "description": "<p>height of the element, either AUTO, or a number</p>\n", 18654 "type": "Number|Constant", 18655 "optional": true 18656 }], 18657 "chainable": 1 18658 }] 18659 }, { 18660 "file": "lib/addons/p5.dom.js", 18661 "line": 2038, 18662 "description": "<p>Removes the element and deregisters all listeners.</p>\n", 18663 "itemtype": "method", 18664 "name": "remove", 18665 "example": ["\n<div class='norender'><code>\nvar myDiv = createDiv('this is some text');\nmyDiv.remove();\n</code></div>"], 18666 "class": "p5.Element", 18667 "module": "p5.dom", 18668 "submodule": "p5.dom" 18669 }, { 18670 "file": "lib/addons/p5.dom.js", 18671 "line": 2086, 18672 "description": "<p>Path to the media element source.</p>\n", 18673 "itemtype": "property", 18674 "name": "src", 18675 "return": { 18676 "description": "src", 18677 "type": "String" 18678 }, 18679 "example": ["\n<div><code>\nvar ele;\n\nfunction setup() {\n background(250);\n\n //p5.MediaElement objects are usually created\n //by calling the createAudio(), createVideo(),\n //and createCapture() functions.\n\n //In this example we create\n //a new p5.MediaElement via createAudio().\n ele = createAudio('assets/beat.mp3');\n\n //We'll set up our example so that\n //when you click on the text,\n //an alert box displays the MediaElement's\n //src field.\n textAlign(CENTER);\n text('Click Me!', width / 2, height / 2);\n}\n\nfunction mouseClicked() {\n //here we test if the mouse is over the\n //canvas element when it's clicked\n if (mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height) {\n //Show our p5.MediaElement's src field\n alert(ele.src);\n }\n}\n</code></div>"], 18680 "class": "p5.MediaElement", 18681 "module": "p5.dom", 18682 "submodule": "p5.dom" 18683 }, { 18684 "file": "lib/addons/p5.dom.js", 18685 "line": 2152, 18686 "description": "<p>Play an HTML5 media element.</p>\n", 18687 "itemtype": "method", 18688 "name": "play", 18689 "chainable": 1, 18690 "example": ["\n<div><code>\nvar ele;\n\nfunction setup() {\n //p5.MediaElement objects are usually created\n //by calling the createAudio(), createVideo(),\n //and createCapture() functions.\n\n //In this example we create\n //a new p5.MediaElement via createAudio().\n ele = createAudio('assets/beat.mp3');\n\n background(250);\n textAlign(CENTER);\n text('Click to Play!', width / 2, height / 2);\n}\n\nfunction mouseClicked() {\n //here we test if the mouse is over the\n //canvas element when it's clicked\n if (mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height) {\n //Here we call the play() function on\n //the p5.MediaElement we created above.\n //This will start the audio sample.\n ele.play();\n\n background(200);\n text('You clicked Play!', width / 2, height / 2);\n }\n}\n</code></div>"], 18691 "class": "p5.MediaElement", 18692 "module": "p5.dom", 18693 "submodule": "p5.dom" 18694 }, { 18695 "file": "lib/addons/p5.dom.js", 18696 "line": 2213, 18697 "description": "<p>Stops an HTML5 media element (sets current time to zero).</p>\n", 18698 "itemtype": "method", 18699 "name": "stop", 18700 "chainable": 1, 18701 "example": ["\n<div><code>\n//This example both starts\n//and stops a sound sample\n//when the user clicks the canvas\n\n//We will store the p5.MediaElement\n//object in here\nvar ele;\n\n//while our audio is playing,\n//this will be set to true\nvar sampleIsPlaying = false;\n\nfunction setup() {\n //Here we create a p5.MediaElement object\n //using the createAudio() function.\n ele = createAudio('assets/beat.mp3');\n background(200);\n textAlign(CENTER);\n text('Click to play!', width / 2, height / 2);\n}\n\nfunction mouseClicked() {\n //here we test if the mouse is over the\n //canvas element when it's clicked\n if (mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height) {\n background(200);\n\n if (sampleIsPlaying) {\n //if the sample is currently playing\n //calling the stop() function on\n //our p5.MediaElement will stop\n //it and reset its current\n //time to 0 (i.e. it will start\n //at the beginning the next time\n //you play it)\n ele.stop();\n\n sampleIsPlaying = false;\n text('Click to play!', width / 2, height / 2);\n } else {\n //loop our sound element until we\n //call ele.stop() on it.\n ele.loop();\n\n sampleIsPlaying = true;\n text('Click to stop!', width / 2, height / 2);\n }\n }\n}\n</code></div>"], 18702 "class": "p5.MediaElement", 18703 "module": "p5.dom", 18704 "submodule": "p5.dom" 18705 }, { 18706 "file": "lib/addons/p5.dom.js", 18707 "line": 2277, 18708 "description": "<p>Pauses an HTML5 media element.</p>\n", 18709 "itemtype": "method", 18710 "name": "pause", 18711 "chainable": 1, 18712 "example": ["\n<div><code>\n//This example both starts\n//and pauses a sound sample\n//when the user clicks the canvas\n\n//We will store the p5.MediaElement\n//object in here\nvar ele;\n\n//while our audio is playing,\n//this will be set to true\nvar sampleIsPlaying = false;\n\nfunction setup() {\n //Here we create a p5.MediaElement object\n //using the createAudio() function.\n ele = createAudio('assets/lucky_dragons.mp3');\n background(200);\n textAlign(CENTER);\n text('Click to play!', width / 2, height / 2);\n}\n\nfunction mouseClicked() {\n //here we test if the mouse is over the\n //canvas element when it's clicked\n if (mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height) {\n background(200);\n\n if (sampleIsPlaying) {\n //Calling pause() on our\n //p5.MediaElement will stop it\n //playing, but when we call the\n //loop() or play() functions\n //the sample will start from\n //where we paused it.\n ele.pause();\n\n sampleIsPlaying = false;\n text('Click to resume!', width / 2, height / 2);\n } else {\n //loop our sound element until we\n //call ele.pause() on it.\n ele.loop();\n\n sampleIsPlaying = true;\n text('Click to pause!', width / 2, height / 2);\n }\n }\n}\n</code></div>"], 18713 "class": "p5.MediaElement", 18714 "module": "p5.dom", 18715 "submodule": "p5.dom" 18716 }, { 18717 "file": "lib/addons/p5.dom.js", 18718 "line": 2339, 18719 "description": "<p>Set 'loop' to true for an HTML5 media element, and starts playing.</p>\n", 18720 "itemtype": "method", 18721 "name": "loop", 18722 "chainable": 1, 18723 "example": ["\n<div><code>\n//Clicking the canvas will loop\n//the audio sample until the user\n//clicks again to stop it\n\n//We will store the p5.MediaElement\n//object in here\nvar ele;\n\n//while our audio is playing,\n//this will be set to true\nvar sampleIsLooping = false;\n\nfunction setup() {\n //Here we create a p5.MediaElement object\n //using the createAudio() function.\n ele = createAudio('assets/lucky_dragons.mp3');\n background(200);\n textAlign(CENTER);\n text('Click to loop!', width / 2, height / 2);\n}\n\nfunction mouseClicked() {\n //here we test if the mouse is over the\n //canvas element when it's clicked\n if (mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height) {\n background(200);\n\n if (!sampleIsLooping) {\n //loop our sound element until we\n //call ele.stop() on it.\n ele.loop();\n\n sampleIsLooping = true;\n text('Click to stop!', width / 2, height / 2);\n } else {\n ele.stop();\n\n sampleIsLooping = false;\n text('Click to loop!', width / 2, height / 2);\n }\n }\n}\n</code></div>"], 18724 "class": "p5.MediaElement", 18725 "module": "p5.dom", 18726 "submodule": "p5.dom" 18727 }, { 18728 "file": "lib/addons/p5.dom.js", 18729 "line": 2395, 18730 "description": "<p>Set 'loop' to false for an HTML5 media element. Element will stop\nwhen it reaches the end.</p>\n", 18731 "itemtype": "method", 18732 "name": "noLoop", 18733 "chainable": 1, 18734 "example": ["\n<div><code>\n//This example both starts\n//and stops loop of sound sample\n//when the user clicks the canvas\n\n//We will store the p5.MediaElement\n//object in here\nvar ele;\n//while our audio is playing,\n//this will be set to true\nvar sampleIsPlaying = false;\n\nfunction setup() {\n //Here we create a p5.MediaElement object\n //using the createAudio() function.\n ele = createAudio('assets/beat.mp3');\n background(200);\n textAlign(CENTER);\n text('Click to play!', width / 2, height / 2);\n}\n\nfunction mouseClicked() {\n //here we test if the mouse is over the\n //canvas element when it's clicked\n if (mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height) {\n background(200);\n\n if (sampleIsPlaying) {\n ele.noLoop();\n text('No more Loops!', width / 2, height / 2);\n } else {\n ele.loop();\n sampleIsPlaying = true;\n text('Click to stop looping!', width / 2, height / 2);\n }\n }\n}\n</code></div>\n"], 18735 "class": "p5.MediaElement", 18736 "module": "p5.dom", 18737 "submodule": "p5.dom" 18738 }, { 18739 "file": "lib/addons/p5.dom.js", 18740 "line": 2447, 18741 "description": "<p>
18741Set HTML5 media element to autoplay or not.</p>\n", 18742 "itemtype": "method", 18743 "name": "autoplay", 18744 "params": [{ 18745 "name": "autoplay", 18746 "description": "<p>whether the element should autoplay</p>\n", 18747 "type": "Boolean" 18748 }], 18749 "chainable": 1, 18750 "class": "p5.MediaElement", 18751 "module": "p5.dom", 18752 "submodule": "p5.dom" 18753 }, { 18754 "file": "lib/addons/p5.dom.js", 18755 "line": 2459, 18756 "description": "<p>Sets volume for this HTML5 media element. If no argument is given,\nreturns the current volume.</p>\n", 18757 "itemtype": "method", 18758 "name": "volume", 18759 "return": { 18760 "description": "current volume", 18761 "type": "Number" 18762 }, 18763 "example": ["\n<div><code>\nvar ele;\nfunction setup() {\n // p5.MediaElement objects are usually created\n // by calling the createAudio(), createVideo(),\n // and createCapture() functions.\n // In this example we create\n // a new p5.MediaElement via createAudio().\n ele = createAudio('assets/lucky_dragons.mp3');\n background(250);\n textAlign(CENTER);\n text('Click to Play!', width / 2, height / 2);\n}\nfunction mouseClicked() {\n // Here we call the volume() function\n // on the sound element to set its volume\n // Volume must be between 0.0 and 1.0\n ele.volume(0.2);\n ele.play();\n background(200);\n text('You clicked Play!', width / 2, height / 2);\n}\n</code></div>\n<div><code>\nvar audio;\nvar counter = 0;\n\nfunction loaded() {\n audio.play();\n}\n\nfunction setup() {\n audio = createAudio('assets/lucky_dragons.mp3', loaded);\n textAlign(CENTER);\n}\n\nfunction draw() {\n if (counter === 0) {\n background(0, 255, 0);\n text('volume(0.9)', width / 2, height / 2);\n } else if (counter === 1) {\n background(255, 255, 0);\n text('volume(0.5)', width / 2, height / 2);\n } else if (counter === 2) {\n background(255, 0, 0);\n text('volume(0.1)', width / 2, height / 2);\n }\n}\n\nfunction mousePressed() {\n counter++;\n if (counter === 0) {\n audio.volume(0.9);\n } else if (counter === 1) {\n audio.volume(0.5);\n } else if (counter === 2) {\n audio.volume(0.1);\n } else {\n counter = 0;\n audio.volume(0.9);\n }\n}\n</code>\n</div>"], 18764 "class": "p5.MediaElement", 18765 "module": "p5.dom", 18766 "submodule": "p5.dom", 18767 "overloads": [{ 18768 "line": 2459, 18769 "params": [], 18770 "return": { 18771 "description": "current volume", 18772 "type": "Number" 18773 } 18774 }, { 18775 "line": 2532, 18776 "params": [{ 18777 "name": "val", 18778 "description": "<p>volume between 0.0 and 1.0</p>\n", 18779 "type": "Number" 18780 }], 18781 "chainable": 1 18782 }] 18783 }, { 18784 "file": "lib/addons/p5.dom.js", 18785 "line": 2545, 18786 "description": "<p>If no arguments are given, returns the current playback speed of the\nelement. The speed parameter sets the speed where 2.0 will play the\nelement twice as fast, 0.5 will play at half the speed, and -1 will play\nthe element in normal speed in reverse.(Note that not all browsers support\nbackward playback and even if they do, playback might not be smooth.)</p>\n", 18787 "itemtype": "method", 18788 "name": "speed", 18789 "return": { 18790 "description": "current playback speed of the element", 18791 "type": "Number" 18792 }, 18793 "example": ["\n<div class='norender notest'><code>\n//Clicking the canvas will loop\n//the audio sample until the user\n//clicks again to stop it\n\n//We will store the p5.MediaElement\n//object in here\nvar ele;\nvar button;\n\nfunction setup() {\n createCanvas(710, 400);\n //Here we create a p5.MediaElement object\n //using the createAudio() function.\n ele = createAudio('assets/beat.mp3');\n ele.loop();\n background(200);\n\n button = createButton('2x speed');\n button.position(100, 68);\n button.mousePressed(twice_speed);\n\n button = createButton('half speed');\n button.position(200, 68);\n button.mousePressed(half_speed);\n\n button = createButton('reverse play');\n button.position(300, 68);\n button.mousePressed(reverse_speed);\n\n button = createButton('STOP');\n button.position(400, 68);\n button.mousePressed(stop_song);\n\n button = createButton('PLAY!');\n button.position(500, 68);\n button.mousePressed(play_speed);\n}
18793\n\nfunction twice_speed() {\n ele.speed(2);\n}\n\nfunction half_speed() {\n ele.speed(0.5);\n}\n\nfunction reverse_speed() {\n ele.speed(-1);\n}\n\nfunction stop_song() {\n ele.stop();\n}\n\nfunction play_speed() {\n ele.play();\n}\n</code></div>"], 18794 "class": "p5.MediaElement", 18795 "module": "p5.dom", 18796 "submodule": "p5.dom", 18797 "overloads": [{ 18798 "line": 2545, 18799 "params": [], 18800 "return": { 18801 "description": "current playback speed of the element", 18802 "type": "Number" 18803 } 18804 }, { 18805 "line": 2616, 18806 "params": [{ 18807 "name": "speed", 18808 "description": "<p>speed multiplier for element playback</p>\n", 18809 "type": "Number" 18810 }], 18811 "chainable": 1 18812 }] 18813 }, { 18814 "file": "lib/addons/p5.dom.js", 18815 "line": 2633, 18816 "description": "<p>If no arguments are given, returns the current time of the element.\nIf an argument is given the current time of the element is set to it.</p>\n", 18817 "itemtype": "method", 18818 "name": "time", 18819 "return": { 18820 "description": "current time (in seconds)", 18821 "type": "Number" 18822 }, 18823 "example": ["\n<div><code>\nvar ele;\nvar beginning = true;\nfunction setup() {\n //p5.MediaElement objects are usually created\n //by calling the createAudio(), createVideo(),\n //and createCapture() functions.\n\n //In this example we create\n //a new p5.MediaElement via createAudio().\n ele = createAudio('assets/lucky_dragons.mp3');\n background(250);\n textAlign(CENTER);\n text('start at beginning', width / 2, height / 2);\n}\n\n// this function fires with click anywhere\nfunction mousePressed() {\n if (beginning === true) {\n // here we start the sound at the beginning\n // time(0) is not necessary here\n // as this produces the same result as\n // play()\n ele.play().time(0);\n background(200);\n text('jump 2 sec in', width / 2, height / 2);\n beginning = false;\n } else {\n // here we jump 2 seconds into the sound\n ele.play().time(2);\n background(250);\n text('start at beginning', width / 2, height / 2);\n beginning = true;\n }\n}\n</code></div>"], 18824 "class": "p5.MediaElement", 18825 "module": "p5.dom", 18826 "submodule": "p5.dom", 18827 "overloads": [{ 18828 "line": 2633, 18829 "params": [], 18830 "return": { 18831 "description": "current time (in seconds)", 18832 "type": "Number" 18833 } 18834 }, { 18835 "line": 2678, 18836 "params": [{ 18837 "name": "time", 18838 "description": "<p>time to jump to (in seconds)</p>\n", 18839 "type": "Number" 18840 }], 18841 "chainable": 1 18842 }] 18843 }, { 18844 "file": "lib/addons/p5.dom.js", 18845 "line": 2692, 18846 "description": "<p>Returns the duration of the HTML5 media element.</p>\n", 18847 "itemtype": "method", 18848 "name": "duration", 18849 "return": { 18850 "description": "duration", 18851 "type": "Number" 18852 }, 18853 "example": ["\n<div><code>\nvar ele;\nfunction setup() {\n //p5.MediaElement objects are usually created\n //by calling the createAudio(), createVideo(),\n //and createCapture() functions.\n //In this example we create\n //a new p5.MediaElement via createAudio().\n ele = createAudio('assets/doorbell.mp3');\n background(250);\n textAlign(CENTER);\n text('Click to know the duration!', 10, 25, 70, 80);\n}\nfunction mouseClicked() {\n ele.play();\n background(200);\n //ele.duration dislpays the duration\n text(ele.duration() + ' seconds', width / 2, height / 2);\n}\n</code></div>"], 18854 "class": "p5.MediaElement", 18855 "module": "p5.dom", 18856 "submodule": "p5.dom" 18857 }, { 18858 "file": "lib/addons/p5.dom.js", 18859 "line": 2833, 18860 "description": "<p>Schedule an event to be called when the audio or video\nelement reaches the end. If the element is looping,\nthis will not be called. The element is passed in\nas the argument to the onended callback.</p>\n", 18861 "itemtype": "method", 18862 "name": "onended", 18863 "params": [{ 18864 "name": "callback", 18865 "description": "<p>function to call when the\n soundfile has ended. The\n media element will be passed\n in as the argument to the\n callback.</p>\n", 18866 "type": "Function" 18867 }], 18868 "chainable": 1, 18869 "example": ["\n<div><code>\nfunction setup() {\n var audioEl = createAudio('assets/beat.mp3');\n audioEl.showControls();\n audioEl.onended(sayDone);\n}\n\nfunction sayDone(elt) {\n alert('done playing ' + elt.src);\n}\n</code></div>"], 18870 "class": "p5.MediaElement", 18871 "module": "p5.dom", 18872 "submodule": "p5.dom" 18873 }, { 18874 "file": "lib/addons/p5.dom.js", 18875 "line": 2864, 18876 "class": "p5.MediaElement", 18877 "module": "p5.dom", 18878 "submodule": "p5.dom" 18879 }, { 18880 "file": "lib/addons/p5.dom.js", 18881 "line": 2866, 18882 "description": "<p>Send the audio output of this element to a specified audioNode or\np5.sound object. If no element is provided, connects to p5's master\noutput. That connection is established when this method is first called.\nAll connections are removed by the .disconnect() method.</p>\n<p>This method is meant to be used with the p5.sound.js addon library.</p>\n", 18883 "itemtype": "method", 18884 "name": "connect", 18885 "params": [{ 18886 "name": "audioNode", 18887 "description": "<p>AudioNode from the Web Audio API,\nor an object from the p5.sound library</p>\n", 18888 "type": "AudioNode|Object" 18889 }], 18890 "class": "p5.MediaElement", 18891 "module": "p5.dom", 18892 "submodule": "p5.dom" 18893 }, { 18894 "file": "lib/addons/p5.dom.js", 18895 "line": 2915, 18896 "description": "<p>Disconnect all Web Audio routing, including to master output.\nThis is useful if you want to re-route the output through\naudio effects, for example.</p>\n", 18897 "itemtype": "method", 18898 "name": "disconnect", 18899 "class": "p5.MediaElement", 18900 "module": "p5.dom", 18901 "submodule": "p5.dom" 18902 }, { 18903 "file": "lib/addons/p5.dom.js", 18904 "line": 2930, 18905 "class": "p5.MediaElement", 18906 "module": "p5.dom", 18907 "submodule": "p5.dom" 18908 }, { 18909 "file": "lib/addons/p5.dom.js", 18910 "line": 2932, 18911 "description": "<p>Show the default MediaElement controls, as determined by the web browser.</p>\n", 18912 "itemtype": "method", 18913 "name": "showControls", 18914 "example": ["\n<div><code>\nvar ele;\nfunction setup() {\n //p5.MediaElement objects are usually created\n //by calling the createAudio(), createVideo(),\n //and createCapture() functions.\n //In this example we create\n //a new p5.MediaElement via createAudio()\n ele = createAudio('assets/lucky_dragons.mp3');\n background(200);\n textAlign(CENTER);\n text('Click to Show Controls!', 10, 25, 70, 80);\n}\nfunction mousePressed() {\n ele.showControls();\n background(200);\n text('Controls Shown', width / 2, height / 2);\n}\n</code></div>"], 18915 "class": "p5.MediaElement", 18916 "module": "p5.dom", 18917 "submodule": "p5.dom" 18918 }, { 18919 "file": "lib/addons/p5.dom.js", 18920 "line": 2963, 18921 "description": "<p>Hide the default mediaElement controls.</p>\n", 18922 "itemtype": "method", 18923 "name": "hideControls", 18924 "example": ["\n<div><code>\nvar ele;\nfunction setup() {\n //p5.MediaElement objects are usually created\n //by calling the createAudio(), createVideo(),\n //and createCapture() functions.\n //In this example we create\n //a new p5.MediaElement via createAudio()\n ele = createAudio('assets/lucky_dragons.mp3');\n ele.showControls();\n background(200);\n textAlign(CENTER);\n text('Click to hide Controls!', 10, 25, 70, 80);\n}\nfunction mousePressed() {\n ele.hideControls();\n background(200);\n text('Controls hidden', width / 2, height / 2);\n}\n</code></div>"], 18925 "class": "p5.MediaElement", 18926 "module": "p5.dom", 18927 "submodule": "p5.dom" 18928 }, { 18929 "file": "lib/addons/p5.dom.js", 18930 "line": 2992, 18931 "class": "p5.MediaElement", 18932 "module": "p5.dom", 18933 "submodule": "p5.dom" 18934 }, { 18935 "file": "lib/addons/p5.dom.js", 18936 "line": 3003, 18937 "description": "<p>Schedule events to trigger every time a MediaElement\n(audio/video) reaches a playback cue point.</p>\n<p>Accepts a callback function, a time (in seconds) at which to trigger\nthe callback, and an optional parameter for the callback.</p>\n<p>Time will be passed as the first parameter to the callback function,\nand param will be the second parameter.</p>\n", 18938 "itemtype": "method", 18939 "name": "addCue", 18940 "params": [{ 18941 "name": "time", 18942 "description": "<p>Time in seconds, relative to this media\n element's playback. For example, to trigger\n an event every time playback reaches two\n seconds, pass in the number 2. This will be\n passed as the first parameter to\n the callback function.</p>\n", 18943 "type": "Number" 18944 }, { 18945 "name": "callback", 18946 "description": "<p>Name of a function that will be\n called at the given time. The callback will\n receive time and (optionally) param as its\n two parameters.</p>\n", 18947 "type": "Function" 18948 }, { 18949 "name": "value", 18950 "description": "<p>An object to be passed as the\n second parameter to the\n callback function.</p>\n", 18951 "type": "Object", 18952 "optional": true 18953 }], 18954 "return": { 18955 "description": "id ID of this cue,\n useful for removeCue(id)", 18956 "type": "Number" 18957 }, 18958 "example": ["\n<div><code>\n//\n//\nfunction setup() {\n noCanvas();\n\n var audioEl = createAudio('assets/beat.mp3');\n audioEl.showControls();
18958\n\n // schedule three calls to changeBackground\n audioEl.addCue(0.5, changeBackground, color(255, 0, 0));\n audioEl.addCue(1.0, changeBackground, color(0, 255, 0));\n audioEl.addCue(2.5, changeBackground, color(0, 0, 255));\n audioEl.addCue(3.0, changeBackground, color(0, 255, 255));\n audioEl.addCue(4.2, changeBackground, color(255, 255, 0));\n audioEl.addCue(5.0, changeBackground, color(255, 255, 0));\n}\n\nfunction changeBackground(val) {\n background(val);\n}\n</code></div>"], 18959 "class": "p5.MediaElement", 18960 "module": "p5.dom", 18961 "submodule": "p5.dom" 18962 }, { 18963 "file": "lib/addons/p5.dom.js", 18964 "line": 3067, 18965 "description": "<p>Remove a callback based on its ID. The ID is returned by the\naddCue method.</p>\n", 18966 "itemtype": "method", 18967 "name": "removeCue", 18968 "params": [{ 18969 "name": "id", 18970 "description": "<p>ID of the cue, as returned by addCue</p>\n", 18971 "type": "Number" 18972 }], 18973 "example": ["\n<div><code>\nvar audioEl, id1, id2;\nfunction setup() {\n background(255, 255, 255);\n audioEl = createAudio('assets/beat.mp3');\n audioEl.showControls();\n // schedule five calls to changeBackground\n id1 = audioEl.addCue(0.5, changeBackground, color(255, 0, 0));\n audioEl.addCue(1.0, changeBackground, color(0, 255, 0));\n audioEl.addCue(2.5, changeBackground, color(0, 0, 255));\n audioEl.addCue(3.0, changeBackground, color(0, 255, 255));\n id2 = audioEl.addCue(4.2, changeBackground, color(255, 255, 0));\n text('Click to remove first and last Cue!', 10, 25, 70, 80);\n}\nfunction mousePressed() {\n audioEl.removeCue(id1);\n audioEl.removeCue(id2);\n}\nfunction changeBackground(val) {\n background(val);\n}\n</code></div>"], 18974 "class": "p5.MediaElement", 18975 "module": "p5.dom", 18976 "submodule": "p5.dom" 18977 }, { 18978 "file": "lib/addons/p5.dom.js", 18979 "line": 3109, 18980 "description": "<p>Remove all of the callbacks that had originally been scheduled\nvia the addCue method.</p>\n", 18981 "itemtype": "method", 18982 "name": "clearCues", 18983 "params": [{ 18984 "name": "id", 18985 "description": "<p>ID of the cue, as returned by addCue</p>\n", 18986 "type": "Number" 18987 }], 18988 "example": ["\n<div><code>\nvar audioEl;\nfunction setup() {\n background(255, 255, 255);\n audioEl = createAudio('assets/beat.mp3');\n //Show the default MediaElement controls, as determined by the web browser\n audioEl.showControls();\n // schedule calls to changeBackground\n background(200);\n text('Click to change Cue!', 10, 25, 70, 80);\n audioEl.addCue(0.5, changeBackground, color(255, 0, 0));\n audioEl.addCue(1.0, changeBackground, color(0, 255, 0));\n audioEl.addCue(2.5, changeBackground, color(0, 0, 255));\n audioEl.addCue(3.0, changeBackground, color(0, 255, 255));\n audioEl.addCue(4.2, changeBackground, color(255, 255, 0));\n}\nfunction mousePressed() {\n // here we clear the scheduled callbacks\n audioEl.clearCues();\n // then we add some more callbacks\n audioEl.addCue(1, changeBackground, color(2, 2, 2));\n audioEl.addCue(3, changeBackground, color(255, 255, 0));\n}\nfunction changeBackground(val) {\n background(val);\n}\n</code></div>"], 18989 "class": "p5.MediaElement", 18990 "module": "p5.dom", 18991 "submodule": "p5.dom" 18992 }, { 18993 "file": "lib/addons/p5.dom.js", 18994 "line": 3179, 18995 "description": "<p>Underlying File object. All normal File methods can be called on this.</p>\n", 18996 "itemtype": "property", 18997 "name": "file", 18998 "class": "p5.File", 18999 "module": "p5.dom", 19000 "submodule": "p5.dom" 19001 }, { 19002 "file": "lib/addons/p5.dom.js", 19003 "line": 3191, 19004 "description": "<p>File type (image, text, etc.)</p>\n", 19005 "itemtype": "property", 19006 "name": "type", 19007 "class": "p5.File", 19008 "module": "p5.dom", 19009 "submodule": "p5.dom" 19010 }, { 19011 "file": "lib/addons/p5.dom.js", 19012 "line": 3197, 19013 "description": "<p>File subtype (usually the file extension jpg, png, xml, etc.)</p>\n", 19014 "itemtype": "property", 19015 "name": "subtype", 19016 "class": "p5.File", 19017 "module": "p5.dom", 19018 "submodule": "p5.dom" 19019 }, { 19020 "file": "lib/addons/p5.dom.js", 19021 "line": 3203, 19022 "description": "<p>File name</p>\n", 19023 "itemtype": "property", 19024 "name": "name", 19025 "class": "p5.File", 19026 "module": "p5.dom", 19027 "submodule": "p5.dom" 19028 }, { 19029 "file": "lib/addons/p5.dom.js", 19030 "line": 3209, 19031 "description": "<p>File size</p>\n", 19032 "itemtype": "property", 19033 "name": "size", 19034 "class": "p5.File", 19035 "module": "p5.dom", 19036 "submodule": "p5.dom" 19037 }, { 19038 "file": "lib/addons/p5.dom.js", 19039 "line": 3216, 19040 "description": "<p>URL string containing image data.</p>\n", 19041 "itemtype": "property", 19042 "name": "data", 19043 "class": "p5.File", 19044 "module": "p5.dom", 19045 "submodule": "p5.dom" 19046 }, { 19047 "file": "lib/addons/p5.sound.js", 19048 "line": 46, 19049 "description": "<p>p5.sound \n<a href=\"https://p5js.org/reference/#/libraries/p5.sound\">https://p5js.org/reference/#/libraries/p5.sound</a></p>\n<p>From the Processing Foundation and contributors\n<a href=\"https://github.com/processing/p5.js-sound/graphs/contributors\">https://github.com/processing/p5.js-sound/graphs/contributors</a></p>\n<p>MIT License (MIT)\n<a href=\"https://github.com/processing/p5.js-sound/blob/master/LICENSE\">https://github.com/processing/p5.js-sound/blob/master/LICENSE</a></p>\n<p>Some of the many audio libraries & resources that inspire p5.sound:</p>\n<ul>\n<li>TONE.js (c) Yotam Mann. Licensed under The MIT License (MIT). <a href=\"https://github.com/TONEnoTONE/Tone.js\">https://github.com/TONEnoTONE/Tone.js</a></li>\n<li>buzz.js (c) Jay Salvat. Licensed under The MIT License (MIT). <a href=\"http://buzz.jaysalvat.com/\">http://buzz.jaysalvat.com/</a></li>\n<li>Boris Smus Web Audio API book, 2013. Licensed under the Apache License <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</a></li>\n<li>wavesurfer.js <a href=\"https://github.com/katspaugh/wavesurfer.js\">https://github.com/katspaugh/wavesurfer.js</a></li>\n<li>Web Audio Components by Jordan Santell <a href=\"https://github.com/web-audio-components\">https://github.com/web-audio-components</a></li>\n<li><p>Wilm Thoben's Sound library for Processing <a href=\"https://github.com/processing/processing/tree/master/java/libraries/sound\">https://github.com/processing/processing/tree/master/java/libraries/sound</a></p>\n<p>Web Audio API: <a href=\"http://w3.org/TR/webaudio/\">http://w3.org/TR/webaudio/</a></p>\n</li>\n</ul>\n", 19050 "class": "p5.sound", 19051 "module": "p5.sound", 19052 "submodule": "p5.sound" 19053 }, { 19054 "file": "lib/addons/p5.sound.js", 19055 "line": 214, 19056 "description": "<p>Determine which filetypes are supported (inspired by buzz.js)\nThe audio element (el) will only be used to test browser support for various audio formats</p>\n", 19057 "class": "p5.sound", 19058 "module": "p5.sound", 19059 "submodule": "p5.sound" 19060 }, { 19061 "file": "lib/addons/p5.sound.js", 19062 "line": 364, 19063 "description": "<p>Returns the Audio Context for this sketch. Useful for users\nwho would like to dig deeper into the <a target='_blank' href=\n'http://webaudio.github.io/web-audio-api/'>Web Audio API\n</a>.</p>\n\n<p>Some browsers require users to startAudioContext\nwith a user gesture, such as touchStarted in the example below.</p>", 19064 "itemtype": "method", 19065 "name": "getAudioContext", 19066 "return": { 19067 "description": "AudioContext for this sketch", 19068 "type": "Object" 19069 }, 19070 "example": ["\n<div><code>\n function draw() {\n background(255);\n textAlign(CENTER);\n\n if (getAudioContext().state !== 'running') {\n text('click to start audio', width/2, height/2);\n } else {\n text('audio is enabled', width/2, height/2);\n }\n }
19070\n\n function touchStarted() {\n if (getAudioContext().state !== 'running') {\n getAudioContext().resume();\n }\n var synth = new p5.MonoSynth();\n synth.play('A4', 0.5, 0, 0.2);\n }\n\n</div></code>"], 19071 "class": "p5.sound", 19072 "module": "p5.sound", 19073 "submodule": "p5.sound" 19074 }, { 19075 "file": "lib/addons/p5.sound.js", 19076 "line": 401, 19077 "description": "<p>It is a good practice to give users control over starting audio playback.\nThis practice is enforced by Google Chrome's autoplay policy as of r70\n(<a href=\"https://goo.gl/7K7WLu\">info</a>), iOS Safari, and other browsers.\n</p>\n\n<p>\nuserStartAudio() starts the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/AudioContext\"\ntarget=\"_blank\" title=\"Audio Context @ MDN\">Audio Context</a> on a user gesture. It utilizes\nthe <a href=\"https://github.com/tambien/StartAudioContext\">StartAudioContext</a> library by\nYotam Mann (MIT Licence, 2016). Read more at <a href=\"https://github.com/tambien/StartAudioContext\">https://github.com/tambien/StartAudioContext</a>.\n</p>\n\n<p>Starting the audio context on a user gesture can be as simple as <code>userStartAudio()</code>.\nOptional parameters let you decide on a specific element that will start the audio context,\nand/or call a function once the audio context is started.</p>", 19078 "params": [{ 19079 "name": "element(s)", 19080 "description": "<p>This argument can be an Element,\n Selector String, NodeList, p5.Element,\n jQuery Element, or an Array of any of those.</p>\n", 19081 "type": "Element|Array", 19082 "optional": true 19083 }, { 19084 "name": "callback", 19085 "description": "<p>Callback to invoke when the AudioContext has started</p>\n", 19086 "type": "Function", 19087 "optional": true 19088 }], 19089 "return": { 19090 "description": "Returns a Promise which is resolved when\n the AudioContext state is 'running'", 19091 "type": "Promise" 19092 }, 19093 "itemtype": "method", 19094 "name": "userStartAudio", 19095 "example": ["\n<div><code>\nfunction setup() {\n var myDiv = createDiv('click to start audio');\n myDiv.position(0, 0);\n\n var mySynth = new p5.MonoSynth();\n \n // This won't play until the context has started\n mySynth.play('A6');\n\n // Start the audio context on a click/touch event\n userStartAudio().then(function() {\n myDiv.remove();\n });\n}\n</code></div>"], 19096 "class": "p5.sound", 19097 "module": "p5.sound", 19098 "submodule": "p5.sound" 19099 }, { 19100 "file": "lib/addons/p5.sound.js", 19101 "line": 458, 19102 "description": "<p>Master contains AudioContext and the master sound output.</p>\n", 19103 "class": "p5.sound", 19104 "module": "p5.sound", 19105 "submodule": "p5.sound" 19106 }, { 19107 "file": "lib/addons/p5.sound.js", 19108 "line": 492, 19109 "description": "<p>Returns a number representing the master amplitude (volume) for sound\nin this sketch.</p>\n", 19110 "itemtype": "method", 19111 "name": "getMasterVolume", 19112 "return": { 19113 "description": "Master amplitude (volume) for sound in this sketch.\n Should be between 0.0 (silence) and 1.0.", 19114 "type": "Number" 19115 }, 19116 "class": "p5.sound", 19117 "module": "p5.sound", 19118 "submodule": "p5.sound" 19119 }, { 19120 "file": "lib/addons/p5.sound.js", 19121 "line": 503, 19122 "description": "<p>Scale the output of all sound in this sketch</p>\nScaled between 0.0 (silence) and 1.0 (full volume).\n1.0 is the maximum amplitude of a digital sound, so multiplying\nby greater than 1.0 may cause digital distortion. To\nfade, provide a <code>rampTime</code> parameter. For more\ncomplex fades, see the Envelope class.\n\nAlternately, you can pass in a signal source such as an\noscillator to modulate the amplitude with an audio signal.\n\n<p><b>How This Works</b>: When you load the p5.sound module, it\ncreates a single instance of p5sound. All sound objects in this\nmodule output to p5sound before reaching your computer's output.\nSo if you change the amplitude of p5sound, it impacts all of the\nsound in this module.</p>\n\n<p>If no value is provided, returns a Web Audio API Gain Node</p>", 19123 "itemtype": "method", 19124 "name": "masterVolume", 19125 "params": [{ 19126 "name": "volume", 19127 "description": "<p>Volume (amplitude) between 0.0\n and 1.0 or modulating signal/oscillator</p>\n", 19128 "type": "Number|Object" 19129 }, { 19130 "name": "rampTime", 19131 "description": "<p>Fade for t seconds</p>\n", 19132 "type": "Number", 19133 "optional": true 19134 }, { 19135 "name": "timeFromNow", 19136 "description": "<p>Schedule this event to happen at\n t seconds
19136in the future</p>\n", 19137 "type": "Number", 19138 "optional": true 19139 }], 19140 "class": "p5.sound", 19141 "module": "p5.sound", 19142 "submodule": "p5.sound" 19143 }, { 19144 "file": "lib/addons/p5.sound.js", 19145 "line": 545, 19146 "description": "<p><code>p5.soundOut</code> is the p5.sound master output. It sends output to\nthe destination of this window's web audio context. It contains\nWeb Audio API nodes including a dyanmicsCompressor (<code>.limiter</code>),\nand Gain Nodes for <code>.input</code> and <code>.output</code>.</p>\n", 19147 "itemtype": "property", 19148 "name": "soundOut", 19149 "type": "Object", 19150 "class": "p5.sound", 19151 "module": "p5.sound", 19152 "submodule": "p5.sound" 19153 }, { 19154 "file": "lib/addons/p5.sound.js", 19155 "line": 570, 19156 "class": "p5", 19157 "module": "p5.sound", 19158 "submodule": "p5.sound" 19159 }, { 19160 "file": "lib/addons/p5.sound.js", 19161 "line": 573, 19162 "description": "<p>Returns a number representing the sample rate, in samples per second,\nof all sound objects in this audio context. It is determined by the\nsampling rate of your operating system's sound card, and it is not\ncurrently possile to change.\nIt is often 44100, or twice the range of human hearing.</p>\n", 19163 "itemtype": "method", 19164 "name": "sampleRate", 19165 "return": { 19166 "description": "samplerate samples per second", 19167 "type": "Number" 19168 }, 19169 "class": "p5", 19170 "module": "p5.sound", 19171 "submodule": "p5.sound" 19172 }, { 19173 "file": "lib/addons/p5.sound.js", 19174 "line": 586, 19175 "description": "<p>Returns the closest MIDI note value for\na given frequency.</p>\n", 19176 "itemtype": "method", 19177 "name": "freqToMidi", 19178 "params": [{ 19179 "name": "frequency", 19180 "description": "<p>A freqeuncy, for example, the "A"\n above Middle C is 440Hz</p>\n", 19181 "type": "Number" 19182 }], 19183 "return": { 19184 "description": "MIDI note value", 19185 "type": "Number" 19186 }, 19187 "class": "p5", 19188 "module": "p5.sound", 19189 "submodule": "p5.sound" 19190 }, { 19191 "file": "lib/addons/p5.sound.js", 19192 "line": 600, 19193 "description": "<p>Returns the frequency value of a MIDI note value.\nGeneral MIDI treats notes as integers where middle C\nis 60, C# is 61, D is 62 etc. Useful for generating\nmusical frequencies with oscillators.</p>\n", 19194 "itemtype": "method", 19195 "name": "midiToFreq", 19196 "params": [{ 19197 "name": "midiNote", 19198 "description": "<p>The number of a MIDI note</p>\n", 19199 "type": "Number" 19200 }], 19201 "return": { 19202 "description": "Frequency value of the given MIDI note", 19203 "type": "Number" 19204 }, 19205 "example": ["\n<div><code>\nvar notes = [60, 64, 67, 72];\nvar i = 0;\n\nfunction setup() {\n osc = new p5.Oscillator('Triangle');\n osc.start();\n frameRate(1);\n}\n\nfunction draw() {\n var freq = midiToFreq(notes[i]);\n osc.freq(freq);\n i++;\n if (i >= notes.length){\n i = 0;\n }\n}\n</code></div>"], 19206 "class": "p5", 19207 "module": "p5.sound", 19208 "submodule": "p5.sound" 19209 }, { 19210 "file": "lib/addons/p5.sound.js", 19211 "line": 662, 19212 "description": "<p>List the SoundFile formats that you will include. LoadSound\nwill search your directory for these extensions, and will pick\na format that is compatable with the client's web browser.\n<a href=\"http://media.io/\">Here</a> is a free online file\nconverter.</p>\n", 19213 "itemtype": "method", 19214 "name": "soundFormats", 19215 "params": [{ 19216 "name": "formats", 19217 "description": "<p>i.e. 'mp3', 'wav', 'ogg'</p>\n", 19218 "type": "String", 19219 "optional": true, 19220 "multiple": true 19221 }], 19222 "example": ["\n<div><code>\nfunction preload() {\n // set the global sound formats\n soundFormats('mp3', 'ogg');\n\n // load either beatbox.mp3, or .ogg, depending on browser\n mySound = loadSound('assets/beatbox.mp3');\n}\n\nfunction setup() {\n mySound.play();\n}\n</code></div>"], 19223 "class": "p5", 19224 "module": "p5.sound", 19225 "submodule": "p5.sound" 19226 }, { 19227 "file": "lib/addons/p5.sound.js", 19228 "line": 775, 19229 "description": "<p>Used by Osc and Envelope to chain signal math</p>\n", 19230 "class": "p5", 19231 "module": "p5.sound", 19232 "submodule": "p5.sound" 19233 }, { 19234 "file": "lib/addons/p5.sound.js", 19235 "line": 1121, 19236 "description": "<p>loadSound() returns a new p5.SoundFile from a specified\npath. If called during preload(), the p5.SoundFile will be ready\nto play in time for setup() and draw(). If called outside of\npreload, the p5.SoundFile will not be ready immediately, so\nloadSound accepts a callback as the second parameter. Using a\n<a href=\"https://github.com/processing/p5.js/wiki/Local-server\">\nlocal server</a> is recommended when loading external files.</p>\n", 19237 "itemtype": "method", 19238 "name": "loadSound", 19239 "params": [{ 19240 "name": "path", 19241 "description": "<p>Path to the sound file, or an array with\n paths to soundfiles in multiple formats\n i.e. ['sound.ogg', 'sound.mp3'].\n Alternately, accepts an object: either\n from the HTML5 File API, or a p5.File.</p>\n", 19242 "type": "String|Array" 19243 }, { 19244 "name": "successCallback", 19245 "description": "<p>Name of a function to call once file loads</p>\n", 19246 "type": "Function", 19247 "optional": true 19248 }, { 19249 "name": "errorCallback", 19250 "description": "<p>Name of a function to call if there is\n an error loading the file.</p>\n", 19251 "type": "Function", 19252 "optional": true 19253 }, { 19254 "name": "whileLoading", 19255 "description": "<p>Name of a function to call while file is loading.\n This function will receive the percentage loaded\n so far, from 0.0 to 1.0.</p>\n", 19256 "type": "Function", 19257 "optional": true 19258 }], 19259 "return": { 19260 "description": "Returns a p5.SoundFile", 19261 "type": "SoundFile" 19262 }, 19263 "example": ["\n<div><code>\nfunction preload() {\n mySound = loadSound('assets/doorbell.mp3');\n}\n\nfunction setup() {\n mySound.setVolume(0.1);\n mySound.play();\n}\n</code></div>"], 19264 "class": "p5.SoundFile", 19265 "module": "p5.sound", 19266 "submodule": "p5.sound" 19267 }, { 19268 "file": "lib/addons/p5.sound.js", 19269 "line": 1277, 19270 "description": "<p>Returns true if the sound file finished loading successfully.</p>\n", 19271 "itemtype": "method", 19272 "name": "isLoaded", 19273 "return": { 19274 "description": "", 19275 "type": "Boolean" 19276 }, 19277 "class": "p5.SoundFile", 19278 "module": "p5.sound", 19279 "submodule": "p5.sound" 19280 }, { 19281 "file": "lib/addons/p5.sound.js", 19282 "line": 1290, 19283 "description": "<p>Play the p5.SoundFile</p>\n", 19284 "itemtype": "method", 19285 "name": "play", 19286 "params": [{ 19287 "name": "startTime", 19288 "description": "<p>(optional) schedule playback to start (in seconds from now).</p>\n", 19289 "type": "Number", 19290 "optional": true 19291 }, { 19292 "name": "rate", 19293 "description": "<p>(optional) playback rate</p>\n", 19294 "type": "Number", 19295 "optional": true 19296 }, { 19297 "name": "amp", 19298 "description": "<p>(optional) amplitude (volume)\n of playback</p>\n", 19299 "type": "Number", 19300 "optional": true 19301 }, { 19302 "name": "cueStart", 19303 "description": "<p>(optional) cue start time in seconds</p>\n", 19304 "type": "Number", 19305 "optional": true 19306 }, { 19307 "name": "duration", 19308 "description": "<p>(optional) duration of playback in seconds</p>\n", 19309 "type": "Number", 19310 "optional": true 19311 }], 19312 "class": "p5.SoundFile", 19313 "module": "p5.sound", 19314 "submodule": "p5.sound" 19315 }, { 19316 "file": "lib/addons/p5.sound.js", 19317 "line": 1395, 19318 "description": "<p>p5.SoundFile has two play modes: <code>restart</code> and\n<code>sustain</code>. Play Mode determines what happens to a\np5.SoundFile if it is triggered while in the middle of playback.\nIn sustain mode, playback will continue simultaneous to the\nnew playback. In restart mode, play() will stop playback\nand start over. With untilDone, a sound will play only if it's\nnot already playing. Sustain is the default mode.</p>\n", 19319 "itemtype": "method", 19320 "name": "playMode", 19321 "params": [{ 19322 "name": "str", 19323 "description": "<p>'restart' or 'sustain' or 'untilDone'</p>\n", 19324 "type": "String" 19325 }], 19326 "example": ["\n<div><code>\nvar mySound;\nfunction preload(){\n mySound = loadSound('assets/Damscray_DancingTiger.mp3');\n}\nfunction mouseClicked() {\n mySound.playMode('sustain');\n mySound.play();\n}\nfunction keyPressed() {\n mySound.playMode('restart');\n mySound.play();\n}\n\n </code></div>"], 19327 "class": "p5.SoundFile", 19328 "module": "p5.sound", 19329 "submodule": "p5.sound" 19330 }, { 19331 "file": "lib/addons/p5.sound.js", 19332 "line": 1439, 19333 "description": "<p>Pauses a file that is currently playing. If the file is not\nplaying, then nothing will happen.</p>\n<p>After pausing, .play() will resume from the paused\nposition.\nIf p5.SoundFile had been set to loop before it was paused,\nit will continue to loop after it is unpaused with .play().</p>\n", 19334 "itemtype": "method", 19335 "name": "pause", 19336 "params": [{ 19337 "name": "startTime", 19338 "description": "<p>(optional) schedule event to occur\n seconds from now</p>\n", 19339 "type": "Number", 19340 "optional": true 19341 }], 19342 "example": ["\n<div><code>\nvar soundFile;\n\nfunction preload() {\n soundFormats('ogg', 'mp3');\n soundFile = loadSound('assets/Damscray_-_Dancing_Tiger_02.mp3');\n}\nfunction setup() {\n background(0, 255, 0);\n soundFile.setVolume(0.1);\n soundFile.loop();\n}\nfunction keyTyped() {\n if (key == 'p') {\n soundFile.pause();\n background(255, 0, 0);\n }\n}\n\nfunction keyReleased() {\n if (key == 'p') {\n soundFile.play();\n background(0, 255, 0);\n }\n}\n</code>\n</div>"], 19343 "class": "p5.SoundFile", 19344 "module": "p5.sound", 19345 "submodule": "p5.sound" 19346 }, { 19347 "file": "lib/addons/p5.sound.js", 19348 "line": 1495, 19349 "description": "<p>
19349Loop the p5.SoundFile. Accepts optional parameters to set the\nplayback rate, playback volume, loopStart, loopEnd.</p>\n", 19350 "itemtype": "method", 19351 "name": "loop", 19352 "params": [{ 19353 "name": "startTime", 19354 "description": "<p>(optional) schedule event to occur\n seconds from now</p>\n", 19355 "type": "Number", 19356 "optional": true 19357 }, { 19358 "name": "rate", 19359 "description": "<p>(optional) playback rate</p>\n", 19360 "type": "Number", 19361 "optional": true 19362 }, { 19363 "name": "amp", 19364 "description": "<p>(optional) playback volume</p>\n", 19365 "type": "Number", 19366 "optional": true 19367 }, { 19368 "name": "cueLoopStart", 19369 "description": "<p>(optional) startTime in seconds</p>\n", 19370 "type": "Number", 19371 "optional": true 19372 }, { 19373 "name": "duration", 19374 "description": "<p>(optional) loop duration in seconds</p>\n", 19375 "type": "Number", 19376 "optional": true 19377 }], 19378 "class": "p5.SoundFile", 19379 "module": "p5.sound", 19380 "submodule": "p5.sound" 19381 }, { 19382 "file": "lib/addons/p5.sound.js", 19383 "line": 1511, 19384 "description": "<p>Set a p5.SoundFile's looping flag to true or false. If the sound\nis currently playing, this change will take effect when it\nreaches the end of the current playback.</p>\n", 19385 "itemtype": "method", 19386 "name": "setLoop", 19387 "params": [{ 19388 "name": "Boolean", 19389 "description": "<p>set looping to true or false</p>\n", 19390 "type": "Boolean" 19391 }], 19392 "class": "p5.SoundFile", 19393 "module": "p5.sound", 19394 "submodule": "p5.sound" 19395 }, { 19396 "file": "lib/addons/p5.sound.js", 19397 "line": 1532, 19398 "description": "<p>Returns 'true' if a p5.SoundFile is currently looping and playing, 'false' if not.</p>\n", 19399 "itemtype": "method", 19400 "name": "isLooping", 19401 "return": { 19402 "description": "", 19403 "type": "Boolean" 19404 }, 19405 "class": "p5.SoundFile", 19406 "module": "p5.sound", 19407 "submodule": "p5.sound" 19408 }, { 19409 "file": "lib/addons/p5.sound.js", 19410 "line": 1547, 19411 "description": "<p>Returns true if a p5.SoundFile is playing, false if not (i.e.\npaused or stopped).</p>\n", 19412 "itemtype": "method", 19413 "name": "isPlaying", 19414 "return": { 19415 "description": "", 19416 "type": "Boolean" 19417 }, 19418 "class": "p5.SoundFile", 19419 "module": "p5.sound", 19420 "submodule": "p5.sound" 19421 }, { 19422 "file": "lib/addons/p5.sound.js", 19423 "line": 1557, 19424 "description": "<p>Returns true if a p5.SoundFile is paused, false if not (i.e.\nplaying or stopped).</p>\n", 19425 "itemtype": "method", 19426 "name": "isPaused", 19427 "return": { 19428 "description": "", 19429 "type": "Boolean" 19430 }, 19431 "class": "p5.SoundFile", 19432 "module": "p5.sound", 19433 "submodule": "p5.sound" 19434 }, { 19435 "file": "lib/addons/p5.sound.js", 19436 "line": 1567, 19437 "description": "<p>Stop soundfile playback.</p>\n", 19438 "itemtype": "method", 19439 "name": "stop", 19440 "params": [{ 19441 "name": "startTime", 19442 "description": "<p>(optional) schedule event to occur\n in seconds from now</p>\n", 19443 "type": "Number", 19444 "optional": true 19445 }], 19446 "class": "p5.SoundFile", 19447 "module": "p5.sound", 19448 "submodule": "p5.sound" 19449 }, { 19450 "file": "lib/addons/p5.sound.js", 19451 "line": 1613, 19452 "description": "<p>Multiply the output volume (amplitude) of a sound file\nbetween 0.0 (silence) and 1.0 (full volume).\n1.0 is the maximum amplitude of a digital sound, so multiplying\nby greater than 1.0 may cause digital distortion. To\nfade, provide a <code>rampTime</code> parameter. For more\ncomplex fades, see the Envelope class.</p>\n<p>Alternately, you can pass in a signal source such as an\noscillator to modulate the amplitude with an audio signal.</p>\n", 19453 "itemtype": "method", 19454 "name": "setVolume", 19455 "params": [{ 19456 "name": "volume", 19457 "description": "<p>Volume (amplitude) between 0.0\n and 1.0 or modulating signal/oscillator</p>\n", 19458 "type": "Number|Object" 19459 }, { 19460 "name": "rampTime", 19461 "description": "<p>Fade for t seconds</p>\n", 19462 "type": "Number", 19463 "optional": true 19464 }, { 19465 "name": "timeFromNow", 19466 "description": "<p>Schedule this event to happen at\n t seconds
19466in the future</p>\n", 19467 "type": "Number", 19468 "optional": true 19469 }], 19470 "class": "p5.SoundFile", 19471 "module": "p5.sound", 19472 "submodule": "p5.sound" 19473 }, { 19474 "file": "lib/addons/p5.sound.js", 19475 "line": 1654, 19476 "description": "<p>Set the stereo panning of a p5.sound object to\na floating point number between -1.0 (left) and 1.0 (right).\nDefault is 0.0 (center).</p>\n", 19477 "itemtype": "method", 19478 "name": "pan", 19479 "params": [{ 19480 "name": "panValue", 19481 "description": "<p>Set the stereo panner</p>\n", 19482 "type": "Number", 19483 "optional": true 19484 }, { 19485 "name": "timeFromNow", 19486 "description": "<p>schedule this event to happen\n seconds from now</p>\n", 19487 "type": "Number", 19488 "optional": true 19489 }], 19490 "example": ["\n<div><code>\n\n var ball = {};\n var soundFile;\n\n function preload() {\n soundFormats('ogg', 'mp3');\n soundFile = loadSound('assets/beatbox.mp3');\n }\n\n function draw() {\n background(0);\n ball.x = constrain(mouseX, 0, width);\n ellipse(ball.x, height/2, 20, 20)\n }\n\n function mousePressed(){\n // map the ball's x location to a panning degree\n // between -1.0 (left) and 1.0 (right)\n var panning = map(ball.x, 0., width,-1.0, 1.0);\n soundFile.pan(panning);\n soundFile.play();\n }\n </div></code>"], 19491 "class": "p5.SoundFile", 19492 "module": "p5.sound", 19493 "submodule": "p5.sound" 19494 }, { 19495 "file": "lib/addons/p5.sound.js", 19496 "line": 1693, 19497 "description": "<p>Returns the current stereo pan position (-1.0 to 1.0)</p>\n", 19498 "itemtype": "method", 19499 "name": "getPan", 19500 "return": { 19501 "description": "Returns the stereo pan setting of the Oscillator\n as a number between -1.0 (left) and 1.0 (right).\n 0.0 is center and default.", 19502 "type": "Number" 19503 }, 19504 "class": "p5.SoundFile", 19505 "module": "p5.sound", 19506 "submodule": "p5.sound" 19507 }, { 19508 "file": "lib/addons/p5.sound.js", 19509 "line": 1704, 19510 "description": "<p>Set the playback rate of a sound file. Will change the speed and the pitch.\nValues less than zero will reverse the audio buffer.</p>\n", 19511 "itemtype": "method", 19512 "name": "rate", 19513 "params": [{ 19514 "name": "playbackRate", 19515 "description": "<p>Set the playback rate. 1.0 is normal,\n .5 is half-speed, 2.0 is twice as fast.\n Values less than zero play backwards.</p>\n", 19516 "type": "Number", 19517 "optional": true 19518 }], 19519 "example": ["\n<div><code>\nvar song;\n\nfunction preload() {\n song = loadSound('assets/Damscray_DancingTiger.mp3');\n}\n\nfunction setup() {\n song.loop();\n}\n\nfunction draw() {\n background(200);\n\n // Set the rate to a range between 0.1 and 4\n // Changing the rate also alters the pitch\n var speed = map(mouseY, 0.1, height, 0, 2);\n speed = constrain(speed, 0.01, 4);\n song.rate(speed);\n\n // Draw a circle to show what is going on\n stroke(0);\n fill(51, 100);\n ellipse(mouseX, 100, 48, 48);\n}\n\n </code>\n </div>\n"], 19520 "class": "p5.SoundFile", 19521 "module": "p5.sound", 19522 "submodule": "p5.sound" 19523 }, { 19524 "file": "lib/addons/p5.sound.js", 19525 "line": 1777, 19526 "description": "<p>Returns the duration of a sound file in seconds.</p>\n", 19527 "itemtype": "method", 19528 "name": "duration", 19529 "return": { 19530 "description": "The duration of the soundFile in seconds.", 19531 "type": "Number" 19532 }, 19533 "class": "p5.SoundFile", 19534 "module": "p5.sound", 19535 "submodule": "p5.sound" 19536 }, { 19537 "file": "lib/addons/p5.sound.js", 19538 "line": 1791, 19539 "description": "<p>Return the current position of the p5.SoundFile playhead, in seconds.\nTime is relative to the normal buffer direction, so if <code>reverseBuffer</code>\nhas been called, currentTime will count backwards.</p>\n", 19540 "itemtype": "method", 19541 "name": "currentTime", 19542 "return": { 19543 "description": "currentTime of the soundFile in seconds.", 19544 "type": "Number" 19545 }, 19546 "class": "p5.SoundFile", 19547 "module": "p5.sound", 19548 "submodule": "p5.sound" 19549 }, { 19550 "file": "lib/addons/p5.sound.js", 19551 "line": 1802, 19552 "description": "<p>Move the playhead of the song to a position, in seconds. Start timing\nand playback duration. If none are given, will reset the file to play\nentire duration from start to finish.</p>\n", 19553 "itemtype": "method", 19554 "name": "jump", 19555 "params": [{ 19556 "name": "cueTime", 19557 "description": "<p>cueTime of the soundFile in seconds.</p>\n", 19558 "type": "Number" 19559 }, { 19560 "name": "duration", 19561 "description": "<p>duration in seconds.</p>\n", 19562 "type": "Number" 19563 }], 19564 "class": "p5.SoundFile", 19565 "module": "p5.sound", 19566 "submodule": "p5.sound" 19567 }, { 19568 "file": "lib/addons/p5.sound.js", 19569 "line": 1825, 19570 "description": "<p>Return the number of channels in a sound file.\nFor example, Mono = 1, Stereo = 2.</p>\n", 19571 "itemtype": "method", 19572 "name": "channels", 19573 "return": { 19574 "description": "[channels]", 19575 "type": "Number" 19576 }, 19577 "class": "p5.SoundFile", 19578 "module": "p5.sound", 19579 "submodule": "p5.sound" 19580 }, { 19581 "file": "lib/addons/p5.sound.js", 19582 "line": 1835, 19583 "description": "<p>Return the sample rate of the sound file.</p>\n", 19584 "itemtype": "method", 19585 "name": "sampleRate", 19586 "return": { 19587 "description": "[sampleRate]", 19588 "type": "Number" 19589 }, 19590 "class": "p5.SoundFile", 19591 "module": "p5.sound", 19592 "submodule": "p5.sound" 19593 }, { 19594 "file": "lib/addons/p5.sound.js", 19595 "line": 1844, 19596 "description": "<p>Return the number of samples in a sound file.\nEqual to sampleRate * duration.</p>\n", 19597 "itemtype": "method", 19598 "name": "frames", 19599 "return": {
19600 "description": "[sampleCount]", 19601 "type": "Number" 19602 }, 19603 "class": "p5.SoundFile", 19604 "module": "p5.sound", 19605 "submodule": "p5.sound" 19606 }, { 19607 "file": "lib/addons/p5.sound.js", 19608 "line": 1854, 19609 "description": "<p>Returns an array of amplitude peaks in a p5.SoundFile that can be\nused to draw a static waveform. Scans through the p5.SoundFile's\naudio buffer to find the greatest amplitudes. Accepts one\nparameter, 'length', which determines size of the array.\nLarger arrays result in more precise waveform visualizations.</p>\n<p>Inspired by Wavesurfer.js.</p>\n", 19610 "itemtype": "method", 19611 "name": "getPeaks", 19612 "params": [{ 19613 "name": "length", 19614 "description": "<p>length is the size of the returned array.\n Larger length results in more precision.\n Defaults to 5*width of the browser window.</p>\n", 19615 "type": "Number", 19616 "optional": true 19617 }], 19618 "return": { 19619 "description": "Array of peaks.", 19620 "type": "Float32Array" 19621 }, 19622 "class": "p5.SoundFile", 19623 "module": "p5.sound", 19624 "submodule": "p5.sound" 19625 }, { 19626 "file": "lib/addons/p5.sound.js", 19627 "line": 1906, 19628 "description": "<p>Reverses the p5.SoundFile's buffer source.\nPlayback must be handled separately (see example).</p>\n", 19629 "itemtype": "method", 19630 "name": "reverseBuffer", 19631 "example": ["\n<div><code>\nvar drum;\n\nfunction preload() {\n drum = loadSound('assets/drum.mp3');\n}\n\nfunction setup() {\n drum.reverseBuffer();\n drum.play();\n}\n\n </code>\n </div>"], 19632 "class": "p5.SoundFile", 19633 "module": "p5.sound", 19634 "submodule": "p5.sound" 19635 }, { 19636 "file": "lib/addons/p5.sound.js", 19637 "line": 1946, 19638 "description": "<p>Schedule an event to be called when the soundfile\nreaches the end of a buffer. If the soundfile is\nplaying through once, this will be called when it\nends. If it is looping, it will be called when\nstop is called.</p>\n", 19639 "itemtype": "method", 19640 "name": "onended", 19641 "params": [{ 19642 "name": "callback", 19643 "description": "<p>function to call when the\n soundfile has ended.</p>\n", 19644 "type": "Function" 19645 }], 19646 "class": "p5.SoundFile", 19647 "module": "p5.sound", 19648 "submodule": "p5.sound" 19649 }, { 19650 "file": "lib/addons/p5.sound.js", 19651 "line": 1999, 19652 "description": "<p>Connects the output of a p5sound object to input of another\np5.sound object. For example, you may connect a p5.SoundFile to an\nFFT or an Effect. If no parameter is given, it will connect to\nthe master output. Most p5sound objects connect to the master\noutput when they are created.</p>\n", 19653 "itemtype": "method", 19654 "name": "connect", 19655 "params": [{ 19656 "name": "object", 19657 "description": "<p>Audio object that accepts an input</p>\n", 19658 "type": "Object", 19659 "optional": true 19660 }], 19661 "class": "p5.SoundFile", 19662 "module": "p5.sound", 19663 "submodule": "p5.sound" 19664 }, { 19665 "file": "lib/addons/p5.sound.js", 19666 "line": 2020, 19667 "description": "<p>Disconnects the output of this p5sound object.</p>\n", 19668 "itemtype": "method", 19669 "name": "disconnect", 19670 "class": "p5.SoundFile", 19671 "module": "p5.sound", 19672 "submodule": "p5.sound" 19673 }, { 19674 "file": "lib/addons/p5.sound.js", 19675 "line": 2030, 19676 "class": "p5.SoundFile", 19677 "module": "p5.sound", 19678 "submodule": "p5.sound" 19679 }, { 19680 "file": "lib/addons/p5.sound.js", 19681 "line": 2035, 19682 "description": "<p>Reset the source for this SoundFile to a\nnew path (URL).</p>\n", 19683 "itemtype": "method", 19684 "name": "setPath", 19685 "params": [{ 19686 "name": "path", 19687 "description": "<p>path to audio file</p>\n", 19688 "type": "String" 19689 }, { 19690 "name": "callback", 19691 "description": "<p>Callback</p>\n", 19692 "type": "Function" 19693 }], 19694 "class": "p5.SoundFile", 19695 "module": "p5.sound", 19696 "submodule": "p5.sound" 19697 }, { 19698 "file": "lib/addons/p5.sound.js", 19699 "line": 2048, 19700 "description": "<p>Replace the current Audio Buffer with a new Buffer.</p>\n", 19701 "itemtype": "method", 19702 "name": "setBuffer", 19703 "params": [{ 19704 "name": "buf", 19705 "description": "<p>Array of Float32 Array(s). 2 Float32 Arrays\n will create a stereo source. 1 will create\n a mono source.</p>\n", 19706 "type": "Array" 19707 }], 19708 "class": "p5.SoundFile", 19709 "module": "p5.sound", 19710 "submodule": "p5.sound" 19711 }, { 19712 "file": "lib/addons/p5.sound.js", 19713 "line": 2120, 19714 "description": "<p>processPeaks returns an array of timestamps where it thinks there is a beat.</p>\n<p>This is an asynchronous function that processes the soundfile in an offline audio context,\nand sends the results to your callback function.</p>\n<p>The process involves running the soundfile through a lowpass filter, and finding all of the\npeaks above the initial threshold. If the total number of peaks are below the minimum number of peaks,\nit decreases the threshold and re-runs the analysis until either minPeaks or minThreshold are reached.</p>\n", 19715 "itemtype": "method", 19716 "name": "processPeaks", 19717 "params": [{ 19718 "name": "callback", 19719 "description": "<p>a function to call once this data is returned</p>\n", 19720 "type": "Function" 19721 }, { 19722 "name": "initThreshold", 19723 "description": "<p>initial threshold defaults to 0.9</p>\n", 19724 "type": "Number", 19725 "optional": true 19726 }, { 19727 "name": "minThreshold", 19728 "description": "<p>minimum threshold defaults to 0.22</p>\n", 19729 "type": "Number", 19730 "optional": true 19731 }, { 19732 "name": "minPeaks", 19733 "description": "<p>minimum number of peaks defaults to 200</p>\n", 19734 "type": "Number", 19735 "optional": true 19736 }], 19737 "return": { 19738 "description": "Array of timestamped peaks", 19739 "type": "Array" 19740 }, 19741 "class": "p5.SoundFile", 19742 "module": "p5.sound", 19743 "submodule": "p5.sound" 19744 }, { 19745 "file": "lib/addons/p5.sound.js", 19746 "line": 2313, 19747 "class": "p5.SoundFile", 19748 "module": "p5.sound", 19749 "submodule": "p5.sound" 19750 }, { 19751 "file": "lib/addons/p5.sound.js", 19752 "line": 2322, 19753 "description": "<p>Schedule events to trigger every time a MediaElement\n(audio/video) reaches a playback cue point.</p>\n<p>Accepts a callback function, a time (in seconds) at which to trigger\nthe callback, and an optional parameter for the callback.</p>\n<p>Time will be passed as the first parameter to the callback function,\nand param will be the second parameter.</p>\n", 19754 "itemtype": "method", 19755 "name": "addCue", 19756 "params": [{ 19757 "name": "time", 19758 "description": "<p>Time in seconds, relative to this media\n element's playback. For example, to trigger\n an event every time playback reaches two\n seconds, pass in the number 2. This will be\n passed as the first parameter to\n the callback function.</p>\n", 19759 "type": "Number" 19760 }, { 19761 "name": "callback", 19762 "description": "<p>Name of a function that will be\n called at the given time. The callback will\n receive time and (optionally) param as its\n two parameters.</p>\n", 19763 "type": "Function" 19764 }, { 19765 "name": "value", 19766 "description": "<p>An object to be passed as the\n second parameter to the\n callback function.</p>\n", 19767 "type": "Object", 19768 "optional": true 19769 }], 19770 "return": { 19771 "description": "id ID of this cue,\n useful for removeCue(id)", 19772 "type": "Number" 19773 }, 19774 "example": ["\n<div><code>\nvar mySound;\nfunction preload() {\n mySound = loadSound('assets/beat.mp3');\n}\n\nfunction setup() {\n background(0);\n noStroke();\n fill(255);\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n\n // schedule calls to changeText\n mySound.addCue(0.50, changeText, \"hello\" );\n mySound.addCue(1.00, changeText, \"p5\" );\n mySound.addCue(1.50, changeText, \"what\" );\n mySound.addCue(2.00, changeText, \"do\" );\n mySound.addCue(2.50, changeText, \"you\" );\n mySound.addCue(3.00, changeText, \"want\" );\n mySound.addCue(4.00, changeText, \"to\" );\n mySound.addCue(5.00, changeText, \"make\" );
19774\n mySound.addCue(6.00, changeText, \"?\" );\n}\n\nfunction changeText(val) {\n background(0);\n text(val, width/2, height/2);\n}\n\nfunction mouseClicked() {\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n if (mySound.isPlaying() ) {\n mySound.stop();\n } else {\n mySound.play();\n }\n }\n}\n</code></div>"], 19775 "class": "p5.SoundFile", 19776 "module": "p5.sound", 19777 "submodule": "p5.sound" 19778 }, { 19779 "file": "lib/addons/p5.sound.js", 19780 "line": 2400, 19781 "description": "<p>Remove a callback based on its ID. The ID is returned by the\naddCue method.</p>\n", 19782 "itemtype": "method", 19783 "name": "removeCue", 19784 "params": [{ 19785 "name": "id", 19786 "description": "<p>ID of the cue, as returned by addCue</p>\n", 19787 "type": "Number" 19788 }], 19789 "class": "p5.SoundFile", 19790 "module": "p5.sound", 19791 "submodule": "p5.sound" 19792 }, { 19793 "file": "lib/addons/p5.sound.js", 19794 "line": 2419, 19795 "description": "<p>Remove all of the callbacks that had originally been scheduled\nvia the addCue method.</p>\n", 19796 "itemtype": "method", 19797 "name": "clearCues", 19798 "class": "p5.SoundFile", 19799 "module": "p5.sound", 19800 "submodule": "p5.sound" 19801 }, { 19802 "file": "lib/addons/p5.sound.js", 19803 "line": 2444, 19804 "description": "<p>Save a p5.SoundFile as a .wav file. The browser will prompt the user\nto download the file to their device. To upload a file to a server, see\n<a href=\"/docs/reference/#/p5.SoundFile/getBlob\">getBlob</a></p>\n", 19805 "itemtype": "method", 19806 "name": "save", 19807 "params": [{ 19808 "name": "fileName", 19809 "description": "<p>name of the resulting .wav file.</p>\n", 19810 "type": "String", 19811 "optional": true 19812 }], 19813 "example": ["\n <div><code>\n var inp, button, mySound;\n var fileName = 'cool';\n function preload() {\n mySound = loadSound('assets/doorbell.mp3');\n }\n function setup() {\n btn = createButton('click to save file');\n btn.position(0, 0);\n btn.mouseClicked(handleMouseClick);\n }\n\n function handleMouseClick() {\n mySound.save(fileName);\n }\n</code></div>"], 19814 "class": "p5.SoundFile", 19815 "module": "p5.sound", 19816 "submodule": "p5.sound" 19817 }, { 19818 "file": "lib/addons/p5.sound.js", 19819 "line": 2473, 19820 "description": "<p>This method is useful for sending a SoundFile to a server. It returns the\n.wav-encoded audio data as a "<a target=\"_blank\" title=\"Blob reference at\nMDN\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Blob\">Blob</a>".\nA Blob is a file-like data object that can be uploaded to a server\nwith an <a href=\"/docs/reference/#/p5/httpDo\">http</a> request. We'll\nuse the <code>httpDo</code> options object to send a POST request with some\nspecific options: we encode the request as <code>multipart/form-data</code>,\nand attach the blob as one of the form values using <code>FormData</code>.</p>\n", 19821 "itemtype": "method", 19822 "name": "getBlob", 19823 "return": { 19824 "description": "A file-like data object", 19825 "type": "Blob" 19826 }, 19827 "example": ["\n <div><code>\n\n function preload() {\n mySound = loadSound('assets/doorbell.mp3');\n }\n\n function setup() {\n noCanvas();\n var soundBlob = mySound.getBlob();\n\n // Now we can send the blob to a server...\n var serverUrl = 'https://jsonplaceholder.typicode.com/posts';\n var httpRequestOptions = {\n method: 'POST',\n body: new FormData().append('soundBlob', soundBlob),\n headers: new Headers({\n 'Content-Type': 'multipart/form-data'\n })\n };\n httpDo(serverUrl, httpRequestOptions);\n\n // We can also create an `ObjectURL` pointing to the Blob\n var blobUrl = URL.createObjectURL(soundBlob);\n\n // The `<Audio>` Element accepts Object URL's\n var htmlAudioElt = createAudio(blobUrl).showControls();\n\n createDiv();\n\n // The ObjectURL exists as long as this tab is open\n var input = createInput(blobUrl);\n input.attribute('readonly', true);\n input.mouseClicked(function() { input.elt.select() });\n }\n\n</code></div>"], 19828 "class": "p5.SoundFile", 19829 "module": "p5.sound", 19830 "submodule": "p5.sound" 19831 }, { 19832 "file": "lib/addons/p5.sound.js", 19833 "line": 2611, 19834 "description": "<p>Connects to the p5sound instance (master output) by default.\nOptionally, you can pass in a specific source (i.e. a soundfile).</p>\n", 19835 "itemtype": "method", 19836 "name": "setInput", 19837 "params": [{ 19838 "name": "snd", 19839 "description": "<p>set the sound source\n (optional, defaults to\n master output)</p>\n", 19840 "type": "SoundObject|undefined", 19841 "optional": true 19842 }, { 19843 "name": "smoothing", 19844 "description": "<p>a range between 0.0 and 1.0\n to smooth amplitude readings</p>\n", 19845 "type": "Number|undefined", 19846 "optional": true 19847 }], 19848 "example": ["\n<div><code>\nfunction preload(){\n sound1 = loadSound('assets/beat.mp3');\n sound2 = loadSound('assets/drum.mp3');\n}\nfunction setup(){\n amplitude = new p5.Amplitude();\n sound1.play();\n sound2.play();\n amplitude.setInput(sound2);\n}\nfunction draw() {\n background(0);\n fill(255);\n var level = amplitude.getLevel();\n var size = map(level, 0, 1, 0, 200);\n ellipse(width/2, height/2, size, size);\n}\nfunction mouseClicked(){\n sound1.stop();\n sound2.stop();\n}\n</code></div>"], 19849 "class": "p5.Amplitude", 19850 "module": "p5.sound", 19851 "submodule": "p5.sound" 19852 }, { 19853 "file": "lib/addons/p5.sound.js", 19854 "line": 2718, 19855 "description": "<p>Returns a single Amplitude reading at the moment it is called.\nFor continuous readings, run in the draw loop.</p>\n", 19856 "itemtype": "method", 19857 "name": "getLevel", 19858 "params": [{ 19859 "name": "channel", 19860 "description": "<p>Optionally return only channel 0 (left) or 1 (right)</p>\n", 19861 "type": "Number", 19862 "optional": true 19863 }], 19864 "return": { 19865 "description": "Amplitude as a number between 0.0 and 1.0", 19866 "type": "Number" 19867 }, 19868 "example": ["\n<div><code>\nfunction preload(){\n sound = loadSound('assets/beat.mp3');\n}\nfunction setup() {\n amplitude = new p5.Amplitude();\n sound.play();\n}\nfunction draw() {\n background(0);\n fill(255);\n var level = amplitude.getLevel();\n var size = map(level, 0, 1, 0, 200);\n ellipse(width/2, height/2, size, size);\n}\nfunction mouseClicked(){\n sound.stop();\n}\n</code></div>"], 19869 "class": "p5.Amplitude", 19870 "module": "p5.sound", 19871 "submodule": "p5.sound" 19872 }, { 19873 "file": "lib/addons/p5.sound.js", 19874 "line": 2759, 19875 "description": "<p>Determines whether the results of Amplitude.process() will be\nNormalized. To normalize, Amplitude finds the difference the\nloudest reading it has processed and the maximum amplitude of\n1.0. Amplitude adds this difference to all values to produce\nresults that will reliably map between 0.0 and 1.0. However,\nif a louder moment occurs, the amount that Normalize adds to\nall the values will change. Accepts an optional boolean parameter\n(true or false). Normalizing is off by default.</p>\n", 19876 "itemtype": "method", 19877 "name": "toggleNormalize", 19878 "params": [{ 19879 "name": "boolean", 19880 "description": "<p>set normalize to true (1) or false (0)</p>\n", 19881 "type": "Boolean", 19882 "optional": true 19883 }], 19884 "class": "p5.Amplitude", 19885 "module": "p5.sound", 19886 "submodule": "p5.sound" 19887 }, { 19888 "file": "lib/addons/p5.sound.js", 19889 "line": 2779, 19890 "description": "<p>Smooth Amplitude analysis by averaging with the last analysis\nframe. Off by default.</p>\n", 19891 "itemtype": "method", 19892 "name": "smooth", 19893 "params": [{ 19894 "name": "set", 19895 "description": "<p>smoothing from 0.0 <= 1</p>\n", 19896 "type": "Number" 19897 }], 19898 "class": "p5.Amplitude", 19899 "module": "p5.sound", 19900 "submodule": "p5.sound" 19901 }, { 19902 "file": "lib/addons/p5.sound.js", 19903 "line": 2953, 19904 "description": "<p>Set the input source for the FFT analysis. If no source is\nprovided, FFT will analyze all sound in the sketch.</p>\n", 19905 "itemtype": "method", 19906 "name": "setInput", 19907 "params": [{ 19908 "name": "source", 19909 "description": "<p>p5.sound object (or web audio API source node)</p>\n", 19910 "type": "Object", 19911 "optional": true 19912 }], 19913 "class": "p5.FFT", 19914 "module": "p5.sound", 19915 "submodule": "p5.sound" 19916 }, { 19917 "file": "lib/addons/p5.sound.js", 19918 "line": 2972, 19919 "description": "<p>Returns an array of amplitude values (between -1.0 and +1.0) that represent\na snapshot of amplitude readings in a single buffer. Length will be\nequal to bins (defaults to 1024). Can be used to draw the waveform\nof a sound.</p>\n", 19920 "itemtype": "method", 19921 "name": "waveform", 19922 "params": [{ 19923 "name": "bins", 19924 "description": "<p>Must be a power of two between\n 16 and 1024. Defaults to 1024.</p>\n", 19925 "type": "Number", 19926 "optional": true 19927 }, { 19928 "name": "precision", 19929 "description": "<p>If any value is provided, will return results\n in a Float32 Array which is more precise\n than a regular array.</p>\n", 19930 "type": "String", 19931 "optional": true 19932 }], 19933 "return": { 19934 "description": "Array Array of amplitude values (-1 to 1)\n over time. Array length = bins.", 19935 "type": "Array" 19936 }, 19937 "class": "p5.FFT", 19938 "module": "p5.sound", 19939 "submodule": "p5.sound" 19940 }, { 19941 "file": "lib/addons/p5.sound.js", 19942 "line": 3015, 19943 "description": "<p>Returns an array of amplitude values (between 0 and 255)\nacross the frequency spectrum. Length is equal to FFT bins\n(1024 by default). The array indices correspond to frequencies\n(i.e. pitches), from the lowest to the highest that humans can\nhear. Each value represents amplitude at that slice of the\nfrequency spectrum. Must be called prior to using\n<code>getEnergy()</code>.</p>\n", 19944 "itemtype": "method", 19945 "name": "analyze", 19946 "params": [{ 19947 "name": "bins", 19948 "description": "<p>Must be a power of two between\n 16 and 1024. Defaults to 1024.</p>\n", 19949 "type": "Number", 19950 "optional": true 19951 }, { 19952 "name": "scale", 19953 "description": "<p>If "dB," returns decibel\n float measurements between\n -14
199530 and 0 (max).\n Otherwise returns integers from 0-255.</p>\n", 19954 "type": "Number", 19955 "optional": true 19956 }], 19957 "return": { 19958 "description": "spectrum Array of energy (amplitude/volume)\n values across the frequency spectrum.\n Lowest energy (silence) = 0, highest\n possible is 255.", 19959 "type": "Array" 19960 }, 19961 "example": ["\n<div><code>\nvar osc;\nvar fft;\n\nfunction setup(){\n createCanvas(100,100);\n osc = new p5.Oscillator();\n osc.amp(0);\n osc.start();\n fft = new p5.FFT();\n}\n\nfunction draw(){\n background(0);\n\n var freq = map(mouseX, 0, 800, 20, 15000);\n freq = constrain(freq, 1, 20000);\n osc.freq(freq);\n\n var spectrum = fft.analyze();\n noStroke();\n fill(0,255,0); // spectrum is green\n for (var i = 0; i< spectrum.length; i++){\n var x = map(i, 0, spectrum.length, 0, width);\n var h = -height + map(spectrum[i], 0, 255, height, 0);\n rect(x, height, width / spectrum.length, h );\n }\n\n stroke(255);\n text('Freq: ' + round(freq)+'Hz', 10, 10);\n\n isMouseOverCanvas();\n}\n\n// only play sound when mouse is over canvas\nfunction isMouseOverCanvas() {\n var mX = mouseX, mY = mouseY;\n if (mX > 0 && mX < width && mY < height && mY > 0) {\n osc.amp(0.5, 0.2);\n } else {\n osc.amp(0, 0.2);\n }\n}\n</code></div>\n\n"], 19962 "class": "p5.FFT", 19963 "module": "p5.sound", 19964 "submodule": "p5.sound" 19965 }, { 19966 "file": "lib/addons/p5.sound.js", 19967 "line": 3107, 19968 "description": "<p>Returns the amount of energy (volume) at a specific\n<a href=\"https://en.wikipedia.org/wiki/Audio_frequency\" target=\"_blank\">\nfrequency</a>, or the average amount of energy between two\nfrequencies. Accepts Number(s) corresponding\nto frequency (in Hz), or a String corresponding to predefined\nfrequency ranges ("bass", "lowMid", "mid", "highMid", "treble").\nReturns a range between 0 (no energy/volume at that frequency) and\n255 (maximum energy).\n<em>NOTE: analyze() must be called prior to getEnergy(). Analyze()\ntells the FFT to analyze frequency data, and getEnergy() uses\nthe results determine the value at a specific frequency or\nrange of frequencies.</em></p></p>\n", 19969 "itemtype": "method", 19970 "name": "getEnergy", 19971 "params": [{ 19972 "name": "frequency1", 19973 "description": "<p>Will return a value representing\n energy at this frequency. Alternately,\n the strings "bass", "lowMid" "mid",\n "highMid", and "treble" will return\n predefined frequency ranges.</p>\n", 19974 "type": "Number|String" 19975 }, { 19976 "name": "frequency2", 19977 "description": "<p>If a second frequency is given,\n will return average amount of\n energy that exists between the\n two frequencies.</p>\n", 19978 "type": "Number", 19979 "optional": true 19980 }], 19981 "return": { 19982 "description": "Energy Energy (volume/amplitude) from\n 0 and 255.", 19983 "type": "Number" 19984 }, 19985 "class": "p5.FFT", 19986 "module": "p5.sound", 19987 "submodule": "p5.sound" 19988 }, { 19989 "file": "lib/addons/p5.sound.js", 19990 "line": 3189, 19991 "description": "<p>Returns the\n<a href=\"http://en.wikipedia.org/wiki/Spectral_centroid\" target=\"_blank\">\nspectral centroid</a> of the input signal.\n<em>NOTE: analyze() must be called prior to getCentroid(). Analyze()\ntells the FFT to analyze frequency data, and getCentroid() uses\nthe results determine the spectral centroid.</em></p></p>\n", 19992 "itemtype": "method", 19993 "name": "getCentroid", 19994 "return": { 19995 "description": "Spectral Centroid Frequency Frequency of the spectral centroid in Hz.", 19996 "type": "Number" 19997 }, 19998 "example": ["\n<div><code>\n\n\nfunction setup(){\ncnv = createCanvas(100,100);\nsound = new p5.AudioIn();\nsound.start();\nfft = new p5.FFT();\nsound.connect(fft);\n}\n\n\nfunction draw(){\n\nvar centroidplot = 0.0;\nvar spectralCentroid = 0;\n\n\nbackground(0);\nstroke(0,255,0);\nvar spectrum = fft.analyze();\nfill(0,255,0); // spectrum is green\n\n//draw the spectrum\nfor (var i = 0; i< spectrum.length; i++){\n var x = map(log(i), 0, log(spectrum.length), 0, width);
19998\n var h = map(spectrum[i], 0, 255, 0, height);\n var rectangle_width = (log(i+1)-log(i))*(width/log(spectrum.length));\n rect(x, height, rectangle_width, -h )\n}\n\nvar nyquist = 22050;\n\n// get the centroid\nspectralCentroid = fft.getCentroid();\n\n// the mean_freq_index calculation is for the display.\nvar mean_freq_index = spectralCentroid/(nyquist/spectrum.length);\n\ncentroidplot = map(log(mean_freq_index), 0, log(spectrum.length), 0, width);\n\n\nstroke(255,0,0); // the line showing where the centroid is will be red\n\nrect(centroidplot, 0, width / spectrum.length, height)\nnoStroke();\nfill(255,255,255); // text is white\ntext(\"centroid: \", 10, 20);\ntext(round(spectralCentroid)+\" Hz\", 10, 40);\n}\n </code></div>"], 19999 "class": "p5.FFT", 20000 "module": "p5.sound", 20001 "submodule": "p5.sound" 20002 }, { 20003 "file": "lib/addons/p5.sound.js", 20004 "line": 3269, 20005 "description": "<p>Smooth FFT analysis by averaging with the last analysis frame.</p>\n", 20006 "itemtype": "method", 20007 "name": "smooth", 20008 "params": [{ 20009 "name": "smoothing", 20010 "description": "<p>0.0 < smoothing < 1.0.\n Defaults to 0.8.</p>\n", 20011 "type": "Number" 20012 }], 20013 "class": "p5.FFT", 20014 "module": "p5.sound", 20015 "submodule": "p5.sound" 20016 }, { 20017 "file": "lib/addons/p5.sound.js", 20018 "line": 3291, 20019 "description": "<p>Returns an array of average amplitude values for a given number\nof frequency bands split equally. N defaults to 16.\n<em>NOTE: analyze() must be called prior to linAverages(). Analyze()\ntells the FFT to analyze frequency data, and linAverages() uses\nthe results to group them into a smaller set of averages.</em></p></p>\n", 20020 "itemtype": "method", 20021 "name": "linAverages", 20022 "params": [{ 20023 "name": "N", 20024 "description": "<p>Number of returned frequency groups</p>\n", 20025 "type": "Number" 20026 }], 20027 "return": { 20028 "description": "linearAverages Array of average amplitude values for each group", 20029 "type": "Array" 20030 }, 20031 "class": "p5.FFT", 20032 "module": "p5.sound", 20033 "submodule": "p5.sound" 20034 }, { 20035 "file": "lib/addons/p5.sound.js", 20036 "line": 3321, 20037 "description": "<p>Returns an array of average amplitude values of the spectrum, for a given\nset of <a href=\"https://en.wikipedia.org/wiki/Octave_band\" target=\"_blank\">\nOctave Bands</a>\n<em>NOTE: analyze() must be called prior to logAverages(). Analyze()\ntells the FFT to analyze frequency data, and logAverages() uses\nthe results to group them into a smaller set of averages.</em></p></p>\n", 20038 "itemtype": "method", 20039 "name": "logAverages", 20040 "params": [{ 20041 "name": "octaveBands", 20042 "description": "<p>Array of Octave Bands objects for grouping</p>\n", 20043 "type": "Array" 20044 }], 20045 "return": { 20046 "description": "logAverages Array of average amplitude values for each group", 20047 "type": "Array" 20048 }, 20049 "class": "p5.FFT", 20050 "module": "p5.sound", 20051 "submodule": "p5.sound" 20052 }, { 20053 "file": "lib/addons/p5.sound.js", 20054 "line": 3351, 20055 "description": "<p>Calculates and Returns the 1/N\n<a href=\"https://en.wikipedia.org/wiki/Octave_band\" target=\"_blank\">Octave Bands</a>\nN defaults to 3 and minimum central frequency to 15.625Hz.\n(1/3 Octave Bands ~= 31 Frequency Bands)\nSetting fCtr0 to a central value of a higher octave will ignore the lower bands\nand produce less frequency groups.</p>\n", 20056 "itemtype": "method", 20057 "name": "getOctaveBands", 20058 "params": [{ 20059 "name": "N", 20060 "description": "<p>Specifies the 1/N type of generated octave bands</p>\n", 20061 "type": "Number" 20062 }, { 20063 "name": "fCtr0", 20064 "description": "<p>Minimum central frequency for the lowest band</p>\n", 20065 "type": "Number" 20066 }], 20067 "return": { 20068 "description": "octaveBands Array of octave band objects with their bounds", 20069 "type": "Array" 20070 }, 20071 "class": "p5.FFT", 20072 "module": "p5.sound", 20073 "submodule": "p5.sound" 20074 }, { 20075 "file": "lib/addons/p5.sound.js", 20076 "line": 3409, 20077 "class": "p5.FFT", 20078 "module": "p5.sound", 20079 "submodule": "p5.sound" 20080 }, { 20081 "file": "lib/addons/p5.sound.js", 20082 "line": 3786, 20083 "class": "p5.FFT", 20084 "module": "p5.sound", 20085 "submodule": "p5.sound" 20086 }, { 20087 "file": "lib/addons/p5.sound.js", 20088 "line": 3807, 20089 "class": "p5.FFT", 20090 "module": "p5.sound", 20091 "submodule": "p5.sound" 20092 }, { 20093 "file": "lib/addons/p5.sound.js", 20094 "line": 3866, 20095 "class": "p5.FFT", 20096 "module": "p5.sound", 20097 "submodule": "p5.sound" 20098 }, { 20099 "file": "lib/addons/p5.sound.js", 20100 "line": 4184, 20101 "class": "p5.FFT", 20102 "module": "p5.sound", 20103 "submodule": "p5.sound" 20104 }, { 20105 "file": "lib/addons/p5.sound.js", 20106 "line": 4356, 20107 "class": "p5.FFT", 20108 "module": "p5.sound", 20109 "submodule": "p5.sound" 20110 }, { 20111 "file": "lib/addons/p5.sound.js", 20112 "line": 4514, 20113 "class": "p5.FFT", 20114 "module": "p5.sound", 20115 "submodule": "p5.sound" 20116 }, { 20117 "file": "lib/addons/p5.sound.js", 20118 "line": 4555, 20119 "class": "p5.FFT", 20120 "module": "p5.sound", 20121 "submodule": "p5.sound" 20122 }, { 20123 "file": "lib/addons/p5.sound.js", 20124 "line": 4625, 20125 "class": "p5.FFT", 20126 "module": "p5.sound", 20127 "submodule": "p5.sound" 20128 }, { 20129 "file": "lib/addons/p5.sound.js", 20130 "line": 4813, 20131 "class": "p5.FFT", 20132 "module": "p5.sound", 20133 "submodule": "p5.sound" 20134 }, { 20135 "file": "lib/addons/p5.sound.js", 20136 "line": 4870,
20137 "class": "p5.FFT", 20138 "module": "p5.sound", 20139 "submodule": "p5.sound" 20140 }, { 20141 "file": "lib/addons/p5.sound.js", 20142 "line": 5038, 20143 "class": "p5.FFT", 20144 "module": "p5.sound", 20145 "submodule": "p5.sound" 20146 }, { 20147 "file": "lib/addons/p5.sound.js", 20148 "line": 5086, 20149 "class": "p5.FFT", 20150 "module": "p5.sound", 20151 "submodule": "p5.sound" 20152 }, { 20153 "file": "lib/addons/p5.sound.js", 20154 "line": 5117, 20155 "class": "p5.FFT", 20156 "module": "p5.sound", 20157 "submodule": "p5.sound" 20158 }, { 20159 "file": "lib/addons/p5.sound.js", 20160 "line": 5138, 20161 "class": "p5.FFT", 20162 "module": "p5.sound", 20163 "submodule": "p5.sound" 20164 }, { 20165 "file": "lib/addons/p5.sound.js", 20166 "line": 5158, 20167 "class": "p5.FFT", 20168 "module": "p5.sound", 20169 "submodule": "p5.sound" 20170 }, { 20171 "file": "lib/addons/p5.sound.js", 20172 "line": 5260, 20173 "description": "<p>Fade to value, for smooth transitions</p>\n", 20174 "itemtype": "method", 20175 "name": "fade", 20176 "params": [{ 20177 "name": "value", 20178 "description": "<p>Value to set this signal</p>\n", 20179 "type": "Number" 20180 }, { 20181 "name": "secondsFromNow", 20182 "description": "<p>Length of fade, in seconds from now</p>\n", 20183 "type": "Number", 20184 "optional": true 20185 }], 20186 "class": "p5.Signal", 20187 "module": "p5.sound", 20188 "submodule": "p5.sound" 20189 }, { 20190 "file": "lib/addons/p5.sound.js", 20191 "line": 5271, 20192 "description": "<p>Connect a p5.sound object or Web Audio node to this\np5.Signal so that its amplitude values can be scaled.</p>\n", 20193 "itemtype": "method", 20194 "name": "setInput", 20195 "params": [{ 20196 "name": "input", 20197 "description": "", 20198 "type": "Object" 20199 }], 20200 "class": "p5.Signal", 20201 "module": "p5.sound", 20202 "submodule": "p5.sound" 20203 }, { 20204 "file": "lib/addons/p5.sound.js", 20205 "line": 5285, 20206 "description": "<p>Add a constant value to this audio signal,\nand return the resulting audio signal. Does\nnot change the value of the original signal,\ninstead it returns a new p5.SignalAdd.</p>\n", 20207 "itemtype": "method", 20208 "name": "add", 20209 "params": [{ 20210 "name": "number", 20211 "description": "", 20212 "type": "Number" 20213 }], 20214 "return": { 20215 "description": "object", 20216 "type": "p5.Signal" 20217 }, 20218 "class": "p5.Signal", 20219 "module": "p5.sound", 20220 "submodule": "p5.sound" 20221 }, { 20222 "file": "lib/addons/p5.sound.js", 20223 "line": 5304, 20224 "description": "<p>Multiply this signal by a constant value,\nand return the resulting audio signal. Does\nnot change the value of the original signal,\ninstead it returns a new p5.SignalMult.</p>\n", 20225 "itemtype": "method", 20226 "name": "mult", 20227 "params": [{ 20228 "name": "number", 20229 "description": "<p>to multiply</p>\n", 20230 "type": "Number" 20231 }], 20232 "return": { 20233 "description": "object", 20234 "type": "p5.Signal" 20235 }, 20236 "class": "p5.Signal", 20237 "module": "p5.sound", 20238 "submodule": "p5.sound" 20239 }, { 20240 "file": "lib/addons/p5.sound.js", 20241 "line": 5323, 20242 "description": "<p>Scale this signal value to a given range,\nand return the result as an audio signal. Does\nnot change the value of the original signal,\ninstead it returns a new p5.SignalScale.</p>\n", 20243 "itemtype": "method", 20244 "name": "scale", 20245 "params": [{ 20246 "name": "number", 20247 "description": "<p>to multiply</p>\n", 20248 "type": "Number" 20249 }, { 20250 "name": "inMin", 20251 "description": "<p>input range minumum</p>\n", 20252 "type": "Number" 20253 }, { 20254 "name": "inMax", 20255 "description": "<p>input range maximum</p>\n", 20256 "type": "Number" 20257 }, { 20258 "name": "outMin", 20259 "description": "<p>input range minumum</p>\n", 20260 "type": "Number" 20261 }, { 20262 "name": "outMax", 20263 "description": "<p>input range maximum</p>\n", 20264 "type": "Number" 20265 }], 20266 "return": { 20267 "description": "object", 20268 "type": "p5.Signal" 20269 }, 20270 "class": "p5.Signal", 20271 "module": "p5.sound", 20272 "submodule": "p5.sound" 20273 }, { 20274 "file": "lib/addons/p5.sound.js", 20275 "line": 5457, 20276 "description": "<p>Start an oscillator. Accepts an optional parameter to\ndetermine how long (in seconds from now) until the\noscillator starts.</p>\n", 20277 "itemtype": "method", 20278 "name": "start", 20279 "params": [{ 20280 "name": "time", 20281 "description": "<p>startTime in seconds from now.</p>\n", 20282 "type": "Number", 20283 "optional": true 20284 }, { 20285 "name": "frequency", 20286 "description": "<p>frequency in Hz.</p>\n", 20287 "type": "Number", 20288 "optional": true 20289 }], 20290 "class": "p5.Oscillator", 20291 "module": "p5.sound", 20292 "submodule": "p5.sound" 20293 }, { 20294 "file": "lib/addons/p5.sound.js", 20295 "line": 5497, 20296 "description": "<p>Stop an oscillator. Accepts an optional parameter\nto determine how long (in seconds from now) until the\noscillator stops.</p>\n", 20297 "itemtype": "method", 20298 "name": "stop", 20299 "params": [{ 20300 "name": "secondsFromNow", 20301 "description": "<p>Time, in seconds from now.</p>\n", 20302 "type": "Number" 20303 }], 20304 "class": "p5.Oscillator", 20305 "module": "p5.sound", 20306 "submodule": "p5.sound" 20307 }, { 20308 "file": "lib/addons/p5.sound.js", 20309 "line": 5513, 20310 "description": "<p>Set the amplitude between 0 and 1.0. Or, pass in an object\nsuch as an oscillator to modulate amplitude with an audio signal.</p>\n", 20311 "itemtype": "method", 20312 "name": "amp", 20313 "params": [{ 20314 "name": "vol", 20315 "description": "<p>between 0 and 1.0\n or a modulating signal/oscillator</p>\n", 20316 "type": "Number|Object" 20317 }, { 20318 "name": "rampTime", 20319 "description": "<p>create a fade that lasts rampTime</p>\n", 20320 "type": "Number", 20321 "optional": true 20322 }, { 20323 "name": "timeFromNow", 20324 "description": "<p>schedule this event to happen\n seconds from now</p>\n", 20325 "type": "Number", 20326 "optional": true 20327 }], 20328 "return": { 20329 "description": "gain If no value is provided,\n returns the Web Audio API\n AudioParam that c
20329ontrols\n this oscillator's\n gain/amplitude/volume)", 20330 "type": "AudioParam" 20331 }, 20332 "class": "p5.Oscillator", 20333 "module": "p5.sound", 20334 "submodule": "p5.sound" 20335 }, { 20336 "file": "lib/addons/p5.sound.js", 20337 "line": 5548, 20338 "description": "<p>Set frequency of an oscillator to a value. Or, pass in an object\nsuch as an oscillator to modulate the frequency with an audio signal.</p>\n", 20339 "itemtype": "method", 20340 "name": "freq", 20341 "params": [{ 20342 "name": "Frequency", 20343 "description": "<p>Frequency in Hz\n or modulating signal/oscillator</p>\n", 20344 "type": "Number|Object" 20345 }, { 20346 "name": "rampTime", 20347 "description": "<p>Ramp time (in seconds)</p>\n", 20348 "type": "Number", 20349 "optional": true 20350 }, { 20351 "name": "timeFromNow", 20352 "description": "<p>Schedule this event to happen\n at x seconds from now</p>\n", 20353 "type": "Number", 20354 "optional": true 20355 }], 20356 "return": { 20357 "description": "Frequency If no value is provided,\n returns the Web Audio API\n AudioParam that controls\n this oscillator's frequency", 20358 "type": "AudioParam" 20359 }, 20360 "example": ["\n<div><code>\nvar osc = new p5.Oscillator(300);\nosc.start();\nosc.freq(40, 10);\n</code></div>"], 20361 "class": "p5.Oscillator", 20362 "module": "p5.sound", 20363 "submodule": "p5.sound" 20364 }, { 20365 "file": "lib/addons/p5.sound.js", 20366 "line": 5607, 20367 "description": "<p>Set type to 'sine', 'triangle', 'sawtooth' or 'square'.</p>\n", 20368 "itemtype": "method", 20369 "name": "setType", 20370 "params": [{ 20371 "name": "type", 20372 "description": "<p>'sine', 'triangle', 'sawtooth' or 'square'.</p>\n", 20373 "type": "String" 20374 }], 20375 "class": "p5.Oscillator", 20376 "module": "p5.sound", 20377 "submodule": "p5.sound" 20378 }, { 20379 "file": "lib/addons/p5.sound.js", 20380 "line": 5619, 20381 "description": "<p>Connect to a p5.sound / Web Audio object.</p>\n", 20382 "itemtype": "method", 20383 "name": "connect", 20384 "params": [{ 20385 "name": "unit", 20386 "description": "<p>A p5.sound or Web Audio object</p>\n", 20387 "type": "Object" 20388 }], 20389 "class": "p5.Oscillator", 20390 "module": "p5.sound", 20391 "submodule": "p5.sound" 20392 }, { 20393 "file": "lib/addons/p5.sound.js", 20394 "line": 5636, 20395 "description": "<p>Disconnect all outputs</p>\n", 20396 "itemtype": "method", 20397 "name": "disconnect", 20398 "class": "p5.Oscillator", 20399 "module": "p5.sound", 20400 "submodule": "p5.sound" 20401 }, { 20402 "file": "lib/addons/p5.sound.js", 20403 "line": 5653, 20404 "description": "<p>Pan between Left (-1) and Right (1)</p>\n", 20405 "itemtype": "method", 20406 "name": "pan", 20407 "params": [{ 20408 "name": "panning", 20409 "description": "<p>Number between -1 and 1</p>\n", 20410 "type": "Number" 20411 }, { 20412 "name": "timeFromNow", 20413 "description": "<p>schedule this event to happen\n seconds from now</p>\n", 20414 "type": "Number" 20415 }], 20416 "class": "p5.Oscillator", 20417 "module": "p5.sound", 20418 "submodule": "p5.sound" 20419 }, { 20420 "file": "lib/addons/p5.sound.js", 20421 "line": 5685, 20422 "description": "<p>Set the phase of an oscillator between 0.0 and 1.0.\nIn this implementation, phase is a delay time\nbased on the oscillator's current frequency.</p>\n", 20423 "itemtype": "method", 20424 "name": "phase", 20425 "params": [{ 20426 "name": "phase", 20427 "description": "<p>float between 0.0 and 1.0</p>\n", 20428 "type": "Number" 20429 }], 20430 "class": "p5.Oscillator", 20431 "module": "p5.sound", 20432 "submodule": "p5.sound" 20433 }, { 20434 "file": "lib/addons/p5.sound.js", 20435 "line": 5739, 20436 "description": "<p>Add a value to the p5.Oscillator's output amplitude,\nand return the oscillator. Calling this method again\nwill override the initial add() with a new value.</p>\n", 20437 "itemtype": "method", 20438 "name": "add", 20439 "params": [{ 20440 "name": "number", 20441 "description": "<p>Constant number to add</p>\n", 20442 "type": "Number" 20443 }], 20444 "return": { 20445 "description": "Oscillator Returns this oscillator\n with scaled output", 20446 "type": "p5.Oscillator" 20447 }, 20448 "class": "p5.Oscillator", 20449 "module": "p5.sound", 20450 "submodule": "p5.sound" 20451 }, { 20452 "file": "lib/addons/p5.sound.js", 20453 "line": 5756, 20454 "description": "<p>Multiply the p5.Oscillator's output amplitude\nby a fixed value (i.e. turn it up!). Calling this method\nagain will override the initial mult() with a new value.</p>\n", 20455 "itemtype": "method", 20456 "name": "mult", 20457 "params": [{ 20458 "name": "number", 20459 "description": "<p>Constant number to multiply</p>\n", 20460 "type": "Number" 20461 }], 20462 "return": { 20463 "description": "Oscillator Returns this oscillator\n with multiplied output", 20464 "type": "p5.Oscillator" 20465 }, 20466 "class": "p5.Oscillator", 20467 "module": "p5.sound", 20468 "submodule": "p5.sound" 20469 }, { 20470 "file": "lib/addons/p5.sound.js", 20471 "line": 5772, 20472 "description": "<p>Scale this oscillator's amplitude values to a given\nrange, and return the oscillator. Calling this method\nagain will override the initial scale() with new values.</p>\n", 20473 "itemtype": "method", 20474 "name": "scale", 20475 "params": [{ 20476 "name": "inMin", 20477 "description": "<p>input range minumum</p>\n", 20478 "type": "Number" 20479 }, { 20480 "name": "inMax", 20481 "description": "<p>input range maximum</p>\n", 20482 "type": "Number" 20483 }, { 20484 "name": "outMin", 20485 "description": "<p>input range minumum</p>\n", 20486 "type": "Number" 20487 }, { 20488 "name": "outMax", 20489 "description": "<p>input range maximum</p>\n", 20490 "type": "Number" 20491 }], 20492 "return": { 20493 "description": "Oscillator Returns this oscillator\n with scaled output", 20494 "type": "p5.Oscillator" 20495 }, 20496 "class": "p5.Oscillator", 20497 "module": "p5.sound", 20498 "submodule": "p5.sound" 20499 }, { 20500 "file": "lib/addons/p5.sound.js", 20501 "line": 5871, 20502 "class": "p5.SqrOsc", 20503 "module": "p5.sound", 20504 "submodule": "p5.sound" 20505 }, { 20506 "file": "lib/addons/p5.sound.js", 20507 "line": 6074, 20508 "class": "p5.SqrOsc", 20509 "module": "p5.sound", 20510 "submodule": "p5.sound" 20511 }, { 20512 "file": "lib/addons/p5.sound.js", 20513 "line": 6363, 20514 "description": "<p>Time until envelope reaches attackLevel</p>\n", 20515 "itemtype": "property", 20516 "name": "attackTime", 20517 "class": "p5.Envelope", 20518 "module": "p5.sound", 20519 "submodule": "p5.sound" 20520 }, { 20521 "file": "lib/addons/p5.sound.js", 20522 "line": 6368, 20523 "description": "<p>Level once attack is complete.</p>\n", 20524 "itemtype": "property", 20525 "name": "attackLevel", 20526 "class": "p5.Envelope", 20527 "module": "p5.sound", 20528 "submodule": "p5.sound" 20529 }, { 20530 "file": "lib/addons/p5.sound.js", 20531 "line": 6373, 20532 "description": "<p>Time until envelope reaches decayLevel.</p>\n", 20533 "itemtype": "property", 20534 "name": "decayTime", 20535 "class": "p5.Envelope", 20536 "module": "p5.sound", 20537 "submodule": "p5.sound" 20538 }, { 20539 "file": "lib/addons/p5.sound.js", 20540 "line": 6378, 20541 "description": "<p>Level after decay. The envelope will sustain here until it is released.</p>\n", 20542 "itemtype": "property", 20543 "name": "decayLevel", 20544 "class": "p5.Envelope", 20545 "module": "p5.sound", 20546 "submodule": "p5.sound" 20547 }, { 20548 "file": "lib/addons/p5.sound.js", 20549 "line": 6383, 20550 "description": "<p>Duration of the release portion of the envelope.</p>\n", 20551 "itemtype": "property", 20552 "name": "releaseTime", 20553 "class": "p5.Envelope", 20554 "module": "p5.sound", 20555 "submodule": "p5.sound" 20556 }, { 20557 "file": "lib/addons/p5.sound.js", 20558 "line": 6388, 20559 "description": "<p>Level at the end of the release.</p>\n", 20560 "itemtype": "property", 20561 "name": "releaseLevel", 20562 "class": "p5.Envelope", 20563 "module": "p5.sound", 20564 "submodule": "p5.sound" 20565 }, { 20566 "file": "lib/addons/p5.sound.js", 20567 "line": 6424, 20568 "description": "<p>Reset the envelope with a series of time/value pairs.</p>\n", 20569 "itemtype": "method", 20570 "name": "set", 20571 "params": [{ 20572 "name": "attackTime", 20573 "description": "<p>Time (in seconds) before level\n reaches attackLevel</p>\n", 20574 "type": "Number" 20575 }, { 20576 "name": "attackLevel", 20577 "description": "<p>Typically an amplitude between\n 0.0 and 1.0</p>\n", 20578 "type": "Number" 20579 }, { 20580 "name": "decayTime", 20581 "description": "<p>Time</p>\n", 20582 "type": "Number" 20583 }, { 20584 "name": "decayLevel", 20585 "description": "<p>Amplitude (In a standard ADSR envelope,\n decayLevel = sustainLevel)</p>\n", 20586 "type": "Number" 20587 }, { 20588 "name": "releaseTime", 20589 "description": "<p>Release Time (in seconds)</p>\n", 20590 "type": "Number" 20591 }, { 20592 "name": "releaseLevel", 20593 "description": "<p>Amplitude</p>\n", 20594 "type": "Number" 20595 }], 20596 "example": ["\n<div><code>\nvar t1 = 0.1;
20596 // attack time in seconds\nvar l1 = 0.7; // attack level 0.0 to 1.0\nvar t2 = 0.3; // decay time in seconds\nvar l2 = 0.1; // decay level 0.0 to 1.0\nvar t3 = 0.2; // sustain time in seconds\nvar l3 = 0.5; // sustain level 0.0 to 1.0\n// release level defaults to zero\n\nvar env;\nvar triOsc;\n\nfunction setup() {\n background(0);\n noStroke();\n fill(255);\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n\n env = new p5.Envelope(t1, l1, t2, l2, t3, l3);\n triOsc = new p5.Oscillator('triangle');\n triOsc.amp(env); // give the env control of the triOsc's amp\n triOsc.start();\n}\n\n// mouseClick triggers envelope if over canvas\nfunction mouseClicked() {\n // is mouse over canvas?\n if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {\n env.play(triOsc);\n }\n}\n</code></div>\n"], 20597 "class": "p5.Envelope", 20598 "module": "p5.sound", 20599 "submodule": "p5.sound" 20600 }, { 20601 "file": "lib/addons/p5.sound.js", 20602 "line": 6483, 20603 "description": "<p>Set values like a traditional\n<a href=\"https://en.wikipedia.org/wiki/Synthesizer#/media/File:ADSR_parameter.svg\">\nADSR envelope\n</a>.</p>\n", 20604 "itemtype": "method", 20605 "name": "setADSR", 20606 "params": [{ 20607 "name": "attackTime", 20608 "description": "<p>Time (in seconds before envelope\n reaches Attack Level</p>\n", 20609 "type": "Number" 20610 }, { 20611 "name": "decayTime", 20612 "description": "<p>Time (in seconds) before envelope\n reaches Decay/Sustain Level</p>\n", 20613 "type": "Number", 20614 "optional": true 20615 }, { 20616 "name": "susRatio", 20617 "description": "<p>Ratio between attackLevel and releaseLevel, on a scale from 0 to 1,\n where 1.0 = attackLevel, 0.0 = releaseLevel.\n The susRatio determines the decayLevel and the level at which the\n sustain portion of the envelope will sustain.\n For example, if attackLevel is 0.4, releaseLevel is 0,\n and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is\n increased to 1.0 (using <code>setRange</code>),\n then decayLevel would increase proportionally, to become 0.5.</p>\n", 20618 "type": "Number", 20619 "optional": true 20620 }, { 20621 "name": "releaseTime", 20622 "description": "<p>Time in seconds from now (defaults to 0)</p>\n", 20623 "type": "Number", 20624 "optional": true 20625 }], 20626 "example": ["\n<div><code>\nvar attackLevel = 1.0;\nvar releaseLevel = 0;\n\nvar attackTime = 0.001;\nvar decayTime = 0.2;\nvar susPercent = 0.2;\nvar releaseTime = 0.5;\n\nvar env, triOsc;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n\n env = new p5.Envelope();\n env.setADSR(attackTime, decayTime, susPercent, releaseTime);\n env.setRange(attackLevel, releaseLevel);\n\n triOsc = new p5.Oscillator('triangle');\n triOsc.amp(env);\n triOsc.start();\n triOsc.freq(220);\n\n cnv.mousePressed(playEnv);\n}\n\nfunction playEnv() {\n env.play();\n}\n</code></div>"], 20627 "class": "p5.Envelope", 20628 "module": "p5.sound", 20629 "submodule": "p5.sound" 20630 }, { 20631 "file": "lib/addons/p5.sound.js", 20632 "line": 6548, 20633 "description": "<p>Set max (attackLevel) and min (releaseLevel) of envelope.</p>\n", 20634 "itemtype": "method", 20635 "name": "setRange", 20636 "params": [{ 20637 "name": "aLevel", 20638 "description": "<p>attack level (defaults to 1)</p>\n", 20639 "type": "Number" 20640 }, { 20641 "name": "rLevel", 20642 "description": "<p>release level (defaults to 0)</p>\n", 20643 "type": "Number" 20644 }], 20645 "example": ["\n<div><code>\nvar attackLevel = 1.0;\nvar releaseLevel = 0;\n\nvar attackTime = 0.001;\nvar decayTime = 0.2;\nvar susPercent = 0.2;\nvar releaseTime = 0.5;\n\nvar env, triOsc;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n\n env = new p5.Envelope();\n env.setADSR(attackTime, decayTime, susPercent, releaseTime);\n env.setRange(attackLevel, releaseLevel);\n\n triOsc = new p5.Oscillator('triangle');\n triOsc.amp(env);\n triOsc.start();\n triOsc.freq(220);\n\n cnv.mousePressed(playEnv);\n}\n\nfunction playEnv() {\n env.play();\n}\n</code></div>"], 20646 "class": "p5.Envelope", 20647 "module": "p5.sound", 20648 "submodule": "p5.sound" 20649 }, { 20650 "file": "lib/addons/p5.sound.js", 20651 "line": 6627, 20652 "description": "<p>Assign a parameter to be controlled by this envelope.\nIf a p5.Sound object is given, then the p5.Envelope will c
20652ontrol its\noutput gain. If multiple inputs are provided, the env will\ncontrol all of them.</p>\n", 20653 "itemtype": "method", 20654 "name": "setInput", 20655 "params": [{ 20656 "name": "inputs", 20657 "description": "<p>A p5.sound object or\n Web Audio Param.</p>\n", 20658 "type": "Object", 20659 "optional": true, 20660 "multiple": true 20661 }], 20662 "class": "p5.Envelope", 20663 "module": "p5.sound", 20664 "submodule": "p5.sound" 20665 }, { 20666 "file": "lib/addons/p5.sound.js", 20667 "line": 6642, 20668 "description": "<p>Set whether the envelope ramp is linear (default) or exponential.\nExponential ramps can be useful because we perceive amplitude\nand frequency logarithmically.</p>\n", 20669 "itemtype": "method", 20670 "name": "setExp", 20671 "params": [{ 20672 "name": "isExp", 20673 "description": "<p>true is exponential, false is linear</p>\n", 20674 "type": "Boolean" 20675 }], 20676 "class": "p5.Envelope", 20677 "module": "p5.sound", 20678 "submodule": "p5.sound" 20679 }, { 20680 "file": "lib/addons/p5.sound.js", 20681 "line": 6660, 20682 "description": "<p>Play tells the envelope to start acting on a given input.\nIf the input is a p5.sound object (i.e. AudioIn, Oscillator,\nSoundFile), then Envelope will control its output volume.\nEnvelopes can also be used to control any <a href=\"\nhttp://docs.webplatform.org/wiki/apis/webaudio/AudioParam\">\nWeb Audio Audio Param.</a></p>\n", 20683 "itemtype": "method", 20684 "name": "play", 20685 "params": [{ 20686 "name": "unit", 20687 "description": "<p>A p5.sound object or\n Web Audio Param.</p>\n", 20688 "type": "Object" 20689 }, { 20690 "name": "startTime", 20691 "description": "<p>time from now (in seconds) at which to play</p>\n", 20692 "type": "Number", 20693 "optional": true 20694 }, { 20695 "name": "sustainTime", 20696 "description": "<p>time to sustain before releasing the envelope</p>\n", 20697 "type": "Number", 20698 "optional": true 20699 }], 20700 "example": ["\n<div><code>\nvar attackLevel = 1.0;\nvar releaseLevel = 0;\n\nvar attackTime = 0.001;\nvar decayTime = 0.2;\nvar susPercent = 0.2;\nvar releaseTime = 0.5;\n\nvar env, triOsc;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n\n env = new p5.Envelope();\n env.setADSR(attackTime, decayTime, susPercent, releaseTime);\n env.setRange(attackLevel, releaseLevel);\n\n triOsc = new p5.Oscillator('triangle');\n triOsc.amp(env);\n triOsc.start();\n triOsc.freq(220);\n\n cnv.mousePressed(playEnv);\n}\n\nfunction playEnv() {\n // trigger env on triOsc, 0 seconds from now\n // After decay, sustain for 0.2 seconds before release\n env.play(triOsc, 0, 0.2);\n}\n</code></div>"], 20701 "class": "p5.Envelope", 20702 "module": "p5.sound", 20703 "submodule": "p5.sound" 20704 }, { 20705 "file": "lib/addons/p5.sound.js", 20706 "line": 6721, 20707 "description": "<p>Trigger the Attack, and Decay portion of the Envelope.\nSimilar to holding down a key on a piano, but it will\nhold the sustain level until you let go. Input can be\nany p5.sound object, or a <a href=\"\nhttp://docs.webplatform.org/wiki/apis/webaudio/AudioParam\">\nWeb Audio Param</a>.</p>\n", 20708 "itemtype": "method", 20709 "name": "triggerAttack", 20710 "params": [{ 20711 "name": "unit", 20712 "description": "<p>p5.sound Object or Web Audio Param</p>\n", 20713 "type": "Object" 20714 }, { 20715 "name": "secondsFromNow", 20716 "description": "<p>time from now (in seconds)</p>\n", 20717 "type": "Number" 20718 }], 20719 "example": ["\n<div><code>\n\nvar attackLevel = 1.0;\nvar releaseLevel = 0;\n\nvar attackTime = 0.001;\nvar decayTime = 0.3;\nvar susPercent = 0.4;\nvar releaseTime = 0.5;\n\nvar env, triOsc;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n background(200);\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n\n env = new p5.Envelope();\n env.setADSR(attackTime, decayTime, susPercent, releaseTime);\n env.setRange(attackLevel, releaseLevel);\n\n triOsc = new p5.Oscillator('triangle');\n triOsc.amp(env);\n triOsc.start();\n triOsc.freq(220);\n\n cnv.mousePressed(envAttack);\n}\n\nfunction envAttack() {\n console.log('trigger attack');\n env.triggerAttack();\n\n background(0,255,0);\n text('attack!', width/2, height/2);\n}\n\nfunction mouseReleased() {\n env.triggerRelease();\n\n background(200);\n text('click to play', width/2, height/2);\n}\n</code></div>"], 20720 "class": "p5.Envelope", 20721 "module": "p5.sound", 20722 "submodule": "p5.sound" 20723 }, { 20724 "file": "lib/addons/p5.sound.js", 20725 "line": 6828, 20726 "description": "<p>Trigger the Release of the Envelope. This is similar to releasing\nthe key on a piano and letting the sound fade according to the\nrelease level and release time.</p>\n", 20727 "itemtype": "method", 20728 "name": "triggerRelease", 20729 "params": [{ 20730 "name": "unit", 20731 "description": "<p>p5.sound Object or Web Audio Param</p>\n", 20732 "type": "Object" 20733 }, { 20734 "name": "secondsFromNow", 20735 "description": "<p>time to trigger the release</p>\n", 20736 "type": "Number" 20737 }], 20738 "example": ["\n<div><code>\n\nvar attackLevel = 1.0;\nvar releaseLevel = 0;\n\nvar attackTime = 0.001;\nvar decayTime = 0.3;\nvar susPercent = 0.4;\nvar releaseTime = 0.5;\n\nvar env, triOsc;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n background(200);\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n\n env = new p5.Envelope();\n env.setADSR(attackTime, decayTime, susPercent, releaseTime);\n env.setRange(attackLevel, releaseLevel);\n\n triOsc = new p5.Oscillator('triangle');\n triOsc.amp(env);\n triOsc.start();\n triOsc.freq(220);\n\n cnv.mousePressed(envAttack);\n}\n\nfunction envAttack() {\n console.log('trigger attack');\n env.triggerAttack();\n\n background(0,255,0);\n text('attack!', width/2, height/2);\n}\n\nfunction mouseReleased() {\n env.triggerRelease();\n\n background(200);\n text('click to play', width/2, height/2);\n}\n</code></div>"], 20739 "class": "p5.Envelope", 20740 "module": "p5.sound", 20741 "submodule": "p5.sound" 20742 }, { 20743 "file": "lib/addons/p5.sound.js", 20744 "line": 6925, 20745 "description": "<p>Exponentially ramp to a value using the first two\nvalues from <code><a href=\"#/p5.Envelope/setADSR\">setADSR(attackTime, decayTime)</a></code>\nas <a href=\"https://en.wikipedia.org/wiki/RC_time_constant\">\ntime constants</a> for simple exponential ramps.\nIf the value is higher than current value, it uses attackTime,\nwhile a decrease uses decayTime.</p>\n", 20746 "itemtype": "method", 20747 "name": "ramp", 20748 "params": [{ 20749 "name": "unit", 20750 "description": "<p>p5.sound Object or Web Audio Param</p>\n", 20751 "type": "Object" 20752 }, { 20753 "name": "secondsFromNow", 20754 "description": "<p>When to trigger the ramp</p>\n", 20755 "type": "Number" 20756 }, { 20757 "name": "v", 20758 "description": "<p>Target value</p>\n", 20759 "type": "Number" 20760 }, { 20761 "name": "v2", 20762 "description": "<p>Second target value (optional)</p>\n", 20763 "type": "Number", 20764 "optional": true 20765 }], 20766 "example": ["\n<div><code>\nvar env, osc, amp, cnv;\n\nvar attackTime = 0.001;\nvar decayTime = 0.2;\nvar attackLevel = 1;\nvar decayLevel = 0;\n\nfunction setup() {\n cnv = createCanvas(100, 100);\n fill(0,255,0);\n noStroke();\n\n env = new p5.Envelope();\n env.setADSR(attackTime, decayTime);\n\n osc = new p5.Oscillator();\n osc.amp(env);\n osc.start();\n\n amp = new p5.Amplitude();\n\n cnv.mousePressed(triggerRamp);\n}\n\nfunction triggerRamp() {\n env.ramp(osc, 0, attackLevel, decayLevel);\n}\n\nfunction draw() {\n background(20,20,20);\n text('click me', 10, 20);
20766\n var h = map(amp.getLevel(), 0, 0.4, 0, height);;\n\n rect(0, height, width, -h);\n}\n</code></div>"], 20767 "class": "p5.Envelope", 20768 "module": "p5.sound", 20769 "submodule": "p5.sound" 20770 }, { 20771 "file": "lib/addons/p5.sound.js", 20772 "line": 7032, 20773 "description": "<p>Add a value to the p5.Oscillator's output amplitude,\nand return the oscillator. Calling this method\nagain will override the initial add() with new values.</p>\n", 20774 "itemtype": "method", 20775 "name": "add", 20776 "params": [{ 20777 "name": "number", 20778 "description": "<p>Constant number to add</p>\n", 20779 "type": "Number" 20780 }], 20781 "return": { 20782 "description": "Envelope Returns this envelope\n with scaled output", 20783 "type": "p5.Envelope" 20784 }, 20785 "class": "p5.Envelope", 20786 "module": "p5.sound", 20787 "submodule": "p5.sound" 20788 }, { 20789 "file": "lib/addons/p5.sound.js", 20790 "line": 7048, 20791 "description": "<p>Multiply the p5.Envelope's output amplitude\nby a fixed value. Calling this method\nagain will override the initial mult() with new values.</p>\n", 20792 "itemtype": "method", 20793 "name": "mult", 20794 "params": [{ 20795 "name": "number", 20796 "description": "<p>Constant number to multiply</p>\n", 20797 "type": "Number" 20798 }], 20799 "return": { 20800 "description": "Envelope Returns this envelope\n with scaled output", 20801 "type": "p5.Envelope" 20802 }, 20803 "class": "p5.Envelope", 20804 "module": "p5.sound", 20805 "submodule": "p5.sound" 20806 }, { 20807 "file": "lib/addons/p5.sound.js", 20808 "line": 7064, 20809 "description": "<p>Scale this envelope's amplitude values to a given\nrange, and return the envelope. Calling this method\nagain will override the initial scale() with new values.</p>\n", 20810 "itemtype": "method", 20811 "name": "scale", 20812 "params": [{ 20813 "name": "inMin", 20814 "description": "<p>input range minumum</p>\n", 20815 "type": "Number" 20816 }, { 20817 "name": "inMax", 20818 "description": "<p>input range maximum</p>\n", 20819 "type": "Number" 20820 }, { 20821 "name": "outMin", 20822 "description": "<p>input range minumum</p>\n", 20823 "type": "Number" 20824 }, { 20825 "name": "outMax", 20826 "description": "<p>input range maximum</p>\n", 20827 "type": "Number" 20828 }], 20829 "return": { 20830 "description": "Envelope Returns this envelope\n with scaled output", 20831 "type": "p5.Envelope" 20832 }, 20833 "class": "p5.Envelope", 20834 "module": "p5.sound", 20835 "submodule": "p5.sound" 20836 }, { 20837 "file": "lib/addons/p5.sound.js", 20838 "line": 7172, 20839 "description": "<p>Set the width of a Pulse object (an oscillator that implements\nPulse Width Modulation).</p>\n", 20840 "itemtype": "method", 20841 "name": "width", 20842 "params": [{ 20843 "name": "width", 20844 "description": "<p>Width between the pulses (0 to 1.0,\n defaults to 0)</p>\n", 20845 "type": "Number", 20846 "optional": true 20847 }], 20848 "class": "p5.Pulse", 20849 "module": "p5.sound", 20850 "submodule": "p5.sound" 20851 }, { 20852 "file": "lib/addons/p5.sound.js", 20853 "line": 7359, 20854 "description": "<p>Set type of noise to 'white', 'pink' or 'brown'.\nWhite is the default.</p>\n", 20855 "itemtype": "method", 20856 "name": "setType", 20857 "params": [{ 20858 "name": "type", 20859 "description": "<p>'white', 'pink' or 'brown'</p>\n", 20860 "type": "String", 20861 "optional": true 20862 }], 20863 "class": "p5.Noise", 20864 "module": "p5.sound", 20865 "submodule": "p5.sound" 20866 }, { 20867 "file": "lib/addons/p5.sound.js", 20868 "line": 7472, 20869 "itemtype": "property", 20870 "name": "input", 20871 "type": "GainNode", 20872 "class": "p5.AudioIn", 20873 "module": "p5.sound", 20874 "submodule": "p5.sound" 20875 }, { 20876 "file": "lib/addons/p5.sound.js", 20877 "line": 7476, 20878 "itemtype": "property", 20879 "name": "output", 20880 "type": "GainNode", 20881 "class": "p5.AudioIn", 20882 "module": "p5.sound", 20883 "submodule": "p5.sound" 20884 }, { 20885 "file": "lib/addons/p5.sound.js", 20886 "line": 7480, 20887 "itemtype": "property", 20888 "name": "stream", 20889 "type": "MediaStream|null", 20890 "class": "p5.AudioIn", 20891 "module": "p5.sound", 20892 "submodule": "p5.sound" 20893 }, { 20894 "file": "lib/addons/p5.sound.js", 20895 "line": 7484, 20896 "itemtype": "property", 20897 "name": "mediaStream", 20898 "type": "MediaStreamAudioSourceNode|null", 20899 "class": "p5.AudioIn", 20900 "module": "p5.sound", 20901 "submodule": "p5.sound" 20902 }, { 20903 "file": "lib/addons/p5.sound.js", 20904 "line": 7488, 20905 "itemtype": "property", 20906 "name": "currentSource", 20907 "type": "Number|null", 20908 "class": "p5.AudioIn", 20909 "module": "p5.sound", 20910 "submodule": "p5.sound" 20911 }, { 20912 "file": "lib/addons/p5.sound.js", 20913 "line": 7492, 20914 "description": "<p>Client must allow browser to access their microphone / audioin source.\nDefault: false. Will become true when the client enables acces.</p>\n", 20915 "itemtype": "property", 20916 "name": "enabled", 20917 "type": "Boolean", 20918 "class": "p5.AudioIn", 20919 "module": "p5.sound", 20920 "submodule": "p5.sound" 20921 }, { 20922 "file": "lib/addons/p5.sound.js", 20923 "line": 7499, 20924 "description": "<p>Input amplitude, connect to it by default but not to master out</p>\n", 20925 "itemtype": "property", 20926 "name": "amplitude", 20927 "type": "p5.Amplitude", 20928 "class": "p5.AudioIn", 20929 "module": "p5.sound", 20930 "submodule": "p5.sound" 20931 }, { 20932 "file": "lib/addons/p5.sound.js", 20933 "line": 7512, 20934 "description": "<p>Start processing audio input. This enables the use of other\nAudioIn methods like getLevel(). Note that by default, AudioIn\nis not connected to p5.sound's output. So you won't hear\nanything unless you use the connect() method.<br/></p>\n<p>Certain browsers limit access to the user's microphone. For example,\nChrome only allows access from localhost and over https. For this reason,\nyou may want to include an errorCallbackâa function that is called
20934in case\nthe browser won't provide mic access.</p>\n", 20935 "itemtype": "method", 20936 "name": "start", 20937 "params": [{ 20938 "name": "successCallback", 20939 "description": "<p>Name of a function to call on\n success.</p>\n", 20940 "type": "Function", 20941 "optional": true 20942 }, { 20943 "name": "errorCallback", 20944 "description": "<p>Name of a function to call if\n there was an error. For example,\n some browsers do not support\n getUserMedia.</p>\n", 20945 "type": "Function", 20946 "optional": true 20947 }], 20948 "class": "p5.AudioIn", 20949 "module": "p5.sound", 20950 "submodule": "p5.sound" 20951 }, { 20952 "file": "lib/addons/p5.sound.js", 20953 "line": 7565, 20954 "description": "<p>Turn the AudioIn off. If the AudioIn is stopped, it cannot getLevel().\nIf re-starting, the user may be prompted for permission access.</p>\n", 20955 "itemtype": "method", 20956 "name": "stop", 20957 "class": "p5.AudioIn", 20958 "module": "p5.sound", 20959 "submodule": "p5.sound" 20960 }, { 20961 "file": "lib/addons/p5.sound.js", 20962 "line": 7581, 20963 "description": "<p>Connect to an audio unit. If no parameter is provided, will\nconnect to the master output (i.e. your speakers).<br/></p>\n", 20964 "itemtype": "method", 20965 "name": "connect", 20966 "params": [{ 20967 "name": "unit", 20968 "description": "<p>An object that accepts audio input,\n such as an FFT</p>\n", 20969 "type": "Object", 20970 "optional": true 20971 }], 20972 "class": "p5.AudioIn", 20973 "module": "p5.sound", 20974 "submodule": "p5.sound" 20975 }, { 20976 "file": "lib/addons/p5.sound.js", 20977 "line": 7602, 20978 "description": "<p>Disconnect the AudioIn from all audio units. For example, if\nconnect() had been called, disconnect() will stop sending\nsignal to your speakers.<br/></p>\n", 20979 "itemtype": "method", 20980 "name": "disconnect", 20981 "class": "p5.AudioIn", 20982 "module": "p5.sound", 20983 "submodule": "p5.sound" 20984 }, { 20985 "file": "lib/addons/p5.sound.js", 20986 "line": 7616, 20987 "description": "<p>Read the Amplitude (volume level) of an AudioIn. The AudioIn\nclass contains its own instance of the Amplitude class to help\nmake it easy to get a microphone's volume level. Accepts an\noptional smoothing value (0.0 < 1.0). <em>NOTE: AudioIn must\n.start() before using .getLevel().</em><br/></p>\n", 20988 "itemtype": "method", 20989 "name": "getLevel", 20990 "params": [{ 20991 "name": "smoothing", 20992 "description": "<p>Smoothing is 0.0 by default.\n Smooths values based on previous values.</p>\n", 20993 "type": "Number", 20994 "optional": true 20995 }], 20996 "return": { 20997 "description": "Volume level (between 0.0 and 1.0)", 20998 "type": "Number" 20999 }, 21000 "class": "p5.AudioIn", 21001 "module": "p5.sound", 21002 "submodule": "p5.sound" 21003 }, { 21004 "file": "lib/addons/p5.sound.js", 21005 "line": 7634, 21006 "description": "<p>Set amplitude (volume) of a mic input between 0 and 1.0. <br/></p>\n", 21007 "itemtype": "method", 21008 "name": "amp", 21009 "params": [{ 21010 "name": "vol", 21011 "description": "<p>between 0 and 1.0</p>\n", 21012 "type": "Number" 21013 }, { 21014 "name": "time", 21015 "description": "<p>ramp time (optional)</p>\n", 21016 "type": "Number", 21017 "optional": true 21018 }], 21019 "class": "p5.AudioIn", 21020 "module": "p5.sound", 21021 "submodule": "p5.sound" 21022 }, { 21023 "file": "lib/addons/p5.sound.js", 21024 "line": 7653, 21025 "description": "<p>Returns a list of available input sources. This is a wrapper\nfor <a title="MediaDevices.enumerateDevices() - Web APIs | MDN" target="_blank" href=\n "<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices\">https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices</a>"</p>\n<blockquote>\n<p>and it returns a Promise.</p>\n</blockquote>\n", 21026 "itemtype": "method", 21027 "name": "getSources", 21028 "params": [{ 21029 "name": "successCallback", 21030 "description": "<p>This callback function handles the sources when they\n have been enumerated. The callback function\n receives the deviceList array as its only argument</p>\n", 21031 "type": "Function", 21032 "optional": true 21033 }, { 21034 "name": "errorCallback", 21035 "description": "<p>This optional callback receives the error\n message as its argument.</p>\n", 21036 "type": "Function", 21037 "optional": true 21038 }], 21039 "return": { 21040 "description": "Returns a Promise that can be used in place of the callbacks, similar\n to the enumerateDevices() method", 21041 "type": "Promise" 21042 }, 21043 "example": ["\n <div><code>\n var audiograb;
21043\n\n function setup(){\n //new audioIn\n audioGrab = new p5.AudioIn();\n\n audioGrab.getSources(function(deviceList) {\n //print out the array of available sources\n console.log(deviceList);\n //set the source to the first item in the deviceList array\n audioGrab.setSource(0);\n });\n }\n </code></div>"], 21044 "class": "p5.AudioIn", 21045 "module": "p5.sound", 21046 "submodule": "p5.sound" 21047 }, { 21048 "file": "lib/addons/p5.sound.js", 21049 "line": 7704, 21050 "description": "<p>Set the input source. Accepts a number representing a\nposition in the array returned by getSources().\nThis is only available in browsers that support\n<a title="MediaDevices.enumerateDevices() - Web APIs | MDN" target="_blank" href=\n"<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices\">https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices</a>"</p>\n<blockquote>\n<p>navigator.mediaDevices.enumerateDevices()</a>.<br/></p>\n</blockquote>\n", 21051 "itemtype": "method", 21052 "name": "setSource", 21053 "params": [{ 21054 "name": "num", 21055 "description": "<p>position of input source in the array</p>\n", 21056 "type": "Number" 21057 }], 21058 "class": "p5.AudioIn", 21059 "module": "p5.sound", 21060 "submodule": "p5.sound" 21061 }, { 21062 "file": "lib/addons/p5.sound.js", 21063 "line": 7744, 21064 "class": "p5.AudioIn", 21065 "module": "p5.sound", 21066 "submodule": "p5.sound" 21067 }, { 21068 "file": "lib/addons/p5.sound.js", 21069 "line": 7760, 21070 "class": "p5.AudioIn", 21071 "module": "p5.sound", 21072 "submodule": "p5.sound" 21073 }, { 21074 "file": "lib/addons/p5.sound.js", 21075 "line": 7784, 21076 "class": "p5.AudioIn", 21077 "module": "p5.sound", 21078 "submodule": "p5.sound" 21079 }, { 21080 "file": "lib/addons/p5.sound.js", 21081 "line": 7810, 21082 "class": "p5.AudioIn", 21083 "module": "p5.sound", 21084 "submodule": "p5.sound" 21085 }, { 21086 "file": "lib/addons/p5.sound.js", 21087 "line": 7832, 21088 "class": "p5.AudioIn", 21089 "module": "p5.sound", 21090 "submodule": "p5.sound" 21091 }, { 21092 "file": "lib/addons/p5.sound.js", 21093 "line": 7854, 21094 "class": "p5.AudioIn", 21095 "module": "p5.sound", 21096 "submodule": "p5.sound" 21097 }, { 21098 "file": "lib/addons/p5.sound.js", 21099 "line": 7900, 21100 "class": "p5.AudioIn", 21101 "module": "p5.sound", 21102 "submodule": "p5.sound" 21103 }, { 21104 "file": "lib/addons/p5.sound.js", 21105 "line": 7931, 21106 "class": "p5.AudioIn", 21107 "module": "p5.sound", 21108 "submodule": "p5.sound" 21109 }, { 21110 "file": "lib/addons/p5.sound.js", 21111 "line": 7949, 21112 "class": "p5.AudioIn", 21113 "module": "p5.sound", 21114 "submodule": "p5.sound" 21115 }, { 21116 "file": "lib/addons/p5.sound.js", 21117 "line": 8286, 21118 "class": "p5.AudioIn", 21119 "module": "p5.sound", 21120 "submodule": "p5.sound" 21121 }, { 21122 "file": "lib/addons/p5.sound.js", 21123 "line": 8308, 21124 "class": "p5.AudioIn", 21125 "module": "p5.sound", 21126 "submodule": "p5.sound" 21127 }, { 21128 "file": "lib/addons/p5.sound.js", 21129 "line": 8384, 21130 "description": "<p>In classes that extend\np5.Effect, connect effect nodes\nto the wet parameter</p>\n", 21131 "class": "p5.Effect", 21132 "module": "p5.sound", 21133 "submodule": "p5.sound" 21134 }, { 21135 "file": "lib/addons/p5.sound.js", 21136 "line": 8397, 21137 "description": "<p>Set the output volume of the filter.</p>\n", 21138 "itemtype": "method", 21139 "name": "amp", 21140 "params": [{ 21141 "name": "vol", 21142 "description": "<p>amplitude between 0 and 1.0</p>\n", 21143 "type": "Number", 21144 "optional": true 21145 }, { 21146 "name": "rampTime", 21147 "description": "<p>create a fade that lasts until rampTime</p>\n", 21148 "type": "Number", 21149 "optional": true 21150 }, { 21151 "name": "tFromNow", 21152 "description": "<p>schedule this event to happen in tFromNow seconds</p>\n", 21153 "type": "Number", 21154 "optional": true 21155 }],
21156 "class": "p5.Effect", 21157 "module": "p5.sound", 21158 "submodule": "p5.sound" 21159 }, { 21160 "file": "lib/addons/p5.sound.js", 21161 "line": 8414, 21162 "description": "<p>Link effects together in a chain<br>Example usage: filter.chain(reverb, delay, panner);\nMay be used with an open-ended number of arguments</p>\n", 21163 "itemtype": "method", 21164 "name": "chain", 21165 "params": [{ 21166 "name": "arguments", 21167 "description": "<p>Chain together multiple sound objects</p>\n", 21168 "type": "Object", 21169 "optional": true 21170 }], 21171 "class": "p5.Effect", 21172 "module": "p5.sound", 21173 "submodule": "p5.sound" 21174 }, { 21175 "file": "lib/addons/p5.sound.js", 21176 "line": 8431, 21177 "description": "<p>Adjust the dry/wet value.</p>\n", 21178 "itemtype": "method", 21179 "name": "drywet", 21180 "params": [{ 21181 "name": "fade", 21182 "description": "<p>The desired drywet value (0 - 1.0)</p>\n", 21183 "type": "Number", 21184 "optional": true 21185 }], 21186 "class": "p5.Effect", 21187 "module": "p5.sound", 21188 "submodule": "p5.sound" 21189 }, { 21190 "file": "lib/addons/p5.sound.js", 21191 "line": 8443, 21192 "description": "<p>Send output to a p5.js-sound, Web Audio Node, or use signal to\ncontrol an AudioParam</p>\n", 21193 "itemtype": "method", 21194 "name": "connect", 21195 "params": [{ 21196 "name": "unit", 21197 "description": "", 21198 "type": "Object" 21199 }], 21200 "class": "p5.Effect", 21201 "module": "p5.sound", 21202 "submodule": "p5.sound" 21203 }, { 21204 "file": "lib/addons/p5.sound.js", 21205 "line": 8454, 21206 "description": "<p>Disconnect all output.</p>\n", 21207 "itemtype": "method", 21208 "name": "disconnect", 21209 "class": "p5.Effect", 21210 "module": "p5.sound", 21211 "submodule": "p5.sound" 21212 }, { 21213 "file": "lib/addons/p5.sound.js", 21214 "line": 8572, 21215 "description": "<p>The p5.Filter is built with a\n<a href=\"http://www.w3.org/TR/webaudio/#BiquadFilterNode\">\nWeb Audio BiquadFilter Node</a>.</p>\n", 21216 "itemtype": "property", 21217 "name": "biquadFilter", 21218 "type": "DelayNode", 21219 "class": "p5.Filter", 21220 "module": "p5.sound", 21221 "submodule": "p5.sound" 21222 }, { 21223 "file": "lib/addons/p5.sound.js", 21224 "line": 8590, 21225 "description": "<p>Filter an audio signal according to a set\nof filter parameters.</p>\n", 21226 "itemtype": "method", 21227 "name": "process", 21228 "params": [{ 21229 "name": "Signal", 21230 "description": "<p>An object that outputs audio</p>\n", 21231 "type": "Object" 21232 }, { 21233 "name": "freq", 21234 "description": "<p>Frequency in Hz, from 10 to 22050</p>\n", 21235 "type": "Number", 21236 "optional": true 21237 }, { 21238 "name": "res", 21239 "description": "<p>Resonance/Width of the filter frequency\n from 0.001 to 1000</p>\n", 21240 "type": "Number", 21241 "optional": true 21242 }], 21243 "class": "p5.Filter", 21244 "module": "p5.sound", 21245 "submodule": "p5.sound" 21246 }, { 21247 "file": "lib/addons/p5.sound.js", 21248 "line": 8604, 21249 "description": "<p>Set the frequency and the resonance of the filter.</p>\n", 21250 "itemtype": "method", 21251 "name": "set", 21252 "params": [{ 21253 "name": "freq", 21254 "description": "<p>Frequency in Hz, from 10 to 22050</p>\n", 21255 "type": "Number", 21256 "optional": true 21257 }, { 21258 "name": "res", 21259 "description": "<p>Resonance (Q) from 0.001 to 1000</p>\n", 21260 "type": "Number", 21261 "optional": true 21262 }, { 21263 "name": "timeFromNow", 21264 "description": "<p>schedule this event to happen\n seconds from now</p>\n", 21265 "type": "Number", 21266 "optional": true 21267 }], 21268 "class": "p5.Filter", 21269 "module": "p5.sound", 21270 "submodule": "p5.sound" 21271 }, { 21272 "file": "lib/addons/p5.sound.js", 21273 "line": 8621, 21274 "description": "<p>Set the filter frequency, in Hz, from 10 to 22050 (the range of\
21274nhuman hearing, although in reality most people hear in a narrower\nrange).</p>\n", 21275 "itemtype": "method", 21276 "name": "freq", 21277 "params": [{ 21278 "name": "freq", 21279 "description": "<p>Filter Frequency</p>\n", 21280 "type": "Number" 21281 }, { 21282 "name": "timeFromNow", 21283 "description": "<p>schedule this event to happen\n seconds from now</p>\n", 21284 "type": "Number", 21285 "optional": true 21286 }], 21287 "return": { 21288 "description": "value Returns the current frequency value", 21289 "type": "Number" 21290 }, 21291 "class": "p5.Filter", 21292 "module": "p5.sound", 21293 "submodule": "p5.sound" 21294 }, { 21295 "file": "lib/addons/p5.sound.js", 21296 "line": 8645, 21297 "description": "<p>Controls either width of a bandpass frequency,\nor the resonance of a low/highpass cutoff frequency.</p>\n", 21298 "itemtype": "method", 21299 "name": "res", 21300 "params": [{ 21301 "name": "res", 21302 "description": "<p>Resonance/Width of filter freq\n from 0.001 to 1000</p>\n", 21303 "type": "Number" 21304 }, { 21305 "name": "timeFromNow", 21306 "description": "<p>schedule this event to happen\n seconds from now</p>\n", 21307 "type": "Number", 21308 "optional": true 21309 }], 21310 "return": { 21311 "description": "value Returns the current res value", 21312 "type": "Number" 21313 }, 21314 "class": "p5.Filter", 21315 "module": "p5.sound", 21316 "submodule": "p5.sound" 21317 }, { 21318 "file": "lib/addons/p5.sound.js", 21319 "line": 8667, 21320 "description": "<p>Controls the gain attribute of a Biquad Filter.\nThis is distinctly different from .amp() which is inherited from p5.Effect\n.amp() controls the volume via the output gain node\np5.Filter.gain() controls the gain parameter of a Biquad Filter node.</p>\n", 21321 "itemtype": "method", 21322 "name": "gain", 21323 "params": [{ 21324 "name": "gain", 21325 "description": "", 21326 "type": "Number" 21327 }], 21328 "return": { 21329 "description": "Returns the current or updated gain value", 21330 "type": "Number" 21331 }, 21332 "class": "p5.Filter", 21333 "module": "p5.sound", 21334 "submodule": "p5.sound" 21335 }, { 21336 "file": "lib/addons/p5.sound.js", 21337 "line": 8688, 21338 "description": "<p>Toggle function. Switches between the specified type and allpass</p>\n", 21339 "itemtype": "method", 21340 "name": "toggle", 21341 "return": { 21342 "description": "[Toggle value]", 21343 "type": "Boolean" 21344 }, 21345 "class": "p5.Filter", 21346 "module": "p5.sound", 21347 "submodule": "p5.sound" 21348 }, { 21349 "file": "lib/addons/p5.sound.js", 21350 "line": 8703, 21351 "description": "<p>Set the type of a p5.Filter. Possible types include:\n"lowpass" (default), "highpass", "bandpass",\n"lowshelf", "highshelf", "peaking", "notch",\n"allpass".</p>\n", 21352 "itemtype": "method", 21353 "name": "setType", 21354 "params": [{ 21355 "name": "t", 21356 "description": "", 21357 "type": "String" 21358 }], 21359 "class": "p5.Filter", 21360 "module": "p5.sound", 21361 "submodule": "p5.sound" 21362 }, { 21363 "file": "lib/addons/p5.sound.js", 21364 "line": 8910, 21365 "description": "<p>The p5.EQ is built with abstracted p5.Filter objects.\nTo modify any bands, use methods of the <a \nhref=\"/reference/#/p5.Filter\" title=\"p5.Filter reference\">\np5.Filter</a> API, especially <code>gain</code> and <code>freq</code>.\nBands are stored in an array, with indices 0 - 3, or 0 - 7</p>\n", 21366 "itemtype": "property", 21367 "name": "bands", 21368 "type": "Array", 21369 "class": "p5.EQ", 21370 "module": "p5.sound", 21371 "submodule": "p5.sound" 21372 }, { 21373 "file": "lib/addons/p5.sound.js", 21374 "line": 8945, 21375 "description": "<p>Process an input by connecting it to the EQ</p>\n", 21376 "itemtype": "method", 21377 "name": "process", 21378 "params": [{ 21379 "name": "src", 21380 "description": "<p>Audio source</p>\n", 21381 "type": "Object" 21382 }], 21383 "class": "p5.EQ", 21384 "module": "p5.sound", 21385 "submodule": "p5.sound" 21386 }, { 21387 "file": "lib/addons/p5.sound.js", 21388 "line": 9033, 21389 "description": "<p><a title=\"Web Audio Panner docs\" href=\n\"https://developer.mozilla.org/en-US/docs/Web/API/PannerNode\">\nWeb Audio Spatial Panner Node</a></p>\n<p>Properties include</p>\n<ul>\n<li><a title="w3 spec for Panning Model"\nhref="<a href=\"https://www.w3.org/TR/webaudio/#idl-def-PanningModelType\">https://www.w3.org/TR/webaudio/#idl-def-PanningModelType</a>"<blockquote>\n<p>panningModel</a>: "equal power" or "HRTF"</p>\n</blockquote>\n</li>\n<li><a title="w3 spec for Distance Model"\nhref="<a href=\"https://www.w3.org/TR/webaudio/#idl-def-DistanceModelType\">https://www.w3.org/TR/webaudio/#idl-def-DistanceModelType</a>"<blockquote>\n<p>distanceModel</a>: "linear", "inverse", or "exponential"</p>\n</blockquote>\n</li>\n</ul>\n", 21390 "itemtype": "property", 21391 "name": "panner", 21392 "type": "AudioNode", 21393 "class": "p5.Panner3D", 21394 "module": "p5.sound", 21395 "submodule": "p5.sound" 21396 }, { 21397 "file": "lib/addons/p5.sound.js", 21398 "line": 9056, 21399 "description": "<p>Connect an audio sorce</p>\n", 21400 "itemtype": "method", 21401 "name": "process", 21402 "params": [{ 21403 "name": "src", 21404 "description": "<p>Input source</p>\n", 21405 "type": "Object" 21406 }], 21407 "class": "p5.Panner3D", 21408 "module": "p5.sound", 21409 "submodule": "p5.sound" 21410 }, { 21411 "file": "lib/addons/p5.sound.js", 21412 "line": 9065, 21413 "description": "<p>Set the X,Y,Z position of the Panner</p>\n", 21414 "itemtype": "method", 21415 "name": "set", 21416 "params": [{ 21417 "name": "xVal", 21418 "description": "", 21419 "type": "Number" 21420 }, { 21421 "name": "yVal", 21422 "description": "", 21423 "type": "Number" 21424 }, { 21425 "name": "zVal", 21426 "description": "", 21427 "type": "Number" 21428 }, { 21429 "name": "time", 21430 "description": "", 21431 "type": "Number" 21432 }], 21433 "return": { 21434 "description": "Updated x, y, z values as an array", 21435 "type": "Array" 21436 }, 21437 "class": "p5.Panner3D", 21438 "module": "p5.sound", 21439 "submodule": "p5.sound" 21440 }, { 21441 "file": "lib/addons/p5.sound.js", 21442 "line": 9084, 21443 "description": "<p>Getter and setter methods for position coordinates</p>\n", 21444 "itemtype": "method", 21445 "name": "positionX", 21446 "return": { 21447 "description": "updated coordinate value", 21448 "type": "Number" 21449 }, 21450 "class": "p5.Panner3D", 21451 "module": "p5.sound", 21452 "submodule": "p5.sound" 21453 }, { 21454 "file": "lib/addons/p5.sound.js", 21455 "line": 9089, 21456 "description": "<p>Getter and setter methods for position coordinates</p>\n", 21457 "itemtype": "method", 21458 "name": "positionY", 21459 "return": { 21460 "description": "updated coordinate value", 21461 "type": "Number" 21462 }, 21463 "class": "p5.Panner3D", 21464 "module": "p5.sound", 21465 "submodule": "p5.sound" 21466 }, { 21467 "file": "lib/addons/p5.sound.js", 21468 "line": 9094, 21469 "description": "<p>Getter and setter methods for position coordinates</p>\n", 21470 "itemtype": "method", 21471 "name": "positionZ", 21472 "return": { 21473 "description": "updated coordinate value", 21474 "type": "Number" 21475 }, 21476 "class": "p5.Panner3D", 21477 "module": "p5.sound", 21478 "submodule": "p5.sound" 21479 }, { 21480 "file": "lib/addons/p5.sound.js", 21481 "line": 9132, 21482 "description": "<p>Set the X,Y,Z position of the Panner</p>\n", 21483 "itemtype": "method", 21484 "name": "orient", 21485 "params": [{ 21486 "name": "xVal", 21487 "description": "", 21488 "type": "Number" 21489 }, { 21490 "name": "yVal", 21491 "description": "", 21492 "type": "Number" 21493 }, { 21494 "name": "zVal", 21495 "description": "", 21496 "type": "Number" 21497 }, { 21498 "name": "time", 21499 "description": "", 21500 "type": "Number" 21501 }], 21502 "return": { 21503 "description": "Updated x, y, z values as an array", 21504 "type": "Array" 21505 }, 21506 "class": "p5.Panner3D", 21507 "module": "p5.sound", 21508 "submodule": "p5.sound" 21509 }, { 21510 "file": "lib/addons/p5.sound.js", 21511 "line": 9151, 21512 "description": "<p>Getter and setter methods for orient coordinates</p>\n", 21513 "itemtype": "method", 21514 "name": "orientX", 21515 "return": { 21516 "description": "updated coordinate value", 21517 "type": "Number" 21518 }, 21519 "class": "p5.Panner3D", 21520 "module": "p5.sound", 21521 "submodule": "p5.sound" 21522 }, { 21523 "file": "lib/addons/p5.sound.js", 21524 "line": 9156, 21525 "description": "<p>Getter and setter methods for orient coordinates</p>\n", 21526 "itemtype": "method", 21527 "name": "orientY", 21528 "return": { 21529 "description": "updated coordinate value", 21530 "type": "Number" 21531 }, 21532 "class": "p5.Panner3D", 21533 "module": "p5.sound", 21534 "submodule": "p5.sound" 21535 }, { 21536 "file": "lib/addons/p5.sound.js", 21537 "line": 9161, 21538 "description": "<p>Getter and setter methods for orient coordinates</p>\n", 21539 "itemtype": "method", 21540 "name": "orientZ", 21541 "return": { 21542 "description": "updated coordinate value", 21543 "type": "Number" 21544 }, 21545 "class": "p5.Panner3D", 21546 "module": "p5.sound", 21547 "submodule": "p5.sound" 21548 }, { 21549 "file": "lib/addons/p5.sound.js", 21550 "line": 9199, 21551 "description": "<p>Set the rolloff factor and max distance</p>\n", 21552 "itemtype": "method", 21553 "name": "setFalloff", 21554 "params": [{ 21555 "name": "maxDistance", 21556 "description": "", 21557 "type": "Number", 21558 "optional": true 21559 }, { 21560 "name": "rolloffFactor", 21561 "description": "", 21562 "type": "Number", 21563 "optional": true 21564 }], 21565 "class": "p5.Panner3D", 21566 "module": "p5.sound", 21567 "submodule": "p5.sound" 21568 }, { 21569 "file": "lib/addons/p5.sound.js", 21570 "line": 9209, 21571 "description": "<p>Maxium distance between the source and the listener</p>\n", 21572 "itemtype": "method", 21573 "name": "maxDist", 21574 "params": [{ 21575 "name": "maxDistance", 21576 "description": "", 21577 "type": "Number" 21578 }], 21579 "return": { 21580 "description": "updated value", 21581 "type": "Number" 21582 }, 21583 "class": "p5.Panner3D", 21584 "module": "p5.sound", 21585 "submodule": "p5.sound" 21586 }, { 21587 "file": "lib/addons/p5.sound.js", 21588 "line": 9221, 21589 "description": "<p>How quickly the volume is reduced as the source moves away from the listener</p>\n", 21590 "itemtype": "method", 21591 "name": "rollof", 21592 "params": [{ 21593 "name": "rolloffFactor", 21594 "description": "", 21595 "type": "Number" 21596 }], 21597 "return": { 21598 "description": "updated value", 21599 "type": "Number" 21600 }, 21601 "class": "p5.Panner3D", 21602 "module": "p5.sound", 21603 "submodule": "p5.sound" 21604 }, { 21605 "file": "lib/addons/p5.sound.js", 21606 "line": 9526, 21607 "description": "<p>The p5.Delay is built with two\n<a href=\"http://www.w3.org/TR/webaudio/#DelayNode\">\nWeb Audio Delay Nodes</a>, one for each stereo channel.</p>\n", 21608 "itemtype": "property", 21609 "name": "leftDelay", 21610 "type": "DelayNode", 21611 "class": "p5.Delay", 21612 "module": "p5.sound", 21613 "submodule": "p5.sound" 21614 }, { 21615 "file": "lib/addons/p5.sound.js", 21616 "line": 9534, 21617 "description": "<p>The p5.Delay is built with two\n<a href=\"http://www.w3.org/TR/webaudio/#DelayNode\">\nWeb Audio Delay Nodes</a>, one for each stereo channel.</p>\n", 21618 "itemtype": "property", 21619 "name": "rightDelay", 21620 "type": "DelayNode", 21621 "class": "p5.Delay", 21622 "module": "p5.sound", 21623 "submodule": "p5.sound" 21624 }, { 21625 "file": "lib/addons/p5.sound.js", 21626 "line": 9566, 21627 "description": "<p>Add delay to an audio signal according to a set\nof delay parameters.</p>\n", 21628 "itemtype": "method", 21629 "name": "process", 21630 "params": [{ 21631 "name": "Signal", 21632 "description": "<p>An object that outputs audio</p>\n", 21633 "type": "Object" 21634 }, { 21635 "name": "delayTime", 21636 "description": "<p>Time (in seconds) of the delay/echo.\n Some browsers limit delayTime to\n 1 second.</p>\n", 21637 "type": "Number", 21638 "optional": true 21639 }, { 21640 "name": "feedback", 21641 "description": "<p>sends the delay back through itself\n in a loop that decreases in volume\n each time.</p>\n", 21642 "type": "Number", 21643 "optional": true 21644 }, { 21645 "name": "lowPass", 21646 "description": "<p>Cutoff frequency. Only frequencies\n below the lowPass will be part of the\n delay.</p>\n", 21647 "type": "Number", 21648 "optional": true 21649 }], 21650 "class": "p5.Delay", 21651 "module": "p5.sound", 21652 "submodule": "p5.sound" 21653 }, { 21654 "file": "lib/addons/p5.sound.js", 21655 "line": 9601, 21656 "description": "<p>Set the delay (echo) time, in seconds. Usually this value will be\na floating point number between 0.0 and 1.0.</p>\n", 21657 "itemtype": "method", 21658 "name": "delayTime", 21659 "params": [{ 21660 "name": "delayTime", 21661 "description": "<p>Time (in seconds) of the delay</p>\n", 21662 "type": "Number" 21663 }], 21664 "class": "p5.Delay", 21665 "module": "p5.sound", 21666 "submodule": "p5.sound" 21667 }, { 21668 "file": "lib/addons/p5.sound.js", 21669 "line": 9620, 21670 "description": "<p>Feedback occurs when Delay sends its signal back through its input\nin a loop. The feedback amount determines how much signal to send each\ntime through the loop. A feedback greater than 1.0 is not desirable because\nit will increase the overall output each time through the loop,\ncreating an infinite feedback loop. The default value is 0.5</p>\n", 21671 "itemtype": "method", 21672 "name": "feedback", 21673 "params": [{ 21674 "name": "feedback", 21675 "description": "<p>0.0 to 1.0, or an object such as an\n Oscillator that can be used to\n modulate this param</p>\n", 21676 "type": "Number|Object" 21677 }], 21678 "return": { 21679 "description": "Feedback value", 21680 "type": "Number" 21681 }, 21682 "class": "p5.Delay", 21683 "module": "p5.sound", 21684 "submodule": "p5.sound" 21685 }, { 21686 "file": "lib/addons/p5.sound.js", 21687 "line": 9648, 21688
21688 "description": "<p>Set a lowpass filter frequency for the delay. A lowpass filter\nwill cut off any frequencies higher than the filter frequency.</p>\n", 21689 "itemtype": "method", 21690 "name": "filter", 21691 "params": [{ 21692 "name": "cutoffFreq", 21693 "description": "<p>A lowpass filter will cut off any\n frequencies higher than the filter frequency.</p>\n", 21694 "type": "Number|Object" 21695 }, { 21696 "name": "res", 21697 "description": "<p>Resonance of the filter frequency\n cutoff, or an object (i.e. a p5.Oscillator)\n that can be used to modulate this parameter.\n High numbers (i.e. 15) will produce a resonance,\n low numbers (i.e. .2) will produce a slope.</p>\n", 21698 "type": "Number|Object" 21699 }], 21700 "class": "p5.Delay", 21701 "module": "p5.sound", 21702 "submodule": "p5.sound" 21703 }, { 21704 "file": "lib/addons/p5.sound.js", 21705 "line": 9665, 21706 "description": "<p>Choose a preset type of delay. 'pingPong' bounces the signal\nfrom the left to the right channel to produce a stereo effect.\nAny other parameter will revert to the default delay setting.</p>\n", 21707 "itemtype": "method", 21708 "name": "setType", 21709 "params": [{ 21710 "name": "type", 21711 "description": "<p>'pingPong' (1) or 'default' (0)</p>\n", 21712 "type": "String|Number" 21713 }], 21714 "class": "p5.Delay", 21715 "module": "p5.sound", 21716 "submodule": "p5.sound" 21717 }, { 21718 "file": "lib/addons/p5.sound.js", 21719 "line": 9698, 21720 "description": "<p>Set the output level of the delay effect.</p>\n", 21721 "itemtype": "method", 21722 "name": "amp", 21723 "params": [{ 21724 "name": "volume", 21725 "description": "<p>amplitude between 0 and 1.0</p>\n", 21726 "type": "Number" 21727 }, { 21728 "name": "rampTime", 21729 "description": "<p>create a fade that lasts rampTime</p>\n", 21730 "type": "Number", 21731 "optional": true 21732 }, { 21733 "name": "timeFromNow", 21734 "description": "<p>schedule this event to happen\n seconds from now</p>\n", 21735 "type": "Number", 21736 "optional": true 21737 }], 21738 "class": "p5.Delay", 21739 "module": "p5.sound", 21740 "submodule": "p5.sound" 21741 }, { 21742 "file": "lib/addons/p5.sound.js", 21743 "line": 9707, 21744 "description": "<p>Send output to a p5.sound or web audio object</p>\n", 21745 "itemtype": "method", 21746 "name": "connect", 21747 "params": [{ 21748 "name": "unit", 21749 "description": "", 21750 "type": "Object" 21751 }], 21752 "class": "p5.Delay", 21753 "module": "p5.sound", 21754 "submodule": "p5.sound" 21755 }, { 21756 "file": "lib/addons/p5.sound.js", 21757 "line": 9713, 21758 "description": "<p>Disconnect all output.</p>\n", 21759 "itemtype": "method", 21760 "name": "disconnect", 21761 "class": "p5.Delay", 21762 "module": "p5.sound", 21763 "submodule": "p5.sound" 21764 }, { 21765 "file": "lib/addons/p5.sound.js", 21766 "line": 9806, 21767 "description": "<p>Connect a source to the reverb, and assign reverb parameters.</p>\n", 21768 "itemtype": "method", 21769 "name": "process", 21770 "params": [{ 21771 "name": "src", 21772 "description": "<p>p5.sound / Web Audio object with a sound\n output.</p>\n", 21773 "type": "Object" 21774 }, { 21775 "name": "seconds", 21776 "description": "<p>Duration of the reverb, in seconds.\n Min: 0, Max: 10. Defaults to 3.</p>\n", 21777 "type": "Number", 21778 "optional": true 21779 }, { 21780 "name": "decayRate", 21781 "description": "<p>Percentage of decay with each echo.\n Min: 0, Max: 100. Defaults to 2.</p>\n", 21782 "type": "Number", 21783 "optional": true 21784 }, { 21785 "name": "reverse", 21786 "description": "<p>Play the reverb backwards or forwards.</p>\n", 21787 "type": "Boolean", 21788 "optional": true 21789 }], 21790 "class": "p5.Reverb", 21791 "module": "p5.sound", 21792 "submodule": "p5.sound" 21793 }, { 21794 "file": "lib/addons/p5.sound.js", 21795 "line": 9835, 21796 "description": "<p>Set the reverb settings. Similar to .process(), but without\nassigning a new input.</p>\n", 21797 "itemtype": "method", 21798 "name": "set", 21799 "params": [{ 21800 "name": "seconds", 21801 "description": "<p>Duration of the reverb, in seconds.\n Min: 0, Max: 10. Defaults to 3.</p>\n", 21802 "type": "Number", 21803 "optional": true 21804 }, { 21805 "name": "decayRate", 21806 "description": "<p>Percentage of decay with each echo.\n Min: 0, Max: 100. Defaults to 2.</p>\n", 21807 "type": "Number", 21808 "optional": true 21809 }, { 21810 "name": "reverse", 21811 "description": "<p>Play the reverb backwards or forwards.</p>\n", 21812 "type": "Boolean", 21813 "optional": true 21814 }], 21815 "class": "p5.Reverb", 21816 "module": "p5.sound", 21817 "submodule": "p5.sound" 21818 }, { 21819 "file": "lib/addons/p5.sound.js", 21820 "line": 9863, 21821 "description": "<p>Set the output level of the reverb effect.</p>\n", 21822 "itemtype": "method", 21823 "name": "amp", 21824 "params": [{ 21825 "name": "volume", 21826 "description": "<p>amplitude between 0 and 1.0</p>\n", 21827 "type": "Number" 21828 }, { 21829 "name": "rampTime", 21830 "description": "<p>create a fade that lasts rampTime</p>\n", 21831 "type": "Number", 21832 "optional": true 21833 }, { 21834 "name": "timeFromNow", 21835 "description": "<p>schedule this event to happen\n seconds from now</p>\n", 21836 "type": "Number", 21837 "optional": true 21838 }], 21839 "class": "p5.Reverb", 21840 "module": "p5.sound", 21841 "submodule": "p5.sound" 21842 }, { 21843 "file": "lib/addons/p5.sound.js", 21844 "line": 9872, 21845 "description": "<p>Send output to a p5.sound or web audio object</p>\n", 21846 "itemtype": "method", 21847 "name": "connect", 21848 "params": [{ 21849 "name": "unit", 21850 "description": "", 21851 "type": "Object" 21852 }], 21853 "class": "p5.Reverb", 21854 "module": "p5.sound", 21855 "submodule": "p5.sound" 21856 }, { 21857 "file": "lib/addons/p5.sound.js", 21858 "line": 9878, 21859 "description": "<p>Disconnect all output.</p>\n", 21860 "itemtype": "method", 21861 "name": "disconnect", 21862 "class": "p5.Reverb", 21863 "module": "p5.sound", 21864 "submodule": "p5.sound" 21865 }, { 21866 "file": "lib/addons/p5.sound.js", 21867 "line": 9969, 21868 "description": "<p>Internally, the p5.Convolver uses the a\n<a href=\"http://www.w3.org/TR/webaudio/#ConvolverNode\">\nWeb Audio Convolver Node</a>.</p>\n", 21869 "itemtype": "property", 21870 "name": "convolverNode", 21871 "type": "ConvolverNode", 21872 "class": "p5.Convolver", 21873 "module": "p5.sound", 21874 "submodule": "p5.sound" 21875 }, { 21876 "file": "lib/addons/p5.sound.js", 21877 "line": 9992, 21878 "description": "<p>Create a p5.Convolver. Accepts a path to a soundfile\nthat will be used to generate an impulse response.</p>\n", 21879 "itemtype": "method", 21880 "name": "createConvolver", 21881 "params": [{ 21882 "name": "path", 21883 "description": "<p>
21883path to a sound file</p>\n", 21884 "type": "String" 21885 }, { 21886 "name": "callback", 21887 "description": "<p>function to call if loading is successful.\n The object will be passed in as the argument\n to the callback function.</p>\n", 21888 "type": "Function", 21889 "optional": true 21890 }, { 21891 "name": "errorCallback", 21892 "description": "<p>function to call if loading is not successful.\n A custom error will be passed in as the argument\n to the callback function.</p>\n", 21893 "type": "Function", 21894 "optional": true 21895 }], 21896 "return": { 21897 "description": "", 21898 "type": "p5.Convolver" 21899 }, 21900 "example": ["\n<div><code>\nvar cVerb, sound;\nfunction preload() {\n // We have both MP3 and OGG versions of all sound assets\n soundFormats('ogg', 'mp3');\n\n // Try replacing 'bx-spring' with other soundfiles like\n // 'concrete-tunnel' 'small-plate' 'drum' 'beatbox'\n cVerb = createConvolver('assets/bx-spring.mp3');\n\n // Try replacing 'Damscray_DancingTiger' with\n // 'beat', 'doorbell', lucky_dragons_-_power_melody'\n sound = loadSound('assets/Damscray_DancingTiger.mp3');\n}\n\nfunction setup() {\n // disconnect from master output...\n sound.disconnect();\n\n // ...and process with cVerb\n // so that we only hear the convolution\n cVerb.process(sound);\n\n sound.play();\n}\n</code></div>"], 21901 "class": "p5.Convolver", 21902 "module": "p5.sound", 21903 "submodule": "p5.sound" 21904 }, { 21905 "file": "lib/addons/p5.sound.js", 21906 "line": 10116, 21907 "description": "<p>Connect a source to the reverb, and assign reverb parameters.</p>\n", 21908 "itemtype": "method", 21909 "name": "process", 21910 "params": [{ 21911 "name": "src", 21912 "description": "<p>p5.sound / Web Audio object with a sound\n output.</p>\n", 21913 "type": "Object" 21914 }], 21915 "example": ["\n<div><code>\nvar cVerb, sound;\nfunction preload() {\n soundFormats('ogg', 'mp3');\n\n cVerb = createConvolver('assets/concrete-tunnel.mp3');\n\n sound = loadSound('assets/beat.mp3');\n}\n\nfunction setup() {\n // disconnect from master output...\n sound.disconnect();\n\n // ...and process with (i.e. connect to) cVerb\n // so that we only hear the convolution\n cVerb.process(sound);\n\n sound.play();\n}\n</code></div>"], 21916 "class": "p5.Convolver", 21917 "module": "p5.sound", 21918 "submodule": "p5.sound" 21919 }, { 21920 "file": "lib/addons/p5.sound.js", 21921 "line": 10148, 21922 "description": "<p>If you load multiple impulse files using the .addImpulse method,\nthey will be stored as Objects in this Array. Toggle between them\nwith the <code>toggleImpulse(id)</code> method.</p>\n", 21923 "itemtype": "property", 21924 "name": "impulses", 21925 "type": "Array", 21926 "class": "p5.Convolver", 21927 "module": "p5.sound", 21928 "submodule": "p5.sound" 21929 }, { 21930 "file": "lib/addons/p5.sound.js", 21931 "line": 10156, 21932 "description": "<p>Load and assign a new Impulse Response to the p5.Convolver.\nThe impulse is added to the <code>.impulses</code> array. Previous\nimpulses can be accessed with the <code>.toggleImpulse(id)</code>\nmethod.</p>\n", 21933 "itemtype": "method", 21934 "name": "addImpulse", 21935 "params": [{ 21936 "name": "path", 21937 "description": "<p>path to a sound file</p>\n", 21938 "type": "String" 21939 }, { 21940 "name": "callback", 21941 "description": "<p>function (optional)</p>\n", 21942 "type": "Function" 21943 }, { 21944 "name": "errorCallback", 21945 "description": "<p>function (optional)</p>\n", 21946 "type": "Function" 21947 }], 21948 "class": "p5.Convolver", 21949 "module": "p5.sound", 21950 "submodule": "p5.sound" 21951 }, { 21952 "file": "lib/addons/p5.sound.js", 21953 "line": 10174, 21954 "description": "<p>Similar to .addImpulse, except that the <code>.impulses</code>\nArray is reset to save memory. A new <code>.impulses</code>\narray is created with this impulse as the only item.</p>\n", 21955 "itemtype": "method", 21956 "name": "resetImpulse", 21957 "params": [{ 21958 "name": "path", 21959 "description": "<p>
21959path to a sound file</p>\n", 21960 "type": "String" 21961 }, { 21962 "name": "callback", 21963 "description": "<p>function (optional)</p>\n", 21964 "type": "Function" 21965 }, { 21966 "name": "errorCallback", 21967 "description": "<p>function (optional)</p>\n", 21968 "type": "Function" 21969 }], 21970 "class": "p5.Convolver", 21971 "module": "p5.sound", 21972 "submodule": "p5.sound" 21973 }, { 21974 "file": "lib/addons/p5.sound.js", 21975 "line": 10192, 21976 "description": "<p>If you have used <code>.addImpulse()</code> to add multiple impulses\nto a p5.Convolver, then you can use this method to toggle between\nthe items in the <code>.impulses</code> Array. Accepts a parameter\nto identify which impulse you wish to use, identified either by its\noriginal filename (String) or by its position in the <code>.impulses\n</code> Array (Number).<br/>\nYou can access the objects in the .impulses Array directly. Each\nObject has two attributes: an <code>.audioBuffer</code> (type:\nWeb Audio <a href=\"\nhttp://webaudio.github.io/web-audio-api/#the-audiobuffer-interface\">\nAudioBuffer)</a> and a <code>.name</code>, a String that corresponds\nwith the original filename.</p>\n", 21977 "itemtype": "method", 21978 "name": "toggleImpulse", 21979 "params": [{ 21980 "name": "id", 21981 "description": "<p>Identify the impulse by its original filename\n (String), or by its position in the\n <code>.impulses</code> Array (Number).</p>\n", 21982 "type": "String|Number" 21983 }], 21984 "class": "p5.Convolver", 21985 "module": "p5.sound", 21986 "submodule": "p5.sound" 21987 }, { 21988 "file": "lib/addons/p5.sound.js", 21989 "line": 10234, 21990 "class": "p5.Convolver", 21991 "module": "p5.sound", 21992 "submodule": "p5.sound" 21993 }, { 21994 "file": "lib/addons/p5.sound.js", 21995 "line": 10259, 21996 "class": "p5.Convolver", 21997 "module": "p5.sound", 21998 "submodule": "p5.sound" 21999 }, { 22000 "file": "lib/addons/p5.sound.js", 22001 "line": 10454, 22002 "description": "<p>Set the global tempo, in beats per minute, for all\np5.Parts. This method will impact all active p5.Parts.</p>\n", 22003 "itemtype": "method", 22004 "name": "setBPM", 22005 "params": [{ 22006 "name": "BPM", 22007 "description": "<p>Beats Per Minute</p>\n", 22008 "type": "Number" 22009 }, { 22010 "name": "rampTime", 22011 "description": "<p>Seconds from now</p>\n", 22012 "type": "Number" 22013 }], 22014 "class": "p5.Convolver", 22015 "module": "p5.sound", 22016 "submodule": "p5.sound" 22017 }, { 22018 "file": "lib/addons/p5.sound.js", 22019 "line": 10544, 22020 "description": "<p>Array of values to pass into the callback\nat each step of the phrase. Depending on the callback\nfunction's requirements, these values may be numbers,\nstrings, or an object with multiple parameters.\nZero (0) indicates a rest.</p>\n", 22021 "itemtype": "property", 22022 "name": "sequence", 22023 "type": "Array", 22024 "class": "p5.Phrase", 22025 "module": "p5.sound", 22026 "submodule": "p5.sound" 22027 }, { 22028 "file": "lib/addons/p5.sound.js", 22029 "line": 10632, 22030 "description": "<p>Set the tempo of this part, in Beats Per Minute.</p>\n", 22031 "itemtype": "method", 22032 "name": "setBPM", 22033 "params": [{ 22034 "name": "BPM", 22035 "description": "<p>Beats Per Minute</p>\n", 22036 "type": "Number" 22037 }, { 22038 "name": "rampTime", 22039 "description": "<p>Seconds from now</p>\n", 22040 "type": "Number", 22041 "optional": true 22042 }], 22043 "class": "p5.Part", 22044 "module": "p5.sound", 22045 "submodule": "p5.sound" 22046 }, { 22047 "file": "lib/addons/p5.sound.js", 22048 "line": 10642, 22049 "description": "<p>Returns the tempo, in Beats Per Minute, of this part.</p>\n", 22050 "itemtype": "method", 22051 "name": "getBPM", 22052 "return": { 22053 "description": "", 22054 "type": "Number" 22055 }, 22056 "class": "p5.Part", 22057 "module": "p5.sound", 22058 "submodule": "p5.sound" 22059 }, { 22060 "file": "lib/addons/p5.sound.js", 22061 "line": 10651, 22062 "description": "<p>Start playback of this part. It will play\nthrough all of its phrases at a speed\ndetermined by setBPM.</p>\n", 22063 "itemtype": "method", 22064 "name": "start", 22065 "params": [{ 22066 "name": "time", 22067 "description": "<p>seconds from now</p>\n", 22068 "type": "Number", 22069 "optional": true 22070 }], 22071 "class": "p5.Part", 22072 "module": "p5.sound", 22073 "submodule": "p5.sound" 22074 }, { 22075 "file": "lib/addons/p5.sound.js", 22076 "line": 10667, 22077 "description": "<p>Loop playback of this part. It will begin\nlooping through all of its phrases at a speed\ndetermined by setBPM.</p>\n", 22078 "itemtype": "method", 22079 "name": "loop", 22080 "params": [{ 22081 "name": "time", 22082 "description": "<p>seconds from now</p>\n", 22083 "type": "Number", 22084 "optional": true 22085 }], 22086 "class": "p5.Part", 22087 "module": "p5.sound", 22088 "submodule": "p5.sound" 22089 }, { 22090 "file": "lib/addons/p5.sound.js", 22091 "line": 10684, 22092 "description": "<p>Tell the part to stop looping.</p>\n", 22093 "itemtype": "method", 22094 "name": "noLoop", 22095 "class": "p5.Part", 22096 "module": "p5.sound", 22097 "submodule": "p5.sound" 22098 }, { 22099 "file": "lib/addons/p5.sound.js", 22100 "line": 10696, 22101 "description": "<p>Stop the part and cue it to step 0. Playback will resume from the begining of the Part when it is played again.</p>\n", 22102 "itemtype": "method", 22103 "name": "stop", 22104 "params": [{ 22105 "name": "time", 22106 "description": "<p>seconds from now</p>\n", 22107 "type": "Number", 22108 "optional": true 22109 }], 22110 "class": "p5.Part", 22111 "module": "p5.sound", 22112 "submodule": "p5.sound" 22113 }, { 22114 "file": "lib/addons/p5.sound.js", 22115 "line": 10706, 22116 "description": "<p>Pause the part. Playback will resume\nfrom the current step.</p>\n", 22117 "itemtype": "method", 22118 "name": "pause", 22119 "params": [{ 22120 "name": "time", 22121 "description": "<p>seconds from now</p>\n", 22122 "type": "Number" 22123 }], 22124 "class": "p5.Part", 22125 "module": "p5.sound", 22126 "submodule": "p5.sound" 22127 }, { 22128 "file": "lib/addons/p5.sound.js", 22129 "line": 10718, 22130 "description": "<p>Add a p5.Phrase to this Part.</p>\n", 22131 "itemtype": "method", 22132 "name": "addPhrase", 22133 "params": [{ 22134 "name": "phrase", 22135 "description": "<p>reference to a p5.Phrase</p>\n", 22136 "type": "p5.Phrase" 22137 }], 22138 "class": "p5.Part", 22139 "module": "p5.sound", 22140 "submodule": "p5.sound" 22141 }, { 22142 "file": "lib/addons/p5.sound.js", 22143 "line": 10739, 22144 "description": "<p>Remove a phrase from this part, based on the name it was\ngiven when it was created.</p>\n", 22145 "itemtype": "method", 22146 "name": "removePhrase", 22147 "params": [{ 22148 "name": "phraseName", 22149 "description": "", 22150 "type": "String" 22151 }], 22152 "class": "p5.Part", 22153 "module": "p5.sound", 22154 "submodule": "p5.sound" 22155 }, { 22156 "file": "lib/addons/p5.sound.js", 22157 "line": 10753, 22158 "description": "<p>Get a phrase from this part, based on the name it was\ngiven when it was created. Now you can modify its array.</p>\n", 22159 "itemtype": "method", 22160 "name": "getPhrase", 22161 "params": [{ 22162 "name": "phraseName", 22163 "description": "", 22164 "type": "String" 22165 }], 22166 "class": "p5.Part", 22167 "module": "p5.sound", 22168 "submodule": "p5.sound" 22169 }, { 22170 "file": "lib/addons/p5.sound.js", 22171 "line": 10767, 22172 "description": "<p>Find all sequences with the specified name, and replace their patterns with the specified array.</p>\n", 22173 "itemtype": "method", 22174 "name": "replaceSequence", 22175 "params": [{ 22176 "name": "phraseName", 22177 "description": "", 22178 "type": "String" 22179 }, { 22180 "name": "sequence", 22181 "description": "<p>Array of values to pass into the callback\n at each step of the phrase.</p>\n", 22182 "type": "Array" 22183 }], 22184 "class": "p5.Part", 22185 "module": "p5.sound", 22186 "submodule": "p5.sound" 22187 }, { 22188 "file": "lib/addons/p5.sound.js", 22189 "line": 10794, 22190 "description": "<p>Set the function that will be called at every step. This will clear the previous function.</p>\n", 22191 "itemtype": "method", 22192 "name": "onStep", 22193 "params": [{ 22194 "name": "callback", 22195 "description": "<p>The name of the callback\n you want to fire\n on every beat/tatum.</p>\n", 22196 "type": "Function" 22197 }], 22198 "class": "p5.Part", 22199 "module": "p5.sound", 22200 "submodule": "p5.sound" 22201 }, { 22202 "file": "lib/addons/p5.sound.js", 22203 "line": 10847, 22204 "description": "<p>Start playback of the score.</p>\n", 22205 "itemtype": "method", 22206 "name": "start", 22207 "class": "p5.Score", 22208 "module": "p5.sound", 22209 "submodule": "p5.sound" 22210 }, { 22211 "file": "lib/addons/p5.sound.js", 22212 "line": 10856, 22213 "description": "<p>Stop playback of the score.</p>\n", 22214 "itemtype": "method", 22215 "name": "stop", 22216 "class": "p5.Score", 22217 "module": "p5.sound", 22218 "submodule": "p5.sound" 22219 }, { 22220 "file": "lib/addons/p5.sound.js", 22221 "line": 10866, 22222 "description": "<p>Pause playback of the score.</p>\n", 22223 "itemtype": "method", 22224 "name": "pause", 22225 "class": "p5.Score", 22226 "module": "p5.sound", 22227 "submodule": "p5.sound" 22228 }, { 22229 "file": "lib/addons/p5.sound.js", 22230 "line": 10874, 22231 "description": "<p>Loop playback of the score.</p>\n", 22232 "itemtype": "method", 22233 "name": "loop", 22234 "class": "p5.Score", 22235 "module": "p5.sound", 22236 "submodule": "p5.sound" 22237 }, { 22238 "file": "lib/addons/p5.sound.js", 22239 "line": 10883, 22240 "description": "<p>Stop looping playback of the score. If it\nis currently playing, this will go into effect\nafter the current roun
22240d of playback completes.</p>\n", 22241 "itemtype": "method", 22242 "name": "noLoop", 22243 "class": "p5.Score", 22244 "module": "p5.sound", 22245 "submodule": "p5.sound" 22246 }, { 22247 "file": "lib/addons/p5.sound.js", 22248 "line": 10908, 22249 "description": "<p>Set the tempo for all parts in the score</p>\n", 22250 "itemtype": "method", 22251 "name": "setBPM", 22252 "params": [{ 22253 "name": "BPM", 22254 "description": "<p>Beats Per Minute</p>\n", 22255 "type": "Number" 22256 }, { 22257 "name": "rampTime", 22258 "description": "<p>Seconds from now</p>\n", 22259 "type": "Number" 22260 }], 22261 "class": "p5.Score", 22262 "module": "p5.sound", 22263 "submodule": "p5.sound" 22264 }, { 22265 "file": "lib/addons/p5.sound.js", 22266 "line": 10976, 22267 "description": "<p>musicalTimeMode uses <a href = \"https://github.com/Tonejs/Tone.js/wiki/Time\">Tone.Time</a> convention\ntrue if string, false if number</p>\n", 22268 "itemtype": "property", 22269 "name": "musicalTimeMode", 22270 "type": "Boolean", 22271 "class": "p5.SoundLoop", 22272 "module": "p5.sound", 22273 "submodule": "p5.sound" 22274 }, { 22275 "file": "lib/addons/p5.sound.js", 22276 "line": 10983, 22277 "description": "<p>musicalTimeMode variables\nmodify these only when the interval is specified in musicalTime format as a string</p>\n", 22278 "class": "p5.SoundLoop", 22279 "module": "p5.sound", 22280 "submodule": "p5.sound" 22281 }, { 22282 "file": "lib/addons/p5.sound.js", 22283 "line": 10990, 22284 "description": "<p>Set a limit to the number of loops to play. defaults to Infinity</p>\n", 22285 "itemtype": "property", 22286 "name": "maxIterations", 22287 "type": "Number", 22288 "class": "p5.SoundLoop", 22289 "module": "p5.sound", 22290 "submodule": "p5.sound" 22291 }, { 22292 "file": "lib/addons/p5.sound.js", 22293 "line": 10999, 22294 "description": "<p>Do not initiate the callback if timeFromNow is < 0\nThis ususually occurs for a few milliseconds when the page\nis not fully loaded</p>\n<p>The callback should only be called until maxIterations is reached</p>\n", 22295 "class": "p5.SoundLoop", 22296 "module": "p5.sound", 22297 "submodule": "p5.sound" 22298 }, { 22299 "file": "lib/addons/p5.sound.js", 22300 "line": 11013, 22301 "description": "<p>Start the loop</p>\n", 22302 "itemtype": "method", 22303 "name": "start", 22304 "params": [{ 22305 "name": "timeFromNow", 22306 "description": "<p>schedule a starting time</p>\n", 22307 "type": "Number", 22308 "optional": true 22309 }], 22310 "class": "p5.SoundLoop", 22311 "module": "p5.sound", 22312 "submodule": "p5.sound" 22313 }, { 22314 "file": "lib/addons/p5.sound.js", 22315 "line": 11026, 22316 "description": "<p>Stop the loop</p>\n", 22317 "itemtype": "method", 22318 "name": "stop", 22319 "params": [{ 22320 "name": "timeFromNow", 22321 "description": "<p>schedule a stopping time</p>\n", 22322 "type": "Number", 22323 "optional": true 22324 }], 22325 "class": "p5.SoundLoop", 22326 "module": "p5.sound", 22327 "submodule": "p5.sound" 22328 }, { 22329 "file": "lib/addons/p5.sound.js", 22330 "line": 11039, 22331 "description": "<p>Pause the loop</p>\n", 22332 "itemtype": "method", 22333 "name": "pause", 22334 "params": [{ 22335 "name": "timeFromNow", 22336 "description": "<p>schedule a pausing time</p>\n", 22337 "type": "Number", 22338 "optional": true 22339 }], 22340 "class": "p5.SoundLoop", 22341 "module": "p5.sound", 22342 "submodule": "p5.sound" 22343 }, { 22344 "file": "lib/addons/p5.sound.js", 22345 "line": 11052, 22346 "description": "<p>Synchronize loops. Use this method to start two more more loops in synchronization\nor to start a loop in synchronization with a loop that is already playing\nThis method will schedule the implicit loop in sync with the explicit master loop\ni.e. loopToStart.syncedStart(loopToSyncWith)</p>\n", 22347 "itemtype": "method", 22348 "name": "syncedStart", 22349 "params": [{ 22350 "name": "otherLoop", 22351 "description": "<p>a p5.SoundLoop to sync with</p>\n", 22352 "type": "Object" 22353 }, { 22354 "name": "timeFromNow", 22355 "description": "<p>Start the loops in sync after timeFromNow seconds</p>\n", 22356 "type": "Number", 22357 "optional": true 22358 }], 22359 "class": "p5.SoundLoop", 22360 "module": "p5.sound", 22361 "submodule": "p5.sound" 22362 }, { 22363 "file": "lib/addons/p5.sound.js", 22364 "line": 11133, 22365 "description": "<p>Getters and Setters, setting any paramter will result in a change in the clock's\nfrequency, that will be reflected after the next callback\nbeats per minute (defaults to 60)</p>\n", 22366 "itemtype": "property", 22367 "name": "bpm", 22368 "type": "Number", 22369 "class": "p5.SoundLoop", 22370 "module": "p5.sound", 22371 "submodule": "p5.sound" 22372 }, { 22373 "file": "lib/addons/p5.sound.js", 22374 "line": 11151, 22375 "description": "<p>number of quarter notes in a measure (defaults to 4)</p>\n", 22376 "itemtype": "property", 22377 "name": "timeSignature", 22378 "type": "Number", 22379 "class": "p5.SoundLoop", 22380 "module": "p5.sound", 22381 "submodule": "p5.sound" 22382 }, { 22383 "file": "lib/addons/p5.sound.js", 22384 "line": 11167, 22385 "description": "<p>length of the loops interval</p>\n", 22386 "itemtype": "property", 22387 "name": "interval", 22388 "type": "Number|String", 22389 "class": "p5.SoundLoop", 22390 "module": "p5.sound", 22391 "submodule": "p5.sound" 22392 }, { 22393 "file": "lib/addons/p5.sound.js", 22394 "line": 11181, 22395 "description": "<p>how many times the callback has been called so far</p>\n", 22396 "itemtype": "property", 22397 "name": "iterations", 22398 "type": "Number", 22399 "readonly": "", 22400 "class": "p5.SoundLoop", 22401 "module": "p5.sound", 22402 "submodule": "p5.sound" 22403 }, { 22404 "file": "lib/addons/p5.sound.js", 22405 "line": 11222, 22406 "description": "<p>The p5.Compressor is built with a <a href=\"https://www.w3.org/TR/webaudio/#the-dynamicscompressornode-interface\" \n target=\"_blank\" title=\"W3 spec for Dynamics Compressor Node\">
22406Web Audio Dynamics Compressor Node\n </a></p>\n", 22407 "itemtype": "property", 22408 "name": "compressor", 22409 "type": "AudioNode", 22410 "class": "p5.Compressor", 22411 "module": "p5.sound", 22412 "submodule": "p5.sound" 22413 }, { 22414 "file": "lib/addons/p5.sound.js", 22415 "line": 11233, 22416 "description": "<p>Performs the same function as .connect, but also accepts\noptional parameters to set compressor's audioParams</p>\n", 22417 "itemtype": "method", 22418 "name": "process", 22419 "params": [{ 22420 "name": "src", 22421 "description": "<p>Sound source to be connected</p>\n", 22422 "type": "Object" 22423 }, { 22424 "name": "attack", 22425 "description": "<p>The amount of time (in seconds) to reduce the gain by 10dB,\n default = .003, range 0 - 1</p>\n", 22426 "type": "Number", 22427 "optional": true 22428 }, { 22429 "name": "knee", 22430 "description": "<p>A decibel value representing the range above the \n threshold where the curve smoothly transitions to the "ratio" portion.\n default = 30, range 0 - 40</p>\n", 22431 "type": "Number", 22432 "optional": true 22433 }, { 22434 "name": "ratio", 22435 "description": "<p>The amount of dB change in input for a 1 dB change in output\n default = 12, range 1 - 20</p>\n", 22436 "type": "Number", 22437 "optional": true 22438 }, { 22439 "name": "threshold", 22440 "description": "<p>The decibel value above which the compression will start taking effect\n default = -24, range -100 - 0</p>\n", 22441 "type": "Number", 22442 "optional": true 22443 }, { 22444 "name": "release", 22445 "description": "<p>The amount of time (in seconds) to increase the gain by 10dB\n default = .25, range 0 - 1</p>\n", 22446 "type": "Number", 22447 "optional": true 22448 }], 22449 "class": "p5.Compressor", 22450 "module": "p5.sound", 22451 "submodule": "p5.sound" 22452 }, { 22453 "file": "lib/addons/p5.sound.js", 22454 "line": 11256, 22455 "description": "<p>Set the paramters of a compressor.</p>\n", 22456 "itemtype": "method", 22457 "name": "set", 22458 "params": [{ 22459 "name": "attack", 22460 "description": "<p>The amount of time (in seconds) to reduce the gain by 10dB,\n default = .003, range 0 - 1</p>\n", 22461 "type": "Number" 22462 }, { 22463 "name": "knee", 22464 "description": "<p>A decibel value representing the range above the \n threshold where the curve smoothly transitions to the "ratio" portion.\n default = 30, range 0 - 40</p>\n", 22465 "type": "Number" 22466 }, { 22467 "name": "ratio", 22468 "description": "<p>The amount of dB change in input for a 1 dB change in output\n default = 12, range 1 - 20</p>\n", 22469 "type": "Number" 22470 }, { 22471 "name": "threshold", 22472 "description": "<p>The decibel value above which the compression will start taking effect\n default = -24, range -100 - 0</p>\n", 22473 "type": "Number" 22474 }, { 22475 "name": "release", 22476 "description": "<p>The amount of time (in seconds) to increase the gain by 10dB\n default = .25, range 0 - 1</p>\n", 22477 "type": "Number" 22478 }], 22479 "class": "p5.Compressor", 22480 "module": "p5.sound", 22481 "submodule": "p5.sound" 22482 }, { 22483 "file": "lib/addons/p5.sound.js", 22484 "line": 11288, 22485 "description": "<p>Get current attack or set value w/ time ramp</p>\n", 22486 "itemtype": "method", 22487 "name": "attack", 22488 "params": [{ 22489 "name": "attack", 22490 "description": "<p>Attack is the amount of time (in seconds) to reduce the gain by 10dB,\n default = .003, range 0 - 1</p>\n", 22491 "type": "Number", 22492 "optional": true 22493 }, { 22494 "name": "time", 22495 "description": "<p>Assign time value to schedule the change in value</p>\n", 22496 "type": "Number", 22497 "optional": true 22498 }], 22499 "class": "p5.Compressor", 22500 "module": "p5.sound", 22501 "submodule": "p5.sound" 22502 }, { 22503 "file": "lib/addons/p5.sound.js", 22504 "line": 11308, 22505 "description": "<p>Get current knee or set value w/ time ramp</p>\n", 22506 "itemtype": "method", 22507 "name": "knee", 22508 "params": [{ 22509 "name": "knee", 22510 "description": "<p>A decibel value representing the range above the \n threshold where the curve smoothly transitions to the "ratio" portion.\n default = 30, range 0 - 40</p>\n", 22511 "type": "Number", 22512 "optional": true 22513 }, { 22514 "name": "time", 22515 "description": "<p>Assign time value to schedule the change in value</p>\n", 22516 "type": "Number", 22517 "optional": true 22518 }], 22519 "class": "p5.Compressor", 22520 "module": "p5.sound", 22521 "submodule": "p5.sound" 22522 }, { 22523 "file": "lib/addons/p5.sound.js", 22524 "line": 11328, 22525 "description": "<p>Get current ratio or set value w/ time ramp</p>\n", 22526 "itemtype": "method", 22527 "name": "ratio", 22528 "params": [{ 22529 "name": "ratio", 22530 "description": "<p>The amount of dB change in input for a 1 dB change in output\n default = 12, range 1 - 20</p>\n", 22531 "type": "Number", 22532 "optional": true 22533 }, { 22534 "name": "time", 22535 "description": "<p>Assign time value to schedule the change in value</p>\n", 22536 "type": "Number", 22537 "optional": true 22538 }], 22539 "class": "p5.Compressor", 22540 "module": "p5.sound", 22541 "submodule": "p5.sound" 22542 }, { 22543 "file": "lib/addons/p5.sound.js", 22544 "line": 11347, 22545 "description": "<p>Get current threshold or set value w/ time ramp</p>\n", 22546 "itemtype": "method", 22547 "name": "threshold", 22548 "params": [{ 22549 "name": "threshold", 22550 "description": "<p>The decibel value above which the compression will start taking effect\n default = -24, range -100 - 0</p>\n", 22551 "type": "Number" 22552 }, { 22553 "name": "time", 22554 "description": "<p>Assign time value to schedule the change in value</p>\n", 22555 "type": "Number", 22556 "optional": true 22557 }], 22558 "class": "p5.Compressor", 22559 "module": "p5.sound", 22560 "submodule": "p5.sound" 22561 }, { 22562 "file": "lib/addons/p5.sound.js", 22563 "line": 11366, 22564 "description": "<p>Get current release or set value w/ time ramp</p>\n", 22565 "itemtype": "method", 22566 "name": "release", 22567 "params": [{ 22568 "name": "release", 22569 "description": "<p>The amount of time (in seconds) to increase the gain by 10dB\n default = .25, range 0 - 1</p>\n", 22570 "type": "Number" 22571 }, { 22572 "name": "time", 22573 "description": "<p>Assign time value to schedule the change in value</p>\n", 22574 "type": "Number", 22575 "optional": true 22576 }], 22577 "class": "p5.Compressor", 22578 "module": "p5.sound", 22579 "submodule": "p5.sound" 22580 }, { 22581 "file": "lib/addons/p5.sound.js", 22582 "line": 11386, 22583 "description": "<p>Return the current reduction value</p>\n", 22584 "itemtype": "method", 22585 "name": "reduction", 22586 "return": { 22587 "description": "Value of the amount of gain reduction that is applied to the signal", 22588 "type": "Number" 22589 }, 22590 "class": "p5.Compressor", 22591 "module": "p5.sound", 22592 "submodule": "p5.sound" 22593 }, { 22594 "file": "lib/addons/p5.sound.js", 22595 "line": 11502, 22596 "description": "<p>Connect a specific device to the p5.SoundRecorder.\nIf no parameter is given, p5.SoundRecorer will record\nall audible p5.sound from your sketch.</p>\n", 22597 "itemtype": "method", 22598 "name": "setInput", 22599 "params": [{ 22600 "name": "unit", 22601 "description": "<p>p5.sound object or a web audio unit\n that outputs sound</p>\n", 22602 "type": "Object", 22603 "optional": true 22604 }], 22605 "class": "p5.SoundRecorder", 22606 "module": "p5.sound", 22607 "submodule": "p5.sound" 22608 }, { 22609 "file": "lib/addons/p5.sound.js", 22610 "line": 11523, 22611 "description": "<p>Start recording. To access the recording, provide\na p5.SoundFile as the first parameter. The p5.SoundRecorder\nwill send its recording to that p5.SoundFile for playback once\nrecording is complete. Optional parameters include duration\n(in seconds) of the recording, and a callback function that\nwill be called once the complete recording has been\ntransfered to the p5.SoundFile.</p>\n", 22612 "itemtype": "method", 22613 "name": "record", 22614 "params": [{ 22615 "name": "soundFile", 22616 "description": "<p>p5.SoundFile</p>\n", 22617 "type": "p5.SoundFile" 22618 }, { 22619 "name": "duration", 22620 "description": "<p>Time (in seconds)</p>\n", 22621 "type": "Number", 22622 "optional": true 22623 }, { 22624 "name": "callback", 22625 "description": "<p>The name of a function that will be\n called once the recording completes</p>\n", 22626 "type": "Function", 22627 "optional": true 22628 }], 22629 "class": "p5.SoundRecorder", 22630 "module": "p5.sound", 22631 "submodule": "p5.sound" 22632 }, { 22633 "file": "lib/addons/p5.sound.js", 22634 "line": 11556, 22635 "description": "<p>Stop the recording. Once the recording is stopped,\nthe results will be sent to the p5.SoundFile that\nwas given on .record(), and if a callback function\nwas provided on record, that function will be called.</p>\n", 22636 "itemtype": "method", 22637 "name": "stop", 22638 "class": "p5.SoundRecorder", 22639 "module": "p5.sound", 22640 "submodule": "p5.sound" 22641 }, { 22642 "file": "lib/addons/p5.sound.js", 22643 "line": 11629, 22644 "description": "<p>Save a p5.SoundFile as a .wav file. The browser will prompt the user\nto download the file to their device.\nFor uploading audio to a server, use\n<a href=\"/docs/reference/#/p5.SoundFile/saveBlob\"><code>p5.SoundFile.saveBlob</code></a>.</p>\n", 22645 "itemtype": "method", 22646 "name": "saveSound", 22647 "params": [{ 22648 "name": "soundFile", 22649 "description": "<p>
22649p5.SoundFile that you wish to save</p>\n", 22650 "type": "p5.SoundFile" 22651 }, { 22652 "name": "fileName", 22653 "description": "<p>name of the resulting .wav file.</p>\n", 22654 "type": "String" 22655 }], 22656 "class": "p5", 22657 "module": "p5.sound", 22658 "submodule": "p5.sound" 22659 }, { 22660 "file": "lib/addons/p5.sound.js", 22661 "line": 11755, 22662 "description": "<p>isDetected is set to true when a peak is detected.</p>\n", 22663 "itemtype": "attribute", 22664 "name": "isDetected", 22665 "type": "Boolean", 22666 "default": "false", 22667 "class": "p5.PeakDetect", 22668 "module": "p5.sound", 22669 "submodule": "p5.sound" 22670 }, { 22671 "file": "lib/addons/p5.sound.js", 22672 "line": 11768, 22673 "description": "<p>The update method is run in the draw loop.</p>\n<p>Accepts an FFT object. You must call .analyze()\non the FFT object prior to updating the peakDetect\nbecause it relies on a completed FFT analysis.</p>\n", 22674 "itemtype": "method", 22675 "name": "update", 22676 "params": [{ 22677 "name": "fftObject", 22678 "description": "<p>A p5.FFT object</p>\n", 22679 "type": "p5.FFT" 22680 }], 22681 "class": "p5.PeakDetect", 22682 "module": "p5.sound", 22683 "submodule": "p5.sound" 22684 }, { 22685 "file": "lib/addons/p5.sound.js", 22686 "line": 11799, 22687 "description": "<p>onPeak accepts two arguments: a function to call when\na peak is detected. The value of the peak,\nbetween 0.0 and 1.0, is passed to the callback.</p>\n", 22688 "itemtype": "method", 22689 "name": "onPeak", 22690 "params": [{ 22691 "name": "callback", 22692 "description": "<p>Name of a function that will\n be called when a peak is\n detected.</p>\n", 22693 "type": "Function" 22694 }, { 22695 "name": "val", 22696 "description": "<p>Optional value to pass\n into the function when\n a peak is detected.</p>\n", 22697 "type": "Object", 22698 "optional": true 22699 }], 22700 "example": ["\n<div><code>\nvar cnv, soundFile, fft, peakDetect;\nvar ellipseWidth = 0;\n\nfunction preload() {\n soundFile = loadSound('assets/beat.mp3');\n}\n\nfunction setup() {\n cnv = createCanvas(100,100);\n textAlign(CENTER);\n\n fft = new p5.FFT();\n peakDetect = new p5.PeakDetect();\n\n setupSound();\n\n // when a beat is detected, call triggerBeat()\n peakDetect.onPeak(triggerBeat);\n}\n\nfunction draw() {\n background(0);\n fill(255);\n text('click to play', width/2, height/2);\n\n fft.analyze();\n peakDetect.update(fft);\n\n ellipseWidth *= 0.95;\n ellipse(width/2, height/2, ellipseWidth, ellipseWidth);\n}\n\n// this function is called by peakDetect.onPeak\nfunction triggerBeat() {\n ellipseWidth = 50;\n}\n\n// mouseclick starts/stops sound\nfunction setupSound() {\n cnv.mouseClicked( function() {\n if (soundFile.isPlaying() ) {\n soundFile.stop();\n } else {\n soundFile.play();\n }\n });\n}\n</code></div>"], 22701 "class": "p5.PeakDetect", 22702 "module": "p5.sound", 22703 "submodule": "p5.sound" 22704 }, { 22705 "file": "lib/addons/p5.sound.js", 22706 "line": 11948, 22707 "description": "<p>Connect a source to the gain node.</p>\n", 22708 "itemtype": "method", 22709 "name": "setInput", 22710 "params": [{ 22711 "name": "src", 22712 "description": "<p>p5.sound / Web Audio object with a sound\n output.</p>\n", 22713 "type": "Object" 22714 }], 22715 "class": "p5.Gain", 22716 "module": "p5.sound", 22717 "submodule": "p5.sound" 22718 }, { 22719 "file": "lib/addons/p5.sound.js", 22720 "line": 11958, 22721 "description": "<p>Send output to a p5.sound or web audio object</p>\n", 22722 "itemtype": "method", 22723 "name": "connect", 22724 "params": [{ 22725 "name": "unit", 22726 "description": "", 22727 "type": "Object" 22728 }], 22729 "class": "p5.Gain", 22730 "module": "p5.sound", 22731 "submodule": "p5.sound" 22732 }, { 22733 "file": "lib/addons/p5.sound.js", 22734 "line": 11968, 22735 "description": "<p>Disconnect all output.</p>\n", 22736 "itemtype": "method", 22737 "name": "disconnect", 22738 "class": "p5.Gain", 22739 "module": "p5.sound", 22740 "submodule": "p5.sound" 22741 }, { 22742 "file": "lib/addons/p5.sound.js", 22743 "line": 11978, 22744 "description": "<p>Set the output level of the gain node.</p>\n", 22745 "itemtype": "method", 22746 "name": "amp", 22747 "params": [{ 22748 "name": "volume", 22749 "description": "<p>amplitude between 0 and 1.0</p>\n", 22750 "type": "Number" 22751 }, { 22752 "name": "rampTime", 22753 "description": "<p>create a fade that lasts rampTime</p>\n", 22754 "type": "Number", 22755 "optional": true 22756 }, { 22757 "name": "timeFromNow", 22758 "description": "<p>schedule this event to happen\n seconds from now</p>\n", 22759 "type": "Number", 22760 "optional": true 22761 }], 22762 "class": "p5.Gain", 22763 "module": "p5.sound", 22764 "submodule": "p5.sound" 22765 }, { 22766 "file": "lib/addons/p5.sound.js", 22767 "line": 12036, 22768 "description": "<p>Connect to p5 objects or Web Audio Nodes</p>\n", 22769 "itemtype": "method", 22770 "name": "connect", 22771 "params": [{ 22772 "name": "unit", 22773 "description": "", 22774 "type": "Object" 22775 }], 22776 "class": "p5.AudioVoice", 22777 "module": "p5.sound", 22778 "submodule": "p5.sound" 22779 }, { 22780 "file": "lib/addons/p5.sound.js", 22781 "line": 12045, 22782 "description": "<p>Disconnect from soundOut</p>\n", 22783 "itemtype": "method", 22784 "name": "disconnect", 22785 "class": "p5.AudioVoice", 22786 "module": "p5.sound", 22787 "submodule": "p5.sound" 22788 }, { 22789 "file": "lib/addons/p5.sound.js", 22790 "line": 12125, 22791 "description": "<p>Play tells the MonoSynth to start playing a note. This method schedules\nthe calling of .triggerAttack and .triggerRelease.</p>\n", 22792 "itemtype": "method", 22793 "name": "play", 22794 "params": [{ 22795 "name": "note", 22796 "description": "<p>the note you want to play, specified as a\n frequency in Hertz (Number) or as a midi\n value in Note/Octave format ("C4", "Eb3"...etc")\n See <a href = \"https://github.com/Tonejs/Tone.js/wiki/Instruments\">\n Tone</a>. Defaults to 440 hz.</p>\n", 22797 "type": "String | Number" 22798 }, { 22799 "name": "velocity", 22800 "description": "<p>velocity of the note to play (ranging from 0 to 1)</p>\n", 22801 "type": "Number", 22802 "optional": true 22803 }, { 22804 "name": "secondsFromNow", 22805 "description": "<p>time from now (in seconds) at which to play</p>\n", 22806 "type": "Number", 22807 "optional": true 22808 }, { 22809 "name": "sustainTime", 22810 "description": "<p>time to sustain before releasing the envelope</p>\n", 22811 "type": "Number", 22812 "optional": true 22813 }], 22814 "example": ["\n<div><code>\nvar monoSynth;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n cnv.mousePressed(playSynth);\n\n monoSynth = new p5.MonoSynth();\n\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n}\n\nfunction playSynth() {\n // time from now (in seconds)\n var time = 0;\n // note duration (in seconds)\n var dur = 1/6;\n // note velocity (volume, from 0 to 1)\n var v = random();\n\n monoSynth.play(\"Fb3\", v, 0, dur);\n monoSynth.play(\"Gb3\", v, time += dur, dur);\n\n background(random(255), random(255), 255);\n text('click to play', width/2, height/2);\n}\n</code></div>\n"], 22815 "class": "p5.MonoSynth", 22816 "module": "p5.sound", 22817 "submodule": "p5.sound" 22818 }, { 22819 "file": "lib/addons/p5.sound.js", 22820 "line": 12173, 22821 "description": "<p>Trigger the Attack, and Decay portion of the Envelope.\nSimilar to holding down a key on a piano, but it will\nhold the sustain level until you let go.</p>\n", 22822 "params": [{ 22823 "name": "note", 22824 "description": "<p>the note you want to play, specified as a\n frequency in Hertz (Number) or as a midi\n value in Note/Octave format ("C4", "Eb3"...etc")\n See <a href = \"https://github.com/Tonejs/Tone.js/wiki/Instruments\">\n Tone</a>. Defaults to 440 hz</p>\n", 22825 "type": "String | Number" 22826 }, { 22827 "name": "velocity", 22828 "description": "<p>velocity of the note to play (ranging from 0 to 1)</p>\n", 22829 "type": "Number", 22830 "optional": true 22831 }, { 22832 "name": "secondsFromNow", 22833 "description": "<p>time from now (in seconds) at which to play</p>\n", 22834 "type": "Number", 22835 "optional": true 22836 }], 22837 "itemtype": "method", 22838 "name": "triggerAttack", 22839 "example": ["\n<div><code>\nvar monoSynth = new p5.MonoSynth();\n\nfunction mousePressed() {\n monoSynth.triggerAttack(\"E3\");\n}\n\nfunction mouseReleased() {\n monoSynth.triggerRelease();\n}\n</code></div>"], 22840 "class": "p5.MonoSynth", 22841 "module": "p5.sound", 22842 "submodule": "p5.sound" 22843 }, { 22844 "file": "lib/addons/p5.sound.js", 22845 "line": 12206, 22846 "description": "<p>Trigger the release of the Envelope. This is similar to releasing\nthe key on a piano and letting the sound fade according to the\nrelease level and release time.</p>\n", 22847 "params": [{ 22848 "name": "secondsFromNow", 22849 "description": "<p>time to trigger the release</p>\n", 22850 "type": "Number" 22851 }], 22852 "itemtype": "method", 22853 "name": "triggerRelease", 22854 "example": ["\n<div><code>\nvar monoSynth = new p5.MonoSynth();\n\nfunction mousePressed() {\n monoSynth.triggerAttack(\"E3\");\n}\n\nfunction mouseReleased() {\n monoSynth.triggerRelease();\n}\n</code></div>"], 22855 "class": "p5.MonoSynth", 22856 "module": "p5.sound", 22857 "submodule": "p5.sound" 22858 }, { 22859 "file": "lib/addons/p5.sound.js", 22860 "line": 12230, 22861 "description": "<p>Set values like a traditional\n<a href=\"https://en.wikipedia.org/wiki/Synthesizer#/media/File:ADSR_parameter.svg\">\nADSR envelope\n</a>.</p>\n", 22862 "itemtype": "method", 22863 "name": "setADSR", 22864 "params": [{ 22865 "name": "attackTime", 22866 "description": "<p>Time (in seconds before envelope\n reaches Attack Level</p>\n", 22867 "type": "Number" 22868 }, { 22869 "name": "decayTime", 22870 "description": "<p>Time (in seconds) before envelope\n reaches Decay/Sustain Level</p>\n", 22871 "type": "Number", 22872 "optional": true 22873 }, { 22874 "name": "susRatio", 22875 "description": "<p>Ratio between attackLevel and releaseLevel, on a scale from 0 to 1,\n where 1.0 = attackLevel, 0.0 = releaseLevel.\n The susRatio determines the decayLevel and the level at which the\n sustain portion of the envelope will sustain.\n For example, if attackLevel is 0.4, releaseLevel is 0,\n and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is\n increased to 1.0 (using <code>setRange</code>),\n then decayLevel would increase proportionally, to become 0.5.</p>\n", 22876 "type": "Number", 22877 "optional": true 22878 }, { 22879 "name": "releaseTime", 22880 "description": "<p>Time in seconds from now (defaults to 0)</p>\n", 22881 "type": "Number", 22882 "optional": true 22883 }], 22884 "class": "p5.MonoSynth", 22885 "module": "p5.sound", 22886 "submodule": "p5.sound" 22887 }, { 22888 "file": "lib/addons/p5.sound.js", 22889 "line": 12254, 22890 "description": "<p>Getters and Setters</p>\n", 22891 "itemtype": "property", 22892 "name": "attack", 22893 "type": "Number", 22894 "class": "p5.MonoSynth", 22895 "module": "p5.sound", 22896 "submodule": "p5.sound" 22897 }, { 22898 "file": "lib/addons/p5.sound.js", 22899 "line": 12258, 22900 "itemtype": "property", 22901 "name": "decay", 22902 "type": "Number", 22903 "class": "p5.MonoSynth", 22904 "module": "p5.sound", 22905 "submodule": "p5.sound" 22906 }, { 22907 "file": "lib/addons/p5.sound.js", 22908 "line": 12261, 22909 "itemtype": "property", 22910 "name": "sustain", 22911 "type": "Number", 22912 "class": "p5.MonoSynth", 22913 "module": "p5.sound", 22914 "submodule": "p5.sound" 22915 }, { 22916 "file": "lib/addons/p5.sound.js", 22917 "line": 12264, 22918 "itemtype": "property", 22919 "name": "release", 22920 "type": "Number", 22921 "class": "p5.MonoSynth", 22922 "module": "p5.sound", 22923 "submodule": "p5.sound" 22924 }, { 22925 "file": "lib/addons/p5.sound.js", 22926 "line": 12301, 22927 "description": "<p>MonoSynth amp</p>\n", 22928 "itemtype": "method", 22929 "name": "amp", 22930 "params": [{ 22931 "name": "vol", 22932 "description": "<p>desired volume</p>\n", 22933 "type": "Number" 22934 }, { 22935 "name": "rampTime", 22936 "description": "<p>Time to reach new volume</p>\n", 22937 "type": "Number", 22938 "optional": true 22939 }], 22940 "return": { 22941 "description": "new volume value", 22942 "type": "Number" 22943 }, 22944 "class": "p5.MonoSynth", 22945 "module": "p5.sound", 22946 "submodule": "p5.sound" 22947 }, { 22948 "file": "lib/addons/p5.sound.js", 22949 "line": 12315, 22950 "description": "<p>Connect to a p5.sound / Web Audio object.</p>\n", 22951 "itemtype": "method", 22952 "name": "connect", 22953 "params": [{ 22954 "name": "unit", 22955 "description": "<p>A p5.sound or Web Audio object</p>\n", 22956 "type": "Object" 22957 }], 22958 "class": "p5.MonoSynth", 22959 "module": "p5.sound", 22960 "submodule": "p5.sound" 22961 }, { 22962 "file": "lib/addons/p5.sound.js", 22963 "line": 12325, 22964 "description": "<p>Disconnect all outputs</p>\n", 22965 "itemtype": "method", 22966 "name": "disconnect", 22967 "class": "p5.MonoSynth", 22968 "module": "p5.sound", 22969 "submodule": "p5.sound" 22970 }, { 22971 "file": "lib/addons/p5.sound.js", 22972 "line": 12335, 22973 "description": "<p>Get rid of the MonoSynth and free up its resources / memory.</p>\n", 22974 "itemtype": "method", 22975 "name": "dispose", 22976 "class": "p5.MonoSynth", 22977 "module": "p5.sound", 22978 "submodule": "p5.sound" 22979 }, { 22980 "file": "lib/addons/p5.sound.js", 22981 "line": 12405, 22982 "description": "<p>An object that holds information about which notes have been played and\nwhich notes are currently being played. New notes are added as keys\non the fly. While a note has been attacked, but not released, the value of the\nkey is the audiovoice which is generating that note. When notes are released,\nthe value of the key becomes undefined.</p>\n", 22983 "itemtype": "property", 22984 "name": "notes", 22985 "class": "p5.PolySynth", 22986 "module": "p5.sound", 22987 "submodule": "p5.sound" 22988 }, { 22989 "file": "lib/addons/p5.sound.js", 22990 "line":
2299012417, 22991 "description": "<p>A PolySynth must have at least 1 voice, defaults to 8</p>\n", 22992 "itemtype": "property", 22993 "name": "polyvalue", 22994 "class": "p5.PolySynth", 22995 "module": "p5.sound", 22996 "submodule": "p5.sound" 22997 }, { 22998 "file": "lib/addons/p5.sound.js", 22999 "line": 12422, 23000 "description": "<p>Monosynth that generates the sound for each note that is triggered. The\np5.PolySynth defaults to using the p5.MonoSynth as its voice.</p>\n", 23001 "itemtype": "property", 23002 "name": "AudioVoice", 23003 "class": "p5.PolySynth", 23004 "module": "p5.sound", 23005 "submodule": "p5.sound" 23006 }, { 23007 "file": "lib/addons/p5.sound.js", 23008 "line": 12453, 23009 "description": "<p>Play a note by triggering noteAttack and noteRelease with sustain time</p>\n", 23010 "itemtype": "method", 23011 "name": "play", 23012 "params": [{ 23013 "name": "note", 23014 "description": "<p>midi note to play (ranging from 0 to 127 - 60 being a middle C)</p>\n", 23015 "type": "Number", 23016 "optional": true 23017 }, { 23018 "name": "velocity", 23019 "description": "<p>velocity of the note to play (ranging from 0 to 1)</p>\n", 23020 "type": "Number", 23021 "optional": true 23022 }, { 23023 "name": "secondsFromNow", 23024 "description": "<p>time from now (in seconds) at which to play</p>\n", 23025 "type": "Number", 23026 "optional": true 23027 }, { 23028 "name": "sustainTime", 23029 "description": "<p>time to sustain before releasing the envelope</p>\n", 23030 "type": "Number", 23031 "optional": true 23032 }], 23033 "example": ["\n<div><code>\nvar polySynth;\n\nfunction setup() {\n var cnv = createCanvas(100, 100);\n cnv.mousePressed(playSynth);\n\n polySynth = new p5.PolySynth();\n\n textAlign(CENTER);\n text('click to play', width/2, height/2);\n}\n\nfunction playSynth() {\n // note duration (in seconds)\n var dur = 0.1;\n\n // time from now (in seconds)\n var time = 0;\n\n // velocity (volume, from 0 to 1)\n var vel = 0.1;\n\n polySynth.play(\"G2\", vel, 0, dur);\n polySynth.play(\"C3\", vel, 0, dur);\n polySynth.play(\"G3\", vel, 0, dur);\n\n background(random(255), random(255), 255);\n text('click to play', width/2, height/2);\n}\n</code></div>"], 23034 "class": "p5.PolySynth", 23035 "module": "p5.sound", 23036 "submodule": "p5.sound" 23037 }, { 23038 "file": "lib/addons/p5.sound.js", 23039 "line": 12499, 23040 "description": "<p>noteADSR sets the envelope for a specific note that has just been triggered.\nUsing this method modifies the envelope of whichever audiovoice is being used\nto play the desired note. The envelope should be reset before noteRelease is called\nin order to prevent the modified envelope from being used on other notes.</p>\n", 23041 "itemtype": "method", 23042 "name": "noteADSR", 23043 "params": [{ 23044 "name": "note", 23045 "description": "<p>Midi note on which ADSR should be set.</p>\n", 23046 "type": "Number", 23047 "optional": true 23048 }, { 23049 "name": "attackTime", 23050 "description": "<p>Time (in seconds before envelope\n reaches Attack Level</p>\n", 23051 "type": "Number", 23052 "optional": true 23053 }, { 23054 "name": "decayTime", 23055 "description": "<p>Time (in seconds) before envelope\n reaches Decay/Sustain Level</p>\n", 23056 "type": "Number", 23057 "optional": true 23058 }, { 23059 "name": "susRatio", 23060 "description": "<p>Ratio between attackLevel and releaseLevel, on a scale from 0 to 1,\n where 1.0 = attackLevel, 0.0 = releaseLevel.\n The susRatio determines the decayLevel and the level at which the\n sustain portion of the envelope will sustain.\n For example, if attackLevel is 0.4, releaseLevel is 0,\n and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is\n increased to 1.0 (using <code>setRange</code>),\n then decayLevel would increase proportionally, to become 0.5.</p>\n", 23061 "type": "Number", 23062 "optional": true 23063 }, { 23064 "name": "releaseTime", 23065 "description": "<p>Time in seconds from now (defaults to 0)</p>\n", 23066 "type": "Number", 23067 "optional": true 23068 }], 23069 "class": "p5.PolySynth", 23070 "module": "p5.sound", 23071 "submodule": "p5.sound" 23072 }, { 23073 "file": "lib/addons/p5.sound.js", 23074 "line": 12527, 23075 "description": "<p>Set the PolySynths global envelope. This method modifies the envelopes of each\nmonosynth so that all notes are played with this envelope.</p>\n", 23076 "itemtype": "method", 23077 "name": "setADSR", 23078 "params": [{ 23079 "name": "attackTime", 23080 "description": "<p>Time (in seconds before envelope\n reaches Attack Level</p>\n", 23081 "type": "Number", 23082 "optional": true 23083 }, { 23084 "name": "decayTime", 23085 "description": "<p>Time (in seconds) before envelope\n reaches Decay/Sustain Level</p>\n", 23086 "type": "Number", 23087 "optional": true 23088 }, { 23089 "name": "susRatio", 23090 "description": "<p>Ratio between attackLevel and releaseLevel, on a scale from 0 to 1,\n where 1.0 = attackLevel, 0.0 = releaseLevel.\n The susRatio determines the decayLevel and the level at which the\n sustain portion of the envelope will sustain.\n For example, if attackLevel is 0.4, releaseLevel is 0,\n and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is\n increased to 1.0 (using <code>setRange</code>),\n then decayLevel would increase proportionally, to become 0.5.</p>\n", 23091 "type": "Number", 23092 "optional": true 23093 }, { 23094 "name": "releaseTime", 23095 "description": "<p>Time in seconds from now (defaults to 0)</p>\n", 23096 "type": "Number", 23097 "optional": true 23098 }], 23099 "class": "p5.PolySynth", 23100 "module": "p5.sound", 23101 "submodule": "p5.sound" 23102 }, { 23103 "file": "lib/addons/p5.sound.js", 23104 "line": 12551, 23105 "description": "<p>Trigger the Attack, and Decay portion of a MonoSynth.\nSimilar to holding down a key on a piano, but it will\nhold the sustain level until you let go.</p>\n", 23106 "itemtype": "method", 23107 "name": "noteAttack", 23108 "params": [{ 23109 "name": "note", 23110 "description": "<p>midi note on which attack should be triggered.</p>\n", 23111 "type": "Number", 23112 "optional": true 23113 }, { 23114 "name": "velocity", 23115 "description": "<p>velocity of the note to play (ranging from 0 to 1)/</p>\n", 23116 "type": "Number", 23117 "optional": true 23118 }, { 23119 "name": "secondsFromNow", 23120 "description": "<p>time from now (in seconds)</p>\n", 23121 "type": "Number", 23122 "optional": true 23123 }], 23124 "example": ["\n<div><code>\nvar polySynth = new p5.PolySynth();\nvar pitches = [\"G\", \"D\", \"G\", \"C\"];\nvar octaves = [2, 3, 4];\n\nfunction mousePressed() {\n // play a chord: multiple notes at the same time\n for (var i = 0; i < 4;
23124 i++) {\n var note = random(pitches) + random(octaves);\n polySynth.noteAttack(note, 0.1);\n }\n}\n\nfunction mouseReleased() {\n // release all voices\n polySynth.noteRelease();\n}\n</code></div>"], 23125 "class": "p5.PolySynth", 23126 "module": "p5.sound", 23127 "submodule": "p5.sound" 23128 }, { 23129 "file": "lib/addons/p5.sound.js", 23130 "line": 12641, 23131 "description": "<p>Trigger the Release of an AudioVoice note. This is similar to releasing\nthe key on a piano and letting the sound fade according to the\nrelease level and release time.</p>\n", 23132 "itemtype": "method", 23133 "name": "noteRelease", 23134 "params": [{ 23135 "name": "note", 23136 "description": "<p>midi note on which attack should be triggered.\n If no value is provided, all notes will be released.</p>\n", 23137 "type": "Number", 23138 "optional": true 23139 }, { 23140 "name": "secondsFromNow", 23141 "description": "<p>time to trigger the release</p>\n", 23142 "type": "Number", 23143 "optional": true 23144 }], 23145 "example": ["\n<div><code>\nvar pitches = [\"G\", \"D\", \"G\", \"C\"];\nvar octaves = [2, 3, 4];\nvar polySynth = new p5.PolySynth();\n\nfunction mousePressed() {\n // play a chord: multiple notes at the same time\n for (var i = 0; i < 4; i++) {\n var note = random(pitches) + random(octaves);\n polySynth.noteAttack(note, 0.1);\n }\n}\n\nfunction mouseReleased() {\n // release all voices\n polySynth.noteRelease();\n}\n</code></div>\n"], 23146 "class": "p5.PolySynth", 23147 "module": "p5.sound", 23148 "submodule": "p5.sound" 23149 }, { 23150 "file": "lib/addons/p5.sound.js", 23151 "line": 12706, 23152 "description": "<p>Connect to a p5.sound / Web Audio object.</p>\n", 23153 "itemtype": "method", 23154 "name": "connect", 23155 "params": [{ 23156 "name": "unit", 23157 "description": "<p>A p5.sound or Web Audio object</p>\n", 23158 "type": "Object" 23159 }], 23160 "class": "p5.PolySynth", 23161 "module": "p5.sound", 23162 "submodule": "p5.sound" 23163 }, { 23164 "file": "lib/addons/p5.sound.js", 23165 "line": 12716, 23166 "description": "<p>Disconnect all outputs</p>\n", 23167 "itemtype": "method", 23168 "name": "disconnect", 23169 "class": "p5.PolySynth", 23170 "module": "p5.sound", 23171 "submodule": "p5.sound" 23172 }, { 23173 "file": "lib/addons/p5.sound.js", 23174 "line": 12726, 23175 "description": "<p>Get rid of the MonoSynth and free up its resources / memory.</p>\n", 23176 "itemtype": "method", 23177 "name": "dispose", 23178 "class": "p5.PolySynth", 23179 "module": "p5.sound", 23180 "submodule": "p5.sound" 23181 }, { 23182 "file": "lib/addons/p5.sound.js", 23183 "line": 12794, 23184 "description": "<p>The p5.Distortion is built with a\n<a href=\"http://www.w3.org/TR/webaudio/#WaveShaperNode\">\nWeb Audio WaveShaper Node</a>.</p>\n", 23185 "itemtype": "property", 23186 "name": "WaveShaperNode", 23187 "type": "AudioNode", 23188 "class": "p5.Distortion", 23189 "module": "p5.sound", 23190 "submodule": "p5.sound" 23191 }, { 23192 "file": "lib/addons/p5.sound.js", 23193 "line": 12809, 23194 "description": "<p>Process a sound source, optionally specify amount and oversample values.</p>\n", 23195 "itemtype": "method", 23196 "name": "process", 23197 "params": [{ 23198 "name": "amount", 23199 "description": "<p>Unbounded distortion amount.\n Normal values range from 0-1.</p>\n", 23200 "type": "Number", 23201 "optional": true, 23202 "optdefault": "0.25" 23203 }, { 23204 "name": "oversample", 23205 "description": "<p>'none', '2x', or '4x'.</p>\n", 23206 "type": "String", 23207 "optional": true, 23208 "optdefault": "'none'" 23209 }], 23210 "class": "p5.Distortion", 23211 "module": "p5.sound", 23212 "submodule": "p5.sound" 23213 }, { 23214 "file": "lib/addons/p5.sound.js", 23215 "line": 12821, 23216 "description": "<p>Set the amount and oversample of the waveshaper distortion.</p>\n", 23217 "itemtype": "method", 23218 "name": "set", 23219 "params": [{ 23220 "name": "amount", 23221 "description": "<p>Unbounded distortion amount.\n Normal values range from 0-1.</p>\n", 23222 "type": "Number", 23223 "optional": true, 23224 "optdefault": "0.25" 23225 }, { 23226 "name": "oversample", 23227 "description": "<p>'none', '2x', or '4x'.</p>\n", 23228 "type": "String", 23229 "optional": true, 23230 "optdefault": "'none'" 23231 }], 23232 "class": "p5.Distortion", 23233 "module": "p5.sound", 23234 "submodule": "p5.sound" 23235 }, { 23236 "file": "lib/addons/p5.sound.js", 23237 "line": 12839, 23238 "description": "<p>Return the distortion amount, typically between 0-1.</p>\n", 23239 "itemtype": "method", 23240 "name": "getAmount", 23241 "return": { 23242 "description": "Unbounded distortion amount.\n Normal values range from 0-1.", 23243 "type": "Number" 23244 }, 23245 "class": "p5.Distortion", 23246 "module": "p5.sound", 23247 "submodule": "p5.sound" 23248 }, { 23249 "file": "lib/addons/p5.sound.js", 23250 "line": 12849, 23251 "description": "<p>Return the oversampling.</p>\n", 23252 "itemtype": "method", 23253 "name": "getOversample", 23254 "return": { 23255 "description": "Oversample can either be 'none', '2x', or '4x'.", 23256 "type": "String" 23257 }, 23258 "class": "p5.Distortion", 23259 "module": "p5.sound", 23260 "submodule": "p5.sound" 23261 }], 23262 "warnings": [{ 23263 "message": "unknown tag: alt", 23264 "line": " src/color/creating_reading.js:16" 23265 }, { 23266 "message": "unknown tag: alt", 23267 "line": " src/color/creating_reading.js:61" 23268 }, { 23269 "message": "unknown tag: alt", 23270 "line": " src/color/creating_reading.js:91"
23271 }, { 23272 "message": "unknown tag: alt", 23273 "line": " src/color/creating_reading.js:121" 23274 }, { 23275 "message": "unknown tag: alt", 23276 "line": " src/color/creating_reading.js:319" 23277 }, { 23278 "message": "unknown tag: alt", 23279 "line": " src/color/creating_reading.js:350" 23280 }, { 23281 "message": "unknown tag: alt", 23282 "line": " src/color/creating_reading.js:387" 23283 }, { 23284 "message": "unknown tag: alt", 23285 "line": " src/color/creating_reading.js:484" 23286 }, { 23287 "message": "unknown tag: alt", 23288 "line": " src/color/creating_reading.js:514" 23289 }, { 23290 "message": "unknown tag: alt", 23291 "line": " src/color/creating_reading.js:554" 23292 }, { 23293 "message": "unknown tag: alt", 23294 "line": " src/color/p5.Color.js:52" 23295 }, { 23296 "message": "unknown tag: alt", 23297 "line": " src/color/p5.Color.js:248" 23298 }, { 23299 "message": "unknown tag: alt", 23300 "line": " src/color/p5.Color.js:275" 23301 }, { 23302 "message": "unknown tag: alt", 23303 "line": " src/color/p5.Color.js:302" 23304 }, { 23305 "message": "unknown tag: alt", 23306 "line": " src/color/p5.Color.js:329" 23307 }, { 23308 "message": "unknown tag: alt", 23309 "line": " src/color/p5.Color.js:763" 23310 }, { 23311 "message": "unknown tag: alt", 23312 "line": " src/color/setting.js:15" 23313 }, { 23314 "message": "unknown tag: alt", 23315 "line": " src/color/setting.js:185" 23316 }, { 23317 "message": "unknown tag: alt", 23318 "line": " src/color/setting.js:223" 23319 }, { 23320 "message": "unknown tag: alt", 23321 "line": " src/color/setting.js:344" 23322 }, { 23323 "message": "unknown tag: alt", 23324 "line": " src/color/setting.js:501" 23325 }, { 23326 "message": "unknown tag: alt", 23327 "line": " src/color/setting.js:542" 23328 }, { 23329 "message": "unknown tag: alt", 23330 "line": " src/color/setting.js:582" 23331 }, { 23332 "message": "unknown tag: alt", 23333 "line": " src/core/shape/2d_primitives.js:16" 23334 }, { 23335 "message": "unknown tag: alt", 23336 "line": " src/core/shape/2d_primitives.js:149" 23337 }, { 23338 "message": "unknown tag: alt", 23339 "line": " src/core/shape/2d_primitives.js:209" 23340 }, { 23341 "message": "unknown tag: alt", 23342 "line": " src/core/shape/2d_primitives.js:239" 23343 }, { 23344 "message": "unknown tag: alt", 23345 "line": " src/core/shape/2d_primitives.js:295" 23346 }, { 23347 "message": "unknown tag: alt", 23348 "line": " src/core/shape/2d_primitives.js:330" 23349 }, { 23350 "message": "unknown tag: alt", 23351 "line": " src/core/shape/2d_primitives.js:384" 23352 }, { 23353 "message": "unknown tag: alt", 23354 "line": " src/core/shape/2d_primitives.js:467" 23355 }, { 23356 "message": "unknown tag: alt", 23357 "line": " src/core/shape/2d_primitives.js:524" 23358 }, { 23359 "message": "unknown tag: alt", 23360 "line": " src/core/shape/attributes.js:14" 23361 }, { 23362 "message": "unknown tag: alt", 23363 "line": " src/core/shape/attributes.js:83" 23364 }, { 23365 "message": "unknown tag: alt", 23366 "line": " src/core/shape/attributes.js:113" 23367 }, { 23368 "message": "unknown tag: alt", 23369 "line": " src/core/shape/attributes.js:182" 23370 }, { 23371 "message": "unknown tag: alt", 23372 "line": " src/core/shape/attributes.js:213" 23373 }, { 23374 "message": "unknown tag: alt", 23375 "line": " src/core/shape/attributes.js:250" 23376 }, { 23377 "message": "unknown tag: alt", 23378 "line": " src/core/shape/attributes.js:317" 23379 }, { 23380 "message": "unknown tag: alt", 23381 "line": " src/core/shape/curves.js:13" 23382 }, { 23383 "message": "unknown tag: alt", 23384 "line": " src/core/shape/curves.js:96" 23385 }, { 23386 "message": "unknown tag: alt", 23387 "line": " src/core/shape/curves.js:139" 23388 }, { 23389 "message": "unknown tag: alt", 23390 "line": " src/core/shape/curves.js:194" 23391 }, { 23392 "message": "unknown tag: alt", 23393 "line": " src/core/shape/curves.js:273" 23394 }, { 23395 "message": "unknown tag: alt", 23396 "line": " src/core/shape/curves.js:364" 23397 }, { 23398 "message": "unknown tag: alt", 23399 "line": " src/core/shape/curves.js:406" 23400 }, { 23401 "message": "unknown tag: alt", 23402 "line": " src/core/shape/curves.js:502" 23403 }, { 23404 "message": "unknown tag: alt", 23405 "line": " src/core/shape/vertex.js:22" 23406 }, { 23407 "message": "unknown tag: alt", 23408 "line": " src/core/shape/vertex.js:70" 23409 }, { 23410 "message": "unknown tag: alt", 23411 "line": " src/core/shape/vertex.js:270" 23412 }, { 23413 "message": "unknown tag: alt", 23414 "line": " src/core/shape/vertex.js:270" 23415 }, { 23416 "message": "unknown tag: alt", 23417 "line": " src/core/shape/vertex.js:270" 23418 }, { 23419 "message": "unknown tag: alt", 23420 "line": " src/core/shape/vertex.js:398" 23421 }, { 23422 "message": "unknown tag: alt", 23423 "line": " src/core/shape/vertex.js:443" 23424 }, { 23425 "message": "unknown tag: alt", 23426 "line": " src/core/shape/vertex.js:508" 23427 }, { 23428 "message": "unknown tag: alt", 23429 "line": " src/core/shape/vertex.js:568" 23430 }, { 23431 "message": "unknown tag: alt", 23432 "line": " src/core/shape/vertex.js:654" 23433 }, { 23434 "message": "unknown tag: alt", 23435 "line": " src/core/shape/vertex.js:720" 23436 }, { 23437 "message": "unknown tag: alt", 23438 "line": " src/core/shape/vertex.js:813" 23439 }, { 23440 "message": "unknown tag: alt", 23441 "line": " src/core/shape/vertex.js:813" 23442 }, { 23443 "message": "unknown tag: alt", 23444 "line": " src/core/shape/vertex.js:813" 23445 }, { 23446 "message": "unknown tag: alt", 23447 "line": " src/core/shape/vertex.js:813" 23448 }, { 23449 "message": "unknown tag: alt", 23450 "line": " src/core/constants.js:58" 23451 }, { 23452 "message": "unknown tag: alt", 23453 "line": " src/core/constants.js:77" 23454 }, { 23455 "message": "unknown tag: alt", 23456 "line": " src/core/constants.js:96" 23457 }, { 23458 "message": "unknown tag: alt", 23459 "line": " src/core/constants.js:115" 23460 }, { 23461 "message": "unknown tag: alt", 23462 "line": " src/core/constants.js:134" 23463 }, { 23464 "message": "unknown tag: alt", 23465 "line": " src/core/environment.js:22" 23466 }, { 23467 "message": "unknown tag: alt", 23468 "line": " src/core/environment.js:53" 23469 }, { 23470 "message": "unknown tag: alt", 23471 "line": " src/core/environment.js:80" 23472 }, { 23473 "message": "unknown tag: alt", 23474 "line": " src/core/environment.js:112" 23475 }, { 23476 "message": "unknown tag: alt", 23477 "line": " src/core/environment.js:181" 23478 }, { 23479 "message": "unknown tag: alt", 23480 "line": " src/core/environment.js:281" 23481 }, { 23482 "message": "unknown tag: alt", 23483 "line": " src/core/environment.js:306" 23484 }, { 23485 "message": "unknown tag: alt", 23486 "line": " src/core/environment.js:325" 23487 }, { 23488 "message": "unknown tag: alt", 23489 "line": " src/core/environment.js:344" 23490 }, { 23491 "message": "unknown tag: alt", 23492 "line": " src/core/environment.js:360" 23493 }, { 23494 "message": "unknown tag: alt", 23495 "line": " src/core/environment.js:376" 23496 }, { 23497 "message": "unknown tag: alt", 23498 "line": " src/core/environment.js:454" 23499 }, { 23500 "message": "unknown tag: alt", 23501 "line": " src/core/environment.js:505" 23502 }, { 23503 "message": "replacing incorrect tag: returns with return", 23504 "line": " src/core/environment.js:540" 23505 }, { 23506 "message": "replacing incorrect tag: returns with return", 23507 "line": " src/core/environment.js:560" 23508 }, { 23509 "message": "unknown tag: alt", 23510 "line": " src/core/environment.js:560" 23511 }, { 23512 "message": "unknown tag: alt", 23513 "line": " src/core/environment.js:617" 23514 }, { 23515 "message": "unknown tag: alt", 23516 "line": " src/core/environment.js:648" 23517 }, { 23518 "message": "unknown tag: alt", 23519 "line": " src/core/environment.js:671" 23520 }, { 23521 "message": "unknown tag: alt", 23522 "line": " src/core/main.js:49" 23523 }, { 23524 "message": "unknown tag: alt", 23525 "line": " src/core/main.js:90" 23526 }, { 23527 "message": "unknown tag: alt", 23528 "line": " src/core/main.js:121" 23529 }, { 23530 "message": "unknown tag: alt", 23531 "line": " src/core/main.js:400" 23532 }, { 23533 "message": "unknown tag: alt", 23534 "line": " src/core/p5.Element.js:52" 23535 }, { 23536 "message": "unknown tag: alt", 23537 "line": " src/core/p5.Element.js:122" 23538 }, { 23539 "message": "unknown tag: alt",
23540 "line": " src/core/p5.Element.js:159" 23541 }, { 23542 "message": "unknown tag: alt", 23543 "line": " src/core/p5.Element.js:194" 23544 }, { 23545 "message": "unknown tag: alt", 23546 "line": " src/core/p5.Element.js:255" 23547 }, { 23548 "message": "unknown tag: alt", 23549 "line": " src/core/p5.Element.js:304" 23550 }, { 23551 "message": "unknown tag: alt", 23552 "line": " src/core/p5.Element.js:370" 23553 }, { 23554 "message": "unknown tag: alt", 23555 "line": " src/core/p5.Element.js:424" 23556 }, { 23557 "message": "unknown tag: alt", 23558 "line": " src/core/p5.Element.js:480" 23559 }, { 23560 "message": "unknown tag: alt", 23561 "line": " src/core/p5.Element.js:538" 23562 }, { 23563 "message": "unknown tag: alt", 23564 "line": " src/core/p5.Element.js:581" 23565 }, { 23566 "message": "unknown tag: alt", 23567 "line": " src/core/p5.Element.js:623" 23568 }, { 23569 "message": "unknown tag: alt", 23570 "line": " src/core/p5.Element.js:671" 23571 }, { 23572 "message": "unknown tag: alt", 23573 "line": " src/core/p5.Element.js:711" 23574 }, { 23575 "message": "unknown tag: alt", 23576 "line": " src/core/p5.Element.js:760" 23577 }, { 23578 "message": "unknown tag: alt", 23579 "line": " src/core/p5.Element.js:798" 23580 }, { 23581 "message": "unknown tag: alt", 23582 "line": " src/core/p5.Element.js:836" 23583 }, { 23584 "message": "unknown tag: alt", 23585 "line": " src/core/p5.Graphics.js:65" 23586 }, { 23587 "message": "unknown tag: alt", 23588 "line": " src/core/rendering.js:17" 23589 }, { 23590 "message": "unknown tag: alt", 23591 "line": " src/core/rendering.js:119" 23592 }, { 23593 "message": "unknown tag: alt", 23594 "line": " src/core/rendering.js:174" 23595 }, { 23596 "message": "unknown tag: alt", 23597 "line": " src/core/rendering.js:197" 23598 }, { 23599 "message": "unknown tag: alt", 23600 "line": " src/core/rendering.js:236" 23601 }, { 23602 "message": "unknown tag: alt", 23603 "line": " src/core/structure.js:12" 23604 }, { 23605 "message": "unknown tag: alt", 23606 "line": " src/core/structure.js:74" 23607 }, { 23608 "message": "unknown tag: alt", 23609 "line": " src/core/structure.js:116" 23610 }, { 23611 "message": "unknown tag: alt", 23612 "line": " src/core/structure.js:181" 23613 }, { 23614 "message": "unknown tag: alt", 23615 "line": " src/core/structure.js:247" 23616 }, { 23617 "message": "unknown tag: alt", 23618 "line": " src/core/transform.js:13" 23619 }, { 23620 "message": "unknown tag: alt", 23621 "line": " src/core/transform.js:135" 23622 }, { 23623 "message": "unknown tag: alt", 23624 "line": " src/core/transform.js:161" 23625 }, { 23626 "message": "unknown tag: alt", 23627 "line": " src/core/transform.js:201" 23628 }, { 23629 "message": "unknown tag: alt", 23630 "line": " src/core/transform.js:231" 23631 }, { 23632 "message": "unknown tag: alt", 23633 "line": " src/core/transform.js:261" 23634 }, { 23635 "message": "unknown tag: alt", 23636 "line": " src/core/transform.js:291" 23637 }, { 23638 "message": "unknown tag: alt", 23639 "line": " src/core/transform.js:366" 23640 }, { 23641 "message": "unknown tag: alt", 23642 "line": " src/core/transform.js:405" 23643 }, { 23644 "message": "unknown tag: alt", 23645 "line": " src/core/transform.js:444" 23646 }, { 23647 "message": "unknown tag: alt", 23648 "line": " src/events/acceleration.js:23" 23649 }, { 23650 "message": "unknown tag: alt", 23651 "line": " src/events/acceleration.js:46" 23652 }, { 23653 "message": "unknown tag: alt", 23654 "line": " src/events/acceleration.js:69" 23655 }, { 23656 "message": "unknown tag: alt", 23657 "line": " src/events/acceleration.js:135" 23658 }, { 23659 "message": "unknown tag: alt", 23660 "line": " src/events/acceleration.js:166" 23661 }, { 23662 "message": "unknown tag: alt", 23663 "line": " src/events/acceleration.js:197" 23664 }, { 23665 "message": "unknown tag: alt", 23666 "line": " src/events/acceleration.js:233" 23667 }, { 23668 "message": "unknown tag: alt", 23669 "line": " src/events/acceleration.js:278" 23670 }, { 23671 "message": "unknown tag: alt", 23672 "line": " src/events/acceleration.js:322" 23673 }, { 23674 "message": "unknown tag: alt", 23675 "line": " src/events/acceleration.js:380" 23676 }, { 23677 "message": "unknown tag: alt", 23678 "line": " src/events/acceleration.js:419" 23679 }, { 23680 "message": "unknown tag: alt", 23681 "line": " src/events/acceleration.js:462" 23682 }, { 23683 "message": "unknown tag: alt", 23684 "line": " src/events/acceleration.js:506" 23685 }, { 23686 "message": "unknown tag: alt", 23687 "line": " src/events/acceleration.js:538" 23688 }, { 23689 "message": "unknown tag: alt", 23690 "line": " src/events/acceleration.js:597" 23691 }, { 23692 "message": "unknown tag: alt", 23693 "line": " src/events/keyboard.js:18" 23694 }, { 23695 "message": "unknown tag: alt", 23696 "line": " src/events/keyboard.js:45" 23697 }, { 23698 "message": "unknown tag: alt", 23699 "line": " src/events/keyboard.js:74" 23700 }, { 23701 "message": "unknown tag: alt", 23702 "line": " src/events/keyboard.js:107" 23703 }, { 23704 "message": "unknown tag: alt", 23705 "line": " src/events/keyboard.js:194" 23706 }, { 23707 "message": "unknown tag: alt", 23708 "line": " src/events/keyboard.js:246" 23709 }, { 23710 "message": "unknown tag: alt", 23711 "line": " src/events/keyboard.js:310" 23712 }, { 23713 "message": "unknown tag: alt", 23714 "line": " src/events/mouse.js:22" 23715 }, { 23716 "message": "unknown tag: alt", 23717 "line": " src/events/mouse.js:48" 23718 }, { 23719 "message": "unknown tag: alt", 23720 "line": " src/events/mouse.js:74" 23721 }, { 23722 "message": "unknown tag: alt", 23723 "line": " src/events/mouse.js:106" 23724 }, { 23725 "message": "unknown tag: alt", 23726 "line": " src/events/mouse.js:137" 23727 }, { 23728 "message": "unknown tag: alt", 23729 "line": " src/events/mouse.js:174" 23730 }, { 23731 "message": "unknown tag: alt", 23732 "line": " src/events/mouse.js:211" 23733 }, { 23734 "message": "unknown tag: alt", 23735 "line": " src/events/mouse.js:252" 23736 }, { 23737 "message": "unknown tag: alt", 23738 "line": " src/events/mouse.js:294" 23739 }, { 23740 "message": "unknown tag: alt", 23741 "line": " src/events/mouse.js:333" 23742 }, { 23743 "message": "unknown tag: alt", 23744 "line": " src/events/mouse.js:424" 23745 }, { 23746 "message": "unknown tag: alt", 23747 "line": " src/events/mouse.js:479" 23748 }, { 23749 "message": "unknown tag: alt", 23750 "line": " src/events/mouse.js:560" 23751 }, { 23752 "message": "unknown tag: alt", 23753 "line": " src/events/mouse.js:637" 23754 }, { 23755 "message": "unknown tag: alt", 23756 "line": " src/events/mouse.js:715" 23757 }, { 23758 "message": "unknown tag: alt", 23759 "line": " src/events/mouse.js:785" 23760 }, { 23761 "message": "unknown tag: alt", 23762 "line": " src/events/mouse.js:870" 23763 }, { 23764 "message": "unknown tag: alt", 23765 "line": " src/events/touch.js:12" 23766 }, { 23767 "message": "unknown tag: alt", 23768 "line": " src/events/touch.js:74" 23769 }, { 23770 "message": "unknown tag: alt", 23771 "line": " src/events/touch.js:149" 23772 }, { 23773 "message": "unknown tag: alt", 23774 "line": " src/events/touch.js:222" 23775 }, { 23776 "message": "unknown tag: alt", 23777 "line": " src/image/image.js:22" 23778 }, { 23779 "message": "unknown tag: alt", 23780 "line": " src/image/image.js:102" 23781 }, { 23782 "message": "unknown tag: alt", 23783 "line": " src/image/image.js:195" 23784 }, { 23785 "message": "unknown tag: alt", 23786 "line": " src/image/loading_displaying.js:17" 23787 }, { 23788 "message": "replacing incorrect tag: returns with return", 23789 "line": " src/image/loading_displaying.js:110" 23790 }, { 23791 "message": "unknown tag: alt", 23792 "line": " src/image/loading_displaying.js:127" 23793 }, { 23794 "message": "unknown tag: alt", 23795 "line": " src/image/loading_displaying.js:298" 23796 }, { 23797 "message": "unknown tag: alt", 23798 "line": " src/image/loading_displaying.js:398" 23799 }, { 23800 "message": "unknown tag: alt", 23801 "line": " src/image/loading_displaying.js:464" 23802 }, { 23803 "message": "unknown tag: alt", 23804 "line": " src/image/p5.Image.js:90" 23805 }, { 23806 "message": "unknown tag: alt", 23807 "line": " src/image/p5.Image.js:117" 23808 }, { 23809 "message": "unknown tag: alt", 23810 "line": " src/image/p5.Image.js:152" 23811 }, { 23812 "message": "unknown tag: alt", 23813 "line": " src/image/p5.Image.js:231" 23814 }, { 23815 "message": "unknown tag: alt", 23816 "line": " src/image/p5.Image.js:267" 23817 }, { 23818 "message": "unknown tag: alt", 23819 "line": " src/image/p5.Image.js:315" 23820 }, { 23821 "message": "unknown tag: alt", 23822 "line": " src/image/p5.Image.js:360" 23823 }, { 23824 "message": "unknown tag: alt", 23825 "line": " src/image/p5.Image.js:398" 23826 }, { 23827 "message": "unknown tag: alt", 23828 "line": " src/image/p5.Image.js:483" 23829 }, { 23830 "message": "unknown tag: alt", 23831 "line": " src/image/p5.Image.js:564" 23832 }, { 23833 "message": "unknown tag: alt", 23834 "line": " src/image/p5.Image.js:627" 23835 }, { 23836 "message": "unknown tag: alt", 23837 "line": " src/image/p5.Image.js:663" 23838 }, { 23839 "message": "unknown tag: alt", 23840 "line": " src/image/p5.Image.js:785" 23841 }, { 23842 "message": "unknown tag: alt", 23843 "line": " src/image/pixels.js:14" 23844 }, { 23845 "message": "unknown tag: alt", 23846 "line": " src/image/pixels.js:83" 23847 }, { 23848 "message": "unknown tag: alt", 23849 "line": " src/image/pixels.js:177" 23850 }, { 23851 "message": "unknown tag: alt", 23852 "line": " src/image/pixels.js:236" 23853 }, { 23854 "message": "unknown tag: alt", 23855 "line": " src/image/pixels.js:415" 23856 }, { 23857 "message": "unknown tag: alt", 23858 "line": " src/image/pixels.js:520" 23859 }, { 23860 "message": "unknown tag: alt", 23861 "line": " src/image/pixels.js:557" 23862 }, { 23863 "message": "unknown tag: alt", 23864 "line": " src/image/pixels.js:631" 23865 }, { 23866 "message": "unknown tag: alt", 23867 "line": " src/io/files.js:19" 23868 }, { 23869 "message": "unknown tag: alt", 23870 "line": " src/io/files.js:180" 23871 }, { 23872 "message": "unknown tag: alt", 23873 "line": " src/io/files.js:293" 23874 }, { 23875 "message": "unknown tag: alt", 23876 "line": " src/io/files.js:603" 23877 }, { 23878 "message": "replacing incorrect tag: returns with return", 23879 "line": " src/io/files.js:714" 23880 }, { 23881 "message": "unknown tag: alt", 23882 "line": " src/io/files.js:714" 23883 }, { 23884 "message": "unknown tag: alt", 23885 "line": " src/io/files.js:1516" 23886 }, { 23887 "message": "unknown tag: alt", 23888 "line": " src/io/files.js:1574" 23889 }, { 23890 "message": "unknown tag: alt", 23891 "line": " src/io/files.js:1642" 23892 }, { 23893 "message": "unknown tag: alt", 23894 "line": " src/io/p5.Table.js:56" 23895 }, { 23896 "message": "unknown tag: alt", 23897 "line": " src/io/p5.Table.js:120" 23898 }, { 23899 "message": "unknown tag: alt", 23900 "line": " src/io/p5.Table.js:168" 23901 }, { 23902 "message": "unknown tag: alt", 23903 "line": " src/io/p5.Table.js:214" 23904 }, { 23905 "message": "unknown tag: alt", 23906 "line": " src/io/p5.Table.js:263" 23907 }, { 23908 "message": "unknown tag: alt", 23909 "line": " src/io/p5.Table.js:328" 23910 }, { 23911 "message": "unknown tag: alt", 23912 "line": " src/io/p5.Table.js:523" 23913 }, { 23914 "message": "unknown tag: alt", 23915 "line": " src/io/p5.Table.js:576" 23916 }, { 23917 "message": "unknown tag: alt", 23918 "line": " src/io/p5.Table.js:618" 23919 }, { 23920 "message": "unknown tag: alt", 23921 "line": " src/io/p5.Table.js:879" 23922 }, { 23923 "message": "unknown tag: alt", 23924 "line": " src/io/p5.Table.js:944" 23925 }, { 23926 "message": "unknown tag: alt", 23927 "line": " src/io/p5.Table.js:994" 23928 }, { 23929 "message": "unknown tag: alt", 23930 "line": " src/io/p5.Table.js:1040" 23931 }, { 23932 "message": "unknown tag: alt", 23933 "line": " src/io/p5.Table.js:1085" 23934 }, { 23935 "message": "unknown tag: alt", 23936 "line": " src/io/p5.Table.js:1132" 23937 }, { 23938 "message": "unknown tag: alt", 23939 "line": " src/io/p5.Table.js:1177" 23940 }, { 23941 "message": "unknown tag: alt", 23942 "line": " src/io/p5.Table.js:1230" 23943 }, { 23944 "message": "unknown tag: alt", 23945 "line": " src/io/p5.Table.js:1296" 23946 }, { 23947 "message": "unknown tag: alt", 23948 "line": " src/io/p5.TableRow.js:42" 23949 }, { 23950 "message": "unknown tag: alt", 23951 "line": " src/io/p5.TableRow.js:106" 23952 }, { 23953 "message": "unknown tag: alt", 23954 "line": " src/io/p5.TableRow.js:150" 23955 }, { 23956 "message": "unknown tag: alt", 23957 "line": " src/io/p5.TableRow.js:195" 23958 }, { 23959 "message": "unknown tag: alt", 23960 "line": " src/io/p5.TableRow.js:243" 23961 }, { 23962 "message": "unknown tag: alt", 23963 "line": " src/io/p5.TableRow.js:299" 23964 }, { 23965 "message": "unknown tag: alt", 23966 "line": " src/io/p5.XML.js:11" 23967 }, { 23968 "message": "unknown tag: alt", 23969 "line": " src/math/calculation.js:12" 23970 }, { 23971 "message": "unknown tag: alt", 23972 "line": " src/math/calculation.js:36" 23973 }, { 23974 "message": "unknown tag: alt", 23975 "line": " src/math/calculation.js:76" 23976 }, { 23977 "message": "unknown tag: alt", 23978 "line": " src/math/calculation.js:121" 23979 }, { 23980 "message": "unknown tag: alt", 23981 "line": " src/math/calculation.js:190" 23982 }, { 23983 "message": "unknown tag: alt", 23984 "line": " src/math/calculation.js:240" 23985 }, { 23986 "message": "unknown tag: alt", 23987 "line": " src/math/calculation.js:279" 23988 }, { 23989 "message": "unknown tag: alt", 23990 "line": " src/math/calculation.js:327" 23991 }, { 23992 "message": "unknown tag: alt", 23993 "line": " src/math/calculation.js:383" 23994 }, { 23995 "message": "unknown tag: alt", 23996 "line": " src/math/calculation.js:422" 23997 }, { 23998 "message": "unknown tag: alt", 23999 "line": " src/math/calculation.js:478" 24000 }, { 24001 "message": "unknown tag: alt", 24002 "line": " src/math/calculation.js:528" 24003 }, { 24004 "message": "unknown tag: alt", 24005 "line": " src/math/calculation.js:578" 24006 }, { 24007 "message": "unknown tag: alt", 24008 "line": " src/math/calculation.js:631" 24009 }, { 24010 "message": "unknown tag: alt", 24011 "line": " src/math/calculation.js:665" 24012 }, { 24013 "message": "unknown tag: alt", 24014 "line": " src/math/calculation.js:704" 24015 }, { 24016 "message": "unknown tag: alt", 24017 "line": " src/math/calculation.js:751" 24018 }, { 24019 "message": "unknown tag: alt", 24020 "line": " src/math/math.js:12" 24021 }, { 24022 "message": "unknown tag: alt", 24023 "line": " src/math/noise.js:40" 24024 }, { 24025 "message": "un
24025known tag: alt", 24026 "line": " src/math/noise.js:187" 24027 }, { 24028 "message": "unknown tag: alt", 24029 "line": " src/math/noise.js:253" 24030 }, { 24031 "message": "unknown tag: alt", 24032 "line": " src/math/p5.Vector.js:12" 24033 }, { 24034 "message": "unknown tag: alt", 24035 "line": " src/math/random.js:48" 24036 }, { 24037 "message": "unknown tag: alt", 24038 "line": " src/math/random.js:79" 24039 }, { 24040 "message": "unknown tag: alt", 24041 "line": " src/math/random.js:166" 24042 }, { 24043 "message": "unknown tag: alt", 24044 "line": " src/math/trigonometry.js:124" 24045 }, { 24046 "message": "unknown tag: alt", 24047 "line": " src/math/trigonometry.js:160" 24048 }, { 24049 "message": "unknown tag: alt", 24050 "line": " src/math/trigonometry.js:188" 24051 }, { 24052 "message": "unknown tag: alt", 24053 "line": " src/math/trigonometry.js:216" 24054 }, { 24055 "message": "unknown tag: alt", 24056 "line": " src/math/trigonometry.js:296" 24057 }, { 24058 "message": "replacing incorrect tag: returns with return", 24059 "line": " src/math/trigonometry.js:332" 24060 }, { 24061 "message": "replacing incorrect tag: returns with return", 24062 "line": " src/math/trigonometry.js:347" 24063 }, { 24064 "message": "replacing incorrect tag: returns with return", 24065 "line": " src/math/trigonometry.js:362" 24066 }, { 24067 "message": "unknown tag: alt", 24068 "line": " src/typography/attributes.js:13" 24069 }, { 24070 "message": "unknown tag: alt", 24071 "line": " src/typography/attributes.js:84" 24072 }, { 24073 "message": "unknown tag: alt", 24074 "line": " src/typography/attributes.js:122" 24075 }, { 24076 "message": "unknown tag: alt", 24077 "line": " src/typography/attributes.js:154" 24078 }, { 24079 "message": "unknown tag: alt", 24080 "line": " src/typography/attributes.js:191" 24081 }, { 24082 "message": "unknown tag: alt", 24083 "line": " src/typography/loading_displaying.js:16" 24084 }, { 24085 "message": "unknown tag: alt", 24086 "line": " src/typography/loading_displaying.js:143" 24087 }, { 24088 "message": "unknown tag: alt", 24089 "line": " src/typography/loading_displaying.js:230" 24090 }, { 24091 "message": "unknown tag: alt", 24092 "line": " src/typography/p5.Font.js:32" 24093 }, { 24094 "message": "unknown tag: alt", 24095 "line": " src/utilities/conversion.js:12" 24096 }, { 24097 "message": "unknown tag: alt", 24098 "line": " src/utilities/string_functions.js:15" 24099 }, { 24100 "message": "unknown tag: alt", 24101 "line": " src/utilities/string_functions.js:44" 24102 }, { 24103 "message": "unknown tag: alt", 24104 "line": " src/utilities/string_functions.js:132" 24105 }, { 24106 "message": "unknown tag: alt", 24107 "line": " src/utilities/string_functions.js:243" 24108 }, { 24109 "message": "unknown tag: alt", 24110 "line": " src/utilities/string_functions.js:319" 24111 }, { 24112 "message": "unknown tag: alt", 24113 "line": " src/utilities/string_functions.js:381" 24114 }, { 24115 "message": "unknown tag: alt", 24116 "line": " src/utilities/string_functions.js:459" 24117 }, { 24118 "message": "unknown tag: alt", 24119 "line": " src/utilities/string_functions.js:548" 24120 }, { 24121 "message": "unknown tag: alt", 24122 "line": " src/utilities/time_date.js:12" 24123 }, { 24124 "message": "unknown tag: alt", 24125 "line": " src/utilities/time_date.js:34" 24126 }, { 24127 "message": "unknown tag: alt", 24128 "line": " src/utilities/time_date.js:56" 24129 }, { 24130 "message": "unknown tag: alt", 24131 "line": " src/utilities/time_date.js:78" 24132 }, { 24133 "message": "unknown tag: alt", 24134 "line": " src/utilities/time_date.js:101" 24135 }, { 24136 "message": "unknown tag: alt", 24137 "line": " src/utilities/time_date.js:123" 24138 }, { 24139 "message": "unknown tag: alt", 24140 "line": " src/utilities/time_date.js:145" 24141 }, { 24142 "message": "unknown tag: alt", 24143 "line": " src/webgl/3d_primitives.js:15" 24144 }, { 24145 "message": "unknown tag: alt", 24146 "line": " src/webgl/interaction.js:13" 24147 }, { 24148 "message": "unknown tag: alt", 24149 "line": " src/webgl/interaction.js:146" 24150 }, { 24151 "message": "unknown tag: alt", 24152 "line": " src/webgl/interaction.js:146" 24153 }, { 24154 "message": "unknown tag: alt", 24155 "line": " src/webgl/interaction.js:146" 24156 }, { 24157 "message": "unknown tag: alt", 24158 "line": " src/webgl/interaction.js:146" 24159 }, { 24160 "message": "unknown tag: alt", 24161 "line": " src/webgl/interaction.js:146" 24162 }, { 24163 "message": "unknown tag: alt", 24164 "line": " src/webgl/interaction.js:380" 24165 }, { 24166 "message": "unknown tag: alt", 24167 "line": " src/webgl/light.js:12" 24168 }, { 24169 "message": "unknown tag: alt", 24170 "line": " src/webgl/light.js:101" 24171 }, { 24172 "message": "unknown tag: alt", 24173 "line": " src/webgl/light.js:212" 24174 }, { 24175 "message": "unknown tag: alt", 24176 "line": " src/webgl/loading.js:14" 24177 }, { 24178 "message": "unknown tag: alt", 24179 "line": " src/webgl/loading.js:14" 24180 }, { 24181 "message": "unknown tag: alt", 24182 "line": " src/webgl/loading.js:244" 24183 }, { 24184 "message": "unknown tag: alt", 24185 "line": " src/webgl/material.js:14" 24186 }, { 24187 "message": "replacing incorrect tag: returns with return", 24188 "line": " src/webgl/material.js:83" 24189 }, { 24190 "message": "unknown tag: alt", 24191 "line": " src/webgl/material.js:83" 24192 }, { 24193 "message": "unknown tag: alt", 24194 "line": " src/webgl/material.js:176" 24195 }, { 24196 "message": "unknown tag: alt", 24197 "line": " src/webgl/material.js:211" 24198 }, { 24199 "message": "unknown tag: alt", 24200 "line": " src/webgl/material.js:302" 24201 }, { 24202 "message": "unknown tag: alt", 24203 "line": " src/webgl/material.js:302" 24204 }, { 24205 "message": "unknown tag: alt", 24206 "line": " src/webgl/material.js:381" 24207 }, { 24208 "message": "unknown tag: alt", 24209 "line": " src/webgl/material.js:430" 24210 }, { 24211 "message": "unknown tag: alt", 24212 "line": " src/webgl/p5.Camera.js:15" 24213 }, { 24214 "message": "unknown tag: alt", 24215 "line": " src/webgl/p5.Camera.js:61" 24216 }, { 24217 "message": "unknown tag: alt", 24218 "line": " src/webgl/p5.Camera.js:126" 24219 }, { 24220 "message": "unknown tag: alt", 24221 "line": " src/webgl/p5.Camera.js:209" 24222 }, { 24223 "message": "unknown tag: alt", 24224 "line": " src/webgl/p5.Camera.js:486" 24225 }, { 24226 "message": "unknown tag: alt", 24227 "line": " src/webgl/p5.Camera.js:545" 24228 }, { 24229 "message": "unknown tag: alt", 24230 "line": " src/webgl/p5.Camera.js:603" 24231 }, { 24232 "message": "unknown tag: alt", 24233 "line": " src/webgl/p5.Camera.js:751" 24234 }, { 24235 "message": "unknown tag: alt", 24236 "line": " src/webgl/p5.Camera.js:823" 24237 }, { 24238 "message": "unknown tag: alt", 24239 "line": " src/webgl/p5.Camera.js:1088" 24240 }, { 24241 "message": "unknown tag: alt", 24242 "line": " src/webgl/p5.RendererGL.js:216" 24243 }, { 24244 "message": "unknown tag: alt", 24245 "line": " src/webgl/p5.RendererGL.js:428" 24246 }, { 24247 "message": "unknown tag: alt", 24248 "line": " src/webgl/p5.RendererGL.js:475" 24249 }, { 24250 "message": "unknown tag: alt", 24251 "line": " src/webgl/p5.RendererGL.js:516" 24252 }, { 24253 "message": "replacing incorrect tag: function with method", 24254 "line": " src/webgl/text.js:117" 24255 }, { 24256 "message": "replacing incorrect tag: returns with return", 24257 "line": " src/webgl/text.js:160" 24258 }, { 24259 "message": "replacing incorrect tag: function with method", 24260 "line": " src/webgl/text.js:193" 24261 }, { 24262 "message": "replacing incorrect tag: function with method", 24263 "line": " src/webgl/text.js:205" 24264 }, { 24265 "message": "replacing incorrect tag: function with method", 24266 "line": " src/webgl/text.js:235" 24267 }, { 24268 "message": "replacing incorrect tag: function with method", 24269 "line": " src/webgl/text.js:249" 24270 }, { 24271 "message": "replacing incorrect tag: function with method", 24272 "line": " src/webgl/text.js:387" 24273 }, { 24274 "message": "replacing incorrect tag: returns with return", 24275 "line": " src/webgl/text.js:387" 24276 }, { 24277 "message": "replacing incorrect tag: function with method", 24278 "line": " src/webgl/text.js:457" 24279 }, { 24280 "message": "replacing incorrect tag: function with method", 24281 "line": " src/webgl/text.js:472" 24282 }, { 24283 "message": "replacing incorrect tag: function with method", 24284 "line": " src/webgl/text.js:547" 24285 }, { 24286 "message": "unknown tag: alt", 24287 "line": " lib/addons/p5.dom.js:245" 24288 }, { 24289 "message": "unknown tag: alt", 24290 "line": " lib/addons/p5.dom.js:313" 24291 }, { 24292 "message": "replacing incorrect tag: returns with return", 24293 "line": " lib/addons/p5.dom.js:1453" 24294 }, { 24295 "message": "replacing incorrect tag: returns with return", 24296 "line": " lib/addons/p5.dom.js:1557" 24297 }, { 24298 "message": "replacing incorrect tag: returns with return", 24299 "line": " lib/addons/p5.dom.js:1596" 24300 }, { 24301 "message": "replacing incorrect tag: returns with return", 24302 "line": " lib/addons/p5.dom.js:1690" 24303 }, { 24304 "message": "replacing incorrect tag: params with param", 24305 "line": " lib/addons/p5.sound.js:1854" 24306 }, { 24307 "message": "replacing incorrect tag: returns with return", 24308 "line": " lib/addons/p5.sound.js:1854" 24309 }, { 24310 "message": "replacing incorrect tag: returns with return", 24311 "line": " lib/addons/p5.sound.js:2473" 24312 }, { 24313 "message": "replacing incorrect tag: returns with return", 24314 "line": " lib/addons/p5.sound.js:7653" 24315 }, { 24316 "message": "replacing incorrect tag: returns with return", 24317 "line": " lib/addons/p5.sound.js:9620" 24318 }, { 24319 "message": "Missing item type\nConversions adapted from <http://www.easyrgb.com/en/math.php>.\n\nIn these functions, hue is always in the range [0, 1], just like all other\ncomponents are in the range [0, 1]. 'Brightness' and 'value' are used\ninterchangeably.", 24320 "line": " src/color/color_conversion.js:10" 24321 }, { 24322 "message": "Missing item type\nConvert an HSBA array to HSLA.", 24323 "line": " src/color/color_conversion.js:21" 24324 }, { 24325 "message": "Missing item type\nConvert an HSBA array to RGBA.", 24326 "line": " src/color/color_conversion.js:47" 24327 }, { 24328 "message": "Missing item type\nConvert an HSLA array to HSBA.", 24329 "line": " src/color/color_conversion.js:102" 24330 }, { 24331 "message": "Missing item type\nConvert an HSLA array to RGBA.\n\nWe need to change basis from HSLA to something that can be more easily be\nprojected onto RGBA. We will choose hue and brightness as our first two\ncomponents, and pick a convenient third one ('zest') so that we don't need\nto calculate formal HSBA saturation.", 24332 "line": " src/color/color_conversion.js:125" 24333 }, { 24334 "message": "Missing item type\nConvert an RGBA array to HSBA.", 24335 "line": " src/color/color_conversion.js:189" 24336 }, { 24337 "message": "Missing item type\nConvert an RGBA array to HSLA.", 24338 "line": " src/color/color_conversion.js:228" 24339 }, { 24340 "message": "Missing item type\nHue is the same in HSB and HSL, but the maximum value may be different.\nThis function will return the HSB-normalized saturation when supplied with\nan HSB color object, but will default to the HSL-normalized saturation\notherwise.", 24341 "line": " src/color/p5.Color.js:410" 24342 }, { 24343 "message": "Missing item type\nSaturation is scaled differently in HSB and HSL. This function will return\nthe HSB saturation when supplied with an HSB color object, but will default\nto the HSL saturation otherwise.", 24344 "line": " src/color/p5.Color.js:441" 24345 }, { 24346 "message": "Missing item type\nCSS named colors.", 24347 "line": " src/color/p5.Color.js:460" 24348 }, { 24349 "message": "Missing item type\nThese regular expressions are used to build up the patterns for matching\nviable CSS color strings: fragmenting the regexes in this way increases the\nlegibility and comprehensibility of the code.\n\nNote that RGB values of .9 are not parsed by IE, but are supported here for\ncolor string consistency.", 24350 "line": " src/color/p5.Color.js:613" 24351 }, { 24352 "message": "Missing item type\nFull color string patterns. The capture groups are necessary.", 24353 "line": " src/color/p5.Color.js:626" 24354 }, { 24355 "message": "Missing item type\nFor a number of different inputs, returns a color formatted as [r, g, b, a]\narrays, with each component normalized between 0 and 1.", 24356 "line": " src/color/p5.Color.js:763" 24357 }, { 24358 "message": "Missing item type\nFor HSB and HSL, interpret the gray level as a brightness/lightness\nvalue (they are equivalent when chroma is zero). For RGB, normalize the\ngray level according to the blue maximum.", 24359 "line": " src/color/p5.Color.js:989" 24360 }, { 24361 "message": "Missing item type\nReturns the current framerate.", 24362 "line": " src/core/environment.js:255" 24363 }, { 24364 "message": "Missing item type\nSpecifies the number of frames to be displayed every second. For example,\nthe function call frameRate(30) will attempt to refresh 30 times a second.\nIf the processor is not fast enough to maintain the specified rate, the\nframe rate will not be achieved. Setting the frame rate within <a href=\"#/p5/setup\">setup()</a> is\nrecommended. The default rate is 60 frames per second.\n\nCalling <a href=\"#/p5/frameRate\">frameRate()</a> with no arguments returns the current framerate.", 24365 "line": " src/core/environment.js:265" 24366 }, { 24367 "message": "Missing item type", 24368 "line": " src/core/error_helpers.js:1" 24369 }, { 24370 "message": "Missing item type\nValidates parameters\nparam {String} func the name of the function\nparam {Array} args user input arguments\n\nexample:\n var a;\n ellipse(10,10,a,5);\nconsole ouput:\n \"It looks like ellipse received an empty variable in spot #2.\"\n\nexample:\n ellipse(10,\"foo\",5,5);\nconsole output:\n \"ellipse was expecting a number for parameter #1,\n received \"foo\" instead.\"", 24371 "line": " src/core/error_helpers.js:584" 24372 }, { 24373 "message": "Missing item type\nPrints out all the colors in the color pallete with white text.\nFor color blindness testing.", 24374 "line": " src/core/error_helpers.js:645" 24375 }, { 24376 "message": "Missing item type", 24377 "line": " src/core/helpers.js:1" 24378 }, { 24379 "message": "Missing item type\n_globalInit\n\nTODO: ???\nif sketch is on window\nassume \"global\" mode\nand instantiate p5 automatically\notherwise do nothing", 24380 "line": " src/core/init.js:5" 24381 }, { 24382 "message": "Missing item type", 24383 "line": " src/core/legacy.js:1" 24384 }, { 24385 "message": "Missing item type\nHelper fxn for sharing pixel methods", 24386 "line": " src/core/p5.Element.js:969" 24387 }, { 24388 "message": "Missing item type\nResize our canvas element.", 24389 "line": " src/core/p5.Renderer.js:96" 24390 }, { 24391 "message": "Missing item type\nHelper fxn to check font type (syste
24391m or otf)", 24392 "line": " src/core/p5.Renderer.js:301" 24393 }, { 24394 "message": "Missing item type\nHelper fxn to measure ascent and descent.\nAdapted from http://stackoverflow.com/a/25355178", 24395 "line": " src/core/p5.Renderer.js:354" 24396 }, { 24397 "message": "Missing item type\np5.Renderer2D\nThe 2D graphics canvas renderer class.\nextends p5.Renderer", 24398 "line": " src/core/p5.Renderer2D.js:9" 24399 }, { 24400 "message": "Missing item type\nGenerate a cubic Bezier representing an arc on the unit circle of total\nangle `size` radians, beginning `start` radians above the x-axis. Up to\nfour of these curves are combined to make a full arc.\n\nSee www.joecridge.me/bezier.pdf for an explanation of the method.", 24401 "line": " src/core/p5.Renderer2D.js:392" 24402 }, { 24403 "message": "Missing item type\nshim for Uint8ClampedArray.slice\n(allows arrayCopy to work with pixels[])\nwith thanks to http://halfpapstudios.com/blog/tag/html5-canvas/\nEnumerable set to false to protect for...in from\nUint8ClampedArray.prototype pollution.", 24404 "line": " src/core/shim.js:23" 24405 }, { 24406 "message": "Missing item type\nthis is implementation of Object.assign() which is unavailable in\nIE11 and (non-Chrome) Android browsers.\nThe assign() method is used to copy the values of all enumerable\nown properties from one or more source objects to a target object.\nIt will return the target object.\nModified from https://github.com/ljharb/object.assign", 24407 "line": " src/core/shim.js:45" 24408 }, { 24409 "message": "Missing item type\nprivate helper function to handle the user passing in objects\nduring construction or calls to create()", 24410 "line": " src/data/p5.TypedDict.js:203" 24411 }, { 24412 "message": "Missing item type\nprivate helper function to ensure that the user passed in valid\nvalues for the Dictionary type", 24413 "line": " src/data/p5.TypedDict.js:394" 24414 }, { 24415 "message": "Missing item type\nprivate helper function to ensure that the user passed in valid\nvalues for the Dictionary type", 24416 "line": " src/data/p5.TypedDict.js:437" 24417 }, { 24418 "message": "Missing item type\nprivate helper function for finding lowest or highest value\nthe argument 'flip' is used to flip the comparison arrow\nfrom 'less than' to 'greater than'", 24419 "line": " src/data/p5.TypedDict.js:554" 24420 }, { 24421 "message": "Missing item type\nprivate helper function for finding lowest or highest key\nthe argument 'flip' is used to flip the comparison arrow\nfrom 'less than' to 'greater than'", 24422 "line": " src/data/p5.TypedDict.js:621" 24423 }, { 24424 "message": "Missing item type\n_updatePAccelerations updates the pAcceleration values", 24425 "line": " src/events/acceleration.js:124" 24426 }, { 24427 "message": "Missing item type\nHolds the key codes of currently pressed keys.", 24428 "line": " src/events/keyboard.js:12" 24429 }, { 24430 "message": "Missing item type\nThe onblur function is called when the user is no longer focused\non the p5 element. Because the keyup events will not fire if the user is\nnot focused on the element we must assume all keys currently down have\nbeen released.", 24431 "line": " src/events/keyboard.js:300" 24432 }, { 24433 "message": "Missing item type\nThe checkDownKeys function returns a boolean true if any keys pressed\nand a false if no keys are currently pressed.\n\nHelps avoid instances where a multiple keys are pressed simultaneously and\nreleasing a single key will then switch the\nkeyIsPressed property to true.", 24434 "line": " src/events/keyboard.js:387" 24435 }, { 24436 "message": "Missing item type\nThis module defines the filters for use with image buffers.\n\nThis module is basically a collection of functions stored in an object\nas opposed to modules. The functions are destructive, modifying\nthe passed in canvas rather than creating a copy.\n\nGenerally speaking users of this module will use the Filters.apply method\non a canvas to create an effect.\n\nA number of functions are borrowed/adapted from\nhttp://www.html5rocks.com/en/tutorials/canvas/imagefilters/\nor the java processing implementation.", 24437 "line": " src/image/filters.js:3" 24438 }, { 24439 "message": "Missing item type\nReturns the pixel buffer for a canvas", 24440 "line": " src/image/filters.js:26" 24441 }, { 24442 "message": "Missing item type\nReturns a 32 bit number containing ARGB data at ith pixel in the\n1D array containing pixels data.", 24443 "line": " src/image/filters.js:46" 24444 }, { 24445 "message": "Missing item type\nModifies pixels RGBA values to values contained in the data object.", 24446 "line": " src/image/filters.js:67" 24447 }, { 24448 "message": "Missing item type\nReturns the ImageData object for a canvas\nhttps://developer.mozilla.org/en-US/docs/Web/API/ImageData", 24449 "line": " src/image/filters.js:87" 24450 }, { 24451 "message": "Missing item type\nReturns a blank ImageData object.", 24452 "line": " src/image/filters.js:107" 24453 }, { 24454 "message": "Missing item type\nApplys a filter function to a canvas.\n\nThe difference between this and the actual filter functions defined below\nis that the filter functions generally modify the pixel buffer but do\nnot actually put that data back to the canvas (where it would actually\nupdate what is visible). By contrast this method does make the changes\nactually visible in the canvas.\n\nThe apply method is the method that callers of this module would generally\nuse. It has been separated from the actual filters to
24454support an advanced\nuse case of creating a filter chain that executes without actually updating\nthe canvas in between everystep.", 24455 "line": " src/image/filters.js:122" 24456 }, { 24457 "message": "Missing item type\nConverts the image to black and white pixels depending if they are above or\nbelow the threshold defined by the level parameter. The parameter must be\nbetween 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is used.\n\nBorrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/", 24458 "line": " src/image/filters.js:159" 24459 }, { 24460 "message": "Missing item type\nConverts any colors in the image to grayscale equivalents.\nNo parameter is used.\n\nBorrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/", 24461 "line": " src/image/filters.js:193" 24462 }, { 24463 "message": "Missing item type\nSets the alpha channel to entirely opaque. No parameter is used.", 24464 "line": " src/image/filters.js:216" 24465 }, { 24466 "message": "Missing item type\nSets each pixel to its inverse value. No parameter is used.", 24467 "line": " src/image/filters.js:232" 24468 }, { 24469 "message": "Missing item type\nLimits each channel of the image to the number of colors specified as\nthe parameter. The parameter can be set to values between 2 and 255, but\nresults are most noticeable in the lower ranges.\n\nAdapted from java based processing implementation", 24470 "line": " src/image/filters.js:247" 24471 }, { 24472 "message": "Missing item type\nreduces the bright areas in an image", 24473 "line": " src/image/filters.js:279" 24474 }, { 24475 "message": "Missing item type\nincreases the bright areas in an image", 24476 "line": " src/image/filters.js:367" 24477 }, { 24478 "message": "Missing item type\nThis module defines the p5 methods for the <a href=\"#/p5.Image\">p5.Image</a> class\nfor drawing images to the main display canvas.", 24479 "line": " src/image/image.js:8" 24480 }, { 24481 "message": "Missing item type\nValidates clipping params. Per drawImage spec sWidth and sHight cannot be\nnegative or greater than image intrinsic width and height", 24482 "line": " src/image/loading_displaying.js:110" 24483 }, { 24484 "message": "Missing item type\nApply the current tint color to the input image, return the resulting\ncanvas.", 24485 "line": " src/image/loading_displaying.js:427" 24486 }, { 24487 "message": "Missing item type\nThis module defines the <a href=\"#/p5.Image\">p5.Image</a> class and P5 methods for\ndrawing images to the main display canvas.", 24488 "line": " src/image/p5.Image.js:9" 24489 }, { 24490 "message": "Missing item type\nHelper fxn for sharing pixel methods", 24491 "line": " src/image/p5.Image.js:222" 24492 }, { 24493 "message": "Missing item type\nGenerate a blob of file data as a url to prepare for download.\nAccepts an array of data, a filename, and an extension (optional).\nThis is a private function because it does not do any formatting,\nbut it is used by <a href=\"#/p5/saveStrings\">saveStrings</a>, <a href=\"#/p5/saveJSON\">saveJSON</a>, <a href=\"#/p5/saveTable\">saveTable</a> etc.", 24494 "line": " src/io/files.js:1768" 24495 }, { 24496 "message": "Missing item type\nReturns a file extension, or another string\nif the provided parameter has no extension.", 24497 "line": " src/io/files.js:1837" 24498 }, { 24499 "message": "Missing item type\nReturns true if the browser is Safari, false if not.\nSafari makes trouble for downloading files.", 24500 "line": " src/io/files.js:1870" 24501 }, { 24502 "message": "Missing item type\nHelper function, a callback for download that deletes\nan invisible anchor element from the DOM once the file\nhas been automatically downloaded.", 24503 "line": " src/io/files.js:1882" 24504 }, { 24505 "message": "Missing item type\nTable Options\n<p>Generic class for handling tabular data, typically from a\nCSV, TSV, or other sort of spreadsheet file.</p>\n<p>CSV files are\n<a href=\"http://en.wikipedia.org/wiki/Comma-separated_values\">\ncomma separated values</a>, often with the data in quotes. TSV\nfiles use tabs as separators, and usually don't bother with the\nquotes.</p>\n<p>File names should end with .csv if they're comma separated.</p>\n<p>A rough \"spec\" for CSV can be found\n<a href=\"http://tools.ietf.org/html/rfc4180\">here</a>.</p>\n<p>To load files, use the <a href=\"#/p5/loadTable\">loadTable</a> method.</p>\n<p>To save tables to your computer, use the <a href=\"#/p5/save\">save</a> method\n or the <a href=\"#/p5/saveTable\">saveTable</a> method.</p>\n\nPossible options include:\n<ul>\n<li>csv - parse the table as comma-separated values\n<li>tsv - parse the table as tab-separated values\n<li>header - this table has a header (title) row\n</ul>", 24506 "line": " src/io/p5.Table.js:11" 24507 }, { 24508 "message": "Missing item type\nMultiplies a vector by a scalar and returns a new vector.", 24509 "line": " src/math/p5.Vector.js:1611" 24510 }, { 24511 "message": "Missing item type\nDivides a vector by a scalar and returns a new vector.", 24512 "line": " src/math/p5.Vector.js:1638" 24513 }, { 24514 "message": "Missing item type\nCalculates the dot product of two vectors.", 24515 "line": " src/math/p5.Vector.js:1665" 24516 }, { 24517 "message": "Missing item type\nCalculates the cross product of two vectors.", 24518 "line": " src/math/p5.Vector.js:1679" 24519 }, { 24520 "message": "Missing item type\nCalculates the Euclidean distance between two points (considering a\npoint as a vector object).", 24521 "line": " src/math/p5.Vector.js:1693" 24522 }, { 24523 "message": "Missing item type\nLinear interpolate a vector to another vector and return the result as a\nne
24523w vector.", 24524 "line": " src/math/p5.Vector.js:1708" 24525 }, { 24526 "message": "Missing item type\nHelper function to measure ascent and descent.", 24527 "line": " src/typography/attributes.js:284" 24528 }, { 24529 "message": "Missing item type\nReturns the set of opentype glyphs for the supplied string.\n\nNote that there is not a strict one-to-one mapping between characters\nand glyphs, so the list of returned glyphs can be larger or smaller\n than the length of the given string.", 24530 "line": " src/typography/p5.Font.js:255" 24531 }, { 24532 "message": "Missing item type\nReturns an opentype path for the supplied string and position.", 24533 "line": " src/typography/p5.Font.js:270" 24534 }, { 24535 "message": "Missing item type", 24536 "line": " src/webgl/3d_primitives.js:259" 24537 }, { 24538 "message": "Missing item type\nDraws a point, a coordinate in space at the dimension of one pixel,\ngiven x, y and z coordinates. The color of the point is determined\nby the current stroke, while the point size is determined by current\nstroke weight.", 24539 "line": " src/webgl/3d_primitives.js:745" 24540 }, { 24541 "message": "Missing item type\nDraw a line given two points", 24542 "line": " src/webgl/3d_primitives.js:1162" 24543 }, { 24544 "message": "Missing item type\nParse OBJ lines into model. For reference, this is what a simple model of a\nsquare might look like:\n\nv -0.5 -0.5 0.5\nv -0.5 -0.5 -0.5\nv -0.5 0.5 -0.5\nv -0.5 0.5 0.5\n\nf 4 3 2 1", 24545 "line": " src/webgl/loading.js:135" 24546 }, { 24547 "message": "Missing item type", 24548 "line": " src/webgl/material.js:479" 24549 }, { 24550 "message": "Missing item type\nCreate a 2D array for establishing stroke connections", 24551 "line": " src/webgl/p5.Geometry.js:190" 24552 }, { 24553 "message": "Missing item type\nCreate 4 vertices for each stroke line, two at the beginning position\nand two at the end position. These vertices are displaced relative to\nthat line's normal on the GPU", 24554 "line": " src/webgl/p5.Geometry.js:211" 24555 }, { 24556 "message": "Missing item type", 24557 "line": " src/webgl/p5.Matrix.js:1" 24558 }, { 24559 "message": "Missing item type\nPRIVATE", 24560 "line": " src/webgl/p5.Matrix.js:671" 24561 }, { 24562 "message": "Missing item type\nWelcome to RendererGL Immediate Mode.\nImmediate mode is used for drawing custom shapes\nfrom a set of vertices. Immediate Mode is activated\nwhen you call <a href=\"#/p5/beginShape\">beginShape()</a> & de-activated when you call <a href=\"#/p5/endShape\">endShape()</a>.\nImmediate mode is a style of programming borrowed\nfrom OpenGL's (now-deprecated) immediate mode.\nIt differs from p5.js' default, Retained Mode, which caches\ngeometries and buffers on the CPU to reduce the number of webgl\ndraw calls. Retained mode is more efficient & performative,\nhowever, Immediate Mode is useful for sketching quick\ngeometric ideas.", 24563 "line": " src/webgl/p5.RendererGL.Immediate.js:1" 24564 }, { 24565 "message": "Missing item type\nEnd shape drawing and render vertices to screen.", 24566 "line": " src/webgl/p5.RendererGL.Immediate.js:132" 24567 }, { 24568 "message": "Missing item type\ninitializes buffer defaults. runs each time a new geometry is\nregistered", 24569 "line": " src/webgl/p5.RendererGL.Retained.js:8" 24570 }, { 24571 "message": "Missing item type\ncreateBuffers description", 24572 "line": " src/webgl/p5.RendererGL.Retained.js:47" 24573 }, { 24574 "message": "Missing item type\nDraws buffers given a geometry key ID", 24575 "line": " src/webgl/p5.RendererGL.Retained.js:191" 24576 }, { 24577 "message": "Missing item type\nmodel view, projection, & normal\nmatrices", 24578 "line": " src/webgl/p5.RendererGL.js:83" 24579 }, { 24580 "message": "Missing item type\n[background description]", 24581 "line": " src/webgl/p5.RendererGL.js:406" 24582 }, { 24583 "message": "Missing item type\n[resize description]", 24584 "line": " src/webgl/p5.RendererGL.js:676" 24585 }, { 24586 "message": "Missing item type\nclears color and depth buffers\nwith r,g,b,a", 24587 "line": " src/webgl/p5.RendererGL.js:702" 24588 }, { 24589 "message": "Missing item type\n[translate description]", 24590 "line": " src/webgl/p5.RendererGL.js:720" 24591 }, { 24592 "message": "Missing item type\nScales the Model View Matrix by a vector", 24593 "line": " src/webgl/p5.RendererGL.js:739" 24594 }, { 24595 "message": "Missing item type\nturn a two dimensional array into one dimensional array", 24596 "line": " src/webgl/p5.RendererGL.js:1060" 24597 }, { 24598 "message": "Missing item type\nturn a p5.Vector Array into a one dimensional number array", 24599 "line": " src/webgl/p5.RendererGL.js:1097" 24600 }, { 24601 "message": "Missing item type\nensures that p5 is using a 3d renderer. throws an error if not.", 24602 "line": " src/webgl/p5.RendererGL.js:1113" 24603 }, { 24604 "message": "Missing item type\nHelper function for select and selectAll", 24605 "line": " lib/addons/p5.dom.js:168" 24606 }, { 24607 "message": "Missing item type\nHelper function for getElement and getElements.", 24608 "line": " lib/addons/p5.dom.js:184" 24609 }, { 24610 "message": "Missing item type\nHelpers for create methods.", 24611 "line": " lib/addons/p5.dom.js:348" 24612 }, { 24613 "message": "Missing item type", 24614 "line": " lib/addons/p5.dom.js:487" 24615 }, { 24616 "message": "Missing item type", 24617 "line": " lib/addons/p5.dom.js:1066" 24618 }, { 24619 "message": "Missing item type", 24620 "line": " lib/addons/p5.dom.js:1147" 24621 }, { 24622 "message": "Missing item type", 24623 "line": " lib/addons/p5.dom.js:1187" 24624 }, { 24625 "message": "Missing item type", 24626 "line": " lib/addons/p5.dom.js:2864" 24627 }, { 24628 "message": "Missing item type", 24629 "line": " lib/addons/p5.dom.js:2930" 24630 }, { 24631 "message": "Missing item type", 24632 "line": " lib/addons/p5.dom.js:2992" 24633 }, { 24634 "message": "Missing item type\np5.sound \nhttps://p5js.org/reference/#/libraries/p5.sound\n\nFrom the Processing Foundation and contributors\nhttps://github.com/processing/p5.js-sound/graphs/contributors\n\nMIT License (MIT)\nhttps://github.com/processing/p5.js-sound/blob/master/LICENSE\n\nSome of the many audio libraries & resources that inspire p5.sound:\n - TONE.js (c) Yotam Mann. Licensed under The MIT License (MIT). https://github.com/TONEnoTONE/Tone.js\n - buzz.js (c) Jay Salvat. Licensed under The MIT License (MIT). http://buzz.jaysalvat.com/\n - Boris Smus Web Audio API book, 2013. Licensed under the Apache License http://www.apache.org/licenses/LICENSE-2.0\n - wavesurfer.js https://github.com/katspaugh/wavesurfer.js\n - Web Audio Components by Jordan Santell https://github.com/web-audio-components\n - Wilm Thoben's Sound library for Processing https://github.com/processing/processing/tree/master/java/libraries/sound\n\n Web Audio API: http://w3.org/TR/webaudio/", 24635 "line": " lib/addons/p5.sound.js:46" 24636 }, { 24637 "message": "Missing item type\nDetermine which filetypes are supported (inspired by buzz.js)\nThe audio element (el) will only be used to test browser support for various audio formats", 24638 "line": " lib/addons/p5.sound.js:214" 24639 }, { 24640 "message": "Missing item type\nMaster contains AudioContext and the master sound output.", 24641 "line": " lib/addons/p5.sound.js:458" 24642 }, {
24643 "message": "Missing item type\na silent connection to the DesinationNode\nwhich will ensure that anything connected to it\nwill not be garbage collected", 24644 "line": " lib/addons/p5.sound.js:554" 24645 }, { 24646 "message": "Missing item type", 24647 "line": " lib/addons/p5.sound.js:570" 24648 }, { 24649 "message": "Missing item type\nUsed by Osc and Envelope to chain signal math", 24650 "line": " lib/addons/p5.sound.js:775" 24651 }, { 24652 "message": "Missing item type\nThis is a helper function that the p5.SoundFile calls to load\nitself. Accepts a callback (the name of another function)\nas an optional parameter.", 24653 "line": " lib/addons/p5.sound.js:1171" 24654 }, { 24655 "message": "Missing item type\nStop playback on all of this soundfile's sources.", 24656 "line": " lib/addons/p5.sound.js:1591" 24657 }, { 24658 "message": "Missing item type", 24659 "line": " lib/addons/p5.sound.js:2030" 24660 }, { 24661 "message": "Missing item type", 24662 "line": " lib/addons/p5.sound.js:2313" 24663 }, { 24664 "message": "Missing item type", 24665 "line": " lib/addons/p5.sound.js:3409" 24666 }, { 24667 "message": "Missing item type", 24668 "line": " lib/addons/p5.sound.js:3786" 24669 }, { 24670 "message": "Missing item type", 24671 "line": " lib/addons/p5.sound.js:3807" 24672 }, { 24673 "message": "Missing item type", 24674 "line": " lib/addons/p5.sound.js:3866" 24675 }, { 24676 "message": "Missing item type", 24677 "line": " lib/addons/p5.sound.js:4184" 24678 }, { 24679 "message": "Missing item type", 24680 "line": " lib/addons/p5.sound.js:4356" 24681 }, { 24682 "message": "Missing item type", 24683 "line": " lib/addons/p5.sound.js:4514" 24684 }, { 24685 "message": "Missing item type", 24686 "line": " lib/addons/p5.sound.js:4555" 24687 }, { 24688 "message": "Missing item type", 24689 "line": " lib/addons/p5.sound.js:4625" 24690 }, { 24691 "message": "Missing item type", 24692 "line": " lib/addons/p5.sound.js:4813" 24693 }, { 24694 "message": "Missing item type", 24695 "line": " lib/addons/p5.sound.js:4870" 24696 }, { 24697 "message": "Missing item type", 24698 "line": " lib/addons/p5.sound.js:5038" 24699 }, { 24700 "message": "Missing item type", 24701 "line": " lib/addons/p5.sound.js:5086" 24702 }, { 24703 "message": "Missing item type", 24704 "line": " lib/addons/p5.sound.js:5117" 24705 }, { 24706 "message": "Missing item type", 24707 "line": " lib/addons/p5.sound.js:5138" 24708 }, { 24709 "message": "Missing item type", 24710 "line": " lib/addons/p5.sound.js:5158" 24711 }, { 24712 "message": "Missing item type", 24713 "line": " lib/addons/p5.sound.js:5871" 24714 }, { 24715 "message": "Missing item type", 24716 "line": " lib/addons/p5.sound.js:6074" 24717 }, { 24718 "message": "Missing item type", 24719 "line": " lib/addons/p5.sound.js:7744" 24720 }, { 24721 "message": "Missing item type", 24722 "line": " lib/addons/p5.sound.js:7760" 24723 }, { 24724 "message": "Missing item type", 24725 "line": " lib/addons/p5.sound.js:7784" 24726 }, { 24727 "message": "Missing item type", 24728 "line": " lib/addons/p5.sound.js:7810" 24729 }, { 24730 "message": "Missing item type", 24731 "line": " lib/addons/p5.sound.js:7832" 24732 }, { 24733 "message": "Missing item type", 24734 "line": " lib/addons/p5.sound.js:7854" 24735 }, { 24736 "message": "Missing item type", 24737 "line": " lib/addons/p5.sound.js:7900" 24738 }, { 24739 "message": "Missing item type", 24740 "line": " lib/addons/p5.sound.js:7931" 24741 }, { 24742 "message": "Missing item type", 24743 "line": " lib/addons/p5.sound.js:7949" 24744 }, { 24745 "message": "Missing item type", 24746 "line": " lib/addons/p5.sound.js:8286" 24747 }, { 24748 "message": "Missing item type", 24749 "line": " lib/addons/p5.sound.js:8308" 24750 }, { 24751 "message": "Missing item type\nThe p5.Effect class is built\n \tusing Tone.js CrossFade", 24752 "line": " lib/addons/p5.sound.js:8378" 24753 }, { 24754 "message": "Missing item type\nIn classes that extend\np5.Effect, connect effect nodes\nto the wet parameter", 24755 "line": " lib/addons/p5.sound.js:8384" 24756 }, { 24757 "message": "Missing item type\nEQFilter extends p5.Filter with constraints\nnecessary for the p5.EQ", 24758 "line": " lib/addons/p5.sound.js:8773" 24759 }, { 24760 "message": "Missing item type\nInspired by Simple Reverb by Jordan Santell\nhttps://github.com/web-audio-components/simple-reverb/blob/master/index.js\n\nUtility function for building an impulse response\nbased on the module parameters.", 24761 "line": " lib/addons/p5.sound.js:9883" 24762 }, { 24763 "message": "Missing item type\nPrivate method to load a buffer as an Impulse Response,\nassign it to the convolverNode, and add to the Array of .impulses.", 24764 "line": " lib/addons/p5.sound.js:10050" 24765 }, { 24766 "message": "Missing item type", 24767 "line": " lib/addons/p5.sound.js:10234" 24768 }, { 24769 "message": "Missing item type", 24770 "line": " lib/addons/p5.sound.js:10259" 24771 }, { 24772 "message": "Missing item type\nmusicalTimeMode variables\nmodify these only when the interval is specified in musicalTime format as a string", 24773 "line": " lib/addons/p5.sound.js:10983" 24774 }, { 24775 "message": "Missing item type\nDo not initiate the callback if timeFromNow is < 0\nThis ususually occurs for a few milliseconds when the page\
24775nis not fully loaded\n\nThe callback should only be called until maxIterations is reached", 24776 "line": " lib/addons/p5.sound.js:10999" 24777 }, { 24778 "message": "Missing item type\ncallback invoked when the recording is over", 24779 "line": " lib/addons/p5.sound.js:11489" 24780 }, { 24781 "message": "Missing item type\ninternal method called on audio process", 24782 "line": " lib/addons/p5.sound.js:11575" 24783 }, { 24784 "message": "Missing item type\nPrivate method to ensure accurate values of this._voicesInUse\nAny time a new value is scheduled, it is necessary to increment all subsequent\nscheduledValues after attack, and decrement all subsequent\nscheduledValues after release", 24785 "line": " lib/addons/p5.sound.js:12621" 24786 }, { 24787 "message": "Missing item type\np5.sound \nhttps://p5js.org/reference/#/libraries/p5.sound\n\nFrom the Processing Foundation and contributors\nhttps://github.com/processing/p5.js-sound/graphs/contributors\n\nMIT License (MIT)\nhttps://github.com/processing/p5.js-sound/blob/master/LICENSE\n\nSome of the many audio libraries & resources that inspire p5.sound:\n - TONE.js (c) Yotam Mann. Licensed under The MIT License (MIT). https://github.com/TONEnoTONE/Tone.js\n - buzz.js (c) Jay Salvat. Licensed under The MIT License (MIT). http://buzz.jaysalvat.com/\n - Boris Smus Web Audio API book, 2013. Licensed under the Apache License http://www.apache.org/licenses/LICENSE-2.0\n - wavesurfer.js https://github.com/katspaugh/wavesurfer.js\n - Web Audio Components by Jordan Santell https://github.com/web-audio-components\n - Wilm Thoben's Sound library for Processing https://github.com/processing/processing/tree/master/java/libraries/sound\n\n Web Audio API: http://w3.org/TR/webaudio/", 24788 "line": " lib/addons/p5.sound.min.js:3" 24789 }], 24790 "consts": { 24791 "RGB": ["p5.colorMode"], 24792 "HSB": ["p5.colorMode"], 24793 "HSL": ["p5.colorMode"], 24794 "CHORD": ["p5.arc"], 24795 "PIE": ["p5.arc"], 24796 "OPEN": ["p5.arc"], 24797 "CENTER": ["p5.ellipseMode", "p5.rectMode", "p5.imageMode", "p5.textAlign"], 24798 "RADIUS": ["p5.ellipseMode", "p5.rectMode"], 24799 "CORNER": ["p5.ellipseMode", "p5.rectMode", "p5.imageMode"], 24800 "CORNERS": ["p5.ellipseMode", "p5.rectMode", "p5.imageMode"], 24801 "SQUARE": ["p5.strokeCap"], 24802 "PROJECT": ["p5.strokeCap"], 24803 "ROUND": ["p5.strokeCap", "p5.strokeJoin"], 24804 "MITER": ["p5.strokeJoin"], 24805 "BEVEL": ["p5.strokeJoin"], 24806 "POINTS": ["p5.beginShape"], 24807 "LINES": ["p5.beginShape"], 24808 "TRIANGLES": ["p5.beginShape"], 24809 "TRIANGLE_FAN": ["p5.beginShape"], 24810 "TRIANGLE_STRIP": ["p5.beginShape"], 24811 "QUADS": ["p5.beginShape"], 24812 "QUAD_STRIP": ["p5.beginShape"], 24813 "CLOSE": ["p5.endShape"], 24814 "ARROW": ["p5.cursor"], 24815 "CROSS": ["p5.cursor"], 24816 "HAND": ["p5.cursor"], 24817 "MOVE": ["p5.cursor"], 24818 "TEXT": ["p5.cursor"], 24819 "P2D": ["p5.createCanvas", "p5.createGraphics"], 24820 "WEBGL": ["p5.createCanvas", "p5.createGraphics"], 24821 "BLEND": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24822 "DARKEST": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24823 "LIGHTEST": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24824 "DIFFERENCE": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24825 "MULTIPLY": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24826 "EXCLUSION": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24827 "SCREEN": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24828 "REPLACE": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24829 "OVERLAY": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24830 "HARD_LIGHT": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24831 "SOFT_LIGHT": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24832 "DODGE": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24833 "BURN": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24834 "ADD": ["p5.blendMode", "p5.Image.blend", "p5.blend"], 24835 "NORMAL": ["p5.blendMode", "p5.Image.blend", "p5.blend", "p5.textStyle", "p5.textureMode"], 24836 "THRESHOLD": ["p5.Image.filter", "p5.filter"], 24837 "GRAY": ["p5.Image.filter", "p5.filter"], 24838 "OPAQUE": ["p5.Image.filter", "p5.filter"], 24839 "INVERT": ["p5.Image.filter", "p5.filter"], 24840 "POSTERIZE": ["p5.Image.filter", "p5.filter"], 24841 "BLUR": ["p5.Image.filter", "p5.filter"], 24842 "ERODE": ["p5.Image.filter", "p5.filter"], 24843 "DILATE": ["p5.Image.filter", "p5.filter"], 24844 "RADIANS": ["p5.angleMode"], 24845 "DEGREES": ["p5.angleMode"], 24846 "LEFT": ["p5.textAlign"], 24847 "RIGHT": ["p5.textAlign"], 24848 "TOP": ["p5.textAlign"], 24849 "BOTTOM": ["p5.textAlign"], 24850 "BASELINE": ["p5.textAlign"], 24851 "ITALIC": ["p5.textStyle"], 24852 "BOLD": ["p5.textStyle"], 24853 "BOLDITALIC": ["p5.textStyle"], 24854 "IMAGE": ["p5.textureMode"], 24855 "VIDEO": ["p5.createCapture"], 24856 "AUDIO": ["p5.createCapture"] 24857 } 24858 }; 24859 }, {}],
vendor: 4,382 bytes, lines 24860-24979
24860 2: [function (_dereq_, module, exports) { 24861 'use strict'; 24862 24863 exports.byteLength = byteLength; 24864 exports.toByteArray = toByteArray; 24865 exports.fromByteArray = fromByteArray; 24866 var lookup = []; 24867 var revLookup = []; 24868 var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array; 24869 var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 24870 24871 for (var i = 0, len = code.length; i < len; ++i) { 24872 lookup[i] = code[i]; 24873 revLookup[code.charCodeAt(i)] = i; 24874 } // Support decoding URL-safe base64 strings, as Node.js does. 24875 // See: https://en.wikipedia.org/wiki/Base64#URL_applications 24876 24877 24878 revLookup['-'.charCodeAt(0)] = 62; 24879 revLookup['_'.charCodeAt(0)] = 63; 24880 24881 function getLens(b64) { 24882 var len = b64.length; 24883 24884 if (len % 4 > 0) { 24885 throw new Error('Invalid string. Length must be a multiple of 4'); 24886 } // Trim off extra bytes after placeholder bytes are found 24887 // See: https://github.com/beatgammit/base64-js/issues/42 24888 24889 24890 var validLen = b64.indexOf('='); 24891 if (validLen === -1) validLen = len; 24892 var placeHoldersLen = validLen === len ? 0 : 4 - validLen % 4; 24893 return [validLen, placeHoldersLen]; 24894 } // base64 is 4/3 + up to two characters of the original data 24895 24896 24897 function byteLength(b64) { 24898 var lens = getLens(b64); 24899 var validLen = lens[0]; 24900 var placeHoldersLen = lens[1]; 24901 return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen; 24902 } 24903 24904 function _byteLength(b64, validLen, placeHoldersLen) { 24905 return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen; 24906 } 24907 24908 function toByteArray(b64) { 24909 var tmp; 24910 var lens = getLens(b64); 24911 var validLen = lens[0]; 24912 var placeHoldersLen = lens[1]; 24913 var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)); 24914 var curByte = 0; // if there are placeholders, only get up to the last complete 4 chars 24915 24916 var len = placeHoldersLen > 0 ? validLen - 4 : validLen; 24917 24918 for (var i = 0; i < len; i += 4) { 24919 tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)]; 24920 arr[curByte++] = tmp >> 16 & 0xFF; 24921 arr[curByte++] = tmp >> 8 & 0xFF; 24922 arr[curByte++] = tmp & 0xFF; 24923 } 24924 24925 if (placeHoldersLen === 2) { 24926 tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4; 24927 arr[curByte++] = tmp & 0xFF; 24928 } 24929 24930 if (placeHoldersLen === 1) { 24931 tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2; 24932 arr[curByte++] = tmp >> 8 & 0xFF; 24933 arr[curByte++] = tmp & 0xFF; 24934 } 24935 24936 return arr; 24937 } 24938 24939 function tripletToBase64(num) { 24940 return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]; 24941 } 24942 24943 function encodeChunk(uint8, start, end) { 24944 var tmp; 24945 var output = []; 24946 24947 for (var i = start; i < end; i += 3) { 24948 tmp = (uint8[i] << 16 & 0xFF0000) + (uint8[i + 1] << 8 & 0xFF00) + (uint8[i + 2] & 0xFF); 24949 output.push(tripletToBase64(tmp)); 24950 } 24951 24952 return output.join(''); 24953 } 24954 24955 function fromByteArray(uint8) { 24956 var tmp; 24957 var len = uint8.length; 24958 var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes 24959 24960 var parts = []; 24961 var maxChunkLength = 16383; // must be multiple of 3 24962 // go through the array every three bytes, we'll deal with trailing stuff later 24963 24964 for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { 24965 parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength)); 24966 } // pad the end with zeros, but make sure to not forget the extra bytes 24967 24968 24969 if (extraBytes === 1) { 24970 tmp = uint8[len - 1]; 24971 parts.push(lookup[tmp >> 2] + lookup[tmp << 4 & 0x3F] + '=='); 24972 } else if (extraBytes === 2) { 24973 tmp = (uint8[len - 2] << 8) + uint8[len - 1]; 24974 parts.push(lookup[tmp >> 10] + lookup[tmp >> 4 & 0x3F] + lookup[tmp << 2 & 0x3F] + '='); 24975 } 24976 24977 return parts.join(''); 24978 } 24979 }, {}],
vendor: 6,512 bytes, lines 24980-25158
24980 3: [function (_dereq_, module, exports) {}, {}], 24981 4: [function (_dereq_, module, exports) { 24982 /*! 24983 * The buffer module from node.js, for the browser. 24984 * 24985 * @author Feross Aboukhadijeh <https://feross.org> 24986 * @license MIT 24987 */ 24988 24989 /* eslint-disable no-proto */ 24990 'use strict'; 24991 24992 var base64 = _dereq_('base64-js'); 24993 24994 var ieee754 = _dereq_('ieee754'); 24995 24996 exports.Buffer = Buffer; 24997 exports.SlowBuffer = SlowBuffer; 24998 exports.INSPECT_MAX_BYTES = 50; 24999 var K_MAX_LENGTH = 0x7fffffff; 25000 exports.kMaxLength = K_MAX_LENGTH; 25001 /** 25002 * If `Buffer.TYPED_ARRAY_SUPPORT`: 25003 * === true Use Uint8Array implementation (fastest) 25004 * === false Print warning and recommend using `buffer` v4.x which has an Object 25005 * implementation (most compatible, even IE6) 25006 * 25007 * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, 25008 * Opera 11.6+, iOS 4.2+. 25009 * 25010 * We report that the browser does not support typed arrays if the are not subclassable 25011 * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` 25012 * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support 25013 * for __proto__ and has a buggy typed array implementation. 25014 */ 25015 25016 Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport(); 25017 25018 if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && typeof console.error === 'function') { 25019 console.error('This browser lacks typed array (Uint8Array) support which is required by ' + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'); 25020 } 25021 25022 function typedArraySupport() { 25023 // Can typed array instances can be augmented? 25024 try { 25025 var arr = new Uint8Array(1); 25026 arr.__proto__ = { 25027 __proto__: Uint8Array.prototype, 25028 foo: function () { 25029 return 42; 25030 } 25031 }; 25032 return arr.foo() === 42; 25033 } catch (e) { 25034 return false; 25035 } 25036 } 25037 25038 Object.defineProperty(Buffer.prototype, 'parent', { 25039 enumerable: true, 25040 get: function () { 25041 if (!Buffer.isBuffer(this)) return undefined; 25042 return this.buffer; 25043 } 25044 }); 25045 Object.defineProperty(Buffer.prototype, 'offset', { 25046 enumerable: true, 25047 get: function () { 25048 if (!Buffer.isBuffer(this)) return undefined; 25049 return this.byteOffset; 25050 } 25051 }); 25052 25053 function createBuffer(length) { 25054 if (length > K_MAX_LENGTH) { 25055 throw new RangeError('The value "' + length + '" is invalid for option "size"'); 25056 } // Return an augmented `Uint8Array` instance 25057 25058 25059 var buf = new Uint8Array(length); 25060 buf.__proto__ = Buffer.prototype; 25061 return buf; 25062 } 25063 /** 25064 * The Buffer constructor returns instances of `Uint8Array` that have their 25065 * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of 25066 * `Uint8Array`, so the returned instances will have all the node `Buffer` methods 25067 * and the `Uint8Array` methods. Square bracket notation works as expected -- it 25068 * returns a single octet. 25069 * 25070 * The `Uint8Array` prototype remains unmodified. 25071 */ 25072 25073 25074 function Buffer(arg, encodingOrOffset, length) { 25075 // Common case. 25076 if (typeof arg === 'number') { 25077 if (typeof encodingOrOffset === 'string') { 25078 throw new TypeError('The "string" argument must be of type string. Received type number'); 25079 } 25080 25081 return allocUnsafe(arg); 25082 } 25083 25084 return from(arg, encodingOrOffset, length); 25085 } // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 25086 25087 25088 if (typeof Symbol !== 'undefined' && Symbol.species != null && Buffer[Symbol.species] === Buffer) { 25089 Object.defineProperty(Buffer, Symbol.species, { 25090 value: null, 25091 configurable: true, 25092 enumerable: false, 25093 writable: false 25094 }); 25095 } 25096 25097 Buffer.poolSize = 8192; // not used by this implementation 25098 25099 function from(value, encodingOrOffset, length) { 25100 if (typeof value === 'string') { 25101 return fromString(value, encodingOrOffset); 25102 } 25103 25104 if (ArrayBuffer.isView(value)) { 25105 return fromArrayLike(value); 25106 } 25107 25108 if (value == null) { 25109 throw TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + 'or Array-like Object. Received type ' + typeof value); 25110 } 25111 25112 if (isInstance(value, ArrayBuffer) || value && isInstance(value.buffer, ArrayBuffer)) { 25113 return fromArrayBuffer(value, encodingOrOffset, length); 25114 } 25115 25116 if (typeof value === 'number') { 25117 throw new TypeError('The "value" argument must not be of type number. Received type number'); 25118 } 25119 25120 var valueOf = value.valueOf && value.valueOf(); 25121 25122 if (valueOf != null && valueOf !== value) { 25123 return Buffer.from(valueOf, encodingOrOffset, length); 25124 } 25125 25126 var b = fromObject(value); 25127 if (b) return b; 25128 25129 if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && typeof value[Symbol.toPrimitive] === 'function') { 25130 return Buffer.from(value[Symbol.toPrimitive]('string'), encodingOrOffset, length); 25131 } 25132 25133 throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + 'or Array-like Object. Received type ' + typeof value); 25134 } 25135 /** 25136 * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError 25137 * if value is a number. 25138 * Buffer.from(str[, encoding]) 25139 * Buffer.from(array) 25140 * Buffer.from(buffer) 25141 * Buffer.from(arrayBuffer[, byteOffset[, length]]) 25142 **/ 25143 25144 25145 Buffer.from = function (value, encodingOrOffset, length) { 25146 return from(value, encodingOrOffset, length); 25147 }; // Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: 25148 // https://github.com/feross/buffer/pull/148 25149 25150 25151 Buffer.prototype.__proto__ = Uint8Array.prototype; 25152 Buffer.__proto__ = Uint8Array; 25153 25154 function assertSize(size) { 25155 if (typeof size !== 'number') { 25156 throw new TypeError('"size" argument must be of type number'); 25157 } else if (size < 0) { 25158 throw new RangeError('The value "' + size + '" is invali
vendor: 4,462 bytes, lines 25158-25313
25158d for option "size"'); 25159 } 25160 } 25161 25162 function alloc(size, fill, encoding) { 25163 assertSize(size); 25164 25165 if (size <= 0) { 25166 return createBuffer(size); 25167 } 25168 25169 if (fill !== undefined) { 25170 // Only pay attention to encoding if it's a string. This 25171 // prevents accidentally sending in a number that would 25172 // be interpretted as a start offset. 25173 return typeof encoding === 'string' ? createBuffer(size).fill(fill, encoding) : createBuffer(size).fill(fill); 25174 } 25175 25176 return createBuffer(size); 25177 } 25178 /** 25179 * Creates a new filled Buffer instance. 25180 * alloc(size[, fill[, encoding]]) 25181 **/ 25182 25183 25184 Buffer.alloc = function (size, fill, encoding) { 25185 return alloc(size, fill, encoding); 25186 }; 25187 25188 function allocUnsafe(size) { 25189 assertSize(size); 25190 return createBuffer(size < 0 ? 0 : checked(size) | 0); 25191 } 25192 /** 25193 * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. 25194 * */ 25195 25196 25197 Buffer.allocUnsafe = function (size) { 25198 return allocUnsafe(size); 25199 }; 25200 /** 25201 * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. 25202 */ 25203 25204 25205 Buffer.allocUnsafeSlow = function (size) { 25206 return allocUnsafe(size); 25207 }; 25208 25209 function fromString(string, encoding) { 25210 if (typeof encoding !== 'string' || encoding === '') { 25211 encoding = 'utf8'; 25212 } 25213 25214 if (!Buffer.isEncoding(encoding)) { 25215 throw new TypeError('Unknown encoding: ' + encoding); 25216 } 25217 25218 var length = byteLength(string, encoding) | 0; 25219 var buf = createBuffer(length); 25220 var actual = buf.write(string, encoding); 25221 25222 if (actual !== length) { 25223 // Writing a hex string, for example, that contains invalid characters will 25224 // cause everything after the first invalid character to be ignored. (e.g. 25225 // 'abxxcd' will be treated as 'ab') 25226 buf = buf.slice(0, actual); 25227 } 25228 25229 return buf; 25230 } 25231 25232 function fromArrayLike(array) { 25233 var length = array.length < 0 ? 0 : checked(array.length) | 0; 25234 var buf = createBuffer(length); 25235 25236 for (var i = 0; i < length; i += 1) { 25237 buf[i] = array[i] & 255; 25238 } 25239 25240 return buf; 25241 } 25242 25243 function fromArrayBuffer(array, byteOffset, length) { 25244 if (byteOffset < 0 || array.byteLength < byteOffset) { 25245 throw new RangeError('"offset" is outside of buffer bounds'); 25246 } 25247 25248 if (array.byteLength < byteOffset + (length || 0)) { 25249 throw new RangeError('"length" is outside of buffer bounds'); 25250 } 25251 25252 var buf; 25253 25254 if (byteOffset === undefined && length === undefined) { 25255 buf = new Uint8Array(array); 25256 } else if (length === undefined) { 25257 buf = new Uint8Array(array, byteOffset); 25258 } else { 25259 buf = new Uint8Array(array, byteOffset, length); 25260 } // Return an augmented `Uint8Array` instance 25261 25262 25263 buf.__proto__ = Buffer.prototype; 25264 return buf; 25265 } 25266 25267 function fromObject(obj) { 25268 if (Buffer.isBuffer(obj)) { 25269 var len = checked(obj.length) | 0; 25270 var buf = createBuffer(len); 25271 25272 if (buf.length === 0) { 25273 return buf; 25274 } 25275 25276 obj.copy(buf, 0, 0, len); 25277 return buf; 25278 } 25279 25280 if (obj.length !== undefined) { 25281 if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { 25282 return createBuffer(0); 25283 } 25284 25285 return fromArrayLike(obj); 25286 } 25287 25288 if (obj.type === 'Buffer' && Array.isArray(obj.data)) { 25289 return fromArrayLike(obj.data); 25290 } 25291 } 25292 25293 function checked(length) { 25294 // Note: cannot use `length < K_MAX_LENGTH` here because that fails when 25295 // length is NaN (which is otherwise coerced to zero.) 25296 if (length >= K_MAX_LENGTH) { 25297 throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes'); 25298 } 25299 25300 return length | 0; 25301 } 25302 25303 function SlowBuffer(length) { 25304 if (+length != length) { 25305 // eslint-disable-line eqeqeq 25306 length = 0; 25307 } 25308 25309 return Buffer.alloc(+length); 25310 } 25311 25312 Buffer.isBuffer = function isBuffer(b) { 25313 return b != null && b._isBuffer === true && b !== Buffer.prototype;
vendor: 11,805 bytes, lines 25313-25718
25313 // so Buffer.isBuffer(Buffer.prototype) will be false 25314 }; 25315 25316 Buffer.compare = function compare(a, b) { 25317 if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength); 25318 if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength); 25319 25320 if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { 25321 throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array'); 25322 } 25323 25324 if (a === b) return 0; 25325 var x = a.length; 25326 var y = b.length; 25327 25328 for (var i = 0, len = Math.min(x, y); i < len; ++i) { 25329 if (a[i] !== b[i]) { 25330 x = a[i]; 25331 y = b[i]; 25332 break; 25333 } 25334 } 25335 25336 if (x < y) return -1; 25337 if (y < x) return 1; 25338 return 0; 25339 }; 25340 25341 Buffer.isEncoding = function isEncoding(encoding) { 25342 switch (String(encoding).toLowerCase()) { 25343 case 'hex': 25344 case 'utf8': 25345 case 'utf-8': 25346 case 'ascii': 25347 case 'latin1': 25348 case 'binary': 25349 case 'base64': 25350 case 'ucs2': 25351 case 'ucs-2': 25352 case 'utf16le': 25353 case 'utf-16le': 25354 return true; 25355 25356 default: 25357 return false; 25358 } 25359 }; 25360 25361 Buffer.concat = function concat(list, length) { 25362 if (!Array.isArray(list)) { 25363 throw new TypeError('"list" argument must be an Array of Buffers'); 25364 } 25365 25366 if (list.length === 0) { 25367 return Buffer.alloc(0); 25368 } 25369 25370 var i; 25371 25372 if (length === undefined) { 25373 length = 0; 25374 25375 for (i = 0; i < list.length; ++i) { 25376 length += list[i].length; 25377 } 25378 } 25379 25380 var buffer = Buffer.allocUnsafe(length); 25381 var pos = 0; 25382 25383 for (i = 0; i < list.length; ++i) { 25384 var buf = list[i]; 25385 25386 if (isInstance(buf, Uint8Array)) { 25387 buf = Buffer.from(buf); 25388 } 25389 25390 if (!Buffer.isBuffer(buf)) { 25391 throw new TypeError('"list" argument must be an Array of Buffers'); 25392 } 25393 25394 buf.copy(buffer, pos); 25395 pos += buf.length; 25396 } 25397 25398 return buffer; 25399 }; 25400 25401 function byteLength(string, encoding) { 25402 if (Buffer.isBuffer(string)) { 25403 return string.length; 25404 } 25405 25406 if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { 25407 return string.byteLength; 25408 } 25409 25410 if (typeof string !== 'string') { 25411 throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + 'Received type ' + typeof string); 25412 } 25413 25414 var len = string.length; 25415 var mustMatch = arguments.length > 2 && arguments[2] === true; 25416 if (!mustMatch && len === 0) return 0; // Use a for loop to avoid recursion 25417 25418 var loweredCase = false; 25419 25420 for (;;) { 25421 switch (encoding) { 25422 case 'ascii': 25423 case 'latin1': 25424 case 'binary': 25425 return len; 25426 25427 case 'utf8': 25428 case 'utf-8': 25429 return utf8ToBytes(string).length; 25430 25431 case 'ucs2': 25432 case 'ucs-2': 25433 case 'utf16le': 25434 case 'utf-16le': 25435 return len * 2; 25436 25437 case 'hex': 25438 return len >>> 1; 25439 25440 case 'base64': 25441 return base64ToBytes(string).length; 25442 25443 default: 25444 if (loweredCase) { 25445 return mustMatch ? -1 : utf8ToBytes(string).length; // assume utf8 25446 } 25447 25448 encoding = ('' + encoding).toLowerCase(); 25449 loweredCase = true; 25450 } 25451 } 25452 } 25453 25454 Buffer.byteLength = byteLength; 25455 25456 function slowToString(encoding, start, end) { 25457 var loweredCase = false; // No need to verify that "this.length <= MAX_UINT32" since it's a read-only 25458 // property of a typed array. 25459 // This behaves neither like String nor Uint8Array in that we set start/end 25460 // to their upper/lower bounds if the value passed is out of range. 25461 // undefined is handled specially as per ECMA-262 6th Edition, 25462 // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. 25463 25464 if (start === undefined || start < 0) { 25465 start = 0; 25466 } // Return early if start > this.length. Done here to prevent potential uint32 25467 // coercion fail below. 25468 25469 25470 if (start > this.length) { 25471 return ''; 25472 } 25473 25474 if (end === undefined || end > this.length) { 25475 end = this.length; 25476 } 25477 25478 if (end <= 0) { 25479 return ''; 25480 } // Force coersion to uint32. This will also coerce falsey/NaN values to 0. 25481 25482 25483 end >>>= 0; 25484 start >>>= 0; 25485 25486 if (end <= start) { 25487 return ''; 25488 } 25489 25490 if (!encoding) encoding = 'utf8'; 25491 25492 while (true) { 25493 switch (encoding) { 25494 case 'hex': 25495 return hexSlice(this, start, end); 25496 25497 case 'utf8': 25498 case 'utf-8': 25499 return utf8Slice(this, start, end); 25500 25501 case 'ascii': 25502 return asciiSlice(this, start, end); 25503 25504 case 'latin1': 25505 case 'binary': 25506 return latin1Slice(this, start, end); 25507 25508 case 'base64': 25509 return base64Slice(this, start, end); 25510 25511 case 'ucs2': 25512 case 'ucs-2': 25513 case 'utf16le': 25514 case 'utf-16le': 25515 return utf16leSlice(this, start, end); 25516 25517 default: 25518 if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding); 25519 encoding = (encoding + '').toLowerCase(); 25520 loweredCase = true; 25521 } 25522 } 25523 } // This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) 25524 // to detect a Buffer instance. It's not possible to use `instanceof Buffer` 25525 // reliably in a browserify context because there could be multiple different 25526 // copies of the 'buffer' package in use. This method works even for Buffer 25527 // instances that were created from another copy of the `buffer` package. 25528 // See: https://github.com/feross/buffer/issues/154 25529 25530 25531 Buffer.prototype._isBuffer = true; 25532 25533 function swap(b, n, m) { 25534 var i = b[n]; 25535 b[n] = b[m]; 25536 b[m] = i; 25537 } 25538 25539 Buffer.prototype.swap16 = function swap16() { 25540 var len = this.length; 25541 25542 if (len % 2 !== 0) { 25543 throw new RangeError('Buffer size must be a multiple of 16-bits'); 25544 } 25545 25546 for (var i = 0; i < len; i += 2) { 25547 swap(this, i, i + 1); 25548 } 25549 25550 return this; 25551 }; 25552 25553 Buffer.prototype.swap32 = function swap32() { 25554 var len = this.length; 25555 25556 if (len % 4 !== 0) { 25557 throw new RangeError('Buffer size must be a multiple of 32-bits'); 25558 } 25559 25560 for (var i = 0; i < len; i += 4) { 25561 swap(this, i, i + 3); 25562 swap(this, i + 1, i + 2); 25563 } 25564 25565 return this; 25566 }; 25567 25568 Buffer.prototype.swap64 = function swap64() { 25569 var len = this.length; 25570 25571 if (len % 8 !== 0) { 25572 throw new RangeError('Buffer size must be a multiple of 64-bits'); 25573 } 25574 25575 for (var i = 0; i < len; i += 8) { 25576 swap(this, i, i + 7); 25577 swap(this, i + 1, i + 6); 25578 swap(this, i + 2, i + 5); 25579 swap(this, i + 3, i + 4); 25580 } 25581 25582 return this; 25583 }; 25584 25585 Buffer.prototype.toString = function toString() { 25586 var length = this.length; 25587 if (length === 0) return ''; 25588 if (arguments.length === 0) return utf8Slice(this, 0, length); 25589 return slowToString.apply(this, arguments); 25590 }; 25591 25592 Buffer.prototype.toLocaleString = Buffer.prototype.toString; 25593 25594 Buffer.prototype.equals = function equals(b) { 25595 if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer'); 25596 if (this === b) return true; 25597 return Buffer.compare(this, b) === 0; 25598 }; 25599 25600 Buffer.prototype.inspect = function inspect() { 25601 var str = ''; 25602 var max = exports.INSPECT_MAX_BYTES; 25603 str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim(); 25604 if (this.length > max) str += ' ... '; 25605 return '<Buffer ' + str + '>'; 25606 }; 25607 25608 Buffer.prototype.compare = function compare(target, start, end, thisStart, thisEnd) { 25609 if (isInstance(target, Uint8Array)) { 25610 target = Buffer.from(target, target.offset, target.byteLength); 25611 } 25612 25613 if (!Buffer.isBuffer(target)) { 25614 throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. ' + 'Received type ' + typeof target); 25615 } 25616 25617 if (start === undefined) { 25618 start = 0; 25619 } 25620 25621 if (end === undefined) { 25622 end = target ? target.length : 0; 25623 } 25624 25625 if (thisStart === undefined) { 25626 thisStart = 0; 25627 } 25628 25629 if (thisEnd === undefined) { 25630 thisEnd = this.length; 25631 } 25632 25633 if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { 25634 throw new RangeError('out of range index'); 25635 } 25636 25637 if (thisStart >= thisEnd && start >= end) { 25638 return 0; 25639 } 25640 25641 if (thisStart >= thisEnd) { 25642 return -1; 25643 } 25644 25645 if (start >= end) { 25646 return 1; 25647 } 25648 25649 start >>>= 0; 25650 end >>>= 0; 25651 thisStart >>>= 0; 25652 thisEnd >>>= 0; 25653 if (this === target) return 0; 25654 var x = thisEnd - thisStart; 25655 var y = end - start; 25656 var len = Math.min(x, y); 25657 var thisCopy = this.slice(thisStart, thisEnd); 25658 var targetCopy = target.slice(start, end); 25659 25660 for (var i = 0; i < len; ++i) { 25661 if (thisCopy[i] !== targetCopy[i]) { 25662 x = thisCopy[i]; 25663 y = targetCopy[i]; 25664 break; 25665 } 25666 } 25667 25668 if (x < y) return -1; 25669 if (y < x) return 1; 25670 return 0; 25671 }; // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, 25672 // OR the last index of `val` in `buffer` at offset <= `byteOffset`. 25673 // 25674 // Arguments: 25675 // - buffer - a Buffer to search 25676 // - val - a string, Buffer, or number 25677 // - byteOffset - an index into `buffer`; will be clamped to an int32 25678 // - encoding - an optional encoding, relevant is val is a string 25679 // - dir - true for indexOf, false for lastIndexOf 25680 25681 25682 function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) { 25683 // Empty buffer means no match 25684 if (buffer.length === 0) return -1; // Normalize byteOffset 25685 25686 if (typeof byteOffset === 'string') { 25687 encoding = byteOffset; 25688 byteOffset = 0; 25689 } else if (byteOffset > 0x7fffffff) { 25690 byteOffset = 0x7fffffff; 25691 } else if (byteOffset < -0x80000000) { 25692 byteOffset = -0x80000000; 25693 } 25694 25695 byteOffset = +byteOffset; // Coerce to Number. 25696 25697 if (numberIsNaN(byteOffset)) { 25698 // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer 25699 byteOffset = dir ? 0 : buffer.length - 1; 25700 } // Normalize byteOffset: negative offsets start from the end of the buffer 25701 25702 25703 if (byteOffset < 0) byteOffset = buffer.length + byteOffset; 25704 25705 if (byteOffset >= buffer.length) { 25706 if (dir) return -1;else byteOffset = buffer.length - 1; 25707 } else if (byteOffset < 0) { 25708 if (dir) byteOffset = 0;else return -1; 25709 } // Normalize val 25710 25711 25712 if (typeof val === 'string') { 25713 val = Buffer.from(val, encoding); 25714 } // Finally, search either indexOf (if dir is true) or lastIndexOf 25715 25716 25717 if (Buffer.isBuffer(val)) { 25718 // Special case: looking for empty string/buffer always fail
vendor: 9,503 bytes, lines 25718-26019
25718s 25719 if (val.length === 0) { 25720 return -1; 25721 } 25722 25723 return arrayIndexOf(buffer, val, byteOffset, encoding, dir); 25724 } else if (typeof val === 'number') { 25725 val = val & 0xFF; // Search for a byte value [0-255] 25726 25727 if (typeof Uint8Array.prototype.indexOf === 'function') { 25728 if (dir) { 25729 return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset); 25730 } else { 25731 return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset); 25732 } 25733 } 25734 25735 return arrayIndexOf(buffer, [val], byteOffset, encoding, dir); 25736 } 25737 25738 throw new TypeError('val must be string, number or Buffer'); 25739 } 25740 25741 function arrayIndexOf(arr, val, byteOffset, encoding, dir) { 25742 var indexSize = 1; 25743 var arrLength = arr.length; 25744 var valLength = val.length; 25745 25746 if (encoding !== undefined) { 25747 encoding = String(encoding).toLowerCase(); 25748 25749 if (encoding === 'ucs2' || encoding === 'ucs-2' || encoding === 'utf16le' || encoding === 'utf-16le') { 25750 if (arr.length < 2 || val.length < 2) { 25751 return -1; 25752 } 25753 25754 indexSize = 2; 25755 arrLength /= 2; 25756 valLength /= 2; 25757 byteOffset /= 2; 25758 } 25759 } 25760 25761 function read(buf, i) { 25762 if (indexSize === 1) { 25763 return buf[i]; 25764 } else { 25765 return buf.readUInt16BE(i * indexSize); 25766 } 25767 } 25768 25769 var i; 25770 25771 if (dir) { 25772 var foundIndex = -1; 25773 25774 for (i = byteOffset; i < arrLength; i++) { 25775 if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { 25776 if (foundIndex === -1) foundIndex = i; 25777 if (i - foundIndex + 1 === valLength) return foundIndex * indexSize; 25778 } else { 25779 if (foundIndex !== -1) i -= i - foundIndex; 25780 foundIndex = -1; 25781 } 25782 } 25783 } else { 25784 if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength; 25785 25786 for (i = byteOffset; i >= 0; i--) { 25787 var found = true; 25788 25789 for (var j = 0; j < valLength; j++) { 25790 if (read(arr, i + j) !== read(val, j)) { 25791 found = false; 25792 break; 25793 } 25794 } 25795 25796 if (found) return i; 25797 } 25798 } 25799 25800 return -1; 25801 } 25802 25803 Buffer.prototype.includes = function includes(val, byteOffset, encoding) { 25804 return this.indexOf(val, byteOffset, encoding) !== -1; 25805 }; 25806 25807 Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) { 25808 return bidirectionalIndexOf(this, val, byteOffset, encoding, true); 25809 }; 25810 25811 Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) { 25812 return bidirectionalIndexOf(this, val, byteOffset, encoding, false); 25813 }; 25814 25815 function hexWrite(buf, string, offset, length) { 25816 offset = Number(offset) || 0; 25817 var remaining = buf.length - offset; 25818 25819 if (!length) { 25820 length = remaining; 25821 } else { 25822 length = Number(length); 25823 25824 if (length > remaining) { 25825 length = remaining; 25826 } 25827 } 25828 25829 var strLen = string.length; 25830 25831 if (length > strLen / 2) { 25832 length = strLen / 2; 25833 } 25834 25835 for (var i = 0; i < length; ++i) { 25836 var parsed = parseInt(string.substr(i * 2, 2), 16); 25837 if (numberIsNaN(parsed)) return i; 25838 buf[offset + i] = parsed; 25839 } 25840 25841 return i; 25842 } 25843 25844 function utf8Write(buf, string, offset, length) { 25845 return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length); 25846 } 25847 25848 function asciiWrite(buf, string, offset, length) { 25849 return blitBuffer(asciiToBytes(string), buf, offset, length); 25850 } 25851 25852 function latin1Write(buf, string, offset, length) { 25853 return asciiWrite(buf, string, offset, length); 25854 } 25855 25856 function base64Write(buf, string, offset, length) { 25857 return blitBuffer(base64ToBytes(string), buf, offset, length); 25858 } 25859 25860 function ucs2Write(buf, string, offset, length) { 25861 return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length); 25862 } 25863 25864 Buffer.prototype.write = function write(string, offset, length, encoding) { 25865 // Buffer#write(string) 25866 if (offset === undefined) { 25867 encoding = 'utf8'; 25868 length = this.length; 25869 offset = 0; // Buffer#write(string, encoding) 25870 } else if (length === undefined && typeof offset === 'string') { 25871 encoding = offset; 25872 length = this.length; 25873 offset = 0; // Buffer#write(string, offset[, length][, encoding]) 25874 } else if (isFinite(offset)) { 25875 offset = offset >>> 0; 25876 25877 if (isFinite(length)) { 25878 length = length >>> 0; 25879 if (encoding === undefined) encoding = 'utf8'; 25880 } else { 25881 encoding = length; 25882 length = undefined; 25883 } 25884 } else { 25885 throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported'); 25886 } 25887 25888 var remaining = this.length - offset; 25889 if (length === undefined || length > remaining) length = remaining; 25890 25891 if (string.length > 0 && (length < 0 || offset < 0) || offset > this.length) { 25892 throw new RangeError('Attempt to write outside buffer bounds'); 25893 } 25894 25895 if (!encoding) encoding = 'utf8'; 25896 var loweredCase = false; 25897 25898 for (;;) { 25899 switch (encoding) { 25900 case 'hex': 25901 return hexWrite(this, string, offset, length); 25902 25903 case 'utf8': 25904 case 'utf-8': 25905 return utf8Write(this, string, offset, length); 25906 25907 case 'ascii': 25908 return asciiWrite(this, string, offset, length); 25909 25910 case 'latin1': 25911 case 'binary': 25912 return latin1Write(this, string, offset, length); 25913 25914 case 'base64': 25915 // Warning: maxLength not taken into account in base64Write 25916 return base64Write(this, string, offset, length); 25917 25918 case 'ucs2': 25919 case 'ucs-2': 25920 case 'utf16le': 25921 case 'utf-16le': 25922 return ucs2Write(this, string, offset, length); 25923 25924 default: 25925 if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding); 25926 encoding = ('' + encoding).toLowerCase(); 25927 loweredCase = true; 25928 } 25929 } 25930 }; 25931 25932 Buffer.prototype.toJSON = function toJSON() { 25933 return { 25934 type: 'Buffer', 25935 data: Array.prototype.slice.call(this._arr || this, 0) 25936 }; 25937 }; 25938 25939 function base64Slice(buf, start, end) { 25940 if (start === 0 && end === buf.length) { 25941 return base64.fromByteArray(buf); 25942 } else { 25943 return base64.fromByteArray(buf.slice(start, end)); 25944 } 25945 } 25946 25947 function utf8Slice(buf, start, end) { 25948 end = Math.min(buf.length, end); 25949 var res = []; 25950 var i = start; 25951 25952 while (i < end) { 25953 var firstByte = buf[i]; 25954 var codePoint = null; 25955 var bytesPerSequence = firstByte > 0xEF ? 4 : firstByte > 0xDF ? 3 : firstByte > 0xBF ? 2 : 1; 25956 25957 if (i + bytesPerSequence <= end) { 25958 var secondByte, thirdByte, fourthByte, tempCodePoint; 25959 25960 switch (bytesPerSequence) { 25961 case 1: 25962 if (firstByte < 0x80) { 25963 codePoint = firstByte; 25964 } 25965 25966 break; 25967 25968 case 2: 25969 secondByte = buf[i + 1]; 25970 25971 if ((secondByte & 0xC0) === 0x80) { 25972 tempCodePoint = (firstByte & 0x1F) << 0x6 | secondByte & 0x3F; 25973 25974 if (tempCodePoint > 0x7F) { 25975 codePoint = tempCodePoint; 25976 } 25977 } 25978 25979 break; 25980 25981 case 3: 25982 secondByte = buf[i + 1]; 25983 thirdByte = buf[i + 2]; 25984 25985 if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { 25986 tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | thirdByte & 0x3F; 25987 25988 if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { 25989 codePoint = tempCodePoint; 25990 } 25991 } 25992 25993 break; 25994 25995 case 4: 25996 secondByte = buf[i + 1]; 25997 thirdByte = buf[i + 2]; 25998 fourthByte = buf[i + 3]; 25999 26000 if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { 26001 tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | fourthByte & 0x3F; 26002 26003 if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { 26004 codePoint = tempCodePoint; 26005 } 26006 } 26007 26008 } 26009 } 26010 26011 if (codePoint === null) { 26012 // we did not generate a valid codePoint so insert a 26013 // replacement char (U+FFFD) and advance only 1 byte 26014 codePoint = 0xFFFD; 26015 bytesPerSequence = 1; 26016 } else if (codePoint > 0xFFFF) { 26017 // encode to utf16 (surrogate pair dance) 26018 codePoint -= 0x10000; 26019 res.push(codePoint >>>
vendor: 25,189 bytes, lines 26019-26781
26019 10 & 0x3FF | 0xD800); 26020 codePoint = 0xDC00 | codePoint & 0x3FF; 26021 } 26022 26023 res.push(codePoint); 26024 i += bytesPerSequence; 26025 } 26026 26027 return decodeCodePointsArray(res); 26028 } // Based on http://stackoverflow.com/a/22747272/680742, the browser with 26029 // the lowest limit is Chrome, with 0x10000 args. 26030 // We go 1 magnitude less, for safety 26031 26032 26033 var MAX_ARGUMENTS_LENGTH = 0x1000; 26034 26035 function decodeCodePointsArray(codePoints) { 26036 var len = codePoints.length; 26037 26038 if (len <= MAX_ARGUMENTS_LENGTH) { 26039 return String.fromCharCode.apply(String, codePoints); // avoid extra slice() 26040 } // Decode in chunks to avoid "call stack size exceeded". 26041 26042 26043 var res = ''; 26044 var i = 0; 26045 26046 while (i < len) { 26047 res += String.fromCharCode.apply(String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)); 26048 } 26049 26050 return res; 26051 } 26052 26053 function asciiSlice(buf, start, end) { 26054 var ret = ''; 26055 end = Math.min(buf.length, end); 26056 26057 for (var i = start; i < end; ++i) { 26058 ret += String.fromCharCode(buf[i] & 0x7F); 26059 } 26060 26061 return ret; 26062 } 26063 26064 function latin1Slice(buf, start, end) { 26065 var ret = ''; 26066 end = Math.min(buf.length, end); 26067 26068 for (var i = start; i < end; ++i) { 26069 ret += String.fromCharCode(buf[i]); 26070 } 26071 26072 return ret; 26073 } 26074 26075 function hexSlice(buf, start, end) { 26076 var len = buf.length; 26077 if (!start || start < 0) start = 0; 26078 if (!end || end < 0 || end > len) end = len; 26079 var out = ''; 26080 26081 for (var i = start; i < end; ++i) { 26082 out += toHex(buf[i]); 26083 } 26084 26085 return out; 26086 } 26087 26088 function utf16leSlice(buf, start, end) { 26089 var bytes = buf.slice(start, end); 26090 var res = ''; 26091 26092 for (var i = 0; i < bytes.length; i += 2) { 26093 res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256); 26094 } 26095 26096 return res; 26097 } 26098 26099 Buffer.prototype.slice = function slice(start, end) { 26100 var len = this.length; 26101 start = ~~start; 26102 end = end === undefined ? len : ~~end; 26103 26104 if (start < 0) { 26105 start += len; 26106 if (start < 0) start = 0; 26107 } else if (start > len) { 26108 start = len; 26109 } 26110 26111 if (end < 0) { 26112 end += len; 26113 if (end < 0) end = 0; 26114 } else if (end > len) { 26115 end = len; 26116 } 26117 26118 if (end < start) end = start; 26119 var newBuf = this.subarray(start, end); // Return an augmented `Uint8Array` instance 26120 26121 newBuf.__proto__ = Buffer.prototype; 26122 return newBuf; 26123 }; 26124 /* 26125 * Need to make sure that buffer isn't trying to write out of bounds. 26126 */ 26127 26128 26129 function checkOffset(offset, ext, length) { 26130 if (offset % 1 !== 0 || offset < 0) throw new RangeError('offset is not uint'); 26131 if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length'); 26132 } 26133 26134 Buffer.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) { 26135 offset = offset >>> 0; 26136 byteLength = byteLength >>> 0; 26137 if (!noAssert) checkOffset(offset, byteLength, this.length); 26138 var val = this[offset]; 26139 var mul = 1; 26140 var i = 0; 26141 26142 while (++i < byteLength && (mul *= 0x100)) { 26143 val += this[offset + i] * mul; 26144 } 26145 26146 return val; 26147 }; 26148 26149 Buffer.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) { 26150 offset = offset >>> 0; 26151 byteLength = byteLength >>> 0; 26152 26153 if (!noAssert) { 26154 checkOffset(offset, byteLength, this.length); 26155 } 26156 26157 var val = this[offset + --byteLength]; 26158 var mul = 1; 26159 26160 while (byteLength > 0 && (mul *= 0x100)) { 26161 val += this[offset + --byteLength] * mul; 26162 } 26163 26164 return val; 26165 }; 26166 26167 Buffer.prototype.readUInt8 = function readUInt8(offset, noAssert) { 26168 offset = offset >>> 0; 26169 if (!noAssert) checkOffset(offset, 1, this.length); 26170 return this[offset]; 26171 }; 26172 26173 Buffer.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) { 26174 offset = offset >>> 0; 26175 if (!noAssert) checkOffset(offset, 2, this.length); 26176 return this[offset] | this[offset + 1] << 8; 26177 }; 26178 26179 Buffer.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) { 26180 offset = offset >>> 0; 26181 if (!noAssert) checkOffset(offset, 2, this.length); 26182 return this[offset] << 8 | this[offset + 1]; 26183 }; 26184 26185 Buffer.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) { 26186 offset = offset >>> 0; 26187 if (!noAssert) checkOffset(offset, 4, this.length); 26188 return (this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16) + this[offset + 3] * 0x1000000; 26189 }; 26190 26191 Buffer.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) { 26192 offset = offset >>> 0; 26193 if (!noAssert) checkOffset(offset, 4, this.length); 26194 return this[offset] * 0x1000000 + (this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]); 26195 }; 26196 26197 Buffer.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) { 26198 offset = offset >>> 0; 26199 byteLength = byteLength >>> 0; 26200 if (!noAssert) checkOffset(offset, byteLength, this.length); 26201 var val = this[offset]; 26202 var mul = 1; 26203 var i = 0; 26204 26205 while (++i < byteLength && (mul *= 0x100)) { 26206 val += this[offset + i] * mul; 26207 } 26208 26209 mul *= 0x80; 26210 if (val >= mul) val -= Math.pow(2, 8 * byteLength); 26211 return val; 26212 }; 26213 26214 Buffer.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) { 26215 offset = offset >>> 0; 26216 byteLength = byteLength >>> 0; 26217 if (!noAssert) checkOffset(offset, byteLength, this.length); 26218 var i = byteLength; 26219 var mul = 1; 26220 var val = this[offset + --i]; 26221 26222 while (i > 0 && (mul *= 0x100)) { 26223 val += this[offset + --i] * mul; 26224 } 26225 26226 mul *= 0x80; 26227 if (val >= mul) val -= Math.pow(2, 8 * byteLength); 26228 return val; 26229 }; 26230 26231 Buffer.prototype.readInt8 = function readInt8(offset, noAssert) { 26232 offset = offset >>> 0; 26233 if (!noAssert) checkOffset(offset, 1, this.length); 26234 if (!(this[offset] & 0x80)) return this[offset]; 26235 return (0xff - this[offset] + 1) * -1; 26236 }; 26237 26238 Buffer.prototype.readInt16LE = function readInt16LE(offset, noAssert) { 26239 offset = offset >>> 0; 26240 if (!noAssert) checkOffset(offset, 2, this.length); 26241 var val = this[offset] | this[offset + 1] << 8; 26242 return val & 0x8000 ? val | 0xFFFF0000 : val; 26243 }; 26244 26245 Buffer.prototype.readInt16BE = function readInt16BE(offset, noAssert) { 26246 offset = offset >>> 0; 26247 if (!noAssert) checkOffset(offset, 2, this.length); 26248 var val = this[offset + 1] | this[offset] << 8; 26249 return val & 0x8000 ? val | 0xFFFF0000 : val; 26250 }; 26251 26252 Buffer.prototype.readInt32LE = function readInt32LE(offset, noAssert) { 26253 offset = offset >>> 0; 26254 if (!noAssert) checkOffset(offset, 4, this.length); 26255 return this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16 | this[offset + 3] << 24; 26256 }; 26257 26258 Buffer.prototype.readInt32BE = function readInt32BE(offset, noAssert) { 26259 offset = offset >>> 0; 26260 if (!noAssert) checkOffset(offset, 4, this.length); 26261 return this[offset] << 24 | this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]; 26262 }; 26263 26264 Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) { 26265 offset = offset >>> 0; 26266 if (!noAssert) checkOffset(offset, 4, this.length); 26267 return ieee754.read(this, offset, true, 23, 4); 26268 }; 26269 26270 Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) { 26271 offset = offset >>> 0; 26272 if (!noAssert) checkOffset(offset, 4, this.length); 26273 return ieee754.read(this, offset, false, 23, 4); 26274 }; 26275 26276 Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) { 26277 offset = offset >>> 0; 26278 if (!noAssert) checkOffset(offset, 8, this.length); 26279 return ieee754.read(this, offset, true, 52, 8); 26280 }; 26281 26282 Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) { 26283 offset = offset >>> 0; 26284 if (!noAssert) checkOffset(offset, 8, this.length); 26285 return ieee754.read(this, offset, false, 52, 8); 26286 }; 26287 26288 function checkInt(buf, value, offset, ext, max, min) { 26289 if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance'); 26290 if (value > max || value < min) throw new RangeError('"value" argument is out of bounds'); 26291 if (offset + ext > buf.length) throw new RangeError('Index out of range'); 26292 } 26293 26294 Buffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) { 26295 value = +value; 26296 offset = offset >>> 0; 26297 byteLength = byteLength >>> 0; 26298 26299 if (!noAssert) { 26300 var maxBytes = Math.pow(2, 8 * byteLength) - 1; 26301 checkInt(this, value, offset, byteLength, maxBytes, 0); 26302 } 26303 26304 var mul = 1; 26305 var i = 0; 26306 this[offset] = value & 0xFF; 26307 26308 while (++i < byteLength && (mul *= 0x100)) { 26309 this[offset + i] = value / mul & 0xFF; 26310 } 26311 26312 return offset + byteLength; 26313 }; 26314 26315 Buffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) { 26316 value = +value; 26317 offset = offset >>> 0; 26318 byteLength = byteLength >>> 0; 26319 26320 if (!noAssert) { 26321 var maxBytes = Math.pow(2, 8 * byteLength) - 1; 26322 checkInt(this, value, offset, byteLength, maxBytes, 0); 26323 } 26324 26325 var i = byteLength - 1; 26326 var mul = 1; 26327 this[offset + i] = value & 0xFF; 26328 26329 while (--i >= 0 && (mul *= 0x100)) { 26330 this[offset + i] = value / mul & 0xFF; 26331 } 26332 26333 return offset + byteLength; 26334 }; 26335 26336 Buffer.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) { 26337 value = +value; 26338 offset = offset >>> 0; 26339 if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0); 26340 this[offset] = value & 0xff; 26341 return offset + 1; 26342 }; 26343 26344 Buffer.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) { 26345 value = +value; 26346 offset = offset >>> 0; 26347 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); 26348 this[offset] = value & 0xff; 26349 this[offset + 1] = value >>> 8; 26350 return offset + 2; 26351 }; 26352 26353 Buffer.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) { 26354 value = +value; 26355 offset = offset >>> 0; 26356 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); 26357 this[offset] = value >>> 8; 26358 this[offset + 1] = value & 0xff; 26359 return offset + 2; 26360 }; 26361 26362 Buffer.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) { 26363 value = +value; 26364 offset = offset >>> 0; 26365 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); 26366 this[offset + 3] = value >>> 24; 26367 this[offset + 2] = value >>> 16; 26368 this[offset + 1] = value >>> 8; 26369 this[offset] = value & 0xff; 26370 return offset + 4; 26371 }; 26372 26373 Buffer.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) { 26374 value = +value; 26375 offset = offset >>> 0; 26376 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); 26377 this[offset] = value >>> 24; 26378 this[offset + 1] = value >>> 16; 26379 this[offset + 2] = value >>> 8; 26380 this[offset + 3] = value & 0xff; 26381 return offset + 4; 26382 }; 26383 26384 Buffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) { 26385 value = +value; 26386 offset = offset >>> 0; 26387 26388 if (!noAssert) { 26389 var limit = Math.pow(2, 8 * byteLength - 1); 26390 checkInt(this, value, offset, byteLength, limit - 1, -limit); 26391 } 26392 26393 var i = 0; 26394 var mul = 1; 26395 var sub = 0; 26396 this[offset] = value & 0xFF; 26397 26398 while (++i < byteLength && (mul *= 0x100)) { 26399 if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { 26400 sub = 1; 26401 } 26402 26403 this[offset + i] = (value / mul >> 0) - sub & 0xFF; 26404 } 26405 26406 return offset + byteLength; 26407 }; 26408 26409 Buffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) { 26410 value = +value; 26411 offset = offset >>> 0; 26412 26413 if (!noAssert) { 26414 var limit = Math.pow(2, 8 * byteLength - 1); 26415 checkInt(this, value, offset, byteLength, limit - 1, -limit); 26416 } 26417 26418 var i = byteLength - 1; 26419 var mul = 1; 26420 var sub = 0; 26421 this[offset + i] = value & 0xFF; 26422 26423 while (--i >= 0 && (mul *= 0x100)) { 26424 if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { 26425 sub = 1; 26426 } 26427 26428 this[offset + i] = (value / mul >> 0) - sub & 0xFF; 26429 } 26430 26431 return offset + byteLength; 26432 }; 26433 26434 Buffer.prototype.writeInt8 = function writeInt8(value, offset, noAssert) { 26435 value = +value; 26436 offset = offset >>> 0; 26437 if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80); 26438 if (value < 0) value = 0xff + value + 1; 26439 this[offset] = value & 0xff; 26440 return offset + 1; 26441 }; 26442 26443 Buffer.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) { 26444 value = +value; 26445 offset = offset >>> 0; 26446 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); 26447 this[offset] = value & 0xff; 26448 this[offset + 1] = value >>> 8; 26449 return offset + 2; 26450 }; 26451 26452 Buffer.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) { 26453 value = +value; 26454 offset = offset >>> 0; 26455 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); 26456 this[offset] = value >>> 8; 26457 this[offset + 1] = value & 0xff; 26458 return offset + 2; 26459 }; 26460 26461 Buffer.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) { 26462 value = +value; 26463 offset = offset >>> 0; 26464 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); 26465 this[offset] = value & 0xff; 26466 this[offset + 1] = value >>> 8; 26467 this[offset + 2] = value >>> 16; 26468 this[offset + 3] = value >>> 24; 26469 return offset + 4; 26470 }; 26471 26472 Buffer.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) { 26473 value = +value; 26474 offset = offset >>> 0; 26475 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); 26476 if (value < 0) value = 0xffffffff + value + 1; 26477 this[offset] = value >>> 24; 26478 this[offset + 1] = value >>> 16; 26479 this[offset + 2] = value >>> 8; 26480 this[offset + 3] = value & 0xff; 26481 return offset + 4; 26482 }; 26483 26484 function checkIEEE754(buf, value, offset, ext, max, min) { 26485 if (offset + ext > buf.length) throw new RangeError('Index out of range'); 26486 if (offset < 0) throw new RangeError('Index out of range'); 26487 } 26488 26489 function writeFloat(buf, value, offset, littleEndian, noAssert) { 26490 value = +value; 26491 offset = offset >>> 0; 26492 26493 if (!noAssert) { 26494 checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38); 26495 } 26496 26497 ieee754.write(buf, value, offset, littleEndian, 23, 4); 26498 return offset + 4; 26499 } 26500 26501 Buffer.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) { 26502 return writeFloat(this, value, offset, true, noAssert); 26503 }; 26504 26505 Buffer.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) { 26506 return writeFloat(this, value, offset, false, noAssert); 26507 }; 26508 26509 function writeDouble(buf, value, offset, littleEndian, noAssert) { 26510 value = +value; 26511 offset = offset >>> 0; 26512 26513 if (!noAssert) { 26514 checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308); 26515 } 26516 26517 ieee754.write(buf, value, offset, littleEndian, 52, 8); 26518 return offset + 8; 26519 } 26520 26521 Buffer.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) { 26522 return writeDouble(this, value, offset, true, noAssert); 26523 }; 26524 26525 Buffer.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) { 26526 return writeDouble(this, value, offset, false, noAssert); 26527 }; // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) 26528 26529 26530 Buffer.prototype.copy = function copy(target, targetStart, start, end) { 26531 if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer'); 26532 if (!start) start = 0; 26533 if (!end && end !== 0) end = this.length; 26534 if (targetStart >= target.length) targetStart = target.length; 26535 if (!targetStart) targetStart = 0; 26536 if (end > 0 && end < start) end = start; // Copy 0 bytes; we're done 26537 26538 if (end === start) return 0; 26539 if (target.length === 0 || this.length === 0) return 0; // Fatal error conditions 26540 26541 if (targetStart < 0) { 26542 throw new RangeError('targetStart out of bounds'); 26543 } 26544 26545 if (start < 0 || start >= this.length) throw new RangeError('Index out of range'); 26546 if (end < 0) throw new RangeError('sourceEnd out of bounds'); // Are we oob? 26547 26548 if (end > this.length) end = this.length; 26549 26550 if (target.length - targetStart < end - start) { 26551 end = target.length - targetStart + start; 26552 } 26553 26554 var len = end - start; 26555 26556 if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { 26557 // Use built-in when available, missing from IE11 26558 this.copyWithin(targetStart, start, end); 26559 } else if (this === target && start < targetStart && targetStart < end) { 26560 // descending copy from end 26561 for (var i = len - 1; i >= 0; --i) { 26562 target[i + targetStart] = this[i + start]; 26563 } 26564 } else { 26565 Uint8Array.prototype.set.call(target, this.subarray(start, end), targetStart); 26566 } 26567 26568 return len; 26569 }; // Usage: 26570 // buffer.fill(number[, offset[, end]]) 26571 // buffer.fill(buffer[, offset[, end]]) 26572 // buffer.fill(string[, offset[, end]][, encoding]) 26573 26574 26575 Buffer.prototype.fill = function fill(val, start, end, encoding) { 26576 // Handle string cases: 26577 if (typeof val === 'string') { 26578 if (typeof start === 'string') { 26579 encoding = start; 26580 start = 0; 26581 end = this.length; 26582 } else if (typeof end === 'string') { 26583 encoding = end; 26584 end = this.length; 26585 } 26586 26587 if (encoding !== undefined && typeof encoding !== 'string') { 26588 throw new TypeError('encoding must be a string'); 26589 } 26590 26591 if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { 26592 throw new TypeError('Unknown encoding: ' + encoding); 26593 } 26594 26595 if (val.length === 1) { 26596 var code = val.charCodeAt(0); 26597 26598 if (encoding === 'utf8' && code < 128 || encoding === 'latin1') { 26599 // Fast path: If `val` fits into a single byte, use that numeric value. 26600 val = code; 26601 } 26602 } 26603 } else if (typeof val === 'number') { 26604 val = val & 255; 26605 } // Invalid ranges are not set to a default, so can range check early. 26606 26607 26608 if (start < 0 || this.length < start || this.length < end) { 26609 throw new RangeError('Out of range index'); 26610 } 26611 26612 if (end <= start) { 26613 return this; 26614 } 26615 26616 start = start >>> 0; 26617 end = end === undefined ? this.length : end >>> 0; 26618 if (!val) val = 0; 26619 var i; 26620 26621 if (typeof val === 'number') { 26622 for (i = start; i < end; ++i) { 26623 this[i] = val; 26624 } 26625 } else { 26626 var bytes = Buffer.isBuffer(val) ? val : Buffer.from(val, encoding); 26627 var len = bytes.length; 26628 26629 if (len === 0) { 26630 throw new TypeError('The value "' + val + '" is invalid for argument "value"'); 26631 } 26632 26633 for (i = 0; i < end - start; ++i) { 26634 this[i + start] = bytes[i % len]; 26635 } 26636 } 26637 26638 return this; 26639 }; // HELPER FUNCTIONS 26640 // ================ 26641 26642 26643 var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g; 26644 26645 function base64clean(str) { 26646 // Node takes equal signs as end of the Base64 encoding 26647 str = str.split('=')[0]; // Node strips out invalid characters like \n and \t from the string, base64-js does not 26648 26649 str = str.trim().replace(INVALID_BASE64_RE, ''); // Node converts strings with length < 2 to '' 26650 26651 if (str.length < 2) return ''; // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not 26652 26653 while (str.length % 4 !== 0) { 26654 str = str + '='; 26655 } 26656 26657 return str; 26658 } 26659 26660 function toHex(n) { 26661 if (n < 16) return '0' + n.toString(16); 26662 return n.toString(16); 26663 } 26664 26665 function utf8ToBytes(string, units) { 26666 units = units || Infinity; 26667 var codePoint; 26668 var length = string.length; 26669 var leadSurrogate = null; 26670 var bytes = []; 26671 26672 for (var i = 0; i < length; ++i) { 26673 codePoint = string.charCodeAt(i); // is surrogate component 26674 26675 if (codePoint > 0xD7FF && codePoint < 0xE000) { 26676 // last char was a lead 26677 if (!leadSurrogate) { 26678 // no lead yet 26679 if (codePoint > 0xDBFF) { 26680 // unexpected trail 26681 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); 26682 continue; 26683 } else if (i + 1 === length) { 26684 // unpaired lead 26685 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); 26686 continue; 26687 } // valid lead 26688 26689 26690 leadSurrogate = codePoint; 26691 continue; 26692 } // 2 leads in a row 26693 26694 26695 if (codePoint < 0xDC00) { 26696 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); 26697 leadSurrogate = codePoint; 26698 continue; 26699 } // valid surrogate pair 26700 26701 26702 codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000; 26703 } else if (leadSurrogate) { 26704 // valid bmp char, but last char was a lead 26705 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); 26706 } 26707 26708 leadSurrogate = null; // encode utf8 26709 26710 if (codePoint < 0x80) { 26711 if ((units -= 1) < 0) break; 26712 bytes.push(codePoint); 26713 } else if (codePoint < 0x800) { 26714 if ((units -= 2) < 0) break; 26715 bytes.push(codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80); 26716 } else if (codePoint < 0x10000) { 26717 if ((units -= 3) < 0) break; 26718 bytes.push(codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80); 26719 } else if (codePoint < 0x110000) { 26720 if ((units -= 4) < 0) break; 26721 bytes.push(codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80); 26722 } else { 26723 throw new Error('Invalid code point'); 26724 } 26725 } 26726 26727 return bytes; 26728 } 26729 26730 function asciiToBytes(str) { 26731 var byteArray = []; 26732 26733 for (var i = 0; i < str.length; ++i) { 26734 // Node's code seems to be doing this and not & 0x7F.. 26735 byteArray.push(str.charCodeAt(i) & 0xFF); 26736 } 26737 26738 return byteArray; 26739 } 26740 26741 function utf16leToBytes(str, units) { 26742 var c, hi, lo; 26743 var byteArray = []; 26744 26745 for (var i = 0; i < str.length; ++i) { 26746 if ((units -= 2) < 0) break; 26747 c = str.charCodeAt(i); 26748 hi = c >> 8; 26749 lo = c % 256; 26750 byteArray.push(lo); 26751 byteArray.push(hi); 26752 } 26753 26754 return byteArray; 26755 } 26756 26757 function base64ToBytes(str) { 26758 return base64.toByteArray(base64clean(str)); 26759 } 26760 26761 function blitBuffer(src, dst, offset, length) { 26762 for (var i = 0; i < length; ++i) { 26763 if (i + offset >= dst.length || i >= src.length) break; 26764 dst[i + offset] = src[i]; 26765 } 26766 26767 return i; 26768 } // ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass 26769 // the `instanceof` check but they should be treated as of that type. 26770 // See: https://github.com/feross/buffer/issues/166 26771 26772 26773 function isInstance(obj, type) { 26774 return obj instanceof type || obj != null && obj.constructor != null && obj.constructor.name != null && obj.constructor.name === type.name; 26775 } 26776 26777 function numberIsNaN(obj) { 26778 // For IE11 support 26779 return obj !== obj; // eslint-disable-line no-self-compare 26780 } 26781 }, {
vendor: 22,463 bytes, lines 26782-27459
26782 "base64-js": 2, 26783 "ieee754": 8 26784 }], 26785 5: [function (_dereq_, module, exports) { 26786 (function (process, global) { 26787 /*! 26788 * @overview es6-promise - a tiny implementation of Promises/A+. 26789 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) 26790 * @license Licensed under MIT license 26791 * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE 26792 * @version 4.1.1 26793 */ 26794 (function (global, factory) { 26795 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : global.ES6Promise = factory(); 26796 })(this, function () { 26797 'use strict'; 26798 26799 function objectOrFunction(x) { 26800 var type = typeof x; 26801 return x !== null && (type === 'object' || type === 'function'); 26802 } 26803 26804 function isFunction(x) { 26805 return typeof x === 'function'; 26806 } 26807 26808 var _isArray = undefined; 26809 26810 if (Array.isArray) { 26811 _isArray = Array.isArray; 26812 } else { 26813 _isArray = function (x) { 26814 return Object.prototype.toString.call(x) === '[object Array]'; 26815 }; 26816 } 26817 26818 var isArray = _isArray; 26819 var len = 0; 26820 var vertxNext = undefined; 26821 var customSchedulerFn = undefined; 26822 26823 var asap = function asap(callback, arg) { 26824 queue[len] = callback; 26825 queue[len + 1] = arg; 26826 len += 2; 26827 26828 if (len === 2) { 26829 // If len is 2, that means that we need to schedule an async flush. 26830 // If additional callbacks are queued before the queue is flushed, they 26831 // will be processed by this flush that we are scheduling. 26832 if (customSchedulerFn) { 26833 customSchedulerFn(flush); 26834 } else { 26835 scheduleFlush(); 26836 } 26837 } 26838 }; 26839 26840 function setScheduler(scheduleFn) { 26841 customSchedulerFn = scheduleFn; 26842 } 26843 26844 function setAsap(asapFn) { 26845 asap = asapFn; 26846 } 26847 26848 var browserWindow = typeof window !== 'undefined' ? window : undefined; 26849 var browserGlobal = browserWindow || {}; 26850 var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; 26851 var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; // test for web worker but not in IE10 26852 26853 var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; // node 26854 26855 function useNextTick() { 26856 // node version 0.10.x displays a deprecation warning when nextTick is used recursively 26857 // see https://github.com/cujojs/when/issues/410 for details 26858 return function () { 26859 return process.nextTick(flush); 26860 }; 26861 } // vertx 26862 26863 26864 function useVertxTimer() { 26865 if (typeof vertxNext !== 'undefined') { 26866 return function () { 26867 vertxNext(flush); 26868 }; 26869 } 26870 26871 return useSetTimeout(); 26872 } 26873 26874 function useMutationObserver() { 26875 var iterations = 0; 26876 var observer = new BrowserMutationObserver(flush); 26877 var node = document.createTextNode(''); 26878 observer.observe(node, { 26879 characterData: true 26880 }); 26881 return function () { 26882 node.data = iterations = ++iterations % 2; 26883 }; 26884 } // web worker 26885 26886 26887 function useMessageChannel() { 26888 var channel = new MessageChannel(); 26889 channel.port1.onmessage = flush; 26890 return function () { 26891 return channel.port2.postMessage(0); 26892 }; 26893 } 26894 26895 function useSetTimeout() { 26896 // Store setTimeout reference so es6-promise will be unaffected by 26897 // other code modifying setTimeout (like sinon.useFakeTimers()) 26898 var globalSetTimeout = setTimeout; 26899 return function () { 26900 return globalSetTimeout(flush, 1); 26901 }; 26902 } 26903 26904 var queue = new Array(1000); 26905 26906 function flush() { 26907 for (var i = 0; i < len; i += 2) { 26908 var callback = queue[i]; 26909 var arg = queue[i + 1]; 26910 callback(arg); 26911 queue[i] = undefined; 26912 queue[i + 1] = undefined; 26913 } 26914 26915 len = 0; 26916 } 26917 26918 function attemptVertx() { 26919 try { 26920 var r = _dereq_; 26921 var vertx = r('vertx'); 26922 vertxNext = vertx.runOnLoop || vertx.runOnContext; 26923 return useVertxTimer(); 26924 } catch (e) { 26925 return useSetTimeout(); 26926 } 26927 } 26928 26929 var scheduleFlush = undefined; // Decide what async method to use to triggering processing of queued callbacks: 26930 26931 if (isNode) { 26932 scheduleFlush = useNextTick(); 26933 } else if (BrowserMutationObserver) { 26934 scheduleFlush = useMutationObserver(); 26935 } else if (isWorker) { 26936 scheduleFlush = useMessageChannel(); 26937 } else if (browserWindow === undefined && typeof _dereq_ === 'function') { 26938 scheduleFlush = attemptVertx(); 26939 } else { 26940 scheduleFlush = useSetTimeout(); 26941 } 26942 26943 function then(onFulfillment, onRejection) { 26944 var _arguments = arguments; 26945 var parent = this; 26946 var child = new this.constructor(noop); 26947 26948 if (child[PROMISE_ID] === undefined) { 26949 makePromise(child); 26950 } 26951 26952 var _state = parent._state; 26953 26954 if (_state) { 26955 (function () { 26956 var callback = _arguments[_state - 1]; 26957 asap(function () { 26958 return invokeCallback(_state, child, callback, parent._result); 26959 }); 26960 })(); 26961 } else { 26962 subscribe(parent, child, onFulfillment, onRejection); 26963 } 26964 26965 return child; 26966 } 26967 /** 26968 `Promise.resolve` returns a promise that will become resolved with the 26969 passed `value`. It is shorthand for the following: 26970 26971 ```javascript 26972 let promise = new Promise(function(resolve, reject){ 26973 resolve(1); 26974 }); 26975 26976 promise.then(function(value){ 26977 // value === 1 26978 }); 26979 ``` 26980 26981 Instead of writing the above, your code now simply becomes the following: 26982 26983 ```javascript 26984 let promise = Promise.resolve(1); 26985 26986 promise.then(function(value){ 26987 // value === 1 26988 }); 26989 ``` 26990 26991 @method resolve 26992 @static 26993 @param {Any} value value that the returned promise will be resolved with 26994 Useful for tooling. 26995 @return {Promise} a promise that will become fulfilled with the given 26996 `value` 26997 */ 26998 26999 27000 function resolve$1(object) { 27001 /*jshint validthis:true */ 27002 var Constructor = this; 27003 27004 if (object && typeof object === 'object' && object.constructor === Constructor) { 27005 return object; 27006 } 27007 27008 var promise = new Constructor(noop); 27009 resolve(promise, object); 27010 return promise; 27011 } 27012 27013 var PROMISE_ID = Math.random().toString(36).substring(16); 27014 27015 function noop() {} 27016 27017 var PENDING = void 0; 27018 var FULFILLED = 1; 27019 var REJECTED = 2; 27020 var GET_THEN_ERROR = new ErrorObject(); 27021 27022 function selfFulfillment() { 27023 return new TypeError("You cannot resolve a promise with itself"); 27024 } 27025 27026 function cannotReturnOwn() { 27027 return new TypeError('A promises callback cannot return that same promise.'); 27028 } 27029 27030 function getThen(promise) { 27031 try { 27032 return promise.then; 27033 } catch (error) { 27034 GET_THEN_ERROR.error = error; 27035 return GET_THEN_ERROR; 27036 } 27037 } 27038 27039 function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) { 27040 try { 27041 then$$1.call(value, fulfillmentHandler, rejectionHandler); 27042 } catch (e) { 27043 return e; 27044 } 27045 } 27046 27047 function handleForeignThenable(promise, thenable, then$$1) { 27048 asap(function (promise) { 27049 var sealed = false; 27050 var error = tryThen(then$$1, thenable, function (value) { 27051 if (sealed) { 27052 return; 27053 } 27054 27055 sealed = true; 27056 27057 if (thenable !== value) { 27058 resolve(promise, value); 27059 } else { 27060 fulfill(promise, value); 27061 } 27062 }, function (reason) { 27063 if (sealed) { 27064 return; 27065 } 27066 27067 sealed = true; 27068 reject(promise, reason); 27069 }, 'Settle: ' + (promise._label || ' unknown promise')); 27070 27071 if (!sealed && error) { 27072 sealed = true; 27073 reject(promise, error); 27074 } 27075 }, promise); 27076 } 27077 27078 function handleOwnThenable(promise, thenable) { 27079 if (thenable._state === FULFILLED) { 27080 fulfill(promise, thenable._result); 27081 } else if (thenable._state === REJECTED) { 27082 reject(promise, thenable._result); 27083 } else { 27084 subscribe(thenable, undefined, function (value) { 27085 return resolve(promise, value); 27086 }, function (reason) { 27087 return reject(promise, reason); 27088 }); 27089 } 27090 } 27091 27092 function handleMaybeThenable(promise, maybeThenable, then$$1) { 27093 if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) { 27094 handleOwnThenable(promise, maybeThenable); 27095 } else { 27096 if (then$$1 === GET_THEN_ERROR) { 27097 reject(promise, GET_THEN_ERROR.error); 27098 GET_THEN_ERROR.error = null; 27099 } else if (then$$1 === undefined) { 27100 fulfill(promise, maybeThenable); 27101 } else if (isFunction(then$$1)) { 27102 handleForeignThenable(promise, maybeThenable, then$$1); 27103 } else { 27104 fulfill(promise, maybeThenable); 27105 } 27106 } 27107 } 27108 27109 function resolve(promise, value) { 27110 if (promise === value) { 27111 reject(promise, selfFulfillment()); 27112 } else if (objectOrFunction(value)) { 27113 handleMaybeThenable(promise, value, getThen(value)); 27114 } else { 27115 fulfill(promise, value); 27116 } 27117 } 27118 27119 function publishRejection(promise) { 27120 if (promise._onerror) { 27121 promise._onerror(promise._result); 27122 } 27123 27124 publish(promise); 27125 } 27126 27127 function fulfill(promise, value) { 27128 if (promise._state !== PENDING) { 27129 return; 27130 } 27131 27132 promise._result = value; 27133 promise._state = FULFILLED; 27134 27135 if (promise._subscribers.length !== 0) { 27136 asap(publish, promise); 27137 } 27138 } 27139 27140 function reject(promise, reason) { 27141 if (promise._state !== PENDING) { 27142 return; 27143 } 27144 27145 promise._state = REJECTED; 27146 promise._result = reason; 27147 asap(publishRejection, promise); 27148 } 27149 27150 function subscribe(parent, child, onFulfillment, onRejection) { 27151 var _subscribers = parent._subscribers; 27152 var length = _subscribers.length; 27153 parent._onerror = null; 27154 _subscribers[length] = child; 27155 _subscribers[length + FULFILLED] = onFulfillment; 27156 _subscribers[length + REJECTED] = onRejection; 27157 27158 if (length === 0 && parent._state) { 27159 asap(publish, parent); 27160 } 27161 } 27162 27163 function publish(promise) { 27164 var subscribers = promise._subscribers; 27165 var settled = promise._state; 27166 27167 if (subscribers.length === 0) { 27168 return; 27169 } 27170 27171 var child = undefined, 27172 callback = undefined, 27173 detail = promise._result; 27174 27175 for (var i = 0; i < subscribers.length; i += 3) { 27176 child = subscribers[i]; 27177 callback = subscribers[i + settled]; 27178 27179 if (child) { 27180 invokeCallback(settled, child, callback, detail); 27181 } else { 27182 callback(detail); 27183 } 27184 } 27185 27186 promise._subscribers.length = 0; 27187 } 27188 27189 function ErrorObject() { 27190 this.error = null; 27191 } 27192 27193 var TRY_CATCH_ERROR = new ErrorObject(); 27194 27195 function tryCatch(callback, detail) { 27196 try { 27197 return callback(detail); 27198 } catch (e) { 27199 TRY_CATCH_ERROR.error = e; 27200 return TRY_CATCH_ERROR; 27201 } 27202 } 27203 27204 function invokeCallback(settled, promise, callback, detail) { 27205 var hasCallback = isFunction(callback), 27206 value = undefined, 27207 error = undefined, 27208 succeeded = undefined, 27209 failed = undefined; 27210 27211 if (hasCallback) { 27212 value = tryCatch(callback, detail); 27213 27214 if (value === TRY_CATCH_ERROR) { 27215 failed = true; 27216 error = value.error; 27217 value.error = null; 27218 } else { 27219 succeeded = true; 27220 } 27221 27222 if (promise === value) { 27223 reject(promise, cannotReturnOwn()); 27224 return; 27225 } 27226 } else { 27227 value = detail; 27228 succeeded = true; 27229 } 27230 27231 if (promise._state !== PENDING) {// noop 27232 } else if (hasCallback && succeeded) { 27233 resolve(promise, value); 27234 } else if (failed) { 27235 reject(promise, error); 27236 } else if (settled === FULFILLED) { 27237 fulfill(promise, value); 27238 } else if (settled === REJECTED) { 27239 reject(promise, value); 27240 } 27241 } 27242 27243 function initializePromise(promise, resolver) { 27244 try { 27245 resolver(function resolvePromise(value) { 27246 resolve(promise, value); 27247 }, function rejectPromise(reason) { 27248 reject(promise, reason); 27249 }); 27250 } catch (e) { 27251 reject(promise, e); 27252 } 27253 } 27254 27255 var id = 0; 27256 27257 function nextId() { 27258 return id++; 27259 } 27260 27261 function makePromise(promise) { 27262 promise[PROMISE_ID] = id++; 27263 promise._state = undefined; 27264 promise._result = undefined; 27265 promise._subscribers = []; 27266 } 27267 27268 function Enumerator$1(Constructor, input) { 27269 this._instanceConstructor = Constructor; 27270 this.promise = new Constructor(noop); 27271 27272 if (!this.promise[PROMISE_ID]) { 27273 makePromise(this.promise); 27274 } 27275 27276 if (isArray(input)) { 27277 this.length = input.length; 27278 this._remaining = input.length; 27279 this._result = new Array(this.length); 27280 27281 if (this.length === 0) { 27282 fulfill(this.promise, this._result); 27283 } else { 27284 this.length = this.length || 0; 27285 27286 this._enumerate(input); 27287 27288 if (this._remaining === 0) { 27289 fulfill(this.promise, this._result); 27290 } 27291 } 27292 } else { 27293 reject(this.promise, validationError()); 27294 } 27295 } 27296 27297 function validationError() { 27298 return new Error('Array Methods must be provided an Array'); 27299 } 27300 27301 Enumerator$1.prototype._enumerate = function (input) { 27302 for (var i = 0; this._state === PENDING && i < input.length; i++) { 27303 this._eachEntry(input[i], i); 27304 } 27305 }; 27306 27307 Enumerator$1.prototype._eachEntry = function (entry, i) { 27308 var c = this._instanceConstructor; 27309 var resolve$$1 = c.resolve; 27310 27311 if (resolve$$1 === resolve$1) { 27312 var _then = getThen(entry); 27313 27314 if (_then === then && entry._state !== PENDING) { 27315 this._settledAt(entry._state, i, entry._result); 27316 } else if (typeof _then !== 'function') { 27317 this._remaining--; 27318 this._result[i] = entry; 27319 } else if (c === Promise$2) { 27320 var promise = new c(noop); 27321 handleMaybeThenable(promise, entry, _then); 27322 27323 this._willSettleAt(promise, i); 27324 } else { 27325 this._willSettleAt(new c(function (resolve$$1) { 27326 return resolve$$1(entry); 27327 }), i); 27328 } 27329 } else { 27330 this._willSettleAt(resolve$$1(entry), i); 27331 } 27332 }; 27333 27334 Enumerator$1.prototype._settledAt = function (state, i, value) { 27335 var promise = this.promise; 27336 27337 if (promise._state === PENDING) { 27338 this._remaining--; 27339 27340 if (state === REJECTED) { 27341 reject(promise, value); 27342 } else { 27343 this._result[i] = value; 27344 } 27345 } 27346 27347 if (this._remaining === 0) { 27348 fulfill(promise, this._result); 27349 } 27350 }; 27351 27352 Enumerator$1.prototype._willSettleAt = function (promise, i) { 27353 var enumerator = this; 27354 subscribe(promise, undefined, function (value) { 27355 return enumerator._settledAt(FULFILLED, i, value); 27356 }, function (reason) { 27357 return enumerator._settledAt(REJECTED, i, reason); 27358 }); 27359 }; 27360 /** 27361 `Promise.all` accepts an array of promises, and returns a new promise which 27362 is fulfilled with an array of fulfillment values for the passed promises, or 27363 rejected with the reason of the first passed promise to be rejected. It casts all 27364 elements of the passed iterable to promises as it runs this algorithm. 27365 27366 Example: 27367 27368 ```javascript 27369 let promise1 = resolve(1); 27370 let promise2 = resolve(2); 27371 let promise3 = resolve(3); 27372 let promises = [ promise1, promise2, promise3 ]; 27373 27374 Promise.all(promises).then(function(array){ 27375 // The array here would be [ 1, 2, 3 ]; 27376 }); 27377 ``` 27378 27379 If any of the `promises` given to `all` are rejected, the first promise 27380 that is rejected will be given as an argument to the returned promises's 27381 rejection handler. For example: 27382 27383 Example: 27384 27385 ```javascript 27386 let promise1 = resolve(1); 27387 let promise2 = reject(new Error("2")); 27388 let promise3 = reject(new Error("3")); 27389 let promises = [ promise1, promise2, promise3 ]; 27390 27391 Promise.all(promises).then(function(array){ 27392 // Code here never runs because there are rejected promises! 27393 }, function(error) { 27394 // error.message === "2" 27395 }); 27396 ``` 27397 27398 @method all 27399 @static 27400 @param {Array} entries array of promises 27401 @param {String} label optional string for labeling the promise. 27402 Useful for tooling. 27403 @return {Promise} promise that is fulfilled when all `promises` have been 27404 fulfilled, or rejected if any of them become rejected. 27405 @static 27406 */ 27407 27408 27409 function all$1(entries) { 27410 return new Enumerator$1(this, entries).promise; 27411 } 27412 /** 27413 `Promise.race` returns a new promise which is settled in the same way as the 27414 first passed promise to settle. 27415 27416 Example: 27417 27418 ```javascript 27419 let promise1 = new Promise(function(resolve, reject){ 27420 setTimeout(function(){ 27421 resolve('promise 1'); 27422 }, 200); 27423 }); 27424 27425 let promise2 = new Promise(function(resolve, reject){ 27426 setTimeout(function(){ 27427 resolve('promise 2'); 27428 }, 100); 27429 }); 27430 27431 Promise.race([promise1, promise2]).then(function(result){ 27432 // result === 'promise 2' because it was resolved before promise1 27433 // was resolved. 27434 }); 27435 ``` 27436 27437 `Promise.race` is deterministic in that only the state of the first 27438 settled promise matters. For example, even if other promises given to the 27439 `promises` array argument are resolved, but the first settled promise has 27440 become rejected before the other promises became fulfilled, the returned 27441 promise will become rejected: 27442 27443 ```javascript 27444 let promise1 = new Promise(function(resolve, reject){ 27445 setTimeout(function(){ 27446 resolve('promise 1'); 27447 }, 200); 27448 }); 27449 27450 let promise2 = new Promise(function(resolve, reject){ 27451 setTimeout(function(){ 27452 reject(new Error('promise 2')); 27453 }, 100); 27454 }); 27455 27456 Promise.race([promise1, promise2]).then(function(result){ 27457 // Code here never runs 27458 }, function(reason){ 27459 // reason.message === 'promise 2' because promise 2 be
27459came rejected before 27460 // promise 1 became fulfilled 27461 }); 27462 ``` 27463 27464 An example real-world use case is implementing timeouts: 27465 27466 ```javascript 27467 Promise.race([ajax('foo.json'), timeout(5000)]) 27468 ``` 27469 27470 @method race 27471 @static 27472 @param {Array} promises array of promises to observe 27473 Useful for tooling. 27474 @return {Promise} a promise which settles in the same way as the first passed 27475 promise to settle. 27476 */ 27477 27478 27479 function race$1(entries) { 27480 /*jshint validthis:true */ 27481 var Constructor = this; 27482 27483 if (!isArray(entries)) { 27484 return new Constructor(function (_, reject) { 27485 return reject(new TypeError('You must pass an array to race.')); 27486 }); 27487 } else { 27488 return new Constructor(function (resolve, reject) { 27489 var length = entries.length; 27490 27491 for (var i = 0; i < length; i++) { 27492 Constructor.resolve(entries[i]).then(resolve, reject); 27493 } 27494 }); 27495 } 27496 } 27497 /** 27498 `Promise.reject` returns a promise rejected with the passed `reason`. 27499 It is shorthand for the following: 27500 27501 ```javascript 27502 let promise = new Promise(function(resolve, reject){ 27503 reject(new Error('WHOOPS')); 27504 }); 27505 27506 promise.then(function(value){ 27507 // Code here doesn't run because the promise is rejected! 27508 }, function(reason){ 27509 // reason.message === 'WHOOPS' 27510 }); 27511 ``` 27512 27513 Instead of writing the above, your code now simply becomes the following: 27514 27515 ```javascript 27516 let promise = Promise.reject(new Error('WHOOPS')); 27517 27518 promise.then(function(value){ 27519 // Code here doesn't run because the promise is rejected! 27520 }, function(reason){ 27521 // reason.message === 'WHOOPS' 27522 }); 27523 ``` 27524 27525 @method reject 27526 @static 27527 @param {Any} reason value that the returned promise will be rejected with. 27528 Useful for tooling. 27529 @return {Promise} a promise rejected with the given `reason`. 27530 */ 27531 27532 27533 function reject$1(reason) { 27534 /*jshint validthis:true */ 27535 var Constructor = this; 27536 var promise = new Constructor(noop); 27537 reject(promise, reason); 27538 return promise; 27539 } 27540 27541 function needsResolver() { 27542 throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); 27543 } 27544 27545 function needsNew() { 27546 throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object c
27546onstructor cannot be called as a function."); 27547 } 27548 /** 27549 Promise objects represent the eventual result of an asynchronous operation. The 27550 primary way of interacting with a promise is through its `then` method, which 27551 registers callbacks to receive either a promise's eventual value or the reason 27552 why the promise cannot be fulfilled. 27553 27554 Terminology 27555 ----------- 27556 27557 - `promise` is an object or function with a `then` method whose behavior conforms to this specification. 27558 - `thenable` is an object or function that defines a `then` method. 27559 - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). 27560 - `exception` is a value that is thrown using the throw statement. 27561 - `reason` is a value that indicates why a promise was rejected. 27562 - `settled` the final resting state of a promise, fulfilled or rejected. 27563 27564 A promise can be in one of three states: pending, fulfilled, or rejected. 27565 27566 Promises that are fulfilled have a fulfillment value and are in the fulfilled 27567 state. Promises that are rejected have a rejection reason and are in the 27568 rejected state. A fulfillment value is never a thenable. 27569 27570 Promises can also be said to *resolve* a value. If this value is also a 27571 promise, then the original promise's settled state will match the value's 27572 settled state. So a promise that *resolves* a promise that rejects will 27573 itself reject, and a promise that *resolves* a promise that fulfills will 27574 itself fulfill. 27575 27576 27577 Basic Usage: 27578 ------------ 27579 27580 ```js 27581 let promise = new Promise(function(resolve, reject) { 27582 // on success 27583 resolve(value); 27584 27585 // on failure 27586 reject(reason); 27587 }); 27588 27589 promise.then(function(value) { 27590 // on fulfillment 27591 }, function(reason) { 27592 // on rejection 27593 }); 27594 ``` 27595 27596 Advanced Usage: 27597 --------------- 27598 27599 Promises shine when abstracting away asynchronous interactions such as 27600 `XMLHttpRequest`s. 27601 27602 ```js 27603 function getJSON(url) { 27604 return new Promise(function(resolve, reject){ 27605 let xhr = new XMLHttpRequest(); 27606 27607 xhr.open('GET', url); 27608 xhr.onreadystatechange = handler; 27609 xhr.responseType = 'json'; 27610 xhr.setRequestHeader('Accept', 'application/json'); 27611 xhr.send(); 27612 27613 function handler() { 27614 if (this.readyState === this.DONE) { 27615 if (this.status === 200) { 27616 resolve(this.response); 27617 } else { 27618 reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); 27619 } 27620 } 27621 }; 27622 }); 27623 } 27624 27625 getJSON('/posts.json').then(function(json) { 27626 // on fulfillment 27627 }, function(reason) { 27628 // on rejection 27629 }); 27630 ``` 27631 27632 Unlike callbacks, promises are great composable primitives. 27633 27634 ```js 27635 Promise.all([ 27636 getJSON('/posts'), 27637 getJSON('/comments') 27638 ]).then(function(values){ 27639 values[0] // => postsJSON 27640 values[1] // => commentsJSON 27641 27642 return values; 27643 }); 27644 ``` 27645 27646 @class Promise 27647 @param {function} resolver 27648 Useful for tooling. 27649 @constructor 27650 */ 27651 27652 27653 function Promise$2(resolver) { 27654 this[PROMISE_ID] = nextId(); 27655 this._result = this._state = undefined; 27656 this._subscribers = []; 27657 27658 if (noop !== resolver) { 27659 typeof resolver !== 'function' && needsResolver(); 27660 this instanceof Promise$2 ? initializePromise(this, resolver) : needsNew(); 27661 } 27662 } 27663 27664 Promise$2.all = all$1; 27665 Promise$2.race = race$1; 27666 Promise$2.resolve = resolve$1; 27667 Promise$2.reject = reject$1; 27668 Promise$2._setScheduler = setScheduler; 27669 Promise$2._setAsap = setAsap; 27670 Promise$2._asap = asap; 27671 Promise$2.prototype = { 27672 constructor: Promise$2, 27673 27674 /** 27675 The primary way of interacting with a promise is through its `then` method, 27676 which registers callbacks to receive either a promise's eventual value or the 27677 reason why the promise cannot be fulfilled. 27678 27679 ```js 27680 findUser().then(function(user){ 27681 // user is available 27682 }, function(reason){ 27683 // user is unavailable, and you are given the reason why 27684 }); 27685 ``` 27686 27687 Chaining 27688 -------- 27689 27690 The return value of `then` is itself a promise. This second, 'downstream' 27691 promise is resolved with the return value of the first promise's fulfillment 27692 or rejection handler, or rejected if the handler throws an exception. 27693 27694 ```js 27695 findUser().then(function (user) { 27696 return user.name; 27697 }, function (reason) { 27698 return 'default name'; 27699 }).then(function (userName) { 27700 // If `findUser` fulfilled, `userName` will be the user's name, otherwise it 27701 // will be `'default name'` 27702 }); 27703 27704 findUser().then(function (user) { 27705 throw new Error('Found user, but still unhappy'); 27706 }, function (reason) { 27707 throw new Error('`findUser` rejected and we're unhappy'); 27708 }).then(function (value) { 27709 // never reached 27710 }, function (reason) { 27711 // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. 27712 // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. 27713 }); 27714 ``` 27715 If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. 27716 27717 ```js 27718 findUser().then(function (user) { 27719 throw new PedagogicalException('Upstream error'); 27720 }).then(function (value) { 27721 // never reached 27722 }).then(function (value) { 27723 // never reached 27724 }, function (reason) { 27725 // The `PedgagocialException` is propagated all the way down to here 27726 }); 27727 ``` 27728 27729 Assimilation 27730 ------------ 27731 27732 Sometimes the value you want to propagate to a downstream promise can only be 27733 retrieved asynchronously. This can be achieved by returning a promise in the 27734 fulfillment or rejection handler. The downstream promise will then be pending 27735 until the returned promise is settled. This is called *assimilation*. 27736 27737 ```js 27738 findUser().then(function (user) { 27739 return findCommentsByAuthor(user); 27740 }).then(function (comments) { 27741 // The user's comments are now available 27742 }); 27743 ``` 27744 27745 If the assimliated promise rejects, then the downstream promise will also reject. 27746 27747 ```js 27748 findUser().then(function (user) { 27749 return findCommentsByAuthor(user); 27750 }).then(function (comments) { 27751 // If `findCommentsByAuthor` fulfills, we'll have the value here 27752 }, function (reason) { 27753 // If `findCommentsByAuthor` rejects, we'll have the reason here 27754 }); 27755 ``` 27756
27757 Simple Example 27758 -------------- 27759 27760 Synchronous Example 27761 27762 ```javascript 27763 let result; 27764 27765 try { 27766 result = findResult(); 27767 // success 27768 } catch(reason) { 27769 // failure 27770 } 27771 ``` 27772 27773 Errback Example 27774 27775 ```js 27776 findResult(function(result, err){ 27777 if (err) { 27778 // failure 27779 } else { 27780 // success 27781 } 27782 }); 27783 ``` 27784 27785 Promise Example; 27786 27787 ```javascript 27788 findResult().then(function(result){ 27789 // success 27790 }, function(reason){ 27791 // failure 27792 }); 27793 ``` 27794 27795 Advanced Example 27796 -------------- 27797 27798 Synchronous Example 27799 27800 ```javascript 27801 let author, books; 27802 27803 try { 27804 author = findAuthor(); 27805 books = findBooksByAuthor(author); 27806 // success 27807 } catch(reason) { 27808 // failure 27809 } 27810 ``` 27811 27812 Errback Example 27813 27814 ```js 27815 27816 function foundBooks(books) { 27817 27818 } 27819 27820 function failure(reason) { 27821 27822 } 27823 27824 findAuthor(function(author, err){ 27825 if (err) { 27826 failure(err); 27827 // failure 27828 } else { 27829 try { 27830 findBoooksByAuthor(author, function(books, err) { 27831 if (err) { 27832 failure(err); 27833 } else { 27834 try { 27835 foundBooks(books); 27836 } catch(reason) { 27837 failure(reason); 27838 } 27839 } 27840 }); 27841 } catch(error) { 27842 failure(err); 27843 } 27844 // success 27845 } 27846 }); 27847 ``` 27848 27849 Promise Example; 27850 27851 ```javascript 27852 findAuthor(). 27853 then(findBooksByAuthor). 27854 then(function(books){ 27855 // found books 27856 }).catch(function(reason){ 27857 // something went wrong 27858 }); 27859 ``` 27860 27861 @method then 27862 @param {Function} onFulfilled 27863 @param {Function} onRejected 27864 Useful for tooling. 27865 @return {Promise} 27866 */ 27867 then: then, 27868 27869 /** 27870 `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same 27871 as the catch block of a try/catch statement. 27872 27873 ```js 27874 function findAuthor(){ 27875 throw new Error('couldn't find that author'); 27876 } 27877 27878 // synchronous 27879 try { 27880 findAuthor(); 27881 } catch(reason) { 27882 // something went wrong 27883 } 27884 27885 // async with promises 27886 findAuthor().catch(function(reason){ 27887 // something went wrong 27888 }); 27889 ``` 27890 27891 @method catch 27892 @param {Function} onRejection 27893 Useful for tooling. 27894 @return {Promise} 27895 */ 27896 'catch': function _catch(onRejection) { 27897 return this.then(null, onRejection); 27898 } 27899 }; 27900 /*global self*/ 27901 27902 function polyfill$1() { 27903 var local = undefined; 27904 27905 if (typeof global !== 'undefined') { 27906 local = global; 27907 } else if (typeof self !== 'undefined') { 27908 local = self; 27909 } else { 27910 try { 27911 local = Function('return this')(); 27912 } catch (e) { 27913 throw new Error('polyfill failed because global object is unavailable in this environment'); 27914 } 27915 } 27916 27917 var P = local.Promise; 27918 27919 if (P) { 27920 var promiseToString = null; 27921 27922 try { 27923 promiseToString = Object.prototype.toString.call(P.resolve()); 27924 } catch (e) {// silently ignored 27925 } 27926 27927 if (promiseToString === '[object Promise]' && !P.cast) { 27928 return; 27929 } 27930 } 27931 27932 local.Promise = Promise$2; 27933 } // Strange compat.. 27934 27935 27936 Promise$2.polyfill = polyfill$1; 27937 Promise$2.Promise = Promise$2; 27938 return Promise$2; 27939 }); 27940 }).call(this, _dereq_('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}); 27941 }, {
vendor: 4,224 bytes, lines 27942-28061
27942 "_process": 11 27943 }], 27944 6: [function (_dereq_, module, exports) { 27945 (function (global, factory) { 27946 if (typeof define === 'function' && define.amd) { 27947 define(['exports', 'module'], factory); 27948 } else if (typeof exports !== 'undefined' && typeof module !== 'undefined') { 27949 factory(exports, module); 27950 } else { 27951 var mod = { 27952 exports: {} 27953 }; 27954 factory(mod.exports, mod); 27955 global.fetchJsonp = mod.exports; 27956 } 27957 })(this, function (exports, module) { 27958 'use strict'; 27959 27960 var defaultOptions = { 27961 timeout: 5000, 27962 jsonpCallback: 'callback', 27963 jsonpCallbackFunction: null 27964 }; 27965 27966 function generateCallbackFunction() { 27967 return 'jsonp_' + Date.now() + '_' + Math.ceil(Math.random() * 100000); 27968 } 27969 27970 function clearFunction(functionName) { 27971 // IE8 throws an exception when you try to delete a property on window 27972 // http://stackoverflow.com/a/1824228/751089 27973 try { 27974 delete window[functionName]; 27975 } catch (e) { 27976 window[functionName] = undefined; 27977 } 27978 } 27979 27980 function removeScript(scriptId) { 27981 var script = document.getElementById(scriptId); 27982 27983 if (script) { 27984 document.getElementsByTagName('head')[0].removeChild(script); 27985 } 27986 } 27987 27988 function fetchJsonp(_url) { 27989 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; // to avoid param reassign 27990 27991 var url = _url; 27992 var timeout = options.timeout || defaultOptions.timeout; 27993 var jsonpCallback = options.jsonpCallback || defaultOptions.jsonpCallback; 27994 var timeoutId = undefined; 27995 return new Promise(function (resolve, reject) { 27996 var callbackFunction = options.jsonpCallbackFunction || generateCallbackFunction(); 27997 var scriptId = jsonpCallback + '_' + callbackFunction; 27998 27999 window[callbackFunction] = function (response) { 28000 resolve({ 28001 ok: true, 28002 // keep consistent with fetch API 28003 json: function json() { 28004 return Promise.resolve(response); 28005 } 28006 }); 28007 if (timeoutId) clearTimeout(timeoutId); 28008 removeScript(scriptId); 28009 clearFunction(callbackFunction); 28010 }; // Check if the user set their own params, and if not add a ? to start a list of params 28011 28012 28013 url += url.indexOf('?') === -1 ? '?' : '&'; 28014 var jsonpScript = document.createElement('script'); 28015 jsonpScript.setAttribute('src', '' + url + jsonpCallback + '=' + callbackFunction); 28016 28017 if (options.charset) { 28018 jsonpScript.setAttribute('charset', options.charset); 28019 } 28020 28021 jsonpScript.id = scriptId; 28022 document.getElementsByTagName('head')[0].appendChild(jsonpScript); 28023 timeoutId = setTimeout(function () { 28024 reject(new Error('JSONP request to ' + _url + ' timed out')); 28025 clearFunction(callbackFunction); 28026 removeScript(scriptId); 28027 28028 window[callbackFunction] = function () { 28029 clearFunction(callbackFunction); 28030 }; 28031 }, timeout); // Caught if got 404/500 28032 28033 jsonpScript.onerror = function () { 28034 reject(new Error('JSONP request to ' + _url + ' failed')); 28035 clearFunction(callbackFunction); 28036 removeScript(scriptId); 28037 if (timeoutId) clearTimeout(timeoutId); 28038 }; 28039 }); 28040 } // export as global function 28041 28042 /* 28043 let local; 28044 if (typeof global !== 'undefined') { 28045 local = global; 28046 } else if (typeof self !== 'undefined') { 28047 local = self; 28048 } else { 28049 try { 28050 local = Function('return this')(); 28051 } catch (e) { 28052 throw new Error('polyfill failed because global object is unavailable in this environment'); 28053 } 28054 } 28055 local.fetchJsonp = fetchJsonp; 28056 */ 28057 28058 28059 module.exports = fetchJsonp; 28060 }); 28061 }, {}],
28062 7: [function (_dereq_, module, exports) { 28063 /* FileSaver.js 28064 * A saveAs() FileSaver implementation. 28065 * 1.3.2 28066 * 2016-06-16 18:25:19 28067 * 28068 * By Eli Grey, http://eligrey.com 28069 * License: MIT 28070 * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md 28071 */ 28072 28073 /*global self */ 28074 28075 /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 28076 28077 /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 28078 var saveAs = saveAs || function (view) { 28079 "use strict"; // IE <10 is explicitly unsupported 28080 28081 if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { 28082 return; 28083 } 28084 28085 var doc = view.document // only get URL when necessary in case Blob.js hasn't overridden it yet 28086 , 28087 get_URL = function () { 28088 return view.URL || view.webkitURL || view; 28089 }, 28090 save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"), 28091 can_use_save_link = "download" in save_link, 28092 click = function (node) { 28093 var event = new MouseEvent("click"); 28094 node.dispatchEvent(event); 28095 }, 28096 is_safari = /constructor/i.test(view.HTMLElement) || view.safari, 28097 is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent), 28098 throw_outside = function (ex) { 28099 (view.setImmediate || view.setTimeout)(function () { 28100 throw ex; 28101 }, 0); 28102 }, 28103 force_saveable_type = "application/octet-stream" // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to 28104 , 28105 arbitrary_revoke_timeout = 1000 * 40 // in ms 28106 , 28107 revoke = function (file) { 28108 var revoker = function () { 28109 if (typeof file === "string") { 28110 // file is an object URL 28111 get_URL().revokeObjectURL(file); 28112 } else { 28113 // file is a File 28114 file.remove(); 28115 } 28116 }; 28117 28118 setTimeout(revoker, arbitrary_revoke_timeout); 28119 }, 28120 dispatch = function (filesaver, event_types, event) { 28121 event_types = [].concat(event_types); 28122 var i = event_types.length; 28123 28124 while (i--) { 28125 var listener = filesaver["on" + event_types[i]]; 28126 28127 if (typeof listener === "function") { 28128 try { 28129 listener.call(filesaver, event || filesaver); 28130 } catch (ex) { 28131 throw_outside(ex); 28132 } 28133 } 28134 } 28135 }, 28136 auto_bom = function (blob) { 28137 // prepend BOM for UTF-8 XML and text/* types (including HTML) 28138 // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF 28139 if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { 28140 return new Blob([String.fromCharCode(0xFEFF), blob], { 28141 type: blob.type 28142 }); 28143 } 28144 28145 return blob; 28146 }, 28147 FileSaver = function (blob, name, no_auto_bom) { 28148 if (!no_auto_bom) { 28149 blob = auto_bom(blob); 28150 } // First try a.download, then web filesystem, then object URLs 28151 28152 28153 var filesaver = this, 28154 type = blob.type, 28155 force = type === force_saveable_type, 28156 object_url, 28157 dispatch_all = function () { 28158 dispatch(filesaver, "writestart progress write writeend".split(" ")); 28159 } // on any filesys errors revert to saving with object URLs 28160 , 28161 fs_error = function () { 28162 if ((is_chrome_ios || force && is_safari) && view.FileReader) { 28163 // Safari doesn't allow downloading of blob urls 28164 var reader = new FileReader(); 28165 28166 reader.onloadend = function () { 28167 var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;'); 28168 var popup = view.open(url, '_blank'); 28169 if (!popup) view.location.href = url; 28170 url = undefined; // release reference before dispatching 28171 28172 filesaver.readyState = filesaver.DONE; 28173 dispatch_all(); 28174 }; 28175
vendor: 1,104 bytes, lines 28176-28207
28176 reader.readAsDataURL(blob); 28177 filesaver.readyState = filesaver.INIT; 28178 return; 28179 } // don't create more object URLs than needed 28180 28181 28182 if (!object_url) { 28183 object_url = get_URL().createObjectURL(blob); 28184 } 28185 28186 if (force) { 28187 view.location.href = object_url; 28188 } else { 28189 var opened = view.open(object_url, "_blank"); 28190 28191 if (!opened) { 28192 // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html 28193 view.location.href = object_url; 28194 } 28195 } 28196 28197 filesaver.readyState = filesaver.DONE; 28198 dispatch_all(); 28199 revoke(object_url); 28200 }; 28201 28202 filesaver.readyState = filesaver.INIT; 28203 28204 if (can_use_save_link) { 28205 object_url = get_URL().createObjectURL(blob); 28206 setTimeout(function () { 28207 save_link.href = object_url;
28208 save_link.download = name; 28209 click(save_link); 28210 dispatch_all(); 28211 revoke(object_url); 28212 filesaver.readyState = filesaver.DONE; 28213 }); 28214 return; 28215 } 28216 28217 fs_error(); 28218 }, 28219 FS_proto = FileSaver.prototype, 28220 saveAs = function (blob, name, no_auto_bom) { 28221 return new FileSaver(blob, name || blob.name || "download", no_auto_bom); 28222 }; // IE 10+ (native saveAs) 28223 28224 28225 if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { 28226 return function (blob, name, no_auto_bom) { 28227 name = name || blob.name || "download"; 28228 28229 if (!no_auto_bom) { 28230 blob = auto_bom(blob); 28231 } 28232 28233 return navigator.msSaveOrOpenBlob(blob, name); 28234 }; 28235 } 28236 28237 FS_proto.abort = function () {}; 28238 28239 FS_proto.readyState = FS_proto.INIT = 0; 28240 FS_proto.WRITING = 1; 28241 FS_proto.DONE = 2; 28242 FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null; 28243 return saveAs; 28244 }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content); // `self` is undefined in Firefox for Android content script context 28245 // while `this` is nsIContentFrameMessageManager 28246 // with an attribute `content` that corresponds to the window 28247 28248 28249 if (typeof module !== "undefined" && module.exports) { 28250 module.exports.saveAs = saveAs; 28251 } else if (typeof define !== "undefined" && define !== null && define.amd !== null) { 28252 define("FileSaver.js", function () { 28253 return saveAs; 28254 }); 28255 } 28256 }, {}], 28257 8: [function (_dereq_, module, exports) { 28258 exports.read = function (buffer, offset, isLE, mLen, nBytes) { 28259 var e, m; 28260 var eLen = nBytes * 8 - mLen - 1; 28261 var eMax = (1 << eLen) - 1; 28262 var eBias = eMax >> 1; 28263 var nBits = -7; 28264 var i = isLE ? nBytes - 1 : 0; 28265 var d = isLE ? -1 : 1; 28266 var s = buffer[offset + i]; 28267 i += d; 28268 e = s & (1 << -nBits) - 1; 28269 s >>= -nBits; 28270 nBits += eLen; 28271 28272 for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} 28273 28274 m = e & (1 << -nBits) - 1; 28275 e >>= -nBits; 28276 nBits += mLen; 28277 28278 for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} 28279 28280 if (e === 0) { 28281 e = 1 - eBias; 28282 } else if (e === eMax) { 28283 return m ? NaN : (s ? -1 : 1) * Infinity; 28284 } else { 28285 m = m + Math.pow(2, mLen); 28286 e = e - eBias; 28287 } 28288 28289 return (s ? -1 : 1) * m * Math.pow(2, e - mLen); 28290 }; 28291 28292 exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { 28293 var e, m, c; 28294 var eLen = nBytes * 8 - mLen - 1; 28295 var eMax = (1 << eLen) - 1; 28296 var eBias = eMax >> 1; 28297 var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0; 28298 var i = isLE ? 0 : nBytes - 1; 28299 var d = isLE ? 1 : -1; 28300 var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0; 28301 value = Math.abs(value); 28302 28303 if (isNaN(value) || value === Infinity) { 28304 m = isNaN(value) ? 1 : 0; 28305 e = eMax; 28306 } else { 28307 e = Math.floor(Math.log(value) / Math.LN2); 28308 28309 if (value * (c = Math.pow(2, -e)) < 1) { 28310 e--; 28311 c *= 2; 28312 } 28313 28314 if (e + eBias >= 1) { 28315 value += rt / c; 28316 } else { 28317 value += rt * Math.pow(2, 1 - eBias); 28318 } 28319 28320 if (value * c >= 2) { 28321 e++; 28322 c /= 2; 28323 } 28324 28325 if (e + eBias >= eMax) { 28326 m = 0; 28327 e = eMax; 28328 } else if (e + eBias >= 1) { 28329 m = (value * c - 1) * Math.pow(2, mLen); 28330 e = e + eBias; 28331 } else { 28332 m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); 28333 e = 0; 28334 } 28335 } 28336 28337 for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} 28338 28339 e = e << mLen | m; 28340 eLen += mLen; 28341 28342 for (; eLen > 0;
28342 buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} 28343 28344 buffer[offset + i - d] |= s * 128; 28345 }; 28346 }, {}], 28347 9: [function (_dereq_, module, exports) { 28348 /* 28349 28350 Copyright 2000, Silicon Graphics, Inc. All Rights Reserved. 28351 Copyright 2015, Google Inc. All Rights Reserved. 28352 28353 Permission is hereby granted, free of charge, to any person obtaining a copy 28354 of this software and associated documentation files (the "Software"), to 28355 deal in the Software without restriction, including without limitation the 28356 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 28357 sell copies of the Software, and to permit persons to whom the Software is 28358 furnished to do so, subject to the following conditions: 28359 28360 The above copyright notice including the dates of first publication and 28361 either this permission notice or a reference to http://oss.sgi.com/projects/FreeB/ 28362 shall be included in all copies or substantial portions of the Software. 28363 28364 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28365 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28366 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28367 SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 28368 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 28369 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28370 28371 Original Code. The Original Code is: OpenGL Sample Implementation, 28372 Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, 28373 Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. 28374 Copyright in any portions created by third parties is as indicated 28375 elsewhere herein. All Rights Reserved. 28376 */ 28377 'use strict'; 28378 28379 var n; 28380 28381 function t(a, b) { 28382 return a.b === b.b && a.a === b.a; 28383 } 28384 28385 function u(a, b) { 28386 return a.b < b.b || a.b === b.b && a.a <= b.a; 28387 } 28388 28389 function v(a, b, c) { 28390 var d = b.b - a.b, 28391 e = c.b - b.b; 28392 return 0 < d + e ? d < e ? b.a - a.a + d / (d + e) * (a.a - c.a) : b.a - c.a + e / (d + e) * (c.a - a.a) : 0; 28393 } 28394 28395 function x(a, b, c) { 28396 var d = b.b - a.b, 28397 e = c.b - b.b; 28398 return 0 < d + e ? (b.a - c.a) * d + (b.a - a.a) * e : 0; 28399 } 28400 28401 function z(a, b) { 28402 return a.a < b.a || a.a === b.a && a.b <= b.b; 28403 } 28404 28405 function aa(a, b, c) { 28406 var d = b.a - a.a, 28407 e = c.a - b.a; 28408 return 0 < d + e ? d < e ? b.b - a.b + d / (d + e) * (a.b - c.b) : b.b - c.b + e / (d + e) * (c.b - a.b) : 0; 28409 } 28410 28411 function ba(a, b, c) { 28412 var d = b.a - a.a, 28413 e = c.a - b.a; 28414 return 0 < d + e ? (b.b - c.b) * d + (b.b - a.b) * e : 0; 28415 } 28416 28417 function ca(a) { 28418 return u(a.b.a, a.a); 28419 } 28420 28421 function da(a) { 28422 return u(a.a, a.b.a); 28423 } 28424 28425 function A(a, b, c, d) { 28426 a = 0 > a ? 0 : a; 28427 c = 0 > c ? 0 : c; 28428 return a <= c ? 0 === c ? (b + d) / 2 : b + a / (a + c) * (d - b) : d + c / (a + c) * (b - d); 28429 } 28430 28431 ; 28432 28433 function ea(a) { 28434 var b = B(a.b); 28435 C(b, a.c); 28436 C(b.b, a.c); 28437 D(b, a.a); 28438 return b; 28439 } 28440 28441 function E(a, b) { 28442 var c = !1, 28443 d = !1; 28444 a !== b && (b.a !== a.a && (d = !0, F(b.a, a.a)), b.d !== a.d && (c = !0, G(b.d, a.d)), H(b, a), d || (C(b, a.a), a.a.c = a), c || (D(b, a.d), a.d.a = a)); 28445 } 28446 28447 function I(a) { 28448 var b = a.b, 28449 c = !1; 28450 a.d !== a.b.d && (c = !0, G(a.d, a.b.d)); 28451 a.c === a ? F(a.a, null) : (a.b.d.a = J(a), a.a.c = a.c, H(a, J(a)), c || D(a, a.d)); 28452 b.c === b ? (F(b.a, null), G(b.d, null)) : (a.d.a = J(b), b.a.c = b.c, H(b, J(b))); 28453 fa(a); 28454 } 28455 28456 function K(a) { 28457 var b = B(a), 28458 c = b.b; 28459 H(b, a.e); 28460 b.a = a.b.a; 28461 C(c, b.a); 28462 b.d = c.d = a.d; 28463 b = b.b; 28464 H(a.b, J(a.b)); 28465 H(a.b, b); 28466 a.b.a = b.a;
28467 b.b.a.c = b.b; 28468 b.b.d = a.b.d; 28469 b.f = a.f; 28470 b.b.f = a.b.f; 28471 return b; 28472 } 28473 28474 function L(a, b) { 28475 var c = !1, 28476 d = B(a), 28477 e = d.b; 28478 b.d !== a.d && (c = !0, G(b.d, a.d)); 28479 H(d, a.e); 28480 H(e, b); 28481 d.a = a.b.a; 28482 e.a = b.a; 28483 d.d = e.d = a.d; 28484 a.d.a = e; 28485 c || D(d, a.d); 28486 return d; 28487 } 28488 28489 function B(a) { 28490 var b = new M(), 28491 c = new M(), 28492 d = a.b.h; 28493 c.h = d; 28494 d.b.h = b; 28495 b.h = a; 28496 a.b.h = c; 28497 b.b = c; 28498 b.c = b; 28499 b.e = c; 28500 c.b = b; 28501 c.c = c; 28502 return c.e = b; 28503 } 28504 28505 function H(a, b) { 28506 var c = a.c, 28507 d = b.c; 28508 c.b.e = b; 28509 d.b.e = a; 28510 a.c = d; 28511 b.c = c; 28512 } 28513 28514 function C(a, b) { 28515 var c = b.f, 28516 d = new N(b, c); 28517 c.e = d; 28518 b.f = d; 28519 c = d.c = a; 28520 28521 do c.a = d, c = c.c; while (c !== a); 28522 } 28523 28524 function D(a, b) { 28525 var c = b.d, 28526 d = new ga(b, c); 28527 c.b = d; 28528 b.d = d; 28529 d.a = a; 28530 d.c = b.c; 28531 c = a; 28532 28533 do c.d = d, c = c.e; while (c !== a); 28534 } 28535 28536 function fa(a) { 28537 var b = a.h; 28538 a = a.b.h; 28539 b.b.h = a; 28540 a.b.h = b; 28541 } 28542 28543 function F(a, b) { 28544 var c = a.c, 28545 d = c; 28546 28547 do d.a = b, d = d.c; while (d !== c); 28548 28549 c = a.f; 28550 d = a.e; 28551 d.f = c; 28552 c.e = d; 28553 } 28554 28555 function G(a, b) { 28556 var c = a.a, 28557 d = c; 28558 28559 do d.d = b, d = d.e; while (d !== c); 28560 28561 c = a.d; 28562 d = a.b; 28563 d.d = c; 28564 c.b = d; 28565 } 28566 28567 ; 28568 28569 function ha(a) { 28570 var b = 0; 28571 Math.abs(a[1]) > Math.abs(a[0]) && (b = 1); 28572 Math.abs(a[2]) > Math.abs(a[b]) && (b = 2); 28573 return b; 28574 } 28575 28576 ; 28577 var O = 4 * 1E150; 28578 28579 function P(a, b) { 28580 a.f += b.f; 28581 a.b.f += b.b.f; 28582 } 28583 28584 function ia(a, b, c) { 28585 a = a.a; 28586 b = b.a; 28587 c = c.a; 28588 if (b.b.a === a) return c.b.a === a ? u(b.a, c.a) ? 0 >= x(c.b.a, b.a, c.a) : 0 <= x(b.b.a, c.a, b.a) : 0 >= x(c.b.a, a, c.a); 28589 if (c.b.a === a) return 0 <= x(b.b.a, a, b.a); 28590 b = v(b.b.a, a, b.a); 28591 a = v(c.b.a, a, c.a); 28592 return b >= a; 28593 } 28594 28595 function Q(a) { 28596 a.a.i = null; 28597 var b = a.e; 28598 b.a.c = b.c; 28599 b.c.a = b.a; 28600 a.e = null; 28601 } 28602 28603 function ja(a, b) { 28604 I(a.a); 28605 a.c = !1; 28606 a.a = b; 28607 b.i = a; 28608 } 28609 28610 function ka(a) { 28611 var b = a.a.a; 28612 28613 do a = R(a); while (a.a.a === b); 28614 28615 a.c && (b = L(S(a).a.b, a.a.e), ja(a, b), a = R(a)); 28616 return a; 28617 } 28618 28619 function la(a, b, c) { 28620 var d = new ma(); 28621 d.a = c; 28622 d.e = na(a.f, b.e, d); 28623 return c.i = d; 28624 } 28625 28626 function oa(a, b) { 28627 switch (a.s) { 28628 case 100130: 28629 return 0 !== (b & 1); 28630 28631 case 100131: 28632 return 0 !== b; 28633 28634 case 100132: 28635 return 0 < b; 28636 28637 case 100133: 28638 return 0 > b; 28639 28640 case 100134: 28641 return 2 <= b || -2 >= b; 28642 } 28643 28644 return !1; 28645 } 28646 28647 function pa(a) { 28648 var b = a.a, 28649 c = b.d; 28650 c.c = a.d; 28651 c.a = b; 28652 Q(a); 28653 } 28654 28655 function T(a, b, c) { 28656 a = b; 28657 28658 for (b = b.a; a !== c;) { 28659 a.c = !1; 28660 var d = S(a), 28661 e = d.a; 28662 28663 if (e.a !== b.a) { 28664 if (!d.c) { 28665 pa(a); 28666 break; 28667 } 28668 28669 e = L(b.c.b, e.b); 28670 ja(d, e); 28671 } 28672 28673 b.c !== e && (E(J(e), e), E(b, e)); 28674 pa(a); 28675 b = d.a; 28676 a = d; 28677 } 28678 28679 return b; 28680 } 28681 28682 function U(a, b, c, d, e, f) { 28683 var g = !0; 28684 28685 do la(a, b, c.b), c = c.c; while (c !== d); 28686 28687 for (null === e && (e = S(b).a.b.c);;) { 28688 d = S(b); 28689 c = d.a.b; 28690 if (c.a !== e.a) break; 28691 c.c !== e && (E(J(c), c), E(J(e), c)); 28692 d.f = b.f - c.f; 28693 d.d = oa(a, d.f); 28694 b.b = !0; 28695 !g && qa(a, b) && (P(c, e), Q(b), I(e)); 28696 g = !1; 28697 b = d; 28698 e = c; 28699 } 28700 28701 b.b = !0; 28702 f && ra(a, b); 28703 } 28704 28705 function sa(a, b, c, d, e) { 28706 var f = [b.g[0], b.g[1], b.g[2]]; 28707 b.d = null; 28708 b.d = a.o ? a.o(f, c, d, a.c) || null : null; 28709 null === b.d && (e ? a.n || (V(a, 100156), a.n = !0) : b.d = c[0]); 28710 } 28711 28712 function ta(a, b, c) { 28713 var d = [null, null, null, null]; 28714 d[0] = b.a.d; 28715 d[1] = c.a.d; 28716 sa(a, b.a, d, [.5, .5, 0, 0], !1); 28717 E(b, c); 28718 } 28719 28720 function ua(a, b, c, d, e) { 28721 var f = Math.abs(b.b - a.b) + Math.abs(b.a - a.a), 28722 g = Math.abs(c.b - a.b) + Math.abs(c.a - a.a), 28723 h = e + 1; 28724 d[e] = .5 * g / (f + g); 28725 d[h] = .5 * f / (f + g); 28726 a.g[0] += d[e] * b.g[0] + d[h] * c.g[0]; 28727 a.g[1] += d[e] * b.g[1] + d[h] * c.g[1]; 28728 a.g[2] += d[e] * b.g[2] + d[h] * c.g[2]; 28729 } 28730 28731 function qa(a, b) { 28732 var c = S(b), 28733 d = b.a, 28734 e = c.a; 28735 28736 if (u(d.a, e.a)) { 28737 if (0 < x(e.b.a, d.a, e.a)) return !1; 28738 if (!t(d.a, e.a)) K(e.b), E(d, J(e)), b.b = c.b = !0;else if (d.a !== e.a) { 28739 var c = a.e, 28740 f = d.a.h; 28741 28742 if (0 <= f) { 28743 var c = c.b, 28744 g = c.d, 28745 h = c.e, 28746 k = c.c, 28747 l = k[f]; 28748 g[l] = g[c.a]; 28749 k[g[l]] = l; 28750 l <= --c.a && (1 >= l ? W(c, l) : u(h[g[l >> 1]], h[g[l]]) ? W(c, l) : va(c, l)); 28751 h[f] = null; 28752 k[f] = c.b; 28753 c.b = f; 28754 } else for (c.c[-(f + 1)] = null; 0 < c.a && null === c.c[c.d[c.a - 1]];) --c.a; 28755 28756 ta(a, J(e), d); 28757 } 28758 } else { 28759 if (0 > x(d.b.a, e.a, d.a)) return !1; 28760 R(b).b = b.b = !0; 28761 K(d.b); 28762 E(J(e), d); 28763 } 28764 28765 return !0; 28766 } 28767 28768 function wa(a, b) { 28769 var c = S(b), 28770 d = b.a, 28771 e = c.a, 28772 f = d.a, 28773 g = e.a, 28774 h = d.b.a, 28775 k = e.b.a,
28776 l = new N(); 28777 x(h, a.a, f); 28778 x(k, a.a, g); 28779 if (f === g || Math.min(f.a, h.a) > Math.max(g.a, k.a)) return !1; 28780 28781 if (u(f, g)) { 28782 if (0 < x(k, f, g)) return !1; 28783 } else if (0 > x(h, g, f)) return !1; 28784 28785 var r = h, 28786 p = f, 28787 q = k, 28788 y = g, 28789 m, 28790 w; 28791 u(r, p) || (m = r, r = p, p = m); 28792 u(q, y) || (m = q, q = y, y = m); 28793 u(r, q) || (m = r, r = q, q = m, m = p, p = y, y = m); 28794 u(q, p) ? u(p, y) ? (m = v(r, q, p), w = v(q, p, y), 0 > m + w && (m = -m, w = -w), l.b = A(m, q.b, w, p.b)) : (m = x(r, q, p), w = -x(r, y, p), 0 > m + w && (m = -m, w = -w), l.b = A(m, q.b, w, y.b)) : l.b = (q.b + p.b) / 2; 28795 z(r, p) || (m = r, r = p, p = m); 28796 z(q, y) || (m = q, q = y, y = m); 28797 z(r, q) || (m = r, r = q, q = m, m = p, p = y, y = m); 28798 z(q, p) ? z(p, y) ? (m = aa(r, q, p), w = aa(q, p, y), 0 > m + w && (m = -m, w = -w), l.a = A(m, q.a, w, p.a)) : (m = ba(r, q, p), w = -ba(r, y, p), 0 > m + w && (m = -m, w = -w), l.a = A(m, q.a, w, y.a)) : l.a = (q.a + p.a) / 2; 28799 u(l, a.a) && (l.b = a.a.b, l.a = a.a.a); 28800 r = u(f, g) ? f : g; 28801 u(r, l) && (l.b = r.b, l.a = r.a); 28802 if (t(l, f) || t(l, g)) return qa(a, b), !1; 28803 28804 if (!t(h, a.a) && 0 <= x(h, a.a, l) || !t(k, a.a) && 0 >= x(k, a.a, l)) { 28805 if (k === a.a) return K(d.b), E(e.b, d), b = ka(b), d = S(b).a, T(a, S(b), c), U(a, b, J(d), d, d, !0), !0; 28806 28807 if (h === a.a) { 28808 K(e.b); 28809 E(d.e, J(e)); 28810 f = c = b; 28811 g = f.a.b.a; 28812 28813 do f = R(f); while (f.a.b.a === g); 28814 28815 b = f; 28816 f = S(b).a.b.c; 28817 c.a = J(e); 28818 e = T(a, c, null); 28819 U(a, b, e.c, d.b.c, f, !0); 28820 return !0; 28821 } 28822 28823 0 <= x(h, a.a, l) && (R(b).b = b.b = !0, K(d.b), d.a.b = a.a.b, d.a.a = a.a.a); 28824 0 >= x(k, a.a, l) && (b.b = c.b = !0, K(e.b), e.a.b = a.a.b, e.a.a = a.a.a); 28825 return !1; 28826 } 28827 28828 K(d.b); 28829 K(e.b); 28830 E(J(e), d); 28831 d.a.b = l.b; 28832 d.a.a = l.a; 28833 d.a.h = xa(a.e, d.a); 28834 d = d.a; 28835 e = [0, 0, 0, 0]; 28836 l = [f.d, h.d, g.d, k.d]; 28837 d.g[0] = d.g[1] = d.g[2] = 0; 28838 ua(d, f, h, e, 0); 28839 ua(d, g, k, e, 2); 28840 sa(a, d, l, e, !0); 28841 R(b).b = b.b = c.b = !0; 28842 return !1; 28843 } 28844 28845 function ra(a, b) { 28846 for (var c = S(b);;) { 28847 for (; c.b;) b = c, c = S(c); 28848 28849 if (!b.b && (c = b, b = R(b), null === b || !b.b)) break; 28850 b.b = !1; 28851 var d = b.a, 28852 e = c.a, 28853 f; 28854 if (f = d.b.a !== e.b.a) a: { 28855 f = b; 28856 var g = S(f), 28857 h = f.a, 28858 k = g.a, 28859 l = void 0; 28860 28861 if (u(h.b.a, k.b.a)) { 28862 if (0 > x(h.b.a, k.b.a, h.a)) { 28863 f = !1; 28864 break a; 28865 } 28866 28867 R(f).b = f.b = !0; 28868 l = K(h); 28869 E(k.b, l); 28870 l.d.c = f.d; 28871 } else { 28872 if (0 < x(k.b.a, h.b.a, k.a)) { 28873 f = !1; 28874 break a; 28875 } 28876 28877 f.b = g.b = !0; 28878 l = K(k); 28879 E(h.e, k.b); 28880 l.b.d.c = f.d; 28881 } 28882 28883 f = !0; 28884 } 28885 f && (c.c ? (Q(c), I(e), c = S(b), e = c.a) : b.c && (Q(b), I(d), b = R(c), d = b.a)); 28886 if (d.a !== e.a) if (d.b.a === e.b.a || b.c || c.c || d.b.a !== a.a && e.b.a !== a.a) qa(a, b);else if (wa(a, b)) break; 28887 d.a === e.a && d.b.a === e.b.a && (P(e, d), Q(b), I(d), b = R(c)); 28888 } 28889 } 28890 28891 function ya(a, b) { 28892 a.a = b; 28893 28894 for (var c = b.c; null === c.i;) if (c = c.c, c === b.c) { 28895 var c = a, 28896 d = b, 28897 e = new ma(); 28898 e.a = d.c.b; 28899 var f = c.f, 28900 g = f.a; 28901 28902 do g = g.a; while (null !== g.b && !f.c(f.b, e, g.b)); 28903 28904 var f = g.b, 28905 h = S(f), 28906 e = f.a, 28907 g = h.a; 28908 if (0 === x(e.b.a, d, e.a)) e = f.a, t(e.a, d) || t(e.b.a, d) || (K(e.b), f.c && (I(e.c), f.c = !1), E(d.c, e), ya(c, d));else { 28909 var k = u(g.b.a, e.b.a) ? f : h, 28910 h = void 0; 28911 f.d || k.c ? (k === f ? h = L(d.c.b, e.e) : h = L(g.b.c.b, d.c).b, k.c ? ja(k, h) : (e = c, f = la(c, f, h), f.f = R(f).f + f.a.f, f.d = oa(e, f.f)), ya(c, d)) : U(c, f, d.c, d.c, null, !0); 28912 } 28913 return; 28914 } 28915 28916 c = ka(c.i); 28917 e = S(c); 28918 f = e.a; 28919 e = T(a, e, null); 28920 28921 if (e.c === f) { 28922 var f = e, 28923 e = f.c, 28924 g = S(c), 28925 h = c.a, 28926 k = g.a, 28927 l = !1; 28928 h.b.a !== k.b.a && wa(a, c); 28929 t(h.a, a.a) && (E(J(e), h), c = ka(c), e = S(c).a, T(a, S(c), g), l = !0); 28930 t(k.a, a.a) && (E(f, J(k)), f = T(a, g, null), l = !0); 28931 l ? U(a, c, f.c, e, e, !0) : (u(k.a, h.a) ? d = J(k) : d = h, d = L(f.c.b, d), U(a, c, d, d.c, d.c, !1), d.b.i.c = !0, ra(a, c)); 28932 } else U(a, c, e.c, f, f, !0); 28933 } 28934 28935 function za(a, b) { 28936 var c = new ma(), 28937 d = ea(a.b); 28938 d.a.b = O; 28939 d.a.a = b; 28940 d.b.a.b = -O; 28941 d.b.a.a = b; 28942 a.a = d.b.a; 28943 c.a = d; 28944 c.f = 0; 28945 c.d = !1; 28946 c.c = !1; 28947 c.h = !0; 28948 c.b = !1; 28949 d = a.f; 28950 d = na(d, d.a, c); 28951 c.e = d; 28952 } 28953 28954 ; 28955 28956 function Aa(a) { 28957 this.a = new Ba(); 28958 this.b = a; 28959 this.c = ia; 28960 } 28961 28962 function na(a, b, c) { 28963 do b = b.c; while (null !== b.b && !a.c(a.b, b.b, c)); 28964 28965 a = new Ba(c, b.a, b); 28966 b.a.c = a; 28967 return b.a = a; 28968 } 28969 28970 ; 28971 28972 function Ba(a, b, c) { 28973 this.b = a || null; 28974 this.a = b || this; 28975 this.c = c || this; 28976 } 28977 28978 ; 28979 28980 function X() { 28981 this.d = Y; 28982 this.p = this.b = this.q = null; 28983 this.j = [0, 0, 0]; 28984 this.s = 100130; 28985 this.n = !1; 28986 this.o = this.a = this.e = this.f = null; 28987 this.m = !1; 28988 this.c = this.r = this.i = this.k = this.l = this.h = null; 28989 } 28990 28991 var Y = 0; 28992 n = X.prototype; 28993 28994 n.x = function () { 28995 Z(this, Y); 28996 }; 28997 28998 n.B = function (a, b) { 28999 switch (a) { 29000 case 100142: 29001 return; 29002 29003 case 100140: 29004 switch (b) { 29005 case 100130: 29006 case 100131: 29007 case 100132: 29008 case 100133: 29009 case 100134: 29010 this.s = b; 29011 return; 29012 } 29013 29014 break; 29015 29016 case 100141: 29017 this.m = !!b; 29018 return; 29019 29020 default: 29021 V(this, 100900); 29022 return; 29023 } 29024 29025 V(this, 100901); 29026 }; 29027 29028 n.y = function (a) { 29029 switch (a) { 29030 case 100142: 29031 return 0; 29032 29033 case 100140: 29034 return this.s; 29035 29036 case 100141: 29037 return this.m; 29038 29039 default: 29040 V(this, 100900); 29041 } 29042 29043 return !1; 29044 }; 29045 29046 n.A = function (a, b, c) { 29047 this.j[0] = a; 29048 this.j[1] = b; 29049 this.j[2] = c; 29050 }; 29051 29052 n.z = function (a, b) { 29053 var c = b ? b : null; 29054 29055 switch (a) { 29056 case 100100: 29057 case 100106: 29058 this.h = c; 29059 break; 29060 29061 case 100104: 29062 case 100110: 29063 this.l = c; 29064 break; 29065 29066 case 100101: 29067 case 100107: 29068 this.k = c; 29069 break; 29070 29071 case 100102: 29072 case 100108: 29073 this.i = c; 29074 break; 29075 29076 case 100103: 29077 case 100109: 29078 this.p = c; 29079 break; 29080 29081 case 100105: 29082 case 100111: 29083 this.o = c; 29084 break; 29085 29086 case 100112: 29087 this.r = c; 29088 break; 29089 29090 default: 29091 V(this, 100900); 29092 } 29093 }; 29094
29095 n.C = function (a, b) { 29096 var c = !1, 29097 d = [0, 0, 0]; 29098 Z(this, 2); 29099 29100 for (var e = 0; 3 > e; ++e) { 29101 var f = a[e]; 29102 -1E150 > f && (f = -1E150, c = !0); 29103 1E150 < f && (f = 1E150, c = !0); 29104 d[e] = f; 29105 } 29106 29107 c && V(this, 100155); 29108 c = this.q; 29109 null === c ? (c = ea(this.b), E(c, c.b)) : (K(c), c = c.e); 29110 c.a.d = b; 29111 c.a.g[0] = d[0]; 29112 c.a.g[1] = d[1]; 29113 c.a.g[2] = d[2]; 29114 c.f = 1; 29115 c.b.f = -1; 29116 this.q = c; 29117 }; 29118 29119 n.u = function (a) { 29120 Z(this, Y); 29121 this.d = 1; 29122 this.b = new Ca(); 29123 this.c = a; 29124 }; 29125 29126 n.t = function () { 29127 Z(this, 1); 29128 this.d = 2; 29129 this.q = null; 29130 }; 29131 29132 n.v = function () { 29133 Z(this, 2); 29134 this.d = 1; 29135 }; 29136 29137 n.w = function () { 29138 Z(this, 1); 29139 this.d = Y; 29140 var a = this.j[0], 29141 b = this.j[1], 29142 c = this.j[2], 29143 d = !1, 29144 e = [a, b, c]; 29145 29146 if (0 === a && 0 === b && 0 === c) { 29147 for (var b = [-2 * 1E150, -2 * 1E150, -2 * 1E150], f = [2 * 1E150, 2 * 1E150, 2 * 1E150], c = [], g = [], d = this.b.c, a = d.e; a !== d; a = a.e) for (var h = 0; 3 > h; ++h) { 29148 var k = a.g[h]; 29149 k < f[h] && (f[h] = k, g[h] = a); 29150 k > b[h] && (b[h] = k, c[h] = a); 29151 } 29152 29153 a = 0; 29154 b[1] - f[1] > b[0] - f[0] && (a = 1); 29155 b[2] - f[2] > b[a] - f[a] && (a = 2); 29156 if (f[a] >= b[a]) e[0] = 0, e[1] = 0, e[2] = 1;else { 29157 b = 0; 29158 f = g[a]; 29159 c = c[a]; 29160 g = [0, 0, 0]; 29161 f = [f.g[0] - c.g[0], f.g[1] - c.g[1], f.g[2] - c.g[2]]; 29162 h = [0, 0, 0]; 29163 29164 for (a = d.e; a !== d; a = a.e) h[0] = a.g[0] - c.g[0], h[1] = a.g[1] - c.g[1], h[2] = a.g[2] - c.g[2], g[0] = f[1] * h[2] - f[2] * h[1], g[1] = f[2] * h[0] - f[0] * h[2], g[2] = f[0] * h[1] - f[1] * h[0], k = g[0] * g[0] + g[1] * g[1] + g[2] * g[2], k > b && (b = k, e[0] = g[0], e[1] = g[1], e[2] = g[2]); 29165 29166 0 >= b && (e[0] = e[1] = e[2] = 0, e[ha(f)] = 1); 29167 } 29168 d = !0; 29169 } 29170 29171 g = ha(e); 29172 a = this.b.c; 29173 b = (g + 1) % 3; 29174 c = (g + 2) % 3; 29175 g = 0 < e[g] ? 1 : -1; 29176 29177 for (e = a.e; e !== a; e = e.e) e.b = e.g[b], e.a = g * e.g[c]; 29178 29179 if (d) { 29180 e = 0; 29181 d = this.b.a; 29182 29183 for (a = d.b; a !== d; a = a.b) if (b = a.a, !(0 >= b.f)) { 29184 do e += (b.a.b - b.b.a.b) * (b.a.a + b.b.a.a), b = b.e; while (b !== a.a); 29185 } 29186 29187 if (0 > e) for (e = this.b.c, d = e.e; d !== e; d = d.e) d.a = -d.a; 29188 } 29189 29190 this.n = !1; 29191 e = this.b.b; 29192 29193 for (a = e.h; a !== e; a = d) if (d = a.h, b = a.e, t(a.a, a.b.a) && a.e.e !== a && (ta(this, b, a), I(a), a = b, b = a.e), b.e === a) { 29194 if (b !== a) { 29195 if (b === d || b === d.b) d = d.h; 29196 I(b); 29197 } 29198 29199 if (a === d || a === d.b) d = d.h; 29200 I(a); 29201 } 29202 29203 this.e = e = new Da(); 29204 d = this.b.c; 29205 29206 for (a = d.e; a !== d; a = a.e) a.h = xa(e, a); 29207 29208 Ea(e); 29209 this.f = new Aa(this); 29210 za(this, -O); 29211 29212 for (za(this, O); null !== (e = Fa(this.e));) { 29213 for (;;) { 29214 a: if (a = this.e, 0 === a.a) d = Ga(a.b);else if (d = a.c[a.d[a.a - 1]], 0 !== a.b.a && (a = Ga(a.b), u(a, d))) { 29215 d = a; 29216 break a; 29217 } 29218 29219 if (null === d || !t(d, e)) break; 29220 d = Fa(this.e); 29221 ta(this, e.c, d.c); 29222 } 29223 29224 ya(this, e); 29225 } 29226 29227 this.a = this.f.a.a.b.a.a; 29228 29229 for (e = 0; null !== (d = this.f.a.a.b);) d.h || ++e, Q(d); 29230 29231 this.f = null; 29232 e = this.e; 29233 e.b = null; 29234 e.d = null; 29235 this.e = e.c = null; 29236 e = this.b; 29237 29238 for (a = e.a.b; a !== e.a; a = d) d = a.b, a = a.a, a.e.e === a && (P(a.c, a), I(a)); 29239 29240 if (!this.n) { 29241 e = this.b; 29242 if (this.m) for (a = e.b.h; a !== e.b; a = d) d = a.h, a.b.d.c !== a.d.c ? a.f = a.d.c ? 1 : -1 : I(a);else for (a = e.a.b; a !== e.a; a = d) if (d = a.b, a.c) { 29243 for (a = a.a; u(a.b.a, a.a); a = a.c.b); 29244 29245 for (; u(a.a, a.b.a); a = a.e); 29246 29247 b = a.c.b; 29248 29249 for (c = void 0; a.e !== b;) if (u(a.b.a, b.a)) { 29250 for (; b.e !== a && (ca(b.e) || 0 >= x(b.a, b.b.a, b.e.b.a));) c = L(b.e, b), b = c.b; 29251 29252 b = b.c.b; 29253 } else { 29254 for (; b.e !== a && (da(a.c.b) || 0 <= x(a.b.a, a.a, a.c.b.a));) c = L(a, a.c.b), a = c.b; 29255 29256 a = a.e; 29257 } 29258 29259 for (; b.e.e !== a;) c = L(b.e, b), b = c.b; 29260 } 29261 if (this.h || this.i || this.k || this.l) if (this.m) for (e = this.b, d = e.a.b; d !== e.a; d = d.b) { 29262 if (d.c) { 29263 this.h && this.h(2, this.c); 29264 a = d.a; 29265 29266 do this.k && this.k(a.a.d, this.c), a = a.e; while (a !== d.a); 29267 29268 this.i && this.i(this.c); 29269 } 29270 } else { 29271 e = this.b; 29272 d = !!this.l; 29273 a = !1; 29274 b = -1; 29275 29276 for (c = e.a.d; c !== e.a; c = c.d) if (c.c) { 29277 a || (this.h && this.h(4, this.c), a = !0); 29278 g = c.a; 29279 29280 do d && (f = g.b.d.c ? 0 : 1, b !== f && (b = f, this.l && this.l(!!b, this.c))), this.k && this.k(g.a.d, this.c), g = g.e; while (g !== c.a); 29281 } 29282 29283 a && this.i && this.i(this.c); 29284 } 29285 29286 if (this.r) { 29287 e = this.b; 29288 29289 for (a = e.a.b; a !== e.a; a = d) if (d = a.b, !a.c) { 29290 b = a.a; 29291 c = b.e; 29292 g = void 0; 29293 29294 do g = c, c = g.e, g.d = null, null === g.b.d && (g.c === g ? F(g.a, null) : (g.a.c = g.c, H(g, J(g))), f = g.b, f.c === f ? F(f.a, null) : (f.a.c = f.c, H(f, J(f))), fa(g)); while (g !== b); 29295 29296 b = a.d; 29297 a = a.b; 29298 a.d = b; 29299 b.b = a; 29300 } 29301 29302 this.r(this.b); 29303 this.c = this.b = null; 29304 return; 29305 } 29306 } 29307 29308 this.b = this.c = null; 29309 }; 29310 29311 function Z(a, b) { 29312 if (a.d !== b) for (; a.d !== b;) if (a.d < b) switch (a.d) { 29313 case Y: 29314 V(a, 100151); 29315 a.u(null); 29316 break; 29317 29318 case 1: 29319 V(a, 100152), a.t(); 29320 } else switch (a.d) { 29321 case 2: 29322 V(a, 100154); 29323 a.v(); 29324 break; 29325 29326 case 1: 29327 V(a, 100153), a.w(); 29328 } 29329 } 29330 29331 function V(a, b) { 29332 a.p && a.p(b, a.c); 29333 } 29334 29335 ; 29336 29337 function ga(a, b) { 29338 this.b = a || this; 29339 this.d = b || this; 29340 this.a = null; 29341 this.c = !1; 29342 } 29343 29344 ; 29345 29346 function M() { 29347 this.h = this; 29348 this.i = this.d = this.a = this.e = this.c = this.b = null; 29349 this.f = 0; 29350 } 29351 29352 function J(a) { 29353 return a.b.e; 29354 } 29355 29356 ; 29357 29358 function Ca() { 29359 this.c = new N(); 29360 this.a = new ga(); 29361 this.b = new M(); 29362 this.d = new M(); 29363 this.b.b = this.d; 29364 this.d.b = this.b; 29365 } 29366 29367 ; 29368 29369 function N(a, b) { 29370 this.e = a || this; 29371 this.f = b || this; 29372 this.d = this.c = null; 29373 this.g = [0, 0, 0]; 29374 this.h = this.a = this.b = 0; 29375 } 29376 29377 ; 29378 29379 function Da() { 29380 this.c = []; 29381 this.d = null; 29382 this.a = 0; 29383 this.e = !1; 29384 this.b = new Ha(); 29385 } 29386 29387 function Ea(a) { 29388 a.d = []; 29389 29390 for (var b = 0; b < a.a; b++) a.d[b] = b; 29391 29392 a.d.sort(function (a) { 29393 return function (b, e) { 29394 return u(a[b], a[e]) ? 1 : -1; 29395 }; 29396 }(a.c)); 29397 a.e = !0; 29398 Ia(a.b); 29399 } 29400 29401 function xa(a, b) { 29402 if (a.e) { 29403 var c = a.b, 29404 d = ++c.a; 29405 2 * d > c.f && (c.f *= 2, c.c = Ja(c.c, c.f + 1)); 29406 var e; 29407 0 === c.b ? e = d : (e = c.b, c.b = c.c[c.b]); 29408 c.e[e] = b; 29409 c.c[e] = d; 29410 c.d[d] = e; 29411 c.h && va(c, d); 29412 return e; 29413 } 29414 29415 c = a.a++; 29416 a.c[c] = b; 29417 return -(c + 1); 29418 } 29419 29420 function Fa(a) { 29421 if (0 === a.a) return Ka(a.b); 29422 var b = a.c[a.d[a.a - 1]]; 29423 if (0 !== a.b.a && u(Ga(a.b), b)) return Ka(a.b); 29424 29425 do --a.a; while (0 < a.a && null === a.c[a.d[a.a - 1]]); 29426 29427 return b; 29428 } 29429 29430 ; 29431 29432 function Ha() { 29433 this.d = Ja([0], 33); 29434 this.e = [null, null]; 29435 this.c = [0, 0]; 29436 this.a = 0; 29437 this.f = 32; 29438 this.b = 0; 29439 this.h = !1; 29440 this.d[1] = 1; 29441 } 29442 29443 function Ja(a, b) { 29444 for (var c = Array(b), d = 0; d < a.length; d++) c[d] = a[d]; 29445 29446 for (; d < b; d++) c[d] = 0; 29447 29448 return c; 29449 } 29450 29451 function Ia(a) { 29452 for (var b = a.a; 1 <= b; --b) W(a, b); 29453 29454 a.h = !0; 29455 } 29456 29457 function Ga(a) { 29458 return a.e[a.d[1]]; 29459 } 29460 29461 function Ka(a) { 29462 var b = a.d, 29463 c = a.e, 29464 d = a.c, 29465 e = b[1], 29466 f = c[e]; 29467 0 < a.a && (b[1] = b[a.a], d[b[1]] = 1, c[e] = null, d[e] = a.b, a.b = e, 0 < --a.a && W(a, 1)); 29468 return f; 29469 } 29470 29471 function W(a, b) { 29472 for (var c = a.d, d = a.e, e = a.c, f = b, g = c[f];;) { 29473 var h = f << 1; 29474 h < a.a && u(d[c[h + 1]], d[c[h]]) && (h += 1); 29475 var k = c[h]; 29476 29477 if (h > a.a || u(d[g], d[k])) { 29478 c[f] = g; 29479 e[g] = f; 29480 break; 29481 } 29482 29483 c[f] = k; 29484 e[k] = f; 29485 f = h; 29486 } 29487 } 29488 29489 function va(a, b) { 29490 for (var c = a.d, d = a.e, e = a.c, f = b, g = c[f];;) { 29491 var h = f >> 1, 29492 k = c[h]; 29493 29494 if (0 === h || u(d[k], d[g])) { 29495 c[f] = g; 29496 e[g] = f; 29497 break; 29498 } 29499 29500 c[f] = k; 29501 e[k] = f; 29502 f = h; 29503 } 29504 } 29505 29506 ; 29507 29508 function ma() { 29509 this.e = this.a = null; 29510 this.f = 0; 29511 this.c = this.b = this.h = this.d = !1; 29512 } 29513 29514 function S(a) { 29515 return a.e.c.b; 29516 } 29517 29518 function R(a) { 29519 return a.e.a.b; 29520 } 29521 29522 ; 29523 this.libtess = { 29524 GluTesselator: X, 29525 windingRule: { 29526 GLU_TESS_WINDING_ODD: 100130, 29527 GLU_TESS_WINDING_NONZERO: 100131, 29528 GLU_TESS_WINDING_POSITIVE: 100132, 29529 GLU_TESS_WINDING_NEGATIVE: 100133, 29530 GLU_TESS_WINDING_ABS_GEQ_TWO: 100134 29531 }, 29532 primitiveType: { 29533 GL_LINE_LOOP: 2, 29534 GL_TRIANGLES: 4, 29535 GL_TRIANGLE_STRIP: 5, 29536 GL_TRIANGLE_FAN: 6 29537 }, 29538 errorType: { 29539 GLU_TESS_MISSING_BEGIN_POLYGON: 100151, 29540 GLU_TESS_MISSING_END_POLYGON: 100153,
29541 GLU_TESS_MISSING_BEGIN_CONTOUR: 100152, 29542 GLU_TESS_MISSING_END_CONTOUR: 100154, 29543 GLU_TESS_COORD_TOO_LARGE: 100155, 29544 GLU_TESS_NEED_COMBINE_CALLBACK: 100156 29545 }, 29546 gluEnum: { 29547 GLU_TESS_MESH: 100112, 29548 GLU_TESS_TOLERANCE: 100142, 29549 GLU_TESS_WINDING_RULE: 100140, 29550 GLU_TESS_BOUNDARY_ONLY: 100141, 29551 GLU_INVALID_ENUM: 100900, 29552 GLU_INVALID_VALUE: 100901, 29553 GLU_TESS_BEGIN: 100100, 29554 GLU_TESS_VERTEX: 100101, 29555 GLU_TESS_END: 100102, 29556 GLU_TESS_ERROR: 100103, 29557 GLU_TESS_EDGE_FLAG: 100104, 29558 GLU_TESS_COMBINE: 100105, 29559 GLU_TESS_BEGIN_DATA: 100106, 29560 GLU_TESS_VERTEX_DATA: 100107, 29561 GLU_TESS_END_DATA: 100108, 29562 GLU_TESS_ERROR_DATA: 100109, 29563 GLU_TESS_EDGE_FLAG_DATA: 100110, 29564 GLU_TESS_COMBINE_DATA: 100111 29565 } 29566 }; 29567 X.prototype.gluDeleteTess = X.prototype.x; 29568 X.prototype.gluTessProperty = X.prototype.B; 29569 X.prototype.gluGetTessProperty = X.prototype.y; 29570 X.prototype.gluTessNormal = X.prototype.A; 29571 X.prototype.gluTessCallback = X.prototype.z; 29572 X.prototype.gluTessVertex = X.prototype.C; 29573 X.prototype.gluTessBeginPolygon = X.prototype.u; 29574 X.prototype.gluTessBeginContour = X.prototype.t; 29575 X.prototype.gluTessEndContour = X.prototype.v; 29576 X.prototype.gluTessEndPolygon = X.prototype.w; 29577 29578 if (typeof module !== 'undefined') { 29579 module.exports = this.libtess; 29580 } 29581 }, {}], 29582 10: [function (_dereq_, module, exports) { 29583 (function (Buffer) { 29584 /** 29585 * https://opentype.js.org v0.9.0 | (c) Frederik De Bleser and other contributors | MIT License | Uses tiny-inflate by Devon Govett and string.prototype.codepointat polyfill by Mathias Bynens 29586 */ 29587 (function (global, factory) { 29588 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : factory(global.opentype = {}); 29589 })(this, function (exports) { 29590 'use strict'; 29591 /*! https://mths.be/codepointat v0.2.0 by @mathias */ 29592 29593 if (!String.prototype.codePointAt) { 29594 (function () { 29595 var defineProperty = function () { 29596 // IE 8 only supports `Object.defineProperty` on DOM elements 29597 try { 29598 var object = {}; 29599 var $defineProperty = Object.defineProperty; 29600 var result = $defineProperty(object, object, object) && $defineProperty; 29601 } catch (error) {} 29602 29603 return result; 29604 }(); 29605 29606 var codePointAt = function (position) { 29607 if (this == null) { 29608 throw TypeError(); 29609 } 29610 29611 var string = String(this); 29612 var size = string.length; // `ToInteger` 29613 29614 var index = position ? Number(position) : 0; 29615 29616 if (index != index) { 29617 // better `isNaN` 29618 index = 0; 29619 } // Account for out-of-bounds indices: 29620 29621 29622 if (index < 0 || index >= size) { 29623 return undefined; 29624 } // Get the first code unit 29625 29626 29627 var first = string.charCodeAt(index); 29628 var second; 29629 29630 if ( // check if itâs the start of a surrogate pair 29631 first >= 0xD800 && first <= 0xDBFF && // high surrogate 29632 size > index + 1 // there is a next code unit 29633 ) { 29634 second = string.charCodeAt(index + 1); 29635 29636 if (second >= 0xDC00 && second <= 0xDFFF) { 29637 // low surrogate 29638 // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae 29639 return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; 29640 } 29641 } 29642 29643 return first; 29644 }; 29645 29646 if (defineProperty) { 29647 defineProperty(String.prototype, 'codePointAt', { 29648 'value': codePointAt, 29649 'configurable': true, 29650 'writable': true 29651 }); 29652 } else { 29653 String.prototype.codePointAt = codePointAt; 29654 } 29655 })(); 29656 } 29657 29658 var TINF_OK = 0; 29659 var TINF_DATA_ERROR = -3; 29660 29661 function Tree() { 29662 this.table = new Uint16Array(16); 29663 /* table of code length counts */ 29664 29665 this.trans = new Uint16Array(288); 29666 /* code -> symbol translation table */ 29667 } 29668 29669 function Data(source, dest) { 29670 this.source = source; 29671 this.sourceIndex = 0; 29672 this.tag = 0; 29673 this.bitcount = 0; 29674 this.dest = dest; 29675 this.destLen = 0; 29676 this.ltree = new Tree(); 29677 /* dynamic length/symbol tree */ 29678 29679 this.dtree = new Tree(); 29680 /* dynamic distance tree */ 29681 } 29682 /* --------------------------------------------------- *
vendor: 9,999 bytes, lines 29683-30031
29683 * -- uninitialized global data (static structures) -- * 29684 * --------------------------------------------------- */ 29685 29686 29687 var sltree = new Tree(); 29688 var sdtree = new Tree(); 29689 /* extra bits and base tables for length codes */ 29690 29691 var length_bits = new Uint8Array(30); 29692 var length_base = new Uint16Array(30); 29693 /* extra bits and base tables for distance codes */ 29694 29695 var dist_bits = new Uint8Array(30); 29696 var dist_base = new Uint16Array(30); 29697 /* special ordering of code length codes */ 29698 29699 var clcidx = new Uint8Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); 29700 /* used by tinf_decode_trees, avoids allocations every call */ 29701 29702 var code_tree = new Tree(); 29703 var lengths = new Uint8Array(288 + 32); 29704 /* ----------------------- * 29705 * -- utility functions -- * 29706 * ----------------------- */ 29707 29708 /* build extra bits and base tables */ 29709 29710 function tinf_build_bits_base(bits, base, delta, first) { 29711 var i, sum; 29712 /* build bits table */ 29713 29714 for (i = 0; i < delta; ++i) { 29715 bits[i] = 0; 29716 } 29717 29718 for (i = 0; i < 30 - delta; ++i) { 29719 bits[i + delta] = i / delta | 0; 29720 } 29721 /* build base table */ 29722 29723 29724 for (sum = first, i = 0; i < 30; ++i) { 29725 base[i] = sum; 29726 sum += 1 << bits[i]; 29727 } 29728 } 29729 /* build the fixed huffman trees */ 29730 29731 29732 function tinf_build_fixed_trees(lt, dt) { 29733 var i; 29734 /* build fixed length tree */ 29735 29736 for (i = 0; i < 7; ++i) { 29737 lt.table[i] = 0; 29738 } 29739 29740 lt.table[7] = 24; 29741 lt.table[8] = 152; 29742 lt.table[9] = 112; 29743 29744 for (i = 0; i < 24; ++i) { 29745 lt.trans[i] = 256 + i; 29746 } 29747 29748 for (i = 0; i < 144; ++i) { 29749 lt.trans[24 + i] = i; 29750 } 29751 29752 for (i = 0; i < 8; ++i) { 29753 lt.trans[24 + 144 + i] = 280 + i; 29754 } 29755 29756 for (i = 0; i < 112; ++i) { 29757 lt.trans[24 + 144 + 8 + i] = 144 + i; 29758 } 29759 /* build fixed distance tree */ 29760 29761 29762 for (i = 0; i < 5; ++i) { 29763 dt.table[i] = 0; 29764 } 29765 29766 dt.table[5] = 32; 29767 29768 for (i = 0; i < 32; ++i) { 29769 dt.trans[i] = i; 29770 } 29771 } 29772 /* given an array of code lengths, build a tree */ 29773 29774 29775 var offs = new Uint16Array(16); 29776 29777 function tinf_build_tree(t, lengths, off, num) { 29778 var i, sum; 29779 /* clear code length count table */ 29780 29781 for (i = 0; i < 16; ++i) { 29782 t.table[i] = 0; 29783 } 29784 /* scan symbol lengths, and sum code length counts */ 29785 29786 29787 for (i = 0; i < num; ++i) { 29788 t.table[lengths[off + i]]++; 29789 } 29790 29791 t.table[0] = 0; 29792 /* compute offset table for distribution sort */ 29793 29794 for (sum = 0, i = 0; i < 16; ++i) { 29795 offs[i] = sum; 29796 sum += t.table[i]; 29797 } 29798 /* create code->symbol translation table (symbols sorted by code) */ 29799 29800 29801 for (i = 0; i < num; ++i) { 29802 if (lengths[off + i]) { 29803 t.trans[offs[lengths[off + i]]++] = i; 29804 } 29805 } 29806 } 29807 /* ---------------------- * 29808 * -- decode functions -- * 29809 * ---------------------- */ 29810 29811 /* get one bit from source stream */ 29812 29813 29814 function tinf_getbit(d) { 29815 /* check if tag is empty */ 29816 if (!d.bitcount--) { 29817 /* load next tag */ 29818 d.tag = d.source[d.sourceIndex++]; 29819 d.bitcount = 7; 29820 } 29821 /* shift bit out of tag */ 29822 29823 29824 var bit = d.tag & 1; 29825 d.tag >>>= 1; 29826 return bit; 29827 } 29828 /* read a num bit value from a stream and add base */ 29829 29830 29831 function tinf_read_bits(d, num, base) { 29832 if (!num) { 29833 return base; 29834 } 29835 29836 while (d.bitcount < 24) { 29837 d.tag |= d.source[d.sourceIndex++] << d.bitcount; 29838 d.bitcount += 8; 29839 } 29840 29841 var val = d.tag & 0xffff >>> 16 - num; 29842 d.tag >>>= num; 29843 d.bitcount -= num; 29844 return val + base; 29845 } 29846 /* given a data stream and a tree, decode a symbol */ 29847 29848 29849 function tinf_decode_symbol(d, t) { 29850 while (d.bitcount < 24) { 29851 d.tag |= d.source[d.sourceIndex++] << d.bitcount; 29852 d.bitcount += 8; 29853 } 29854 29855 var sum = 0, 29856 cur = 0, 29857 len = 0; 29858 var tag = d.tag; 29859 /* get more bits while code value is above sum */ 29860 29861 do { 29862 cur = 2 * cur + (tag & 1); 29863 tag >>>= 1; 29864 ++len; 29865 sum += t.table[len]; 29866 cur -= t.table[len]; 29867 } while (cur >= 0); 29868 29869 d.tag = tag; 29870 d.bitcount -= len; 29871 return t.trans[sum + cur]; 29872 } 29873 /* given a data stream, decode dynamic trees from it */ 29874 29875 29876 function tinf_decode_trees(d, lt, dt) { 29877 var hlit, hdist, hclen; 29878 var i, num, length; 29879 /* get 5 bits HLIT (257-286) */ 29880 29881 hlit = tinf_read_bits(d, 5, 257); 29882 /* get 5 bits HDIST (1-32) */ 29883 29884 hdist = tinf_read_bits(d, 5, 1); 29885 /* get 4 bits HCLEN (4-19) */ 29886 29887 hclen = tinf_read_bits(d, 4, 4); 29888 29889 for (i = 0; i < 19; ++i) { 29890 lengths[i] = 0; 29891 } 29892 /* read code lengths for code length alphabet */ 29893 29894 29895 for (i = 0; i < hclen; ++i) { 29896 /* get 3 bits code length (0-7) */ 29897 var clen = tinf_read_bits(d, 3, 0); 29898 lengths[clcidx[i]] = clen; 29899 } 29900 /* build code length tree */ 29901 29902 29903 tinf_build_tree(code_tree, lengths, 0, 19); 29904 /* decode code lengths for the dynamic trees */ 29905 29906 for (num = 0; num < hlit + hdist;) { 29907 var sym = tinf_decode_symbol(d, code_tree); 29908 29909 switch (sym) { 29910 case 16: 29911 /* copy previous code length 3-6 times (read 2 bits) */ 29912 var prev = lengths[num - 1]; 29913 29914 for (length = tinf_read_bits(d, 2, 3); length; --length) { 29915 lengths[num++] = prev; 29916 } 29917 29918 break; 29919 29920 case 17: 29921 /* repeat code length 0 for 3-10 times (read 3 bits) */ 29922 for (length = tinf_read_bits(d, 3, 3); length; --length) { 29923 lengths[num++] = 0; 29924 } 29925 29926 break; 29927 29928 case 18: 29929 /* repeat code length 0 for 11-138 times (read 7 bits) */ 29930 for (length = tinf_read_bits(d, 7, 11); length; --length) { 29931 lengths[num++] = 0; 29932 } 29933 29934 break; 29935 29936 default: 29937 /* values 0-15 represent the actual code lengths */ 29938 lengths[num++] = sym; 29939 break; 29940 } 29941 } 29942 /* build dynamic trees */ 29943 29944 29945 tinf_build_tree(lt, lengths, 0, hlit); 29946 tinf_build_tree(dt, lengths, hlit, hdist); 29947 } 29948 /* ----------------------------- * 29949 * -- block inflate functions -- * 29950 * ----------------------------- */ 29951 29952 /* given a stream and two trees, inflate a block of data */ 29953 29954 29955 function tinf_inflate_block_data(d, lt, dt) { 29956 while (1) { 29957 var sym = tinf_decode_symbol(d, lt); 29958 /* check for end of block */ 29959 29960 if (sym === 256) { 29961 return TINF_OK; 29962 } 29963 29964 if (sym < 256) { 29965 d.dest[d.destLen++] = sym; 29966 } else { 29967 var length, dist, offs; 29968 var i; 29969 sym -= 257; 29970 /* possibly get more bits from length code */ 29971 29972 length = tinf_read_bits(d, length_bits[sym], length_base[sym]); 29973 dist = tinf_decode_symbol(d, dt); 29974 /* possibly get more bits from distance code */ 29975 29976 offs = d.destLen - tinf_read_bits(d, dist_bits[dist], dist_base[dist]); 29977 /* copy match */ 29978 29979 for (i = offs; i < offs + length; ++i) { 29980 d.dest[d.destLen++] = d.dest[i]; 29981 } 29982 } 29983 } 29984 } 29985 /* inflate an uncompressed block of data */ 29986 29987 29988 function tinf_inflate_uncompressed_block(d) { 29989 var length, invlength; 29990 var i; 29991 /* unread from bitbuffer */ 29992 29993 while (d.bitcount > 8) { 29994 d.sourceIndex--; 29995 d.bitcount -= 8; 29996 } 29997 /* get length */ 29998 29999 30000 length = d.source[d.sourceIndex + 1]; 30001 length = 256 * length + d.source[d.sourceIndex]; 30002 /* get one's complement of length */ 30003 30004 invlength = d.source[d.sourceIndex + 3]; 30005 invlength = 256 * invlength + d.source[d.sourceIndex + 2]; 30006 /* check length */ 30007 30008 if (length !== (~invlength & 0x0000ffff)) { 30009 return TINF_DATA_ERROR; 30010 } 30011 30012 d.sourceIndex += 4; 30013 /* copy block */ 30014 30015 for (i = length; i; --i) { 30016 d.dest[d.destLen++] = d.source[d.sourceIndex++]; 30017 } 30018 /* make sure we start next block on a byte boundary */ 30019 30020 30021 d.bitcount = 0; 30022 return TINF_OK; 30023 } 30024 /* inflate stream from source to dest */ 30025 30026 30027 function tinf_uncompress(source, dest) { 30028 var d = new Data(source, dest); 30029 var bfinal, btype, res; 30030 30031 do {
30032 /* read final block flag */ 30033 bfinal = tinf_getbit(d); 30034 /* read block type (2 bits) */ 30035 30036 btype = tinf_read_bits(d, 2, 0); 30037 /* decompress block */ 30038 30039 switch (btype) { 30040 case 0: 30041 /* decompress uncompressed block */ 30042 res = tinf_inflate_uncompressed_block(d); 30043 break; 30044 30045 case 1: 30046 /* decompress block with fixed huffman trees */ 30047 res = tinf_inflate_block_data(d, sltree, sdtree); 30048 break; 30049 30050 case 2: 30051 /* decompress block with dynamic huffman trees */ 30052 tinf_decode_trees(d, d.ltree, d.dtree); 30053 res = tinf_inflate_block_data(d, d.ltree, d.dtree); 30054 break; 30055 30056 default: 30057 res = TINF_DATA_ERROR; 30058 } 30059 30060 if (res !== TINF_OK) { 30061 throw new Error('Data error'); 30062 } 30063 } while (!bfinal); 30064 30065 if (d.destLen < d.dest.length) { 30066 if (typeof d.dest.slice === 'function') { 30067 return d.dest.slice(0, d.destLen); 30068 } else { 30069 return d.dest.subarray(0, d.destLen); 30070 } 30071 } 30072 30073 return d.dest; 30074 } 30075 /* -------------------- * 30076 * -- initialization -- * 30077 * -------------------- */ 30078 30079 /* build fixed huffman trees */ 30080 30081 30082 tinf_build_fixed_trees(sltree, sdtree); 30083 /* build extra bits and base tables */ 30084 30085 tinf_build_bits_base(length_bits, length_base, 4, 3); 30086 tinf_build_bits_base(dist_bits, dist_base, 2, 1); 30087 /* fix a special case */ 30088 30089 length_bits[28] = 0; 30090 length_base[28] = 258; 30091 var tinyInflate = tinf_uncompress; // The Bounding Box object 30092 30093 function derive(v0, v1, v2, v3, t) { 30094 return Math.pow(1 - t, 3) * v0 + 3 * Math.pow(1 - t, 2) * t * v1 + 3 * (1 - t) * Math.pow(t, 2) * v2 + Math.pow(t, 3) * v3; 30095 } 30096 /** 30097 * A bounding box is an enclosing box that describes the smallest measure within which all the points lie. 30098 * It is used to calculate the bounding box of a glyph or text path. 30099 * 30100 * On initialization, x1/y1/x2/y2 will be NaN. Check if the bounding box is empty using `isEmpty()`. 30101 * 30102 * @exports opentype.BoundingBox 30103 * @class 30104 * @constructor 30105 */ 30106 30107 30108 function BoundingBox() { 30109 this.x1 = Number.NaN; 30110 this.y1 = Number.NaN; 30111 this.x2 = Number.NaN; 30112 this.y2 = Number.NaN; 30113 } 30114 /** 30115 * Returns true if the bounding box is empty, that is, no points have been added to the box yet. 30116 */ 30117 30118 30119 BoundingBox.prototype.isEmpty = function () { 30120 return isNaN(this.x1) || isNaN(this.y1) || isNaN(this.x2) || isNaN(this.y2); 30121 }; 30122 /** 30123 * Add the point to the bounding box. 30124 * The x1/y1/x2/y2 coordinates of the bounding box will now encompass the given point. 30125 * @param {number} x - The X coordinate of the point. 30126 * @param {number} y - The Y coordinate of the point. 30127 */ 30128 30129 30130 BoundingBox.prototype.addPoint = function (x, y) { 30131 if (typeof x === 'number') { 30132 if (isNaN(this.x1) || isNaN(this.x2)) { 30133 this.x1 = x; 30134 this.x2 = x; 30135 } 30136 30137 if (x < this.x1) { 30138 this.x1 = x; 30139 } 30140 30141 if (x > this.x2) { 30142 this.x2 = x; 30143 } 30144 } 30145 30146 if (typeof y === 'number') { 30147 if (isNaN(this.y1) || isNaN(this.y2)) { 30148 this.y1 = y; 30149 this.y2 = y; 30150 } 30151 30152 if (y < this.y1) { 30153 this.y1 = y; 30154 } 30155 30156 if (y > this.y2) { 30157 this.y2 = y; 30158 } 30159 } 30160 }; 30161 /** 30162 * Add a X coordinate to the bounding box. 30163 * This extends the bounding box to include the X coordinate. 30164 * This function is used internally inside of addBezier. 30165 * @param {number} x - The X coordinate of the point. 30166 */ 30167 30168 30169 BoundingBox.prototype.addX = function (x) { 30170 this.addPoint(x, null); 30171 }; 30172 /** 30173 * Add a Y coordinate to the bounding box. 30174 * This extends the bounding box to include the Y coordinate. 30175 * This function is used internally inside of addBezier. 30176 * @param {number} y - The Y coordinate of the point. 30177 */ 30178 30179 30180 BoundingBox.prototype.addY = function (y) { 30181 this.addPoint(null, y); 30182 }; 30183 /** 30184 * Add a Bézier curve to the bounding box. 30185 * This extends the bounding box to include the entire Bézier. 30186 * @param {number} x0 - The starting X coordinate. 30187 * @param {number} y0 - The starting Y coordinate. 30188 * @param {number} x1 - The X coordinate of the first control point. 30189 * @param {number} y1 - The Y coordinate of the first control point. 30190 * @param {number} x2 - The X coordinate of the second control point. 30191 * @param {number} y2 - The Y coordinate of the second control point. 30192 * @param {number} x - The ending X coordinate. 30193 * @param {number} y - The ending Y coordinate. 30194 */ 30195 30196 30197 BoundingBox.prototype.addBezier = function (x0, y0, x1, y1, x2, y2, x, y) { 30198 var this$1 = this; // This code is based on http://nishiohirokazu.blogspot.com/2009/06/how-to-calculate-bezier-curves-bounding.html 30199 // and https://github.com/icons8/svg-path-bounding-box 30200 30201 var p0 = [x0, y0]; 30202 var p1 = [x1, y1]; 30203 var p2 = [x2, y2]; 30204 var p3 = [x, y]; 30205 this.addPoint(x0, y0); 30206 this.addPoint(x, y); 30207 30208 for (var i = 0; i <= 1; i++) { 30209 var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; 30210 var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; 30211 var c = 3 * p1[i] - 3 * p0[i]; 30212 30213 if (a === 0) { 30214 if (b === 0) { 30215 continue; 30216 } 30217 30218 var t = -c / b; 30219 30220 if (0 < t && t < 1) { 30221 if (i === 0) {
30222 this$1.addX(derive(p0[i], p1[i], p2[i], p3[i], t)); 30223 } 30224 30225 if (i === 1) { 30226 this$1.addY(derive(p0[i], p1[i], p2[i], p3[i], t)); 30227 } 30228 } 30229 30230 continue; 30231 } 30232 30233 var b2ac = Math.pow(b, 2) - 4 * c * a; 30234 30235 if (b2ac < 0) { 30236 continue; 30237 } 30238 30239 var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); 30240 30241 if (0 < t1 && t1 < 1) { 30242 if (i === 0) { 30243 this$1.addX(derive(p0[i], p1[i], p2[i], p3[i], t1)); 30244 } 30245 30246 if (i === 1) { 30247 this$1.addY(derive(p0[i], p1[i], p2[i], p3[i], t1)); 30248 } 30249 } 30250 30251 var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); 30252 30253 if (0 < t2 && t2 < 1) { 30254 if (i === 0) { 30255 this$1.addX(derive(p0[i], p1[i], p2[i], p3[i], t2)); 30256 } 30257 30258 if (i === 1) { 30259 this$1.addY(derive(p0[i], p1[i], p2[i], p3[i], t2)); 30260 } 30261 } 30262 } 30263 }; 30264 /** 30265 * Add a quadratic curve to the bounding box. 30266 * This extends the bounding box to include the entire quadratic curve. 30267 * @param {number} x0 - The starting X coordinate. 30268 * @param {number} y0 - The starting Y coordinate. 30269 * @param {number} x1 - The X coordinate of the control point. 30270 * @param {number} y1 - The Y coordinate of the control point. 30271 * @param {number} x - The ending X coordinate. 30272 * @param {number} y - The ending Y coordinate. 30273 */ 30274 30275 30276 BoundingBox.prototype.addQuad = function (x0, y0, x1, y1, x, y) { 30277 var cp1x = x0 + 2 / 3 * (x1 - x0); 30278 var cp1y = y0 + 2 / 3 * (y1 - y0); 30279 var cp2x = cp1x + 1 / 3 * (x - x0); 30280 var cp2y = cp1y + 1 / 3 * (y - y0); 30281 this.addBezier(x0, y0, cp1x, cp1y, cp2x, cp2y, x, y); 30282 }; // Geometric objects 30283 30284 /** 30285 * A bézier path containing a set of path commands similar to a SVG path. 30286 * Paths can be drawn on a context using `draw`. 30287 * @exports opentype.Path 30288 * @class 30289 * @constructor 30290 */ 30291 30292 30293 function Path() { 30294 this.commands = []; 30295 this.fill = 'black'; 30296 this.stroke = null; 30297 this.strokeWidth = 1; 30298 } 30299 /** 30300 * @param {number} x 30301 * @param {number} y 30302 */ 30303 30304 30305 Path.prototype.moveTo = function (x, y) { 30306 this.commands.push({ 30307 type: 'M', 30308 x: x, 30309 y: y 30310 }); 30311 }; 30312 /** 30313 * @param {number} x 30314 * @param {number} y 30315 */ 30316 30317 30318 Path.prototype.lineTo = function (x, y) { 30319 this.commands.push({ 30320 type: 'L', 30321 x: x, 30322 y: y 30323 }); 30324 }; 30325 /** 30326 * Draws cubic curve 30327 * @function 30328 * curveTo 30329 * @memberof opentype.Path.prototype 30330 * @param {number} x1 - x of control 1 30331 * @param {number} y1 - y of control 1 30332 * @param {number} x2 - x of control 2 30333 * @param {number} y2 - y of control 2 30334 * @param {number} x - x of path point 30335 * @param {number} y - y of path point 30336 */ 30337 30338 /** 30339 * Draws cubic curve 30340 * @function 30341 * bezierCurveTo 30342 * @memberof opentype.Path.prototype 30343 * @param {number} x1 - x of control 1 30344 * @param {number} y1 - y of control 1 30345 * @param {number} x2 - x of control 2 30346 * @param {number} y2 - y of control 2 30347 * @param {number} x - x of path point 30348 * @param {number} y - y of path point 30349 * @see curveTo 30350 */ 30351 30352 30353 Path.prototype.curveTo = Path.prototype.bezierCurveTo = function (x1, y1, x2, y2, x, y) { 30354 this.commands.push({ 30355 type: 'C', 30356 x1: x1, 30357 y1: y1, 30358 x2: x2, 30359 y2: y2, 30360 x: x, 30361 y: y 30362 }); 30363 }; 30364 /** 30365 * Draws quadratic curve 30366 * @function 30367 * quadraticCurveTo 30368 * @memberof opentype.Path.prototype 30369 * @param {number} x1 - x of control 30370 * @param {number} y1 - y of control 30371 * @param {number} x - x of path point 30372 * @param {number} y - y of path point 30373 */ 30374 30375 /** 30376 * Draws quadratic curve 30377 * @function 30378 * quadTo 30379 * @memberof opentype.Path.prototype 30380 * @param {number} x1 - x of control 30381 * @param {number} y1 - y of control 30382 * @param {number} x - x of path point 30383 * @param {number} y - y of path point 30384 */ 30385 30386 30387 Path.prototype.quadTo = Path.prototype.quadraticCurveTo = function (x1, y1, x, y) { 30388 this.commands.push({ 30389 type: 'Q', 30390 x1: x1, 30391 y1: y1, 30392 x: x, 30393 y: y 30394 }); 30395 }; 30396 /** 30397 * Closes the path 30398 * @function closePath 30399 * @memberof opentype.Path.prototype 30400 */ 30401 30402 /** 30403 * Close the path 30404 * @function close 30405 * @memberof opentype.Path.prototype 30406 */ 30407 30408 30409 Path.prototype.close = Path.prototype.closePath = function () { 30410 this.commands.push({ 30411 type: 'Z' 30412 }); 30413 }; 30414 /** 30415 * Add the given path or list of commands to the commands of this path. 30416 * @param {Array} pathOrCommands - another opentype.Path, an opentype.BoundingBox, or an array of commands. 30417 */ 30418 30419 30420 Path.prototype.extend = function (pathOrCommands) { 30421 if (pathOrCommands.commands) { 30422 pathOrCommands = pathOrCommands.commands; 30423 } else if (pathOrCommands instanceof BoundingBox) { 30424 var box = pathOrCommands; 30425 this.moveTo(box.x1, box.y1); 30426 this.lineTo(box.x2, box.y1); 30427 this.lineTo(box.x2, box.y2); 30428 this.lineTo(box.x1, box.y2); 30429 this.close(); 30430 return; 30431 } 30432 30433 Array.prototype.push.apply(this.commands, pathOrCommands); 30434 }; 30435 /** 30436 * Calculate the bounding box of the path.
30437 * @returns {opentype.BoundingBox} 30438 */ 30439 30440 30441 Path.prototype.getBoundingBox = function () { 30442 var this$1 = this; 30443 var box = new BoundingBox(); 30444 var startX = 0; 30445 var startY = 0; 30446 var prevX = 0; 30447 var prevY = 0; 30448 30449 for (var i = 0; i < this.commands.length; i++) { 30450 var cmd = this$1.commands[i]; 30451 30452 switch (cmd.type) { 30453 case 'M': 30454 box.addPoint(cmd.x, cmd.y); 30455 startX = prevX = cmd.x; 30456 startY = prevY = cmd.y; 30457 break; 30458 30459 case 'L': 30460 box.addPoint(cmd.x, cmd.y); 30461 prevX = cmd.x; 30462 prevY = cmd.y; 30463 break; 30464 30465 case 'Q': 30466 box.addQuad(prevX, prevY, cmd.x1, cmd.y1, cmd.x, cmd.y); 30467 prevX = cmd.x; 30468 prevY = cmd.y; 30469 break; 30470 30471 case 'C': 30472 box.addBezier(prevX, prevY, cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y); 30473 prevX = cmd.x; 30474 prevY = cmd.y; 30475 break; 30476 30477 case 'Z': 30478 prevX = startX; 30479 prevY = startY; 30480 break; 30481 30482 default: 30483 throw new Error('Unexpected path command ' + cmd.type); 30484 } 30485 } 30486 30487 if (box.isEmpty()) { 30488 box.addPoint(0, 0); 30489 } 30490 30491 return box; 30492 }; 30493 /** 30494 * Draw the path to a 2D context. 30495 * @param {CanvasRenderingContext2D} ctx - A 2D drawing context. 30496 */ 30497 30498 30499 Path.prototype.draw = function (ctx) { 30500 var this$1 = this; 30501 ctx.beginPath(); 30502 30503 for (var i = 0; i < this.commands.length; i += 1) { 30504 var cmd = this$1.commands[i]; 30505 30506 if (cmd.type === 'M') { 30507 ctx.moveTo(cmd.x, cmd.y); 30508 } else if (cmd.type === 'L') { 30509 ctx.lineTo(cmd.x, cmd.y); 30510 } else if (cmd.type === 'C') { 30511 ctx.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y); 30512 } else if (cmd.type === 'Q') { 30513 ctx.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y); 30514 } else if (cmd.type === 'Z') { 30515 ctx.closePath(); 30516 } 30517 } 30518 30519 if (this.fill) { 30520 ctx.fillStyle = this.fill; 30521 ctx.fill(); 30522 } 30523 30524 if (this.stroke) { 30525 ctx.strokeStyle = this.stroke; 30526 ctx.lineWidth = this.strokeWidth; 30527 ctx.stroke(); 30528 } 30529 }; 30530 /** 30531 * Convert the Path to a string of path data instructions 30532 * See http://www.w3.org/TR/SVG/paths.html#PathData 30533 * @param {number} [decimalPlaces=2] - The amount of decimal places for floating-point values 30534 * @return {string} 30535 */ 30536 30537 30538 Path.prototype.toPathData = function (decimalPlaces) { 30539 var this$1 = this; 30540 decimalPlaces = decimalPlaces !== undefined ? decimalPlaces : 2; 30541 30542 function floatToString(v) { 30543 if (Math.round(v) === v) { 30544 return '' + Math.round(v); 30545 } else { 30546 return v.toFixed(decimalPlaces); 30547 } 30548 } 30549 30550 function packValues() { 30551 var arguments$1 = arguments; 30552 var s = ''; 30553 30554 for (var i = 0; i < arguments.length; i += 1) { 30555 var v = arguments$1[i]; 30556 30557 if (v >= 0 && i > 0) { 30558 s += ' '; 30559 } 30560 30561 s += floatToString(v); 30562 } 30563 30564 return s; 30565 } 30566 30567 var d = ''; 30568 30569 for (var i = 0; i < this.commands.length; i += 1) { 30570 var cmd = this$1.commands[i]; 30571 30572 if (cmd.type === 'M') { 30573 d += 'M' + packValues(cmd.x, cmd.y); 30574 } else if (cmd.type === 'L') { 30575 d += 'L' + packValues(cmd.x, cmd.y); 30576 } else if (cmd.type === 'C') { 30577 d += 'C' + packValues(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y); 30578 } else if (cmd.type === 'Q') { 30579 d += 'Q' + packValues(cmd.x1, cmd.y1, cmd.x, cmd.y); 30580 } else if (cmd.type === 'Z') { 30581 d += 'Z'; 30582 } 30583 } 30584 30585 return d; 30586 }; 30587 /** 30588 * Convert the path to an SVG <path> element, as a string. 30589 * @param {number} [decimalPlaces=2] - The amount of decimal places for floating-point values 30590 * @return {string} 30591 */ 30592 30593 30594 Path.prototype.toSVG = function (decimalPlaces) { 30595 var svg = '<path d="'; 30596 svg += this.toPathData(decimalPlaces); 30597 svg += '"'; 30598 30599 if (this.fill && this.fill !== 'black') { 30600 if (this.fill === null) { 30601 svg += ' fill="none"'; 30602 } else { 30603 svg += ' fill="' + this.fill + '"'; 30604 } 30605 } 30606 30607 if (this.stroke) { 30608 svg += ' stroke="' + this.stroke + '" stroke-width="' + this.strokeWidth + '"'; 30609 } 30610 30611 svg += '/>'; 30612 return svg; 30613 }; 30614 /** 30615 * Convert the path to a DOM element. 30616 * @param {number} [decimalPlaces=2] - The amount of decimal places for floating-point values 30617 * @return {SVGPathElement} 30618 */ 30619 30620 30621 Path.prototype.toDOMElement = function (decimalPlaces) { 30622 var temporaryPath = this.toPathData(decimalPlaces); 30623 var newPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 30624 newPath.setAttribute('d', temporaryPath); 30625 return newPath; 30626 }; // Run-time checking of preconditions. 30627 30628 30629 function fail(message) { 30630 throw new Error(message); 30631 }
vendor: 6,278 bytes, lines 30631-30871
30631 // Precondition function that checks if the given predicate is true. 30632 // If not, it will throw an error. 30633 30634 30635 function argument(predicate, message) { 30636 if (!predicate) { 30637 fail(message); 30638 } 30639 } 30640 30641 var check = { 30642 fail: fail, 30643 argument: argument, 30644 assert: argument 30645 }; // Data types used in the OpenType font file. 30646 30647 var LIMIT16 = 32768; // The limit at which a 16-bit number switches signs == 2^15 30648 30649 var LIMIT32 = 2147483648; // The limit at which a 32-bit number switches signs == 2 ^ 31 30650 30651 /** 30652 * @exports opentype.decode 30653 * @class 30654 */ 30655 30656 var decode = {}; 30657 /** 30658 * @exports opentype.encode 30659 * @class 30660 */ 30661 30662 var encode = {}; 30663 /** 30664 * @exports opentype.sizeOf 30665 * @class 30666 */ 30667 30668 var sizeOf = {}; // Return a function that always returns the same value. 30669 30670 function constant(v) { 30671 return function () { 30672 return v; 30673 }; 30674 } // OpenType data types ////////////////////////////////////////////////////// 30675 30676 /** 30677 * Convert an 8-bit unsigned integer to a list of 1 byte. 30678 * @param {number} 30679 * @returns {Array} 30680 */ 30681 30682 30683 encode.BYTE = function (v) { 30684 check.argument(v >= 0 && v <= 255, 'Byte value should be between 0 and 255.'); 30685 return [v]; 30686 }; 30687 /** 30688 * @constant 30689 * @type {number} 30690 */ 30691 30692 30693 sizeOf.BYTE = constant(1); 30694 /** 30695 * Convert a 8-bit signed integer to a list of 1 byte. 30696 * @param {string} 30697 * @returns {Array} 30698 */ 30699 30700 encode.CHAR = function (v) { 30701 return [v.charCodeAt(0)]; 30702 }; 30703 /** 30704 * @constant 30705 * @type {number} 30706 */ 30707 30708 30709 sizeOf.CHAR = constant(1); 30710 /** 30711 * Convert an ASCII string to a list of bytes. 30712 * @param {string} 30713 * @returns {Array} 30714 */ 30715 30716 encode.CHARARRAY = function (v) { 30717 var b = []; 30718 30719 for (var i = 0; i < v.length; i += 1) { 30720 b[i] = v.charCodeAt(i); 30721 } 30722 30723 return b; 30724 }; 30725 /** 30726 * @param {Array} 30727 * @returns {number} 30728 */ 30729 30730 30731 sizeOf.CHARARRAY = function (v) { 30732 return v.length; 30733 }; 30734 /** 30735 * Convert a 16-bit unsigned integer to a list of 2 bytes. 30736 * @param {number} 30737 * @returns {Array} 30738 */ 30739 30740 30741 encode.USHORT = function (v) { 30742 return [v >> 8 & 0xFF, v & 0xFF]; 30743 }; 30744 /** 30745 * @constant 30746 * @type {number} 30747 */ 30748 30749 30750 sizeOf.USHORT = constant(2); 30751 /** 30752 * Convert a 16-bit signed integer to a list of 2 bytes. 30753 * @param {number} 30754 * @returns {Array} 30755 */ 30756 30757 encode.SHORT = function (v) { 30758 // Two's complement 30759 if (v >= LIMIT16) { 30760 v = -(2 * LIMIT16 - v); 30761 } 30762 30763 return [v >> 8 & 0xFF, v & 0xFF]; 30764 }; 30765 /** 30766 * @constant 30767 * @type {number} 30768 */ 30769 30770 30771 sizeOf.SHORT = constant(2); 30772 /** 30773 * Convert a 24-bit unsigned integer to a list of 3 bytes. 30774 * @param {number} 30775 * @returns {Array} 30776 */ 30777 30778 encode.UINT24 = function (v) { 30779 return [v >> 16 & 0xFF, v >> 8 & 0xFF, v & 0xFF]; 30780 }; 30781 /** 30782 * @constant 30783 * @type {number} 30784 */ 30785 30786 30787 sizeOf.UINT24 = constant(3); 30788 /** 30789 * Convert a 32-bit unsigned integer to a list of 4 bytes. 30790 * @param {number} 30791 * @returns {Array} 30792 */ 30793 30794 encode.ULONG = function (v) { 30795 return [v >> 24 & 0xFF, v >> 16 & 0xFF, v >> 8 & 0xFF, v & 0xFF]; 30796 }; 30797 /** 30798 * @constant 30799 * @type {number} 30800 */ 30801 30802 30803 sizeOf.ULONG = constant(4); 30804 /** 30805 * Convert a 32-bit unsigned integer to a list of 4 bytes. 30806 * @param {number} 30807 * @returns {Array} 30808 */ 30809 30810 encode.LONG = function (v) { 30811 // Two's complement 30812 if (v >= LIMIT32) { 30813 v = -(2 * LIMIT32 - v); 30814 } 30815 30816 return [v >> 24 & 0xFF, v >> 16 & 0xFF, v >> 8 & 0xFF, v & 0xFF]; 30817 }; 30818 /** 30819 * @constant 30820 * @type {number} 30821 */ 30822 30823 30824 sizeOf.LONG = constant(4); 30825 encode.FIXED = encode.ULONG; 30826 sizeOf.FIXED = sizeOf.ULONG; 30827 encode.FWORD = encode.SHORT; 30828 sizeOf.FWORD = sizeOf.SHORT; 30829 encode.UFWORD = encode.USHORT; 30830 sizeOf.UFWORD = sizeOf.USHORT; 30831 /** 30832 * Convert a 32-bit Apple Mac timestamp integer to a list of 8 bytes, 64-bit timestamp. 30833 * @param {number} 30834 * @returns {Array} 30835 */ 30836 30837 encode.LONGDATETIME = function (v) { 30838 return [0, 0, 0, 0, v >> 24 & 0xFF, v >> 16 & 0xFF, v >> 8 & 0xFF, v & 0xFF]; 30839 }; 30840 /** 30841 * @constant 30842 * @type {number} 30843 */ 30844 30845 30846 sizeOf.LONGDATETIME = constant(8); 30847 /** 30848 * Convert a 4-char tag to a list of 4 bytes. 30849 * @param {string} 30850 * @returns {Array} 30851 */ 30852 30853 encode.TAG = function (v) { 30854 check.argument(v.length === 4, 'Tag should be exactly 4 ASCII characters.'); 30855 return [v.charCodeAt(0), v.charCodeAt(1), v.charCodeAt(2), v.charCodeAt(3)]; 30856 }; 30857 /** 30858 * @constant 30859 * @type {number} 30860 */ 30861 30862 30863 sizeOf.TAG = constant(4); // CFF data types /////////////////////////////////////////////////////////// 30864 30865 encode.Card8 = encode.BYTE; 30866 sizeOf.Card8 = sizeOf.BYTE; 30867 encode.Card16 = encode.USHORT; 30868 sizeOf.Card16 = sizeOf.USHORT; 30869 encode.OffSize = encode.BYTE; 30870 sizeOf.OffSize = sizeOf.BYTE; 30871 encode.SID = encode.USHORT;
30872 sizeOf.SID = sizeOf.USHORT; // Convert a numeric operand or charstring number to a variable-size list of bytes. 30873 30874 /** 30875 * Convert a numeric operand or charstring number to a variable-size list of bytes. 30876 * @param {number} 30877 * @returns {Array} 30878 */ 30879 30880 encode.NUMBER = function (v) { 30881 if (v >= -107 && v <= 107) { 30882 return [v + 139]; 30883 } else if (v >= 108 && v <= 1131) { 30884 v = v - 108; 30885 return [(v >> 8) + 247, v & 0xFF]; 30886 } else if (v >= -1131 && v <= -108) { 30887 v = -v - 108; 30888 return [(v >> 8) + 251, v & 0xFF]; 30889 } else if (v >= -32768 && v <= 32767) { 30890 return encode.NUMBER16(v); 30891 } else { 30892 return encode.NUMBER32(v); 30893 } 30894 }; 30895 /** 30896 * @param {number} 30897 * @returns {number} 30898 */ 30899 30900 30901 sizeOf.NUMBER = function (v) { 30902 return encode.NUMBER(v).length; 30903 }; 30904 /** 30905 * Convert a signed number between -32768 and +32767 to a three-byte value. 30906 * This ensures we always use three bytes, but is not the most compact format. 30907 * @param {number} 30908 * @returns {Array} 30909 */ 30910 30911 30912 encode.NUMBER16 = function (v) { 30913 return [28, v >> 8 & 0xFF, v & 0xFF]; 30914 }; 30915 /** 30916 * @constant 30917 * @type {number} 30918 */ 30919 30920 30921 sizeOf.NUMBER16 = constant(3); 30922 /** 30923 * Convert a signed number between -(2^31) and +(2^31-1) to a five-byte value. 30924 * This is useful if you want to be sure you always use four bytes, 30925 * at the expense of wasting a few bytes for smaller numbers. 30926 * @param {number} 30927 * @returns {Array} 30928 */ 30929 30930 encode.NUMBER32 = function (v) { 30931 return [29, v >> 24 & 0xFF, v >> 16 & 0xFF, v >> 8 & 0xFF, v & 0xFF]; 30932 }; 30933 /** 30934 * @constant 30935 * @type {number} 30936 */ 30937 30938 30939 sizeOf.NUMBER32 = constant(5); 30940 /** 30941 * @param {number} 30942 * @returns {Array} 30943 */ 30944 30945 encode.REAL = function (v) { 30946 var value = v.toString(); // Some numbers use an epsilon to encode the value. (e.g. JavaScript will store 0.0000001 as 1e-7) 30947 // This code converts it back to a number without the epsilon. 30948 30949 var m = /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(value); 30950 30951 if (m) { 30952 var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length)); 30953 value = (Math.round(v * epsilon) / epsilon).toString(); 30954 } 30955 30956 var nibbles = ''; 30957 30958 for (var i = 0, ii = value.length; i < ii; i += 1) { 30959 var c = value[i]; 30960 30961 if (c === 'e') { 30962 nibbles += value[++i] === '-' ? 'c' : 'b'; 30963 } else if (c === '.') { 30964 nibbles += 'a'; 30965 } else if (c === '-') { 30966 nibbles += 'e'; 30967 } else { 30968 nibbles += c; 30969 } 30970 } 30971 30972 nibbles += nibbles.length & 1 ? 'f' : 'ff'; 30973 var out = [30]; 30974 30975 for (var i$1 = 0, ii$1 = nibbles.length; i$1 < ii$1; i$1 += 2) { 30976 out.push(parseInt(nibbles.substr(i$1, 2), 16)); 30977 } 30978 30979 return out; 30980 }; 30981 /** 30982 * @param {number} 30983 * @returns {number} 30984 */ 30985 30986 30987 sizeOf.REAL = function (v) { 30988 return encode.REAL(v).length; 30989 }; 30990 30991 encode.NAME = encode.CHARARRAY; 30992 sizeOf.NAME = sizeOf.CHARARRAY; 30993 encode.STRING = encode.CHARARRAY;
30994 sizeOf.STRING = sizeOf.CHARARRAY; 30995 /** 30996 * @param {DataView} data 30997 * @param {number} offset 30998 * @param {number} numBytes 30999 * @returns {string} 31000 */ 31001 31002 decode.UTF8 = function (data, offset, numBytes) { 31003 var codePoints = []; 31004 var numChars = numBytes; 31005 31006 for (var j = 0; j < numChars; j++, offset += 1) { 31007 codePoints[j] = data.getUint8(offset); 31008 } 31009 31010 return String.fromCharCode.apply(null, codePoints); 31011 }; 31012 /** 31013 * @param {DataView} data 31014 * @param {number} offset 31015 * @param {number} numBytes 31016 * @returns {string} 31017 */ 31018 31019 31020 decode.UTF16 = function (data, offset, numBytes) { 31021 var codePoints = []; 31022 var numChars = numBytes / 2; 31023 31024 for (var j = 0; j < numChars; j++, offset += 2) { 31025 codePoints[j] = data.getUint16(offset); 31026 } 31027 31028 return String.fromCharCode.apply(null, codePoints); 31029 }; 31030 /** 31031 * Convert a JavaScript string to UTF16-BE. 31032 * @param {string} 31033 * @returns {Array} 31034 */ 31035 31036 31037 encode.UTF16 = function (v) { 31038 var b = []; 31039 31040 for (var i = 0; i < v.length; i += 1) { 31041 var codepoint = v.charCodeAt(i); 31042 b[b.length] = codepoint >> 8 & 0xFF; 31043 b[b.length] = codepoint & 0xFF; 31044 } 31045 31046 return b; 31047 }; 31048 /** 31049 * @param {string} 31050 * @returns {number} 31051 */ 31052 31053 31054 sizeOf.UTF16 = function (v) { 31055 return v.length * 2; 31056 }; // Data for converting old eight-bit Macintosh encodings to Unicode. 31057 // This representation is optimized for decoding; encoding is slower 31058 // and needs more memory. The assumption is that all opentype.js users 31059 // want to open fonts, but saving a font will be comparatively rare 31060 // so it can be more expensive. Keyed by IANA character set name. 31061 // 31062 // Python script for generating these strings: 31063 // 31064 // s = u''.join([chr(c).decode('mac_greek') for c in range(128, 256)]) 31065 // print(s.encode('utf-8')) 31066 31067 /** 31068 * @private 31069 */ 31070 31071 31072 var eightBitMacEncodings = { 31073 'x-mac-croatian': // Python: 'mac_croatian' 31074 'Ãà ÃÃÃÃÃáà âäãåçéèêëÃìîïñóòôöõúùûüâ °¢£§â¢Â¶Ã®Šâ¢Â´Â¨â ŽÃâ±â¤â¥âµâââÅ¡â«ÂªÂºÎ©Å¾Ã¸' + '¿¡¬âÆâÄ«Äâ¦Â ÃÃÃÅÅÄâââââ÷â©ââ¬â¹âºÃ»â·âââ°ÃÄÃÄÃÃÃÃÃÃÃÄÃÃÃÃıË˯ÏÃË¸ÃæË', 31075 'x-mac-cyrillic': // Python: 'mac_cyrillic' 31076 'ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐРСТУФХЦЧШЩЪЫЬÐЮЯâ °Ò£§â¢Â¶Ð®©â¢ÐÑâ ÐÑâ±â¤â¥ÑµÒÐÐÑÐÑÐÑÐÑ' + 'ÑР¬âÆââ«»â¦Â ÐÑÐÑÑââââââ÷âÐÑÐÑâÐÑÑабвгдежзийклмнопÑÑÑÑÑÑ ÑÑÑÑÑÑÑÑÑ', 31077 'x-mac-gaelic': // http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/GAELIC.TXT 31078 'Ãà ÃÃÃÃÃáà âäãåçéèêëÃìîïñóòôöõúùûüâ °¢£§â¢Â¶Ã®©â¢Â´Â¨â ÃÃá¸Â±â¤â¥á¸ÄÄá¸á¸á¸á¸Ä Ä¡á¹Ã¦Ã¸' + 'á¹á¹á¹É¼ÆÅ¿á¹ «»â¦Â ÃÃÃÅÅââââââṡáºÃ¿Å¸á¹ªâ¬â¹âºÅ¶Å·á¹«Â·á»²á»³âÃÃÃÃÃÃÃÃÃÃÃâ£ÃÃÃÃıÃýŴŵáºáº áºáºáºáº', 31079 'x-mac-greek': // Python: 'mac_greek' 31080 'ù²Ã³ÃÃΠà âäΨçéèêë£â¢Ã®Ã¯â¢Â½â°Ã´Ã¶Â¦â¬Ã¹Ã»Ã¼â ÎÎÎÎÎΠî©ΣΪ§â °·Î±â¤â¥Â¥ÎÎÎÎÎÎÎΦΫΨΩ' + 'άάÎΡâΤ«»â¦Â ΥΧÎÎÅââââââ÷ÎÎÎÎÎήίÏÎÏαβÏδεÏγηιξκλμνοÏÏÏÏÏθÏÏÏÏ Î¶ÏÏÎΰ\u00AD', 31081 'x-mac-icelandic': // Python: 'mac_iceland' 31082 'Ãà ÃÃÃÃÃáà âäãåçéèêëÃìîïñóòôöõúùûü𢣧â¢Â¶Ã®©â¢Â´Â¨â ÃÃâ±â¤â¥Â¥ÂµâââÏâ«ÂªÂºÎ©Ã¦Ã¸' + '¿¡¬âÆââ«»â¦Â ÃÃÃÅÅââââââ÷âÿŸââ¬ÃðÃþý·âââ°ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃıË˯ËË˸ËËË', 31083 'x-mac-inuit': // http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/INUIT.TXT 31084 'ááá áááá±á²á³á´á¸á¹áááááááá¦áá®á¯á°á²á³ááááááá°á¡á¥á¦â¢Â¶á§Â®Â©â¢á¨áªá«á»áááá áááá¯á°á±á²á´áµá ááá' + 'ááááªá¨á©áªá«áâ¦Â á®á¾áááââââââáááááááááááá¿áááááá áááááááá±á²á³á´áµá¶áá á¡á¢á£á¤á¥á¦á¼ÅÅ', 31085 'x-mac-ce': // Python: 'mac_latin2' 31086 'ÃÄÄÃÄÃÃÃ¡Ä ÄäÄÄÄ鏟ÄÃÄÄÄÄóÄôöõúÄÄüâ °Ä£§â¢Â¶Ã®©â¢Ä¨â ģĮįĪâ¤â¥Ä«Ä¶ââÅĻļĽľĹĺŠ' + 'ÅŬâÅÅâ«»â¦Â ÅÅÃÅÅââââââ÷âÅÅÅÅâ¹âºÅÅÅÅ ââÅ¡ÅÅÃŤťÃŽžŪÃÃūŮÃůŰűŲųÃýķŻÅżĢË', 31087 macintosh: // Python: 'mac_roman' 31088 'Ãà ÃÃÃÃÃáà âäãåçéèêëÃìîïñóòôöõúùûüâ °¢£§â¢Â¶Ã®©â¢Â´Â¨â ÃÃâ±â¤â¥Â¥ÂµâââÏâ«ÂªÂºÎ©Ã¦Ã¸' + '¿¡¬âÆââ«»â¦Â ÃÃÃÅÅââââââ÷âÿŸââ¬â¹âºï¬ï¬â¡Â·âââ°ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃıË˯ËË˸ËËË', 31089 'x-mac-romanian': // Python: 'mac_romanian' 31090 'Ãà ÃÃÃÃÃáà âäãåçéèêëÃìîïñóòôöõúùûüâ °¢£§â¢Â¶Ã®©â¢Â´Â¨â ÄÈâ±â¤â¥Â¥ÂµâââÏâ«ÂªÂºÎ©ÄÈ' + '¿¡¬âÆââ«»â¦Â ÃÃÃÅÅââââââ÷âÿŸââ¬â¹âºÈÈâ¡Â·âââ°ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃıË˯ËË˸ËËË', 31091 'x-mac-turkish': // Python: 'mac_turkish' 31092 'Ãà ÃÃÃÃÃáà âäãåçéèêëÃìîïñóòôöõúùûüâ °¢£§â¢Â¶Ã®©â¢Â´Â¨â ÃÃâ±â¤â¥Â¥ÂµâââÏâ«ÂªÂºÎ©Ã¦Ã¸' + '¿¡¬âÆââ«»â¦Â ÃÃÃÅÅââââââ÷âÿŸÄÄİıÅÅâ¡Â·âââ°ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃï¢ Ë˯ËË˸ËËË' 31093 }; 31094 /** 31095 * Decodes an old-style Macintosh string. Returns either a Unicode JavaScript 31096 * string, or 'undefined' if the encoding is unsupported. For example, we do 31097 * not support Chinese, Japanese or Korean because these would need large 31098 * mapping tables. 31099 * @param {DataView} dataView 31100 * @param {number} offset 31101 * @param {number} dataLength 31102 * @param {string} encoding 31103 * @returns {string} 31104 */ 31105 31106 decode.MACSTRING = function (dataView, offset, dataLength, encoding) { 31107 var table = eightBitMacEncodings[encoding]; 31108 31109 if (table === undefined) { 31110 return undefined; 31111 } 31112 31113 var result = ''; 31114 31115 for (var i = 0; i < dataLength; i++) { 31116 var c = dataView.getUint8(offset + i); // In all eight-bit Mac encodings, the characters 0x00..0x7F are 31117 // mapped to U+0000..U+007F; we only need to look up the others. 31118 31119 if (c <= 0x7F) { 31120 result += String.fromCharCode(c); 31121 } else { 31122 result += table[c & 0x7F]; 31123 } 31124 } 31125 31126 return result; 31127 }; // Helper function for encode.MACSTRING. Returns a dictionary for mapping 31128 // Unicode character codes to their 8-bit MacOS equivalent. This table 31129 // is not exactly a super cheap data structure, but we do not care because 31130 // encoding Macintosh strings is only rarely needed in typical applications. 31131 31132 31133 var macEncodingTableCache = typeof WeakMap === 'function' && new WeakMap(); 31134 var macEncodingCacheKeys; 31135 31136 var getMacEncodingTable = function (encoding) { 31137 // Since we use encoding as a cache key for WeakMap, it has to be 31138 // a String object and not a literal. And at least on NodeJS 2.10.1, 31139 // WeakMap requires that the same String instance is passed for cache hits. 31140 if (!macEncodingCacheKeys) { 31141 macEncodingCacheKeys = {}; 31142 31143 for (var e in eightBitMacEncodings) { 31144 /*jshint -W053 */ 31145 // Suppress "Do not use String as a constructor." 31146 macEncodingCacheKeys[e] = new String(e); 31147 } 31148 } 31149 31150 var cacheKey = macEncodingCacheKeys[encoding]; 31151 31152 if (cacheKey === undefined) { 31153 return undefined; 31154 } // We can't do "if (cache.has(key)) {return cache.get(key)}" here: 31155 // since garbage collection may run at any time, it could also kick in 31156 // between the calls to cache.has() and cache.get(). In that case, 31157 // we would return 'undefined' even though we do support the encoding. 31158 31159 31160 if (macEncodingTableCache) { 31161 var cachedTable = macEncodingTableCache.get(cacheKey); 31162 31163 if (cachedTable !== undefined) { 31164 return cachedTable; 31165 } 31166 } 31167 31168 var decodingTable = eightBitMacEncodings[encoding]; 31169 31170 if (decodingTable === undefined) { 31171 return undefined; 31172 } 31173 31174 var encodingTable = {}; 31175 31176 for (var i = 0; i < decodingTable.length; i++) { 31177 encodingTable[decodingTable.charCodeAt(i)] = i + 0x80; 31178 } 31179 31180 if (macEncodingTableCache) { 31181 macEncodingTableCache.set(cacheKey, encodingTable); 31182 } 31183 31184 return encodingTable; 31185 }; 31186 /** 31187 * Encodes an old-style Macintosh string. Returns a byte array upon success. 31188 * If the requested encoding is unsupported, or if the input string contains 31189 * a character that cannot be expressed in the encoding, the function returns 31190 * 'undefined'. 31191 * @param {string} str 31192 * @param {string} encoding 31193 * @returns {Array} 31194 */ 31195 31196 31197 encode.MACSTRING = function (str, encoding) { 31198 var table = getMacEncodingTable(encoding); 31199 31200 if (table === undefined) { 31201 return undefined; 31202 } 31203 31204 var result = []; 31205 31206 for (var i = 0; i < str.length; i++) { 31207 var c = str.charCodeAt(i); // In all eight-bit Mac encodings, the characters 0x00..0x7F are 31208 // mapped to U+0000..U+007F; we only need to look up the others. 31209 31210 if (c >= 0x80) { 31211 c = table[c]; 31212 31213 if (c === undefined) { 31214 // str contains a Unicode character that cannot be encoded 31215 // in the requested encoding. 31216 return undefined; 31217 } 31218 } 31219 31220 result[i] = c; // result.push(c); 31221 } 31222 31223 return result; 31224 }; 31225 /** 31226 * @param {string} str 31227 * @param {string} encoding 31228 * @returns {number} 31229 */ 31230 31231 31232 sizeOf.MACSTRING = function (str, encoding) { 31233 var b = encode.MACSTRING(str, encoding); 31234 31235 if (b !== undefined) { 31236 return b.length; 31237 } else { 31238 return 0; 31239 } 31240 }; // Helper for encode.VARDELTAS 31241 31242 31243 function isByteEncodable(value) { 31244 return value >= -128 && value <= 127; 31245 } // Helper for encode.VARDELTAS 31246 31247 31248 function encodeVarDeltaRunAsZeroes(deltas, pos, result) { 31249 var runLength = 0; 31250 var numDeltas = deltas.length; 31251 31252 while (pos < numDeltas && runLength < 64 && deltas[pos] === 0) { 31253 ++pos; 31254 ++runLength; 31255 } 31256 31257 result.push(0x80 | runLength - 1); 31258 return pos; 31259 } // Helper for encode.VARDELTAS 31260 31261 31262 function encodeVarDeltaRunAsBytes(deltas, offset, result) { 31263 var runLength = 0; 31264 var numDeltas = deltas.length; 31265 var pos = offset; 31266 31267 while (pos < numDeltas && runLength < 64) { 31268 var value = deltas[pos]; 31269 31270 if (!isByteEncodable(value)) { 31271 break; 31272 } // Within a byte-encoded run of deltas, a single zero is best 31273 // stored literally as 0x00 value. However, if we have two or 31274 // more zeroes in a sequence, it is better to start a new run. 31275 // Fore example, the sequence of deltas [15, 15, 0, 15, 15] 31276 // becomes 6 bytes (04 0F 0F 00 0F 0F) when storing the zero 31277 // within the current run, but 7 bytes (01 0F 0F 80 01 0F 0F) 31278 // when starting a new run. 31279 31280 31281 if (value === 0 && pos + 1 < numDeltas && deltas[pos + 1] === 0) { 31282 break; 31283 } 31284 31285 ++pos; 31286 ++runLength; 31287 } 31288 31289 result.push(runLength - 1); 31290 31291 for (var i = offset; i < pos; ++i) { 31292 result.push(deltas[i] + 256 & 0xff); 31293 } 31294 31295 return pos; 31296 } // Helper for encode.VARDELTAS 31297 31298 31299 function encodeVarDeltaRunAsWords(deltas, offset, result) { 31300 var runLength = 0; 31301 var numDeltas = deltas.length; 31302 var pos = offset; 31303 31304 while (pos < numDeltas && runLength < 64) { 31305 var value = deltas[pos]; // Within a word-encoded run of deltas, it is easiest to start 31306 // a new run (with a different encoding) whenever we encounter 31307 // a zero value. For example, the sequence [0x6666, 0, 0x7777] 31308 // needs 7 bytes when storing the zero inside the current run 31309 // (42 66 66 00 00 77 77), and equally 7 bytes when starting a 31310 // new run (40 66 66 80 40 77 77). 31311 31312 if (value === 0) { 31313 break; 31314 } // Within a word-encoded run of deltas, a single value in the 31315 // range (-128..127) should be encoded within the current run 31316 // because it is more compact. For example, the sequence 31317 // [0x6666, 2, 0x7777] becomes 7 bytes when storing the value 31318 // literally (42 66 66 00 02 77 77), but 8 bytes when starting 31319 // a new run (40 66 66 00 02 40 77 77). 31320 31321 31322 if (isByteEncodable(value) && pos + 1 < numDeltas && isByteEncodable(deltas[pos + 1])) { 31323 break; 31324 } 31325 31326 ++pos; 31327 ++runLength; 31328 } 31329 31330 result.push(0x40 | runLength - 1); 31331 31332 for (var i = offset; i < pos; ++i) { 31333 var val = deltas[i]; 31334 result.push(val + 0x10000 >> 8 & 0xff, val + 0x100 & 0xff); 31335 } 31336 31337 return pos; 31338 } 31339 /** 31340 * Encode a list of variation adjustment deltas. 31341 * 31342 * Variation adjustment deltas are used in âgvarâ and âcvarâ tables. 31343 * They indicate how points (in âgvarâ) or values (in âcvarâ) get adjusted 31344 * when generating instances of variation fonts. 31345 * 31346 * @see https://www.microsoft.com/typography/otspec/gvar.htm 31347 * @see https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gvar.html 31348 * @param {Array} 31349 * @return {Array} 31350 */ 31351 31352 31353 encode.VARDELTAS = function (deltas) { 31354 var pos = 0; 31355 var result = []; 31356 31357 while (pos < deltas.length) { 31358 var value = deltas[pos]; 31359 31360 if (value === 0) { 31361 pos = encodeVarDeltaRunAsZeroes(deltas, pos, result); 31362 } else if (value >= -128 && value <= 127) { 31363 pos = encodeVarDeltaRunAsBytes(deltas, pos, result); 31364 } else { 31365 pos = encodeVarDeltaRunAsWords(deltas, pos, result); 31366 } 31367 } 31368 31369 return result; 31370 }; // Convert a list of values to a CFF INDEX structure. 31371 // The values should be objects containing name / type / value. 31372 31373 /** 31374 * @param {Array} l 31375 * @returns {Array} 31376 */ 31377 31378 31379 encode.INDEX = function (l) { 31380 //var offset, offsets, offsetEncoder, encodedOffsets, encodedOffset, data, 31381 // i, v; 31382 // Because we have to know which data type to use to encode the offsets, 31383
31383 // we have to go through the values twice: once to encode the data and 31384 // calculate the offsets, then again to encode the offsets using the fitting data type. 31385 var offset = 1; // First offset is always 1. 31386 31387 var offsets = [offset]; 31388 var data = []; 31389 31390 for (var i = 0; i < l.length; i += 1) { 31391 var v = encode.OBJECT(l[i]); 31392 Array.prototype.push.apply(data, v); 31393 offset += v.length; 31394 offsets.push(offset); 31395 } 31396 31397 if (data.length === 0) { 31398 return [0, 0]; 31399 } 31400 31401 var encodedOffsets = []; 31402 var offSize = 1 + Math.floor(Math.log(offset) / Math.log(2)) / 8 | 0; 31403 var offsetEncoder = [undefined, encode.BYTE, encode.USHORT, encode.UINT24, encode.ULONG][offSize]; 31404 31405 for (var i$1 = 0; i$1 < offsets.length; i$1 += 1) { 31406 var encodedOffset = offsetEncoder(offsets[i$1]); 31407 Array.prototype.push.apply(encodedOffsets, encodedOffset); 31408 } 31409 31410 return Array.prototype.concat(encode.Card16(l.length), encode.OffSize(offSize), encodedOffsets, data); 31411 }; 31412 /** 31413 * @param {Array} 31414 * @returns {number} 31415 */ 31416 31417 31418 sizeOf.INDEX = function (v) { 31419 return encode.INDEX(v).length; 31420 }; 31421 /** 31422 * Convert an object to a CFF DICT structure. 31423 * The keys should be numeric. 31424 * The values should be objects containing name / type / value. 31425 * @param {Object} m 31426 * @returns {Array} 31427 */ 31428 31429 31430 encode.DICT = function (m) { 31431 var d = []; 31432 var keys = Object.keys(m); 31433 var length = keys.length; 31434 31435 for (var i = 0; i < length; i += 1) { 31436 // Object.keys() return string keys, but our keys are always numeric. 31437 var k = parseInt(keys[i], 0); 31438 var v = m[k]; // Value comes before the key. 31439 31440 d = d.concat(encode.OPERAND(v.value, v.type)); 31441 d = d.concat(encode.OPERATOR(k)); 31442 } 31443 31444 return d; 31445 }; 31446 /** 31447 * @param {Object} 31448 * @returns {number} 31449 */ 31450 31451 31452 sizeOf.DICT = function (m) { 31453 return encode.DICT(m).length; 31454 }; 31455 /** 31456 * @param {number} 31457 * @returns {Array} 31458 */ 31459 31460 31461 encode.OPERATOR = function (v) { 31462 if (v < 1200) { 31463 return [v]; 31464 } else { 31465 return [12, v - 1200]; 31466 } 31467 }; 31468 /** 31469 * @param {Array} v 31470 * @param {string} 31471 * @returns {Array} 31472 */ 31473 31474 31475 encode.OPERAND = function (v, type) { 31476 var d = []; 31477 31478 if (Array.isArray(type)) { 31479 for (var i = 0; i < type.length; i += 1) { 31480 check.argument(v.length === type.length, 'Not enough arguments given for type' + type); 31481 d = d.concat(encode.OPERAND(v[i], type[i])); 31482 } 31483 } else { 31484 if (type === 'SID') { 31485 d = d.concat(encode.NUMBER(v)); 31486 } else if (type === 'offset') { 31487 // We make it easy for ourselves and always encode offsets as 31488 // 4 bytes. This makes offset calculation for the top dict easier. 31489 d = d.concat(encode.NUMBER32(v)); 31490 } else if (type === 'number') { 31491 d = d.concat(encode.NUMBER(v)); 31492 } else if (type === 'real') { 31493 d = d.concat(encode.REAL(v)); 31494 } else { 31495 throw new Error('Unknown operand type ' + type); // FIXME Add support for booleans 31496 } 31497 } 31498 31499 return d; 31500 }; 31501 31502 encode.OP = encode.BYTE; 31503 sizeOf.OP = sizeOf.BYTE; // memoize charstring encoding using WeakMap if available 31504 31505 var wmm = typeof WeakMap === 'function' && new WeakMap(); 31506 /** 31507 * Convert a list of CharString operations to bytes. 31508 * @param {Array} 31509 * @returns {Array} 31510 */ 31511 31512 encode.CHARSTRING = function (ops) { 31513 // See encode.MACSTRING for why we don't do "if (wmm && wmm.has(ops))". 31514 if (wmm) { 31515 var cachedValue = wmm.get(ops); 31516 31517 if (cachedValue !== undefined) { 31518 return cachedValue; 31519 } 31520 } 31521 31522 var d = []; 31523 var length = ops.length; 31524 31525 for (var i = 0; i < length; i += 1) { 31526 var op = ops[i]; 31527 d = d.concat(encode[op.type](op.value)); 31528 } 31529 31530 if (wmm) { 31531 wmm.set(ops, d); 31532 } 31533 31534 return d; 31535 }; 31536 /** 31537 * @param {Array} 31538 * @returns {number} 31539 */ 31540 31541 31542 sizeOf.CHARSTRING = function (ops) { 31543 return encode.CHARSTRING(ops).length; 31544 }; // Utility functions //////////////////////////////////////////////////////// 31545 31546 /**
31547 * Convert an object containing name / type / value to bytes. 31548 * @param {Object} 31549 * @returns {Array} 31550 */ 31551 31552 31553 encode.OBJECT = function (v) { 31554 var encodingFunction = encode[v.type]; 31555 check.argument(encodingFunction !== undefined, 'No encoding function for type ' + v.type); 31556 return encodingFunction(v.value); 31557 }; 31558 /** 31559 * @param {Object} 31560 * @returns {number} 31561 */ 31562 31563 31564 sizeOf.OBJECT = function (v) { 31565 var sizeOfFunction = sizeOf[v.type]; 31566 check.argument(sizeOfFunction !== undefined, 'No sizeOf function for type ' + v.type); 31567 return sizeOfFunction(v.value); 31568 }; 31569 /** 31570 * Convert a table object to bytes. 31571 * A table contains a list of fields containing the metadata (name, type and default value). 31572 * The table itself has the field values set as attributes. 31573 * @param {opentype.Table} 31574 * @returns {Array} 31575 */ 31576 31577 31578 encode.TABLE = function (table) { 31579 var d = []; 31580 var length = table.fields.length; 31581 var subtables = []; 31582 var subtableOffsets = []; 31583 31584 for (var i = 0; i < length; i += 1) { 31585 var field = table.fields[i]; 31586 var encodingFunction = encode[field.type]; 31587 check.argument(encodingFunction !== undefined, 'No encoding function for field type ' + field.type + ' (' + field.name + ')'); 31588 var value = table[field.name]; 31589 31590 if (value === undefined) { 31591 value = field.value; 31592 } 31593 31594 var bytes = encodingFunction(value); 31595 31596 if (field.type === 'TABLE') { 31597 subtableOffsets.push(d.length); 31598 d = d.concat([0, 0]); 31599 subtables.push(bytes); 31600 } else { 31601 d = d.concat(bytes); 31602 } 31603 } 31604 31605 for (var i$1 = 0; i$1 < subtables.length; i$1 += 1) { 31606 var o = subtableOffsets[i$1]; 31607 var offset = d.length; 31608 check.argument(offset < 65536, 'Table ' + table.tableName + ' too big.'); 31609 d[o] = offset >> 8; 31610 d[o + 1] = offset & 0xff; 31611 d = d.concat(subtables[i$1]); 31612 } 31613 31614 return d; 31615 }; 31616 /** 31617 * @param {opentype.Table} 31618 * @returns {number} 31619 */ 31620 31621 31622 sizeOf.TABLE = function (table) { 31623 var numBytes = 0; 31624 var length = table.fields.length; 31625 31626 for (var i = 0; i < length; i += 1) { 31627 var field = table.fields[i]; 31628 var sizeOfFunction = sizeOf[field.type]; 31629 check.argument(sizeOfFunction !== undefined, 'No sizeOf function for field type ' + field.type + ' (' + field.name + ')'); 31630 var value = table[field.name]; 31631 31632 if (value === undefined) { 31633 value = field.value; 31634 } 31635 31636 numBytes += sizeOfFunction(value); // Subtables take 2 more bytes for offsets. 31637 31638 if (field.type === 'TABLE') { 31639 numBytes += 2; 31640 } 31641 } 31642 31643 return numBytes; 31644 }; 31645 31646 encode.RECORD = encode.TABLE; 31647 sizeOf.RECORD = sizeOf.TABLE; // Merge in a list of bytes. 31648 31649 encode.LITERAL = function (v) { 31650 return v; 31651 }; 31652 31653 sizeOf.LITERAL = function (v) { 31654 return v.length; 31655 }; // Table metadata 31656 31657 /** 31658 * @exports opentype.Table 31659 * @class 31660 * @param {string} tableName 31661 * @param {Array} fields 31662 * @param {Object} options 31663 * @constructor 31664 */ 31665 31666 31667 function Table(tableName, fields, options) { 31668 var this$1 = this; 31669 31670 for (var i = 0; i < fields.length; i += 1) { 31671 var field = fields[i]; 31672 this$1[field.name] = field.value; 31673 } 31674 31675 this.tableName = tableName; 31676 this.fields = fields; 31677 31678 if (options) { 31679 var optionKeys = Object.keys(options); 31680 31681 for (var i$1 = 0; i$1 < optionKeys.length; i$1 += 1) { 31682 var k = optionKeys[i$1]; 31683 var v = options[k]; 31684 31685 if (this$1[k] !== undefined) { 31686 this$1[k] = v; 31687 } 31688 } 31689 } 31690 } 31691 /** 31692 * Encodes the table and returns an array of bytes 31693 * @return {Array} 31694 */ 31695 31696 31697 Table.prototype.encode = function () { 31698 return encode.TABLE(this); 31699 }; 31700 /** 31701 * Get the size of the table. 31702 * @return {number} 31703 */ 31704 31705 31706 Table.prototype.sizeOf = function () { 31707 return sizeOf.TABLE(this); 31708 }; 31709 /** 31710 * @private 31711 */ 31712 31713 31714 function ushortList(itemName, list, count) { 31715 if (count === undefined) { 31716 count = list.length; 31717 } 31718 31719 var fields = new Array(list.length + 1); 31720 fields[0] = { 31721 name: itemName + 'Count', 31722 type: 'USHORT', 31723 value: count 31724 }; 31725 31726 for (var i = 0; i < list.length; i++) { 31727 fields[i + 1] = { 31728 name: itemName + i, 31729 type: 'USHORT', 31730 value: list[i] 31731 }; 31732 } 31733 31734 return fields; 31735 } 31736 /** 31737 * @private 31738 */ 31739 31740 31741 function tableList(itemName, records, itemCallback) { 31742 var count = records.length; 31743 var fields = new Array(count + 1); 31744 fields[0] = { 31745 name: itemName + 'Count', 31746 type: 'USHORT', 31747 value: count 31748 }; 31749 31750 for (var i = 0; i < count; i++) { 31751 fields[i + 1] = { 31752 name: itemName + i, 31753 type: 'TABLE', 31754 value: itemCallback(records[i], i) 31755 }; 31756 } 31757 31758 return fields; 31759 } 31760 /** 31761 * @private 31762 */ 31763 31764 31765 function recordList(itemName, records, itemCallback) { 31766 var count = records.length; 31767 var fields = []; 31768 fields[0] = { 31769 name: itemName + 'Count', 31770 type: 'USHORT', 31771 value: count 31772 }; 31773 31774 for (var i = 0; i < count; i++) { 31775 fields = fields.concat(itemCallback(records[i], i)); 31776 } 31777 31778 return fields; 31779 } // Common Layout Tables 31780 31781 /** 31782 * @exports opentype.Coverage 31783 * @class 31784 * @param {opentype.Table} 31785 * @constructor 31786 * @extends opentype.Table 31787 */ 31788 31789 31790 function Coverage(coverageTable) { 31791 if (coverageTable.format === 1) { 31792 Table.call(this, 'coverageTable', [{ 31793 name: 'coverageFormat', 31794 type: 'USHORT', 31795 value: 1 31796 }].concat(ushortList('glyph', coverageTable.glyphs))); 31797 } else { 31798 check.assert(false, 'Can\'t create coverage table format 2 yet.'); 31799 } 31800 } 31801 31802 Coverage.prototype = Object.create(Table.prototype); 31803 Coverage.prototype.constructor = Coverage; 31804 31805 function ScriptList(scriptListTable) { 31806 Table.call(this, 'scriptListTable', recordList('scriptRecord', scriptListTable, function (scriptRecord, i) { 31807 var script = scriptRecord.script; 31808 var defaultLangSys = script.defaultLangSys; 31809 check.assert(!!defaultLangSys, 'Unable to write GSUB: script ' + scriptRecord.tag + ' has no default language system.'); 31810 return [{ 31811 name: 'scriptTag' + i, 31812 type: 'TAG', 31813 value: scriptRecord.tag 31814 }, { 31815 name: 'script' + i, 31816 type: 'TABLE', 31817 value: new Table('scriptTable', [{ 31818 name: 'defaultLangSys', 31819 type: 'TABLE', 31820 value: new Table('defaultLangSys', [{ 31821 name: 'lookupOrder', 31822 type: 'USHORT', 31823 value: 0 31824 }, { 31825 name: 'reqFeatureIndex', 31826 type: 'USHORT', 31827 value: defaultLangSys.reqFeatureIndex 31828 }].concat(ushortList('featureIndex', defaultLangSys.featureIndexes))) 31829 }].concat(recordList('langSys', script.langSysRecords, function (langSysRecord, i) { 31830 var langSys = langSysRecord.langSys; 31831 return [{ 31832 name: 'langSysTag' + i, 31833 type: 'TAG', 31834 value: langSysRecord.tag 31835 }, { 31836 name: 'langSys' + i, 31837 type: 'TABLE', 31838 value: new Table('langSys', [{ 31839 name: 'lookupOrder', 31840 type: 'USHORT', 31841 value: 0 31842 }, { 31843 name: 'reqFeatureIndex', 31844 type: 'USHORT', 31845 value: langSys.reqFeatureIndex 31846 }].concat(ushortList('featureIndex', langSys.featureIndexes))) 31847 }]; 31848 }))) 31849 }]; 31850 })); 31851 } 31852 31853 ScriptList.prototype = Object.create(Table.prototype); 31854 ScriptList.prototype.constructor = ScriptList; 31855 /** 31856 * @exports opentype.FeatureList 31857 * @class 31858 * @param {opentype.Table} 31859 * @constructor 31860 * @extends opentype.Table 31861 */ 31862 31863 function FeatureList(featureListTable) { 31864 Table.call(this, 'featureListTable', recordList('featureRecord', featureListTable, function (featureRecord, i) { 31865 var feature = featureRecord.feature; 31866 return [{ 31867 name: 'featureTag' + i, 31868 type: 'TAG', 31869 value: featureRecord.tag 31870 }, { 31871 name: 'feature' + i, 31872 type: 'TABLE', 31873 value: new Table('featureTable', [{
31874 name: 'featureParams', 31875 type: 'USHORT', 31876 value: feature.featureParams 31877 }].concat(ushortList('lookupListIndex', feature.lookupListIndexes))) 31878 }]; 31879 })); 31880 } 31881 31882 FeatureList.prototype = Object.create(Table.prototype); 31883 FeatureList.prototype.constructor = FeatureList; 31884 /** 31885 * @exports opentype.LookupList 31886 * @class 31887 * @param {opentype.Table} 31888 * @param {Object} 31889 * @constructor 31890 * @extends opentype.Table 31891 */ 31892 31893 function LookupList(lookupListTable, subtableMakers) { 31894 Table.call(this, 'lookupListTable', tableList('lookup', lookupListTable, function (lookupTable) { 31895 var subtableCallback = subtableMakers[lookupTable.lookupType]; 31896 check.assert(!!subtableCallback, 'Unable to write GSUB lookup type ' + lookupTable.lookupType + ' tables.'); 31897 return new Table('lookupTable', [{ 31898 name: 'lookupType', 31899 type: 'USHORT', 31900 value: lookupTable.lookupType 31901 }, { 31902 name: 'lookupFlag', 31903 type: 'USHORT', 31904 value: lookupTable.lookupFlag 31905 }].concat(tableList('subtable', lookupTable.subtables, subtableCallback))); 31906 })); 31907 } 31908 31909 LookupList.prototype = Object.create(Table.prototype); 31910 LookupList.prototype.constructor = LookupList; // Record = same as Table, but inlined (a Table has an offset and its data is further in the stream) 31911 // Don't use offsets inside Records (probable bug), only in Tables. 31912 31913 var table = { 31914 Table: Table, 31915 Record: Table, 31916 Coverage: Coverage, 31917 ScriptList: ScriptList, 31918 FeatureList: FeatureList, 31919 LookupList: LookupList, 31920 ushortList: ushortList, 31921 tableList: tableList, 31922 recordList: recordList 31923 }; // Parsing utility functions 31924 // Retrieve an unsigned byte from the DataView. 31925 31926 function getByte(dataView, offset) { 31927 return dataView.getUint8(offset); 31928 } // Retrieve an unsigned 16-bit short from the DataView. 31929 // The value is stored in big endian. 31930 31931 31932 function getUShort(dataView, offset) { 31933 return dataView.getUint16(offset, false); 31934 } // Retrieve a signed 16-bit short from the DataView. 31935 // The value is stored in big endian. 31936 31937 31938 function getShort(dataView, offset) { 31939 return dataView.getInt16(offset, false); 31940 } // Retrieve an unsigned 32-bit long from the DataView. 31941 // The value is stored in big endian. 31942 31943 31944 function getULong(dataView, offset) { 31945 return dataView.getUint32(offset, false); 31946 } // Retrieve a 32-bit signed fixed-point number (16.16) from the DataView. 31947 // The value is stored in big endian. 31948 31949 31950 function getFixed(dataView, offset) { 31951 var decimal = dataView.getInt16(offset, false); 31952 var fraction = dataView.getUint16(offset + 2, false); 31953 return decimal + fraction / 65535; 31954 } // Retrieve a 4-character tag from the DataView. 31955 // Tags are used to identify tables. 31956 31957 31958 function getTag(dataView, offset) { 31959 var tag = ''; 31960 31961 for (var i = offset; i < offset + 4; i += 1) { 31962 tag += String.fromCharCode(dataView.getInt8(i)); 31963 } 31964 31965 return tag; 31966 } // Retrieve an offset from the DataView. 31967 // Offsets are 1 to 4 bytes in length, depending on the offSize argument. 31968 31969 31970 function getOffset(dataView, offset, offSize) { 31971 var v = 0; 31972 31973 for (var i = 0; i < offSize; i += 1) { 31974 v <<= 8; 31975 v += dataView.getUint8(offset + i); 31976 } 31977 31978 return v; 31979 } // Retrieve a number of bytes from start offset to the end offset from the DataView. 31980 31981 31982 function getBytes(dataView, startOffset, endOffset) { 31983 var bytes = []; 31984 31985 for (var i = startOffset; i < endOffset; i += 1) { 31986 bytes.push(dataView.getUint8(i)); 31987 } 31988 31989 return bytes; 31990 }
31990 // Convert the list of bytes to a string. 31991 31992 31993 function bytesToString(bytes) { 31994 var s = ''; 31995 31996 for (var i = 0; i < bytes.length; i += 1) { 31997 s += String.fromCharCode(bytes[i]); 31998 } 31999 32000 return s; 32001 } 32002 32003 var typeOffsets = { 32004 byte: 1, 32005 uShort: 2, 32006 short: 2, 32007 uLong: 4, 32008 fixed: 4, 32009 longDateTime: 8, 32010 tag: 4 32011 }; // A stateful parser that changes the offset whenever a value is retrieved. 32012 // The data is a DataView. 32013 32014 function Parser(data, offset) { 32015 this.data = data; 32016 this.offset = offset; 32017 this.relativeOffset = 0; 32018 } 32019 32020 Parser.prototype.parseByte = function () { 32021 var v = this.data.getUint8(this.offset + this.relativeOffset); 32022 this.relativeOffset += 1; 32023 return v; 32024 }; 32025 32026 Parser.prototype.parseChar = function () { 32027 var v = this.data.getInt8(this.offset + this.relativeOffset); 32028 this.relativeOffset += 1; 32029 return v; 32030 }; 32031 32032 Parser.prototype.parseCard8 = Parser.prototype.parseByte; 32033 32034 Parser.prototype.parseUShort = function () { 32035 var v = this.data.getUint16(this.offset + this.relativeOffset); 32036 this.relativeOffset += 2; 32037 return v; 32038 }; 32039 32040 Parser.prototype.parseCard16 = Parser.prototype.parseUShort; 32041 Parser.prototype.parseSID = Parser.prototype.parseUShort; 32042 Parser.prototype.parseOffset16 = Parser.prototype.parseUShort; 32043 32044 Parser.prototype.parseShort = function () { 32045 var v = this.data.getInt16(this.offset + this.relativeOffset); 32046 this.relativeOffset += 2; 32047 return v; 32048 }; 32049 32050 Parser.prototype.parseF2Dot14 = function () { 32051 var v = this.data.getInt16(this.offset + this.relativeOffset) / 16384; 32052 this.relativeOffset += 2; 32053 return v; 32054 }; 32055 32056 Parser.prototype.parseULong = function () { 32057 var v = getULong(this.data, this.offset + this.relativeOffset); 32058 this.relativeOffset += 4; 32059 return v; 32060 }; 32061 32062 Parser.prototype.parseOffset32 = Parser.prototype.parseULong; 32063 32064 Parser.prototype.parseFixed = function () { 32065 var v = getFixed(this.data, this.offset + this.relativeOffset); 32066 this.relativeOffset += 4; 32067 return v; 32068 }; 32069 32070 Parser.prototype.parseString = function (length) { 32071 var dataView = this.data; 32072 var offset = this.offset + this.relativeOffset; 32073 var string = ''; 32074 this.relativeOffset += length; 32075 32076 for (var i = 0; i < length; i++) { 32077 string += String.fromCharCode(dataView.getUint8(offset + i)); 32078 } 32079 32080 return string; 32081 }; 32082 32083 Parser.prototype.parseTag = function () { 32084 return this.parseString(4); 32085 }; // LONGDATETIME is a 64-bit integer. 32086 // JavaScript and unix timestamps traditionally use 32 bits, so we 32087 // only take the last 32 bits. 32088 // + Since until 2038 those bits will be filled by zeros we can ignore them. 32089 32090 32091 Parser.prototype.parseLongDateTime = function () { 32092 var v = getULong(this.data, this.offset + this.relativeOffset + 4); // Subtract seconds between 01/01/1904 and 01/01/1970 32093 // to convert Apple Mac timestamp to Standard Unix timestamp 32094 32095 v -= 2082844800; 32096 this.relativeOffset += 8; 32097 return v; 32098 }; 32099 32100 Parser.prototype.parseVersion = function (minorBase) { 32101 var major = getUShort(this.data, this.offset + this.relativeOffset); // How to interpret the minor version is very vague in the spec. 0x5000 is 5, 0x1000 is 1 32102 // Default returns the correct number if minor = 0xN000 where N is 0-9 32103 // Set minorBase to 1 for tables that use minor = N where N is 0-9 32104 32105 var minor = getUShort(this.data, this.offset + this.relativeOffset + 2); 32106 this.relativeOffset += 4; 32107 32108 if (minorBase === undefined) { 32109 minorBase = 0x1000; 32110 } 32111 32112 return major + minor / minorBase / 10; 32113 }; 32114 32115 Parser.prototype.skip = function (type, amount) { 32116 if (amount === undefined) { 32117 amount = 1; 32118 } 32119 32120 this.relativeOffset += typeOffsets[type] * amount; 32121 }; ///// Parsing lists and records /////////////////////////////// 32122 // Parse a list of 32 bit unsigned integers. 32123 32124 32125 Parser.prototype.parseULongList = function (count) { 32126 if (count === undefined) { 32127 count = this.parseULong(); 32128 } 32129 32130 var offsets = new Array(count); 32131 var dataView = this.data; 32132 var offset = this.offset + this.relativeOffset; 32133 32134 for (var i = 0; i < count; i++) { 32135 offsets[i] = dataView.getUint32(offset); 32136 offset += 4; 32137 } 32138 32139 this.relativeOffset += count * 4; 32140 return offsets; 32141 }; // Parse a list of 16 bit unsigned integers. The length of the list can be read on the stream 32142 // or provided as an argument. 32143 32144 32145 Parser.prototype.parseOffset16List = Parser.prototype.parseUShortList = function (count) { 32146 if (count === undefined) { 32147 count = this.parseUShort(); 32148 } 32149 32150 var offsets = new Array(count); 32151 var dataView = this.data; 32152 var offset = this.offset + this.relativeOffset; 32153 32154 for (var i = 0; i < count; i++) { 32155 offsets[i] = dataView.getUint16(offset); 32156 offset += 2; 32157 } 32158 32159 this.relativeOffset += count * 2; 32160 return offsets; 32161 }; // Parses a list of 16 bit signed integers. 32162 32163 32164 Parser.prototype.parseShortList = function (count) { 32165 var list = new Array(count); 32166 var dataView = this.data; 32167 var offset = this.offset + this.relativeOffset; 32168 32169 for (var i = 0; i < count; i++) { 32170 list[i] = dataView.getInt16(offset); 32171 offset += 2; 32172 } 32173 32174 this.relativeOffset += count * 2; 32175 return list; 32176 };
32176 // Parses a list of bytes. 32177 32178 32179 Parser.prototype.parseByteList = function (count) { 32180 var list = new Array(count); 32181 var dataView = this.data; 32182 var offset = this.offset + this.relativeOffset; 32183 32184 for (var i = 0; i < count; i++) { 32185 list[i] = dataView.getUint8(offset++); 32186 } 32187 32188 this.relativeOffset += count; 32189 return list; 32190 }; 32191 /** 32192 * Parse a list of items. 32193 * Record count is optional, if omitted it is read from the stream. 32194 * itemCallback is one of the Parser methods. 32195 */ 32196 32197 32198 Parser.prototype.parseList = function (count, itemCallback) { 32199 var this$1 = this; 32200 32201 if (!itemCallback) { 32202 itemCallback = count; 32203 count = this.parseUShort(); 32204 } 32205 32206 var list = new Array(count); 32207 32208 for (var i = 0; i < count; i++) { 32209 list[i] = itemCallback.call(this$1); 32210 } 32211 32212 return list; 32213 }; 32214 32215 Parser.prototype.parseList32 = function (count, itemCallback) { 32216 var this$1 = this; 32217 32218 if (!itemCallback) { 32219 itemCallback = count; 32220 count = this.parseULong(); 32221 } 32222 32223 var list = new Array(count); 32224 32225 for (var i = 0; i < count; i++) { 32226 list[i] = itemCallback.call(this$1); 32227 } 32228 32229 return list; 32230 }; 32231 /** 32232 * Parse a list of records. 32233 * Record count is optional, if omitted it is read from the stream. 32234 * Example of recordDescription: { sequenceIndex: Parser.uShort, lookupListIndex: Parser.uShort } 32235 */ 32236 32237 32238 Parser.prototype.parseRecordList = function (count, recordDescription) { 32239 var this$1 = this; // If the count argument is absent, read it in the stream. 32240 32241 if (!recordDescription) { 32242 recordDescription = count; 32243 count = this.parseUShort(); 32244 } 32245 32246 var records = new Array(count); 32247 var fields = Object.keys(recordDescription); 32248 32249 for (var i = 0; i < count; i++) { 32250 var rec = {}; 32251 32252 for (var j = 0; j < fields.length; j++) { 32253 var fieldName = fields[j]; 32254 var fieldType = recordDescription[fieldName]; 32255 rec[fieldName] = fieldType.call(this$1); 32256 } 32257 32258 records[i] = rec; 32259 } 32260 32261 return records; 32262 }; 32263 32264 Parser.prototype.parseRecordList32 = function (count, recordDescription) { 32265 var this$1 = this; // If the count argument is absent, read it in the stream. 32266 32267 if (!recordDescription) { 32268 recordDescription = count; 32269 count = this.parseULong(); 32270 } 32271 32272 var records = new Array(count); 32273 var fields = Object.keys(recordDescription); 32274 32275 for (var i = 0; i < count; i++) { 32276 var rec = {}; 32277 32278 for (var j = 0; j < fields.length; j++) { 32279 var fieldName = fields[j]; 32280 var fieldType = recordDescription[fieldName]; 32281 rec[fieldName] = fieldType.call(this$1); 32282 } 32283 32284 records[i] = rec; 32285 } 32286 32287 return records; 32288 }; // Parse a data structure into an object 32289 // Example of description: { sequenceIndex: Parser.uShort, lookupListIndex: Parser.uShort } 32290 32291 32292 Parser.prototype.parseStruct = function (description) { 32293 var this$1 = this; 32294 32295 if (typeof description === 'function') { 32296 return description.call(this); 32297 } else { 32298 var fields = Object.keys(description); 32299 var struct = {}; 32300 32301 for (var j = 0; j < fields.length; j++) { 32302 var fieldName = fields[j]; 32303 var fieldType = description[fieldName]; 32304 struct[fieldName] = fieldType.call(this$1); 32305 } 32306 32307 return struct; 32308 } 32309 }; 32310 /** 32311 * Parse a GPOS valueRecord
32312 * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#value-record 32313 * valueFormat is optional, if omitted it is read from the stream. 32314 */ 32315 32316 32317 Parser.prototype.parseValueRecord = function (valueFormat) { 32318 if (valueFormat === undefined) { 32319 valueFormat = this.parseUShort(); 32320 } 32321 32322 if (valueFormat === 0) { 32323 // valueFormat2 in kerning pairs is most often 0 32324 // in this case return undefined instead of an empty object, to save space 32325 return; 32326 } 32327 32328 var valueRecord = {}; 32329 32330 if (valueFormat & 0x0001) { 32331 valueRecord.xPlacement = this.parseShort(); 32332 } 32333 32334 if (valueFormat & 0x0002) { 32335 valueRecord.yPlacement = this.parseShort(); 32336 } 32337 32338 if (valueFormat & 0x0004) { 32339 valueRecord.xAdvance = this.parseShort(); 32340 } 32341 32342 if (valueFormat & 0x0008) { 32343 valueRecord.yAdvance = this.parseShort(); 32344 } // Device table (non-variable font) / VariationIndex table (variable font) not supported 32345 // https://docs.microsoft.com/fr-fr/typography/opentype/spec/chapter2#devVarIdxTbls 32346 32347 32348 if (valueFormat & 0x0010) { 32349 valueRecord.xPlaDevice = undefined; 32350 this.parseShort(); 32351 } 32352 32353 if (valueFormat & 0x0020) { 32354 valueRecord.yPlaDevice = undefined; 32355 this.parseShort(); 32356 } 32357 32358 if (valueFormat & 0x0040) { 32359 valueRecord.xAdvDevice = undefined; 32360 this.parseShort(); 32361 } 32362 32363 if (valueFormat & 0x0080) { 32364 valueRecord.yAdvDevice = undefined; 32365 this.parseShort(); 32366 } 32367 32368 return valueRecord; 32369 }; 32370 /** 32371 * Parse a list of GPOS valueRecords 32372 * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#value-record 32373 * valueFormat and valueCount are read from the stream. 32374 */ 32375 32376 32377 Parser.prototype.parseValueRecordList = function () { 32378 var this$1 = this; 32379 var valueFormat = this.parseUShort(); 32380 var valueCount = this.parseUShort(); 32381 var values = new Array(valueCount); 32382 32383 for (var i = 0; i < valueCount; i++) { 32384 values[i] = this$1.parseValueRecord(valueFormat); 32385 } 32386 32387 return values; 32388 }; 32389 32390 Parser.prototype.parsePointer = function (description) { 32391 var structOffset = this.parseOffset16(); 32392 32393 if (structOffset > 0) { 32394 // NULL offset => return undefined 32395 return new Parser(this.data, this.offset + structOffset).parseStruct(description); 32396 } 32397 32398 return undefined; 32399 }; 32400 32401 Parser.prototype.parsePointer32 = function (description) { 32402 var structOffset = this.parseOffset32(); 32403 32404 if (structOffset > 0) { 32405 // NULL offset => return undefined 32406 return new Parser(this.data, this.offset + structOffset).parseStruct(description); 32407 } 32408 32409 return undefined; 32410 }; 32411 /** 32412 * Parse a list of offsets to lists of 16-bit integers, 32413 * or a list of offsets to lists of offsets to any kind of items. 32414 * If itemCallback is not provided, a list of list of UShort is assumed. 32415 * If provided, itemCallback is called on each item and must parse the item. 32416 * See examples in tables/gsub.js 32417 */ 32418 32419 32420 Parser.prototype.parseListOfLists = function (itemCallback) { 32421 var this$1 = this; 32422 var offsets = this.parseOffset16List(); 32423 var count = offsets.length; 32424 var relativeOffset = this.relativeOffset; 32425 var list = new Array(count); 32426 32427 for (var i = 0; i < count; i++) { 32428 var start = offsets[i]; 32429 32430 if (start === 0) { 32431 // NULL offset 32432 // Add i as owned property to list. Convenient with assert. 32433 list[i] = undefined; 32434 continue; 32435 } 32436 32437 this$1.relativeOffset = start; 32438 32439 if (itemCallback) { 32440 var subOffsets = this$1.parseOffset16List(); 32441 var subList = new Array(subOffsets.length); 32442 32443 for (var j = 0; j < subOffsets.length; j++) { 32444 this$1.relativeOffset = start + subOffsets[j]; 32445 subList[j] = itemCallback.call(this$1); 32446 } 32447 32448 list[i] = subList; 32449 } else { 32450 list[i] = this$1.parseUShortList(); 32451 } 32452 } 32453 32454 this.relativeOffset = relativeOffset; 32455 return list; 32456 };
vendor: 9,140 bytes, lines 32456-32686
32456 ///// Complex tables parsing ////////////////////////////////// 32457 // Parse a coverage table in a GSUB, GPOS or GDEF table. 32458 // https://www.microsoft.com/typography/OTSPEC/chapter2.htm 32459 // parser.offset must point to the start of the table containing the coverage. 32460 32461 32462 Parser.prototype.parseCoverage = function () { 32463 var this$1 = this; 32464 var startOffset = this.offset + this.relativeOffset; 32465 var format = this.parseUShort(); 32466 var count = this.parseUShort(); 32467 32468 if (format === 1) { 32469 return { 32470 format: 1, 32471 glyphs: this.parseUShortList(count) 32472 }; 32473 } else if (format === 2) { 32474 var ranges = new Array(count); 32475 32476 for (var i = 0; i < count; i++) { 32477 ranges[i] = { 32478 start: this$1.parseUShort(), 32479 end: this$1.parseUShort(), 32480 index: this$1.parseUShort() 32481 }; 32482 } 32483 32484 return { 32485 format: 2, 32486 ranges: ranges 32487 }; 32488 } 32489 32490 throw new Error('0x' + startOffset.toString(16) + ': Coverage format must be 1 or 2.'); 32491 }; // Parse a Class Definition Table in a GSUB, GPOS or GDEF table. 32492 // https://www.microsoft.com/typography/OTSPEC/chapter2.htm 32493 32494 32495 Parser.prototype.parseClassDef = function () { 32496 var startOffset = this.offset + this.relativeOffset; 32497 var format = this.parseUShort(); 32498 32499 if (format === 1) { 32500 return { 32501 format: 1, 32502 startGlyph: this.parseUShort(), 32503 classes: this.parseUShortList() 32504 }; 32505 } else if (format === 2) { 32506 return { 32507 format: 2, 32508 ranges: this.parseRecordList({ 32509 start: Parser.uShort, 32510 end: Parser.uShort, 32511 classId: Parser.uShort 32512 }) 32513 }; 32514 } 32515 32516 throw new Error('0x' + startOffset.toString(16) + ': ClassDef format must be 1 or 2.'); 32517 }; ///// Static methods /////////////////////////////////// 32518 // These convenience methods can be used as callbacks and should be called with "this" context set to a Parser instance. 32519 32520 32521 Parser.list = function (count, itemCallback) { 32522 return function () { 32523 return this.parseList(count, itemCallback); 32524 }; 32525 }; 32526 32527 Parser.list32 = function (count, itemCallback) { 32528 return function () { 32529 return this.parseList32(count, itemCallback); 32530 }; 32531 }; 32532 32533 Parser.recordList = function (count, recordDescription) { 32534 return function () { 32535 return this.parseRecordList(count, recordDescription); 32536 }; 32537 }; 32538 32539 Parser.recordList32 = function (count, recordDescription) { 32540 return function () { 32541 return this.parseRecordList32(count, recordDescription); 32542 }; 32543 }; 32544 32545 Parser.pointer = function (description) { 32546 return function () { 32547 return this.parsePointer(description); 32548 }; 32549 }; 32550 32551 Parser.pointer32 = function (description) { 32552 return function () { 32553 return this.parsePointer32(description); 32554 }; 32555 }; 32556 32557 Parser.tag = Parser.prototype.parseTag; 32558 Parser.byte = Parser.prototype.parseByte; 32559 Parser.uShort = Parser.offset16 = Parser.prototype.parseUShort; 32560 Parser.uShortList = Parser.prototype.parseUShortList; 32561 Parser.uLong = Parser.offset32 = Parser.prototype.parseULong; 32562 Parser.uLongList = Parser.prototype.parseULongList; 32563 Parser.struct = Parser.prototype.parseStruct; 32564 Parser.coverage = Parser.prototype.parseCoverage; 32565 Parser.classDef = Parser.prototype.parseClassDef; ///// Script, Feature, Lookup lists /////////////////////////////////////////////// 32566 // https://www.microsoft.com/typography/OTSPEC/chapter2.htm 32567 32568 var langSysTable = { 32569 reserved: Parser.uShort, 32570 reqFeatureIndex: Parser.uShort, 32571 featureIndexes: Parser.uShortList 32572 }; 32573 32574 Parser.prototype.parseScriptList = function () { 32575 return this.parsePointer(Parser.recordList({ 32576 tag: Parser.tag, 32577 script: Parser.pointer({ 32578 defaultLangSys: Parser.pointer(langSysTable), 32579 langSysRecords: Parser.recordList({ 32580 tag: Parser.tag, 32581 langSys: Parser.pointer(langSysTable) 32582 }) 32583 }) 32584 })) || []; 32585 }; 32586 32587 Parser.prototype.parseFeatureList = function () { 32588 return this.parsePointer(Parser.recordList({ 32589 tag: Parser.tag, 32590 feature: Parser.pointer({ 32591 featureParams: Parser.offset16, 32592 lookupListIndexes: Parser.uShortList 32593 }) 32594 })) || []; 32595 }; 32596 32597 Parser.prototype.parseLookupList = function (lookupTableParsers) { 32598 return this.parsePointer(Parser.list(Parser.pointer(function () { 32599 var lookupType = this.parseUShort(); 32600 check.argument(1 <= lookupType && lookupType <= 9, 'GPOS/GSUB lookup type ' + lookupType + ' unknown.'); 32601 var lookupFlag = this.parseUShort(); 32602 var useMarkFilteringSet = lookupFlag & 0x10; 32603 return { 32604 lookupType: lookupType, 32605 lookupFlag: lookupFlag, 32606 subtables: this.parseList(Parser.pointer(lookupTableParsers[lookupType])), 32607 markFilteringSet: useMarkFilteringSet ? this.parseUShort() : undefined 32608 }; 32609 }))) || []; 32610 }; 32611 32612 Parser.prototype.parseFeatureVariationsList = function () { 32613 return this.parsePointer32(function () { 32614 var majorVersion = this.parseUShort(); 32615 var minorVersion = this.parseUShort(); 32616 check.argument(majorVersion === 1 && minorVersion < 1, 'GPOS/GSUB feature variations table unknown.'); 32617 var featureVariations = this.parseRecordList32({ 32618 conditionSetOffset: Parser.offset32, 32619 featureTableSubstitutionOffset: Parser.offset32 32620 }); 32621 return featureVariations; 32622 }) || []; 32623 }; 32624 32625 var parse = { 32626 getByte: getByte, 32627 getCard8: getByte, 32628 getUShort: getUShort, 32629 getCard16: getUShort, 32630 getShort: getShort, 32631 getULong: getULong, 32632 getFixed: getFixed, 32633 getTag: getTag, 32634 getOffset: getOffset, 32635 getBytes: getBytes, 32636 bytesToString: bytesToString, 32637 Parser: Parser 32638 }; // The `cmap` table stores the mappings from characters to glyphs. 32639 32640 function parseCmapTableFormat12(cmap, p) { 32641 //Skip reserved. 32642 p.parseUShort(); // Length in bytes of the sub-tables. 32643 32644 cmap.length = p.parseULong(); 32645 cmap.language = p.parseULong(); 32646 var groupCount; 32647 cmap.groupCount = groupCount = p.parseULong(); 32648 cmap.glyphIndexMap = {}; 32649 32650 for (var i = 0; i < groupCount; i += 1) { 32651 var startCharCode = p.parseULong(); 32652 var endCharCode = p.parseULong(); 32653 var startGlyphId = p.parseULong(); 32654 32655 for (var c = startCharCode; c <= endCharCode; c += 1) { 32656 cmap.glyphIndexMap[c] = startGlyphId; 32657 startGlyphId++; 32658 } 32659 } 32660 } 32661 32662 function parseCmapTableFormat4(cmap, p, data, start, offset) { 32663 // Length in bytes of the sub-tables. 32664 cmap.length = p.parseUShort(); 32665 cmap.language = p.parseUShort(); // segCount is stored x 2. 32666 32667 var segCount; 32668 cmap.segCount = segCount = p.parseUShort() >> 1; // Skip searchRange, entrySelector, rangeShift. 32669 32670 p.skip('uShort', 3); // The "unrolled" mapping from character codes to glyph indices. 32671 32672 cmap.glyphIndexMap = {}; 32673 var endCountParser = new parse.Parser(data, start + offset + 14); 32674 var startCountParser = new parse.Parser(data, start + offset + 16 + segCount * 2); 32675 var idDeltaParser = new parse.Parser(data, start + offset + 16 + segCount * 4); 32676 var idRangeOffsetParser = new parse.Parser(data, start + offset + 16 + segCount * 6); 32677 var glyphIndexOffset = start + offset + 16 + segCount * 8; 32678 32679 for (var i = 0; i < segCount - 1; i += 1) { 32680 var glyphIndex = void 0; 32681 var endCount = endCountParser.parseUShort(); 32682 var startCount = startCountParser.parseUShort(); 32683 var idDelta = idDeltaParser.parseShort(); 32684 var idRangeOffset = idRangeOffsetParser.parseUShort(); 32685 32686 for (var c = startCount; c <= endCount; c += 1) {
32687 if (idRangeOffset !== 0) { 32688 // The idRangeOffset is relative to the current position in the idRangeOffset array. 32689 // Take the current offset in the idRangeOffset array. 32690 glyphIndexOffset = idRangeOffsetParser.offset + idRangeOffsetParser.relativeOffset - 2; // Add the value of the idRangeOffset, which will move us into the glyphIndex array. 32691 32692 glyphIndexOffset += idRangeOffset; // Then add the character index of the current segment, multiplied by 2 for USHORTs. 32693 32694 glyphIndexOffset += (c - startCount) * 2; 32695 glyphIndex = parse.getUShort(data, glyphIndexOffset); 32696 32697 if (glyphIndex !== 0) { 32698 glyphIndex = glyphIndex + idDelta & 0xFFFF; 32699 } 32700 } else { 32701 glyphIndex = c + idDelta & 0xFFFF; 32702 } 32703 32704 cmap.glyphIndexMap[c] = glyphIndex; 32705 } 32706 } 32707 } // Parse the `cmap` table. This table stores the mappings from characters to glyphs. 32708 // There are many available formats, but we only support the Windows format 4 and 12. 32709 // This function returns a `CmapEncoding` object or null if no supported format could be found. 32710 32711 32712 function parseCmapTable(data, start) { 32713 var cmap = {}; 32714 cmap.version = parse.getUShort(data, start); 32715 check.argument(cmap.version === 0, 'cmap table version should be 0.'); // The cmap table can contain many sub-tables, each with their own format. 32716 // We're only interested in a "platform 0" (Unicode format) and "platform 3" (Windows format) table. 32717 32718 cmap.numTables = parse.getUShort(data, start + 2); 32719 var offset = -1; 32720 32721 for (var i = cmap.numTables - 1; i >= 0; i -= 1) { 32722 var platformId = parse.getUShort(data, start + 4 + i * 8); 32723 var encodingId = parse.getUShort(data, start + 4 + i * 8 + 2); 32724 32725 if (platformId === 3 && (encodingId === 0 || encodingId === 1 || encodingId === 10) || platformId === 0 && (encodingId === 0 || encodingId === 1 || encodingId === 2 || encodingId === 3 || encodingId === 4)) { 32726 offset = parse.getULong(data, start + 4 + i * 8 + 4); 32727 break; 32728 } 32729 } 32730 32731 if (offset === -1) { 32732 // There is no cmap table in the font that we support. 32733 throw new Error('No valid cmap sub-tables found.'); 32734 } 32735 32736 var p = new parse.Parser(data, start + offset); 32737 cmap.format = p.parseUShort(); 32738 32739 if (cmap.format === 12) { 32740 parseCmapTableFormat12(cmap, p); 32741 } else if (cmap.format === 4) { 32742 parseCmapTableFormat4(cmap, p, data, start, offset); 32743 } else { 32744 throw new Error('Only format 4 and 12 cmap tables are supported (found format ' + cmap.format + ').'); 32745 } 32746 32747 return cmap; 32748 } 32749 32750 function addSegment(t, code, glyphIndex) { 32751 t.segments.push({ 32752 end: code, 32753 start: code, 32754 delta: -(code - glyphIndex), 32755 offset: 0, 32756 glyphIndex: glyphIndex 32757 }); 32758 } 32759 32760 function addTerminatorSegment(t) { 32761 t.segments.push({ 32762 end: 0xFFFF, 32763 start: 0xFFFF, 32764 delta: 1, 32765 offset: 0 32766 }); 32767 } // Make cmap table, format 4 by default, 12 if needed only 32768 32769 32770 function makeCmapTable(glyphs) { 32771 // Plan 0 is the base Unicode Plan but emojis, for example are on another plan, and needs cmap 12 format (with 32bit) 32772 var isPlan0Only = true; 32773 var i; // Check if we need to add cmap format 12 or if format 4 only is fine 32774 32775 for (i = glyphs.length - 1; i > 0; i -= 1) { 32776 var g = glyphs.get(i); 32777 32778 if (g.unicode > 65535) { 32779 console.log('Adding CMAP format 12 (needed!)'); 32780 isPlan0Only = false; 32781 break; 32782 } 32783 } 32784 32785 var cmapTable = [{ 32786 name: 'version', 32787 type: 'USHORT', 32788 value: 0 32789 }, { 32790 name: 'numTables', 32791 type: 'USHORT', 32792 value: isPlan0Only ? 1 : 2 32793 }, // CMAP 4 header 32794 { 32795 name: 'platformID', 32796 type: 'USHORT', 32797 value: 3 32798 }, { 32799 name: 'encodingID', 32800 type: 'USHORT', 32801 value: 1 32802 }, { 32803 name: 'offset', 32804 type: 'ULONG', 32805 value: isPlan0Only ? 12 : 12 + 8 32806 }]; 32807 32808 if (!isPlan0Only) { 32809 cmapTable = cmapTable.concat([// CMAP 12 header 32810 { 32811 name: 'cmap12PlatformID', 32812 type: 'USHORT', 32813 value: 3 32814 }, // We encode only for PlatformID = 3 (Windows) because it is supported everywhere 32815 { 32816 name: 'cmap12EncodingID', 32817 type: 'USHORT', 32818 value: 10 32819 }, { 32820 name: 'cmap12Offset', 32821 type: 'ULONG', 32822 value: 0 32823 }]); 32824 } 32825 32826 cmapTable = cmapTable.concat([// CMAP 4 Subtable 32827 { 32828 name: 'format', 32829 type: 'USHORT', 32830 value: 4 32831 }, { 32832 name: 'cmap4Length', 32833 type: 'USHORT', 32834 value: 0 32835 }, { 32836 name: 'language', 32837 type: 'USHORT', 32838 value: 0 32839 }, { 32840 name: 'segCountX2', 32841 type: 'USHORT', 32842 value: 0 32843 }, {
32844 name: 'searchRange', 32845 type: 'USHORT', 32846 value: 0 32847 }, { 32848 name: 'entrySelector', 32849 type: 'USHORT', 32850 value: 0 32851 }, { 32852 name: 'rangeShift', 32853 type: 'USHORT', 32854 value: 0 32855 }]); 32856 var t = new table.Table('cmap', cmapTable); 32857 t.segments = []; 32858 32859 for (i = 0; i < glyphs.length; i += 1) { 32860 var glyph = glyphs.get(i); 32861 32862 for (var j = 0; j < glyph.unicodes.length; j += 1) { 32863 addSegment(t, glyph.unicodes[j], i); 32864 } 32865 32866 t.segments = t.segments.sort(function (a, b) { 32867 return a.start - b.start; 32868 }); 32869 } 32870 32871 addTerminatorSegment(t); 32872 var segCount = t.segments.length; 32873 var segCountToRemove = 0; // CMAP 4 32874 // Set up parallel segment arrays. 32875 32876 var endCounts = []; 32877 var startCounts = []; 32878 var idDeltas = []; 32879 var idRangeOffsets = []; 32880 var glyphIds = []; // CMAP 12 32881 32882 var cmap12Groups = []; // Reminder this loop is not following the specification at 100% 32883 // The specification -> find suites of characters and make a group 32884 // Here we're doing one group for each letter 32885 // Doing as the spec can save 8 times (or more) space 32886 32887 for (i = 0; i < segCount; i += 1) { 32888 var segment = t.segments[i]; // CMAP 4 32889 32890 if (segment.end <= 65535 && segment.start <= 65535) { 32891 endCounts = endCounts.concat({ 32892 name: 'end_' + i, 32893 type: 'USHORT', 32894 value: segment.end 32895 }); 32896 startCounts = startCounts.concat({ 32897 name: 'start_' + i, 32898 type: 'USHORT', 32899 value: segment.start 32900 }); 32901 idDeltas = idDeltas.concat({ 32902 name: 'idDelta_' + i, 32903 type: 'SHORT', 32904 value: segment.delta 32905 }); 32906 idRangeOffsets = idRangeOffsets.concat({ 32907 name: 'idRangeOffset_' + i, 32908 type: 'USHORT', 32909 value: segment.offset 32910 }); 32911 32912 if (segment.glyphId !== undefined) { 32913 glyphIds = glyphIds.concat({ 32914 name: 'glyph_' + i, 32915 type: 'USHORT', 32916 value: segment.glyphId 32917 }); 32918 } 32919 } else { 32920 // Skip Unicode > 65535 (16bit unsigned max) for CMAP 4, will be added in CMAP 12 32921 segCountToRemove += 1; 32922 } // CMAP 12 32923 // Skip Terminator Segment 32924 32925 32926 if (!isPlan0Only && segment.glyphIndex !== undefined) { 32927 cmap12Groups = cmap12Groups.concat({ 32928 name: 'cmap12Start_' + i, 32929 type: 'ULONG', 32930 value: segment.start 32931 }); 32932 cmap12Groups = cmap12Groups.concat({ 32933 name: 'cmap12End_' + i, 32934 type: 'ULONG', 32935 value: segment.end 32936 }); 32937 cmap12Groups = cmap12Groups.concat({ 32938 name: 'cmap12Glyph_' + i, 32939 type: 'ULONG', 32940 value: segment.glyphIndex 32941 }); 32942 } 32943 } // CMAP 4 Subtable 32944 32945 32946 t.segCountX2 = (segCount - segCountToRemove) * 2; 32947 t.searchRange = Math.pow(2, Math.floor(Math.log(segCount - segCountToRemove) / Math.log(2))) * 2; 32948 t.entrySelector = Math.log(t.searchRange / 2) / Math.log(2); 32949 t.rangeShift = t.segCountX2 - t.searchRange; 32950 t.fields = t.fields.concat(endCounts); 32951 t.fields.push({ 32952 name: 'reservedPad', 32953 type: 'USHORT', 32954 value: 0 32955 }); 32956 t.fields = t.fields.concat(startCounts); 32957 t.fields = t.fields.concat(idDeltas); 32958 t.fields = t.fields.concat(idRangeOffsets); 32959 t.fields = t.fields.concat(glyphIds); 32960 t.cmap4Length = 14 + // Subtable header 32961 endCounts.length * 2 + 2 + // reservedPad 32962 startCounts.length * 2 + idDeltas.length * 2 + idRangeOffsets.length * 2 + glyphIds.length * 2; 32963 32964 if (!isPlan0Only) { 32965 // CMAP 12 Subtable 32966 var cmap12Length = 16 + // Subtable header 32967 cmap12Groups.length * 4; 32968 t.cmap12Offset = 12 + 2 * 2 + 4 + t.cmap4Length; 32969 t.fields = t.fields.concat([{ 32970 name: 'cmap12Format', 32971 type: 'USHORT', 32972 value: 12 32973 }, { 32974 name: 'cmap12Reserved', 32975 type: 'USHORT', 32976 value: 0 32977 }, { 32978 name: 'cmap12Length', 32979 type: 'ULONG', 32980 value: cmap12Length 32981 }, { 32982 name: 'cmap12Language', 32983 type: 'ULONG', 32984 value: 0 32985 }, { 32986 name: 'cmap12nGroups', 32987 type: 'ULONG', 32988 value: cmap12Groups.length / 3 32989 }]); 32990 t.fields = t.fields.concat(cmap12Groups); 32991 } 32992 32993 return t; 32994 } 32995 32996 var cmap = { 32997 parse: parseCmapTable, 32998 make: makeCmapTable 32999 }; // Glyph encoding 33000 33001 var cffStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', 'periodce
33001ntered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', '266 ff', 'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold']; 33002 var cffStandardEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl', 'periodce
33002ntered', '', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '', '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls']; 33003 var cffExpertEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '', 'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall']; 33004 var standardNames = ['.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis', 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis', 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodce
33004ntered', 'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar', 'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply', 'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter', 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla', 'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat']; 33005 /** 33006 * This is the encoding used for fonts created from scratch. 33007 * It loops through all glyphs and finds the appropriate unicode value. 33008 * Since it's linear time, other encodings will be faster. 33009 * @exports opentype.DefaultEncoding 33010 * @class 33011 * @constructor 33012 * @param {opentype.Font} 33013 */ 33014 33015 function DefaultEncoding(font) { 33016 this.font = font; 33017 } 33018 33019 DefaultEncoding.prototype.charToGlyphIndex = function (c) { 33020 var code = c.codePointAt(0); 33021 var glyphs = this.font.glyphs; 33022 33023 if (glyphs) { 33024 for (var i = 0; i < glyphs.length; i += 1) { 33025 var glyph = glyphs.get(i); 33026 33027 for (var j = 0; j < glyph.unicodes.length; j += 1) { 33028 if (glyph.unicodes[j] === code) { 33029 return i; 33030 } 33031 } 33032 } 33033 } 33034 33035 return null; 33036 }; 33037 /** 33038 * @exports opentype.CmapEncoding 33039 * @class 33040 * @constructor 33041 * @param {Object} cmap - a object with the cmap encoded data 33042 */ 33043 33044 33045 function CmapEncoding(cmap) { 33046 this.cmap = cmap; 33047 } 33048 /** 33049 * @param {string} c - the character 33050 * @return {number} The glyph index. 33051 */ 33052 33053 33054 CmapEncoding.prototype.charToGlyphIndex = function (c) { 33055 return this.cmap.glyphIndexMap[c.codePointAt(0)] || 0; 33056 }; 33057 /** 33058 * @exports opentype.CffEncoding 33059 * @class 33060 * @constructor 33061 * @param {string} encoding - The encoding 33062 * @param {Array} charset - The character set. 33063 */ 33064 33065 33066 function CffEncoding(encoding, charset) { 33067 this.encoding = encoding; 33068 this.charset = charset; 33069 } 33070 /** 33071 * @param {string} s - The character 33072 * @return {number} The index. 33073 */ 33074 33075 33076 CffEncoding.prototype.charToGlyphIndex = function (s) { 33077 var code = s.codePointAt(0); 33078 var charName = this.encoding[code]; 33079 return this.charset.indexOf(charName); 33080 }; 33081 /** 33082 * @exports opentype.GlyphNames 33083 * @class 33084 * @constructor 33085 * @param {Object} post 33086 */ 33087 33088 33089 function GlyphNames(post) { 33090 var this$1 = this; 33091 33092 switch (post.version) { 33093 case 1: 33094 this.names = standardNames.slice(); 33095 break; 33096 33097 case 2: 33098 this.names = new Array(post.numberOfGlyphs); 33099 33100 for (var i = 0; i < post.numberOfGlyphs; i++) { 33101 if (post.glyphNameIndex[i] < standardNames.length) { 33102 this$1.names[i] = standardNames[post.glyphNameIndex[i]]; 33103 } else { 33104 this$1.names[i] = post.names[post.glyphNameIndex[i] - standardNames.length]; 33105 } 33106 } 33107 33108 break; 33109 33110 case 2.5: 33111 this.names = new Array(post.numberOfGlyphs); 33112 33113 for (var i$1 = 0; i$1 < post.numberOfGlyphs; i$1++) { 33114 this$1.names[i$1] = standardNames[i$1 + post.glyphNameIndex[i$1]]; 33115 } 33116 33117 break; 33118 33119 case 3: 33120 this.names = []; 33121 break; 33122 33123 default: 33124 this.names = []; 33125 break; 33126 } 33127 } 33128 /** 33129 * Gets the index of a glyph by name. 33130 * @param {string} name - The glyph name 33131 * @return {number} The index 33132 */ 33133 33134 33135 GlyphNames.prototype.nameToGlyphIndex = function (name) { 33136 return this.names.indexOf(name); 33137 }; 33138 /** 33139 * @param {number} gid 33140 * @return {string} 33141 */ 33142 33143 33144 GlyphNames.prototype.glyphIndexToName = function (gid) { 33145 return this.names[gid]; 33146 }; 33147 /** 33148 * @alias opentype.addGlyphNames 33149 * @param {opentype.Font} 33150 */ 33151 33152 33153 function addGlyphNames(font) { 33154 var glyph; 33155 var glyphIndexMap = font.tables.cmap.glyphIndexMap;
33156 var charCodes = Object.keys(glyphIndexMap); 33157 33158 for (var i = 0; i < charCodes.length; i += 1) { 33159 var c = charCodes[i]; 33160 var glyphIndex = glyphIndexMap[c]; 33161 glyph = font.glyphs.get(glyphIndex); 33162 glyph.addUnicode(parseInt(c)); 33163 } 33164 33165 for (var i$1 = 0; i$1 < font.glyphs.length; i$1 += 1) { 33166 glyph = font.glyphs.get(i$1); 33167 33168 if (font.cffEncoding) { 33169 if (font.isCIDFont) { 33170 glyph.name = 'gid' + i$1; 33171 } else { 33172 glyph.name = font.cffEncoding.charset[i$1]; 33173 } 33174 } else if (font.glyphNames.names) { 33175 glyph.name = font.glyphNames.glyphIndexToName(i$1); 33176 } 33177 } 33178 } // Drawing utility functions. 33179 // Draw a line on the given context from point `x1,y1` to point `x2,y2`. 33180 33181 33182 function line(ctx, x1, y1, x2, y2) { 33183 ctx.beginPath(); 33184 ctx.moveTo(x1, y1); 33185 ctx.lineTo(x2, y2); 33186 ctx.stroke(); 33187 } 33188 33189 var draw = { 33190 line: line 33191 }; // The Glyph object 33192 // import glyf from './tables/glyf' Can't be imported here, because it's a circular dependency 33193 33194 function getPathDefinition(glyph, path) { 33195 var _path = path || new Path(); 33196 33197 return { 33198 configurable: true, 33199 get: function () { 33200 if (typeof _path === 'function') { 33201 _path = _path(); 33202 } 33203 33204 return _path; 33205 }, 33206 set: function (p) { 33207 _path = p; 33208 } 33209 }; 33210 } 33211 /** 33212 * @typedef GlyphOptions 33213 * @type Object 33214 * @property {string} [name] - The glyph name 33215 * @property {number} [unicode] 33216 * @property {Array} [unicodes] 33217 * @property {number} [xMin] 33218 * @property {number} [yMin] 33219 * @property {number} [xMax] 33220 * @property {number} [yMax] 33221 * @property {number} [advanceWidth] 33222 */ 33223 // A Glyph is an individual mark that often corresponds to a character. 33224 // Some glyphs, such as ligatures, are a combination of many characters. 33225 // Glyphs are the basic building blocks of a font. 33226 // 33227 // The `Glyph` class contains utility methods for drawing the path and its points. 33228 33229 /** 33230 * @exports opentype.Glyph 33231 * @class 33232 * @param {GlyphOptions} 33233 * @constructor 33234 */ 33235 33236 33237 function Glyph(options) { 33238 // By putting all the code on a prototype function (which is only declared once) 33239 // we reduce the memory requirements for larger fonts by some 2% 33240 this.bindConstructorValues(options); 33241 } 33242 /** 33243 * @param {GlyphOptions} 33244 */ 33245 33246 33247 Glyph.prototype.bindConstructorValues = function (options) { 33248 this.index = options.index || 0; // These three values cannot be deferred for memory optimization: 33249 33250 this.name = options.name || null; 33251 this.unicode = options.unicode || undefined; 33252 this.unicodes = options.unicodes || options.unicode !== undefined ? [options.unicode] : []; // But by binding these values only when necessary, we reduce can 33253 // the memory requirements by almost 3% for larger fonts. 33254 33255 if (options.xMin) { 33256 this.xMin = options.xMin; 33257 } 33258 33259 if (options.yMin) { 33260 this.yMin = options.yMin; 33261 } 33262 33263 if (options.xMax) { 33264 this.xMax = options.xMax; 33265 } 33266 33267 if (options.yMax) { 33268 this.yMax = options.yMax; 33269 } 33270 33271 if (options.advanceWidth) { 33272 this.advanceWidth = options.advanceWidth; 33273 } // The path for a glyph is the most memory intensive, and is bound as a value 33274 // with a getter/setter to ensure we actually do path parsing only once the 33275 // path is actually needed by anything. 33276 33277
33278 Object.defineProperty(this, 'path', getPathDefinition(this, options.path)); 33279 }; 33280 /** 33281 * @param {number} 33282 */ 33283 33284 33285 Glyph.prototype.addUnicode = function (unicode) { 33286 if (this.unicodes.length === 0) { 33287 this.unicode = unicode; 33288 } 33289 33290 this.unicodes.push(unicode); 33291 }; 33292 /** 33293 * Calculate the minimum bounding box for this glyph. 33294 * @return {opentype.BoundingBox} 33295 */ 33296 33297 33298 Glyph.prototype.getBoundingBox = function () { 33299 return this.path.getBoundingBox(); 33300 }; 33301 /** 33302 * Convert the glyph to a Path we can draw on a drawing context. 33303 * @param {number} [x=0] - Horizontal position of the beginning of the text. 33304 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 33305 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 33306 * @param {Object=} options - xScale, yScale to stretch the glyph. 33307 * @param {opentype.Font} if hinting is to be used, the font 33308 * @return {opentype.Path} 33309 */ 33310 33311 33312 Glyph.prototype.getPath = function (x, y, fontSize, options, font) { 33313 x = x !== undefined ? x : 0; 33314 y = y !== undefined ? y : 0; 33315 fontSize = fontSize !== undefined ? fontSize : 72; 33316 var commands; 33317 var hPoints; 33318 33319 if (!options) { 33320 options = {}; 33321 } 33322 33323 var xScale = options.xScale; 33324 var yScale = options.yScale; 33325 33326 if (options.hinting && font && font.hinting) { 33327 // in case of hinting, the hinting engine takes care 33328 // of scaling the points (not the path) before hinting. 33329 hPoints = this.path && font.hinting.exec(this, fontSize); // in case the hinting engine failed hPoints is undefined 33330 // and thus reverts to plain rending 33331 } 33332 33333 if (hPoints) { 33334 // Call font.hinting.getCommands instead of `glyf.getPath(hPoints).commands` to avoid a circular dependency 33335 commands = font.hinting.getCommands(hPoints); 33336 x = Math.round(x); 33337 y = Math.round(y); // TODO in case of hinting xyScaling is not yet supported 33338 33339 xScale = yScale = 1; 33340 } else { 33341 commands = this.path.commands; 33342 var scale = 1 / this.path.unitsPerEm * fontSize; 33343 33344 if (xScale === undefined) { 33345 xScale = scale; 33346 } 33347 33348 if (yScale === undefined) { 33349 yScale = scale; 33350 } 33351 } 33352 33353 var p = new Path(); 33354 33355 for (var i = 0; i < commands.length; i += 1) { 33356 var cmd = commands[i]; 33357 33358 if (cmd.type === 'M') { 33359 p.moveTo(x + cmd.x * xScale, y + -cmd.y * yScale); 33360 } else if (cmd.type === 'L') { 33361 p.lineTo(x + cmd.x * xScale, y + -cmd.y * yScale); 33362 } else if (cmd.type === 'Q') { 33363 p.quadraticCurveTo(x + cmd.x1 * xScale, y + -cmd.y1 * yScale, x + cmd.x * xScale, y + -cmd.y * yScale); 33364 } else if (cmd.type === 'C') { 33365 p.curveTo(x + cmd.x1 * xScale, y + -cmd.y1 * yScale, x + cmd.x2 * xScale, y + -cmd.y2 * yScale, x + cmd.x * xScale, y + -cmd.y * yScale); 33366 } else if (cmd.type === 'Z') { 33367 p.closePath(); 33368 } 33369 } 33370 33371 return p; 33372 }; 33373 /** 33374 * Split the glyph into contours. 33375 * This function is here for backwards compatibility, and to 33376 * provide raw access to the TrueType glyph outlines. 33377 * @return {Array} 33378 */ 33379 33380 33381 Glyph.prototype.getContours = function () { 33382 var this$1 = this; 33383 33384 if (this.points === undefined) { 33385 return []; 33386 } 33387 33388 var contours = []; 33389 var currentContour = []; 33390 33391 for (var i = 0; i < this.points.length; i += 1) { 33392 var pt = this$1.points[i]; 33393 currentContour.push(pt); 33394 33395 if (pt.lastPointOfContour) { 33396 contours.push(currentContour); 33397 currentContour = []; 33398 } 33399 } 33400 33401 check.argument(currentContour.length === 0, 'There are still points left in the current contour.'); 33402 return contours; 33403 }; 33404 /**
33405 * Calculate the xMin/yMin/xMax/yMax/lsb/rsb for a Glyph. 33406 * @return {Object} 33407 */ 33408 33409 33410 Glyph.prototype.getMetrics = function () { 33411 var commands = this.path.commands; 33412 var xCoords = []; 33413 var yCoords = []; 33414 33415 for (var i = 0; i < commands.length; i += 1) { 33416 var cmd = commands[i]; 33417 33418 if (cmd.type !== 'Z') { 33419 xCoords.push(cmd.x); 33420 yCoords.push(cmd.y); 33421 } 33422 33423 if (cmd.type === 'Q' || cmd.type === 'C') { 33424 xCoords.push(cmd.x1); 33425 yCoords.push(cmd.y1); 33426 } 33427 33428 if (cmd.type === 'C') { 33429 xCoords.push(cmd.x2); 33430 yCoords.push(cmd.y2); 33431 } 33432 } 33433 33434 var metrics = { 33435 xMin: Math.min.apply(null, xCoords), 33436 yMin: Math.min.apply(null, yCoords), 33437 xMax: Math.max.apply(null, xCoords), 33438 yMax: Math.max.apply(null, yCoords), 33439 leftSideBearing: this.leftSideBearing 33440 }; 33441 33442 if (!isFinite(metrics.xMin)) { 33443 metrics.xMin = 0; 33444 } 33445 33446 if (!isFinite(metrics.xMax)) { 33447 metrics.xMax = this.advanceWidth; 33448 } 33449 33450 if (!isFinite(metrics.yMin)) { 33451 metrics.yMin = 0; 33452 } 33453 33454 if (!isFinite(metrics.yMax)) { 33455 metrics.yMax = 0; 33456 } 33457 33458 metrics.rightSideBearing = this.advanceWidth - metrics.leftSideBearing - (metrics.xMax - metrics.xMin); 33459 return metrics; 33460 }; 33461 /** 33462 * Draw the glyph on the given context. 33463 * @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. 33464 * @param {number} [x=0] - Horizontal position of the beginning of the text. 33465 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 33466 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 33467 * @param {Object=} options - xScale, yScale to stretch the glyph. 33468 */ 33469 33470 33471 Glyph.prototype.draw = function (ctx, x, y, fontSize, options) { 33472 this.getPath(x, y, fontSize, options).draw(ctx); 33473 }; 33474 /** 33475 * Draw the points of the glyph. 33476 * On-curve points will be drawn in blue, off-curve points will be drawn in red. 33477 * @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. 33478 * @param {number} [x=0] - Horizontal position of the beginning of the text. 33479 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 33480 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 33481 */ 33482 33483 33484 Glyph.prototype.drawPoints = function (ctx, x, y, fontSize) { 33485 function drawCircles(l, x, y, scale) { 33486 var PI_SQ = Math.PI * 2; 33487 ctx.beginPath(); 33488 33489 for (var j = 0; j < l.length; j += 1) { 33490 ctx.moveTo(x + l[j].x * scale, y + l[j].y * scale); 33491 ctx.arc(x + l[j].x * scale, y + l[j].y * scale, 2, 0, PI_SQ, false); 33492 } 33493 33494 ctx.closePath(); 33495 ctx.fill(); 33496 } 33497 33498 x = x !== undefined ? x : 0; 33499 y = y !== undefined ? y : 0; 33500 fontSize = fontSize !== undefined ? fontSize : 24; 33501 var scale = 1 / this.path.unitsPerEm * fontSize; 33502 var blueCircles = []; 33503 var redCircles = []; 33504 var path = this.path; 33505 33506 for (var i = 0; i < path.commands.length; i += 1) { 33507 var cmd = path.commands[i]; 33508 33509 if (cmd.x !== undefined) { 33510 blueCircles.push({ 33511 x: cmd.x, 33512 y: -cmd.y 33513 }); 33514 } 33515 33516 if (cmd.x1 !== undefined) { 33517 redCircles.push({ 33518 x: cmd.x1, 33519 y: -cmd.y1 33520 }); 33521 } 33522 33523 if (cmd.x2 !== undefined) { 33524 redCircles.push({ 33525 x: cmd.x2, 33526 y: -cmd.y2 33527 }); 33528 } 33529 } 33530 33531 ctx.fillStyle = 'blue'; 33532 drawCircles(blueCircles, x, y, scale); 33533 ctx.fillStyle = 'red'; 33534 drawCircles(redCircles, x, y, scale); 33535 }; 33536 /** 33537 * Draw lines indicating important font measurements. 33538 * Black lines indicate the origin of the coordinate system (point 0,0). 33539 * Blue lines indicate the glyph bounding box. 33540 * Green line indicates the advance width of the glyph.
33541 * @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. 33542 * @param {number} [x=0] - Horizontal position of the beginning of the text. 33543 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 33544 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 33545 */ 33546 33547 33548 Glyph.prototype.drawMetrics = function (ctx, x, y, fontSize) { 33549 var scale; 33550 x = x !== undefined ? x : 0; 33551 y = y !== undefined ? y : 0; 33552 fontSize = fontSize !== undefined ? fontSize : 24; 33553 scale = 1 / this.path.unitsPerEm * fontSize; 33554 ctx.lineWidth = 1; // Draw the origin 33555 33556 ctx.strokeStyle = 'black'; 33557 draw.line(ctx, x, -10000, x, 10000); 33558 draw.line(ctx, -10000, y, 10000, y); // This code is here due to memory optimization: by not using 33559 // defaults in the constructor, we save a notable amount of memory. 33560 33561 var xMin = this.xMin || 0; 33562 var yMin = this.yMin || 0; 33563 var xMax = this.xMax || 0; 33564 var yMax = this.yMax || 0; 33565 var advanceWidth = this.advanceWidth || 0; // Draw the glyph box 33566 33567 ctx.strokeStyle = 'blue'; 33568 draw.line(ctx, x + xMin * scale, -10000, x + xMin * scale, 10000); 33569 draw.line(ctx, x + xMax * scale, -10000, x + xMax * scale, 10000); 33570 draw.line(ctx, -10000, y + -yMin * scale, 10000, y + -yMin * scale); 33571 draw.line(ctx, -10000, y + -yMax * scale, 10000, y + -yMax * scale); // Draw the advance width 33572 33573 ctx.strokeStyle = 'green'; 33574 draw.line(ctx, x + advanceWidth * scale, -10000, x + advanceWidth * scale, 10000); 33575 }; // The GlyphSet object 33576 // Define a property on the glyph that depends on the path being loaded. 33577 33578 33579 function defineDependentProperty(glyph, externalName, internalName) { 33580 Object.defineProperty(glyph, externalName, { 33581 get: function () { 33582 // Request the path property to make sure the path is loaded. 33583 glyph.path; // jshint ignore:line 33584 33585 return glyph[internalName]; 33586 }, 33587 set: function (newValue) { 33588 glyph[internalName] = newValue; 33589 }, 33590 enumerable: true, 33591 configurable: true 33592 }); 33593 } 33594 /** 33595 * A GlyphSet represents all glyphs available in the font, but modelled using 33596 * a deferred glyph loader, for retrieving glyphs only once they are absolutely 33597 * necessary, to keep the memory footprint down. 33598 * @exports opentype.GlyphSet 33599 * @class 33600 * @param {opentype.Font} 33601 * @param {Array} 33602 */ 33603 33604 33605 function GlyphSet(font, glyphs) { 33606 var this$1 = this; 33607 this.font = font; 33608 this.glyphs = {}; 33609 33610 if (Array.isArray(glyphs)) { 33611 for (var i = 0; i < glyphs.length; i++) { 33612 this$1.glyphs[i] = glyphs[i]; 33613 } 33614 } 33615 33616 this.length = glyphs && glyphs.length || 0; 33617 } 33618 /** 33619 * @param {number} index 33620 * @return {opentype.Glyph} 33621 */ 33622 33623 33624 GlyphSet.prototype.get = function (index) { 33625 if (typeof this.glyphs[index] === 'function') { 33626 this.glyphs[index] = this.glyphs[index](); 33627 } 33628 33629 return this.glyphs[index]; 33630 }; 33631 /** 33632 * @param {number} index 33633 * @param {Object} 33634 */ 33635 33636 33637 GlyphSet.prototype.push = function (index, loader) { 33638 this.glyphs[index] = loader; 33639 this.length++; 33640 }; 33641 /** 33642 * @alias opentype.glyphLoader 33643 * @param {opentype.Font} font 33644 * @param {number} index 33645 * @return {opentype.Glyph} 33646 */ 33647 33648 33649 function glyphLoader(font, index) { 33650 return new Glyph({ 33651 index: index, 33652 font: font 33653 }); 33654 } 33655 /** 33656 * Generate a stub glyph that can be filled with all metadata *except* 33657 * the "points" and "path" properties, which must be loaded only once 33658 * the glyph's path is actually requested for text shaping. 33659 * @alias opentype.ttfGlyphLoader 33660 * @param {opentype.Font} font 33661 * @param {number} index 33662 * @param {Function} parseGlyph 33663 * @param {Object} data 33664 * @param {number} position 33665 * @param {Function} buildPath 33666 * @return {opentype.Glyph} 33667 */ 33668 33669 33670 function ttfGlyphLoader(font, index, parseGlyph, data, position, buildPath) { 33671 return function () { 33672 var glyph = new Glyph({ 33673 index: index, 33674 font: font 33675 }); 33676 33677 glyph.path = function () { 33678 parseGlyph(glyph, data, position); 33679 var path = buildPath(font.glyphs, glyph); 33680 path.unitsPerEm = font.unitsPerEm; 33681 return path; 33682 }; 33683
33684 defineDependentProperty(glyph, 'xMin', '_xMin'); 33685 defineDependentProperty(glyph, 'xMax', '_xMax'); 33686 defineDependentProperty(glyph, 'yMin', '_yMin'); 33687 defineDependentProperty(glyph, 'yMax', '_yMax'); 33688 return glyph; 33689 }; 33690 } 33691 /** 33692 * @alias opentype.cffGlyphLoader 33693 * @param {opentype.Font} font 33694 * @param {number} index 33695 * @param {Function} parseCFFCharstring 33696 * @param {string} charstring 33697 * @return {opentype.Glyph} 33698 */ 33699 33700 33701 function cffGlyphLoader(font, index, parseCFFCharstring, charstring) { 33702 return function () { 33703 var glyph = new Glyph({ 33704 index: index, 33705 font: font 33706 }); 33707 33708 glyph.path = function () { 33709 var path = parseCFFCharstring(font, glyph, charstring); 33710 path.unitsPerEm = font.unitsPerEm; 33711 return path; 33712 }; 33713 33714 return glyph; 33715 }; 33716 } 33717 33718 var glyphset = { 33719 GlyphSet: GlyphSet, 33720 glyphLoader: glyphLoader, 33721 ttfGlyphLoader: ttfGlyphLoader, 33722 cffGlyphLoader: cffGlyphLoader 33723 }; // The `CFF` table contains the glyph outlines in PostScript format. 33724 // Custom equals function that can also check lists. 33725 33726 function equals(a, b) { 33727 if (a === b) { 33728 return true; 33729 } else if (Array.isArray(a) && Array.isArray(b)) { 33730 if (a.length !== b.length) { 33731 return false; 33732 } 33733 33734 for (var i = 0; i < a.length; i += 1) { 33735 if (!equals(a[i], b[i])) { 33736 return false; 33737 } 33738 } 33739 33740 return true; 33741 } else { 33742 return false; 33743 } 33744 } // Subroutines are encoded using the negative half of the number space. 33745 // See type 2 chapter 4.7 "Subroutine operators". 33746 33747 33748 function calcCFFSubroutineBias(subrs) { 33749 var bias; 33750 33751 if (subrs.length < 1240) { 33752 bias = 107; 33753 } else if (subrs.length < 33900) { 33754 bias = 1131; 33755 } else { 33756 bias = 32768; 33757 } 33758 33759 return bias; 33760 } // Parse a `CFF` INDEX array. 33761 // An index array consists of a list of offsets, then a list of objects at those offsets. 33762 33763 33764 function parseCFFIndex(data, start, conversionFn) { 33765 var offsets = []; 33766 var objects = []; 33767 var count = parse.getCard16(data, start); 33768 var objectOffset; 33769 var endOffset; 33770 33771 if (count !== 0) { 33772 var offsetSize = parse.getByte(data, start + 2); 33773 objectOffset = start + (count + 1) * offsetSize + 2; 33774 var pos = start + 3; 33775 33776 for (var i = 0; i < count + 1; i += 1) { 33777 offsets.push(parse.getOffset(data, pos, offsetSize)); 33778 pos += offsetSize; 33779 } // The total size of the index array is 4 header bytes + the value of the last offset. 33780 33781 33782 endOffset = objectOffset + offsets[count]; 33783 } else { 33784 endOffset = start + 2; 33785 } 33786 33787 for (var i$1 = 0; i$1 < offsets.length - 1; i$1 += 1) { 33788 var value = parse.getBytes(data, objectOffset + offsets[i$1], objectOffset + offsets[i$1 + 1]); 33789 33790 if (conversionFn) { 33791 value = conversionFn(value); 33792 } 33793 33794 objects.push(value); 33795 } 33796 33797 return { 33798 objects: objects, 33799 startOffset: start, 33800 endOffset: endOffset 33801 }; 33802 } // Parse a `CFF` DICT real value. 33803 33804 33805 function parseFloatOperand(parser) { 33806 var s = ''; 33807 var eof = 15; 33808 var lookup = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', null, '-']; 33809 33810 while (true) { 33811 var b = parser.parseByte(); 33812 var n1 = b >> 4; 33813 var n2 = b & 15; 33814 33815 if (n1 === eof) { 33816 break; 33817 } 33818 33819 s += lookup[n1]; 33820 33821 if (n2 === eof) { 33822 break; 33823 } 33824 33825 s += lookup[n2]; 33826 } 33827 33828 return parseFloat(s); 33829 } // Parse a `CFF` DICT operand. 33830 33831 33832 function parseOperand(parser, b0) { 33833 var b1; 33834 var b2; 33835 var b3; 33836 var b4; 33837 33838 if (b0 === 28) { 33839 b1 = parser.parseByte(); 33840 b2 = parser.parseByte(); 33841 return b1 << 8 | b2; 33842 } 33843 33844 if (b0 === 29) { 33845 b1 = parser.parseByte(); 33846 b2 = parser.parseByte(); 33847 b3 = parser.parseByte(); 33848 b4 = parser.parseByte(); 33849 return b1 << 24 | b2 << 16 | b3 << 8 | b4; 33850 } 33851 33852 if (b0 === 30) { 33853 return parseFloatOperand(parser); 33854 } 33855 33856 if (b0 >= 32 && b0 <= 246) { 33857 return b0 - 139; 33858 } 33859 33860 if (b0 >= 247 && b0 <= 250) { 33861 b1 = parser.parseByte(); 33862 return (b0 - 247) * 256 + b1 + 108; 33863 } 33864 33865 if (b0 >= 251 && b0 <= 254) { 33866 b1 = parser.parseByte(); 33867 return -(b0 - 251) * 256 - b1 - 108; 33868 } 33869 33870 throw new Error('Invalid b0 ' + b0); 33871 } // Convert the entries returned by `parseDict` to a proper dictionary. 33872 // If a value is a list of one, it is unpacked. 33873 33874 33875 function entriesToObject(entries) { 33876 var o = {}; 33877 33878 for (var i = 0; i < entries.length; i += 1) { 33879 var key = entries[i][0]; 33880 var values = entries[i][1]; 33881 var value = void 0; 33882 33883 if (values.length === 1) { 33884 value = values[0]; 33885 } else { 33886 value = values; 33887 } 33888 33889 if (o.hasOwnProperty(key) && !isNaN(o[key])) { 33890 throw new Error('Object ' + o + ' already has key ' + key); 33891 } 33892 33893 o[key] = value; 33894 } 33895 33896 return o; 33897 } // Parse a `CFF` DICT object. 33898 // A dictionary contains key-value pairs in a compact tokenized format. 33899 33900 33901 function parseCFFDict(data, start, size) { 33902 start = start !== undefined ? start : 0; 33903 var parser = new parse.Parser(data, start); 33904 var entries = []; 33905 var operands = []; 33906 size = size !== undefined ? size : data.length; 33907 33908 while (parser.relativeOffset < size) { 33909 var op = parser.parseByte(); // The first byte for each dict item distinguishes between operator (key) and operand (value). 33910 // Values <= 21 are operators. 33911 33912 if (op <= 21) { 33913 // Two-byte operators have an initial escape byte of 12. 33914 if (op === 12) { 33915 op = 1200 + parser.parseByte(); 33916 } 33917
33918 entries.push([op, operands]); 33919 operands = []; 33920 } else { 33921 // Since the operands (values) come before the operators (keys), we store all operands in a list 33922 // until we encounter an operator. 33923 operands.push(parseOperand(parser, op)); 33924 } 33925 } 33926 33927 return entriesToObject(entries); 33928 } // Given a String Index (SID), return the value of the string. 33929 // Strings below index 392 are standard CFF strings and are not encoded in the font. 33930 33931 33932 function getCFFString(strings, index) { 33933 if (index <= 390) { 33934 index = cffStandardStrings[index]; 33935 } else { 33936 index = strings[index - 391]; 33937 } 33938 33939 return index; 33940 } // Interpret a dictionary and return a new dictionary with readable keys and values for missing entries. 33941 // This function takes `meta` which is a list of objects containing `operand`, `name` and `default`. 33942 33943 33944 function interpretDict(dict, meta, strings) { 33945 var newDict = {}; 33946 var value; // Because we also want to include missing values, we start out from the meta list 33947 // and lookup values in the dict. 33948 33949 for (var i = 0; i < meta.length; i += 1) { 33950 var m = meta[i]; 33951 33952 if (Array.isArray(m.type)) { 33953 var values = []; 33954 values.length = m.type.length; 33955 33956 for (var j = 0; j < m.type.length; j++) { 33957 value = dict[m.op] !== undefined ? dict[m.op][j] : undefined; 33958 33959 if (value === undefined) { 33960 value = m.value !== undefined && m.value[j] !== undefined ? m.value[j] : null; 33961 } 33962 33963 if (m.type[j] === 'SID') { 33964 value = getCFFString(strings, value); 33965 } 33966 33967 values[j] = value; 33968 } 33969 33970 newDict[m.name] = values; 33971 } else { 33972 value = dict[m.op]; 33973 33974 if (value === undefined) { 33975 value = m.value !== undefined ? m.value : null; 33976 } 33977 33978 if (m.type === 'SID') { 33979 value = getCFFString(strings, value); 33980 } 33981 33982 newDict[m.name] = value; 33983 } 33984 } 33985 33986 return newDict; 33987 } // Parse the CFF header. 33988 33989 33990 function parseCFFHeader(data, start) { 33991 var header = {}; 33992 header.formatMajor = parse.getCard8(data, start); 33993 header.formatMinor = parse.getCard8(data, start + 1); 33994 header.size = parse.getCard8(data, start + 2); 33995 header.offsetSize = parse.getCard8(data, start + 3); 33996 header.startOffset = start; 33997 header.endOffset = start + 4; 33998 return header; 33999 } 34000 34001 var TOP_DICT_META = [{ 34002 name: 'version', 34003 op: 0, 34004 type: 'SID' 34005 }, { 34006 name: 'notice', 34007 op: 1, 34008 type: 'SID' 34009 }, { 34010 name: 'copyright', 34011 op: 1200, 34012 type: 'SID' 34013 }, { 34014 name: 'fullName', 34015 op: 2, 34016 type: 'SID' 34017 }, { 34018 name: 'familyName', 34019 op: 3, 34020 type: 'SID' 34021 }, { 34022 name: 'weight', 34023 op: 4, 34024 type: 'SID' 34025 }, { 34026 name: 'isFixedPitch', 34027 op: 1201, 34028 type: 'number', 34029 value: 0 34030 }, { 34031 name: 'italicAngle', 34032 op: 1202, 34033 type: 'number', 34034 value: 0 34035 }, { 34036 name: 'underlinePosition', 34037 op: 1203, 34038 type: 'number', 34039 value: -100 34040 }, { 34041 name: 'underlineThickness', 34042 op: 1204, 34043 type: 'number', 34044 value: 50 34045 }, { 34046 name: 'paintType', 34047 op: 1205, 34048 type: 'number', 34049 value: 0 34050 }, { 34051 name: 'charstringType', 34052 op: 1206, 34053 type: 'number', 34054 value: 2 34055 }, { 34056 name: 'fontMatrix', 34057 op: 1207, 34058 type: ['real', 'real', 'real', 'real', 'real', 'real'], 34059 value: [0.001, 0, 0, 0.001, 0, 0] 34060 }, { 34061 name: 'uniqueId', 34062 op: 13, 34063 type: 'number' 34064 }, { 34065 name: 'fontBBox', 34066 op: 5, 34067 type: ['number', 'number', 'number', 'number'], 34068 value: [0, 0, 0, 0] 34069 }, { 34070 name: 'strokeWidth', 34071 op: 1208, 34072 type: 'number', 34073 value: 0 34074 }, { 34075 name: 'xuid', 34076 op: 14, 34077 type: [], 34078 value: null 34079 }, { 34080 name: 'charset', 34081 op: 15, 34082 type: 'offset', 34083 value: 0 34084 }, { 34085 name: 'encoding', 34086 op: 16, 34087 type: 'offset', 34088 value: 0 34089 }, { 34090 name: 'charStrings', 34091 op: 17, 34092 type: 'offset', 34093 value: 0 34094 }, { 34095 name: 'private', 34096 op: 18, 34097 type: ['number', 'offset'], 34098 value: [0, 0] 34099 }, { 34100 name: 'ros', 34101 op: 1230, 34102 type: ['SID', 'SID', 'number'] 34103 }, { 34104 name: 'cidFontVersion', 34105 op: 1231, 34106 type: 'number', 34107 value: 0 34108 }, { 34109 name: 'cidFontRevision', 34110 op: 1232, 34111 type: 'number', 34112 value: 0 34113 }, { 34114 name: 'cidFontType', 34115 op: 1233, 34116 type: 'number', 34117 value: 0 34118 }, { 34119 name: 'cidCount', 34120 op: 1234, 34121 type: 'number', 34122 value: 8720 34123 }, { 34124 name: 'uidBase', 34125 op: 1235, 34126 type: 'number' 34127 }, { 34128 name: 'fdArray', 34129 op: 1236, 34130 type: 'offset' 34131 }, { 34132 name: 'fdSelect', 34133 op: 1237, 34134 type: 'offset' 34135 }, { 34136 name: 'fontName', 34137 op: 1238, 34138 type: 'SID' 34139 }]; 34140 var PRIVATE_DICT_META = [{ 34141 name: 'subrs', 34142 op: 19, 34143 type: 'offset', 34144 value: 0 34145 }, { 34146 name: 'defaultWidthX', 34147 op: 20, 34148 type: 'number', 34149 value: 0 34150 }, { 34151 name: 'nominalWidthX', 34152 op: 21, 34153 type: 'number', 34154 value: 0 34155 }]; // Parse the CFF top dictionary. A CFF table can contain multiple fonts, each with their own top dictionary. 34156 // The top dictionary contains the essential metadata for the font, together with the private dictionary. 34157 34158 function parseCFFTopDict(data, strings) { 34159 var dict = parseCFFDict(data, 0, data.byteLength); 34160 return interpretDict(dict, TOP_DICT_META, strings); 34161 } // Parse the CFF private dictionary. We don't fully parse out all the values, only the ones we need. 34162 34163 34164 function parseCFFPrivateDict(data, start, size, strings) { 34165 var dict = parseCFFDict(data, start, size); 34166 return interpretDict(dict, PRIVATE_DICT_META, strings); 34167 } // Returns a list of "Top DICT"s found using an INDEX list. 34168 // Used to read both the usual high-level Top DICTs and also the FDArray 34169 // discovered inside CID-keyed fonts. When a Top DICT has a reference to 34170 // a Private DICT that is read and saved into the Top DICT. 34171 // 34172 // In addition to the expected/optional values as outlined in TOP_DICT_META 34173 // the following values might be saved into the Top DICT. 34174 //
vendor: 24,377 bytes, lines 34175-34898
34175 // _subrs [] array of local CFF subroutines from Private DICT 34176 // _subrsBias bias value computed from number of subroutines 34177 // (see calcCFFSubroutineBias() and parseCFFCharstring()) 34178 // _defaultWidthX default widths for CFF characters 34179 // _nominalWidthX bias added to width embedded within glyph description 34180 // 34181 // _privateDict saved copy of parsed Private DICT from Top DICT 34182 34183 34184 function gatherCFFTopDicts(data, start, cffIndex, strings) { 34185 var topDictArray = []; 34186 34187 for (var iTopDict = 0; iTopDict < cffIndex.length; iTopDict += 1) { 34188 var topDictData = new DataView(new Uint8Array(cffIndex[iTopDict]).buffer); 34189 var topDict = parseCFFTopDict(topDictData, strings); 34190 topDict._subrs = []; 34191 topDict._subrsBias = 0; 34192 var privateSize = topDict.private[0]; 34193 var privateOffset = topDict.private[1]; 34194 34195 if (privateSize !== 0 && privateOffset !== 0) { 34196 var privateDict = parseCFFPrivateDict(data, privateOffset + start, privateSize, strings); 34197 topDict._defaultWidthX = privateDict.defaultWidthX; 34198 topDict._nominalWidthX = privateDict.nominalWidthX; 34199 34200 if (privateDict.subrs !== 0) { 34201 var subrOffset = privateOffset + privateDict.subrs; 34202 var subrIndex = parseCFFIndex(data, subrOffset + start); 34203 topDict._subrs = subrIndex.objects; 34204 topDict._subrsBias = calcCFFSubroutineBias(topDict._subrs); 34205 } 34206 34207 topDict._privateDict = privateDict; 34208 } 34209 34210 topDictArray.push(topDict); 34211 } 34212 34213 return topDictArray; 34214 } // Parse the CFF charset table, which contains internal names for all the glyphs. 34215 // This function will return a list of glyph names. 34216 // See Adobe TN #5176 chapter 13, "Charsets". 34217 34218 34219 function parseCFFCharset(data, start, nGlyphs, strings) { 34220 var sid; 34221 var count; 34222 var parser = new parse.Parser(data, start); // The .notdef glyph is not included, so subtract 1. 34223 34224 nGlyphs -= 1; 34225 var charset = ['.notdef']; 34226 var format = parser.parseCard8(); 34227 34228 if (format === 0) { 34229 for (var i = 0; i < nGlyphs; i += 1) { 34230 sid = parser.parseSID(); 34231 charset.push(getCFFString(strings, sid)); 34232 } 34233 } else if (format === 1) { 34234 while (charset.length <= nGlyphs) { 34235 sid = parser.parseSID(); 34236 count = parser.parseCard8(); 34237 34238 for (var i$1 = 0; i$1 <= count; i$1 += 1) { 34239 charset.push(getCFFString(strings, sid)); 34240 sid += 1; 34241 } 34242 } 34243 } else if (format === 2) { 34244 while (charset.length <= nGlyphs) { 34245 sid = parser.parseSID(); 34246 count = parser.parseCard16(); 34247 34248 for (var i$2 = 0; i$2 <= count; i$2 += 1) { 34249 charset.push(getCFFString(strings, sid)); 34250 sid += 1; 34251 } 34252 } 34253 } else { 34254 throw new Error('Unknown charset format ' + format); 34255 } 34256 34257 return charset; 34258 } // Parse the CFF encoding data. Only one encoding can be specified per font. 34259 // See Adobe TN #5176 chapter 12, "Encodings". 34260 34261 34262 function parseCFFEncoding(data, start, charset) { 34263 var code; 34264 var enc = {}; 34265 var parser = new parse.Parser(data, start); 34266 var format = parser.parseCard8(); 34267 34268 if (format === 0) { 34269 var nCodes = parser.parseCard8(); 34270 34271 for (var i = 0; i < nCodes; i += 1) { 34272 code = parser.parseCard8(); 34273 enc[code] = i; 34274 } 34275 } else if (format === 1) { 34276 var nRanges = parser.parseCard8(); 34277 code = 1; 34278 34279 for (var i$1 = 0; i$1 < nRanges; i$1 += 1) { 34280 var first = parser.parseCard8(); 34281 var nLeft = parser.parseCard8(); 34282 34283 for (var j = first; j <= first + nLeft; j += 1) { 34284 enc[j] = code; 34285 code += 1; 34286 } 34287 } 34288 } else { 34289 throw new Error('Unknown encoding format ' + format); 34290 } 34291 34292 return new CffEncoding(enc, charset); 34293 } // Take in charstring code and return a Glyph object. 34294 // The encoding is described in the Type 2 Charstring Format 34295 // https://www.microsoft.com/typography/OTSPEC/charstr2.htm 34296 34297 34298 function parseCFFCharstring(font, glyph, code) { 34299 var c1x; 34300 var c1y; 34301 var c2x; 34302 var c2y; 34303 var p = new Path(); 34304 var stack = []; 34305 var nStems = 0; 34306 var haveWidth = false; 34307 var open = false; 34308 var x = 0; 34309 var y = 0; 34310 var subrs; 34311 var subrsBias; 34312 var defaultWidthX; 34313 var nominalWidthX; 34314 34315 if (font.isCIDFont) { 34316 var fdIndex = font.tables.cff.topDict._fdSelect[glyph.index]; 34317 var fdDict = font.tables.cff.topDict._fdArray[fdIndex]; 34318 subrs = fdDict._subrs; 34319 subrsBias = fdDict._subrsBias; 34320 defaultWidthX = fdDict._defaultWidthX; 34321 nominalWidthX = fdDict._nominalWidthX; 34322 } else { 34323 subrs = font.tables.cff.topDict._subrs; 34324 subrsBias = font.tables.cff.topDict._subrsBias; 34325 defaultWidthX = font.tables.cff.topDict._defaultWidthX; 34326 nominalWidthX = font.tables.cff.topDict._nominalWidthX; 34327 } 34328 34329 var width = defaultWidthX; 34330 34331 function newContour(x, y) { 34332 if (open) { 34333 p.closePath(); 34334 } 34335 34336 p.moveTo(x, y); 34337 open = true; 34338 } 34339 34340 function parseStems() { 34341 var hasWidthArg; // The number of stem operators on the stack is always even. 34342 // If the value is uneven, that means a width is specified. 34343 34344 hasWidthArg = stack.length % 2 !== 0; 34345 34346 if (hasWidthArg && !haveWidth) { 34347 width = stack.shift() + nominalWidthX; 34348 } 34349 34350 nStems += stack.length >> 1; 34351 stack.length = 0; 34352 haveWidth = true; 34353 } 34354 34355 function parse$$1(code) { 34356 var b1; 34357 var b2; 34358 var b3; 34359 var b4; 34360 var codeIndex; 34361 var subrCode; 34362 var jpx; 34363 var jpy; 34364 var c3x; 34365 var c3y; 34366 var c4x; 34367 var c4y; 34368 var i = 0; 34369 34370 while (i < code.length) { 34371 var v = code[i]; 34372 i += 1; 34373 34374 switch (v) { 34375 case 1: 34376 // hstem 34377 parseStems(); 34378 break; 34379 34380 case 3: 34381 // vstem 34382 parseStems(); 34383 break; 34384 34385 case 4: 34386 // vmoveto 34387 if (stack.length > 1 && !haveWidth) { 34388 width = stack.shift() + nominalWidthX; 34389 haveWidth = true; 34390 } 34391 34392 y += stack.pop(); 34393 newContour(x, y); 34394 break; 34395 34396 case 5: 34397 // rlineto 34398 while (stack.length > 0) { 34399 x += stack.shift(); 34400 y += stack.shift(); 34401 p.lineTo(x, y); 34402 } 34403 34404 break; 34405 34406 case 6: 34407 // hlineto 34408 while (stack.length > 0) { 34409 x += stack.shift(); 34410 p.lineTo(x, y); 34411 34412 if (stack.length === 0) { 34413 break; 34414 } 34415 34416 y += stack.shift(); 34417 p.lineTo(x, y); 34418 } 34419 34420 break; 34421 34422 case 7: 34423 // vlineto 34424 while (stack.length > 0) { 34425 y += stack.shift(); 34426 p.lineTo(x, y); 34427 34428 if (stack.length === 0) { 34429 break; 34430 } 34431 34432 x += stack.shift(); 34433 p.lineTo(x, y); 34434 } 34435 34436 break; 34437 34438 case 8: 34439 // rrcurveto 34440 while (stack.length > 0) { 34441 c1x = x + stack.shift(); 34442 c1y = y + stack.shift(); 34443 c2x = c1x + stack.shift(); 34444 c2y = c1y + stack.shift(); 34445 x = c2x + stack.shift(); 34446 y = c2y + stack.shift(); 34447 p.curveTo(c1x, c1y, c2x, c2y, x, y); 34448 } 34449 34450 break; 34451 34452 case 10: 34453 // callsubr 34454 codeIndex = stack.pop() + subrsBias; 34455 subrCode = subrs[codeIndex]; 34456 34457 if (subrCode) { 34458 parse$$1(subrCode); 34459 } 34460 34461 break; 34462 34463 case 11: 34464 // return 34465 return; 34466 34467 case 12: 34468 // flex operators 34469 v = code[i]; 34470 i += 1; 34471 34472 switch (v) { 34473 case 35: 34474 // flex 34475 // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd flex (12 35) |- 34476 c1x = x + stack.shift(); // dx1 34477 34478 c1y = y + stack.shift(); // dy1 34479 34480 c2x = c1x + stack.shift(); // dx2 34481 34482 c2y = c1y + stack.shift(); // dy2 34483 34484 jpx = c2x + stack.shift(); // dx3 34485 34486 jpy = c2y + stack.shift(); // dy3 34487 34488 c3x = jpx + stack.shift(); // dx4 34489 34490 c3y = jpy + stack.shift(); // dy4 34491 34492 c4x = c3x + stack.shift(); // dx5 34493 34494 c4y = c3y + stack.shift(); // dy5 34495 34496 x = c4x + stack.shift(); // dx6 34497 34498 y = c4y + stack.shift(); // dy6 34499 34500 stack.shift(); // flex depth 34501 34502 p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); 34503 p.curveTo(c3x, c3y, c4x, c4y, x, y); 34504 break; 34505 34506 case 34: 34507 // hflex 34508 // |- dx1 dx2 dy2 dx3 dx4 dx5 dx6 hflex (12 34) |- 34509 c1x = x + stack.shift(); // dx1 34510 34511 c1y = y; // dy1 34512 34513 c2x = c1x + stack.shift(); // dx2 34514 34515 c2y = c1y + stack.shift(); // dy2 34516 34517 jpx = c2x + stack.shift(); // dx3 34518 34519 jpy = c2y; // dy3 34520 34521 c3x = jpx + stack.shift(); // dx4 34522 34523 c3y = c2y; // dy4 34524 34525 c4x = c3x + stack.shift(); // dx5 34526 34527 c4y = y; // dy5 34528 34529 x = c4x + stack.shift(); // dx6 34530 34531 p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); 34532 p.curveTo(c3x, c3y, c4x, c4y, x, y); 34533 break; 34534 34535 case 36: 34536 // hflex1 34537 // |- dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6 hflex1 (12 36) |- 34538 c1x = x + stack.shift(); // dx1 34539 34540 c1y = y + stack.shift(); // dy1 34541 34542 c2x = c1x + stack.shift(); // dx2 34543 34544 c2y = c1y + stack.shift(); // dy2 34545 34546 jpx = c2x + stack.shift(); // dx3 34547 34548 jpy = c2y; // dy3 34549 34550 c3x = jpx + stack.shift(); // dx4 34551 34552 c3y = c2y; // dy4 34553 34554 c4x = c3x + stack.shift(); // dx5 34555 34556 c4y = c3y + stack.shift(); // dy5 34557 34558 x = c4x + stack.shift(); // dx6 34559 34560 p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); 34561 p.curveTo(c3x, c3y, c4x, c4y, x, y); 34562 break; 34563 34564 case 37: 34565 // flex1 34566 // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6 flex1 (12 37) |- 34567 c1x = x + stack.shift(); // dx1 34568 34569 c1y = y + stack.shift(); // dy1 34570 34571 c2x = c1x + stack.shift(); // dx2 34572 34573 c2y = c1y + stack.shift(); // dy2 34574 34575 jpx = c2x + stack.shift(); // dx3 34576 34577 jpy = c2y + stack.shift(); // dy3 34578 34579 c3x = jpx + stack.shift(); // dx4 34580 34581 c3y = jpy + stack.shift(); // dy4 34582 34583 c4x = c3x + stack.shift(); // dx5 34584 34585 c4y = c3y + stack.shift(); // dy5 34586 34587 if (Math.abs(c4x - x) > Math.abs(c4y - y)) { 34588 x = c4x + stack.shift(); 34589 } else { 34590 y = c4y + stack.shift(); 34591 } 34592 34593 p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); 34594 p.curveTo(c3x, c3y, c4x, c4y, x, y); 34595 break; 34596 34597 default: 34598 console.log('Glyph ' + glyph.index + ': unknown operator ' + 1200 + v); 34599 stack.length = 0; 34600 } 34601 34602 break; 34603 34604 case 14: 34605 // endchar 34606 if (stack.length > 0 && !haveWidth) { 34607 width = stack.shift() + nominalWidthX; 34608 haveWidth = true; 34609 } 34610 34611 if (open) { 34612 p.closePath(); 34613 open = false; 34614 } 34615 34616 break; 34617 34618 case 18: 34619 // hstemhm 34620 parseStems(); 34621 break; 34622 34623 case 19: // hintmask 34624 34625 case 20: 34626 // cntrmask 34627 parseStems(); 34628 i += nStems + 7 >> 3; 34629 break; 34630 34631 case 21: 34632 // rmoveto 34633 if (stack.length > 2 && !haveWidth) { 34634 width = stack.shift() + nominalWidthX; 34635 haveWidth = true; 34636 } 34637 34638 y += stack.pop(); 34639 x += stack.pop(); 34640 newContour(x, y); 34641 break; 34642 34643 case 22: 34644 // hmoveto 34645 if (stack.length > 1 && !haveWidth) { 34646 width = stack.shift() + nominalWidthX; 34647 haveWidth = true; 34648 } 34649 34650 x += stack.pop(); 34651 newContour(x, y); 34652 break; 34653 34654 case 23: 34655 // vstemhm 34656 parseStems(); 34657 break; 34658 34659 case 24: 34660 // rcurveline 34661 while (stack.length > 2) { 34662 c1x = x + stack.shift(); 34663 c1y = y + stack.shift(); 34664 c2x = c1x + stack.shift(); 34665 c2y = c1y + stack.shift(); 34666 x = c2x + stack.shift(); 34667 y = c2y + stack.shift(); 34668 p.curveTo(c1x, c1y, c2x, c2y, x, y); 34669 } 34670 34671 x += stack.shift(); 34672 y += stack.shift(); 34673 p.lineTo(x, y); 34674 break; 34675 34676 case 25: 34677 // rlinecurve 34678 while (stack.length > 6) { 34679 x += stack.shift(); 34680 y += stack.shift(); 34681 p.lineTo(x, y); 34682 } 34683 34684 c1x = x + stack.shift(); 34685 c1y = y + stack.shift(); 34686 c2x = c1x + stack.shift(); 34687 c2y = c1y + stack.shift(); 34688 x = c2x + stack.shift(); 34689 y = c2y + stack.shift(); 34690 p.curveTo(c1x, c1y, c2x, c2y, x, y); 34691 break; 34692 34693 case 26: 34694 // vvcurveto 34695 if (stack.length % 2) { 34696 x += stack.shift(); 34697 } 34698 34699 while (stack.length > 0) { 34700 c1x = x; 34701 c1y = y + stack.shift(); 34702 c2x = c1x + stack.shift(); 34703 c2y = c1y + stack.shift(); 34704 x = c2x; 34705 y = c2y + stack.shift(); 34706 p.curveTo(c1x, c1y, c2x, c2y, x, y); 34707 } 34708 34709 break; 34710 34711 case 27: 34712 // hhcurveto 34713 if (stack.length % 2) { 34714 y += stack.shift(); 34715 } 34716 34717 while (stack.length > 0) { 34718 c1x = x + stack.shift(); 34719 c1y = y; 34720 c2x = c1x + stack.shift(); 34721 c2y = c1y + stack.shift(); 34722 x = c2x + stack.shift(); 34723 y = c2y; 34724 p.curveTo(c1x, c1y, c2x, c2y, x, y); 34725 } 34726 34727 break; 34728 34729 case 28: 34730 // shortint 34731 b1 = code[i]; 34732 b2 = code[i + 1]; 34733 stack.push((b1 << 24 | b2 << 16) >> 16); 34734 i += 2; 34735 break; 34736 34737 case 29: 34738 // callgsubr 34739 codeIndex = stack.pop() + font.gsubrsBias; 34740 subrCode = font.gsubrs[codeIndex]; 34741 34742 if (subrCode) { 34743 parse$$1(subrCode); 34744 } 34745 34746 break; 34747 34748 case 30: 34749 // vhcurveto 34750 while (stack.length > 0) { 34751 c1x = x; 34752 c1y = y + stack.shift(); 34753 c2x = c1x + stack.shift(); 34754 c2y = c1y + stack.shift(); 34755 x = c2x + stack.shift(); 34756 y = c2y + (stack.length === 1 ? stack.shift() : 0); 34757 p.curveTo(c1x, c1y, c2x, c2y, x, y); 34758 34759 if (stack.length === 0) { 34760 break; 34761 } 34762 34763 c1x = x + stack.shift(); 34764 c1y = y; 34765 c2x = c1x + stack.shift(); 34766 c2y = c1y + stack.shift(); 34767 y = c2y + stack.shift(); 34768 x = c2x + (stack.length === 1 ? stack.shift() : 0); 34769 p.curveTo(c1x, c1y, c2x, c2y, x, y); 34770 } 34771 34772 break; 34773 34774 case 31: 34775 // hvcurveto 34776 while (stack.length > 0) { 34777 c1x = x + stack.shift(); 34778 c1y = y; 34779 c2x = c1x + stack.shift(); 34780 c2y = c1y + stack.shift(); 34781 y = c2y + stack.shift(); 34782 x = c2x + (stack.length === 1 ? stack.shift() : 0); 34783 p.curveTo(c1x, c1y, c2x, c2y, x, y); 34784 34785 if (stack.length === 0) { 34786 break; 34787 } 34788 34789 c1x = x; 34790 c1y = y + stack.shift(); 34791 c2x = c1x + stack.shift(); 34792 c2y = c1y + stack.shift(); 34793 x = c2x + stack.shift(); 34794 y = c2y + (stack.length === 1 ? stack.shift() : 0); 34795 p.curveTo(c1x, c1y, c2x, c2y, x, y); 34796 } 34797 34798 break; 34799 34800 default: 34801 if (v < 32) { 34802 console.log('Glyph ' + glyph.index + ': unknown operator ' + v); 34803 } else if (v < 247) { 34804 stack.push(v - 139); 34805 } else if (v < 251) { 34806 b1 = code[i]; 34807 i += 1; 34808 stack.push((v - 247) * 256 + b1 + 108); 34809 } else if (v < 255) { 34810 b1 = code[i]; 34811 i += 1; 34812 stack.push(-(v - 251) * 256 - b1 - 108); 34813 } else { 34814 b1 = code[i]; 34815 b2 = code[i + 1]; 34816 b3 = code[i + 2]; 34817 b4 = code[i + 3]; 34818 i += 4; 34819 stack.push((b1 << 24 | b2 << 16 | b3 << 8 | b4) / 65536); 34820 } 34821 34822 } 34823 } 34824 } 34825 34826 parse$$1(code); 34827 glyph.advanceWidth = width; 34828 return p; 34829 } 34830 34831 function parseCFFFDSelect(data, start, nGlyphs, fdArrayCount) { 34832 var fdSelect = []; 34833 var fdIndex; 34834 var parser = new parse.Parser(data, start); 34835 var format = parser.parseCard8(); 34836 34837 if (format === 0) { 34838 // Simple list of nGlyphs elements 34839 for (var iGid = 0; iGid < nGlyphs; iGid++) { 34840 fdIndex = parser.parseCard8(); 34841 34842 if (fdIndex >= fdArrayCount) { 34843 throw new Error('CFF table CID Font FDSelect has bad FD index value ' + fdIndex + ' (FD count ' + fdArrayCount + ')'); 34844 } 34845 34846 fdSelect.push(fdIndex); 34847 } 34848 } else if (format === 3) { 34849 // Ranges 34850 var nRanges = parser.parseCard16(); 34851 var first = parser.parseCard16(); 34852 34853 if (first !== 0) { 34854 throw new Error('CFF Table CID Font FDSelect format 3 range has bad initial GID ' + first); 34855 } 34856 34857 var next; 34858 34859 for (var iRange = 0; iRange < nRanges; iRange++) { 34860 fdIndex = parser.parseCard8(); 34861 next = parser.parseCard16(); 34862 34863 if (fdIndex >= fdArrayCount) { 34864 throw new Error('CFF table CID Font FDSelect has bad FD index value ' + fdIndex + ' (FD count ' + fdArrayCount + ')'); 34865 } 34866 34867 if (next > nGlyphs) { 34868 throw new Error('CFF Table CID Font FDSelect format 3 range has bad GID ' + next); 34869 } 34870 34871 for (; first < next; first++) { 34872 fdSelect.push(fdIndex); 34873 } 34874 34875 first = next; 34876 } 34877 34878 if (next !== nGlyphs) { 34879 throw new Error('CFF Table CID Font FDSelect format 3 range has bad final GID ' + next); 34880 } 34881 } else { 34882 throw new Error('CFF Table CID Font FDSelect table has unsupported format ' + format); 34883 } 34884 34885 return fdSelect; 34886 } // Parse the `CFF` table, which contains the glyph outlines in PostScript format. 34887 34888 34889 function parseCFFTable(data, start, font) { 34890 font.tables.cff = {}; 34891 var header = parseCFFHeader(data, start); 34892 var nameIndex = parseCFFIndex(data, header.endOffset, parse.bytesToString); 34893 var topDictIndex = parseCFFIndex(data, nameIndex.endOffset); 34894 var stringIndex = parseCFFIndex(data, topDictIndex.endOffset, parse.bytesToString); 34895 var globalSubrIndex = parseCFFIndex(data, stringIndex.endOffset); 34896 font.gsubrs = globalSubrIndex.objects; 34897 font.gsubrsBias = calcCFFSubroutineBias(font.gsubrs); 34898 var topDictArray = gatherCFFTopDicts(data, start, topDictIndex.objects, str
34898ingIndex.objects); 34899 34900 if (topDictArray.length !== 1) { 34901 throw new Error('CFF table has too many fonts in \'FontSet\' - count of fonts NameIndex.length = ' + topDictArray.length); 34902 } 34903 34904 var topDict = topDictArray[0]; 34905 font.tables.cff.topDict = topDict; 34906 34907 if (topDict._privateDict) { 34908 font.defaultWidthX = topDict._privateDict.defaultWidthX; 34909 font.nominalWidthX = topDict._privateDict.nominalWidthX; 34910 } 34911 34912 if (topDict.ros[0] !== undefined && topDict.ros[1] !== undefined) { 34913 font.isCIDFont = true; 34914 } 34915 34916 if (font.isCIDFont) { 34917 var fdArrayOffset = topDict.fdArray; 34918 var fdSelectOffset = topDict.fdSelect; 34919 34920 if (fdArrayOffset === 0 || fdSelectOffset === 0) { 34921 throw new Error('Font is marked as a CID font, but FDArray and/or FDSelect information is missing'); 34922 } 34923 34924 fdArrayOffset += start; 34925 var fdArrayIndex = parseCFFIndex(data, fdArrayOffset); 34926 var fdArray = gatherCFFTopDicts(data, start, fdArrayIndex.objects, stringIndex.objects); 34927 topDict._fdArray = fdArray; 34928 fdSelectOffset += start; 34929 topDict._fdSelect = parseCFFFDSelect(data, fdSelectOffset, font.numGlyphs, fdArray.length); 34930 } 34931 34932 var privateDictOffset = start + topDict.private[1]; 34933 var privateDict = parseCFFPrivateDict(data, privateDictOffset, topDict.private[0], stringIndex.objects); 34934 font.defaultWidthX = privateDict.defaultWidthX; 34935 font.nominalWidthX = privateDict.nominalWidthX; 34936 34937 if (privateDict.subrs !== 0) { 34938 var subrOffset = privateDictOffset + privateDict.subrs; 34939 var subrIndex = parseCFFIndex(data, subrOffset); 34940 font.subrs = subrIndex.objects; 34941 font.subrsBias = calcCFFSubroutineBias(font.subrs); 34942 } else { 34943 font.subrs = []; 34944 font.subrsBias = 0; 34945 } // Offsets in the top dict are relative to the beginning of the CFF data, so add the CFF start offset. 34946 34947 34948 var charStringsIndex = parseCFFIndex(data, start + topDict.charStrings); 34949 font.nGlyphs = charStringsIndex.objects.length; 34950 var charset = parseCFFCharset(data, start + topDict.charset, font.nGlyphs, stringIndex.objects); 34951 34952 if (topDict.encoding === 0) { 34953 // Standard encoding 34954 font.cffEncoding = new CffEncoding(cffStandardEncoding, charset); 34955 } else if (topDict.encoding === 1) { 34956 // Expert encoding 34957 font.cffEncoding = new CffEncoding(cffExpertEncoding, charset); 34958 } else { 34959 font.cffEncoding = parseCFFEncoding(data, start + topDict.encoding, charset); 34960 } // Prefer the CMAP encoding to the CFF encoding. 34961 34962 34963 font.encoding = font.encoding || font.cffEncoding; 34964 font.glyphs = new glyphset.GlyphSet(font); 34965 34966 for (var i = 0; i < font.nGlyphs; i += 1) { 34967 var charString = charStringsIndex.objects[i]; 34968 font.glyphs.push(i, glyphset.cffGlyphLoader(font, i, parseCFFCharstring, charString)); 34969 } 34970 } // Convert a string to a String ID (SID). 34971 // The list of strings is modified in place. 34972 34973 34974 function encodeString(s, strings) { 34975 var sid; // Is the string in the CFF standard strings? 34976 34977 var i = cffStandardStrings.indexOf(s); 34978 34979 if (i >= 0) { 34980 sid = i; 34981 } // Is the string already in the string index? 34982 34983 34984 i = strings.indexOf(s); 34985 34986 if (i >= 0) { 34987 sid = i + cffStandardStrings.length; 34988 } else { 34989 sid = cffStandardStrings.length + strings.length; 34990 strings.push(s); 34991 } 34992 34993 return sid; 34994 } 34995 34996 function makeHeader() { 34997 return new table.Record('Header', [{ 34998 name: 'major', 34999 type: 'Card8', 35000 value: 1 35001 }, { 35002 name: 'minor', 35003 type: 'Card8', 35004 value: 0 35005 }, { 35006 name: 'hdrSize', 35007 type: 'Card8', 35008 value: 4 35009 }, { 35010 name: 'major', 35011 type: 'Card8', 35012 value: 1 35013 }]); 35014 } 35015 35016 function makeNameIndex(fontNames) { 35017 var t = new table.Record('Name INDEX', [{ 35018 name: 'names', 35019 type: 'INDEX', 35020 value: [] 35021 }]); 35022 t.names = []; 35023 35024 for (var i = 0; i < fontNames.length; i += 1) { 35025 t.names.push({ 35026 name: 'name_' + i, 35027 type: 'NAME', 35028 value: fontNames[i] 35029 }); 35030 } 35031 35032 return t; 35033 } // Given a dictionary's metadata, create a DICT structure. 35034 35035 35036 function makeDict(meta, attrs, strings) { 35037 var m = {}; 35038 35039 for (var i = 0; i < meta.length; i += 1) { 35040 var entry = meta[i]; 35041 var value = attrs[entry.name]; 35042 35043 if (value !== undefined && !equals(value, entry.value)) { 35044 if (entry.type === 'SID') { 35045 value = encodeString(value, strings); 35046 } 35047 35048 m[entry.op] = { 35049 name: entry.name, 35050 type: entry.type, 35051 value: value 35052 }; 35053 } 35054 } 35055 35056 return m; 35057 } // The Top DICT houses the global font attributes. 35058 35059 35060 function makeTopDict(attrs, strings) { 35061 var t = new table.Record('Top DICT', [{ 35062 name: 'dict', 35063 type: 'DICT', 35064 value: {} 35065 }]); 35066 t.dict = makeDict(TOP_DICT_META, attrs, strings); 35067 return t; 35068 } 35069 35070 function makeTopDictIndex(topDict) { 35071 var t = new table.Record('Top DICT INDEX', [{ 35072 name: 'topDicts', 35073 type: 'INDEX', 35074 value: [] 35075 }]); 35076 t.topDicts = [{ 35077 name: 'topDict_0', 35078 type: 'TABLE', 35079 value: topDict 35080 }]; 35081 return t; 35082 } 35083 35084 function makeStringIndex(strings) { 35085 var t = new table.Record('String INDEX', [{ 35086 name: 'strings', 35087 type: 'INDEX', 35088 value: [] 35089 }]); 35090 t.strings = []; 35091 35092 for (var i = 0; i < strings.length; i += 1) { 35093 t.strings.push({ 35094 name: 'string_' + i, 35095 type: 'STRING', 35096 value: strings[i] 35097 }); 35098 } 35099 35100 return t; 35101 } 35102 35103 function makeGlobalSubrIndex() { 35104 // Currently we don't use subroutines. 35105 return new table.Record('Global Subr INDEX', [{ 35106 name: 'subrs', 35107 type: 'INDEX', 35108 value: [] 35109 }]); 35110 } 35111
35112 function makeCharsets(glyphNames, strings) { 35113 var t = new table.Record('Charsets', [{ 35114 name: 'format', 35115 type: 'Card8', 35116 value: 0 35117 }]); 35118 35119 for (var i = 0; i < glyphNames.length; i += 1) { 35120 var glyphName = glyphNames[i]; 35121 var glyphSID = encodeString(glyphName, strings); 35122 t.fields.push({ 35123 name: 'glyph_' + i, 35124 type: 'SID', 35125 value: glyphSID 35126 }); 35127 } 35128 35129 return t; 35130 } 35131 35132 function glyphToOps(glyph) { 35133 var ops = []; 35134 var path = glyph.path; 35135 ops.push({ 35136 name: 'width', 35137 type: 'NUMBER', 35138 value: glyph.advanceWidth 35139 }); 35140 var x = 0; 35141 var y = 0; 35142 35143 for (var i = 0; i < path.commands.length; i += 1) { 35144 var dx = void 0; 35145 var dy = void 0; 35146 var cmd = path.commands[i]; 35147 35148 if (cmd.type === 'Q') { 35149 // CFF only supports bézier curves, so convert the quad to a bézier. 35150 var _13 = 1 / 3; 35151 35152 var _23 = 2 / 3; // We're going to create a new command so we don't change the original path. 35153 35154 35155 cmd = { 35156 type: 'C', 35157 x: cmd.x, 35158 y: cmd.y, 35159 x1: _13 * x + _23 * cmd.x1, 35160 y1: _13 * y + _23 * cmd.y1, 35161 x2: _13 * cmd.x + _23 * cmd.x1, 35162 y2: _13 * cmd.y + _23 * cmd.y1 35163 }; 35164 } 35165 35166 if (cmd.type === 'M') { 35167 dx = Math.round(cmd.x - x); 35168 dy = Math.round(cmd.y - y); 35169 ops.push({ 35170 name: 'dx', 35171 type: 'NUMBER', 35172 value: dx 35173 }); 35174 ops.push({ 35175 name: 'dy', 35176 type: 'NUMBER', 35177 value: dy 35178 }); 35179 ops.push({ 35180 name: 'rmoveto', 35181 type: 'OP', 35182 value: 21 35183 }); 35184 x = Math.round(cmd.x); 35185 y = Math.round(cmd.y); 35186 } else if (cmd.type === 'L') { 35187 dx = Math.round(cmd.x - x); 35188 dy = Math.round(cmd.y - y); 35189 ops.push({ 35190 name: 'dx', 35191 type: 'NUMBER', 35192 value: dx 35193 }); 35194 ops.push({ 35195 name: 'dy', 35196 type: 'NUMBER', 35197 value: dy 35198 }); 35199 ops.push({ 35200 name: 'rlineto', 35201 type: 'OP', 35202 value: 5 35203 }); 35204 x = Math.round(cmd.x); 35205 y = Math.round(cmd.y); 35206 } else if (cmd.type === 'C') { 35207 var dx1 = Math.round(cmd.x1 - x); 35208 var dy1 = Math.round(cmd.y1 - y); 35209 var dx2 = Math.round(cmd.x2 - cmd.x1); 35210 var dy2 = Math.round(cmd.y2 - cmd.y1); 35211 dx = Math.round(cmd.x - cmd.x2); 35212 dy = Math.round(cmd.y - cmd.y2); 35213 ops.push({ 35214 name: 'dx1', 35215 type: 'NUMBER', 35216 value: dx1 35217 }); 35218 ops.push({ 35219 name: 'dy1', 35220 type: 'NUMBER', 35221 value: dy1 35222 }); 35223 ops.push({ 35224 name: 'dx2', 35225 type: 'NUMBER', 35226 value: dx2 35227 }); 35228 ops.push({ 35229 name: 'dy2', 35230 type: 'NUMBER', 35231 value: dy2 35232 }); 35233 ops.push({ 35234 name: 'dx', 35235 type: 'NUMBER', 35236 value: dx 35237 }); 35238 ops.push({ 35239 name: 'dy', 35240 type: 'NUMBER', 35241 value: dy 35242 }); 35243 ops.push({ 35244 name: 'rrcurveto', 35245 type: 'OP', 35246 value: 8 35247 }); 35248 x = Math.round(cmd.x); 35249 y = Math.round(cmd.y); 35250 } // Contours are closed automatically. 35251 35252 } 35253 35254 ops.push({ 35255 name: 'endchar', 35256 type: 'OP', 35257 value: 14 35258 }); 35259 return ops; 35260 } 35261 35262 function makeCharStringsIndex(glyphs) { 35263 var t = new table.Record('CharStrings INDEX', [{ 35264 name: 'charStrings', 35265 type: 'INDEX', 35266 value: [] 35267 }]); 35268 35269 for (var i = 0; i < glyphs.length; i += 1) { 35270 var glyph = glyphs.get(i); 35271 var ops = glyphToOps(glyph); 35272 t.charStrings.push({ 35273 name: glyph.name, 35274 type: 'CHARSTRING', 35275 value: ops 35276 }); 35277 } 35278 35279 return t; 35280 } 35281 35282 function makePrivateDict(attrs, strings) { 35283 var t = new table.Record('Private DICT', [{ 35284 name: 'dict', 35285 type: 'DICT', 35286 value: {} 35287 }]); 35288 t.dict = makeDict(PRIVATE_DICT_META, attrs, strings); 35289 return t; 35290 } 35291 35292 function makeCFFTable(glyphs, options) { 35293 var t = new table.Table('CFF ', [{ 35294 name: 'header', 35295 type: 'RECORD' 35296 }, { 35297 name: 'nameIndex', 35298 type: 'RECORD' 35299 }, { 35300 name: 'topDictIndex', 35301 type: 'RECORD' 35302 }, { 35303 name: 'stringIndex', 35304 type: 'RECORD' 35305 }, { 35306 name: 'globalSubrIndex', 35307 type: 'RECORD' 35308 }, { 35309 name: 'charsets', 35310 type: 'RECORD' 35311 }, { 35312 name: 'charStringsIndex', 35313 type: 'RECORD' 35314 }, { 35315 name: 'privateDict', 35316 type: 'RECORD' 35317 }]); 35318 var fontScale = 1 / options.unitsPerEm; // We use non-zero values for the offsets so that the DICT encodes them. 35319 // This is important because the size of the Top DICT plays a role in offset calculation, 35320 // and the size shouldn't change after we've written correct offsets. 35321 35322 var attrs = { 35323 version: options.version, 35324 fullName: options.fullName, 35325 familyName: options.familyName, 35326 weight: options.weightName, 35327 fontBBox: options.fontBBox || [0, 0, 0, 0], 35328 fontMatrix: [fontScale, 0, 0, fontScale, 0, 0], 35329 charset: 999, 35330 encoding: 0, 35331 charStrings: 999, 35332 private: [0, 999] 35333 }; 35334 var privateAttrs = {}; 35335 var glyphNames = []; 35336 var glyph; // Skip first glyph (.notdef) 35337 35338 for (var i = 1; i < glyphs.length; i += 1) { 35339 glyph = glyphs.get(i); 35340 glyphNames.push(glyph.name); 35341 } 35342 35343 var strings = []; 35344 t.header = makeHeader(); 35345 t.nameIndex = makeNameIndex([options.postScriptName]); 35346 var topDict = makeTopDict(attrs, strings); 35347 t.topDictIndex = makeTopDictIndex(topDict); 35348 t.globalSubrIndex = makeGlobalSubrIndex();
35349 t.charsets = makeCharsets(glyphNames, strings); 35350 t.charStringsIndex = makeCharStringsIndex(glyphs); 35351 t.privateDict = makePrivateDict(privateAttrs, strings); // Needs to come at the end, to encode all custom strings used in the font. 35352 35353 t.stringIndex = makeStringIndex(strings); 35354 var startOffset = t.header.sizeOf() + t.nameIndex.sizeOf() + t.topDictIndex.sizeOf() + t.stringIndex.sizeOf() + t.globalSubrIndex.sizeOf(); 35355 attrs.charset = startOffset; // We use the CFF standard encoding; proper encoding will be handled in cmap. 35356 35357 attrs.encoding = 0; 35358 attrs.charStrings = attrs.charset + t.charsets.sizeOf(); 35359 attrs.private[1] = attrs.charStrings + t.charStringsIndex.sizeOf(); // Recreate the Top DICT INDEX with the correct offsets. 35360 35361 topDict = makeTopDict(attrs, strings); 35362 t.topDictIndex = makeTopDictIndex(topDict); 35363 return t; 35364 } 35365 35366 var cff = { 35367 parse: parseCFFTable, 35368 make: makeCFFTable 35369 }; // The `head` table contains global information about the font. 35370 // Parse the header `head` table 35371 35372 function parseHeadTable(data, start) { 35373 var head = {}; 35374 var p = new parse.Parser(data, start); 35375 head.version = p.parseVersion(); 35376 head.fontRevision = Math.round(p.parseFixed() * 1000) / 1000; 35377 head.checkSumAdjustment = p.parseULong(); 35378 head.magicNumber = p.parseULong(); 35379 check.argument(head.magicNumber === 0x5F0F3CF5, 'Font header has wrong magic number.'); 35380 head.flags = p.parseUShort(); 35381 head.unitsPerEm = p.parseUShort(); 35382 head.created = p.parseLongDateTime(); 35383 head.modified = p.parseLongDateTime(); 35384 head.xMin = p.parseShort(); 35385 head.yMin = p.parseShort(); 35386 head.xMax = p.parseShort(); 35387 head.yMax = p.parseShort(); 35388 head.macStyle = p.parseUShort(); 35389 head.lowestRecPPEM = p.parseUShort(); 35390 head.fontDirectionHint = p.parseShort(); 35391 head.indexToLocFormat = p.parseShort(); 35392 head.glyphDataFormat = p.parseShort(); 35393 return head; 35394 } 35395 35396 function makeHeadTable(options) { 35397 // Apple Mac timestamp epoch is 01/01/1904 not 01/01/1970 35398 var timestamp = Math.round(new Date().getTime() / 1000) + 2082844800; 35399 var createdTimestamp = timestamp; 35400 35401 if (options.createdTimestamp) { 35402 createdTimestamp = options.createdTimestamp + 2082844800; 35403 } 35404 35405 return new table.Table('head', [{ 35406 name: 'version', 35407 type: 'FIXED', 35408 value: 0x00010000 35409 }, { 35410 name: 'fontRevision', 35411 type: 'FIXED', 35412 value: 0x00010000 35413 }, { 35414 name: 'checkSumAdjustment', 35415 type: 'ULONG', 35416 value: 0 35417 }, { 35418 name: 'magicNumber', 35419 type: 'ULONG', 35420 value: 0x5F0F3CF5 35421 }, { 35422 name: 'flags', 35423 type: 'USHORT', 35424 value: 0 35425 }, { 35426 name: 'unitsPerEm', 35427 type: 'USHORT', 35428 value: 1000 35429 }, { 35430 name: 'created', 35431 type: 'LONGDATETIME', 35432 value: createdTimestamp 35433 }, { 35434 name: 'modified', 35435 type: 'LONGDATETIME', 35436 value: timestamp 35437 }, { 35438 name: 'xMin', 35439 type: 'SHORT', 35440 value: 0 35441 }, { 35442 name: 'yMin', 35443 type: 'SHORT', 35444 value: 0 35445 }, { 35446 name: 'xMax', 35447 type: 'SHORT', 35448 value: 0 35449 }, { 35450 name: 'yMax', 35451 type: 'SHORT', 35452 value: 0 35453 }, { 35454 name: 'macStyle', 35455 type: 'USHORT', 35456 value: 0 35457 }, { 35458 name: 'lowestRecPPEM', 35459 type: 'USHORT', 35460 value: 0 35461 }, { 35462 name: 'fontDirectionHint', 35463 type: 'SHORT', 35464 value: 2 35465 }, { 35466 name: 'indexToLocFormat', 35467 type: 'SHORT', 35468 value: 0 35469 }, { 35470 name: 'glyphDataFormat', 35471 type: 'SHORT', 35472 value: 0 35473 }], options); 35474 } 35475 35476 var head = { 35477 parse: parseHeadTable, 35478 make: makeHeadTable 35479 }; // The `hhea` table contains information for horizontal layout. 35480 // Parse the horizontal header `hhea` table 35481 35482 function parseHheaTable(data, start) { 35483 var hhea = {}; 35484 var p = new parse.Parser(data, start); 35485 hhea.version = p.parseVersion(); 35486 hhea.ascender = p.parseShort(); 35487 hhea.descender = p.parseShort(); 35488 hhea.lineGap = p.parseShort(); 35489 hhea.advanceWidthMax = p.parseUShort(); 35490 hhea.minLeftSideBearing = p.parseShort(); 35491 hhea.minRightSideBearing = p.parseShort(); 35492 hhea.xMaxExtent = p.parseShort(); 35493 hhea.caretSlopeRise = p.parseShort(); 35494 hhea.caretSlopeRun = p.parseShort(); 35495 hhea.caretOffset = p.parseShort(); 35496 p.relativeOffset += 8; 35497 hhea.metricDataFormat = p.parseShort(); 35498 hhea.numberOfHMetrics = p.parseUShort(); 35499 return hhea; 35500 } 35501 35502 function makeHheaTable(options) { 35503 return new table.Table('hhea', [{ 35504 name: 'version', 35505 type: 'FIXED', 35506 value: 0x00010000 35507 }, { 35508 name: 'ascender', 35509 type: 'FWORD', 35510 value: 0 35511 }, { 35512 name: 'descender', 35513 type: 'FWORD', 35514 value: 0 35515 }, { 35516 name: 'lineGap', 35517 type: 'FWORD', 35518 value: 0 35519 }, { 35520 name: 'advanceWidthMax', 35521 type: 'UFWORD', 35522 value: 0 35523 }, { 35524 name: 'minLeftSideBearing', 35525 type: 'FWORD', 35526 value: 0 35527 }, { 35528 name: 'minRightSideBearing', 35529 type: 'FWORD', 35530 value: 0 35531 }, { 35532 name: 'xMaxExtent', 35533 type: 'FWORD', 35534 value: 0 35535 }, { 35536 name: 'caretSlopeRise', 35537 type: 'SHORT', 35538 value: 1 35539 }, { 35540 name: 'caretSlopeRun', 35541 type: 'SHORT', 35542 value: 0 35543 }, { 35544 name: 'caretOffset', 35545 type: 'SHORT', 35546 value: 0 35547 }, { 35548 name: 'reserved1', 35549 type: 'SHORT', 35550 value: 0 35551 }, { 35552 name: 'reserved2', 35553 type: 'SHORT', 35554 value: 0 35555 }, { 35556 name: 'reserved3', 35557 type: 'SHORT', 35558 value: 0 35559 }, { 35560 name: 'reserved4', 35561 type: 'SHORT', 35562 value: 0 35563 }, { 35564 name: 'metricDataFormat', 35565 type: 'SHORT', 35566 value: 0 35567 }, { 35568 name: 'numberOfHMetrics', 35569 type: 'USHORT', 35570 value: 0 35571 }], options); 35572 } 35573 35574 var hhea = { 35575 parse: parseHheaTable, 35576 make: makeHheaTable 35577 }; // The `hmtx` table contains the horizontal metrics for all glyphs. 35578 // Parse the `hmtx` table, which contains the horizontal metrics for all glyphs. 35579 // This function augments the glyph array, adding the advanceWidth and leftSideBearing to each glyph. 35580 35581 function parseHmtxTable(data, start, numMetrics, numGlyphs, glyphs) { 35582 var advanceWidth; 35583 var leftSideBearing; 35584 var p = new parse.Parser(data, start); 35585 35586 for (var i = 0; i < numGlyphs; i += 1) { 35587 // If the font is monospaced, only one entry is needed. This last entry applies to all subsequent glyphs. 35588 if (i < numMetrics) { 35589 advanceWidth = p.parseUShort(); 35590 leftSideBearing = p.parseShort(); 35591 } 35592 35593 var glyph = glyphs.get(i); 35594 glyph.advanceWidth = advanceWidth; 35595 glyph.leftSideBearing = leftSideBearing; 35596 } 35597 } 35598 35599 function makeHmtxTable(glyphs) { 35600 var t = new table.Table('hmtx', []); 35601 35602 for (var i = 0; i < glyphs.length; i += 1) { 35603 var glyph = glyphs.get(i); 35604 var advanceWidth = glyph.advanceWidth || 0; 35605 var leftSideBearing = glyph.leftSideBearing || 0; 35606 t.fields.push({ 35607 name: 'advanceWidth_' + i, 35608 type: 'USHORT', 35609 value: advanceWidth 35610 }); 35611 t.fields.push({ 35612 name: 'leftSideBearing_' + i, 35613 type: 'SHORT', 35614 value: leftSideBearing 35615 }); 35616 } 35617 35618 return t; 35619 } 35620 35621 var hmtx = { 35622 parse: parseHmtxTable, 35623 make: makeHmtxTable 35624 }; // The `ltag` table stores IETF BCP-47 language tags. It allows supporting 35625 35626 function makeLtagTable(tags) { 35627 var result = new table.Table('ltag', [{ 35628 name: 'version', 35629 type: 'ULONG', 35630 value: 1 35631 }, { 35632 name: 'flags', 35633 type: 'ULONG', 35634 value: 0 35635 }, { 35636 name: 'numTags', 35637 type: 'ULONG', 35638 value: tags.length 35639 }]); 35640 var stringPool = ''; 35641 var stringPoolOffset = 12 + tags.length * 4; 35642 35643 for (var i = 0; i < tags.length; ++i) { 35644 var pos = stringPool.indexOf(tags[i]); 35645 35646 if (pos < 0) { 35647 pos = stringPool.length;
35648 stringPool += tags[i]; 35649 } 35650 35651 result.fields.push({ 35652 name: 'offset ' + i, 35653 type: 'USHORT', 35654 value: stringPoolOffset + pos 35655 }); 35656 result.fields.push({ 35657 name: 'length ' + i, 35658 type: 'USHORT', 35659 value: tags[i].length 35660 }); 35661 } 35662 35663 result.fields.push({ 35664 name: 'stringPool', 35665 type: 'CHARARRAY', 35666 value: stringPool 35667 }); 35668 return result; 35669 } 35670 35671 function parseLtagTable(data, start) { 35672 var p = new parse.Parser(data, start); 35673 var tableVersion = p.parseULong(); 35674 check.argument(tableVersion === 1, 'Unsupported ltag table version.'); // The 'ltag' specification does not define any flags; skip the field. 35675 35676 p.skip('uLong', 1); 35677 var numTags = p.parseULong(); 35678 var tags = []; 35679 35680 for (var i = 0; i < numTags; i++) { 35681 var tag = ''; 35682 var offset = start + p.parseUShort(); 35683 var length = p.parseUShort(); 35684 35685 for (var j = offset; j < offset + length; ++j) { 35686 tag += String.fromCharCode(data.getInt8(j)); 35687 } 35688 35689 tags.push(tag); 35690 } 35691 35692 return tags; 35693 } 35694 35695 var ltag = { 35696 make: makeLtagTable, 35697 parse: parseLtagTable 35698 }; // The `maxp` table establishes the memory requirements for the font. 35699 // Parse the maximum profile `maxp` table. 35700 35701 function parseMaxpTable(data, start) { 35702 var maxp = {}; 35703 var p = new parse.Parser(data, start); 35704 maxp.version = p.parseVersion(); 35705 maxp.numGlyphs = p.parseUShort(); 35706 35707 if (maxp.version === 1.0) { 35708 maxp.maxPoints = p.parseUShort(); 35709 maxp.maxContours = p.parseUShort(); 35710 maxp.maxCompositePoints = p.parseUShort(); 35711 maxp.maxCompositeContours = p.parseUShort(); 35712 maxp.maxZones = p.parseUShort(); 35713 maxp.maxTwilightPoints = p.parseUShort(); 35714 maxp.maxStorage = p.parseUShort(); 35715 maxp.maxFunctionDefs = p.parseUShort(); 35716 maxp.maxInstructionDefs = p.parseUShort(); 35717 maxp.maxStackElements = p.parseUShort(); 35718 maxp.maxSizeOfInstructions = p.parseUShort(); 35719 maxp.maxComponentElements = p.parseUShort(); 35720 maxp.maxComponentDepth = p.parseUShort(); 35721 } 35722 35723 return maxp; 35724 } 35725 35726 function makeMaxpTable(numGlyphs) { 35727 return new table.Table('maxp', [{ 35728 name: 'version', 35729 type: 'FIXED', 35730 value: 0x00005000 35731 }, { 35732 name: 'numGlyphs', 35733 type: 'USHORT', 35734 value: numGlyphs 35735 }]); 35736 } 35737 35738 var maxp = { 35739 parse: parseMaxpTable, 35740 make: makeMaxpTable 35741 }; // The `name` naming table. 35742 // NameIDs for the name table. 35743 35744 var nameTableNames = ['copyright', // 0 35745 'fontFamily', // 1 35746 'fontSubfamily', // 2 35747 'uniqueID', // 3 35748 'fullName', // 4 35749 'version', // 5 35750 'postScriptName', // 6 35751 'trademark', // 7 35752 'manufacturer', // 8 35753 'designer', // 9 35754 'description', // 10 35755 'manufacturerURL', // 11 35756 'designerURL', // 12 35757 'license', // 13 35758 'licenseURL', // 14 35759 'reserved', // 15 35760 'preferredFamily', // 16 35761 'preferredSubfamily', // 17 35762 'compatibleFullName', // 18
35763 'sampleText', // 19 35764 'postScriptFindFontName', // 20 35765 'wwsFamily', // 21 35766 'wwsSubfamily' // 22 35767 ]; 35768 var macLanguages = { 35769 0: 'en', 35770 1: 'fr', 35771 2: 'de', 35772 3: 'it', 35773 4: 'nl', 35774 5: 'sv', 35775 6: 'es', 35776 7: 'da', 35777 8: 'pt', 35778 9: 'no', 35779 10: 'he', 35780 11: 'ja', 35781 12: 'ar', 35782 13: 'fi', 35783 14: 'el', 35784 15: 'is', 35785 16: 'mt', 35786 17: 'tr', 35787 18: 'hr', 35788 19: 'zh-Hant', 35789 20: 'ur', 35790 21: 'hi', 35791 22: 'th', 35792 23: 'ko', 35793 24: 'lt', 35794 25: 'pl', 35795 26: 'hu', 35796 27: 'es', 35797 28: 'lv', 35798 29: 'se', 35799 30: 'fo', 35800 31: 'fa', 35801 32: 'ru', 35802 33: 'zh', 35803 34: 'nl-BE', 35804 35: 'ga', 35805 36: 'sq', 35806 37: 'ro', 35807 38: 'cz', 35808 39: 'sk', 35809 40: 'si', 35810 41: 'yi', 35811 42: 'sr', 35812 43: 'mk', 35813 44: 'bg', 35814 45: 'uk', 35815 46: 'be', 35816 47: 'uz', 35817 48: 'kk', 35818 49: 'az-Cyrl', 35819 50: 'az-Arab', 35820 51: 'hy', 35821 52: 'ka', 35822 53: 'mo', 35823 54: 'ky', 35824 55: 'tg', 35825 56: 'tk', 35826 57: 'mn-CN', 35827 58: 'mn', 35828 59: 'ps', 35829 60: 'ks', 35830 61: 'ku', 35831 62: 'sd', 35832 63: 'bo', 35833 64: 'ne', 35834 65: 'sa', 35835 66: 'mr', 35836 67: 'bn', 35837 68: 'as', 35838 69: 'gu', 35839 70: 'pa', 35840 71: 'or', 35841 72: 'ml', 35842 73: 'kn', 35843 74: 'ta', 35844 75: 'te', 35845 76: 'si', 35846 77: 'my', 35847 78: 'km', 35848 79: 'lo', 35849 80: 'vi', 35850 81: 'id', 35851 82: 'tl', 35852 83: 'ms', 35853 84: 'ms-Arab', 35854 85: 'am', 35855 86: 'ti', 35856 87: 'om', 35857 88: 'so', 35858 89: 'sw', 35859 90: 'rw', 35860 91: 'rn', 35861 92: 'ny', 35862 93: 'mg', 35863 94: 'eo', 35864 128: 'cy', 35865 129: 'eu', 35866 130: 'ca', 35867 131: 'la', 35868 132: 'qu', 35869 133: 'gn', 35870 134: 'ay', 35871 135: 'tt', 35872 136: 'ug', 35873 137: 'dz', 35874 138: 'jv', 35875 139: 'su', 35876 140: 'gl', 35877 141: 'af', 35878 142: 'br', 35879 143: 'iu', 35880 144: 'gd', 35881 145: 'gv', 35882 146: 'ga', 35883 147: 'to', 35884 148: 'el-polyton', 35885 149: 'kl', 35886 150: 'az', 35887 151: 'nn' 35888 }; // MacOS language ID â MacOS script ID 35889 // 35890 // Note that the script ID is not sufficient to determine what encoding 35891 // to use in TrueType files. For some languages, MacOS used a modification 35892 // of a mainstream script. For example, an Icelandic name would be stored 35893 // with smRoman in the TrueType naming table, but the actual encoding 35894 // is a special Icelandic version of the normal Macintosh Roman encoding. 35895 // As another example, Inuktitut uses an 8-bit encoding for Canadian Aboriginal 35896 // Syllables but MacOS had run out of available script codes, so this was 35897 // done as a (pretty radical) "modification" of Ethiopic. 35898 // 35899 // http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/Readme.txt 35900 35901 var macLanguageToScript = { 35902 0: 0, 35903 // langEnglish â smRoman 35904 1: 0, 35905 // langFrench â smRoman 35906 2: 0, 35907 // langGerman â smRoman 35908 3: 0, 35909 // langItalian â smRoman 35910 4: 0, 35911 // langDutch â smRoman 35912 5: 0, 35913 // langSwedish â smRoman 35914 6: 0, 35915 // langSpanish â smRoman 35916 7: 0, 35917 // langDanish â smRoman 35918 8: 0, 35919 // langPortuguese â smRoman 35920 9: 0, 35921 // langNorwegian â smRoman 35922 10: 5, 35923 // langHebrew â smHebrew 35924 11: 1, 35925 // langJapanese â smJapanese 35926 12: 4, 35927 // langArabic â smArabic 35928 13: 0, 35929 // langFinnish â smRoman 35930 14: 6, 35931 // langGreek â smGreek 35932 15: 0, 35933 // langIcelandic â smRoman (modified) 35934 16: 0, 35935 // langMaltese â smRoman 35936 17: 0, 35937 // langTurkish â smRoman (modified) 35938 18: 0, 35939 // langCroatian â smRoman (modified) 35940 19: 2, 35941 // langTradChinese â smTradChinese 35942 20: 4, 35943 // langUrdu â smArabic 35944 21: 9, 35945 // langHindi â smDevanagari 35946 22: 21, 35947 // langThai â smThai 35948 23: 3, 35949 // langKorean â smKorean 35950 24: 29, 35951 // langLithuanian â smCentralEuroRoman 35952 25: 29, 35953 // langPolish â smCentralEuroRoman 35954 26: 29, 35955 // langHungarian â smCentralEuroRoman 35956 27: 29, 35957 // langEstonian â smCentralEuroRoman 35958 28: 29, 35959 // langLatvian â smCentralEuroRoman 35960 29: 0, 35961 // langSami â smRoman 35962 30: 0, 35963 // langFaroese â smRoman (modified) 35964 31: 4, 35965 // langFarsi â smArabic (modified) 35966 32: 7, 35967 // langRussian â smCyrillic 35968 33: 25,
35969 // langSimpChinese â smSimpChinese 35970 34: 0, 35971 // langFlemish â smRoman 35972 35: 0, 35973 // langIrishGaelic â smRoman (modified) 35974 36: 0, 35975 // langAlbanian â smRoman 35976 37: 0, 35977 // langRomanian â smRoman (modified) 35978 38: 29, 35979 // langCzech â smCentralEuroRoman 35980 39: 29, 35981 // langSlovak â smCentralEuroRoman 35982 40: 0, 35983 // langSlovenian â smRoman (modified) 35984 41: 5, 35985 // langYiddish â smHebrew 35986 42: 7, 35987 // langSerbian â smCyrillic 35988 43: 7, 35989 // langMacedonian â smCyrillic 35990 44: 7, 35991 // langBulgarian â smCyrillic 35992 45: 7, 35993 // langUkrainian â smCyrillic (modified) 35994 46: 7, 35995 // langByelorussian â smCyrillic 35996 47: 7, 35997 // langUzbek â smCyrillic 35998 48: 7, 35999 // langKazakh â smCyrillic 36000 49: 7, 36001 // langAzerbaijani â smCyrillic 36002 50: 4, 36003 // langAzerbaijanAr â smArabic 36004 51: 24, 36005 // langArmenian â smArmenian 36006 52: 23, 36007 // langGeorgian â smGeorgian 36008 53: 7, 36009 // langMoldavian â smCyrillic 36010 54: 7, 36011 // langKirghiz â smCyrillic 36012 55: 7, 36013 // langTajiki â smCyrillic 36014 56: 7, 36015 // langTurkmen â smCyrillic 36016 57: 27, 36017 // langMongolian â smMongolian 36018 58: 7, 36019 // langMongolianCyr â smCyrillic 36020 59: 4, 36021 // langPashto â smArabic 36022 60: 4, 36023 // langKurdish â smArabic 36024 61: 4, 36025 // langKashmiri â smArabic 36026 62: 4, 36027 // langSindhi â smArabic 36028 63: 26, 36029 // langTibetan â smTibetan 36030 64: 9, 36031 // langNepali â smDevanagari 36032 65: 9, 36033 // langSanskrit â smDevanagari 36034 66: 9, 36035 // langMarathi â smDevanagari 36036 67: 13, 36037 // langBengali â smBengali 36038 68: 13, 36039 // langAssamese â smBengali 36040 69: 11, 36041 // langGujarati â smGujarati 36042 70: 10, 36043 // langPunjabi â smGurmukhi 36044 71: 12, 36045 // langOriya â smOriya 36046 72: 17, 36047 // langMalayalam â smMalayalam 36048 73: 16, 36049 // langKannada â smKannada 36050 74: 14, 36051 // langTamil â smTamil 36052 75: 15, 36053 // langTelugu â smTelugu 36054 76: 18, 36055 // langSinhalese â smSinhalese 36056 77: 19, 36057 // langBurmese â smBurmese 36058 78: 20, 36059 // langKhmer â smKhmer 36060 79: 22, 36061 // langLao â smLao 36062 80: 30, 36063 // langVietnamese â smVietnamese 36064 81: 0, 36065 // langIndonesian â smRoman 36066 82: 0, 36067 // langTagalog â smRoman 36068 83: 0, 36069 // langMalayRoman â smRoman 36070 84: 4, 36071 // langMalayArabic â smArabic 36072 85: 28, 36073 // langAmharic â smEthiopic 36074 86: 28, 36075 // langTigrinya â smEthiopic 36076 87: 28, 36077 // langOromo â smEthiopic 36078 88: 0, 36079 // langSomali â smRoman 36080 89: 0, 36081 // langSwahili â smRoman 36082 90: 0, 36083 // langKinyarwanda â smRoman 36084 91: 0, 36085 // langRundi â smRoman 36086 92: 0, 36087 // langNyanja â smRoman 36088 93: 0, 36089 // langMalagasy â smRoman 36090 94: 0, 36091 // langEsperanto â smRoman 36092 128: 0, 36093 // langWelsh â smRoman (modified) 36094 129: 0, 36095 // langBasque â smRoman 36096 130: 0, 36097 // langCatalan â smRoman 36098 131: 0, 36099 // langLatin â smRoman 36100 132: 0, 36101 // langQuechua â smRoman 36102 133: 0, 36103 // langGuarani â smRoman 36104 134: 0, 36105 // langAymara â smRoman 36106 135: 7, 36107 // langTatar â smCyrillic 36108 136: 4, 36109 // langUighur â smArabic 36110 137: 26, 36111 // langDzongkha â smTibetan 36112 138: 0,
36113 // langJavaneseRom â smRoman 36114 139: 0, 36115 // langSundaneseRom â smRoman 36116 140: 0, 36117 // langGalician â smRoman 36118 141: 0, 36119 // langAfrikaans â smRoman 36120 142: 0, 36121 // langBreton â smRoman (modified) 36122 143: 28, 36123 // langInuktitut â smEthiopic (modified) 36124 144: 0, 36125 // langScottishGaelic â smRoman (modified) 36126 145: 0, 36127 // langManxGaelic â smRoman (modified) 36128 146: 0, 36129 // langIrishGaelicScript â smRoman (modified) 36130 147: 0, 36131 // langTongan â smRoman 36132 148: 6, 36133 // langGreekAncient â smRoman 36134 149: 0, 36135 // langGreenlandic â smRoman 36136 150: 0, 36137 // langAzerbaijanRoman â smRoman 36138 151: 0 // langNynorsk â smRoman 36139 36140 }; // While Microsoft indicates a region/country for all its language 36141 // IDs, we omit the region code if it's equal to the "most likely 36142 // region subtag" according to Unicode CLDR. For scripts, we omit 36143 // the subtag if it is equal to the Suppress-Script entry in the 36144 // IANA language subtag registry for IETF BCP 47. 36145 // 36146 // For example, Microsoft states that its language code 0x041A is 36147 // Croatian in Croatia. We transform this to the BCP 47 language code 'hr' 36148 // and not 'hr-HR' because Croatia is the default country for Croatian, 36149 // according to Unicode CLDR. As another example, Microsoft states 36150 // that 0x101A is Croatian (Latin) in Bosnia-Herzegovina. We transform 36151 // this to 'hr-BA' and not 'hr-Latn-BA' because Latin is the default script 36152 // for the Croatian language, according to IANA. 36153 // 36154 // http://www.unicode.org/cldr/charts/latest/supplemental/likely_subtags.html 36155 // http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry 36156 36157 var windowsLanguages = { 36158 0x0436: 'af', 36159 0x041C: 'sq', 36160 0x0484: 'gsw', 36161 0x045E: 'am', 36162 0x1401: 'ar-DZ', 36163 0x3C01: 'ar-BH', 36164 0x0C01: 'ar', 36165 0x0801: 'ar-IQ', 36166 0x2C01: 'ar-JO', 36167 0x3401: 'ar-KW', 36168 0x3001: 'ar-LB', 36169 0x1001: 'ar-LY', 36170 0x1801: 'ary', 36171 0x2001: 'ar-OM', 36172 0x4001: 'ar-QA', 36173 0x0401: 'ar-SA', 36174 0x2801: 'ar-SY', 36175 0x1C01: 'aeb', 36176 0x3801: 'ar-AE', 36177 0x2401: 'ar-YE', 36178 0x042B: 'hy', 36179 0x044D: 'as', 36180 0x082C: 'az-Cyrl', 36181 0x042C: 'az', 36182 0x046D: 'ba', 36183 0x042D: 'eu', 36184 0x0423: 'be', 36185 0x0845: 'bn', 36186 0x0445: 'bn-IN', 36187 0x201A: 'bs-Cyrl', 36188 0x141A: 'bs', 36189 0x047E: 'br', 36190 0x0402: 'bg', 36191 0x0403: 'ca', 36192 0x0C04: 'zh-HK', 36193 0x1404: 'zh-MO', 36194 0x0804: 'zh', 36195 0x1004: 'zh-SG', 36196 0x0404: 'zh-TW', 36197 0x0483: 'co', 36198 0x041A: 'hr', 36199 0x101A: 'hr-BA', 36200 0x0405: 'cs', 36201 0x0406: 'da', 36202 0x048C: 'prs', 36203 0x0465: 'dv', 36204 0x0813: 'nl-BE', 36205 0x0413: 'nl', 36206 0x0C09: 'en-AU', 36207 0x2809: 'en-BZ', 36208 0x1009: 'en-CA', 36209 0x2409: 'en-029', 36210 0x4009: 'en-IN', 36211 0x1809: 'en-IE', 36212 0x2009: 'en-JM', 36213 0x4409: 'en-MY', 36214 0x1409: 'en-NZ', 36215 0x3409: 'en-PH', 36216 0x4809: 'en-SG', 36217 0x1C09: 'en-ZA', 36218 0x2C09: 'en-TT', 36219 0x0809: 'en-GB', 36220 0x0409: 'en', 36221 0x3009: 'en-ZW', 36222 0x0425: 'et', 36223 0x0438: 'fo', 36224 0x0464: 'fil', 36225 0x040B: 'fi', 36226 0x080C: 'fr-BE', 36227 0x0C0C: 'fr-CA', 36228 0x040C: 'fr', 36229 0x140C: 'fr-LU', 36230 0x180C: 'fr-MC', 36231 0x100C: 'fr-CH', 36232 0x0462: 'fy', 36233 0x0456: 'gl', 36234 0x0437: 'ka', 36235 0x0C07: 'de-AT', 36236 0x0407: 'de', 36237 0x1407: 'de-LI', 36238 0x1007: 'de-LU', 36239 0x0807: 'de-CH', 36240 0x0408: 'el', 36241 0x046F: 'kl', 36242 0x0447: 'gu', 36243 0x0468: 'ha', 36244 0x040D: 'he', 36245 0x0439: 'hi', 36246 0x040E: 'hu', 36247 0x040F: 'is', 36248 0x0470: 'ig', 36249 0x0421: 'id', 36250 0x045D: 'iu', 36251 0x085D: 'iu-Latn', 36252 0x083C: 'ga', 36253 0x0434: 'xh', 36254 0x0435: 'zu', 36255 0x0410: 'it', 36256 0x0810: 'it-CH', 36257 0x0411: 'ja', 36258 0x044B: 'kn', 36259 0x043F: 'kk',
36260 0x0453: 'km', 36261 0x0486: 'quc', 36262 0x0487: 'rw', 36263 0x0441: 'sw', 36264 0x0457: 'kok', 36265 0x0412: 'ko', 36266 0x0440: 'ky', 36267 0x0454: 'lo', 36268 0x0426: 'lv', 36269 0x0427: 'lt', 36270 0x082E: 'dsb', 36271 0x046E: 'lb', 36272 0x042F: 'mk', 36273 0x083E: 'ms-BN', 36274 0x043E: 'ms', 36275 0x044C: 'ml', 36276 0x043A: 'mt', 36277 0x0481: 'mi', 36278 0x047A: 'arn', 36279 0x044E: 'mr', 36280 0x047C: 'moh', 36281 0x0450: 'mn', 36282 0x0850: 'mn-CN', 36283 0x0461: 'ne', 36284 0x0414: 'nb', 36285 0x0814: 'nn', 36286 0x0482: 'oc', 36287 0x0448: 'or', 36288 0x0463: 'ps', 36289 0x0415: 'pl', 36290 0x0416: 'pt', 36291 0x0816: 'pt-PT', 36292 0x0446: 'pa', 36293 0x046B: 'qu-BO', 36294 0x086B: 'qu-EC', 36295 0x0C6B: 'qu', 36296 0x0418: 'ro', 36297 0x0417: 'rm', 36298 0x0419: 'ru', 36299 0x243B: 'smn', 36300 0x103B: 'smj-NO', 36301 0x143B: 'smj', 36302 0x0C3B: 'se-FI', 36303 0x043B: 'se', 36304 0x083B: 'se-SE', 36305 0x203B: 'sms', 36306 0x183B: 'sma-NO', 36307 0x1C3B: 'sms', 36308 0x044F: 'sa', 36309 0x1C1A: 'sr-Cyrl-BA', 36310 0x0C1A: 'sr', 36311 0x181A: 'sr-Latn-BA', 36312 0x081A: 'sr-Latn', 36313 0x046C: 'nso', 36314 0x0432: 'tn', 36315 0x045B: 'si', 36316 0x041B: 'sk', 36317 0x0424: 'sl', 36318 0x2C0A: 'es-AR', 36319 0x400A: 'es-BO', 36320 0x340A: 'es-CL', 36321 0x240A: 'es-CO', 36322 0x140A: 'es-CR', 36323 0x1C0A: 'es-DO', 36324 0x300A: 'es-EC', 36325 0x440A: 'es-SV', 36326 0x100A: 'es-GT', 36327 0x480A: 'es-HN', 36328 0x080A: 'es-MX', 36329 0x4C0A: 'es-NI', 36330 0x180A: 'es-PA', 36331 0x3C0A: 'es-PY', 36332 0x280A: 'es-PE', 36333 0x500A: 'es-PR', 36334 // Microsoft has defined two different language codes for 36335 // âSpanish with modern sortingâ and âSpanish with traditional 36336 // sortingâ. This makes sense for collation APIs, and it would be 36337 // possible to express this in BCP 47 language tags via Unicode 36338 // extensions (eg., es-u-co-trad is Spanish with traditional 36339 // sorting). However, for storing names in fonts, the distinction 36340 // does not make sense, so we give âesâ in both cases. 36341 0x0C0A: 'es', 36342 0x040A: 'es', 36343 0x540A: 'es-US', 36344 0x380A: 'es-UY', 36345 0x200A: 'es-VE', 36346 0x081D: 'sv-FI', 36347 0x041D: 'sv', 36348 0x045A: 'syr', 36349 0x0428: 'tg', 36350 0x085F: 'tzm', 36351 0x0449: 'ta', 36352 0x0444: 'tt', 36353 0x044A: 'te', 36354 0x041E: 'th', 36355 0x0451: 'bo', 36356 0x041F: 'tr', 36357 0x0442: 'tk', 36358 0x0480: 'ug', 36359 0x0422: 'uk', 36360 0x042E: 'hsb', 36361 0x0420: 'ur', 36362 0x0843: 'uz-Cyrl', 36363 0x0443: 'uz', 36364 0x042A: 'vi', 36365 0x0452: 'cy', 36366 0x0488: 'wo', 36367 0x0485: 'sah', 36368 0x0478: 'ii', 36369 0x046A: 'yo' 36370 }; // Returns a IETF BCP 47 language code, for example 'zh-Hant' 36371 // for 'Chinese in the traditional script'. 36372 36373 function getLanguageCode(platformID, languageID, ltag) { 36374 switch (platformID) { 36375 case 0: 36376 // Unicode 36377 if (languageID === 0xFFFF) { 36378 return 'und'; 36379 } else if (ltag) { 36380 return ltag[languageID]; 36381 } 36382 36383 break; 36384 36385 case 1: 36386 // Macintosh 36387 return macLanguages[languageID]; 36388 36389 case 3:
36390 // Windows 36391 return windowsLanguages[languageID]; 36392 } 36393 36394 return undefined; 36395 } 36396 36397 var utf16 = 'utf-16'; // MacOS script ID â encoding. This table stores the default case, 36398 // which can be overridden by macLanguageEncodings. 36399 36400 var macScriptEncodings = { 36401 0: 'macintosh', 36402 // smRoman 36403 1: 'x-mac-japanese', 36404 // smJapanese 36405 2: 'x-mac-chinesetrad', 36406 // smTradChinese 36407 3: 'x-mac-korean', 36408 // smKorean 36409 6: 'x-mac-greek', 36410 // smGreek 36411 7: 'x-mac-cyrillic', 36412 // smCyrillic 36413 9: 'x-mac-devanagai', 36414 // smDevanagari 36415 10: 'x-mac-gurmukhi', 36416 // smGurmukhi 36417 11: 'x-mac-gujarati', 36418 // smGujarati 36419 12: 'x-mac-oriya', 36420 // smOriya 36421 13: 'x-mac-bengali', 36422 // smBengali 36423 14: 'x-mac-tamil', 36424 // smTamil 36425 15: 'x-mac-telugu', 36426 // smTelugu 36427 16: 'x-mac-kannada', 36428 // smKannada 36429 17: 'x-mac-malayalam', 36430 // smMalayalam 36431 18: 'x-mac-sinhalese', 36432 // smSinhalese 36433 19: 'x-mac-burmese', 36434 // smBurmese 36435 20: 'x-mac-khmer', 36436 // smKhmer 36437 21: 'x-mac-thai', 36438 // smThai 36439 22: 'x-mac-lao', 36440 // smLao 36441 23: 'x-mac-georgian', 36442 // smGeorgian 36443 24: 'x-mac-armenian', 36444 // smArmenian 36445 25: 'x-mac-chinesesimp', 36446 // smSimpChinese 36447 26: 'x-mac-tibetan', 36448 // smTibetan 36449 27: 'x-mac-mongolian', 36450 // smMongolian 36451 28: 'x-mac-ethiopic', 36452 // smEthiopic 36453 29: 'x-mac-ce', 36454 // smCentralEuroRoman 36455 30: 'x-mac-vietnamese', 36456 // smVietnamese 36457 31: 'x-mac-extarabic' // smExtArabic 36458 36459 }; // MacOS language ID â encoding. This table stores the exceptional 36460 // cases, which override macScriptEncodings. For writing MacOS naming 36461 // tables, we need to emit a MacOS script ID. Therefore, we cannot 36462 // merge macScriptEncodings into macLanguageEncodings. 36463 // 36464 // http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/Readme.txt 36465 36466 var macLanguageEncodings = { 36467 15: 'x-mac-icelandic', 36468 // langIcelandic 36469 17: 'x-mac-turkish', 36470 // langTurkish 36471 18: 'x-mac-croatian', 36472 // langCroatian 36473 24: 'x-mac-ce', 36474 // langLithuanian 36475 25: 'x-mac-ce', 36476 // langPolish 36477 26: 'x-mac-ce', 36478 // langHungarian 36479 27: 'x-mac-ce', 36480 // langEstonian 36481 28: 'x-mac-ce', 36482 // langLatvian 36483 30: 'x-mac-icelandic', 36484 // langFaroese 36485 37: 'x-mac-romanian', 36486 // langRomanian 36487 38: 'x-mac-ce', 36488 // langCzech 36489 39: 'x-mac-ce', 36490 // langSlovak 36491 40: 'x-mac-ce', 36492 // langSlovenian 36493 143: 'x-mac-inuit', 36494 // langInuktitut 36495 146: 'x-mac-gaelic' // langIrishGaelicScript 36496 36497 }; 36498 36499 function getEncoding(platformID, encodingID, languageID) { 36500 switch (platformID) { 36501 case 0: 36502 // Unicode 36503 return utf16; 36504 36505 case 1: 36506 // Apple Macintosh 36507 return macLanguageEncodings[languageID] || macScriptEncodings[encodingID]; 36508 36509 case 3: 36510 // Microsoft Windows 36511 if (encodingID === 1 || encodingID === 10) { 36512 return utf16; 36513 } 36514 36515 break; 36516 } 36517 36518 return undefined; 36519 } // Parse the naming `name` table. 36520 // FIXME: Format 1 additional fields are not supported yet. 36521 // ltag is the content of the `ltag' table, such as ['en', 'zh-Hans', 'de-CH-1904']. 36522 36523 36524 function parseNameTable(data, start, ltag) { 36525 var name = {}; 36526 var p = new parse.Parser(data, start); 36527 var format = p.parseUShort(); 36528 var count = p.parseUShort(); 36529 var stringOffset = p.offset + p.parseUShort(); 36530 36531 for (var i = 0; i < count; i++) { 36532 var platformID = p.parseUShort(); 36533 var encodingID = p.parseUShort(); 36534 var languageID = p.parseUShort(); 36535 var nameID = p.parseUShort(); 36536 var property = nameTableNames[nameID] || nameID; 36537 var byteLength = p.parseUShort(); 36538 var offset = p.parseUShort(); 36539 var language = getLanguageCode(platformID, languageID, ltag); 36540 var encoding = getEncoding(platformID, encodingID, languageID); 36541 36542 if (encoding !== undefined && language !== undefined) { 36543 var text = void 0; 36544 36545 if (encoding === utf16) { 36546 text = decode.UTF16(data, stringOffset + offset, byteLength); 36547 } else { 36548 text = decode.MACSTRING(data, stringOffset + offset, byteLength, encoding); 36549 } 36550 36551 if (text) { 36552 var translations = name[property]; 36553 36554 if (translations === undefined) { 36555 translations = name[property] = {}; 36556 } 36557 36558 translations[language] = text; 36559 } 36560 } 36561 } 36562 36563 var langTagCount = 0; 36564 36565 if (format === 1) { 36566 // FIXME: Also handle Microsoft's 'name' table 1. 36567 langTagCount = p.parseUShort(); 36568 } 36569 36570 return name; 36571 } // {23: 'foo'} â {'foo': 23} 36572 // ['bar', 'baz'] â {'bar': 0, 'baz': 1} 36573 36574 36575 function reverseDict(dict) { 36576 var result = {}; 36577 36578 for (var key in dict) { 36579 result[dict[key]] = parseInt(key); 36580 } 36581 36582 return result; 36583 } 36584 36585 function makeNameRecord(platformID, encodingID, languageID, nameID, length, offset) { 36586 return new table.Record('NameRecord', [{ 36587 name: 'platformID', 36588 type: 'USHORT', 36589 value: platformID 36590 }, { 36591 name: 'encodingID', 36592 type: 'USHORT', 36593 value: encodingID 36594 }, { 36595 name: 'languageID', 36596 type: 'USHORT', 36597 value: languageID 36598 }, { 36599 name: 'nameID', 36600 type: 'USHORT', 36601 value: nameID 36602 }, { 36603 name: 'length', 36604 type: 'USHORT', 36605 value: length 36606 }, { 36607 name: 'offset', 36608 type: 'USHORT', 36609 value: offset 36610 }]); 36611 } // Finds the position of needle in haystack, or -1 if not there. 36612 // Like String.indexOf(), but for arrays. 36613 36614 36615 function findSubArray(needle, haystack) { 36616 var needleLength = needle.length; 36617 var limit = haystack.length - needleLength + 1; 36618 36619 loop: for (var pos = 0; pos < limit; pos++) { 36620 for (; pos < limit; pos++) { 36621 for (var k = 0; k < needleLength; k++) { 36622 if (haystack[pos + k] !== needle[k]) { 36623 continue loop; 36624 } 36625 } 36626 36627 return pos; 36628 } 36629 } 36630 36631 return -1; 36632 } 36633 36634 function addStringToPool(s, pool) { 36635 var offset = findSubArray(s, pool); 36636 36637 if (offset < 0) { 36638 offset = pool.length; 36639 var i = 0; 36640 var len = s.length; 36641 36642 for (; i < len; ++i) { 36643 pool.push(s[i]); 36644 } 36645 } 36646 36647 return offset; 36648 } 36649 36650 function makeNameTable(names, ltag) { 36651 var nameID; 36652 var nameIDs = []; 36653 var namesWithNumericKeys = {}; 36654 var nameTableIds = reverseDict(nameTableNames); 36655 36656 for (var key in names) {
36657 var id = nameTableIds[key]; 36658 36659 if (id === undefined) { 36660 id = key; 36661 } 36662 36663 nameID = parseInt(id); 36664 36665 if (isNaN(nameID)) { 36666 throw new Error('Name table entry "' + key + '" does not exist, see nameTableNames for complete list.'); 36667 } 36668 36669 namesWithNumericKeys[nameID] = names[key]; 36670 nameIDs.push(nameID); 36671 } 36672 36673 var macLanguageIds = reverseDict(macLanguages); 36674 var windowsLanguageIds = reverseDict(windowsLanguages); 36675 var nameRecords = []; 36676 var stringPool = []; 36677 36678 for (var i = 0; i < nameIDs.length; i++) { 36679 nameID = nameIDs[i]; 36680 var translations = namesWithNumericKeys[nameID]; 36681 36682 for (var lang in translations) { 36683 var text = translations[lang]; // For MacOS, we try to emit the name in the form that was introduced 36684 // in the initial version of the TrueType spec (in the late 1980s). 36685 // However, this can fail for various reasons: the requested BCP 47 36686 // language code might not have an old-style Mac equivalent; 36687 // we might not have a codec for the needed character encoding; 36688 // or the name might contain characters that cannot be expressed 36689 // in the old-style Macintosh encoding. In case of failure, we emit 36690 // the name in a more modern fashion (Unicode encoding with BCP 47 36691 // language tags) that is recognized by MacOS 10.5, released in 2009. 36692 // If fonts were only read by operating systems, we could simply 36693 // emit all names in the modern form; this would be much easier. 36694 // However, there are many applications and libraries that read 36695 // 'name' tables directly, and these will usually only recognize 36696 // the ancient form (silently skipping the unrecognized names). 36697 36698 var macPlatform = 1; // Macintosh 36699 36700 var macLanguage = macLanguageIds[lang]; 36701 var macScript = macLanguageToScript[macLanguage]; 36702 var macEncoding = getEncoding(macPlatform, macScript, macLanguage); 36703 var macName = encode.MACSTRING(text, macEncoding); 36704 36705 if (macName === undefined) { 36706 macPlatform = 0; // Unicode 36707 36708 macLanguage = ltag.indexOf(lang); 36709 36710 if (macLanguage < 0) { 36711 macLanguage = ltag.length; 36712 ltag.push(lang); 36713 } 36714 36715 macScript = 4; // Unicode 2.0 and later 36716 36717 macName = encode.UTF16(text); 36718 } 36719 36720 var macNameOffset = addStringToPool(macName, stringPool); 36721 nameRecords.push(makeNameRecord(macPlatform, macScript, macLanguage, nameID, macName.length, macNameOffset)); 36722 var winLanguage = windowsLanguageIds[lang]; 36723 36724 if (winLanguage !== undefined) { 36725 var winName = encode.UTF16(text); 36726 var winNameOffset = addStringToPool(winName, stringPool); 36727 nameRecords.push(makeNameRecord(3, 1, winLanguage, nameID, winName.length, winNameOffset)); 36728 } 36729 } 36730 } 36731 36732 nameRecords.sort(function (a, b) { 36733 return a.platformID - b.platformID || a.encodingID - b.encodingID || a.languageID - b.languageID || a.nameID - b.nameID; 36734 }); 36735 var t = new table.Table('name', [{ 36736 name: 'format', 36737 type: 'USHORT', 36738 value: 0 36739 }, { 36740 name: 'count', 36741 type: 'USHORT', 36742 value: nameRecords.length 36743 }, { 36744 name: 'stringOffset', 36745 type: 'USHORT', 36746 value: 6 + nameRecords.length * 12 36747 }]); 36748 36749 for (var r = 0; r < nameRecords.length; r++) { 36750 t.fields.push({ 36751 name: 'record_' + r, 36752 type: 'RECORD', 36753 value: nameRecords[r] 36754 }); 36755 } 36756 36757 t.fields.push({ 36758 name: 'strings', 36759 type: 'LITERAL', 36760 value: stringPool 36761 }); 36762 return t; 36763 } 36764 36765 var _name = { 36766 parse: parseNameTable, 36767 make: makeNameTable 36768 }; // The `OS/2` table contains metrics required in OpenType fonts. 36769 36770 var unicodeRanges = [{ 36771 begin: 0x0000, 36772 end: 0x007F 36773 }, // Basic Latin 36774 { 36775 begin: 0x0080, 36776 end: 0x00FF 36777 }, // Latin-1 Supplement 36778 { 36779 begin: 0x0100, 36780 end: 0x017F 36781 }, // Latin Extended-A 36782 { 36783 begin: 0x0180, 36784 end: 0x024F 36785 }, // Latin Extended-B 36786 { 36787 begin: 0x0250, 36788 end: 0x02AF 36789 }, // IPA Extensions 36790 { 36791 begin: 0x02B0, 36792 end: 0x02FF 36793 }, // Spacing Modifier Letters 36794 { 36795 begin: 0x0300, 36796 end: 0x036F 36797 }, // Combining Diacritical Marks 36798 { 36799 begin: 0x0370, 36800 end: 0x03FF 36801 }, // Greek and Coptic 36802 { 36803 begin: 0x2C80, 36804 end: 0x2CFF 36805 }, // Coptic 36806 { 36807 begin: 0x0400, 36808 end: 0x04FF 36809 }, // Cyrillic 36810 { 36811 begin: 0x0530, 36812 end: 0x058F 36813 }, // Armenian 36814 { 36815 begin: 0x0590, 36816 end: 0x05FF 36817 }, // Hebrew 36818 { 36819 begin: 0xA500, 36820 end: 0xA63F 36821 }, // Vai 36822 { 36823 begin: 0x0600, 36824 end: 0x06FF 36825 }, // Arabic 36826 { 36827 begin: 0x07C0, 36828 end: 0x07FF 36829 }, // NKo 36830 { 36831 begin: 0x0900, 36832 end: 0x097F 36833 }, // Devanagari 36834 { 36835 begin: 0x0980, 36836 end: 0x09FF 36837 }, // Bengali 36838 { 36839 begin: 0x0A00, 36840 end: 0x0A7F 36841 }, // Gurmukhi 36842 { 36843 begin: 0x0A80, 36844 end: 0x0AFF 36845 }, // Gujarati 36846 { 36847 begin: 0x0B00, 36848 end: 0x0B7F 36849 }, // Oriya 36850 { 36851 begin: 0x0B80, 36852 end: 0x0BFF 36853 }, // Tamil 36854 { 36855 begin: 0x0C00, 36856 end: 0x0C7F 36857 }, // Telugu 36858 { 36859 begin: 0x0C80, 36860 end: 0x0CFF 36861 }, // Kannada 36862 { 36863 begin: 0x0D00, 36864 end: 0x0D7F 36865 }, // Malayalam 36866 { 36867 begin: 0x0E00, 36868 end: 0x0E7F 36869 }, // Thai 36870 { 36871 begin: 0x0E80, 36872 end: 0x0EFF 36873 }, // Lao 36874 { 36875 begin: 0x10A0, 36876 end: 0x10FF 36877 }, // Georgian 36878 { 36879 begin: 0x1B00, 36880 end: 0x1B7F 36881 }, // Balinese 36882 { 36883 begin: 0x1100, 36884 end: 0x11FF 36885 }, // Hangul Jamo 36886 { 36887 begin: 0x1E00, 36888 end: 0x1EFF 36889 }, // Latin Extended Additional 36890 { 36891 begin: 0x1F00, 36892 end: 0x1FFF 36893 }, // Greek Extended 36894 { 36895 begin: 0x2000, 36896 end: 0x206F 36897 }, // General Punctuation 36898 { 36899 begin: 0x2070, 36900 end: 0x209F 36901 }, // Superscripts And Subscripts 36902 { 36903 begin: 0x20A0, 36904 end: 0x20CF 36905 }, // Currency Symbol 36906 { 36907 begin: 0x20D0, 36908 end: 0x20FF 36909 }, // Combining Diacritical Marks For Symbols 36910 { 36911 begin: 0x2100, 36912 end: 0x214F 36913 }, // Letterlike Symbols 36914 { 36915 begin: 0x2150, 36916 end: 0x218F 36917 }, // Number Forms 36918 { 36919 begin: 0x2190, 36920 end: 0x21FF 36921 }, // Arrows 36922 { 36923 begin: 0x2200, 36924 end: 0x22FF 36925 }, // Mathematical Operators 36926 { 36927 begin: 0x2300, 36928 end: 0x23FF 36929 }, // Miscellaneous Technical 36930 { 36931 begin: 0x2400, 36932 end: 0x243F 36933 }, // Control Pictures 36934 { 36935 begin: 0x2440, 36936 end: 0x245F 36937 }, // Optical Character Recognition 36938 { 36939 begin: 0x2460, 36940 end: 0x24FF 36941 }, // Enclosed Alphanumerics 36942 { 36943 begin: 0x2500, 36944 end: 0x257F 36945 }, // Box Drawing 36946 { 36947 begin: 0x2580, 36948 end: 0x259F 36949 }, // Block Elements 36950 { 36951 begin: 0x25A0, 36952 end: 0x25FF 36953 }, // Geometric Shapes 36954 { 36955 begin: 0x2600, 36956 end: 0x26FF 36957 }, // Miscellaneous Symbols 36958 { 36959 begin: 0x2700, 36960 end: 0x27BF 36961 }, // Dingbats 36962 { 36963 begin: 0x3000, 36964 end: 0x303F 36965 }, // CJK Symbols And Punctuation 36966 { 36967 begin: 0x3040, 36968 end: 0x309F 36969 }, // Hiragana 36970 { 36971 begin: 0x30A0, 36972 end: 0x30FF 36973 }, // Katakana 36974 { 36975 begin: 0x3100, 36976 end: 0x312F 36977 }, // Bopomofo 36978 { 36979 begin: 0x3130, 36980 end: 0x318F 36981 }, // Hangul Compatibility Jamo 36982 { 36983 begin: 0xA840, 36984 end: 0xA87F 36985 }, // Phags-pa 36986 { 36987 begin: 0x3200, 36988 end: 0x32FF 36989 }, // Enclosed CJK Letters And Months 36990 { 36991 begin: 0x3300, 36992 end: 0x33FF 36993 }, // CJK Compatibility 36994 { 36995 begin: 0xAC00, 36996 end: 0xD7AF 36997 }, // Hangul Syllables 36998 { 36999 begin: 0xD800, 37000 end: 0xDFFF 37001 }, // Non-Plane 0 * 37002 { 37003 begin: 0x10900, 37004 end: 0x1091F 37005 }, // Phoenicia 37006 { 37007 begin: 0x4E00, 37008 end: 0x9FFF 37009 }, // CJK Unified Ideographs 37010 { 37011 begin: 0xE000,
37012 end: 0xF8FF 37013 }, // Private Use Area (plane 0) 37014 { 37015 begin: 0x31C0, 37016 end: 0x31EF 37017 }, // CJK Strokes 37018 { 37019 begin: 0xFB00, 37020 end: 0xFB4F 37021 }, // Alphabetic Presentation Forms 37022 { 37023 begin: 0xFB50, 37024 end: 0xFDFF 37025 }, // Arabic Presentation Forms-A 37026 { 37027 begin: 0xFE20, 37028 end: 0xFE2F 37029 }, // Combining Half Marks 37030 { 37031 begin: 0xFE10, 37032 end: 0xFE1F 37033 }, // Vertical Forms 37034 { 37035 begin: 0xFE50, 37036 end: 0xFE6F 37037 }, // Small Form Variants 37038 { 37039 begin: 0xFE70, 37040 end: 0xFEFF 37041 }, // Arabic Presentation Forms-B 37042 { 37043 begin: 0xFF00, 37044 end: 0xFFEF 37045 }, // Halfwidth And Fullwidth Forms 37046 { 37047 begin: 0xFFF0, 37048 end: 0xFFFF 37049 }, // Specials 37050 { 37051 begin: 0x0F00, 37052 end: 0x0FFF 37053 }, // Tibetan 37054 { 37055 begin: 0x0700, 37056 end: 0x074F 37057 }, // Syriac 37058 { 37059 begin: 0x0780, 37060 end: 0x07BF 37061 }, // Thaana 37062 { 37063 begin: 0x0D80, 37064 end: 0x0DFF 37065 }, // Sinhala 37066 { 37067 begin: 0x1000, 37068 end: 0x109F 37069 }, // Myanmar 37070 { 37071 begin: 0x1200, 37072 end: 0x137F 37073 }, // Ethiopic 37074 { 37075 begin: 0x13A0, 37076 end: 0x13FF 37077 }, // Cherokee 37078 { 37079 begin: 0x1400, 37080 end: 0x167F 37081 }, // Unified Canadian Aboriginal Syllabics 37082 { 37083 begin: 0x1680, 37084 end: 0x169F 37085 }, // Ogham 37086 { 37087 begin: 0x16A0, 37088 end: 0x16FF 37089 }, // Runic 37090 { 37091 begin: 0x1780, 37092 end: 0x17FF 37093 }, // Khmer 37094 { 37095 begin: 0x1800, 37096 end: 0x18AF 37097 }, // Mongolian 37098 { 37099 begin: 0x2800, 37100 end: 0x28FF 37101 }, // Braille Patterns 37102 { 37103 begin: 0xA000, 37104 end: 0xA48F 37105 }, // Yi Syllables 37106 { 37107 begin: 0x1700, 37108 end: 0x171F 37109 }, // Tagalog 37110 { 37111 begin: 0x10300, 37112 end: 0x1032F 37113 }, // Old Italic 37114 { 37115 begin: 0x10330, 37116 end: 0x1034F 37117 }, // Gothic 37118 { 37119 begin: 0x10400, 37120 end: 0x1044F 37121 }, // Deseret 37122 { 37123 begin: 0x1D000, 37124 end: 0x1D0FF 37125 }, // Byzantine Musical Symbols 37126 { 37127 begin: 0x1D400, 37128 end: 0x1D7FF 37129 }, // Mathematical Alphanumeric Symbols 37130 { 37131 begin: 0xFF000, 37132 end: 0xFFFFD 37133 }, // Private Use (plane 15) 37134 { 37135 begin: 0xFE00, 37136 end: 0xFE0F 37137 }, // Variation Selectors 37138 { 37139 begin: 0xE0000, 37140 end: 0xE007F 37141 }, // Tags 37142 { 37143 begin: 0x1900, 37144 end: 0x194F 37145 }, // Limbu 37146 { 37147 begin: 0x1950, 37148 end: 0x197F 37149 }, // Tai Le 37150 { 37151 begin: 0x1980, 37152 end: 0x19DF 37153 }, // New Tai Lue 37154 { 37155 begin: 0x1A00, 37156 end: 0x1A1F 37157 }, // Buginese 37158 { 37159 begin: 0x2C00, 37160 end: 0x2C5F 37161 }, // Glagolitic 37162 { 37163 begin: 0x2D30, 37164 end: 0x2D7F 37165 }, // Tifinagh 37166 { 37167 begin: 0x4DC0, 37168 end: 0x4DFF 37169 }, // Yijing Hexagram Symbols 37170 { 37171 begin: 0xA800, 37172 end: 0xA82F 37173 }, // Syloti Nagri 37174 { 37175 begin: 0x10000, 37176 end: 0x1007F 37177 }, // Linear B Syllabary 37178 { 37179 begin: 0x10140, 37180 end: 0x1018F 37181 }, // Ancient Greek Numbers 37182 { 37183 begin: 0x10380, 37184 end: 0x1039F 37185 }, // Ugaritic 37186 { 37187 begin: 0x103A0, 37188 end: 0x103DF 37189 }, // Old Persian 37190 { 37191 begin: 0x10450, 37192 end: 0x1047F 37193 }, // Shavian 37194 { 37195 begin: 0x10480, 37196 end: 0x104AF 37197 }, // Osmanya 37198 { 37199 begin: 0x10800, 37200 end: 0x1083F 37201 }, // Cypriot Syllabary 37202 { 37203 begin: 0x10A00, 37204 end: 0x10A5F 37205 }, // Kharoshthi 37206 { 37207 begin: 0x1D300, 37208 end: 0x1D35F 37209 }, // Tai Xuan Jing Symbols 37210 { 37211 begin: 0x12000, 37212 end: 0x123FF 37213 }, // Cuneiform 37214 { 37215 begin: 0x1D360, 37216 end: 0x1D37F 37217 }, // Counting Rod Numerals 37218 { 37219 begin: 0x1B80, 37220 end: 0x1BBF 37221 }, // Sundanese 37222 { 37223 begin: 0x1C00, 37224 end: 0x1C4F 37225 }, // Lepcha 37226 { 37227 begin: 0x1C50, 37228 end: 0x1C7F 37229 }, // Ol Chiki 37230 { 37231 begin: 0xA880, 37232 end: 0xA8DF 37233 }, // Saurashtra 37234 { 37235 begin: 0xA900, 37236 end: 0xA92F 37237 }, // Kayah Li 37238 { 37239 begin: 0xA930, 37240 end: 0xA95F 37241 }, // Rejang 37242 { 37243 begin: 0xAA00, 37244 end: 0xAA5F 37245 }, // Cham 37246 { 37247 begin: 0x10190, 37248 end: 0x101CF 37249 }, // Ancient Symbols 37250 { 37251 begin: 0x101D0, 37252 end: 0x101FF 37253 }, // Phaistos Disc 37254 { 37255 begin: 0x102A0, 37256 end: 0x102DF 37257 }, // Carian 37258 { 37259 begin: 0x1F030, 37260 end: 0x1F09F // Domino Tiles 37261 37262 }]; 37263 37264 function getUnicodeRange(unicode) { 37265 for (var i = 0; i < unicodeRanges.length; i += 1) { 37266 var range = unicodeRanges[i]; 37267 37268 if (unicode >= range.begin && unicode < range.end) { 37269 return i; 37270 } 37271 } 37272 37273 return -1; 37274 } // Parse the OS/2 and Windows metrics `OS/2` table 37275 37276 37277 function parseOS2Table(data, start) { 37278 var os2 = {}; 37279 var p = new parse.Parser(data, start); 37280 os2.version = p.parseUShort(); 37281 os2.xAvgCharWidth = p.parseShort(); 37282 os2.usWeightClass = p.parseUShort(); 37283 os2.usWidthClass = p.parseUShort(); 37284 os2.fsType = p.parseUShort(); 37285 os2.ySubscriptXSize = p.parseShort(); 37286 os2.ySubscriptYSize = p.parseShort(); 37287 os2.ySubscriptXOffset = p.parseShort(); 37288 os2.ySubscriptYOffset = p.parseShort(); 37289 os2.ySuperscriptXSize = p.parseShort(); 37290 os2.ySuperscriptYSize = p.parseShort(); 37291 os2.ySuperscriptXOffset = p.parseShort(); 37292 os2.ySuperscriptYOffset = p.parseShort(); 37293 os2.yStrikeoutSize = p.parseShort(); 37294 os2.yStrikeoutPosition = p.parseShort(); 37295 os2.sFamilyClass = p.parseShort(); 37296 os2.panose = []; 37297 37298 for (var i = 0; i < 10; i++) { 37299 os2.panose[i] = p.parseByte(); 37300 } 37301 37302 os2.ulUnicodeRange1 = p.parseULong(); 37303 os2.ulUnicodeRange2 = p.parseULong(); 37304 os2.ulUnicodeRange3 = p.parseULong(); 37305 os2.ulUnicodeRange4 = p.parseULong(); 37306 os2.achVendID = String.fromCharCode(p.parseByte(), p.parseByte(), p.parseByte(), p.parseByte()); 37307 os2.fsSelection = p.parseUShort(); 37308 os2.usFirstCharIndex = p.parseUShort(); 37309 os2.usLastCharIndex = p.parseUShort(); 37310 os2.sTypoAscender = p.parseShort(); 37311 os2.sTypoDescender = p.parseShort(); 37312 os2.sTypoLineGap = p.parseShort(); 37313 os2.usWinAscent = p.parseUShort(); 37314 os2.usWinDescent = p.parseUShort(); 37315
37316 if (os2.version >= 1) { 37317 os2.ulCodePageRange1 = p.parseULong(); 37318 os2.ulCodePageRange2 = p.parseULong(); 37319 } 37320 37321 if (os2.version >= 2) { 37322 os2.sxHeight = p.parseShort(); 37323 os2.sCapHeight = p.parseShort(); 37324 os2.usDefaultChar = p.parseUShort(); 37325 os2.usBreakChar = p.parseUShort(); 37326 os2.usMaxContent = p.parseUShort(); 37327 } 37328 37329 return os2; 37330 } 37331 37332 function makeOS2Table(options) { 37333 return new table.Table('OS/2', [{ 37334 name: 'version', 37335 type: 'USHORT', 37336 value: 0x0003 37337 }, { 37338 name: 'xAvgCharWidth', 37339 type: 'SHORT', 37340 value: 0 37341 }, { 37342 name: 'usWeightClass', 37343 type: 'USHORT', 37344 value: 0 37345 }, { 37346 name: 'usWidthClass', 37347 type: 'USHORT', 37348 value: 0 37349 }, { 37350 name: 'fsType', 37351 type: 'USHORT', 37352 value: 0 37353 }, { 37354 name: 'ySubscriptXSize', 37355 type: 'SHORT', 37356 value: 650 37357 }, { 37358 name: 'ySubscriptYSize', 37359 type: 'SHORT', 37360 value: 699 37361 }, { 37362 name: 'ySubscriptXOffset', 37363 type: 'SHORT', 37364 value: 0 37365 }, { 37366 name: 'ySubscriptYOffset', 37367 type: 'SHORT', 37368 value: 140 37369 }, { 37370 name: 'ySuperscriptXSize', 37371 type: 'SHORT', 37372 value: 650 37373 }, { 37374 name: 'ySuperscriptYSize', 37375 type: 'SHORT', 37376 value: 699 37377 }, { 37378 name: 'ySuperscriptXOffset', 37379 type: 'SHORT', 37380 value: 0 37381 }, { 37382 name: 'ySuperscriptYOffset', 37383 type: 'SHORT', 37384 value: 479 37385 }, { 37386 name: 'yStrikeoutSize', 37387 type: 'SHORT', 37388 value: 49 37389 }, { 37390 name: 'yStrikeoutPosition', 37391 type: 'SHORT', 37392 value: 258 37393 }, { 37394 name: 'sFamilyClass', 37395 type: 'SHORT', 37396 value: 0 37397 }, { 37398 name: 'bFamilyType', 37399 type: 'BYTE', 37400 value: 0 37401 }, { 37402 name: 'bSerifStyle', 37403 type: 'BYTE', 37404 value: 0 37405 }, { 37406 name: 'bWeight', 37407 type: 'BYTE', 37408 value: 0 37409 }, { 37410 name: 'bProportion', 37411 type: 'BYTE', 37412 value: 0 37413 }, { 37414 name: 'bContrast', 37415 type: 'BYTE', 37416 value: 0 37417 }, { 37418 name: 'bStrokeVariation', 37419 type: 'BYTE', 37420 value: 0 37421 }, { 37422 name: 'bArmStyle', 37423 type: 'BYTE', 37424 value: 0 37425 }, { 37426 name: 'bLetterform', 37427 type: 'BYTE', 37428 value: 0 37429 }, { 37430 name: 'bMidline', 37431 type: 'BYTE', 37432 value: 0 37433 }, { 37434 name: 'bXHeight', 37435 type: 'BYTE', 37436 value: 0 37437 }, { 37438 name: 'ulUnicodeRange1', 37439 type: 'ULONG', 37440 value: 0 37441 }, { 37442 name: 'ulUnicodeRange2', 37443 type: 'ULONG', 37444 value: 0 37445 }, { 37446 name: 'ulUnicodeRange3', 37447 type: 'ULONG', 37448 value: 0 37449 }, { 37450 name: 'ulUnicodeRange4', 37451 type: 'ULONG', 37452 value: 0 37453 }, { 37454 name: 'achVendID', 37455 type: 'CHARARRAY', 37456 value: 'XXXX' 37457 }, { 37458 name: 'fsSelection', 37459 type: 'USHORT', 37460 value: 0 37461 }, { 37462 name: 'usFirstCharIndex', 37463 type: 'USHORT', 37464 value: 0 37465 }, { 37466 name: 'usLastCharIndex', 37467 type: 'USHORT', 37468 value: 0 37469 }, { 37470 name: 'sTypoAscender', 37471 type: 'SHORT', 37472 value: 0 37473 }, { 37474 name: 'sTypoDescender', 37475 type: 'SHORT', 37476 value: 0 37477 }, { 37478 name: 'sTypoLineGap', 37479 type: 'SHORT', 37480 value: 0 37481 }, { 37482 name: 'usWinAscent', 37483 type: 'USHORT', 37484 value: 0 37485 }, { 37486 name: 'usWinDescent', 37487 type: 'USHORT', 37488 value: 0 37489 }, { 37490 name: 'ulCodePageRange1', 37491 type: 'ULONG', 37492 value: 0 37493 }, { 37494 name: 'ulCodePageRange2', 37495 type: 'ULONG', 37496 value: 0 37497 }, { 37498 name: 'sxHeight', 37499 type: 'SHORT', 37500 value: 0 37501 }, { 37502 name: 'sCapHeight', 37503 type: 'SHORT', 37504 value: 0 37505 }, { 37506 name: 'usDefaultChar', 37507 type: 'USHORT', 37508 value: 0 37509 }, { 37510 name: 'usBreakChar', 37511 type: 'USHORT', 37512 value: 0 37513 }, { 37514 name: 'usMaxContext', 37515 type: 'USHORT', 37516 value: 0 37517 }], options); 37518 } 37519 37520 var os2 = { 37521 parse: parseOS2Table, 37522 make: makeOS2Table, 37523 unicodeRanges: unicodeRanges, 37524 getUnicodeRange: getUnicodeRange 37525 }; // The `post` table stores additional PostScript information, such as glyph names. 37526 // Parse the PostScript `post` table 37527 37528 function parsePostTable(data, start) { 37529 var post = {}; 37530 var p = new parse.Parser(data, start);
37531 post.version = p.parseVersion(); 37532 post.italicAngle = p.parseFixed(); 37533 post.underlinePosition = p.parseShort(); 37534 post.underlineThickness = p.parseShort(); 37535 post.isFixedPitch = p.parseULong(); 37536 post.minMemType42 = p.parseULong(); 37537 post.maxMemType42 = p.parseULong(); 37538 post.minMemType1 = p.parseULong(); 37539 post.maxMemType1 = p.parseULong(); 37540 37541 switch (post.version) { 37542 case 1: 37543 post.names = standardNames.slice(); 37544 break; 37545 37546 case 2: 37547 post.numberOfGlyphs = p.parseUShort(); 37548 post.glyphNameIndex = new Array(post.numberOfGlyphs); 37549 37550 for (var i = 0; i < post.numberOfGlyphs; i++) { 37551 post.glyphNameIndex[i] = p.parseUShort(); 37552 } 37553 37554 post.names = []; 37555 37556 for (var i$1 = 0; i$1 < post.numberOfGlyphs; i$1++) { 37557 if (post.glyphNameIndex[i$1] >= standardNames.length) { 37558 var nameLength = p.parseChar(); 37559 post.names.push(p.parseString(nameLength)); 37560 } 37561 } 37562 37563 break; 37564 37565 case 2.5: 37566 post.numberOfGlyphs = p.parseUShort(); 37567 post.offset = new Array(post.numberOfGlyphs); 37568 37569 for (var i$2 = 0; i$2 < post.numberOfGlyphs; i$2++) { 37570 post.offset[i$2] = p.parseChar(); 37571 } 37572 37573 break; 37574 } 37575 37576 return post; 37577 } 37578 37579 function makePostTable() { 37580 return new table.Table('post', [{ 37581 name: 'version', 37582 type: 'FIXED', 37583 value: 0x00030000 37584 }, { 37585 name: 'italicAngle', 37586 type: 'FIXED', 37587 value: 0 37588 }, { 37589 name: 'underlinePosition', 37590 type: 'FWORD', 37591 value: 0 37592 }, { 37593 name: 'underlineThickness', 37594 type: 'FWORD', 37595 value: 0 37596 }, { 37597 name: 'isFixedPitch', 37598 type: 'ULONG', 37599 value: 0 37600 }, { 37601 name: 'minMemType42', 37602 type: 'ULONG', 37603 value: 0 37604 }, { 37605 name: 'maxMemType42', 37606 type: 'ULONG', 37607 value: 0 37608 }, { 37609 name: 'minMemType1', 37610 type: 'ULONG', 37611 value: 0 37612 }, { 37613 name: 'maxMemType1', 37614 type: 'ULONG', 37615 value: 0 37616 }]); 37617 } 37618 37619 var post = { 37620 parse: parsePostTable, 37621 make: makePostTable 37622 }; // The `GSUB` table contains ligatures, among other things. 37623 37624 var subtableParsers = new Array(9); // subtableParsers[0] is unused 37625 // https://www.microsoft.com/typography/OTSPEC/GSUB.htm#SS 37626 37627 subtableParsers[1] = function parseLookup1() { 37628 var start = this.offset + this.relativeOffset; 37629 var substFormat = this.parseUShort(); 37630 37631 if (substFormat === 1) { 37632 return { 37633 substFormat: 1, 37634 coverage: this.parsePointer(Parser.coverage), 37635 deltaGlyphId: this.parseUShort() 37636 }; 37637 } else if (substFormat === 2) { 37638 return { 37639 substFormat: 2, 37640 coverage: this.parsePointer(Parser.coverage), 37641 substitute: this.parseOffset16List() 37642 }; 37643 } 37644 37645 check.assert(false, '0x' + start.toString(16) + ': lookup type 1 format must be 1 or 2.'); 37646 }; // https://www.microsoft.com/typography/OTSPEC/GSUB.htm#MS 37647 37648 37649 subtableParsers[2] = function parseLookup2() { 37650 var substFormat = this.parseUShort(); 37651 check.argument(substFormat === 1, 'GSUB Multiple Substitution Subtable identifier-format must be 1'); 37652 return { 37653 substFormat: substFormat, 37654 coverage: this.parsePointer(Parser.coverage), 37655 sequences: this.parseListOfLists() 37656 }; 37657 }; // https://www.microsoft.com/typography/OTSPEC/GSUB.htm#AS 37658 37659 37660 subtableParsers[3] = function parseLookup3() { 37661 var substFormat = this.parseUShort(); 37662 check.argument(substFormat === 1, 'GSUB Alternate Substitution Subtable identifier-format must be 1'); 37663 return { 37664 substFormat: substFormat, 37665 coverage: this.parsePointer(Parser.coverage), 37666 alternateSets: this.parseListOfLists() 37667 }; 37668 }; // https://www.microsoft.com/typography/OTSPEC/GSUB.htm#LS 37669 37670 37671 subtableParsers[4] = function parseLookup4() { 37672 var substFormat = this.parseUShort(); 37673 check.argument(substFormat === 1, 'GSUB ligature table identifier-format must be 1'); 37674 return { 37675 substFormat: substFormat, 37676 coverage: this.parsePointer(Parser.coverage), 37677 ligatureSets: this.parseListOfLists(function () { 37678 return { 37679 ligGlyph: this.parseUShort(), 37680 components: this.parseUShortList(this.parseUShort() - 1) 37681 }; 37682 }) 37683 }; 37684 }; 37685 37686 var lookupRecordDesc = { 37687 sequenceIndex: Parser.uShort, 37688 lookupListIndex: Parser.uShort 37689 }; // https://www.microsoft.com/typography/OTSPEC/GSUB.htm#CSF 37690 37691 subtableParsers[5] = function parseLookup5() { 37692 var start = this.offset + this.relativeOffset; 37693 var substFormat = this.parseUShort(); 37694 37695 if (substFormat === 1) { 37696 return { 37697 substFormat: substFormat, 37698 coverage: this.parsePointer(Parser.coverage), 37699 ruleSets: this.parseListOfLists(function () { 37700 var glyphCount = this.parseUShort(); 37701 var substCount = this.parseUShort(); 37702 return { 37703 input: this.parseUShortList(glyphCount - 1), 37704 lookupRecords: this.parseRecordList(substCount, lookupRecordDesc) 37705 }; 37706 }) 37707 }; 37708 } else if (substFormat === 2) { 37709 return { 37710 substFormat: substFormat, 37711 coverage: this.parsePointer(Parser.coverage), 37712 classDef: this.parsePointer(Parser.classDef), 37713 classSets: this.parseListOfLists(function () { 37714 var glyphCount = this.parseUShort(); 37715 var substCount = this.parseUShort(); 37716 return { 37717 classes: this.parseUShortList(glyphCount - 1), 37718 lookupRecords: this.parseRecordList(substCount, lookupRecordDesc) 37719 }; 37720 }) 37721 }; 37722 } else if (substFormat === 3) { 37723 var glyphCount = this.parseUShort(); 37724 var substCount = this.parseUShort(); 37725 return { 37726 substFormat: substFormat, 37727 coverages: this.parseList(glyphCount, Parser.pointer(Parser.coverage)), 37728 lookupRecords: this.parseRecordList(substCount, lookupRecordDesc) 37729 }; 37730 } 37731 37732 check.assert(false, '0x' + start.toString(16) + ': lookup type 5 format must be 1, 2 or 3.'); 37733 }; // https://www.microsoft.com/typography/OTSPEC/GSUB.htm#CC 37734 37735 37736 subtableParsers[6] = function parseLookup6() { 37737 var start = this.offset + this.relativeOffset; 37738 var substFormat = this.parseUShort(); 37739 37740 if (substFormat === 1) { 37741 return { 37742 substFormat: 1, 37743 coverage: this.parsePointer(Parser.coverage), 37744 chainRuleSets: this.parseListOfLists(function () { 37745 return { 37746 backtrack: this.parseUShortList(), 37747 input: this.parseUShortList(this.parseShort() - 1), 37748 lookahead: this.parseUShortList(), 37749 lookupRecords: this.parseRecordList(lookupRecordDesc) 37750 }; 37751 }) 37752 }; 37753 } else if (substFormat === 2) { 37754 return { 37755 substFormat: 2, 37756 coverage: this.parsePointer(Parser.coverage), 37757 backtrackClassDef: this.parsePointer(Parser.classDef), 37758 inputClassDef: this.parsePointer(Parser.classDef), 37759 lookaheadClassDef: this.parsePointer(Parser.classDef), 37760 chainClassSet: this.parseListOfLists(function () { 37761 return { 37762 backtrack: this.parseUShortList(), 37763 input: this.parseUShortList(this.parseShort() - 1), 37764 lookahead: this.parseUShortList(), 37765 lookupRecords: this.parseRecordList(lookupRecordDesc) 37766 }; 37767 }) 37768 }; 37769 } else if (substFormat === 3) { 37770 return { 37771 substFormat: 3, 37772 backtrackCoverage: this.parseList(Parser.pointer(Parser.coverage)), 37773 inputCoverage: this.parseList(Parser.pointer(Parser.coverage)), 37774 lookaheadCoverage: this.parseList(Parser.pointer(Parser.coverage)), 37775 lookupRecords: this.parseRecordList(lookupRecordDesc) 37776 }; 37777 } 37778 37779 check.assert(false, '0x' + start.toString(16) + ': lookup type 6 format must be 1, 2 or 3.'); 37780 }; // https://www.microsoft.com/typography/OTSPEC/GSUB.htm#ES 37781 37782 37783 subtableParsers[7] = function parseLookup7() { 37784 // Extension Substitution subtable 37785 var substFormat = this.parseUShort(); 37786 check.argument(substFormat === 1, 'GSUB Extension Substitution subtable identifier-format must be 1'); 37787 var extensionLookupType = this.parseUShort(); 37788 var extensionParser = new Parser(this.data, this.offset + this.parseULong()); 37789 return { 37790 substFormat: 1, 37791 lookupType: extensionLookupType, 37792 extension: subtableParsers[extensionLookupType].call(extensionParser) 37793 }; 37794 }; // https://www.microsoft.com/typography/OTSPEC/GSUB.htm#RCCS 37795 37796
37797 subtableParsers[8] = function parseLookup8() { 37798 var substFormat = this.parseUShort(); 37799 check.argument(substFormat === 1, 'GSUB Reverse Chaining Contextual Single Substitution Subtable identifier-format must be 1'); 37800 return { 37801 substFormat: substFormat, 37802 coverage: this.parsePointer(Parser.coverage), 37803 backtrackCoverage: this.parseList(Parser.pointer(Parser.coverage)), 37804 lookaheadCoverage: this.parseList(Parser.pointer(Parser.coverage)), 37805 substitutes: this.parseUShortList() 37806 }; 37807 }; // https://www.microsoft.com/typography/OTSPEC/gsub.htm 37808 37809 37810 function parseGsubTable(data, start) { 37811 start = start || 0; 37812 var p = new Parser(data, start); 37813 var tableVersion = p.parseVersion(1); 37814 check.argument(tableVersion === 1 || tableVersion === 1.1, 'Unsupported GSUB table version.'); 37815 37816 if (tableVersion === 1) { 37817 return { 37818 version: tableVersion, 37819 scripts: p.parseScriptList(), 37820 features: p.parseFeatureList(), 37821 lookups: p.parseLookupList(subtableParsers) 37822 }; 37823 } else { 37824 return { 37825 version: tableVersion, 37826 scripts: p.parseScriptList(), 37827 features: p.parseFeatureList(), 37828 lookups: p.parseLookupList(subtableParsers), 37829 variations: p.parseFeatureVariationsList() 37830 }; 37831 } 37832 } // GSUB Writing ////////////////////////////////////////////// 37833 37834 37835 var subtableMakers = new Array(9); 37836 37837 subtableMakers[1] = function makeLookup1(subtable) { 37838 if (subtable.substFormat === 1) { 37839 return new table.Table('substitutionTable', [{ 37840 name: 'substFormat', 37841 type: 'USHORT', 37842 value: 1 37843 }, { 37844 name: 'coverage', 37845 type: 'TABLE', 37846 value: new table.Coverage(subtable.coverage) 37847 }, { 37848 name: 'deltaGlyphID', 37849 type: 'USHORT', 37850 value: subtable.deltaGlyphId 37851 }]); 37852 } else { 37853 return new table.Table('substitutionTable', [{ 37854 name: 'substFormat', 37855 type: 'USHORT', 37856 value: 2 37857 }, { 37858 name: 'coverage', 37859 type: 'TABLE', 37860 value: new table.Coverage(subtable.coverage) 37861 }].concat(table.ushortList('substitute', subtable.substitute))); 37862 } 37863 37864 check.fail('Lookup type 1 substFormat must be 1 or 2.'); 37865 }; 37866 37867 subtableMakers[3] = function makeLookup3(subtable) { 37868 check.assert(subtable.substFormat === 1, 'Lookup type 3 substFormat must be 1.'); 37869 return new table.Table('substitutionTable', [{ 37870 name: 'substFormat', 37871 type: 'USHORT', 37872 value: 1 37873 }, { 37874 name: 'coverage', 37875 type: 'TABLE', 37876 value: new table.Coverage(subtable.coverage) 37877 }].concat(table.tableList('altSet', subtable.alternateSets, function (alternateSet) { 37878 return new table.Table('alternateSetTable', table.ushortList('alternate', alternateSet)); 37879 }))); 37880 }; 37881 37882 subtableMakers[4] = function makeLookup4(subtable) { 37883 check.assert(subtable.substFormat === 1, 'Lookup type 4 substFormat must be 1.'); 37884 return new table.Table('substitutionTable', [{ 37885 name: 'substFormat', 37886 type: 'USHORT', 37887 value: 1 37888 }, { 37889 name: 'coverage', 37890 type: 'TABLE', 37891 value: new table.Coverage(subtable.coverage) 37892 }].concat(table.tableList('ligSet', subtable.ligatureSets, function (ligatureSet) { 37893 return new table.Table('ligatureSetTable', table.tableList('ligature', ligatureSet, function (ligature) { 37894 return new table.Table('ligatureTable', [{ 37895 name: 'ligGlyph', 37896 type: 'USHORT', 37897 value: ligature.ligGlyph 37898 }
37898].concat(table.ushortList('component', ligature.components, ligature.components.length + 1))); 37899 })); 37900 }))); 37901 }; 37902 37903 function makeGsubTable(gsub) { 37904 return new table.Table('GSUB', [{ 37905 name: 'version', 37906 type: 'ULONG', 37907 value: 0x10000 37908 }, { 37909 name: 'scripts', 37910 type: 'TABLE', 37911 value: new table.ScriptList(gsub.scripts) 37912 }, { 37913 name: 'features', 37914 type: 'TABLE', 37915 value: new table.FeatureList(gsub.features) 37916 }, { 37917 name: 'lookups', 37918 type: 'TABLE', 37919 value: new table.LookupList(gsub.lookups, subtableMakers) 37920 }]); 37921 } 37922 37923 var gsub = { 37924 parse: parseGsubTable, 37925 make: makeGsubTable 37926 }; // The `GPOS` table contains kerning pairs, among other things. 37927 // Parse the metadata `meta` table. 37928 // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6meta.html 37929 37930 function parseMetaTable(data, start) { 37931 var p = new parse.Parser(data, start); 37932 var tableVersion = p.parseULong(); 37933 check.argument(tableVersion === 1, 'Unsupported META table version.'); 37934 p.parseULong(); // flags - currently unused and set to 0 37935 37936 p.parseULong(); // tableOffset 37937 37938 var numDataMaps = p.parseULong(); 37939 var tags = {}; 37940 37941 for (var i = 0; i < numDataMaps; i++) { 37942 var tag = p.parseTag(); 37943 var dataOffset = p.parseULong(); 37944 var dataLength = p.parseULong(); 37945 var text = decode.UTF8(data, start + dataOffset, dataLength); 37946 tags[tag] = text; 37947 } 37948 37949 return tags; 37950 } 37951 37952 function makeMetaTable(tags) { 37953 var numTags = Object.keys(tags).length; 37954 var stringPool = ''; 37955 var stringPoolOffset = 16 + numTags * 12; 37956 var result = new table.Table('meta', [{ 37957 name: 'version', 37958 type: 'ULONG', 37959 value: 1 37960 }, { 37961 name: 'flags', 37962 type: 'ULONG', 37963 value: 0 37964 }, { 37965 name: 'offset', 37966 type: 'ULONG', 37967 value: stringPoolOffset 37968 }, { 37969 name: 'numTags', 37970 type: 'ULONG', 37971 value: numTags 37972 }]); 37973 37974 for (var tag in tags) { 37975 var pos = stringPool.length; 37976 stringPool += tags[tag]; 37977 result.fields.push({ 37978 name: 'tag ' + tag, 37979 type: 'TAG', 37980 value: tag 37981 }); 37982 result.fields.push({ 37983 name: 'offset ' + tag, 37984 type: 'ULONG', 37985 value: stringPoolOffset + pos 37986 }); 37987 result.fields.push({ 37988 name: 'length ' + tag, 37989 type: 'ULONG', 37990 value: tags[tag].length 37991 }); 37992 } 37993 37994 result.fields.push({ 37995 name: 'stringPool', 37996 type: 'CHARARRAY', 37997 value: stringPool 37998 }); 37999 return result; 38000 } 38001 38002 var meta = { 38003 parse: parseMetaTable, 38004 make: makeMetaTable 38005 }; // The `sfnt` wrapper provides organization for the tables in the font. 38006 38007 function log2(v) { 38008 return Math.log(v) / Math.log(2) | 0; 38009 } 38010 38011 function computeCheckSum(bytes) { 38012 while (bytes.length % 4 !== 0) { 38013 bytes.push(0); 38014 } 38015 38016 var sum = 0; 38017 38018 for (var i = 0; i < bytes.length; i += 4) { 38019 sum += (bytes[i] << 24) + (bytes[i + 1] << 16) + (bytes[i + 2] << 8) + bytes[i + 3]; 38020 } 38021 38022 sum %= Math.pow(2, 32); 38023 return sum; 38024 } 38025 38026 function makeTableRecord(tag, checkSum, offset, length) { 38027 return new table.Record('Table Record', [{ 38028 name: 'tag', 38029 type: 'TAG', 38030 value: tag !== undefined ? tag : '' 38031 }, { 38032 name: 'checkSum', 38033 type: 'ULONG', 38034 value: checkSum !== undefined ? checkSum : 0 38035 }, { 38036 name: 'offset', 38037 type: 'ULONG', 38038 value: offset !== undefined ? offset : 0 38039 }, { 38040 name: 'length', 38041 type: 'ULONG', 38042 value: length !== undefined ? length : 0 38043 }]); 38044 } 38045 38046 function makeSfntTable(tables) { 38047 var sfnt = new table.Table('sfnt', [{ 38048 name: 'version', 38049 type: 'TAG', 38050 value: 'OTTO' 38051 }, { 38052 name: 'numTables', 38053 type: 'USHORT', 38054 value: 0 38055 }, {
38056 name: 'searchRange', 38057 type: 'USHORT', 38058 value: 0 38059 }, { 38060 name: 'entrySelector', 38061 type: 'USHORT', 38062 value: 0 38063 }, { 38064 name: 'rangeShift', 38065 type: 'USHORT', 38066 value: 0 38067 }]); 38068 sfnt.tables = tables; 38069 sfnt.numTables = tables.length; 38070 var highestPowerOf2 = Math.pow(2, log2(sfnt.numTables)); 38071 sfnt.searchRange = 16 * highestPowerOf2; 38072 sfnt.entrySelector = log2(highestPowerOf2); 38073 sfnt.rangeShift = sfnt.numTables * 16 - sfnt.searchRange; 38074 var recordFields = []; 38075 var tableFields = []; 38076 var offset = sfnt.sizeOf() + makeTableRecord().sizeOf() * sfnt.numTables; 38077 38078 while (offset % 4 !== 0) { 38079 offset += 1; 38080 tableFields.push({ 38081 name: 'padding', 38082 type: 'BYTE', 38083 value: 0 38084 }); 38085 } 38086 38087 for (var i = 0; i < tables.length; i += 1) { 38088 var t = tables[i]; 38089 check.argument(t.tableName.length === 4, 'Table name' + t.tableName + ' is invalid.'); 38090 var tableLength = t.sizeOf(); 38091 var tableRecord = makeTableRecord(t.tableName, computeCheckSum(t.encode()), offset, tableLength); 38092 recordFields.push({ 38093 name: tableRecord.tag + ' Table Record', 38094 type: 'RECORD', 38095 value: tableRecord 38096 }); 38097 tableFields.push({ 38098 name: t.tableName + ' table', 38099 type: 'RECORD', 38100 value: t 38101 }); 38102 offset += tableLength; 38103 check.argument(!isNaN(offset), 'Something went wrong calculating the offset.'); 38104 38105 while (offset % 4 !== 0) { 38106 offset += 1; 38107 tableFields.push({ 38108 name: 'padding', 38109 type: 'BYTE', 38110 value: 0 38111 }); 38112 } 38113 } // Table records need to be sorted alphabetically. 38114 38115 38116 recordFields.sort(function (r1, r2) { 38117 if (r1.value.tag > r2.value.tag) { 38118 return 1; 38119 } else { 38120 return -1; 38121 } 38122 }); 38123 sfnt.fields = sfnt.fields.concat(recordFields); 38124 sfnt.fields = sfnt.fields.concat(tableFields); 38125 return sfnt; 38126 } // Get the metrics for a character. If the string has more than one character 38127 // this function returns metrics for the first available character. 38128 // You can provide optional fallback metrics if no characters are available. 38129 38130 38131 function metricsForChar(font, chars, notFoundMetrics) { 38132 for (var i = 0; i < chars.length; i += 1) { 38133 var glyphIndex = font.charToGlyphIndex(chars[i]); 38134 38135 if (glyphIndex > 0) { 38136 var glyph = font.glyphs.get(glyphIndex); 38137 return glyph.getMetrics(); 38138 } 38139 } 38140 38141 return notFoundMetrics; 38142 } 38143 38144 function average(vs) { 38145 var sum = 0; 38146 38147 for (var i = 0; i < vs.length; i += 1) { 38148 sum += vs[i]; 38149 } 38150 38151 return sum / vs.length; 38152 } // Convert the font object to a SFNT data structure. 38153 // This structure contains all the necessary tables and metadata to create a binary OTF file. 38154 38155 38156 function fontToSfntTable(font) { 38157 var xMins = []; 38158 var yMins = []; 38159 var xMaxs = []; 38160 var yMaxs = []; 38161 var advanceWidths = []; 38162 var leftSideBearings = []; 38163 var rightSideBearings = []; 38164 var firstCharIndex; 38165 var lastCharIndex = 0; 38166 var ulUnicodeRange1 = 0; 38167 var ulUnicodeRange2 = 0; 38168 var ulUnicodeRange3 = 0; 38169 var ulUnicodeRange4 = 0; 38170 38171 for (var i = 0; i < font.glyphs.length; i += 1) { 38172 var glyph = font.glyphs.get(i); 38173 var unicode = glyph.unicode | 0; 38174 38175 if (isNaN(glyph.advanceWidth)) { 38176 throw new Error('Glyph ' + glyph.name + ' (' + i + '): advanceWidth is not a number.'); 38177 } 38178 38179 if (firstCharIndex > unicode || firstCharIndex === undefined) { 38180 // ignore .notdef char 38181 if (unicode > 0) { 38182 firstCharIndex = unicode; 38183 } 38184 } 38185 38186 if (lastCharIndex < unicode) { 38187 lastCharIndex = unicode; 38188 } 38189 38190 var position = os2.getUnicodeRange(unicode); 38191 38192 if (position < 32) { 38193 ulUnicodeRange1 |= 1 << position; 38194 } else if (position < 64) { 38195 ulUnicodeRange2 |= 1 << position - 32; 38196 } else if (position < 96) { 38197 ulUnicodeRange3 |= 1 << position - 64; 38198 } else if (position < 123) { 38199 ulUnicodeRange4 |= 1 << position - 96; 38200 } else { 38201 throw new Error('Unicode ranges bits > 123 are reserved for internal usage'); 38202 } // Skip non-important characters. 38203 38204 38205 if (glyph.name === '.notdef') { 38206 continue; 38207 } 38208 38209 var metrics = glyph.getMetrics(); 38210 xMins.push(metrics.xMin); 38211 yMins.push(metrics.yMin); 38212 xMaxs.push(metrics.xMax);
38213 yMaxs.push(metrics.yMax); 38214 leftSideBearings.push(metrics.leftSideBearing); 38215 rightSideBearings.push(metrics.rightSideBearing); 38216 advanceWidths.push(glyph.advanceWidth); 38217 } 38218 38219 var globals = { 38220 xMin: Math.min.apply(null, xMins), 38221 yMin: Math.min.apply(null, yMins), 38222 xMax: Math.max.apply(null, xMaxs), 38223 yMax: Math.max.apply(null, yMaxs), 38224 advanceWidthMax: Math.max.apply(null, advanceWidths), 38225 advanceWidthAvg: average(advanceWidths), 38226 minLeftSideBearing: Math.min.apply(null, leftSideBearings), 38227 maxLeftSideBearing: Math.max.apply(null, leftSideBearings), 38228 minRightSideBearing: Math.min.apply(null, rightSideBearings) 38229 }; 38230 globals.ascender = font.ascender; 38231 globals.descender = font.descender; 38232 var headTable = head.make({ 38233 flags: 3, 38234 // 00000011 (baseline for font at y=0; left sidebearing point at x=0) 38235 unitsPerEm: font.unitsPerEm, 38236 xMin: globals.xMin, 38237 yMin: globals.yMin, 38238 xMax: globals.xMax, 38239 yMax: globals.yMax, 38240 lowestRecPPEM: 3, 38241 createdTimestamp: font.createdTimestamp 38242 }); 38243 var hheaTable = hhea.make({ 38244 ascender: globals.ascender, 38245 descender: globals.descender, 38246 advanceWidthMax: globals.advanceWidthMax, 38247 minLeftSideBearing: globals.minLeftSideBearing, 38248 minRightSideBearing: globals.minRightSideBearing, 38249 xMaxExtent: globals.maxLeftSideBearing + (globals.xMax - globals.xMin), 38250 numberOfHMetrics: font.glyphs.length 38251 }); 38252 var maxpTable = maxp.make(font.glyphs.length); 38253 var os2Table = os2.make({ 38254 xAvgCharWidth: Math.round(globals.advanceWidthAvg), 38255 usWeightClass: font.tables.os2.usWeightClass, 38256 usWidthClass: font.tables.os2.usWidthClass, 38257 usFirstCharIndex: firstCharIndex, 38258 usLastCharIndex: lastCharIndex, 38259 ulUnicodeRange1: ulUnicodeRange1, 38260 ulUnicodeRange2: ulUnicodeRange2, 38261 ulUnicodeRange3: ulUnicodeRange3, 38262 ulUnicodeRange4: ulUnicodeRange4, 38263 fsSelection: font.tables.os2.fsSelection, 38264 // REGULAR 38265 // See http://typophile.com/node/13081 for more info on vertical metrics. 38266 // We get metrics for typical characters (such as "x" for xHeight). 38267 // We provide some fallback characters if characters are unavailable: their 38268 // ordering was chosen experimentally. 38269 sTypoAscender: globals.ascender, 38270 sTypoDescender: globals.descender, 38271 sTypoLineGap: 0, 38272 usWinAscent: globals.yMax, 38273 usWinDescent: Math.abs(globals.yMin), 38274 ulCodePageRange1: 1, 38275 // FIXME: hard-code Latin 1 support for now 38276 sxHeight: metricsForChar(font, 'xyvw', { 38277 yMax: Math.round(globals.ascender / 2) 38278 }).yMax, 38279 sCapHeight: metricsForChar(font, 'HIKLEFJMNTZBDPRAGOQSUVWXY', globals).yMax, 38280 usDefaultChar: font.hasChar(' ') ? 32 : 0, 38281 // Use space as the default character, if available. 38282 usBreakChar: font.hasChar(' ') ? 32 : 0 // Use space as the break character, if available. 38283 38284 }); 38285 var hmtxTable = hmtx.make(font.glyphs); 38286 var cmapTable = cmap.make(font.glyphs); 38287 var englishFamilyName = font.getEnglishName('fontFamily'); 38288 var englishStyleName = font.getEnglishName('fontSubfamily'); 38289 var englishFullName = englishFamilyName + ' ' + englishStyleName; 38290 var postScriptName = font.getEnglishName('postScriptName'); 38291 38292 if (!postScriptName) { 38293 postScriptName = englishFamilyName.replace(/\s/g, '') + '-' + englishStyleName; 38294 } 38295 38296 var names = {}; 38297 38298 for (var n in font.names) { 38299 names[n] = font.names[n]; 38300 } 38301 38302 if (!names.uniqueID) { 38303 names.uniqueID = { 38304 en: font.getEnglishName('manufacturer') + ':' + englishFullName 38305 }; 38306 } 38307 38308 if (!names.postScriptName) { 38309 names.postScriptName = { 38310 en: postScriptName 38311 }; 38312 } 38313 38314 if (!names.preferredFamily) { 38315 names.preferredFamily = font.names.fontFamily; 38316 } 38317 38318 if (!names.preferredSubfamily) {
38319 names.preferredSubfamily = font.names.fontSubfamily; 38320 } 38321 38322 var languageTags = []; 38323 38324 var nameTable = _name.make(names, languageTags); 38325 38326 var ltagTable = languageTags.length > 0 ? ltag.make(languageTags) : undefined; 38327 var postTable = post.make(); 38328 var cffTable = cff.make(font.glyphs, { 38329 version: font.getEnglishName('version'), 38330 fullName: englishFullName, 38331 familyName: englishFamilyName, 38332 weightName: englishStyleName, 38333 postScriptName: postScriptName, 38334 unitsPerEm: font.unitsPerEm, 38335 fontBBox: [0, globals.yMin, globals.ascender, globals.advanceWidthMax] 38336 }); 38337 var metaTable = font.metas && Object.keys(font.metas).length > 0 ? meta.make(font.metas) : undefined; // The order does not matter because makeSfntTable() will sort them. 38338 38339 var tables = [headTable, hheaTable, maxpTable, os2Table, nameTable, cmapTable, postTable, cffTable, hmtxTable]; 38340 38341 if (ltagTable) { 38342 tables.push(ltagTable); 38343 } // Optional tables 38344 38345 38346 if (font.tables.gsub) { 38347 tables.push(gsub.make(font.tables.gsub)); 38348 } 38349 38350 if (metaTable) { 38351 tables.push(metaTable); 38352 } 38353 38354 var sfntTable = makeSfntTable(tables); // Compute the font's checkSum and store it in head.checkSumAdjustment. 38355 38356 var bytes = sfntTable.encode(); 38357 var checkSum = computeCheckSum(bytes); 38358 var tableFields = sfntTable.fields; 38359 var checkSumAdjusted = false; 38360 38361 for (var i$1 = 0; i$1 < tableFields.length; i$1 += 1) { 38362 if (tableFields[i$1].name === 'head table') { 38363 tableFields[i$1].value.checkSumAdjustment = 0xB1B0AFBA - checkSum; 38364 checkSumAdjusted = true; 38365 break; 38366 } 38367 } 38368 38369 if (!checkSumAdjusted) { 38370 throw new Error('Could not find head table with checkSum to adjust.'); 38371 } 38372 38373 return sfntTable; 38374 } 38375 38376 var sfnt = { 38377 make: makeSfntTable, 38378 fontToTable: fontToSfntTable, 38379 computeCheckSum: computeCheckSum 38380 }; // The Layout object is the prototype of Substitution objects, and provides 38381 38382 function searchTag(arr, tag) { 38383 /* jshint bitwise: false */ 38384 var imin = 0; 38385 var imax = arr.length - 1; 38386 38387 while (imin <= imax) { 38388 var imid = imin + imax >>> 1; 38389 var val = arr[imid].tag; 38390 38391 if (val === tag) { 38392 return imid; 38393 } else if (val < tag) { 38394 imin = imid + 1; 38395 } else { 38396 imax = imid - 1; 38397 } 38398 } // Not found: return -1-insertion point 38399 38400 38401 return -imin - 1; 38402 } 38403 38404 function binSearch(arr, value) { 38405 /* jshint bitwise: false */ 38406 var imin = 0; 38407 var imax = arr.length - 1; 38408 38409 while (imin <= imax) { 38410 var imid = imin + imax >>> 1; 38411 var val = arr[imid]; 38412 38413 if (val === value) { 38414 return imid; 38415 } else if (val < value) { 38416 imin = imid + 1; 38417 } else { 38418 imax = imid - 1; 38419 } 38420 } // Not found: return -1-insertion point 38421 38422 38423 return -imin - 1; 38424 } // binary search in a list of ranges (coverage, class definition) 38425 38426 38427 function searchRange(ranges, value) { 38428 // jshint bitwise: false 38429 var range; 38430 var imin = 0; 38431 var imax = ranges.length - 1; 38432 38433 while (imin <= imax) { 38434 var imid = imin + imax >>> 1; 38435 range = ranges[imid]; 38436 var start = range.start; 38437 38438 if (start === value) { 38439 return range; 38440 } else if (start < value) { 38441 imin = imid + 1; 38442 } else { 38443 imax = imid - 1; 38444 } 38445 } 38446 38447 if (imin > 0) { 38448 range = ranges[imin - 1]; 38449 38450 if (value > range.end) { 38451 return 0; 38452 } 38453 38454 return range; 38455 } 38456 } 38457 /**
38458 * @exports opentype.Layout 38459 * @class 38460 */ 38461 38462 38463 function Layout(font, tableName) { 38464 this.font = font; 38465 this.tableName = tableName; 38466 } 38467 38468 Layout.prototype = { 38469 /** 38470 * Binary search an object by "tag" property 38471 * @instance 38472 * @function searchTag 38473 * @memberof opentype.Layout 38474 * @param {Array} arr 38475 * @param {string} tag 38476 * @return {number} 38477 */ 38478 searchTag: searchTag, 38479 38480 /** 38481 * Binary search in a list of numbers 38482 * @instance 38483 * @function binSearch 38484 * @memberof opentype.Layout 38485 * @param {Array} arr 38486 * @param {number} value 38487 * @return {number} 38488 */ 38489 binSearch: binSearch, 38490 38491 /** 38492 * Get or create the Layout table (GSUB, GPOS etc). 38493 * @param {boolean} create - Whether to create a new one. 38494 * @return {Object} The GSUB or GPOS table. 38495 */ 38496 getTable: function (create) { 38497 var layout = this.font.tables[this.tableName]; 38498 38499 if (!layout && create) { 38500 layout = this.font.tables[this.tableName] = this.createDefaultTable(); 38501 } 38502 38503 return layout; 38504 }, 38505 38506 /** 38507 * Returns all scripts in the substitution table. 38508 * @instance 38509 * @return {Array} 38510 */ 38511 getScriptNames: function () { 38512 var layout = this.getTable(); 38513 38514 if (!layout) { 38515 return []; 38516 } 38517 38518 return layout.scripts.map(function (script) { 38519 return script.tag; 38520 }); 38521 }, 38522 38523 /** 38524 * Returns the best bet for a script name. 38525 * Returns 'DFLT' if it exists. 38526 * If not, returns 'latn' if it exists. 38527 * If neither exist, returns undefined. 38528 */ 38529 getDefaultScriptName: function () { 38530 var layout = this.getTable(); 38531 38532 if (!layout) { 38533 return; 38534 } 38535 38536 var hasLatn = false; 38537 38538 for (var i = 0; i < layout.scripts.length; i++) { 38539 var name = layout.scripts[i].tag; 38540 38541 if (name === 'DFLT') { 38542 return name; 38543 } 38544 38545 if (name === 'latn') { 38546 hasLatn = true; 38547 } 38548 } 38549 38550 if (hasLatn) { 38551 return 'latn'; 38552 } 38553 }, 38554 38555 /** 38556 * Returns all LangSysRecords in the given script. 38557 * @instance 38558 * @param {string} [script='DFLT'] 38559 * @param {boolean} create - forces the creation of this script table if it doesn't exist. 38560 * @return {Object} An object with tag and script properties. 38561 */ 38562 getScriptTable: function (script, create) { 38563 var layout = this.getTable(create); 38564 38565 if (layout) { 38566 script = script || 'DFLT'; 38567 var scripts = layout.scripts; 38568 var pos = searchTag(layout.scripts, script); 38569 38570 if (pos >= 0) { 38571 return scripts[pos].script; 38572 } else if (create) { 38573 var scr = { 38574 tag: script, 38575 script: { 38576 defaultLangSys: { 38577 reserved: 0, 38578 reqFeatureIndex: 0xffff, 38579 featureIndexes: [] 38580 }, 38581 langSysRecords: [] 38582 } 38583 }; 38584 scripts.splice(-1 - pos, 0, scr); 38585 return scr.script; 38586 } 38587 } 38588 }, 38589 38590 /** 38591 * Returns a language system table 38592 * @instance 38593 * @param {string} [script='DFLT'] 38594 * @param {string} [language='dlft'] 38595 * @param {boolean} create - forces the creation of this langSysTable if it doesn't exist. 38596 * @return {Object} 38597 */ 38598 getLangSysTable: function (script, language, create) {
vendor: 4,771 bytes, lines 38599-38714
38599 var scriptTable = this.getScriptTable(script, create); 38600 38601 if (scriptTable) { 38602 if (!language || language === 'dflt' || language === 'DFLT') { 38603 return scriptTable.defaultLangSys; 38604 } 38605 38606 var pos = searchTag(scriptTable.langSysRecords, language); 38607 38608 if (pos >= 0) { 38609 return scriptTable.langSysRecords[pos].langSys; 38610 } else if (create) { 38611 var langSysRecord = { 38612 tag: language, 38613 langSys: { 38614 reserved: 0, 38615 reqFeatureIndex: 0xffff, 38616 featureIndexes: [] 38617 } 38618 }; 38619 scriptTable.langSysRecords.splice(-1 - pos, 0, langSysRecord); 38620 return langSysRecord.langSys; 38621 } 38622 } 38623 }, 38624 38625 /** 38626 * Get a specific feature table. 38627 * @instance 38628 * @param {string} [script='DFLT'] 38629 * @param {string} [language='dlft'] 38630 * @param {string} feature - One of the codes listed at https://www.microsoft.com/typography/OTSPEC/featurelist.htm 38631 * @param {boolean} create - forces the creation of the feature table if it doesn't exist. 38632 * @return {Object} 38633 */ 38634 getFeatureTable: function (script, language, feature, create) { 38635 var langSysTable = this.getLangSysTable(script, language, create); 38636 38637 if (langSysTable) { 38638 var featureRecord; 38639 var featIndexes = langSysTable.featureIndexes; 38640 var allFeatures = this.font.tables[this.tableName].features; // The FeatureIndex array of indices is in arbitrary order, 38641 // even if allFeatures is sorted alphabetically by feature tag. 38642 38643 for (var i = 0; i < featIndexes.length; i++) { 38644 featureRecord = allFeatures[featIndexes[i]]; 38645 38646 if (featureRecord.tag === feature) { 38647 return featureRecord.feature; 38648 } 38649 } 38650 38651 if (create) { 38652 var index = allFeatures.length; // Automatic ordering of features would require to shift feature indexes in the script list. 38653 38654 check.assert(index === 0 || feature >= allFeatures[index - 1].tag, 'Features must be added in alphabetical order.'); 38655 featureRecord = { 38656 tag: feature, 38657 feature: { 38658 params: 0, 38659 lookupListIndexes: [] 38660 } 38661 }; 38662 allFeatures.push(featureRecord); 38663 featIndexes.push(index); 38664 return featureRecord.feature; 38665 } 38666 } 38667 }, 38668 38669 /** 38670 * Get the lookup tables of a given type for a script/language/feature. 38671 * @instance 38672 * @param {string} [script='DFLT'] 38673 * @param {string} [language='dlft'] 38674 * @param {string} feature - 4-letter feature code 38675 * @param {number} lookupType - 1 to 9 38676 * @param {boolean} create - forces the creation of the lookup table if it doesn't exist, with no subtables. 38677 * @return {Object[]} 38678 */ 38679 getLookupTables: function (script, language, feature, lookupType, create) { 38680 var featureTable = this.getFeatureTable(script, language, feature, create); 38681 var tables = []; 38682 38683 if (featureTable) { 38684 var lookupTable; 38685 var lookupListIndexes = featureTable.lookupListIndexes; 38686 var allLookups = this.font.tables[this.tableName].lookups; // lookupListIndexes are in no particular order, so use naive search. 38687 38688 for (var i = 0; i < lookupListIndexes.length; i++) { 38689 lookupTable = allLookups[lookupListIndexes[i]]; 38690 38691 if (lookupTable.lookupType === lookupType) { 38692 tables.push(lookupTable); 38693 } 38694 } 38695 38696 if (tables.length === 0 && create) { 38697 lookupTable = { 38698 lookupType: lookupType, 38699 lookupFlag: 0, 38700 subtables: [], 38701 markFilteringSet: undefined 38702 }; 38703 var index = allLookups.length; 38704 allLookups.push(lookupTable); 38705 lookupListIndexes.push(index); 38706 return [lookupTable]; 38707 } 38708 } 38709 38710 return tables; 38711 }, 38712 38713 /** 38714 * Find a glyph in a class definition table
38715 * https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table 38716 * @param {object} classDefTable - an OpenType Layout class definition table 38717 * @param {number} glyphIndex - the index of the glyph to find 38718 * @returns {number} -1 if not found 38719 */ 38720 getGlyphClass: function (classDefTable, glyphIndex) { 38721 switch (classDefTable.format) { 38722 case 1: 38723 if (classDefTable.startGlyph <= glyphIndex && glyphIndex < classDefTable.startGlyph + classDefTable.classes.length) { 38724 return classDefTable.classes[glyphIndex - classDefTable.startGlyph]; 38725 } 38726 38727 return 0; 38728 38729 case 2: 38730 var range = searchRange(classDefTable.ranges, glyphIndex); 38731 return range ? range.classId : 0; 38732 } 38733 }, 38734 38735 /** 38736 * Find a glyph in a coverage table 38737 * https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table 38738 * @param {object} coverageTable - an OpenType Layout coverage table 38739 * @param {number} glyphIndex - the index of the glyph to find 38740 * @returns {number} -1 if not found 38741 */ 38742 getCoverageIndex: function (coverageTable, glyphIndex) { 38743 switch (coverageTable.format) { 38744 case 1: 38745 var index = binSearch(coverageTable.glyphs, glyphIndex); 38746 return index >= 0 ? index : -1; 38747 38748 case 2: 38749 var range = searchRange(coverageTable.ranges, glyphIndex); 38750 return range ? range.index + glyphIndex - range.start : -1; 38751 } 38752 }, 38753 38754 /** 38755 * Returns the list of glyph indexes of a coverage table. 38756 * Format 1: the list is stored raw 38757 * Format 2: compact list as range records. 38758 * @instance 38759 * @param {Object} coverageTable 38760 * @return {Array} 38761 */ 38762 expandCoverage: function (coverageTable) { 38763 if (coverageTable.format === 1) { 38764 return coverageTable.glyphs; 38765 } else { 38766 var glyphs = []; 38767 var ranges = coverageTable.ranges; 38768 38769 for (var i = 0; i < ranges.length; i++) { 38770 var range = ranges[i]; 38771 var start = range.start; 38772 var end = range.end; 38773 38774 for (var j = start; j <= end; j++) { 38775 glyphs.push(j); 38776 } 38777 } 38778 38779 return glyphs; 38780 } 38781 } 38782 }; // The Position object provides utility methods to manipulate 38783 38784 /** 38785 * @exports opentype.Position 38786 * @class 38787 * @extends opentype.Layout 38788 * @param {opentype.Font} 38789 * @constructor 38790 */ 38791 38792 function Position(font) { 38793 Layout.call(this, font, 'gpos'); 38794 } 38795 38796 Position.prototype = Layout.prototype; 38797 /** 38798 * Init some data for faster and easier access later. 38799 */ 38800 38801 Position.prototype.init = function () { 38802 var script = this.getDefaultScriptName(); 38803 this.defaultKerningTables = this.getKerningTables(script); 38804 }; 38805 /** 38806 * Find a glyph pair in a list of lookup tables of type 2 and retrieve the xAdvance kerning value. 38807 * 38808 * @param {integer} leftIndex - left glyph index 38809 * @param {integer} rightIndex - right glyph index 38810 * @returns {integer} 38811 */ 38812 38813 38814 Position.prototype.getKerningValue = function (kerningLookups, leftIndex, rightIndex) { 38815 var this$1 = this; 38816 38817 for (var i = 0; i < kerningLookups.length; i++) { 38818 var subtables = kerningLookups[i].subtables; 38819 38820 for (var j = 0; j < subtables.length; j++) { 38821 var subtable = subtables[j]; 38822 var covIndex = this$1.getCoverageIndex(subtable.coverage, leftIndex); 38823 38824 if (covIndex < 0) { 38825 continue; 38826 } 38827 38828 switch (subtable.posFormat) { 38829 case 1: 38830 // Search Pair Adjustment Positioning Format 1 38831 var pairSet = subtable.pairSets[covIndex]; 38832 38833 for (var k = 0; k < pairSet.length; k++) { 38834 var pair = pairSet[k]; 38835 38836 if (pair.secondGlyph === rightIndex) { 38837 return pair.value1 && pair.value1.xAdvance || 0; 38838 } 38839 } 38840 38841 break; 38842 // left glyph found, not right glyph - try next subtable 38843 38844 case 2: 38845 // Search Pair Adjustment Positioning Format 2 38846 var class1 = this$1.getGlyphClass(subtable.classDef1, leftIndex); 38847 var class2 = this$1.getGlyphClass(subtable.classDef2, rightIndex); 38848 var pair$1 = subtable.classRecords[class1][class2]; 38849 return pair$1.value1 && pair$1.value1.xAdvance || 0; 38850 } 38851 } 38852 } 38853 38854 return 0; 38855 }; 38856 /** 38857 * List all kerning lookup tables. 38858 * 38859 * @param {string} [script='DFLT'] - use font.position.getDefaultScriptName() for a better default value 38860 * @param {string} [language='dflt'] 38861 * @return {object[]} The list of kerning lookup tables (may be empty), or undefined if there is no GPOS table (and we should use the kern table) 38862 */ 38863 38864 38865 Position.prototype.getKerningTables = function (script, language) { 38866 if (this.font.tables.gpos) { 38867 return this.getLookupTables(script, language, 'kern', 2); 38868 } 38869 }; // The Substitution object provides utility methods to manipulate 38870 38871 /** 38872 * @exports opentype.Substitution 38873 * @class
vendor: 26,662 bytes, lines 38874-39611
38874 * @extends opentype.Layout 38875 * @param {opentype.Font} 38876 * @constructor 38877 */ 38878 38879 38880 function Substitution(font) { 38881 Layout.call(this, font, 'gsub'); 38882 } // Check if 2 arrays of primitives are equal. 38883 38884 38885 function arraysEqual(ar1, ar2) { 38886 var n = ar1.length; 38887 38888 if (n !== ar2.length) { 38889 return false; 38890 } 38891 38892 for (var i = 0; i < n; i++) { 38893 if (ar1[i] !== ar2[i]) { 38894 return false; 38895 } 38896 } 38897 38898 return true; 38899 } // Find the first subtable of a lookup table in a particular format. 38900 38901 38902 function getSubstFormat(lookupTable, format, defaultSubtable) { 38903 var subtables = lookupTable.subtables; 38904 38905 for (var i = 0; i < subtables.length; i++) { 38906 var subtable = subtables[i]; 38907 38908 if (subtable.substFormat === format) { 38909 return subtable; 38910 } 38911 } 38912 38913 if (defaultSubtable) { 38914 subtables.push(defaultSubtable); 38915 return defaultSubtable; 38916 } 38917 38918 return undefined; 38919 } 38920 38921 Substitution.prototype = Layout.prototype; 38922 /** 38923 * Create a default GSUB table. 38924 * @return {Object} gsub - The GSUB table. 38925 */ 38926 38927 Substitution.prototype.createDefaultTable = function () { 38928 // Generate a default empty GSUB table with just a DFLT script and dflt lang sys. 38929 return { 38930 version: 1, 38931 scripts: [{ 38932 tag: 'DFLT', 38933 script: { 38934 defaultLangSys: { 38935 reserved: 0, 38936 reqFeatureIndex: 0xffff, 38937 featureIndexes: [] 38938 }, 38939 langSysRecords: [] 38940 } 38941 }], 38942 features: [], 38943 lookups: [] 38944 }; 38945 }; 38946 /** 38947 * List all single substitutions (lookup type 1) for a given script, language, and feature. 38948 * @param {string} [script='DFLT'] 38949 * @param {string} [language='dflt'] 38950 * @param {string} feature - 4-character feature name ('aalt', 'salt', 'ss01'...) 38951 * @return {Array} substitutions - The list of substitutions. 38952 */ 38953 38954 38955 Substitution.prototype.getSingle = function (feature, script, language) { 38956 var this$1 = this; 38957 var substitutions = []; 38958 var lookupTables = this.getLookupTables(script, language, feature, 1); 38959 38960 for (var idx = 0; idx < lookupTables.length; idx++) { 38961 var subtables = lookupTables[idx].subtables; 38962 38963 for (var i = 0; i < subtables.length; i++) { 38964 var subtable = subtables[i]; 38965 var glyphs = this$1.expandCoverage(subtable.coverage); 38966 var j = void 0; 38967 38968 if (subtable.substFormat === 1) { 38969 var delta = subtable.deltaGlyphId; 38970 38971 for (j = 0; j < glyphs.length; j++) { 38972 var glyph = glyphs[j]; 38973 substitutions.push({ 38974 sub: glyph, 38975 by: glyph + delta 38976 }); 38977 } 38978 } else { 38979 var substitute = subtable.substitute; 38980 38981 for (j = 0; j < glyphs.length; j++) { 38982 substitutions.push({ 38983 sub: glyphs[j], 38984 by: substitute[j] 38985 }); 38986 } 38987 } 38988 } 38989 } 38990 38991 return substitutions; 38992 }; 38993 /** 38994 * List all alternates (lookup type 3) for a given script, language, and feature. 38995 * @param {string} [script='DFLT'] 38996 * @param {string} [language='dflt'] 38997 * @param {string} feature - 4-character feature name ('aalt', 'salt'...) 38998 * @return {Array} alternates - The list of alternates 38999 */ 39000 39001 39002 Substitution.prototype.getAlternates = function (feature, script, language) { 39003 var this$1 = this; 39004 var alternates = []; 39005 var lookupTables = this.getLookupTables(script, language, feature, 3); 39006 39007 for (var idx = 0; idx < lookupTables.length; idx++) { 39008 var subtables = lookupTables[idx].subtables; 39009 39010 for (var i = 0; i < subtables.length; i++) { 39011 var subtable = subtables[i]; 39012 var glyphs = this$1.expandCoverage(subtable.coverage); 39013 var alternateSets = subtable.alternateSets; 39014 39015 for (var j = 0; j < glyphs.length; j++) { 39016 alternates.push({ 39017 sub: glyphs[j], 39018 by: alternateSets[j] 39019 }); 39020 } 39021 } 39022 } 39023 39024 return alternates; 39025 }; 39026 /** 39027 * List all ligatures (lookup type 4) for a given script, language, and feature. 39028 * The result is an array of ligature objects like { sub: [ids], by: id } 39029 * @param {string} feature - 4-letter feature name ('liga', 'rlig', 'dlig'...) 39030 * @param {string} [script='DFLT'] 39031 * @param {string} [language='dflt'] 39032 * @return {Array} ligatures - The list of ligatures. 39033 */ 39034 39035 39036 Substitution.prototype.getLigatures = function (feature, script, language) { 39037 var this$1 = this; 39038 var ligatures = []; 39039 var lookupTables = this.getLookupTables(script, language, feature, 4); 39040 39041 for (var idx = 0; idx < lookupTables.length; idx++) { 39042 var subtables = lookupTables[idx].subtables; 39043 39044 for (var i = 0; i < subtables.length; i++) { 39045 var subtable = subtables[i]; 39046 var glyphs = this$1.expandCoverage(subtable.coverage); 39047 var ligatureSets = subtable.ligatureSets; 39048 39049 for (var j = 0; j < glyphs.length; j++) { 39050 var startGlyph = glyphs[j]; 39051 var ligSet = ligatureSets[j]; 39052 39053 for (var k = 0; k < ligSet.length; k++) { 39054 var lig = ligSet[k]; 39055 ligatures.push({ 39056 sub: [startGlyph].concat(lig.components), 39057 by: lig.ligGlyph 39058 }); 39059 } 39060 } 39061 } 39062 } 39063 39064 return ligatures; 39065 }; 39066 /** 39067 * Add or modify a single substitution (lookup type 1) 39068 * Format 2, more flexible, is always used. 39069 * @param {string} feature - 4-letter feature name ('liga', 'rlig', 'dlig'...) 39070 * @param {Object} substitution - { sub: id, delta: number } for format 1 or { sub: id, by: id } for format 2. 39071 * @param {string} [script='DFLT'] 39072 * @param {string} [language='dflt'] 39073 */ 39074 39075 39076 Substitution.prototype.addSingle = function (feature, substitution, script, language) { 39077 var lookupTable = this.getLookupTables(script, language, feature, 1, true)[0]; 39078 var subtable = getSubstFormat(lookupTable, 2, { 39079 // lookup type 1 subtable, format 2, coverage format 1 39080 substFormat: 2, 39081 coverage: { 39082 format: 1, 39083 glyphs: [] 39084 }, 39085 substitute: [] 39086 }); 39087 check.assert(subtable.coverage.format === 1, 'Ligature: unable to modify coverage table format ' + subtable.coverage.format); 39088 var coverageGlyph = substitution.sub; 39089 var pos = this.binSearch(subtable.coverage.glyphs, coverageGlyph); 39090 39091 if (pos < 0) { 39092 pos = -1 - pos; 39093 subtable.coverage.glyphs.splice(pos, 0, coverageGlyph); 39094 subtable.substitute.splice(pos, 0, 0); 39095 } 39096 39097 subtable.substitute[pos] = substitution.by; 39098 }; 39099 /** 39100 * Add or modify an alternate substitution (lookup type 1) 39101 * @param {string} feature - 4-letter feature name ('liga', 'rlig', 'dlig'...) 39102 * @param {Object} substitution - { sub: id, by: [ids] } 39103 * @param {string} [script='DFLT'] 39104 * @param {string} [language='dflt'] 39105 */ 39106 39107 39108 Substitution.prototype.addAlternate = function (feature, substitution, script, language) { 39109 var lookupTable = this.getLookupTables(script, language, feature, 3, true)[0]; 39110 var subtable = getSubstFormat(lookupTable, 1, { 39111 // lookup type 3 subtable, format 1, coverage format 1 39112 substFormat: 1, 39113 coverage: { 39114 format: 1, 39115 glyphs: [] 39116 }, 39117 alternateSets: [] 39118 }); 39119 check.assert(subtable.coverage.format === 1, 'Ligature: unable to modify coverage table format ' + subtable.coverage.format); 39120 var coverageGlyph = substitution.sub; 39121 var pos = this.binSearch(subtable.coverage.glyphs, coverageGlyph); 39122 39123 if (pos < 0) { 39124 pos = -1 - pos; 39125 subtable.coverage.glyphs.splice(pos, 0, coverageGlyph); 39126 subtable.alternateSets.splice(pos, 0, 0); 39127 } 39128 39129 subtable.alternateSets[pos] = substitution.by; 39130 }; 39131 /** 39132 * Add a ligature (lookup type 4) 39133 * Ligatures with more components must be stored ahead of those with fewer components in order to be found 39134 * @param {string} feature - 4-letter feature name ('liga', 'rlig', 'dlig'...) 39135 * @param {Object} ligature - { sub: [ids], by: id } 39136 * @param {string} [script='DFLT'] 39137 * @param {string} [language='dflt'] 39138 */ 39139 39140 39141 Substitution.prototype.addLigature = function (feature, ligature, script, language) { 39142 var lookupTable = this.getLookupTables(script, language, feature, 4, true)[0]; 39143 var subtable = lookupTable.subtables[0]; 39144 39145 if (!subtable) { 39146 subtable = { 39147 // lookup type 4 subtable, format 1, coverage format 1 39148 substFormat: 1, 39149 coverage: { 39150 format: 1, 39151 glyphs: [] 39152 }, 39153 ligatureSets: [] 39154 }; 39155 lookupTable.subtables[0] = subtable; 39156 } 39157 39158 check.assert(subtable.coverage.format === 1, 'Ligature: unable to modify coverage table format ' + subtable.coverage.format); 39159 var coverageGlyph = ligature.sub[0]; 39160 var ligComponents = ligature.sub.slice(1); 39161 var ligatureTable = { 39162 ligGlyph: ligature.by, 39163 components: ligComponents 39164 }; 39165 var pos = this.binSearch(subtable.coverage.glyphs, coverageGlyph); 39166 39167 if (pos >= 0) { 39168 // ligatureSet already exists 39169 var ligatureSet = subtable.ligatureSets[pos]; 39170 39171 for (var i = 0; i < ligatureSet.length; i++) { 39172 // If ligature already exists, return. 39173 if (arraysEqual(ligatureSet[i].components, ligComponents)) { 39174 return; 39175 } 39176 } // ligature does not exist: add it. 39177 39178 39179 ligatureSet.push(ligatureTable); 39180 } else { 39181 // Create a new ligatureSet and add coverage for the first glyph. 39182 pos = -1 - pos; 39183 subtable.coverage.glyphs.splice(pos, 0, coverageGlyph); 39184 subtable.ligatureSets.splice(pos, 0, [ligatureTable]); 39185 } 39186 }; 39187 /** 39188 * List all feature data for a given script and language. 39189 * @param {string} feature - 4-letter feature name 39190 * @param {string} [script='DFLT'] 39191 * @param {string} [language='dflt'] 39192 * @return {Array} substitutions - The list of substitutions. 39193 */ 39194 39195 39196 Substitution.prototype.getFeature = function (feature, script, language) { 39197 if (/ss\d\d/.test(feature)) { 39198 // ss01 - ss20 39199 return this.getSingle(feature, script, language); 39200 } 39201 39202 switch (feature) { 39203 case 'aalt': 39204 case 'salt': 39205 return this.getSingle(feature, script, language).concat(this.getAlternates(feature, script, language)); 39206 39207 case 'dlig': 39208 case 'liga': 39209 case 'rlig': 39210 return this.getLigatures(feature, script, language); 39211 } 39212 39213 return undefined; 39214 }; 39215 /** 39216 * Add a substitution to a feature for a given script and language. 39217 * @param {string} feature - 4-letter feature name 39218 * @param {Object} sub - the substitution to add (an object like { sub: id or [ids], by: id or [ids] }) 39219 * @param {string} [script='DFLT'] 39220 * @param {string} [language='dflt'] 39221 */ 39222 39223 39224 Substitution.prototype.add = function (feature, sub, script, language) { 39225 if (/ss\d\d/.test(feature)) { 39226 // ss01 - ss20 39227 return this.addSingle(feature, sub, script, language); 39228 } 39229 39230 switch (feature) { 39231 case 'aalt': 39232 case 'salt': 39233 if (typeof sub.by === 'number') { 39234 return this.addSingle(feature, sub, script, language); 39235 } 39236 39237 return this.addAlternate(feature, sub, script, language); 39238 39239 case 'dlig': 39240 case 'liga': 39241 case 'rlig': 39242 return this.addLigature(feature, sub, script, language); 39243 } 39244 39245 return undefined; 39246 }; 39247 39248 function isBrowser() { 39249 return typeof window !== 'undefined'; 39250 } 39251 39252 function nodeBufferToArrayBuffer(buffer) { 39253 var ab = new ArrayBuffer(buffer.length); 39254 var view = new Uint8Array(ab); 39255 39256 for (var i = 0; i < buffer.length; ++i) { 39257 view[i] = buffer[i]; 39258 } 39259 39260 return ab; 39261 } 39262 39263 function arrayBufferToNodeBuffer(ab) { 39264 var buffer = new Buffer(ab.byteLength); 39265 var view = new Uint8Array(ab); 39266 39267 for (var i = 0; i < buffer.length; ++i) { 39268 buffer[i] = view[i]; 39269 } 39270 39271 return buffer; 39272 } 39273 39274 function checkArgument(expression, message) { 39275 if (!expression) { 39276 throw message; 39277 } 39278 } // The `glyf` table describes the glyphs in TrueType outline format. 39279 // Parse the coordinate data for a glyph. 39280 39281 39282 function parseGlyphCoordinate(p, flag, previousValue, shortVectorBitMask, sameBitMask) { 39283 var v; 39284 39285 if ((flag & shortVectorBitMask) > 0) { 39286 // The coordinate is 1 byte long. 39287 v = p.parseByte(); // The `same` bit is re-used for short values to signify the sign of the value. 39288 39289 if ((flag & sameBitMask) === 0) { 39290 v = -v; 39291 } 39292 39293 v = previousValue + v; 39294 } else { 39295 // The coordinate is 2 bytes long. 39296 // If the `same` bit is set, the coordinate is the same as the previous coordinate. 39297 if ((flag & sameBitMask) > 0) { 39298 v = previousValue; 39299 } else { 39300 // Parse the coordinate as a signed 16-bit delta value. 39301 v = previousValue + p.parseShort(); 39302 } 39303 } 39304 39305 return v; 39306 } // Parse a TrueType glyph. 39307 39308 39309 function parseGlyph(glyph, data, start) { 39310 var p = new parse.Parser(data, start); 39311 glyph.numberOfContours = p.parseShort(); 39312 glyph._xMin = p.parseShort(); 39313 glyph._yMin = p.parseShort(); 39314 glyph._xMax = p.parseShort(); 39315 glyph._yMax = p.parseShort(); 39316 var flags; 39317 var flag; 39318 39319 if (glyph.numberOfContours > 0) { 39320 // This glyph is not a composite. 39321 var endPointIndices = glyph.endPointIndices = []; 39322 39323 for (var i = 0; i < glyph.numberOfContours; i += 1) { 39324 endPointIndices.push(p.parseUShort()); 39325 } 39326 39327 glyph.instructionLength = p.parseUShort(); 39328 glyph.instructions = []; 39329 39330 for (var i$1 = 0; i$1 < glyph.instructionLength; i$1 += 1) { 39331 glyph.instructions.push(p.parseByte()); 39332 } 39333 39334 var numberOfCoordinates = endPointIndices[endPointIndices.length - 1] + 1; 39335 flags = []; 39336 39337 for (var i$2 = 0; i$2 < numberOfCoordinates; i$2 += 1) { 39338 flag = p.parseByte(); 39339 flags.push(flag); // If bit 3 is set, we repeat this flag n times, where n is the next byte. 39340 39341 if ((flag & 8) > 0) { 39342 var repeatCount = p.parseByte(); 39343 39344 for (var j = 0; j < repeatCount; j += 1) { 39345 flags.push(flag); 39346 i$2 += 1; 39347 } 39348 } 39349 } 39350 39351 check.argument(flags.length === numberOfCoordinates, 'Bad flags.'); 39352 39353 if (endPointIndices.length > 0) { 39354 var points = []; 39355 var point; // X/Y coordinates are relative to the previous point, except for the first point which is relative to 0,0. 39356 39357 if (numberOfCoordinates > 0) { 39358 for (var i$3 = 0; i$3 < numberOfCoordinates; i$3 += 1) { 39359 flag = flags[i$3]; 39360 point = {}; 39361 point.onCurve = !!(flag & 1); 39362 point.lastPointOfContour = endPointIndices.indexOf(i$3) >= 0; 39363 points.push(point); 39364 } 39365 39366 var px = 0; 39367 39368 for (var i$4 = 0; i$4 < numberOfCoordinates; i$4 += 1) { 39369 flag = flags[i$4]; 39370 point = points[i$4]; 39371 point.x = parseGlyphCoordinate(p, flag, px, 2, 16); 39372 px = point.x; 39373 } 39374 39375 var py = 0; 39376 39377 for (var i$5 = 0; i$5 < numberOfCoordinates; i$5 += 1) { 39378 flag = flags[i$5]; 39379 point = points[i$5]; 39380 point.y = parseGlyphCoordinate(p, flag, py, 4, 32); 39381 py = point.y; 39382 } 39383 } 39384 39385 glyph.points = points; 39386 } else { 39387 glyph.points = []; 39388 } 39389 } else if (glyph.numberOfContours === 0) { 39390 glyph.points = []; 39391 } else { 39392 glyph.isComposite = true; 39393 glyph.points = []; 39394 glyph.components = []; 39395 var moreComponents = true; 39396 39397 while (moreComponents) { 39398 flags = p.parseUShort(); 39399 var component = { 39400 glyphIndex: p.parseUShort(), 39401 xScale: 1, 39402 scale01: 0, 39403 scale10: 0, 39404 yScale: 1, 39405 dx: 0, 39406 dy: 0 39407 }; 39408 39409 if ((flags & 1) > 0) { 39410 // The arguments are words 39411 if ((flags & 2) > 0) { 39412 // values are offset 39413 component.dx = p.parseShort(); 39414 component.dy = p.parseShort(); 39415 } else { 39416 // values are matched points 39417 component.matchedPoints = [p.parseUShort(), p.parseUShort()]; 39418 } 39419 } else { 39420 // The arguments are bytes 39421 if ((flags & 2) > 0) { 39422 // values are offset 39423 component.dx = p.parseChar(); 39424 component.dy = p.parseChar(); 39425 } else { 39426 // values are matched points 39427 component.matchedPoints = [p.parseByte(), p.parseByte()]; 39428 } 39429 } 39430 39431 if ((flags & 8) > 0) { 39432 // We have a scale 39433 component.xScale = component.yScale = p.parseF2Dot14(); 39434 } else if ((flags & 64) > 0) { 39435 // We have an X / Y scale 39436 component.xScale = p.parseF2Dot14(); 39437 component.yScale = p.parseF2Dot14(); 39438 } else if ((flags & 128) > 0) { 39439 // We have a 2x2 transformation 39440 component.xScale = p.parseF2Dot14(); 39441 component.scale01 = p.parseF2Dot14(); 39442 component.scale10 = p.parseF2Dot14(); 39443 component.yScale = p.parseF2Dot14(); 39444 } 39445 39446 glyph.components.push(component); 39447 moreComponents = !!(flags & 32); 39448 } 39449 39450 if (flags & 0x100) { 39451 // We have instructions 39452 glyph.instructionLength = p.parseUShort(); 39453 glyph.instructions = []; 39454 39455 for (var i$6 = 0; i$6 < glyph.instructionLength; i$6 += 1) { 39456 glyph.instructions.push(p.parseByte()); 39457 } 39458 } 39459 } 39460 } // Transform an array of points and return a new array. 39461 39462 39463 function transformPoints(points, transform) { 39464 var newPoints = []; 39465 39466 for (var i = 0; i < points.length; i += 1) { 39467 var pt = points[i]; 39468 var newPt = { 39469 x: transform.xScale * pt.x + transform.scale01 * pt.y + transform.dx, 39470 y: transform.scale10 * pt.x + transform.yScale * pt.y + transform.dy, 39471 onCurve: pt.onCurve, 39472 lastPointOfContour: pt.lastPointOfContour 39473 }; 39474 newPoints.push(newPt); 39475 } 39476 39477 return newPoints; 39478 } 39479 39480 function getContours(points) { 39481 var contours = []; 39482 var currentContour = []; 39483 39484 for (var i = 0; i < points.length; i += 1) { 39485 var pt = points[i]; 39486 currentContour.push(pt); 39487 39488 if (pt.lastPointOfContour) { 39489 contours.push(currentContour); 39490 currentContour = []; 39491 } 39492 } 39493 39494 check.argument(currentContour.length === 0, 'There are still points left in the current contour.'); 39495 return contours; 39496 } // Convert the TrueType glyph outline to a Path. 39497 39498 39499 function getPath(points) { 39500 var p = new Path(); 39501 39502 if (!points) { 39503 return p; 39504 } 39505 39506 var contours = getContours(points); 39507 39508 for (var contourIndex = 0; contourIndex < contours.length; ++contourIndex) { 39509 var contour = contours[contourIndex]; 39510 var prev = null; 39511 var curr = contour[contour.length - 1]; 39512 var next = contour[0]; 39513 39514 if (curr.onCurve) { 39515 p.moveTo(curr.x, curr.y); 39516 } else { 39517 if (next.onCurve) { 39518 p.moveTo(next.x, next.y); 39519 } else { 39520 // If both first and last points are off-curve, start at their middle. 39521 var start = { 39522 x: (curr.x + next.x) * 0.5, 39523 y: (curr.y + next.y) * 0.5 39524 }; 39525 p.moveTo(start.x, start.y); 39526 } 39527 } 39528 39529 for (var i = 0; i < contour.length; ++i) { 39530 prev = curr; 39531 curr = next; 39532 next = contour[(i + 1) % contour.length]; 39533 39534 if (curr.onCurve) { 39535 // This is a straight line. 39536 p.lineTo(curr.x, curr.y); 39537 } else { 39538 var prev2 = prev; 39539 var next2 = next; 39540 39541 if (!prev.onCurve) { 39542 prev2 = { 39543 x: (curr.x + prev.x) * 0.5, 39544 y: (curr.y + prev.y) * 0.5 39545 }; 39546 } 39547 39548 if (!next.onCurve) { 39549 next2 = { 39550 x: (curr.x + next.x) * 0.5, 39551 y: (curr.y + next.y) * 0.5 39552 }; 39553 } 39554 39555 p.quadraticCurveTo(curr.x, curr.y, next2.x, next2.y); 39556 } 39557 } 39558 39559 p.closePath(); 39560 } 39561 39562 return p; 39563 } 39564 39565 function buildPath(glyphs, glyph) { 39566 if (glyph.isComposite) { 39567 for (var j = 0; j < glyph.components.length; j += 1) { 39568 var component = glyph.components[j]; 39569 var componentGlyph = glyphs.get(component.glyphIndex); // Force the ttfGlyphLoader to parse the glyph. 39570 39571 componentGlyph.getPath(); 39572 39573 if (componentGlyph.points) { 39574 var transformedPoints = void 0; 39575 39576 if (component.matchedPoints === undefined) { 39577 // component positioned by offset 39578 transformedPoints = transformPoints(componentGlyph.points, component); 39579 } else { 39580 // component positioned by matched points 39581 if (component.matchedPoints[0] > glyph.points.length - 1 || component.matchedPoints[1] > componentGlyph.points.length - 1) { 39582 throw Error('Matched points out of range in ' + glyph.name); 39583 } 39584 39585 var firstPt = glyph.points[component.matchedPoints[0]]; 39586 var secondPt = componentGlyph.points[component.matchedPoints[1]]; 39587 var transform = { 39588 xScale: component.xScale, 39589 scale01: component.scale01, 39590 scale10: component.scale10, 39591 yScale: component.yScale, 39592 dx: 0, 39593 dy: 0 39594 }; 39595 secondPt = transformPoints([secondPt], transform)[0]; 39596 transform.dx = firstPt.x - secondPt.x; 39597 transform.dy = firstPt.y - secondPt.y; 39598 transformedPoints = transformPoints(componentGlyph.points, transform); 39599 } 39600 39601 glyph.points = glyph.points.concat(transformedPoints); 39602 } 39603 } 39604 } 39605 39606 return getPath(glyph.points); 39607 } // Parse all the glyphs according to the offsets from the `loca` table. 39608 39609 39610 function parseGlyfTable(data, start, loca, font) { 39611 var glyphs = new glyphset.GlyphSet(font);
39611 // The last element of the loca table is invalid. 39612 39613 for (var i = 0; i < loca.length - 1; i += 1) { 39614 var offset = loca[i]; 39615 var nextOffset = loca[i + 1]; 39616 39617 if (offset !== nextOffset) { 39618 glyphs.push(i, glyphset.ttfGlyphLoader(font, i, parseGlyph, data, start + offset, buildPath)); 39619 } else { 39620 glyphs.push(i, glyphset.glyphLoader(font, i)); 39621 } 39622 } 39623 39624 return glyphs; 39625 } 39626 39627 var glyf = { 39628 getPath: getPath, 39629 parse: parseGlyfTable 39630 }; 39631 /* A TrueType font hinting interpreter. 39632 * 39633 * (c) 2017 Axel Kittenberger 39634 * 39635 * This interpreter has been implemented according to this documentation: 39636 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM05/Chap5.html 39637 * 39638 * According to the documentation F24DOT6 values are used for pixels. 39639 * That means calculation is 1/64 pixel accurate and uses integer operations. 39640 * However, Javascript has floating point operations by default and only 39641 * those are available. One could make a case to simulate the 1/64 accuracy 39642 * exactly by truncating after every division operation 39643 * (for example with << 0) to get pixel exactly results as other TrueType 39644 * implementations. It may make sense since some fonts are pixel optimized 39645 * by hand using DELTAP instructions. The current implementation doesn't 39646 * and rather uses full floating point precision. 39647 * 39648 * xScale, yScale and rotation is currently ignored. 39649 * 39650 * A few non-trivial instructions are missing as I didn't encounter yet 39651 * a font that used them to test a possible implementation. 39652 * 39653 * Some fonts seem to use undocumented features regarding the twilight zone. 39654 * Only some of them are implemented as they were encountered. 39655 * 39656 * The exports.DEBUG statements are removed on the minified distribution file. 39657 */ 39658 39659 var instructionTable; 39660 var exec; 39661 var execGlyph; 39662 var execComponent; 39663 /* 39664 * Creates a hinting object. 39665 * 39666 * There ought to be exactly one 39667 * for each truetype font that is used for hinting. 39668 */ 39669 39670 function Hinting(font) { 39671 // the font this hinting object is for 39672 this.font = font; 39673 39674 this.getCommands = function (hPoints) { 39675 return glyf.getPath(hPoints).commands; 39676 }; // cached states 39677 39678 39679 this._fpgmState = this._prepState = undefined; // errorState 39680 // 0 ... all okay 39681 // 1 ... had an error in a glyf, 39682 // continue working but stop spamming 39683 // the console 39684 // 2 ... error at prep, stop hinting at this ppem 39685 // 3 ... error at fpeg, stop hinting for this font at all 39686 39687 this._errorState = 0; 39688 } 39689 /* 39690 * Not rounding. 39691 */ 39692 39693 39694 function roundOff(v) { 39695 return v; 39696 } 39697 /* 39698 * Rounding to grid. 39699 */ 39700 39701 39702 function roundToGrid(v) { 39703 //Rounding in TT is supposed to "symmetrical around zero" 39704 return Math.sign(v) * Math.round(Math.abs(v)); 39705 } 39706 /* 39707 * Rounding to double grid. 39708 */ 39709 39710 39711 function roundToDoubleGrid(v) { 39712 return Math.sign(v) * Math.round(Math.abs(v * 2)) / 2; 39713 } 39714 /* 39715 * Rounding to half grid. 39716 */ 39717 39718 39719 function roundToHalfGrid(v) { 39720 return Math.sign(v) * (Math.round(Math.abs(v) + 0.5) - 0.5); 39721 } 39722 /* 39723 * Rounding to up to grid. 39724 */ 39725 39726 39727 function roundUpToGrid(v) { 39728 return Math.sign(v) * Math.ceil(Math.abs(v)); 39729 } 39730 /* 39731 * Rounding to down to grid. 39732 */ 39733 39734 39735 function roundDownToGrid(v) { 39736 return Math.sign(v) * Math.floor(Math.abs(v)); 39737 } 39738 /* 39739 * Super rounding. 39740 */ 39741 39742 39743 var roundSuper = function (v) {
vendor: 71,121 bytes, lines 39744-42332
39744 var period = this.srPeriod; 39745 var phase = this.srPhase; 39746 var threshold = this.srThreshold; 39747 var sign = 1; 39748 39749 if (v < 0) { 39750 v = -v; 39751 sign = -1; 39752 } 39753 39754 v += threshold - phase; 39755 v = Math.trunc(v / period) * period; 39756 v += phase; // according to http://xgridfit.sourceforge.net/round.html 39757 39758 if (v < 0) { 39759 return phase * sign; 39760 } 39761 39762 return v * sign; 39763 }; 39764 /* 39765 * Unit vector of x-axis. 39766 */ 39767 39768 39769 var xUnitVector = { 39770 x: 1, 39771 y: 0, 39772 axis: 'x', 39773 // Gets the projected distance between two points. 39774 // o1/o2 ... if true, respective original position is used. 39775 distance: function (p1, p2, o1, o2) { 39776 return (o1 ? p1.xo : p1.x) - (o2 ? p2.xo : p2.x); 39777 }, 39778 // Moves point p so the moved position has the same relative 39779 // position to the moved positions of rp1 and rp2 than the 39780 // original positions had. 39781 // 39782 // See APPENDIX on INTERPOLATE at the bottom of this file. 39783 interpolate: function (p, rp1, rp2, pv) { 39784 var do1; 39785 var do2; 39786 var doa1; 39787 var doa2; 39788 var dm1; 39789 var dm2; 39790 var dt; 39791 39792 if (!pv || pv === this) { 39793 do1 = p.xo - rp1.xo; 39794 do2 = p.xo - rp2.xo; 39795 dm1 = rp1.x - rp1.xo; 39796 dm2 = rp2.x - rp2.xo; 39797 doa1 = Math.abs(do1); 39798 doa2 = Math.abs(do2); 39799 dt = doa1 + doa2; 39800 39801 if (dt === 0) { 39802 p.x = p.xo + (dm1 + dm2) / 2; 39803 return; 39804 } 39805 39806 p.x = p.xo + (dm1 * doa2 + dm2 * doa1) / dt; 39807 return; 39808 } 39809 39810 do1 = pv.distance(p, rp1, true, true); 39811 do2 = pv.distance(p, rp2, true, true); 39812 dm1 = pv.distance(rp1, rp1, false, true); 39813 dm2 = pv.distance(rp2, rp2, false, true); 39814 doa1 = Math.abs(do1); 39815 doa2 = Math.abs(do2); 39816 dt = doa1 + doa2; 39817 39818 if (dt === 0) { 39819 xUnitVector.setRelative(p, p, (dm1 + dm2) / 2, pv, true); 39820 return; 39821 } 39822 39823 xUnitVector.setRelative(p, p, (dm1 * doa2 + dm2 * doa1) / dt, pv, true); 39824 }, 39825 // Slope of line normal to this 39826 normalSlope: Number.NEGATIVE_INFINITY, 39827 // Sets the point 'p' relative to point 'rp' 39828 // by the distance 'd'. 39829 // 39830 // See APPENDIX on SETRELATIVE at the bottom of this file. 39831 // 39832 // p ... point to set 39833 // rp ... reference point 39834 // d ... distance on projection vector 39835 // pv ... projection vector (undefined = this) 39836 // org ... if true, uses the original position of rp as reference. 39837 setRelative: function (p, rp, d, pv, org) { 39838 if (!pv || pv === this) { 39839 p.x = (org ? rp.xo : rp.x) + d; 39840 return; 39841 } 39842 39843 var rpx = org ? rp.xo : rp.x; 39844 var rpy = org ? rp.yo : rp.y; 39845 var rpdx = rpx + d * pv.x; 39846 var rpdy = rpy + d * pv.y; 39847 p.x = rpdx + (p.y - rpdy) / pv.normalSlope; 39848 }, 39849 // Slope of vector line. 39850 slope: 0, 39851 // Touches the point p. 39852 touch: function (p) { 39853 p.xTouched = true; 39854 }, 39855 // Tests if a point p is touched. 39856 touched: function (p) { 39857 return p.xTouched; 39858 }, 39859 // Untouches the point p. 39860 untouch: function (p) { 39861 p.xTouched = false; 39862 } 39863 }; 39864 /* 39865 * Unit vector of y-axis. 39866 */ 39867 39868 var yUnitVector = { 39869 x: 0, 39870 y: 1, 39871 axis: 'y', 39872 // Gets the projected distance between two points. 39873 // o1/o2 ... if true, respective original position is used. 39874 distance: function (p1, p2, o1, o2) { 39875 return (o1 ? p1.yo : p1.y) - (o2 ? p2.yo : p2.y); 39876 }, 39877 // Moves point p so the moved position has the same relative 39878 // position to the moved positions of rp1 and rp2 than the 39879 // original positions had. 39880 // 39881 // See APPENDIX on INTERPOLATE at the bottom of this file. 39882 interpolate: function (p, rp1, rp2, pv) { 39883 var do1; 39884 var do2; 39885 var doa1; 39886 var doa2; 39887 var dm1; 39888 var dm2; 39889 var dt; 39890 39891 if (!pv || pv === this) { 39892 do1 = p.yo - rp1.yo; 39893 do2 = p.yo - rp2.yo; 39894 dm1 = rp1.y - rp1.yo; 39895 dm2 = rp2.y - rp2.yo; 39896 doa1 = Math.abs(do1); 39897 doa2 = Math.abs(do2); 39898 dt = doa1 + doa2; 39899 39900 if (dt === 0) { 39901 p.y = p.yo + (dm1 + dm2) / 2; 39902 return; 39903 } 39904 39905 p.y = p.yo + (dm1 * doa2 + dm2 * doa1) / dt; 39906 return; 39907 } 39908 39909 do1 = pv.distance(p, rp1, true, true); 39910 do2 = pv.distance(p, rp2, true, true); 39911 dm1 = pv.distance(rp1, rp1, false, true); 39912 dm2 = pv.distance(rp2, rp2, false, true); 39913 doa1 = Math.abs(do1); 39914 doa2 = Math.abs(do2); 39915 dt = doa1 + doa2; 39916 39917 if (dt === 0) { 39918 yUnitVector.setRelative(p, p, (dm1 + dm2) / 2, pv, true); 39919 return; 39920 } 39921 39922 yUnitVector.setRelative(p, p, (dm1 * doa2 + dm2 * doa1) / dt, pv, true); 39923 }, 39924 // Slope of line normal to this. 39925 normalSlope: 0, 39926 // Sets the point 'p' relative to point 'rp' 39927 // by the distance 'd' 39928 // 39929 // See APPENDIX on SETRELATIVE at the bottom of this file. 39930 // 39931 // p ... point to set 39932 // rp ... reference point 39933 // d ... distance on projection vector 39934 // pv ... projection vector (undefined = this) 39935 // org ... if true, uses the original position of rp as reference. 39936 setRelative: function (p, rp, d, pv, org) { 39937 if (!pv || pv === this) { 39938 p.y = (org ? rp.yo : rp.y) + d; 39939 return; 39940 } 39941 39942 var rpx = org ? rp.xo : rp.x; 39943 var rpy = org ? rp.yo : rp.y; 39944 var rpdx = rpx + d * pv.x; 39945 var rpdy = rpy + d * pv.y; 39946 p.y = rpdy + pv.normalSlope * (p.x - rpdx); 39947 }, 39948 // Slope of vector line. 39949 slope: Number.POSITIVE_INFINITY, 39950 // Touches the point p. 39951 touch: function (p) { 39952 p.yTouched = true; 39953 }, 39954 // Tests if a point p is touched. 39955 touched: function (p) { 39956 return p.yTouched; 39957 }, 39958 // Untouches the point p. 39959 untouch: function (p) { 39960 p.yTouched = false; 39961 } 39962 }; 39963 Object.freeze(xUnitVector); 39964 Object.freeze(yUnitVector); 39965 /* 39966 * Creates a unit vector that is not x- or y-axis. 39967 */ 39968 39969 function UnitVector(x, y) { 39970 this.x = x; 39971 this.y = y; 39972 this.axis = undefined; 39973 this.slope = y / x; 39974 this.normalSlope = -x / y; 39975 Object.freeze(this); 39976 } 39977 /* 39978 * Gets the projected distance between two points. 39979 * o1/o2 ... if true, respective original position is used. 39980 */ 39981 39982 39983 UnitVector.prototype.distance = function (p1, p2, o1, o2) { 39984 return this.x * xUnitVector.distance(p1, p2, o1, o2) + this.y * yUnitVector.distance(p1, p2, o1, o2); 39985 }; 39986 /* 39987 * Moves point p so the moved position has the same relative 39988 * position to the moved positions of rp1 and rp2 than the 39989 * original positions had. 39990 * 39991 * See APPENDIX on INTERPOLATE at the bottom of this file. 39992 */ 39993 39994 39995 UnitVector.prototype.interpolate = function (p, rp1, rp2, pv) { 39996 var dm1; 39997 var dm2; 39998 var do1; 39999 var do2; 40000 var doa1; 40001 var doa2; 40002 var dt; 40003 do1 = pv.distance(p, rp1, true, true); 40004 do2 = pv.distance(p, rp2, true, true); 40005 dm1 = pv.distance(rp1, rp1, false, true); 40006 dm2 = pv.distance(rp2, rp2, false, true); 40007 doa1 = Math.abs(do1); 40008 doa2 = Math.abs(do2); 40009 dt = doa1 + doa2; 40010 40011 if (dt === 0) { 40012 this.setRelative(p, p, (dm1 + dm2) / 2, pv, true); 40013 return; 40014 } 40015 40016 this.setRelative(p, p, (dm1 * doa2 + dm2 * doa1) / dt, pv, true); 40017 }; 40018 /* 40019 * Sets the point 'p' relative to point 'rp' 40020 * by the distance 'd' 40021 * 40022 * See APPENDIX on SETRELATIVE at the bottom of this file. 40023 * 40024 * p ... point to set 40025 * rp ... reference point 40026 * d ... distance on projection vector 40027 * pv ... projection vector (undefined = this) 40028 * org ... if true, uses the original position of rp as reference. 40029 */ 40030 40031 40032 UnitVector.prototype.setRelative = function (p, rp, d, pv, org) { 40033 pv = pv || this; 40034 var rpx = org ? rp.xo : rp.x; 40035 var rpy = org ? rp.yo : rp.y; 40036 var rpdx = rpx + d * pv.x; 40037 var rpdy = rpy + d * pv.y; 40038 var pvns = pv.normalSlope; 40039 var fvs = this.slope; 40040 var px = p.x; 40041 var py = p.y; 40042 p.x = (fvs * px - pvns * rpdx + rpdy - py) / (fvs - pvns); 40043 p.y = fvs * (p.x - px) + py; 40044 }; 40045 /* 40046 * Touches the point p. 40047 */ 40048 40049 40050 UnitVector.prototype.touch = function (p) { 40051 p.xTouched = true; 40052 p.yTouched = true; 40053 }; 40054 /* 40055 * Returns a unit vector with x/y coordinates. 40056 */ 40057 40058 40059 function getUnitVector(x, y) { 40060 var d = Math.sqrt(x * x + y * y); 40061 x /= d; 40062 y /= d; 40063 40064 if (x === 1 && y === 0) { 40065 return xUnitVector; 40066 } else if (x === 0 && y === 1) { 40067 return yUnitVector; 40068 } else { 40069 return new UnitVector(x, y); 40070 } 40071 } 40072 /* 40073 * Creates a point in the hinting engine. 40074 */ 40075 40076 40077 function HPoint(x, y, lastPointOfContour, onCurve) { 40078 this.x = this.xo = Math.round(x * 64) / 64; // hinted x value and original x-value 40079 40080 this.y = this.yo = Math.round(y * 64) / 64; // hinted y value and original y-value 40081 40082 this.lastPointOfContour = lastPointOfContour; 40083 this.onCurve = onCurve; 40084 this.prevPointOnContour = undefined; 40085 this.nextPointOnContour = undefined; 40086 this.xTouched = false; 40087 this.yTouched = false; 40088 Object.preventExtensions(this); 40089 } 40090 /* 40091 * Returns the next touched point on the contour. 40092 * 40093 * v ... unit vector to test touch axis. 40094 */ 40095 40096 40097 HPoint.prototype.nextTouched = function (v) { 40098 var p = this.nextPointOnContour; 40099 40100 while (!v.touched(p) && p !== this) { 40101 p = p.nextPointOnContour; 40102 } 40103 40104 return p; 40105 }; 40106 /* 40107 * Returns the previous touched point on the contour 40108 * 40109 * v ... unit vector to test touch axis. 40110 */ 40111 40112 40113 HPoint.prototype.prevTouched = function (v) { 40114 var p = this.prevPointOnContour; 40115 40116 while (!v.touched(p) && p !== this) { 40117 p = p.prevPointOnContour; 40118 } 40119 40120 return p; 40121 }; 40122 /* 40123 * The zero point. 40124 */ 40125 40126 40127 var HPZero = Object.freeze(new HPoint(0, 0)); 40128 /* 40129 * The default state of the interpreter. 40130 * 40131 * Note: Freezing the defaultState and then deriving from it 40132 * makes the V8 Javascript engine going awkward, 40133 * so this is avoided, albeit the defaultState shouldn't 40134 * ever change. 40135 */ 40136 40137 var defaultState = { 40138 cvCutIn: 17 / 16, 40139 // control value cut in 40140 deltaBase: 9, 40141 deltaShift: 0.125, 40142 loop: 1, 40143 // loops some instructions 40144 minDis: 1, 40145 // minimum distance 40146 autoFlip: true 40147 }; 40148 /* 40149 * The current state of the interpreter. 40150 * 40151 * env ... 'fpgm' or 'prep' or 'glyf' 40152 * prog ... the program 40153 */ 40154 40155 function State(env, prog) { 40156 this.env = env; 40157 this.stack = []; 40158 this.prog = prog; 40159 40160 switch (env) { 40161 case 'glyf': 40162 this.zp0 = this.zp1 = this.zp2 = 1; 40163 this.rp0 = this.rp1 = this.rp2 = 0; 40164 40165 /* fall through */ 40166 40167 case 'prep': 40168 this.fv = this.pv = this.dpv = xUnitVector; 40169 this.round = roundToGrid; 40170 } 40171 } 40172 /* 40173 * Executes a glyph program. 40174 * 40175 * This does the hinting for each glyph. 40176 * 40177 * Returns an array of moved points. 40178 * 40179 * glyph: the glyph to hint 40180 * ppem: the size the glyph is rendered for 40181 */ 40182 40183 40184 Hinting.prototype.exec = function (glyph, ppem) { 40185 if (typeof ppem !== 'number') { 40186 throw new Error('Point size is not a number!'); 40187 } // Received a fatal error, don't do any hinting anymore. 40188 40189 40190 if (this._errorState > 2) { 40191 return; 40192 } 40193 40194 var font = this.font; 40195 var prepState = this._prepState; 40196 40197 if (!prepState || prepState.ppem !== ppem) { 40198 var fpgmState = this._fpgmState; 40199 40200 if (!fpgmState) { 40201 // Executes the fpgm state. 40202 // This is used by fonts to define functions. 40203 State.prototype = defaultState; 40204 fpgmState = this._fpgmState = new State('fpgm', font.tables.fpgm); 40205 fpgmState.funcs = []; 40206 fpgmState.font = font; 40207 40208 if (exports.DEBUG) { 40209 console.log('---EXEC FPGM---'); 40210 fpgmState.step = -1; 40211 } 40212 40213 try { 40214 exec(fpgmState); 40215 } catch (e) { 40216 console.log('Hinting error in FPGM:' + e); 40217 this._errorState = 3; 40218 return; 40219 } 40220 } // Executes the prep program for this ppem setting. 40221 // This is used by fonts to set cvt values 40222 // depending on to be rendered font size. 40223 40224 40225 State.prototype = fpgmState; 40226 prepState = this._prepState = new State('prep', font.tables.prep); 40227 prepState.ppem = ppem; // Creates a copy of the cvt table 40228 // and scales it to the current ppem setting. 40229 40230 var oCvt = font.tables.cvt; 40231 40232 if (oCvt) { 40233 var cvt = prepState.cvt = new Array(oCvt.length); 40234 var scale = ppem / font.unitsPerEm; 40235 40236 for (var c = 0; c < oCvt.length; c++) { 40237 cvt[c] = oCvt[c] * scale; 40238 } 40239 } else { 40240 prepState.cvt = []; 40241 } 40242 40243 if (exports.DEBUG) { 40244 console.log('---EXEC PREP---'); 40245 prepState.step = -1; 40246 } 40247 40248 try { 40249 exec(prepState); 40250 } catch (e) { 40251 if (this._errorState < 2) { 40252 console.log('Hinting error in PREP:' + e); 40253 } 40254 40255 this._errorState = 2; 40256 } 40257 } 40258 40259 if (this._errorState > 1) { 40260 return; 40261 } 40262 40263 try { 40264 return execGlyph(glyph, prepState); 40265 } catch (e) { 40266 if (this._errorState < 1) { 40267 console.log('Hinting error:' + e); 40268 console.log('Note: further hinting errors are silenced'); 40269 } 40270 40271 this._errorState = 1; 40272 return undefined; 40273 } 40274 }; 40275 /* 40276 * Executes the hinting program for a glyph. 40277 */ 40278 40279 40280 execGlyph = function (glyph, prepState) { 40281 // original point positions 40282 var xScale = prepState.ppem / prepState.font.unitsPerEm; 40283 var yScale = xScale; 40284 var components = glyph.components; 40285 var contours; 40286 var gZone; 40287 var state; 40288 State.prototype = prepState; 40289 40290 if (!components) { 40291 state = new State('glyf', glyph.instructions); 40292 40293 if (exports.DEBUG) { 40294 console.log('---EXEC GLYPH---'); 40295 state.step = -1; 40296 } 40297 40298 execComponent(glyph, state, xScale, yScale); 40299 gZone = state.gZone; 40300 } else { 40301 var font = prepState.font; 40302 gZone = []; 40303 contours = []; 40304 40305 for (var i = 0; i < components.length; i++) { 40306 var c = components[i]; 40307 var cg = font.glyphs.get(c.glyphIndex); 40308 state = new State('glyf', cg.instructions); 40309 40310 if (exports.DEBUG) { 40311 console.log('---EXEC COMP ' + i + '---'); 40312 state.step = -1; 40313 } 40314 40315 execComponent(cg, state, xScale, yScale); // appends the computed points to the result array 40316 // post processes the component points 40317 40318 var dx = Math.round(c.dx * xScale); 40319 var dy = Math.round(c.dy * yScale); 40320 var gz = state.gZone; 40321 var cc = state.contours; 40322 40323 for (var pi = 0; pi < gz.length; pi++) { 40324 var p = gz[pi]; 40325 p.xTouched = p.yTouched = false; 40326 p.xo = p.x = p.x + dx; 40327 p.yo = p.y = p.y + dy; 40328 } 40329 40330 var gLen = gZone.length; 40331 gZone.push.apply(gZone, gz); 40332 40333 for (var j = 0; j < cc.length; j++) { 40334 contours.push(cc[j] + gLen); 40335 } 40336 } 40337 40338 if (glyph.instructions && !state.inhibitGridFit) { 40339 // the composite has instructions on its own 40340 state = new State('glyf', glyph.instructions); 40341 state.gZone = state.z0 = state.z1 = state.z2 = gZone; 40342 state.contours = contours; // note: HPZero cannot be used here, since 40343 // the point might be modified 40344 40345 gZone.push(new HPoint(0, 0), new HPoint(Math.round(glyph.advanceWidth * xScale), 0)); 40346 40347 if (exports.DEBUG) { 40348 console.log('---EXEC COMPOSITE---'); 40349 state.step = -1; 40350 } 40351 40352 exec(state); 40353 gZone.length -= 2; 40354 } 40355 } 40356 40357 return gZone; 40358 }; 40359 /* 40360 * Executes the hinting program for a component of a multi-component glyph 40361 * or of the glyph itself for a non-component glyph. 40362 */ 40363 40364 40365 execComponent = function (glyph, state, xScale, yScale) { 40366 var points = glyph.points || []; 40367 var pLen = points.length; 40368 var gZone = state.gZone = state.z0 = state.z1 = state.z2 = []; 40369 var contours = state.contours = []; // Scales the original points and 40370 // makes copies for the hinted points. 40371 40372 var cp; // current point 40373 40374 for (var i = 0; i < pLen; i++) { 40375 cp = points[i]; 40376 gZone[i] = new HPoint(cp.x * xScale, cp.y * yScale, cp.lastPointOfContour, cp.onCurve); 40377 } // Chain links the contours. 40378 40379 40380 var sp; // start point 40381 40382 var np; // next point 40383 40384 for (var i$1 = 0; i$1 < pLen; i$1++) { 40385 cp = gZone[i$1]; 40386 40387 if (!sp) { 40388 sp = cp; 40389 contours.push(i$1); 40390 } 40391 40392 if (cp.lastPointOfContour) { 40393 cp.nextPointOnContour = sp; 40394 sp.prevPointOnContour = cp; 40395 sp = undefined; 40396 } else { 40397 np = gZone[i$1 + 1]; 40398 cp.nextPointOnContour = np; 40399 np.prevPointOnContour = cp; 40400 } 40401 } 40402 40403 if (state.inhibitGridFit) { 40404 return; 40405 } 40406 40407 if (exports.DEBUG) { 40408 console.log('PROCESSING GLYPH', state.stack); 40409 40410 for (var i$2 = 0; i$2 < pLen; i$2++) { 40411 console.log(i$2, gZone[i$2].x, gZone[i$2].y); 40412 } 40413 } 40414 40415 gZone.push(new HPoint(0, 0), new HPoint(Math.round(glyph.advanceWidth * xScale), 0)); 40416 exec(state); // Removes the extra points. 40417 40418 gZone.length -= 2; 40419 40420 if (exports.DEBUG) { 40421 console.log('FINISHED GLYPH', state.stack); 40422 40423 for (var i$3 = 0; i$3 < pLen; i$3++) { 40424 console.log(i$3, gZone[i$3].x, gZone[i$3].y); 40425 } 40426 } 40427 }; 40428 /* 40429 * Executes the program loaded in state. 40430 */ 40431 40432 40433 exec = function (state) { 40434 var prog = state.prog; 40435 40436 if (!prog) { 40437 return; 40438 } 40439 40440 var pLen = prog.length; 40441 var ins; 40442 40443 for (state.ip = 0; state.ip < pLen; state.ip++) { 40444 if (exports.DEBUG) { 40445 state.step++; 40446 } 40447 40448 ins = instructionTable[prog[state.ip]]; 40449 40450 if (!ins) { 40451 throw new Error('unknown instruction: 0x' + Number(prog[state.ip]).toString(16)); 40452 } 40453 40454 ins(state); // very extensive debugging for each step 40455 40456 /* 40457 if (exports.DEBUG) { 40458 var da; 40459 if (state.gZone) { 40460 da = []; 40461 for (let i = 0; i < state.gZone.length; i++) 40462 { 40463 da.push(i + ' ' + 40464 state.gZone[i].x * 64 + ' ' + 40465 state.gZone[i].y * 64 + ' ' + 40466 (state.gZone[i].xTouched ? 'x' : '') + 40467 (state.gZone[i].yTouched ? 'y' : '') 40468 ); 40469 } 40470 console.log('GZ', da); 40471 } 40472 if (state.tZone) { 40473 da = []; 40474 for (let i = 0; i < state.tZone.length; i++) { 40475 da.push(i + ' ' + 40476 state.tZone[i].x * 64 + ' ' + 40477 state.tZone[i].y * 64 + ' ' + 40478 (state.tZone[i].xTouched ? 'x' : '') + 40479 (state.tZone[i].yTouched ? 'y' : '') 40480 ); 40481 } 40482 console.log('TZ', da); 40483 } 40484 if (state.stack.length > 10) { 40485 console.log( 40486 state.stack.length, 40487 '...', state.stack.slice(state.stack.length - 10) 40488 ); 40489 } else { 40490 console.log(state.stack.length, state.stack); 40491 } 40492 } 40493 */ 40494 } 40495 }; 40496 /* 40497 * Initializes the twilight zone. 40498 * 40499 * This is only done if a SZPx instruction 40500 * refers to the twilight zone. 40501 */ 40502 40503 40504 function initTZone(state) { 40505 var tZone = state.tZone = new Array(state.gZone.length); // no idea if this is actually correct... 40506 40507 for (var i = 0; i < tZone.length; i++) { 40508 tZone[i] = new HPoint(0, 0); 40509 } 40510 } 40511 /* 40512 * Skips the instruction pointer ahead over an IF/ELSE block. 40513 * handleElse .. if true breaks on matching ELSE 40514 */ 40515 40516 40517 function skip(state, handleElse) { 40518 var prog = state.prog; 40519 var ip = state.ip; 40520 var nesting = 1; 40521 var ins; 40522 40523 do { 40524 ins = prog[++ip]; 40525 40526 if (ins === 0x58) // IF 40527 { 40528 nesting++; 40529 } else if (ins === 0x59) // EIF 40530 { 40531 nesting--; 40532 } else if (ins === 0x40) // NPUSHB 40533 { 40534 ip += prog[ip + 1] + 1; 40535 } else if (ins === 0x41) // NPUSHW 40536 { 40537 ip += 2 * prog[ip + 1] + 1; 40538 } else if (ins >= 0xB0 && ins <= 0xB7) // PUSHB 40539 { 40540 ip += ins - 0xB0 + 1; 40541 } else if (ins >= 0xB8 && ins <= 0xBF) // PUSHW 40542 { 40543 ip += (ins - 0xB8 + 1) * 2; 40544 } else if (handleElse && nesting === 1 && ins === 0x1B) // ELSE 40545 { 40546 break; 40547 } 40548 } while (nesting > 0); 40549 40550 state.ip = ip; 40551 } 40552 /*----------------------------------------------------------* 40553 * And then a lot of instructions... * 40554 *----------------------------------------------------------*/ 40555 // SVTCA[a] Set freedom and projection Vectors To Coordinate Axis 40556 // 0x00-0x01 40557 40558 40559 function SVTCA(v, state) { 40560 if (exports.DEBUG) { 40561 console.log(state.step, 'SVTCA[' + v.axis + ']'); 40562 } 40563 40564 state.fv = state.pv = state.dpv = v; 40565 } // SPVTCA[a] Set Projection Vector to Coordinate Axis 40566 // 0x02-0x03 40567 40568 40569 function SPVTCA(v, state) { 40570 if (exports.DEBUG) { 40571 console.log(state.step, 'SPVTCA[' + v.axis + ']'); 40572 } 40573 40574 state.pv = state.dpv = v; 40575 } // SFVTCA[a] Set Freedom Vector to Coordinate Axis 40576 // 0x04-0x05 40577 40578 40579 function SFVTCA(v, state) { 40580 if (exports.DEBUG) { 40581 console.log(state.step, 'SFVTCA[' + v.axis + ']'); 40582 } 40583 40584 state.fv = v; 40585 } // SPVTL[a] Set Projection Vector To Line 40586 // 0x06-0x07 40587 40588 40589 function SPVTL(a, state) { 40590 var stack = state.stack; 40591 var p2i = stack.pop(); 40592 var p1i = stack.pop(); 40593 var p2 = state.z2[p2i]; 40594 var p1 = state.z1[p1i]; 40595 40596 if (exports.DEBUG) { 40597 console.log('SPVTL[' + a + ']', p2i, p1i); 40598 } 40599 40600 var dx; 40601 var dy; 40602 40603 if (!a) { 40604 dx = p1.x - p2.x; 40605 dy = p1.y - p2.y; 40606 } else { 40607 dx = p2.y - p1.y; 40608 dy = p1.x - p2.x; 40609 } 40610 40611 state.pv = state.dpv = getUnitVector(dx, dy); 40612 } // SFVTL[a] Set Freedom Vector To Line 40613 // 0x08-0x09 40614 40615 40616 function SFVTL(a, state) { 40617 var stack = state.stack; 40618 var p2i = stack.pop(); 40619 var p1i = stack.pop(); 40620 var p2 = state.z2[p2i]; 40621 var p1 = state.z1[p1i]; 40622 40623 if (exports.DEBUG) { 40624 console.log('SFVTL[' + a + ']', p2i, p1i); 40625 } 40626 40627 var dx; 40628 var dy; 40629 40630 if (!a) { 40631 dx = p1.x - p2.x; 40632 dy = p1.y - p2.y; 40633 } else { 40634 dx = p2.y - p1.y; 40635 dy = p1.x - p2.x; 40636 } 40637 40638 state.fv = getUnitVector(dx, dy); 40639 } // SPVFS[] Set Projection Vector From Stack 40640 // 0x0A 40641 40642 40643 function SPVFS(state) { 40644 var stack = state.stack; 40645 var y = stack.pop(); 40646 var x = stack.pop(); 40647 40648 if (exports.DEBUG) { 40649 console.log(state.step, 'SPVFS[]', y, x); 40650 } 40651 40652 state.pv = state.dpv = getUnitVector(x, y); 40653 } // SFVFS[] Set Freedom Vector From Stack 40654 // 0x0B 40655 40656 40657 function SFVFS(state) { 40658 var stack = state.stack; 40659 var y = stack.pop(); 40660 var x = stack.pop(); 40661 40662 if (exports.DEBUG) { 40663 console.log(state.step, 'SPVFS[]', y, x); 40664 } 40665 40666 state.fv = getUnitVector(x, y); 40667 } // GPV[] Get Projection Vector 40668 // 0x0C 40669 40670 40671 function GPV(state) { 40672 var stack = state.stack; 40673 var pv = state.pv; 40674 40675 if (exports.DEBUG) { 40676 console.log(state.step, 'GPV[]'); 40677 } 40678 40679 stack.push(pv.x * 0x4000); 40680 stack.push(pv.y * 0x4000); 40681 } // GFV[] Get Freedom Vector 40682 // 0x0C 40683 40684 40685 function GFV(state) { 40686 var stack = state.stack; 40687 var fv = state.fv; 40688 40689 if (exports.DEBUG) { 40690 console.log(state.step, 'GFV[]'); 40691 } 40692 40693 stack.push(fv.x * 0x4000); 40694 stack.push(fv.y * 0x4000); 40695 } // SFVTPV[] Set Freedom Vector To Projection Vector 40696 // 0x0E 40697 40698 40699 function SFVTPV(state) { 40700 state.fv = state.pv; 40701 40702 if (exports.DEBUG) { 40703 console.log(state.step, 'SFVTPV[]'); 40704 } 40705 } // ISECT[] moves point p to the InterSECTion of two lines 40706 // 0x0F 40707 40708 40709 function ISECT(state) { 40710 var stack = state.stack; 40711 var pa0i = stack.pop(); 40712 var pa1i = stack.pop(); 40713 var pb0i = stack.pop(); 40714 var pb1i = stack.pop(); 40715 var pi = stack.pop(); 40716 var z0 = state.z0; 40717 var z1 = state.z1; 40718 var pa0 = z0[pa0i]; 40719 var pa1 = z0[pa1i]; 40720 var pb0 = z1[pb0i]; 40721 var pb1 = z1[pb1i]; 40722 var p = state.z2[pi]; 40723 40724 if (exports.DEBUG) { 40725 console.log('ISECT[], ', pa0i, pa1i, pb0i, pb1i, pi); 40726 } // math from 40727 // en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_two_points_on_each_line 40728 40729 40730 var x1 = pa0.x; 40731 var y1 = pa0.y; 40732 var x2 = pa1.x; 40733 var y2 = pa1.y; 40734 var x3 = pb0.x; 40735 var y3 = pb0.y; 40736 var x4 = pb1.x; 40737 var y4 = pb1.y; 40738 var div = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); 40739 var f1 = x1 * y2 - y1 * x2; 40740 var f2 = x3 * y4 - y3 * x4; 40741 p.x = (f1 * (x3 - x4) - f2 * (x1 - x2)) / div; 40742 p.y = (f1 * (y3 - y4) - f2 * (y1 - y2)) / div; 40743 } // SRP0[] Set Reference Point 0 40744 // 0x10 40745 40746 40747 function SRP0(state) { 40748 state.rp0 = state.stack.pop(); 40749 40750 if (exports.DEBUG) { 40751 console.log(state.step, 'SRP0[]', state.rp0); 40752 } 40753 } // SRP1[] Set Reference Point 1 40754 // 0x11 40755 40756 40757 function SRP1(state) { 40758 state.rp1 = state.stack.pop(); 40759 40760 if (exports.DEBUG) { 40761 console.log(state.step, 'SRP1[]', state.rp1); 40762 } 40763 } // SRP1[] Set Reference Point 2 40764 // 0x12 40765 40766 40767 function SRP2(state) { 40768 state.rp2 = state.stack.pop(); 40769 40770 if (exports.DEBUG) { 40771 console.log(state.step, 'SRP2[]', state.rp2); 40772 } 40773 } // SZP0[] Set Zone Pointer 0 40774 // 0x13 40775 40776 40777 function SZP0(state) { 40778 var n = state.stack.pop(); 40779 40780 if (exports.DEBUG) { 40781 console.log(state.step, 'SZP0[]', n); 40782 } 40783 40784 state.zp0 = n; 40785 40786 switch (n) { 40787 case 0: 40788 if (!state.tZone) { 40789 initTZone(state); 40790 } 40791 40792 state.z0 = state.tZone; 40793 break; 40794 40795 case 1: 40796 state.z0 = state.gZone; 40797 break; 40798 40799 default: 40800 throw new Error('Invalid zone pointer'); 40801 } 40802 } // SZP1[] Set Zone Pointer 1 40803 // 0x14 40804 40805 40806 function SZP1(state) { 40807 var n = state.stack.pop(); 40808 40809 if (exports.DEBUG) { 40810 console.log(state.step, 'SZP1[]', n); 40811 } 40812 40813 state.zp1 = n; 40814 40815 switch (n) { 40816 case 0: 40817 if (!state.tZone) { 40818 initTZone(state); 40819 } 40820 40821 state.z1 = state.tZone; 40822 break; 40823 40824 case 1: 40825 state.z1 = state.gZone; 40826 break; 40827 40828 default: 40829 throw new Error('Invalid zone pointer'); 40830 } 40831 } // SZP2[] Set Zone Pointer 2 40832 // 0x15 40833 40834 40835 function SZP2(state) { 40836 var n = state.stack.pop(); 40837 40838 if (exports.DEBUG) { 40839 console.log(state.step, 'SZP2[]', n); 40840 } 40841 40842 state.zp2 = n; 40843 40844 switch (n) { 40845 case 0: 40846 if (!state.tZone) { 40847 initTZone(state); 40848 } 40849 40850 state.z2 = state.tZone; 40851 break; 40852 40853 case 1: 40854 state.z2 = state.gZone; 40855 break; 40856 40857 default: 40858 throw new Error('Invalid zone pointer'); 40859 } 40860 } // SZPS[] Set Zone PointerS 40861 // 0x16 40862 40863 40864 function SZPS(state) { 40865 var n = state.stack.pop(); 40866 40867 if (exports.DEBUG) { 40868 console.log(state.step, 'SZPS[]', n); 40869 } 40870 40871 state.zp0 = state.zp1 = state.zp2 = n; 40872 40873 switch (n) { 40874 case 0: 40875 if (!state.tZone) { 40876 initTZone(state); 40877 } 40878 40879 state.z0 = state.z1 = state.z2 = state.tZone; 40880 break; 40881 40882 case 1: 40883 state.z0 = state.z1 = state.z2 = state.gZone; 40884 break; 40885 40886 default: 40887 throw new Error('Invalid zone pointer'); 40888 } 40889 } // SLOOP[] Set LOOP variable 40890 // 0x17 40891 40892 40893 function SLOOP(state) { 40894 state.loop = state.stack.pop(); 40895 40896 if (exports.DEBUG) { 40897 console.log(state.step, 'SLOOP[]', state.loop); 40898 } 40899 } // RTG[] Round To Grid 40900 // 0x18 40901 40902 40903 function RTG(state) { 40904 if (exports.DEBUG) { 40905 console.log(state.step, 'RTG[]'); 40906 } 40907 40908 state.round = roundToGrid; 40909 } // RTHG[] Round To Half Grid 40910 // 0x19 40911 40912 40913 function RTHG(state) { 40914 if (exports.DEBUG) { 40915 console.log(state.step, 'RTHG[]'); 40916 } 40917 40918 state.round = roundToHalfGrid; 40919 } // SMD[] Set Minimum Distance 40920 // 0x1A 40921 40922 40923 function SMD(state) { 40924 var d = state.stack.pop(); 40925 40926 if (exports.DEBUG) { 40927 console.log(state.step, 'SMD[]', d); 40928 } 40929 40930 state.minDis = d / 0x40; 40931 } // ELSE[] ELSE clause 40932 // 0x1B 40933 40934 40935 function ELSE(state) { 40936 // This instruction has been reached by executing a then branch 40937 // so it just skips ahead until matching EIF. 40938 // 40939 // In case the IF was negative the IF[] instruction already 40940 // skipped forward over the ELSE[] 40941 if (exports.DEBUG) { 40942 console.log(state.step, 'ELSE[]'); 40943 } 40944 40945 skip(state, false); 40946 } // JMPR[] JuMP Relative 40947 // 0x1C 40948 40949 40950 function JMPR(state) { 40951 var o = state.stack.pop(); 40952 40953 if (exports.DEBUG) { 40954 console.log(state.step, 'JMPR[]', o); 40955 } // A jump by 1 would do nothing. 40956 40957 40958 state.ip += o - 1; 40959 } // SCVTCI[] Set Control Value Table Cut-In 40960 // 0x1D 40961 40962 40963 function SCVTCI(state) { 40964 var n = state.stack.pop(); 40965 40966 if (exports.DEBUG) { 40967 console.log(state.step, 'SCVTCI[]', n); 40968 } 40969 40970 state.cvCutIn = n / 0x40; 40971 } // DUP[] DUPlicate top stack element 40972 // 0x20 40973 40974 40975 function DUP(state) { 40976 var stack = state.stack; 40977 40978 if (exports.DEBUG) { 40979 console.log(state.step, 'DUP[]'); 40980 } 40981 40982 stack.push(stack[stack.length - 1]); 40983 } // POP[] POP top stack element 40984 // 0x21 40985 40986 40987 function POP(state) { 40988 if (exports.DEBUG) { 40989 console.log(state.step, 'POP[]'); 40990 } 40991 40992 state.stack.pop(); 40993 } // CLEAR[] CLEAR the stack 40994 // 0x22 40995 40996 40997 function CLEAR(state) { 40998 if (exports.DEBUG) { 40999 console.log(state.step, 'CLEAR[]'); 41000 } 41001 41002 state.stack.length = 0; 41003 } // SWAP[] SWAP the top two elements on the stack 41004 // 0x23 41005 41006 41007 function SWAP(state) { 41008 var stack = state.stack; 41009 var a = stack.pop(); 41010 var b = stack.pop(); 41011 41012 if (exports.DEBUG) { 41013 console.log(state.step, 'SWAP[]'); 41014 } 41015 41016 stack.push(a); 41017 stack.push(b); 41018 } // DEPTH[] DEPTH of the stack 41019 // 0x24 41020 41021 41022 function DEPTH(state) { 41023 var stack = state.stack; 41024 41025 if (exports.DEBUG) { 41026 console.log(state.step, 'DEPTH[]'); 41027 } 41028 41029 stack.push(stack.length); 41030 } // LOOPCALL[] LOOPCALL function 41031 // 0x2A 41032 41033 41034 function LOOPCALL(state) { 41035 var stack = state.stack; 41036 var fn = stack.pop(); 41037 var c = stack.pop(); 41038 41039 if (exports.DEBUG) { 41040 console.log(state.step, 'LOOPCALL[]', fn, c); 41041 } // saves callers program 41042 41043 41044 var cip = state.ip; 41045 var cprog = state.prog; 41046 state.prog = state.funcs[fn]; // executes the function 41047 41048 for (var i = 0; i < c; i++) { 41049 exec(state); 41050 41051 if (exports.DEBUG) { 41052 console.log(++state.step, i + 1 < c ? 'next loopcall' : 'done loopcall', i); 41053 } 41054 } // restores the callers program 41055 41056 41057 state.ip = cip; 41058 state.prog = cprog; 41059 } // CALL[] CALL function 41060 // 0x2B 41061 41062 41063 function CALL(state) { 41064 var fn = state.stack.pop(); 41065 41066 if (exports.DEBUG) { 41067 console.log(state.step, 'CALL[]', fn); 41068 } // saves callers program 41069 41070 41071 var cip = state.ip; 41072 var cprog = state.prog; 41073 state.prog = state.funcs[fn]; // executes the function 41074 41075 exec(state); // restores the callers program 41076 41077 state.ip = cip; 41078 state.prog = cprog; 41079 41080 if (exports.DEBUG) { 41081 console.log(++state.step, 'returning from', fn); 41082 } 41083 } // CINDEX[] Copy the INDEXed element to the top of the stack 41084 // 0x25 41085 41086 41087 function CINDEX(state) { 41088 var stack = state.stack; 41089 var k = stack.pop(); 41090 41091 if (exports.DEBUG) { 41092 console.log(state.step, 'CINDEX[]', k); 41093 } // In case of k == 1, it copies the last element after popping 41094 // thus stack.length - k. 41095 41096 41097 stack.push(stack[stack.length - k]); 41098 } // MINDEX[] Move the INDEXed element to the top of the stack 41099 // 0x26 41100 41101 41102 function MINDEX(state) { 41103 var stack = state.stack; 41104 var k = stack.pop(); 41105 41106 if (exports.DEBUG) { 41107 console.log(state.step, 'MINDEX[]', k); 41108 } 41109 41110 stack.push(stack.splice(stack.length - k, 1)[0]); 41111 } // FDEF[] Function DEFinition 41112 // 0x2C 41113 41114 41115 function FDEF(state) { 41116 if (state.env !== 'fpgm') { 41117 throw new Error('FDEF not allowed here'); 41118 } 41119 41120 var stack = state.stack; 41121 var prog = state.prog; 41122 var ip = state.ip; 41123 var fn = stack.pop(); 41124 var ipBegin = ip; 41125 41126 if (exports.DEBUG) { 41127 console.log(state.step, 'FDEF[]', fn); 41128 } 41129 41130 while (prog[++ip] !== 0x2D) {} 41131 41132 state.ip = ip; 41133 state.funcs[fn] = prog.slice(ipBegin + 1, ip); 41134 } // MDAP[a] Move Direct Absolute Point 41135 // 0x2E-0x2F 41136 41137 41138 function MDAP(round, state) { 41139 var pi = state.stack.pop(); 41140 var p = state.z0[pi]; 41141 var fv = state.fv; 41142 var pv = state.pv; 41143 41144 if (exports.DEBUG) { 41145 console.log(state.step, 'MDAP[' + round + ']', pi); 41146 } 41147 41148 var d = pv.distance(p, HPZero); 41149 41150 if (round) { 41151 d = state.round(d); 41152 } 41153 41154 fv.setRelative(p, HPZero, d, pv); 41155 fv.touch(p); 41156 state.rp0 = state.rp1 = pi; 41157 } // IUP[a] Interpolate Untouched Points through the outline 41158 // 0x30 41159 41160 41161 function IUP(v, state) { 41162 var z2 = state.z2; 41163 var pLen = z2.length - 2; 41164 var cp; 41165 var pp; 41166 var np; 41167 41168 if (exports.DEBUG) { 41169 console.log(state.step, 'IUP[' + v.axis + ']'); 41170 } 41171 41172 for (var i = 0; i < pLen; i++) { 41173 cp = z2[i]; // current point 41174 // if this point has been touched go on 41175 41176 if (v.touched(cp)) { 41177 continue; 41178 } 41179 41180 pp = cp.prevTouched(v); // no point on the contour has been touched? 41181 41182 if (pp === cp) { 41183 continue; 41184 } 41185 41186 np = cp.nextTouched(v); 41187 41188 if (pp === np) { 41189 // only one point on the contour has been touched 41190 // so simply moves the point like that 41191 v.setRelative(cp, cp, v.distance(pp, pp, false, true), v, true); 41192 } 41193 41194 v.interpolate(cp, pp, np, v); 41195 } 41196 } // SHP[] SHift Point using reference point 41197 // 0x32-0x33 41198 41199 41200 function SHP(a, state) { 41201 var stack = state.stack; 41202 var rpi = a ? state.rp1 : state.rp2; 41203 var rp = (a ? state.z0 : state.z1)[rpi]; 41204 var fv = state.fv; 41205 var pv = state.pv; 41206 var loop = state.loop; 41207 var z2 = state.z2; 41208 41209 while (loop--) { 41210 var pi = stack.pop(); 41211 var p = z2[pi]; 41212 var d = pv.distance(rp, rp, false, true); 41213 fv.setRelative(p, p, d, pv); 41214 fv.touch(p); 41215 41216 if (exports.DEBUG) { 41217 console.log(state.step, (state.loop > 1 ? 'loop ' + (state.loop - loop) + ': ' : '') + 'SHP[' + (a ? 'rp1' : 'rp2') + ']', pi); 41218 } 41219 } 41220 41221 state.loop = 1; 41222 } // SHC[] SHift Contour using reference point 41223 // 0x36-0x37 41224 41225 41226 function SHC(a, state) { 41227 var stack = state.stack; 41228 var rpi = a ? state.rp1 : state.rp2; 41229 var rp = (a ? state.z0 : state.z1)[rpi]; 41230 var fv = state.fv; 41231 var pv = state.pv; 41232 var ci = stack.pop(); 41233 var sp = state.z2[state.contours[ci]]; 41234 var p = sp; 41235 41236 if (exports.DEBUG) { 41237 console.log(state.step, 'SHC[' + a + ']', ci); 41238 } 41239 41240 var d = pv.distance(rp, rp, false, true); 41241 41242 do { 41243 if (p !== rp) { 41244 fv.setRelative(p, p, d, pv); 41245 } 41246 41247 p = p.nextPointOnContour; 41248 } while (p !== sp); 41249 } // SHZ[] SHift Zone using reference point 41250 // 0x36-0x37 41251 41252 41253 function SHZ(a, state) { 41254 var stack = state.stack; 41255 var rpi = a ? state.rp1 : state.rp2; 41256 var rp = (a ? state.z0 : state.z1)[rpi]; 41257 var fv = state.fv; 41258 var pv = state.pv; 41259 var e = stack.pop(); 41260 41261 if (exports.DEBUG) { 41262 console.log(state.step, 'SHZ[' + a + ']', e); 41263 } 41264 41265 var z; 41266 41267 switch (e) { 41268 case 0: 41269 z = state.tZone; 41270 break; 41271 41272 case 1: 41273 z = state.gZone; 41274 break; 41275 41276 default: 41277 throw new Error('Invalid zone'); 41278 } 41279 41280 var p; 41281 var d = pv.distance(rp, rp, false, true); 41282 var pLen = z.length - 2; 41283 41284 for (var i = 0; i < pLen; i++) { 41285 p = z[i]; 41286 fv.setRelative(p, p, d, pv); //if (p !== rp) fv.setRelative(p, p, d, pv); 41287 } 41288 } // SHPIX[] SHift point by a PIXel amount 41289 // 0x38 41290 41291 41292 function SHPIX(state) { 41293 var stack = state.stack; 41294 var loop = state.loop; 41295 var fv = state.fv; 41296 var d = stack.pop() / 0x40; 41297 var z2 = state.z2; 41298 41299 while (loop--) { 41300 var pi = stack.pop(); 41301 var p = z2[pi]; 41302 41303 if (exports.DEBUG) { 41304 console.log(state.step, (state.loop > 1 ? 'loop ' + (state.loop - loop) + ': ' : '') + 'SHPIX[]', pi, d); 41305 } 41306 41307 fv.setRelative(p, p, d); 41308 fv.touch(p); 41309 } 41310 41311 state.loop = 1; 41312 } // IP[] Interpolate Point 41313 // 0x39 41314 41315 41316 function IP(state) { 41317 var stack = state.stack; 41318 var rp1i = state.rp1; 41319 var rp2i = state.rp2; 41320 var loop = state.loop; 41321 var rp1 = state.z0[rp1i]; 41322 var rp2 = state.z1[rp2i]; 41323 var fv = state.fv; 41324 var pv = state.dpv; 41325 var z2 = state.z2; 41326 41327 while (loop--) { 41328 var pi = stack.pop(); 41329 var p = z2[pi]; 41330 41331 if (exports.DEBUG) { 41332 console.log(state.step, (state.loop > 1 ? 'loop ' + (state.loop - loop) + ': ' : '') + 'IP[]', pi, rp1i, '<->', rp2i); 41333 } 41334 41335 fv.interpolate(p, rp1, rp2, pv); 41336 fv.touch(p); 41337 } 41338 41339 state.loop = 1; 41340 } // MSIRP[a] Move Stack Indirect Relative Point 41341 // 0x3A-0x3B 41342 41343 41344 function MSIRP(a, state) { 41345 var stack = state.stack; 41346 var d = stack.pop() / 64; 41347 var pi = stack.pop(); 41348 var p = state.z1[pi]; 41349 var rp0 = state.z0[state.rp0]; 41350 var fv = state.fv; 41351 var pv = state.pv; 41352 fv.setRelative(p, rp0, d, pv); 41353 fv.touch(p); 41354 41355 if (exports.DEBUG) { 41356 console.log(state.step, 'MSIRP[' + a + ']', d, pi); 41357 } 41358 41359 state.rp1 = state.rp0; 41360 state.rp2 = pi; 41361 41362 if (a) { 41363 state.rp0 = pi; 41364 } 41365 } // ALIGNRP[] Align to reference point. 41366 // 0x3C 41367 41368 41369 function ALIGNRP(state) { 41370 var stack = state.stack; 41371 var rp0i = state.rp0; 41372 var rp0 = state.z0[rp0i]; 41373 var loop = state.loop; 41374 var fv = state.fv; 41375 var pv = state.pv; 41376 var z1 = state.z1; 41377 41378 while (loop--) { 41379 var pi = stack.pop(); 41380 var p = z1[pi]; 41381 41382 if (exports.DEBUG) { 41383 console.log(state.step, (state.loop > 1 ? 'loop ' + (state.loop - loop) + ': ' : '') + 'ALIGNRP[]', pi); 41384 } 41385 41386 fv.setRelative(p, rp0, 0, pv); 41387 fv.touch(p); 41388 } 41389 41390 state.loop = 1; 41391 } // RTG[] Round To Double Grid 41392 // 0x3D 41393 41394 41395 function RTDG(state) { 41396 if (exports.DEBUG) { 41397 console.log(state.step, 'RTDG[]'); 41398 } 41399 41400 state.round = roundToDoubleGrid; 41401 } // MIAP[a] Move Indirect Absolute Point 41402 // 0x3E-0x3F 41403 41404 41405 function MIAP(round, state) { 41406 var stack = state.stack; 41407 var n = stack.pop(); 41408 var pi = stack.pop(); 41409 var p = state.z0[pi]; 41410 var fv = state.fv; 41411 var pv = state.pv; 41412 var cv = state.cvt[n]; 41413 41414 if (exports.DEBUG) { 41415 console.log(state.step, 'MIAP[' + round + ']', n, '(', cv, ')', pi); 41416 } 41417 41418 var d = pv.distance(p, HPZero); 41419 41420 if (round) { 41421 if (Math.abs(d - cv) < state.cvCutIn) { 41422 d = cv; 41423 } 41424 41425 d = state.round(d); 41426 } 41427 41428 fv.setRelative(p, HPZero, d, pv); 41429 41430 if (state.zp0 === 0) { 41431 p.xo = p.x; 41432 p.yo = p.y; 41433 } 41434 41435 fv.touch(p); 41436 state.rp0 = state.rp1 = pi; 41437 } // NPUSB[] PUSH N Bytes 41438 // 0x40 41439 41440 41441 function NPUSHB(state) { 41442 var prog = state.prog; 41443 var ip = state.ip; 41444 var stack = state.stack; 41445 var n = prog[++ip]; 41446 41447 if (exports.DEBUG) { 41448 console.log(state.step, 'NPUSHB[]', n); 41449 } 41450 41451 for (var i = 0; i < n; i++) { 41452 stack.push(prog[++ip]); 41453 } 41454 41455 state.ip = ip; 41456 } // NPUSHW[] PUSH N Words 41457 // 0x41 41458 41459 41460 function NPUSHW(state) { 41461 var ip = state.ip; 41462 var prog = state.prog; 41463 var stack = state.stack; 41464 var n = prog[++ip]; 41465 41466 if (exports.DEBUG) { 41467 console.log(state.step, 'NPUSHW[]', n); 41468 } 41469 41470 for (var i = 0; i < n; i++) { 41471 var w = prog[++ip] << 8 | prog[++ip]; 41472 41473 if (w & 0x8000) { 41474 w = -((w ^ 0xffff) + 1); 41475 } 41476 41477 stack.push(w); 41478 } 41479 41480 state.ip = ip; 41481 } // WS[] Write Store 41482 // 0x42 41483 41484 41485 function WS(state) { 41486 var stack = state.stack; 41487 var store = state.store; 41488 41489 if (!store) { 41490 store = state.store = []; 41491 } 41492 41493 var v = stack.pop(); 41494 var l = stack.pop(); 41495 41496 if (exports.DEBUG) { 41497 console.log(state.step, 'WS', v, l); 41498 } 41499 41500 store[l] = v; 41501 } // RS[] Read Store 41502 // 0x43 41503 41504 41505 function RS(state) { 41506 var stack = state.stack; 41507 var store = state.store; 41508 var l = stack.pop(); 41509 41510 if (exports.DEBUG) { 41511 console.log(state.step, 'RS', l); 41512 } 41513 41514 var v = store && store[l] || 0; 41515 stack.push(v); 41516 } // WCVTP[] Write Control Value Table in Pixel units 41517 // 0x44 41518 41519 41520 function WCVTP(state) { 41521 var stack = state.stack; 41522 var v = stack.pop(); 41523 var l = stack.pop(); 41524 41525 if (exports.DEBUG) { 41526 console.log(state.step, 'WCVTP', v, l); 41527 } 41528 41529 state.cvt[l] = v / 0x40; 41530 } // RCVT[] Read Control Value Table entry 41531 // 0x45 41532 41533 41534 function RCVT(state) { 41535 var stack = state.stack; 41536 var cvte = stack.pop(); 41537 41538 if (exports.DEBUG) { 41539 console.log(state.step, 'RCVT', cvte); 41540 } 41541 41542 stack.push(state.cvt[cvte] * 0x40); 41543 } // GC[] Get Coordinate projected onto the projection vector 41544 // 0x46-0x47 41545 41546 41547 function GC(a, state) { 41548 var stack = state.stack; 41549 var pi = stack.pop(); 41550 var p = state.z2[pi]; 41551 41552 if (exports.DEBUG) { 41553 console.log(state.step, 'GC[' + a + ']', pi); 41554 } 41555 41556 stack.push(state.dpv.distance(p, HPZero, a, false) * 0x40); 41557 } // MD[a] Measure Distance 41558 // 0x49-0x4A 41559 41560 41561 function MD(a, state) { 41562 var stack = state.stack; 41563 var pi2 = stack.pop(); 41564 var pi1 = stack.pop(); 41565 var p2 = state.z1[pi2]; 41566 var p1 = state.z0[pi1]; 41567 var d = state.dpv.distance(p1, p2, a, a); 41568 41569 if (exports.DEBUG) { 41570 console.log(state.step, 'MD[' + a + ']', pi2, pi1, '->', d); 41571 } 41572 41573 state.stack.push(Math.round(d * 64)); 41574 } // MPPEM[] Measure Pixels Per EM 41575 // 0x4B 41576 41577 41578 function MPPEM(state) { 41579 if (exports.DEBUG) { 41580 console.log(state.step, 'MPPEM[]'); 41581 } 41582 41583 state.stack.push(state.ppem); 41584 } // FLIPON[] set the auto FLIP Boolean to ON 41585 // 0x4D 41586 41587 41588 function FLIPON(state) { 41589 if (exports.DEBUG) { 41590 console.log(state.step, 'FLIPON[]'); 41591 } 41592 41593 state.autoFlip = true; 41594 } // LT[] Less Than 41595 // 0x50 41596 41597 41598 function LT(state) { 41599 var stack = state.stack; 41600 var e2 = stack.pop(); 41601 var e1 = stack.pop(); 41602 41603 if (exports.DEBUG) { 41604 console.log(state.step, 'LT[]', e2, e1); 41605 } 41606 41607 stack.push(e1 < e2 ? 1 : 0); 41608 } // LTEQ[] Less Than or EQual 41609 // 0x53 41610 41611 41612 function LTEQ(state) { 41613 var stack = state.stack; 41614 var e2 = stack.pop(); 41615 var e1 = stack.pop(); 41616 41617 if (exports.DEBUG) { 41618 console.log(state.step, 'LTEQ[]', e2, e1); 41619 } 41620 41621 stack.push(e1 <= e2 ? 1 : 0); 41622 } // GTEQ[] Greater Than 41623 // 0x52 41624 41625 41626 function GT(state) { 41627 var stack = state.stack; 41628 var e2 = stack.pop(); 41629 var e1 = stack.pop(); 41630 41631 if (exports.DEBUG) { 41632 console.log(state.step, 'GT[]', e2, e1); 41633 } 41634 41635 stack.push(e1 > e2 ? 1 : 0); 41636 } // GTEQ[] Greater Than or EQual 41637 // 0x53 41638 41639 41640 function GTEQ(state) { 41641 var stack = state.stack; 41642 var e2 = stack.pop(); 41643 var e1 = stack.pop(); 41644 41645 if (exports.DEBUG) { 41646 console.log(state.step, 'GTEQ[]', e2, e1); 41647 } 41648 41649 stack.push(e1 >= e2 ? 1 : 0); 41650 } // EQ[] EQual 41651 // 0x54 41652 41653 41654 function EQ(state) { 41655 var stack = state.stack; 41656 var e2 = stack.pop(); 41657 var e1 = stack.pop(); 41658 41659 if (exports.DEBUG) { 41660 console.log(state.step, 'EQ[]', e2, e1); 41661 } 41662 41663 stack.push(e2 === e1 ? 1 : 0); 41664 } // NEQ[] Not EQual 41665 // 0x55 41666 41667 41668 function NEQ(state) { 41669 var stack = state.stack; 41670 var e2 = stack.pop(); 41671 var e1 = stack.pop(); 41672 41673 if (exports.DEBUG) { 41674 console.log(state.step, 'NEQ[]', e2, e1); 41675 } 41676 41677 stack.push(e2 !== e1 ? 1 : 0); 41678 } // ODD[] ODD 41679 // 0x56 41680 41681 41682 function ODD(state) { 41683 var stack = state.stack; 41684 var n = stack.pop(); 41685 41686 if (exports.DEBUG) { 41687 console.log(state.step, 'ODD[]', n); 41688 } 41689 41690 stack.push(Math.trunc(n) % 2 ? 1 : 0); 41691 } // EVEN[] EVEN 41692 // 0x57 41693 41694 41695 function EVEN(state) { 41696 var stack = state.stack; 41697 var n = stack.pop(); 41698 41699 if (exports.DEBUG) { 41700 console.log(state.step, 'EVEN[]', n); 41701 } 41702 41703 stack.push(Math.trunc(n) % 2 ? 0 : 1); 41704 } // IF[] IF test 41705 // 0x58 41706 41707 41708 function IF(state) { 41709 var test = state.stack.pop(); 41710 41711 if (exports.DEBUG) { 41712 console.log(state.step, 'IF[]', test); 41713 } // if test is true it just continues 41714 // if not the ip is skipped until matching ELSE or EIF 41715 41716 41717 if (!test) { 41718 skip(state, true); 41719 41720 if (exports.DEBUG) { 41721 console.log(state.step, 'EIF[]'); 41722 } 41723 } 41724 } // EIF[] End IF 41725 // 0x59 41726 41727 41728 function EIF(state) { 41729 // this can be reached normally when 41730 // executing an else branch. 41731 // -> just ignore it 41732 if (exports.DEBUG) { 41733 console.log(state.step, 'EIF[]'); 41734 } 41735 } // AND[] logical AND 41736 // 0x5A 41737 41738 41739 function AND(state) { 41740 var stack = state.stack; 41741 var e2 = stack.pop(); 41742 var e1 = stack.pop(); 41743 41744 if (exports.DEBUG) { 41745 console.log(state.step, 'AND[]', e2, e1); 41746 } 41747 41748 stack.push(e2 && e1 ? 1 : 0); 41749 } // OR[] logical OR 41750 // 0x5B 41751 41752 41753 function OR(state) { 41754 var stack = state.stack; 41755 var e2 = stack.pop(); 41756 var e1 = stack.pop(); 41757 41758 if (exports.DEBUG) { 41759 console.log(state.step, 'OR[]', e2, e1); 41760 } 41761 41762 stack.push(e2 || e1 ? 1 : 0); 41763 } // NOT[] logical NOT 41764 // 0x5C 41765 41766 41767 function NOT(state) { 41768 var stack = state.stack; 41769 var e = stack.pop(); 41770 41771 if (exports.DEBUG) { 41772 console.log(state.step, 'NOT[]', e); 41773 } 41774 41775 stack.push(e ? 0 : 1); 41776 } // DELTAP1[] DELTA exception P1 41777 // DELTAP2[] DELTA exception P2 41778 // DELTAP3[] DELTA exception P3 41779 // 0x5D, 0x71, 0x72 41780 41781 41782 function DELTAP123(b, state) { 41783 var stack = state.stack; 41784 var n = stack.pop(); 41785 var fv = state.fv; 41786 var pv = state.pv; 41787 var ppem = state.ppem; 41788 var base = state.deltaBase + (b - 1) * 16; 41789 var ds = state.deltaShift; 41790 var z0 = state.z0; 41791 41792 if (exports.DEBUG) { 41793 console.log(state.step, 'DELTAP[' + b + ']', n, stack); 41794 } 41795 41796 for (var i = 0; i < n; i++) { 41797 var pi = stack.pop(); 41798 var arg = stack.pop(); 41799 var appem = base + ((arg & 0xF0) >> 4); 41800 41801 if (appem !== ppem) { 41802 continue; 41803 } 41804 41805 var mag = (arg & 0x0F) - 8; 41806 41807 if (mag >= 0) { 41808 mag++; 41809 } 41810 41811 if (exports.DEBUG) { 41812 console.log(state.step, 'DELTAPFIX', pi, 'by', mag * ds); 41813 } 41814 41815 var p = z0[pi]; 41816 fv.setRelative(p, p, mag * ds, pv); 41817 } 41818 } // SDB[] Set Delta Base in the graphics state 41819 // 0x5E 41820 41821 41822 function SDB(state) { 41823 var stack = state.stack; 41824 var n = stack.pop(); 41825 41826 if (exports.DEBUG) { 41827 console.log(state.step, 'SDB[]', n); 41828 } 41829 41830 state.deltaBase = n; 41831 } // SDS[] Set Delta Shift in the graphics state 41832 // 0x5F 41833 41834 41835 function SDS(state) { 41836 var stack = state.stack; 41837 var n = stack.pop(); 41838 41839 if (exports.DEBUG) { 41840 console.log(state.step, 'SDS[]', n); 41841 } 41842 41843 state.deltaShift = Math.pow(0.5, n); 41844 } // ADD[] ADD 41845 // 0x60 41846 41847 41848 function ADD(state) { 41849 var stack = state.stack; 41850 var n2 = stack.pop(); 41851 var n1 = stack.pop(); 41852 41853 if (exports.DEBUG) { 41854 console.log(state.step, 'ADD[]', n2, n1); 41855 } 41856 41857 stack.push(n1 + n2); 41858 } // SUB[] SUB 41859 // 0x61 41860 41861 41862 function SUB(state) { 41863 var stack = state.stack; 41864 var n2 = stack.pop(); 41865 var n1 = stack.pop(); 41866 41867 if (exports.DEBUG) { 41868 console.log(state.step, 'SUB[]', n2, n1); 41869 } 41870 41871 stack.push(n1 - n2); 41872 } // DIV[] DIV 41873 // 0x62 41874 41875 41876 function DIV(state) { 41877 var stack = state.stack; 41878 var n2 = stack.pop(); 41879 var n1 = stack.pop(); 41880 41881 if (exports.DEBUG) { 41882 console.log(state.step, 'DIV[]', n2, n1); 41883 } 41884 41885 stack.push(n1 * 64 / n2); 41886 } // MUL[] MUL 41887 // 0x63 41888 41889 41890 function MUL(state) { 41891 var stack = state.stack; 41892 var n2 = stack.pop(); 41893 var n1 = stack.pop(); 41894 41895 if (exports.DEBUG) { 41896 console.log(state.step, 'MUL[]', n2, n1); 41897 } 41898 41899 stack.push(n1 * n2 / 64); 41900 } // ABS[] ABSolute value 41901 // 0x64 41902 41903 41904 function ABS(state) { 41905 var stack = state.stack; 41906 var n = stack.pop(); 41907 41908 if (exports.DEBUG) { 41909 console.log(state.step, 'ABS[]', n); 41910 } 41911 41912 stack.push(Math.abs(n)); 41913 } // NEG[] NEGate 41914 // 0x65 41915 41916 41917 function NEG(state) { 41918 var stack = state.stack; 41919 var n = stack.pop(); 41920 41921 if (exports.DEBUG) { 41922 console.log(state.step, 'NEG[]', n); 41923 } 41924 41925 stack.push(-n); 41926 } // FLOOR[] FLOOR 41927 // 0x66 41928 41929 41930 function FLOOR(state) { 41931 var stack = state.stack; 41932 var n = stack.pop(); 41933 41934 if (exports.DEBUG) { 41935 console.log(state.step, 'FLOOR[]', n); 41936 } 41937 41938 stack.push(Math.floor(n / 0x40) * 0x40); 41939 } // CEILING[] CEILING 41940 // 0x67 41941 41942 41943 function CEILING(state) { 41944 var stack = state.stack; 41945 var n = stack.pop(); 41946 41947 if (exports.DEBUG) { 41948 console.log(state.step, 'CEILING[]', n); 41949 } 41950 41951 stack.push(Math.ceil(n / 0x40) * 0x40); 41952 } // ROUND[ab] ROUND value 41953 // 0x68-0x6B 41954 41955 41956 function ROUND(dt, state) { 41957 var stack = state.stack; 41958 var n = stack.pop(); 41959 41960 if (exports.DEBUG) { 41961 console.log(state.step, 'ROUND[]'); 41962 } 41963 41964 stack.push(state.round(n / 0x40) * 0x40); 41965 } // WCVTF[] Write Control Value Table in Funits 41966 // 0x70 41967 41968 41969 function WCVTF(state) { 41970 var stack = state.stack; 41971 var v = stack.pop(); 41972 var l = stack.pop(); 41973 41974 if (exports.DEBUG) { 41975 console.log(state.step, 'WCVTF[]', v, l); 41976 } 41977 41978 state.cvt[l] = v * state.ppem / state.font.unitsPerEm; 41979 } // DELTAC1[] DELTA exception C1 41980 // DELTAC2[] DELTA exception C2 41981 // DELTAC3[] DELTA exception C3 41982 // 0x73, 0x74, 0x75 41983 41984 41985 function DELTAC123(b, state) { 41986 var stack = state.stack; 41987 var n = stack.pop(); 41988 var ppem = state.ppem; 41989 var base = state.deltaBase + (b - 1) * 16; 41990 var ds = state.deltaShift; 41991 41992 if (exports.DEBUG) { 41993 console.log(state.step, 'DELTAC[' + b + ']', n, stack); 41994 } 41995 41996 for (var i = 0; i < n; i++) { 41997 var c = stack.pop(); 41998 var arg = stack.pop(); 41999 var appem = base + ((arg & 0xF0) >> 4); 42000 42001 if (appem !== ppem) { 42002 continue; 42003 } 42004 42005 var mag = (arg & 0x0F) - 8; 42006 42007 if (mag >= 0) { 42008 mag++; 42009 } 42010 42011 var delta = mag * ds; 42012 42013 if (exports.DEBUG) { 42014 console.log(state.step, 'DELTACFIX', c, 'by', delta); 42015 } 42016 42017 state.cvt[c] += delta; 42018 } 42019 } // SROUND[] Super ROUND 42020 // 0x76 42021 42022 42023 function SROUND(state) { 42024 var n = state.stack.pop(); 42025 42026 if (exports.DEBUG) { 42027 console.log(state.step, 'SROUND[]', n); 42028 } 42029 42030 state.round = roundSuper; 42031 var period; 42032 42033 switch (n & 0xC0) { 42034 case 0x00: 42035 period = 0.5; 42036 break; 42037 42038 case 0x40: 42039 period = 1; 42040 break; 42041 42042 case 0x80: 42043 period = 2; 42044 break; 42045 42046 default: 42047 throw new Error('invalid SROUND value'); 42048 } 42049 42050 state.srPeriod = period; 42051 42052 switch (n & 0x30) { 42053 case 0x00: 42054 state.srPhase = 0; 42055 break; 42056 42057 case 0x10: 42058 state.srPhase = 0.25 * period; 42059 break; 42060 42061 case 0x20: 42062 state.srPhase = 0.5 * period; 42063 break; 42064 42065 case 0x30: 42066 state.srPhase = 0.75 * period; 42067 break; 42068 42069 default: 42070 throw new Error('invalid SROUND value'); 42071 } 42072 42073 n &= 0x0F; 42074 42075 if (n === 0) { 42076 state.srThreshold = 0; 42077 } else { 42078 state.srThreshold = (n / 8 - 0.5) * period; 42079 } 42080 } // S45ROUND[] Super ROUND 45 degrees 42081 // 0x77 42082 42083 42084 function S45ROUND(state) { 42085 var n = state.stack.pop(); 42086 42087 if (exports.DEBUG) { 42088 console.log(state.step, 'S45ROUND[]', n); 42089 } 42090 42091 state.round = roundSuper; 42092 var period; 42093 42094 switch (n & 0xC0) { 42095 case 0x00: 42096 period = Math.sqrt(2) / 2; 42097 break; 42098 42099 case 0x40: 42100 period = Math.sqrt(2); 42101 break; 42102 42103 case 0x80: 42104 period = 2 * Math.sqrt(2); 42105 break; 42106 42107 default: 42108 throw new Error('invalid S45ROUND value'); 42109 } 42110 42111 state.srPeriod = period; 42112 42113 switch (n & 0x30) { 42114 case 0x00: 42115 state.srPhase = 0; 42116 break; 42117 42118 case 0x10: 42119 state.srPhase = 0.25 * period; 42120 break; 42121 42122 case 0x20: 42123 state.srPhase = 0.5 * period; 42124 break; 42125 42126 case 0x30: 42127 state.srPhase = 0.75 * period; 42128 break; 42129 42130 default: 42131 throw new Error('invalid S45ROUND value'); 42132 } 42133 42134 n &= 0x0F; 42135 42136 if (n === 0) { 42137 state.srThreshold = 0; 42138 } else { 42139 state.srThreshold = (n / 8 - 0.5) * period; 42140 } 42141 } // ROFF[] Round Off 42142 // 0x7A 42143 42144 42145 function ROFF(state) { 42146 if (exports.DEBUG) { 42147 console.log(state.step, 'ROFF[]'); 42148 } 42149 42150 state.round = roundOff; 42151 } // RUTG[] Round Up To Grid 42152 // 0x7C 42153 42154 42155 function RUTG(state) { 42156 if (exports.DEBUG) { 42157 console.log(state.step, 'RUTG[]'); 42158 } 42159 42160 state.round = roundUpToGrid; 42161 } // RDTG[] Round Down To Grid 42162 // 0x7D 42163 42164 42165 function RDTG(state) { 42166 if (exports.DEBUG) { 42167 console.log(state.step, 'RDTG[]'); 42168 } 42169 42170 state.round = roundDownToGrid; 42171 } // SCANCTRL[] SCAN conversion ConTRoL 42172 // 0x85 42173 42174 42175 function SCANCTRL(state) { 42176 var n = state.stack.pop(); // ignored by opentype.js 42177 42178 if (exports.DEBUG) { 42179 console.log(state.step, 'SCANCTRL[]', n); 42180 } 42181 } // SDPVTL[a] Set Dual Projection Vector To Line 42182 // 0x86-0x87 42183 42184 42185 function SDPVTL(a, state) { 42186 var stack = state.stack; 42187 var p2i = stack.pop(); 42188 var p1i = stack.pop(); 42189 var p2 = state.z2[p2i]; 42190 var p1 = state.z1[p1i]; 42191 42192 if (exports.DEBUG) { 42193 console.log(state.step, 'SDPVTL[' + a + ']', p2i, p1i); 42194 } 42195 42196 var dx; 42197 var dy; 42198 42199 if (!a) { 42200 dx = p1.x - p2.x; 42201 dy = p1.y - p2.y; 42202 } else { 42203 dx = p2.y - p1.y; 42204 dy = p1.x - p2.x; 42205 } 42206 42207 state.dpv = getUnitVector(dx, dy); 42208 } // GETINFO[] GET INFOrmation 42209 // 0x88 42210 42211 42212 function GETINFO(state) { 42213 var stack = state.stack; 42214 var sel = stack.pop(); 42215 var r = 0; 42216 42217 if (exports.DEBUG) { 42218 console.log(state.step, 'GETINFO[]', sel); 42219 } // v35 as in no subpixel hinting 42220 42221 42222 if (sel & 0x01) { 42223 r = 35; 42224 } // TODO rotation and stretch currently not supported 42225 // and thus those GETINFO are always 0. 42226 // opentype.js is always gray scaling 42227 42228 42229 if (sel & 0x20) { 42230 r |= 0x1000; 42231 } 42232 42233 stack.push(r); 42234 } // ROLL[] ROLL the top three stack elements 42235 // 0x8A 42236 42237 42238 function ROLL(state) { 42239 var stack = state.stack; 42240 var a = stack.pop(); 42241 var b = stack.pop(); 42242 var c = stack.pop(); 42243 42244 if (exports.DEBUG) { 42245 console.log(state.step, 'ROLL[]'); 42246 } 42247 42248 stack.push(b); 42249 stack.push(a); 42250 stack.push(c); 42251 } // MAX[] MAXimum of top two stack elements 42252 // 0x8B 42253 42254 42255 function MAX(state) { 42256 var stack = state.stack; 42257 var e2 = stack.pop(); 42258 var e1 = stack.pop(); 42259 42260 if (exports.DEBUG) { 42261 console.log(state.step, 'MAX[]', e2, e1); 42262 } 42263 42264 stack.push(Math.max(e1, e2)); 42265 } // MIN[] MINimum of top two stack elements 42266 // 0x8C 42267 42268 42269 function MIN(state) { 42270 var stack = state.stack; 42271 var e2 = stack.pop(); 42272 var e1 = stack.pop(); 42273 42274 if (exports.DEBUG) { 42275 console.log(state.step, 'MIN[]', e2, e1); 42276 } 42277 42278 stack.push(Math.min(e1, e2)); 42279 } // SCANTYPE[] SCANTYPE 42280 // 0x8D 42281 42282 42283 function SCANTYPE(state) { 42284 var n = state.stack.pop(); // ignored by opentype.js 42285 42286 if (exports.DEBUG) { 42287 console.log(state.step, 'SCANTYPE[]', n); 42288 } 42289 } // INSTCTRL[] INSTCTRL 42290 // 0x8D 42291 42292 42293 function INSTCTRL(state) { 42294 var s = state.stack.pop(); 42295 var v = state.stack.pop(); 42296 42297 if (exports.DEBUG) { 42298 console.log(state.step, 'INSTCTRL[]', s, v); 42299 } 42300 42301 switch (s) { 42302 case 1: 42303 state.inhibitGridFit = !!v; 42304 return; 42305 42306 case 2: 42307 state.ignoreCvt = !!v; 42308 return; 42309 42310 default: 42311 throw new Error('invalid INSTCTRL[] selector'); 42312 } 42313 } // PUSHB[abc] PUSH Bytes 42314 // 0xB0-0xB7 42315 42316 42317 function PUSHB(n, state) { 42318 var stack = state.stack; 42319 var prog = state.prog; 42320 var ip = state.ip; 42321 42322 if (exports.DEBUG) { 42323 console.log(state.step, 'PUSHB[' + n + ']'); 42324 } 42325 42326 for (var i = 0; i < n; i++) { 42327 stack.push(prog[++ip]); 42328 } 42329 42330 state.ip = ip; 42331 } // PUSHW[abc] PUSH Words 42332
42332 // 0xB8-0xBF 42333 42334 42335 function PUSHW(n, state) { 42336 var ip = state.ip; 42337 var prog = state.prog; 42338 var stack = state.stack; 42339 42340 if (exports.DEBUG) { 42341 console.log(state.ip, 'PUSHW[' + n + ']'); 42342 } 42343 42344 for (var i = 0; i < n; i++) { 42345 var w = prog[++ip] << 8 | prog[++ip]; 42346 42347 if (w & 0x8000) { 42348 w = -((w ^ 0xffff) + 1); 42349 } 42350 42351 stack.push(w); 42352 } 42353 42354 state.ip = ip; 42355 } // MDRP[abcde] Move Direct Relative Point 42356 // 0xD0-0xEF 42357 // (if indirect is 0) 42358 // 42359 // and 42360 // 42361 // MIRP[abcde] Move Indirect Relative Point 42362 // 0xE0-0xFF 42363 // (if indirect is 1) 42364 42365 42366 function MDRP_MIRP(indirect, setRp0, keepD, ro, dt, state) { 42367 var stack = state.stack; 42368 var cvte = indirect && stack.pop(); 42369 var pi = stack.pop(); 42370 var rp0i = state.rp0; 42371 var rp = state.z0[rp0i]; 42372 var p = state.z1[pi]; 42373 var md = state.minDis; 42374 var fv = state.fv; 42375 var pv = state.dpv; 42376 var od; // original distance 42377 42378 var d; // moving distance 42379 42380 var sign; // sign of distance 42381 42382 var cv; 42383 d = od = pv.distance(p, rp, true, true); 42384 sign = d >= 0 ? 1 : -1; // Math.sign would be 0 in case of 0 42385 // TODO consider autoFlip 42386 42387 d = Math.abs(d); 42388 42389 if (indirect) { 42390 cv = state.cvt[cvte]; 42391 42392 if (ro && Math.abs(d - cv) < state.cvCutIn) { 42393 d = cv; 42394 } 42395 } 42396 42397 if (keepD && d < md) { 42398 d = md; 42399 } 42400 42401 if (ro) { 42402 d = state.round(d); 42403 } 42404 42405 fv.setRelative(p, rp, sign * d, pv); 42406 fv.touch(p); 42407 42408 if (exports.DEBUG) { 42409 console.log(state.step, (indirect ? 'MIRP[' : 'MDRP[') + (setRp0 ? 'M' : 'm') + (keepD ? '>' : '_') + (ro ? 'R' : '_') + (dt === 0 ? 'Gr' : dt === 1 ? 'Bl' : dt === 2 ? 'Wh' : '') + ']', indirect ? cvte + '(' + state.cvt[cvte] + ',' + cv + ')' : '', pi, '(d =', od, '->', sign * d, ')'); 42410 } 42411 42412 state.rp1 = state.rp0; 42413 state.rp2 = pi; 42414 42415 if (setRp0) { 42416 state.rp0 = pi; 42417 } 42418 } 42419 /* 42420 * The instruction table. 42421 */ 42422 42423 42424 instructionTable = [ 42425 /* 0x00 */ 42426 SVTCA.bind(undefined, yUnitVector), 42427 /* 0x01 */ 42428 SVTCA.bind(undefined, xUnitVector), 42429 /* 0x02 */ 42430 SPVTCA.bind(undefined, yUnitVector), 42431 /* 0x03 */ 42432 SPVTCA.bind(undefined, xUnitVector), 42433 /* 0x04 */ 42434 SFVTCA.bind(undefined, yUnitVector), 42435 /* 0x05 */ 42436 SFVTCA.bind(undefined, xUnitVector), 42437 /* 0x06 */ 42438 SPVTL.bind(undefined, 0), 42439 /* 0x07 */ 42440 SPVTL.bind(undefined, 1), 42441 /* 0x08 */ 42442 SFVTL.bind(undefined, 0), 42443 /* 0x09 */ 42444 SFVTL.bind(undefined, 1), 42445 /* 0x0A */ 42446 SPVFS, 42447 /* 0x0B */ 42448 SFVFS, 42449 /* 0x0C */ 42450 GPV, 42451 /* 0x0D */ 42452 GFV, 42453 /* 0x0E */ 42454 SFVTPV, 42455 /* 0x0F */ 42456 ISECT, 42457 /* 0x10 */ 42458 SRP0, 42459 /* 0x11 */ 42460 SRP1, 42461 /* 0x12 */ 42462 SRP2, 42463 /* 0x13 */ 42464 SZP0, 42465 /* 0x14 */ 42466 SZP1, 42467 /* 0x15 */ 42468 SZP2, 42469 /* 0x16 */ 42470 SZPS, 42471 /* 0x17 */ 42472 SLOOP, 42473 /* 0x18 */ 42474 RTG, 42475 /* 0x19 */ 42476 RTHG, 42477 /* 0x1A */ 42478 SMD, 42479 /* 0x1B */ 42480 ELSE, 42481 /* 0x1C */ 42482 JMPR, 42483 /* 0x1D */ 42484 SCVTCI, 42485 /* 0x1E */ 42486 undefined, // TODO SSWCI 42487 42488 /* 0x1F */ 42489 undefined, // TODO SSW 42490 42491 /* 0x20 */ 42492 DUP, 42493 /* 0x21 */ 42494 POP, 42495 /* 0x22 */ 42496 CLEAR, 42497 /* 0x23 */ 42498 SWAP, 42499 /* 0x24 */ 42500 DEPTH, 42501 /* 0x25 */ 42502 CINDEX, 42503 /* 0x26 */ 42504 MINDEX, 42505 /* 0x27 */ 42506 undefined, // TODO ALIGNPTS 42507 42508 /* 0x28 */ 42509 undefined, 42510 /* 0x29 */ 42511 undefined, // TODO UTP 42512 42513 /* 0x2A */ 42514 LOOPCALL, 42515 /* 0x2B */ 42516 CALL, 42517 /* 0x2C */ 42518 FDEF, 42519 /* 0x2D */ 42520 undefined, // ENDF (eaten by FDEF) 42521 42522 /* 0x2E */ 42523 MDAP.bind(undefined, 0), 42524 /* 0x2F */ 42525 MDAP.bind(undefined, 1), 42526 /* 0x30 */ 42527 IUP.bind(undefined, yUnitVector), 42528 /* 0x31 */ 42529 IUP.bind(undefined, xUnitVector), 42530 /* 0x32 */ 42531 SHP.bind(undefined, 0), 42532 /* 0x33 */ 42533 SHP.bind(undefined, 1), 42534 /* 0x34 */ 42535 SHC.bind(undefined, 0), 42536 /* 0x35 */ 42537 SHC.bind(undefined, 1), 42538 /* 0x36 */ 42539 SHZ.bind(undefined, 0), 42540 /* 0x37 */ 42541 SHZ.bind(undefined, 1), 42542 /* 0x38 */ 42543 SHPIX, 42544 /* 0x39 */ 42545 IP, 42546 /* 0x3A */ 42547 MSIRP.bind(undefined, 0), 42548 /* 0x3B */ 42549 MSIRP.bind(undefined, 1), 42550 /* 0x3C */ 42551 ALIGNRP, 42552 /* 0x3D */ 42553 RTDG, 42554 /* 0x3E */ 42555 MIAP.bind(undefined, 0), 42556 /* 0x3F */ 42557 MIAP.bind(undefined, 1), 42558 /* 0x40 */ 42559 NPUSHB, 42560 /* 0x41 */ 42561 NPUSHW, 42562 /* 0x42 */ 42563 WS, 42564 /* 0x43 */ 42565 RS, 42566 /* 0x44 */ 42567 WCVTP, 42568 /* 0x45 */ 42569 RCVT, 42570 /* 0x46 */ 42571 GC.bind(undefined, 0), 42572 /* 0x47 */ 42573 GC.bind(undefined, 1), 42574 /* 0x48 */ 42575 undefined, // TODO SCFS 42576 42577 /* 0x49 */ 42578 MD.bind(undefined, 0), 42579 /* 0x4A */ 42580 MD.bind(undefined, 1), 42581 /* 0x4B */ 42582 MPPEM, 42583 /* 0x4C */ 42584 undefined, // TODO MPS 42585 42586 /* 0x4D */ 42587 FLIPON, 42588 /* 0x4E */ 42589 undefined, // TODO FLIPOFF 42590 42591 /* 0x4F */ 42592 undefined, // TODO DEBUG 42593 42594 /* 0x50 */ 42595 LT, 42596 /* 0x51 */ 42597 LTEQ, 42598 /* 0x52 */ 42599 GT, 42600 /* 0x53 */ 42601 GTEQ, 42602 /* 0x54 */ 42603 EQ, 42604 /* 0x55 */ 42605 NEQ, 42606 /* 0x56 */ 42607 ODD, 42608 /* 0x57 */ 42609 EVEN, 42610 /* 0x58 */ 42611 IF, 42612 /* 0x59 */ 42613 EIF, 42614 /* 0x5A */ 42615 AND, 42616 /* 0x5B */ 42617 OR, 42618 /* 0x5C */ 42619 NOT, 42620 /* 0x5D */ 42621 DELTAP123.bind(undefined, 1), 42622 /* 0x5E */ 42623 SDB, 42624 /* 0x5F */ 42625 SDS, 42626 /* 0x60 */ 42627 ADD, 42628 /* 0x61 */ 42629 SUB, 42630 /* 0x62 */ 42631 DIV, 42632 /* 0x63 */ 42633 MUL, 42634 /* 0x64 */ 42635 ABS, 42636 /* 0x65 */ 42637 NEG, 42638 /* 0x66 */ 42639 FLOOR, 42640 /* 0x67 */ 42641 CEILING, 42642 /* 0x68 */ 42643 ROUND.bind(undefined, 0), 42644 /* 0x69 */ 42645 ROUND.bind(undefined, 1), 42646 /* 0x6A */ 42647 ROUND.bind(undefined, 2), 42648 /* 0x6B */ 42649 ROUND.bind(undefined, 3), 42650 /* 0x6C */ 42651 undefined, // TODO NROUND[ab] 42652 42653 /* 0x6D */ 42654 undefined, // TODO NROUND[ab] 42655 42656 /* 0x6E */ 42657 undefined, // TODO NROUND[ab] 42658 42659 /* 0x6F */ 42660 undefined, // TODO NROUND[ab] 42661 42662 /* 0x70 */ 42663 WCVTF, 42664 /* 0x71 */ 42665 DELTAP123.bind(undefined, 2), 42666 /* 0x72 */ 42667 DELTAP123.bind(undefined, 3), 42668 /* 0x73 */ 42669 DELTAC123.bind(undefined, 1), 42670 /* 0x74 */ 42671 DELTAC123.bind(undefined, 2), 42672 /* 0x75 */ 42673 DELTAC123.bind(undefined, 3), 42674 /* 0x76 */ 42675 SROUND, 42676 /* 0x77 */ 42677 S45ROUND, 42678 /* 0x78 */ 42679 undefined, // TODO JROT[] 42680 42681 /* 0x79 */ 42682 undefined, // TODO JROF[] 42683 42684 /* 0x7A */ 42685 ROFF, 42686 /* 0x7B */ 42687 undefined, 42688 /* 0x7C */ 42689 RUTG, 42690 /* 0x7D */ 42691 RDTG, 42692 /* 0x7E */ 42693 POP, // actually SANGW, supposed to do only a pop though 42694 42695 /* 0x7F */ 42696 POP, // actually AA, supposed to do only a pop though 42697 42698 /* 0x80 */ 42699 undefined, // TODO FLIPPT 42700 42701 /* 0x81 */ 42702 undefined, // TODO FLIPRGON 42703 42704 /* 0x82 */ 42705 undefined, // TODO FLIPRGOFF 42706 42707 /* 0x83 */ 42708 undefined, 42709 /* 0x84 */ 42710 undefined, 42711 /* 0x85 */ 42712 SCANCTRL, 42713 /* 0x86 */ 42714 SDPVTL.bind(undefined, 0), 42715 /* 0x87 */ 42716 SDPVTL.bind(undefined, 1), 42717 /* 0x88 */ 42718 GETINFO, 42719 /* 0x89 */ 42720 undefined, // TODO IDEF 42721 42722 /* 0x8A */ 42723 ROLL, 42724 /* 0x8B */ 42725 MAX, 42726 /* 0x8C */ 42727 MIN, 42728 /* 0x8D */ 42729 SCANTYPE, 42730 /* 0x8E */ 42731 INSTCTRL, 42732 /* 0x8F */ 42733 undefined, 42734 /* 0x90 */ 42735 undefined, 42736 /* 0x91 */ 42737 undefined, 42738 /* 0x92 */ 42739 undefined, 42740 /* 0x93 */ 42741 undefined, 42742 /* 0x94 */ 42743 undefined, 42744 /* 0x95 */ 42745 undefined, 42746 /* 0x96 */ 42747 undefined, 42748 /* 0x97 */ 42749 undefined, 42750 /* 0x98 */ 42751 undefined, 42752 /* 0x99 */ 42753 undefined, 42754 /* 0x9A */ 42755 undefined, 42756 /* 0x9B */ 42757 undefined, 42758 /* 0x9C */ 42759 undefined, 42760 /* 0x9D */ 42761 undefined, 42762 /* 0x9E */ 42763 undefined, 42764 /* 0x9F */ 42765 undefined, 42766 /* 0xA0 */ 42767 undefined, 42768 /* 0xA1 */ 42769 undefined, 42770 /* 0xA2 */ 42771 undefined, 42772 /* 0xA3 */ 42773 undefined, 42774 /* 0xA4 */ 42775 undefined, 42776 /* 0xA5 */ 42777 undefined, 42778 /* 0xA6 */ 42779 undefined, 42780 /* 0xA7 */ 42781 undefined, 42782 /* 0xA8 */ 42783 undefined, 42784 /* 0xA9 */ 42785 undefined, 42786 /* 0xAA */ 42787 undefined, 42788 /* 0xAB */ 42789 undefined, 42790 /* 0xAC */ 42791 undefined, 42792 /* 0xAD */ 42793 undefined, 42794 /* 0xAE */ 42795 undefined, 42796 /* 0xAF */ 42797 undefined, 42798 /* 0xB0 */ 42799 PUSHB.bind(undefined, 1), 42800 /* 0xB1 */ 42801 PUSHB.bind(undefined, 2), 42802 /* 0xB2 */ 42803 PUSHB.bind(undefined, 3), 42804 /* 0xB3 */ 42805 PUSHB.bind(undefined, 4), 42806 /* 0xB4 */ 42807 PUSHB.bind(undefined, 5), 42808 /* 0xB5 */ 42809 PUSHB.bind(undefined, 6), 42810 /* 0xB6 */ 42811 PUSHB.bind(undefined, 7), 42812 /* 0xB7 */ 42813 PUSHB.bind(undefined, 8), 42814 /* 0xB8 */ 42815 PUSHW.bind(undefined, 1), 42816 /* 0xB9 */ 42817 PUSHW.bind(undefined, 2), 42818 /* 0xBA */ 42819 PUSHW.bind(undefined, 3), 42820 /* 0xBB */ 42821 PUSHW.bind(undefined, 4), 42822 /* 0xBC */ 42823 PUSHW.bind(undefined, 5), 42824 /* 0xBD */ 42825 PUSHW.bind(undefined, 6), 42826 /* 0xBE */ 42827 PUSHW.bind(undefined, 7), 42828 /* 0xBF */ 42829 PUSHW.bind(undefined, 8), 42830 /* 0xC0 */ 42831 MDRP_MIRP.bind(undefined, 0, 0, 0, 0, 0), 42832 /* 0xC1 */ 42833 MDRP_MIRP.bind(undefined, 0, 0, 0, 0, 1), 42834 /* 0xC2 */ 42835 MDRP_MIRP.bind(undefined, 0, 0, 0, 0, 2), 42836 /* 0xC3 */ 42837 MDRP_MIRP.bind(undefined, 0, 0, 0, 0, 3), 42838 /* 0xC4 */ 42839 MDRP_MIRP.bind(undefined, 0, 0, 0, 1, 0), 42840 /* 0xC5 */ 42841 MDRP_MIRP.bind(undefined, 0, 0, 0, 1, 1), 42842 /* 0xC6 */ 42843 MDRP_MIRP.bind(undefined, 0, 0, 0, 1, 2), 42844 /* 0xC7 */ 42845 MDRP_MIRP.bind(undefined, 0, 0, 0, 1, 3), 42846 /* 0xC8 */ 42847 MDRP_MIRP.bind(undefined, 0, 0, 1, 0, 0), 42848 /* 0xC9 */ 42849 MDRP_MIRP.bind(undefined, 0, 0, 1, 0, 1), 42850 /* 0xCA */ 42851 MDRP_MIRP.bind(undefined, 0, 0, 1, 0, 2), 42852 /* 0xCB */ 42853 MDRP_MIRP.bind(undefined, 0, 0, 1, 0, 3), 42854 /* 0xCC */ 42855 MDRP_MIRP.bind(undefined, 0, 0, 1, 1, 0), 42856 /* 0xCD */ 42857 MDRP_MIRP.bind(undefined, 0, 0, 1, 1, 1), 42858 /* 0xCE */ 42859 MDRP_MIRP.bind(undefined, 0, 0, 1, 1, 2), 42860 /* 0xCF */ 42861 MDRP_MIRP.bind(undefined, 0, 0, 1, 1, 3), 42862 /* 0xD0 */ 42863 MDRP_MIRP.bind(undefined, 0, 1, 0, 0, 0), 42864 /* 0xD1 */ 42865 MDRP_MIRP.bind(undefined, 0, 1, 0, 0, 1), 42866 /* 0xD2 */ 42867 MDRP_MIRP.bind(undefined, 0, 1, 0, 0, 2), 42868 /* 0xD3 */ 42869 MDRP_MIRP.bind(undefined, 0, 1, 0, 0, 3), 42870 /* 0xD4 */ 42871 MDRP_MIRP.bind(undefined, 0, 1, 0, 1, 0), 42872 /* 0xD5 */ 42873 MDRP_MIRP.bind(undefined, 0, 1, 0, 1, 1), 42874 /* 0xD6 */ 42875 MDRP_MIRP.bind(undefined, 0, 1, 0, 1, 2), 42876 /* 0xD7 */ 42877 MDRP_MIRP.bind(undefined, 0, 1, 0, 1, 3), 42878 /* 0xD8 */ 42879 MDRP_MIRP.bind(undefined, 0, 1, 1, 0, 0), 42880 /* 0xD9 */ 42881 MDRP_MIRP.bind(undefined, 0, 1, 1, 0, 1), 42882 /* 0xDA */ 42883 MDRP_MIRP.bind(undefined, 0, 1, 1, 0, 2), 42884 /* 0xDB */ 42885 MDRP_MIRP.bind(undefined, 0, 1, 1, 0, 3), 42886 /* 0xDC */ 42887 MDRP_MIRP.bind(undefined, 0, 1, 1, 1, 0), 42888 /* 0xDD */ 42889 MDRP_MIRP.bind(undefined, 0, 1, 1, 1, 1), 42890 /* 0xDE */ 42891 MDRP_MIRP.bind(undefined, 0, 1, 1, 1, 2), 42892 /* 0xDF */ 42893 MDRP_MIRP.bind(undefined, 0, 1, 1, 1, 3), 42894 /* 0xE0 */ 42895 MDRP_MIRP.bind(undefined, 1, 0, 0, 0, 0), 42896 /* 0xE1 */ 42897 MDRP_MIRP.bind(undefined, 1, 0, 0, 0, 1), 42898 /* 0xE2 */ 42899 MDRP_MIRP.bind(undefined, 1, 0, 0, 0, 2), 42900 /* 0xE3 */ 42901 MDRP_MIRP.bind(undefined, 1, 0, 0, 0, 3), 42902 /* 0xE4 */ 42903 MDRP_MIRP.bind(undefined, 1, 0, 0, 1, 0), 42904 /* 0xE5 */ 42905 MDRP_MIRP.bind(undefined, 1, 0, 0, 1, 1), 42906 /* 0xE6 */ 42907 MDRP_MIRP.bind(undefined, 1, 0, 0, 1, 2), 42908 /* 0xE7 */ 42909 MDRP_MIRP.bind(undefined, 1, 0, 0, 1, 3), 42910 /* 0xE8 */ 42911 MDRP_MIRP.bind(undefined, 1, 0, 1, 0, 0), 42912 /* 0xE9 */ 42913 MDRP_MIRP.bind(undefined, 1, 0, 1, 0, 1), 42914 /* 0xEA */ 42915 MDRP_MIRP.bind(undefined, 1, 0, 1, 0, 2), 42916 /* 0xEB */ 42917 MDRP_MIRP.bind(undefined, 1, 0, 1, 0, 3), 42918 /* 0xEC */ 42919 MDRP_MIRP.bind(undefined, 1, 0, 1, 1, 0), 42920 /* 0xED */ 42921 MDRP_MIRP.bind(undefined, 1, 0, 1, 1, 1), 42922 /* 0xEE */ 42923 MDRP_MIRP.bind(undefined, 1, 0, 1, 1, 2), 42924 /* 0xEF */ 42925 MDRP_MIRP.bind(undefined, 1, 0, 1, 1, 3), 42926 /* 0xF0 */ 42927 MDRP_MIRP.bind(undefined, 1, 1, 0, 0, 0), 42928 /* 0xF1 */ 42929 MDRP_MIRP.bind(undefined, 1, 1, 0, 0, 1), 42930 /* 0xF2 */ 42931 MDRP_MIRP.bind(undefined, 1, 1, 0, 0, 2), 42932 /* 0xF3 */ 42933 MDRP_MIRP.bind(undefined, 1, 1, 0, 0, 3), 42934 /* 0xF4 */ 42935 MDRP_MIRP.bind(undefined, 1, 1, 0, 1, 0), 42936 /* 0xF5 */ 42937 MDRP_MIRP.bind(undefined, 1, 1, 0, 1, 1), 42938 /* 0xF6 */ 42939 MDRP_MIRP.bind(undefined, 1, 1, 0, 1, 2), 42940 /* 0xF7 */ 42941 MDRP_MIRP.bind(undefined, 1, 1, 0, 1, 3), 42942 /* 0xF8 */ 42943 MDRP_MIRP.bind(undefined, 1, 1, 1, 0, 0), 42944 /* 0xF9 */ 42945 MDRP_MIRP.bind(undefined, 1, 1, 1, 0, 1), 42946 /* 0xFA */ 42947 MDRP_MIRP.bind(undefined, 1, 1, 1, 0, 2), 42948 /* 0xFB */ 42949 MDRP_MIRP.bind(undefined, 1, 1, 1, 0, 3), 42950 /* 0xFC */ 42951 MDRP_MIRP.bind(undefined, 1, 1, 1, 1, 0), 42952 /* 0xFD */ 42953 MDRP_MIRP.bind(undefined, 1, 1, 1, 1, 1), 42954 /* 0xFE */ 42955 MDRP_MIRP.bind(undefined, 1, 1, 1, 1, 2), 42956 /* 0xFF */ 42957 MDRP_MIRP.bind(undefined, 1, 1, 1, 1, 3)]; 42958 /***************************** 42959 Mathematical Considerations 42960 ****************************** 42961 fv ... refers to freedom vector 42962 pv ... refe
42962rs to projection vector 42963 rp ... refers to reference point 42964 p ... refers to to point being operated on 42965 d ... refers to distance 42966 SETRELATIVE: 42967 ============ 42968 case freedom vector == x-axis: 42969 ------------------------------ 42970 (pv) 42971 .-' 42972 rpd .-' 42973 .-* 42974 d .-'90°' 42975 .-' ' 42976 .-' ' 42977 *-' ' b 42978 rp ' 42979 ' 42980 ' 42981 p *----------*-------------- (fv) 42982 pm 42983 rpdx = rpx + d * pv.x 42984 rpdy = rpy + d * pv.y 42985 equation of line b 42986 y - rpdy = pvns * (x- rpdx) 42987 y = p.y 42988 x = rpdx + ( p.y - rpdy ) / pvns 42989 42990 case freedom vector == y-axis: 42991 ------------------------------ 42992 * pm 42993 |\ 42994 | \ 42995 | \ 42996 | \ 42997 | \ 42998 | \ 42999 | \ 43000 | \ 43001 | \ 43002 | \ b 43003 | \ 43004 | \ 43005 | \ .-' (pv) 43006 | 90° \.-' 43007 | .-'* rpd 43008 | .-' 43009 * *-' d 43010 p rp 43011 rpdx = rpx + d * pv.x 43012 rpdy = rpy + d * pv.y 43013 equation of line b: 43014 pvns ... normal slope to pv 43015 y - rpdy = pvns * (x - rpdx) 43016 x = p.x 43017 y = rpdy + pvns * (p.x - rpdx) 43018 43019 generic case: 43020 ------------- 43021 43022 .'(fv) 43023 .' 43024 .* pm 43025 .' ! 43026 .' . 43027 .' ! 43028 .' . b 43029 .' ! 43030 * . 43031 p ! 43032 90° . ... (pv) 43033 ...-*-''' 43034 ...---''' rpd 43035 ...---''' d 43036 *--''' 43037 rp 43038 rpdx = rpx + d * pv.x 43039 rpdy = rpy + d * pv.y 43040 equation of line b: 43041 pvns... normal slope to pv 43042 y - rpdy = pvns * (x - rpdx) 43043 equation of freedom vector line: 43044 fvs ... slope of freedom vector (=fy/fx) 43045 y - py = fvs * (x - px) 43046 43047 on pm both equations are true for same x/y 43048 y - rpdy = pvns * (x - rpdx) 43049 y - py = fvs * (x - px) 43050 form to y and set equal:
43051 pvns * (x - rpdx) + rpdy = fvs * (x - px) + py 43052 expand: 43053 pvns * x - pvns * rpdx + rpdy = fvs * x - fvs * px + py 43054 switch: 43055 fvs * x - fvs * px + py = pvns * x - pvns * rpdx + rpdy 43056 solve for x: 43057 fvs * x - pvns * x = fvs * px - pvns * rpdx - py + rpdy 43058 43059 fvs * px - pvns * rpdx + rpdy - py 43060 x = ----------------------------------- 43061 fvs - pvns 43062 and: 43063 y = fvs * (x - px) + py 43064 43065 INTERPOLATE: 43066 ============ 43067 Examples of point interpolation. 43068 The weight of the movement of the reference point gets bigger 43069 the further the other reference point is away, thus the safest 43070 option (that is avoiding 0/0 divisions) is to weight the 43071 original distance of the other point by the sum of both distances. 43072 If the sum of both distances is 0, then move the point by the 43073 arithmetic average of the movement of both reference points. 43074 43075 43076 (+6) 43077 rp1o *---->*rp1 43078 . . (+12) 43079 . . rp2o *---------->* rp2 43080 . . . . 43081 . . . . 43082 . 10 20 . . 43083 |.........|...................| . 43084 . . . 43085 . . (+8) . 43086 po *------>*p . 43087 . . . 43088 . 12 . 24 . 43089 |...........|.......................| 43090 36 43091 43092 ------- 43093 43094 (+10) 43095 rp1o *-------->*rp1 43096 . . (-10) 43097 . . rp2 *<---------* rpo2 43098 . . . . 43099 . . . . 43100 . 10 . 30 . . 43101 |.........|.............................| 43102 . . 43103 . (+5) . 43104 po *--->* p . 43105 . . . 43106 . . 20 . 43107 |....|..............| 43108 5 15 43109 43110 ------- 43111 43112 (+10) 43113 rp1o *-------->*rp1 43114 . . 43115 . . 43116 rp2o *-------->*rp2 43117 43118 (+10) 43119 po *-------->* p 43120 ------- 43121 43122 (+10) 43123 rp1o *-------->*rp1 43124 . . 43125 . .(+30) 43126 rp2o *---------------------------->*rp2 43127 43128 (+25) 43129 po *----------------------->* p 43130 43131 vim: set ts=4 sw=4 expandtab: 43132 *****/ 43133 // The Font object 43134 // This code is based on Array.from implementation for strings in https://github.com/mathiasbynens/Array.from 43135 43136 var arrayFromString = Array.from || function (s) { 43137 return s.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]?|[^\uD800-\uDFFF]|./g) || []; 43138 }; 43139 /** 43140 * @typedef FontOptions 43141 * @type Object 43142 * @property {Boolean} empty - whether to create a new empty font 43143 * @property {string} familyName 43144 * @property {string} styleName 43145 * @property {string=} fullName 43146 * @property {string=} postScriptName 43147 * @property {string=} designer 43148 * @property {string=}
43148 designerURL 43149 * @property {string=} manufacturer 43150 * @property {string=} manufacturerURL 43151 * @property {string=} license 43152 * @property {string=} licenseURL 43153 * @property {string=} version 43154 * @property {string=} description 43155 * @property {string=} copyright 43156 * @property {string=} trademark 43157 * @property {Number} unitsPerEm 43158 * @property {Number} ascender 43159 * @property {Number} descender 43160 * @property {Number} createdTimestamp 43161 * @property {string=} weightClass 43162 * @property {string=} widthClass 43163 * @property {string=} fsSelection 43164 */ 43165 43166 /** 43167 * A Font represents a loaded OpenType font file. 43168 * It contains a set of glyphs and methods to draw text on a drawing context, 43169 * or to get a path representing the text. 43170 * @exports opentype.Font 43171 * @class 43172 * @param {FontOptions} 43173 * @constructor 43174 */ 43175 43176 43177 function Font(options) { 43178 options = options || {}; 43179 43180 if (!options.empty) { 43181 // Check that we've provided the minimum set of names. 43182 checkArgument(options.familyName, 'When creating a new Font object, familyName is required.'); 43183 checkArgument(options.styleName, 'When creating a new Font object, styleName is required.'); 43184 checkArgument(options.unitsPerEm, 'When creating a new Font object, unitsPerEm is required.'); 43185 checkArgument(options.ascender, 'When creating a new Font object, ascender is required.'); 43186 checkArgument(options.descender, 'When creating a new Font object, descender is required.'); 43187 checkArgument(options.descender < 0, 'Descender should be negative (e.g. -512).'); // OS X will complain if the names are empty, so we put a single space everywhere by default. 43188 43189 this.names = { 43190 fontFamily: { 43191 en: options.familyName || ' ' 43192 }, 43193 fontSubfamily: { 43194 en: options.styleName || ' ' 43195 }, 43196 fullName: { 43197 en: options.fullName || options.familyName + ' ' + options.styleName 43198 }, 43199 // postScriptName may not contain any whitespace 43200 postScriptName: { 43201 en: options.postScriptName || (options.familyName + options.styleName).replace(/\s/g, '') 43202 }, 43203 designer: { 43204 en: options.designer || ' ' 43205 }, 43206 designerURL: { 43207 en: options.designerURL || ' ' 43208 }, 43209 manufacturer: { 43210 en: options.manufacturer || ' ' 43211 }, 43212 manufacturerURL: { 43213 en: options.manufacturerURL || ' ' 43214 }, 43215 license: { 43216 en: options.license || ' ' 43217 }, 43218 licenseURL: { 43219 en: options.licenseURL || ' ' 43220 }, 43221 version: { 43222 en: options.version || 'Version 0.1' 43223 }, 43224 description: { 43225 en: options.description || ' ' 43226 }, 43227 copyright: { 43228 en: options.copyright || ' ' 43229 }, 43230 trademark: { 43231 en: options.trademark || ' ' 43232 } 43233 }; 43234 this.unitsPerEm = options.unitsPerEm || 1000; 43235 this.ascender = options.ascender; 43236 this.descender = options.descender; 43237 this.createdTimestamp = options.createdTimestamp; 43238 this.tables = { 43239 os2: { 43240 usWeightClass: options.weightClass || this.usWeightClasses.MEDIUM, 43241 usWidthClass: options.widthClass || this.usWidthClasses.MEDIUM, 43242 fsSelection: options.fsSelection || this.fsSelectionValues.REGULAR 43243 } 43244 }; 43245 } 43246 43247 this.supported = true; // Deprecated: parseBuffer will throw an error if font is not supported. 43248 43249 this.glyphs = new glyphset.GlyphSet(this, options.glyphs || []); 43250 this.encoding = new DefaultEncoding(this); 43251 this.position = new Position(this); 43252 this.substitution = new Substitution(this); 43253 this.tables = this.tables || {}; 43254 Object.defineProperty(this, 'hinting', { 43255 get: function () { 43256 if (this._hinting) { 43257 return this._hinting; 43258 } 43259 43260 if (this.outlinesFormat === 'truetype') { 43261 return this._hinting = new Hinting(this); 43262 } 43263 } 43264 }); 43265 } 43266 /** 43267 * Check if the font has a glyph for the given character. 43268 * @param {string} 43269 * @return {Boolean} 43270 */ 43271 43272 43273 Font.prototype.hasChar = function (c) { 43274 return this.encoding.charToGlyphIndex(c) !== null; 43275 }; 43276 /** 43277 * Convert the given character to a single glyph index. 43278 * Note that this function assumes that there is a one-to-one mapping between 43279 * the given character and a glyph; for complex scripts this might not be the case. 43280 * @param {string} 43281 * @return {Number} 43282 */ 43283 43284 43285 Font.prototype.charToGlyphIndex = function (s) { 43286 return this.encoding.charToGlyphIndex(s); 43287 }; 43288 /** 43289 * Convert the given character to a single Glyph object. 43290 * Note that this function assumes that there is a one-to-one mapping between 43291 * the given character and a glyph; for complex scripts this might not be the case. 43292 * @param {string} 43293 * @return {opentype.Glyph} 43294 */ 43295 43296 43297 Font.prototype.charToGlyph = function (c) { 43298 var glyphIndex = this.charToGlyphIndex(c); 43299 var glyph = this.glyphs.get(glyphIndex); 43300 43301 if (!glyph) { 43302 // .notdef 43303 glyph = this.glyphs.get(0); 43304 } 43305 43306 return glyph; 43307 }; 43308 /** 43309 * Convert the given text to a list of Glyph objects. 43310 * Note that there is no strict one-to-one mapping between characters and 43311 * glyphs, so the list of returned glyphs can be larger or smaller than the 43312 * length of the given string. 43313 * @param {string} 43314 * @param {GlyphRenderOptions} [options] 43315 * @return {opentype.Glyph[]} 43316 */ 43317 43318 43319 Font.prototype.stringToGlyphs = function (s, options) { 43320 var this$1 = this; 43321 options = options || this.defaultRenderOptions; // Get glyph indexes 43322 43323 var chars = arrayFromString(s); 43324 var indexes = []; 43325 43326 for (var i = 0; i < chars.length; i += 1) { 43327 var c = chars[i]; 43328 indexes.push(this$1.charToGlyphIndex(c)); 43329 } 43330 43331 var length = indexes.length; // Apply substitutions on glyph indexes 43332 43333 if (options.features) { 43334 var script = options.script || this.substitution.getDefaultScriptName(); 43335 var manyToOne = []; 43336 43337 if (options.features.liga) { 43338 manyToOne = manyToOne.concat(this.substitution.getFeature('liga', script, options.language)); 43339 } 43340 43341 if (options.features.rlig) { 43342 manyToOne = manyToOne.concat(this.substitution.getFeature('rlig', script, options.language)); 43343 } 43344 43345 for (var i$1 = 0; i$1 < length; i$1 += 1) { 43346 for (var j = 0; j < manyToOne.length; j++) { 43347 var ligature = manyToOne[j]; 43348 var components = ligature.sub; 43349 var compCount = components.length; 43350 var k = 0; 43351 43352 while (k < compCount && components[k] === indexes[i$1 + k]) { 43353 k++; 43354 } 43355 43356 if (k === compCount) { 43357 indexes.splice(i$1, compCount, ligature.by); 43358 length = length - compCount + 1; 43359 } 43360 } 43361 } 43362 } // convert glyph indexes to glyph objects 43363 43364 43365 var glyphs = new Array(length); 43366 var notdef = this.glyphs.get(0); 43367 43368 for (var i$2 = 0; i$2 < length; i$2 += 1) { 43369 glyphs[i$2] = this$1.glyphs.get(indexes[i$2]) || notdef; 43370 } 43371 43372 return glyphs; 43373 }; 43374 /** 43375 * @param {string} 43376 * @return {Number} 43377 */ 43378 43379 43380 Font.prototype.nameToGlyphIndex = function (name) { 43381 return this.glyphNames.nameToGlyphIndex(name); 43382 }; 43383 /** 43384 * @param {string} 43385 * @return {opentype.Glyph} 43386 */ 43387 43388 43389 Font.prototype.nameToGlyph = function (name) { 43390 var glyphIndex = this.nameToGlyphIndex(name); 43391 var glyph = this.glyphs.get(glyphIndex); 43392 43393 if (!glyph) { 43394 // .notdef 43395 glyph = this.glyphs.get(0); 43396 } 43397 43398 return glyph; 43399 }; 43400 /** 43401 * @param {Number} 43402 * @return {String} 43403 */ 43404 43405 43406 Font.prototype.glyphIndexToName = function (gid) { 43407 if (!this.glyphNames.glyphIndexToName) { 43408 return ''; 43409 } 43410 43411 return this.glyphNames.glyphIndexToName(gid); 43412 }; 43413 /** 43414 * Retrieve the value of the kerning pair between the left glyph (or its index) 43415 * and the right glyph (or its index). If no kerning pair is found, return 0. 43416 * The kerning value gets added to the advance width when calculating the spacing 43417 * between glyphs. 43418 * For GPOS kerning, this method uses the default script and language, which covers 43419 * most use cases. To have greater control, use font.position.getKerningValue . 43420 * @param {opentype.Glyph} leftGlyph 43421 * @param {opentype.Glyph} rightGlyph 43422 * @return {Number} 43423 */ 43424 43425 43426 Font.prototype.getKerningValue = function (leftGlyph, rightGlyph) { 43427 leftGlyph = leftGlyph.index || leftGlyph; 43428 rightGlyph = rightGlyph.index || rightGlyph; 43429 var gposKerning = this.position.defaultKerningTables; 43430 43431 if (gposKerning) { 43432 return this.position.getKerningValue(gposKerning, leftGlyph, rightGlyph); 43433 } // "kern" table 43434 43435 43436 return this.kerningPairs[leftGlyph + ',' + rightGlyph] || 0; 43437 }; 43438 /** 43439 * @typedef GlyphRenderOptions 43440 * @type Object 43441 * @property {string} [script] - script used to determine which features to apply. By default, 'DFLT' or 'latn' is used. 43442 * See https://www.microsoft.com/typography/otspec/scripttags.htm 43443 * @property {string} [language='dflt'] - language system used to determine which features to apply. 43444 * See https://www.microsoft.com/typography/developers/opentype/languagetags.aspx 43445 * @property {boolean} [kerning=true] - whether to include kerning values 43446 * @property {object} [features] - OpenType Layout feature tags. Used to enable or disable the features of the given script/language system. 43447 * See https://www.microsoft.com/typography/otspec/featuretags.htm 43448 */ 43449 43450 43451 Font.prototype.defaultRenderOptions = { 43452 kerning: true, 43453 features: { 43454 liga: true, 43455 rlig: true 43456 } 43457 }; 43458 /** 43459 * Helper function that invokes the given callback for each glyph in the given text. 43460 * The callback gets `(glyph, x, y, fontSize, options)`.* @param {string} text 43461 * @param {string} text - The text to apply. 43462 * @param {number} [x=0] - Horizontal position of the beginning of the text. 43463 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 43464 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 43465 * @param {GlyphRenderOptions=} options 43466 * @param {Function} callback 43467 */ 43468 43469 Font.prototype.forEachGlyph = function (text, x, y, fontSize, options, callback) { 43470 var this$1 = this; 43471 x = x !== undefined ? x : 0; 43472 y = y !== undefined ? y : 0; 43473 fontSize = fontSize !== undefined ? fontSize : 72; 43474 options = options || this.defaultRenderOptions; 43475 var fontScale = 1 / this.unitsPerEm * fontSize; 43476 var glyphs = this.stringToGlyphs(text, options); 43477 var kerningLookups; 43478 43479 if (options.kerning) { 43480 var script = options.script || this.position.getDefaultScriptName(); 43481 kerningLookups = this.position.getKerningTables(script, options.language); 43482 } 43483 43484 for (var i = 0; i < glyphs.length; i += 1) { 43485 var glyph = glyphs[i]; 43486 callback.call(this$1, glyph, x, y, fontSize, options); 43487 43488 if (glyph.advanceWidth) { 43489 x += glyph.advanceWidth * fontScale; 43490 } 43491 43492 if (options.kerning && i < glyphs.length - 1) { 43493 // We should apply position adjustment lookups in a more generic way. 43494 // Here we only use the xAdvance value. 43495 var kerningValue = kerningLookups ? this$1.position.getKerningValue(kerningLookups, glyph.index, glyphs[i + 1].index) : this$1.getKerningValue(glyph, glyphs[i + 1]); 43496 x += kerningValue * fontScale; 43497 } 43498 43499 if (options.letterSpacing) { 43500 x += options.letterSpacing * fontSize; 43501 } else if (options.tracking) { 43502 x += options.tracking / 1000 * fontSize; 43503 } 43504 } 43505 43506 return x; 43507 }; 43508 /** 43509 * Create a Path object that represents the given text. 43510 * @param {string} text - The text to create. 43511 * @param {number} [x=0] - Horizontal position of the beginning of the text. 43512 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 43513 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 43514 * @param {GlyphRenderOptions=} options 43515 * @return {opentype.Path} 43516 */ 43517 43518 43519 Font.prototype.getPath = function (text, x, y, fontSize, options) { 43520 var fullPath = new Path(); 43521 this.forEachGlyph(text, x, y, fontSize, options, function (glyph, gX, gY, gFontSize) { 43522 var glyphPath = glyph.getPath(gX, gY, gFontSize, options, this); 43523 fullPath.extend(glyphPath); 43524 }); 43525 return fullPath; 43526 }; 43527 /** 43528 * Create an array of Path objects that represent the glyphs of a given text. 43529 * @param {string} text - The text to create. 43530 * @param {number} [x=0] - Horizontal position of the beginning of the text. 43531 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 43532 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 43533 * @param {GlyphRenderOptions=} options 43534 * @return {opentype.Path[]} 43535 */ 43536 43537 43538 Font.prototype.getPaths = function (text, x, y, fontSize, options) { 43539 var glyphPaths = []; 43540 this.forEachGlyph(text, x, y, fontSize, options, function (glyph, gX, gY, gFontSize) { 43541 var glyphPath = glyph.getPath(gX, gY, gFontSize, options, this); 43542 glyphPaths.push(glyphPath); 43543 }); 43544 return glyphPaths; 43545 }; 43546 /** 43547 * Returns the advance width of a text. 43548 * 43549 * This is something different than Path.getBoundingBox() as for example a 43550 * suffixed whitespace increases the advanceWidth but not the bounding box 43551 * or an overhanging letter like a calligraphic 'f' mi
43551ght have a quite larger 43552 * bounding box than its advance width. 43553 * 43554 * This corresponds to canvas2dContext.measureText(text).width 43555 * 43556 * @param {string} text - The text to create. 43557 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 43558 * @param {GlyphRenderOptions=} options 43559 * @return advance width 43560 */ 43561 43562 43563 Font.prototype.getAdvanceWidth = function (text, fontSize, options) { 43564 return this.forEachGlyph(text, 0, 0, fontSize, options, function () {}); 43565 }; 43566 /** 43567 * Draw the text on the given drawing context. 43568 * @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. 43569 * @param {string} text - The text to create. 43570 * @param {number} [x=0] - Horizontal position of the beginning of the text. 43571 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 43572 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 43573 * @param {GlyphRenderOptions=} options 43574 */ 43575 43576 43577 Font.prototype.draw = function (ctx, text, x, y, fontSize, options) { 43578 this.getPath(text, x, y, fontSize, options).draw(ctx); 43579 }; 43580 /** 43581 * Draw the points of all glyphs in the text. 43582 * On-curve points will be drawn in blue, off-curve points will be drawn in red. 43583 * @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. 43584 * @param {string} text - The text to create. 43585 * @param {number} [x=0] - Horizontal position of the beginning of the text. 43586 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 43587 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 43588 * @param {GlyphRenderOptions=} options 43589 */ 43590 43591 43592 Font.prototype.drawPoints = function (ctx, text, x, y, fontSize, options) { 43593 this.forEachGlyph(text, x, y, fontSize, options, function (glyph, gX, gY, gFontSize) { 43594 glyph.drawPoints(ctx, gX, gY, gFontSize); 43595 }); 43596 }; 43597 /** 43598 * Draw lines indicating important font measurements for all glyphs in the text. 43599 * Black lines indicate the origin of the coordinate system (point 0,0). 43600 * Blue lines indicate the glyph bounding box. 43601 * Green line indicates the advance width of the glyph. 43602 * @param {CanvasRenderingContext2D} ctx - A 2D drawing context, like Canvas. 43603 * @param {string} text - The text to create. 43604 * @param {number} [x=0] - Horizontal position of the beginning of the text. 43605 * @param {number} [y=0] - Vertical position of the *baseline* of the text. 43606 * @param {number} [fontSize=72] - Font size in pixels. We scale the glyph units by `1 / unitsPerEm * fontSize`. 43607 * @param {GlyphRenderOptions=} options 43608 */ 43609 43610 43611 Font.prototype.drawMetrics = function (ctx, text, x, y, fontSize, options) { 43612 this.forEachGlyph(text, x, y, fontSize, options, function (glyph, gX, gY, gFontSize) { 43613 glyph.drawMetrics(ctx, gX, gY, gFontSize); 43614 }); 43615 }; 43616 /** 43617 * @param {string} 43618 * @return {string} 43619 */ 43620 43621 43622 Font.prototype.getEnglishName = function (name) { 43623 var translations = this.names[name]; 43624 43625 if (translations) { 43626 return translations.en; 43627 } 43628 }; 43629 /** 43630 * Validate 43631 */ 43632 43633 43634 Font.prototype.validate = function () { 43635 var _this = this; 43636 43637 function assert(predicate, message) {} 43638 43639 function assertNamePresent(name) { 43640 var englishName = _this.getEnglishName(name); 43641 43642 assert(englishName && englishName.trim().length > 0, 'No English ' + name + ' specified.'); 43643 } // Identification information 43644 43645 43646 assertNamePresent('fontFamily'); 43647 assertNamePresent('weightName'); 43648 assertNamePresent('manufacturer'); 43649 assertNamePresent('copyright'); 43650 assertNamePresent('version'); // Dimension information 43651 43652 assert(this.unitsPerEm > 0, 'No unitsPerEm specified.'); 43653 }; 43654 /** 43655 * Convert the font object to a SFNT data structure. 43656 * This structure contains all the necessary tables and metadata to create a binary OTF file. 43657 * @return {opentype.Table} 43658 */ 43659 43660 43661 Font.prototype.toTables = function () { 43662 return sfnt.fontToTable(this); 43663 }; 43664 /** 43665 * @deprecated Font.toBuffer is deprecated. Use Font.toArrayBuffer instead. 43666 */ 43667 43668 43669 Font.prototype.toBuffer = function () { 43670 console.warn('Font.toBuffer is deprecated. Use Font.toArrayBuffer instead.'); 43671 return this.toArrayBuffer(); 43672 }; 43673 /** 43674 * Converts a `opentype.Font` into an `ArrayBuffer` 43675 * @return {ArrayBuffer} 43676 */ 43677 43678 43679 Font.prototype.toArrayBuffer = function () { 43680 var sfntTable = this.toTables(); 43681 var bytes = sfntTable.encode(); 43682 var buffer = new ArrayBuffer(bytes.length); 43683 var intArray = new Uint8Array(buffer); 43684 43685 for (var i = 0; i < bytes.length; i++) { 43686 intArray[i] = bytes[i]; 43687 } 43688 43689 return buffer; 43690 }; 43691 /** 43692 * Initiate a download of the OpenType font. 43693 */ 43694 43695 43696 Font.prototype.download = function (fileName) { 43697 var familyName = this.getEnglishName('fontFamily');
43698 var styleName = this.getEnglishName('fontSubfamily'); 43699 fileName = fileName || familyName.replace(/\s/g, '') + '-' + styleName + '.otf'; 43700 var arrayBuffer = this.toArrayBuffer(); 43701 43702 if (isBrowser()) { 43703 window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; 43704 window.requestFileSystem(window.TEMPORARY, arrayBuffer.byteLength, function (fs) { 43705 fs.root.getFile(fileName, { 43706 create: true 43707 }, function (fileEntry) { 43708 fileEntry.createWriter(function (writer) { 43709 var dataView = new DataView(arrayBuffer); 43710 var blob = new Blob([dataView], { 43711 type: 'font/opentype' 43712 }); 43713 writer.write(blob); 43714 writer.addEventListener('writeend', function () { 43715 // Navigating to the file will download it. 43716 location.href = fileEntry.toURL(); 43717 }, false); 43718 }); 43719 }); 43720 }, function (err) { 43721 throw new Error(err.name + ': ' + err.message); 43722 }); 43723 } else { 43724 var fs = _dereq_('fs'); 43725 43726 var buffer = arrayBufferToNodeBuffer(arrayBuffer); 43727 fs.writeFileSync(fileName, buffer); 43728 } 43729 }; 43730 /** 43731 * @private 43732 */ 43733 43734 43735 Font.prototype.fsSelectionValues = { 43736 ITALIC: 0x001, 43737 //1 43738 UNDERSCORE: 0x002, 43739 //2 43740 NEGATIVE: 0x004, 43741 //4 43742 OUTLINED: 0x008, 43743 //8 43744 STRIKEOUT: 0x010, 43745 //16 43746 BOLD: 0x020, 43747 //32 43748 REGULAR: 0x040, 43749 //64 43750 USER_TYPO_METRICS: 0x080, 43751 //128 43752 WWS: 0x100, 43753 //256 43754 OBLIQUE: 0x200 //512 43755 43756 }; 43757 /** 43758 * @private 43759 */ 43760 43761 Font.prototype.usWidthClasses = { 43762 ULTRA_CONDENSED: 1, 43763 EXTRA_CONDENSED: 2, 43764 CONDENSED: 3, 43765 SEMI_CONDENSED: 4, 43766 MEDIUM: 5, 43767 SEMI_EXPANDED: 6, 43768 EXPANDED: 7, 43769 EXTRA_EXPANDED: 8, 43770 ULTRA_EXPANDED: 9 43771 }; 43772 /** 43773 * @private 43774 */ 43775 43776 Font.prototype.usWeightClasses = { 43777 THIN: 100, 43778 EXTRA_LIGHT: 200, 43779 LIGHT: 300, 43780 NORMAL: 400, 43781 MEDIUM: 500, 43782 SEMI_BOLD: 600, 43783 BOLD: 700, 43784 EXTRA_BOLD: 800, 43785 BLACK: 900 43786 }; // The `fvar` table stores font variation axes and instances. 43787 43788 function addName(name, names) { 43789 var nameString = JSON.stringify(name); 43790 var nameID = 256; 43791 43792 for (var nameKey in names) { 43793 var n = parseInt(nameKey); 43794 43795 if (!n || n < 256) { 43796 continue; 43797 } 43798 43799 if (JSON.stringify(names[nameKey]) === nameString) { 43800 return n; 43801 } 43802 43803 if (nameID <= n) { 43804 nameID = n + 1; 43805 } 43806 } 43807 43808 names[nameID] = name; 43809 return nameID; 43810 } 43811 43812 function makeFvarAxis(n, axis, names) { 43813 var nameID = addName(axis.name, names); 43814 return [{ 43815 name: 'tag_' + n, 43816 type: 'TAG', 43817 value: axis.tag 43818 }, { 43819 name: 'minValue_' + n, 43820 type: 'FIXED', 43821 value: axis.minValue << 16 43822 }, { 43823 name: 'defaultValue_' + n, 43824 type: 'FIXED', 43825 value: axis.defaultValue << 16 43826 }, { 43827 name: 'maxValue_' + n, 43828 type: 'FIXED', 43829 value: axis.maxValue << 16 43830 }, { 43831 name: 'flags_' + n, 43832 type: 'USHORT', 43833 value: 0 43834 }, { 43835 name: 'nameID_' + n, 43836 type: 'USHORT', 43837 value: nameID 43838 }]; 43839 } 43840 43841 function parseFvarAxis(data, start, names) { 43842 var axis = {}; 43843 var p = new parse.Parser(data, start); 43844 axis.tag = p.parseTag(); 43845 axis.minValue = p.parseFixed(); 43846 axis.defaultValue = p.parseFixed(); 43847 axis.maxValue = p.parseFixed();
43848 p.skip('uShort', 1); // reserved for flags; no values defined 43849 43850 axis.name = names[p.parseUShort()] || {}; 43851 return axis; 43852 } 43853 43854 function makeFvarInstance(n, inst, axes, names) { 43855 var nameID = addName(inst.name, names); 43856 var fields = [{ 43857 name: 'nameID_' + n, 43858 type: 'USHORT', 43859 value: nameID 43860 }, { 43861 name: 'flags_' + n, 43862 type: 'USHORT', 43863 value: 0 43864 }]; 43865 43866 for (var i = 0; i < axes.length; ++i) { 43867 var axisTag = axes[i].tag; 43868 fields.push({ 43869 name: 'axis_' + n + ' ' + axisTag, 43870 type: 'FIXED', 43871 value: inst.coordinates[axisTag] << 16 43872 }); 43873 } 43874 43875 return fields; 43876 } 43877 43878 function parseFvarInstance(data, start, axes, names) { 43879 var inst = {}; 43880 var p = new parse.Parser(data, start); 43881 inst.name = names[p.parseUShort()] || {};
43882 p.skip('uShort', 1); // reserved for flags; no values defined 43883 43884 inst.coordinates = {}; 43885 43886 for (var i = 0; i < axes.length; ++i) { 43887 inst.coordinates[axes[i].tag] = p.parseFixed(); 43888 } 43889 43890 return inst; 43891 } 43892 43893 function makeFvarTable(fvar, names) { 43894 var result = new table.Table('fvar', [{ 43895 name: 'version', 43896 type: 'ULONG', 43897 value: 0x10000 43898 }, { 43899 name: 'offsetToData', 43900 type: 'USHORT', 43901 value: 0 43902 }, { 43903 name: 'countSizePairs', 43904 type: 'USHORT', 43905 value: 2 43906 }, { 43907 name: 'axisCount', 43908 type: 'USHORT', 43909 value: fvar.axes.length 43910 }, { 43911 name: 'axisSize', 43912 type: 'USHORT', 43913 value: 20 43914 }, { 43915 name: 'instanceCount', 43916 type: 'USHORT', 43917 value: fvar.instances.length 43918 }, { 43919 name: 'instanceSize', 43920 type: 'USHORT', 43921 value: 4 + fvar.axes.length * 4 43922 }]); 43923 result.offsetToData = result.sizeOf(); 43924 43925 for (var i = 0; i < fvar.axes.length; i++) { 43926 result.fields = result.fields.concat(makeFvarAxis(i, fvar.axes[i], names)); 43927 } 43928 43929 for (var j = 0; j < fvar.instances.length; j++) { 43930 result.fields = result.fields.concat(makeFvarInstance(j, fvar.instances[j], fvar.axes, names)); 43931 } 43932 43933 return result; 43934 } 43935 43936 function parseFvarTable(data, start, names) { 43937 var p = new parse.Parser(data, start); 43938 var tableVersion = p.parseULong(); 43939 check.argument(tableVersion === 0x00010000, 'Unsupported fvar table version.'); 43940 var offsetToData = p.parseOffset16(); // Skip countSizePairs. 43941
vendor: 4,756 bytes, lines 43942-44065
43942 p.skip('uShort', 1); 43943 var axisCount = p.parseUShort(); 43944 var axisSize = p.parseUShort(); 43945 var instanceCount = p.parseUShort(); 43946 var instanceSize = p.parseUShort(); 43947 var axes = []; 43948 43949 for (var i = 0; i < axisCount; i++) { 43950 axes.push(parseFvarAxis(data, start + offsetToData + i * axisSize, names)); 43951 } 43952 43953 var instances = []; 43954 var instanceStart = start + offsetToData + axisCount * axisSize; 43955 43956 for (var j = 0; j < instanceCount; j++) { 43957 instances.push(parseFvarInstance(data, instanceStart + j * instanceSize, axes, names)); 43958 } 43959 43960 return { 43961 axes: axes, 43962 instances: instances 43963 }; 43964 } 43965 43966 var fvar = { 43967 make: makeFvarTable, 43968 parse: parseFvarTable 43969 }; // The `GPOS` table contains kerning pairs, among other things. 43970 43971 var subtableParsers$1 = new Array(10); // subtableParsers[0] is unused 43972 // https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable 43973 // this = Parser instance 43974 43975 subtableParsers$1[1] = function parseLookup1() { 43976 var start = this.offset + this.relativeOffset; 43977 var posformat = this.parseUShort(); 43978 43979 if (posformat === 1) { 43980 return { 43981 posFormat: 1, 43982 coverage: this.parsePointer(Parser.coverage), 43983 value: this.parseValueRecord() 43984 }; 43985 } else if (posformat === 2) { 43986 return { 43987 posFormat: 2, 43988 coverage: this.parsePointer(Parser.coverage), 43989 values: this.parseValueRecordList() 43990 }; 43991 } 43992 43993 check.assert(false, '0x' + start.toString(16) + ': GPOS lookup type 1 format must be 1 or 2.'); 43994 }; // https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-2-pair-adjustment-positioning-subtable 43995 43996 43997 subtableParsers$1[2] = function parseLookup2() { 43998 var start = this.offset + this.relativeOffset; 43999 var posFormat = this.parseUShort(); 44000 check.assert(posFormat === 1 || posFormat === 2, '0x' + start.toString(16) + ': GPOS lookup type 2 format must be 1 or 2.'); 44001 var coverage = this.parsePointer(Parser.coverage); 44002 var valueFormat1 = this.parseUShort(); 44003 var valueFormat2 = this.parseUShort(); 44004 44005 if (posFormat === 1) { 44006 // Adjustments for Glyph Pairs 44007 return { 44008 posFormat: posFormat, 44009 coverage: coverage, 44010 valueFormat1: valueFormat1, 44011 valueFormat2: valueFormat2, 44012 pairSets: this.parseList(Parser.pointer(Parser.list(function () { 44013 return { 44014 // pairValueRecord 44015 secondGlyph: this.parseUShort(), 44016 value1: this.parseValueRecord(valueFormat1), 44017 value2: this.parseValueRecord(valueFormat2) 44018 }; 44019 }))) 44020 }; 44021 } else if (posFormat === 2) { 44022 var classDef1 = this.parsePointer(Parser.classDef); 44023 var classDef2 = this.parsePointer(Parser.classDef); 44024 var class1Count = this.parseUShort(); 44025 var class2Count = this.parseUShort(); 44026 return { 44027 // Class Pair Adjustment 44028 posFormat: posFormat, 44029 coverage: coverage, 44030 valueFormat1: valueFormat1, 44031 valueFormat2: valueFormat2, 44032 classDef1: classDef1, 44033 classDef2: classDef2, 44034 class1Count: class1Count, 44035 class2Count: class2Count, 44036 classRecords: this.parseList(class1Count, Parser.list(class2Count, function () { 44037 return { 44038 value1: this.parseValueRecord(valueFormat1), 44039 value2: this.parseValueRecord(valueFormat2) 44040 }; 44041 })) 44042 }; 44043 } 44044 }; 44045 44046 subtableParsers$1[3] = function parseLookup3() { 44047 return { 44048 error: 'GPOS Lookup 3 not supported' 44049 }; 44050 }; 44051 44052 subtableParsers$1[4] = function parseLookup4() { 44053 return { 44054 error: 'GPOS Lookup 4 not supported' 44055 }; 44056 }; 44057 44058 subtableParsers$1[5] = function parseLookup5() { 44059 return { 44060 error: 'GPOS Lookup 5 not supported' 44061 }; 44062 }; 44063 44064 subtableParsers$1[6] = function parseLookup6() { 44065 return {
44066 error: 'GPOS Lookup 6 not supported' 44067 }; 44068 }; 44069 44070 subtableParsers$1[7] = function parseLookup7() { 44071 return { 44072 error: 'GPOS Lookup 7 not supported' 44073 }; 44074 }; 44075 44076 subtableParsers$1[8] = function parseLookup8() { 44077 return { 44078 error: 'GPOS Lookup 8 not supported' 44079 }; 44080 }; 44081 44082 subtableParsers$1[9] = function parseLookup9() { 44083 return { 44084 error: 'GPOS Lookup 9 not supported' 44085 }; 44086 }; // https://docs.microsoft.com/en-us/typography/opentype/spec/gpos 44087 44088 44089 function parseGposTable(data, start) { 44090 start = start || 0; 44091 var p = new Parser(data, start); 44092 var tableVersion = p.parseVersion(1); 44093 check.argument(tableVersion === 1 || tableVersion === 1.1, 'Unsupported GPOS table version ' + tableVersion); 44094 44095 if (tableVersion === 1) { 44096 return { 44097 version: tableVersion, 44098 scripts: p.parseScriptList(), 44099 features: p.parseFeatureList(), 44100 lookups: p.parseLookupList(subtableParsers$1) 44101 }; 44102 } else { 44103 return { 44104 version: tableVersion, 44105 scripts: p.parseScriptList(), 44106 features: p.parseFeatureList(), 44107 lookups: p.parseLookupList(subtableParsers$1), 44108 variations: p.parseFeatureVariationsList() 44109 }; 44110 } 44111 } // GPOS Writing ////////////////////////////////////////////// 44112 // NOT SUPPORTED 44113 44114 44115 var subtableMakers$1 = new Array(10); 44116 44117 function makeGposTable(gpos) { 44118 return new table.Table('GPOS', [{ 44119 name: 'version', 44120 type: 'ULONG', 44121 value: 0x10000 44122 }, { 44123 name: 'scripts', 44124 type: 'TABLE', 44125 value: new table.ScriptList(gpos.scripts) 44126 }, { 44127 name: 'features', 44128 type: 'TABLE', 44129 value: new table.FeatureList(gpos.features) 44130 }, { 44131 name: 'lookups', 44132 type: 'TABLE', 44133 value: new table.LookupList(gpos.lookups, subtableMakers$1) 44134 }]); 44135 } 44136 44137 var gpos = { 44138 parse: parseGposTable, 44139 make: makeGposTable 44140 }; // The `kern` table contains kerning pairs. 44141 44142 function parseWindowsKernTable(p) { 44143 var pairs = {}; // Skip nTables. 44144 44145 p.skip('uShort'); 44146 var subtableVersion = p.parseUShort(); 44147 check.argument(subtableVersion === 0, 'Unsupported kern sub-table version.'); // Skip subtableLength, subtableCoverage 44148 44149 p.skip('uShort', 2); 44150 var nPairs = p.parseUShort(); // Skip searchRange, entrySelector, rangeShift. 44151 44152 p.skip('uShort', 3); 44153 44154 for (var i = 0; i < nPairs; i += 1) { 44155 var leftIndex = p.parseUShort(); 44156 var rightIndex = p.parseUShort(); 44157 var value = p.parseShort(); 44158 pairs[leftIndex + ',' + rightIndex] = value; 44159 } 44160 44161 return pairs; 44162 } 44163 44164 function parseMacKernTable(p) { 44165 var pairs = {}; // The Mac kern table stores the version as a fixed (32 bits) but we only loaded the first 16 bits. 44166 // Skip the rest. 44167 44168 p.skip('uShort'); 44169 var nTables = p.parseULong(); //check.argument(nTables === 1, 'Only 1 subtable is supported (got ' + nTables + ').'); 44170 44171 if (nTables > 1) { 44172 console.warn('Only the first kern subtable is supported.'); 44173 } 44174 44175 p.skip('uLong'); 44176 var coverage = p.parseUShort(); 44177 var subtableVersion = coverage & 0xFF; 44178 p.skip('uShort'); 44179 44180 if (subtableVersion === 0) { 44181 var nPairs = p.parseUShort(); // Skip searchRange, entrySelector, rangeShift. 44182 44183 p.skip('uShort', 3); 44184 44185 for (var i = 0; i < nPairs; i += 1) { 44186 var leftIndex = p.parseUShort(); 44187 var rightIndex = p.parseUShort(); 44188 var value = p.parseShort(); 44189 pairs[leftIndex + ',' + rightIndex] = value; 44190 } 44191 } 44192 44193 return pairs; 44194 } // Parse the `kern` table which contains kerning pairs. 44195 44196 44197 function parseKernTable(data, start) { 44198 var p = new parse.Parser(data, start); 44199 var tableVersion = p.parseUShort(); 44200 44201 if (tableVersion === 0) { 44202 return parseWindowsKernTable(p); 44203 } else if (tableVersion === 1) { 44204 return parseMacKernTable(p); 44205 } else { 44206 throw new Error('Unsupported kern table version (' + tableVersion + ').'); 44207 } 44208 } 44209 44210 var kern = { 44211 parse: parseKernTable 44212 }; // The `loca` table stores the offsets to the locations of the glyphs in the font. 44213 // Parse the `loca` table. This table stores the offsets to the locations of the glyphs in the font, 44214 // relative to the beginning of the glyphData table. 44215 // The number of glyphs stored in the `loca` table is specified in the `maxp` table (under numGlyphs)
44216 // The loca table has two versions: a short version where offsets are stored as uShorts, and a long 44217 // version where offsets are stored as uLongs. The `head` table specifies which version to use 44218 // (under indexToLocFormat). 44219 44220 function parseLocaTable(data, start, numGlyphs, shortVersion) { 44221 var p = new parse.Parser(data, start); 44222 var parseFn = shortVersion ? p.parseUShort : p.parseULong; // There is an extra entry after the last index element to compute the length of the last glyph. 44223 // That's why we use numGlyphs + 1. 44224 44225 var glyphOffsets = []; 44226 44227 for (var i = 0; i < numGlyphs + 1; i += 1) { 44228 var glyphOffset = parseFn.call(p); 44229 44230 if (shortVersion) { 44231 // The short table version stores the actual offset divided by 2. 44232 glyphOffset *= 2; 44233 } 44234 44235 glyphOffsets.push(glyphOffset); 44236 } 44237 44238 return glyphOffsets; 44239 } 44240 44241 var loca = { 44242 parse: parseLocaTable 44243 }; // opentype.js 44244 44245 /** 44246 * The opentype library. 44247 * @namespace opentype 44248 */ 44249 // File loaders ///////////////////////////////////////////////////////// 44250 44251 /** 44252 * Loads a font from a file. The callback throws an error message as the first parameter if it fails 44253 * and the font as an ArrayBuffer in the second parameter if it succeeds. 44254 * @param {string} path - The path of the file 44255 * @param {Function} callback - The function to call when the font load completes 44256 */ 44257 44258 function loadFromFile(path, callback) { 44259 var fs = _dereq_('fs'); 44260 44261 fs.readFile(path, function (err, buffer) { 44262 if (err) { 44263 return callback(err.message); 44264 } 44265 44266 callback(null, nodeBufferToArrayBuffer(buffer)); 44267 }); 44268 } 44269 /** 44270 * Loads a font from a URL. The callback throws an error message as the first parameter if it fails 44271 * and the font as an ArrayBuffer in the second parameter if it succeeds. 44272 * @param {string} url - The URL of the font file. 44273 * @param {Function} callback - The function to call when the font load completes 44274 */ 44275 44276 44277 function loadFromUrl(url, callback) { 44278 var request = new XMLHttpRequest(); 44279 request.open('get', url, true); 44280 request.responseType = 'arraybuffer'; 44281 44282 request.onload = function () { 44283 if (request.response) { 44284 return callback(null, request.response); 44285 } else { 44286 return callback('Font could not be loaded: ' + request.statusText); 44287 } 44288 }; 44289 44290 request.onerror = function () { 44291 callback('Font could not be loaded'); 44292 }; 44293 44294 request.send(); 44295 } // Table Directory Entries ////////////////////////////////////////////// 44296 44297 /** 44298 * Parses OpenType table entries. 44299 * @param {DataView} 44300 * @param {Number} 44301 * @return {Object[]} 44302 */ 44303 44304 44305 function parseOpenTypeTableEntries(data, numTables) { 44306 var tableEntries = []; 44307 var p = 12; 44308 44309 for (var i = 0; i < numTables; i += 1) { 44310 var tag = parse.getTag(data, p); 44311 var checksum = parse.getULong(data, p + 4); 44312 var offset = parse.getULong(data, p + 8); 44313 var length = parse.getULong(data, p + 12); 44314 tableEntries.push({ 44315 tag: tag, 44316 checksum: checksum, 44317 offset: offset, 44318 length: length, 44319 compression: false 44320 }); 44321 p += 16; 44322 } 44323 44324 return tableEntries; 44325 } 44326 /** 44327 * Parses WOFF table entries. 44328 * @param {DataView} 44329 * @param {Number} 44330 * @return {Object[]} 44331 */ 44332 44333 44334 function parseWOFFTableEntries(data, numTables) { 44335 var tableEntries = []; 44336 var p = 44; // offset to the first table directory entry. 44337 44338 for (var i = 0; i < numTables; i += 1) { 44339 var tag = parse.getTag(data, p); 44340 var offset = parse.getULong(data, p + 4); 44341 var compLength = parse.getULong(data, p + 8); 44342 var origLength = parse.getULong(data, p + 12); 44343 var compression = void 0; 44344 44345 if (compLength < origLength) { 44346 compression = 'WOFF'; 44347 } else { 44348 compression = false;
vendor: 8,505 bytes, lines 44349-44577
44349 } 44350 44351 tableEntries.push({ 44352 tag: tag, 44353 offset: offset, 44354 compression: compression, 44355 compressedLength: compLength, 44356 length: origLength 44357 }); 44358 p += 20; 44359 } 44360 44361 return tableEntries; 44362 } 44363 /** 44364 * @typedef TableData 44365 * @type Object 44366 * @property {DataView} data - The DataView 44367 * @property {number} offset - The data offset. 44368 */ 44369 44370 /** 44371 * @param {DataView} 44372 * @param {Object} 44373 * @return {TableData} 44374 */ 44375 44376 44377 function uncompressTable(data, tableEntry) { 44378 if (tableEntry.compression === 'WOFF') { 44379 var inBuffer = new Uint8Array(data.buffer, tableEntry.offset + 2, tableEntry.compressedLength - 2); 44380 var outBuffer = new Uint8Array(tableEntry.length); 44381 tinyInflate(inBuffer, outBuffer); 44382 44383 if (outBuffer.byteLength !== tableEntry.length) { 44384 throw new Error('Decompression error: ' + tableEntry.tag + ' decompressed length doesn\'t match recorded length'); 44385 } 44386 44387 var view = new DataView(outBuffer.buffer, 0); 44388 return { 44389 data: view, 44390 offset: 0 44391 }; 44392 } else { 44393 return { 44394 data: data, 44395 offset: tableEntry.offset 44396 }; 44397 } 44398 } // Public API /////////////////////////////////////////////////////////// 44399 44400 /** 44401 * Parse the OpenType file data (as an ArrayBuffer) and return a Font object. 44402 * Throws an error if the font could not be parsed. 44403 * @param {ArrayBuffer} 44404 * @return {opentype.Font} 44405 */ 44406 44407 44408 function parseBuffer(buffer) { 44409 var indexToLocFormat; 44410 var ltagTable; // Since the constructor can also be called to create new fonts from scratch, we indicate this 44411 // should be an empty font that we'll fill with our own data. 44412 44413 var font = new Font({ 44414 empty: true 44415 }); // OpenType fonts use big endian byte ordering. 44416 // We can't rely on typed array view types, because they operate with the endianness of the host computer. 44417 // Instead we use DataViews where we can specify endianness. 44418 44419 var data = new DataView(buffer, 0); 44420 var numTables; 44421 var tableEntries = []; 44422 var signature = parse.getTag(data, 0); 44423 44424 if (signature === String.fromCharCode(0, 1, 0, 0) || signature === 'true' || signature === 'typ1') { 44425 font.outlinesFormat = 'truetype'; 44426 numTables = parse.getUShort(data, 4); 44427 tableEntries = parseOpenTypeTableEntries(data, numTables); 44428 } else if (signature === 'OTTO') { 44429 font.outlinesFormat = 'cff'; 44430 numTables = parse.getUShort(data, 4); 44431 tableEntries = parseOpenTypeTableEntries(data, numTables); 44432 } else if (signature === 'wOFF') { 44433 var flavor = parse.getTag(data, 4); 44434 44435 if (flavor === String.fromCharCode(0, 1, 0, 0)) { 44436 font.outlinesFormat = 'truetype'; 44437 } else if (flavor === 'OTTO') { 44438 font.outlinesFormat = 'cff'; 44439 } else { 44440 throw new Error('Unsupported OpenType flavor ' + signature); 44441 } 44442 44443 numTables = parse.getUShort(data, 12); 44444 tableEntries = parseWOFFTableEntries(data, numTables); 44445 } else { 44446 throw new Error('Unsupported OpenType signature ' + signature); 44447 } 44448 44449 var cffTableEntry; 44450 var fvarTableEntry; 44451 var glyfTableEntry; 44452 var gposTableEntry; 44453 var gsubTableEntry; 44454 var hmtxTableEntry; 44455 var kernTableEntry; 44456 var locaTableEntry; 44457 var nameTableEntry; 44458 var metaTableEntry; 44459 var p; 44460 44461 for (var i = 0; i < numTables; i += 1) { 44462 var tableEntry = tableEntries[i]; 44463 var table = void 0; 44464 44465 switch (tableEntry.tag) { 44466 case 'cmap': 44467 table = uncompressTable(data, tableEntry); 44468 font.tables.cmap = cmap.parse(table.data, table.offset); 44469 font.encoding = new CmapEncoding(font.tables.cmap); 44470 break; 44471 44472 case 'cvt ': 44473 table = uncompressTable(data, tableEntry); 44474 p = new parse.Parser(table.data, table.offset); 44475 font.tables.cvt = p.parseShortList(tableEntry.length / 2); 44476 break; 44477 44478 case 'fvar': 44479 fvarTableEntry = tableEntry; 44480 break; 44481 44482 case 'fpgm': 44483 table = uncompressTable(data, tableEntry); 44484 p = new parse.Parser(table.data, table.offset); 44485 font.tables.fpgm = p.parseByteList(tableEntry.length); 44486 break; 44487 44488 case 'head': 44489 table = uncompressTable(data, tableEntry); 44490 font.tables.head = head.parse(table.data, table.offset); 44491 font.unitsPerEm = font.tables.head.unitsPerEm; 44492 indexToLocFormat = font.tables.head.indexToLocFormat; 44493 break; 44494 44495 case 'hhea': 44496 table = uncompressTable(data, tableEntry); 44497 font.tables.hhea = hhea.parse(table.data, table.offset); 44498 font.ascender = font.tables.hhea.ascender; 44499 font.descender = font.tables.hhea.descender; 44500 font.numberOfHMetrics = font.tables.hhea.numberOfHMetrics; 44501 break; 44502 44503 case 'hmtx': 44504 hmtxTableEntry = tableEntry; 44505 break; 44506 44507 case 'ltag': 44508 table = uncompressTable(data, tableEntry); 44509 ltagTable = ltag.parse(table.data, table.offset); 44510 break; 44511 44512 case 'maxp': 44513 table = uncompressTable(data, tableEntry); 44514 font.tables.maxp = maxp.parse(table.data, table.offset); 44515 font.numGlyphs = font.tables.maxp.numGlyphs; 44516 break; 44517 44518 case 'name': 44519 nameTableEntry = tableEntry; 44520 break; 44521 44522 case 'OS/2': 44523 table = uncompressTable(data, tableEntry); 44524 font.tables.os2 = os2.parse(table.data, table.offset); 44525 break; 44526 44527 case 'post': 44528 table = uncompressTable(data, tableEntry); 44529 font.tables.post = post.parse(table.data, table.offset); 44530 font.glyphNames = new GlyphNames(font.tables.post); 44531 break; 44532 44533 case 'prep': 44534 table = uncompressTable(data, tableEntry); 44535 p = new parse.Parser(table.data, table.offset); 44536 font.tables.prep = p.parseByteList(tableEntry.length); 44537 break; 44538 44539 case 'glyf': 44540 glyfTableEntry = tableEntry; 44541 break; 44542 44543 case 'loca': 44544 locaTableEntry = tableEntry; 44545 break; 44546 44547 case 'CFF ': 44548 cffTableEntry = tableEntry; 44549 break; 44550 44551 case 'kern': 44552 kernTableEntry = tableEntry; 44553 break; 44554 44555 case 'GPOS': 44556 gposTableEntry = tableEntry; 44557 break; 44558 44559 case 'GSUB': 44560 gsubTableEntry = tableEntry; 44561 break; 44562 44563 case 'meta': 44564 metaTableEntry = tableEntry; 44565 break; 44566 } 44567 } 44568 44569 var nameTable = uncompressTable(data, nameTableEntry); 44570 font.tables.name = _name.parse(nameTable.data, nameTable.offset, ltagTable); 44571 font.names = font.tables.name; 44572 44573 if (glyfTableEntry && locaTableEntry) { 44574 var shortVersion = indexToLocFormat === 0; 44575 var locaTable = uncompressTable(data, locaTableEntry); 44576 var locaOffsets = loca.parse(locaTable.data, locaTable.offset, font.numGlyphs, shortVersion); 44577 var glyfTable = uncompressTable(data, glyfTableEntry
44577); 44578 font.glyphs = glyf.parse(glyfTable.data, glyfTable.offset, locaOffsets, font); 44579 } else if (cffTableEntry) { 44580 var cffTable = uncompressTable(data, cffTableEntry); 44581 cff.parse(cffTable.data, cffTable.offset, font); 44582 } else { 44583 throw new Error('Font doesn\'t contain TrueType or CFF outlines.'); 44584 } 44585 44586 var hmtxTable = uncompressTable(data, hmtxTableEntry); 44587 hmtx.parse(hmtxTable.data, hmtxTable.offset, font.numberOfHMetrics, font.numGlyphs, font.glyphs); 44588 addGlyphNames(font); 44589 44590 if (kernTableEntry) { 44591 var kernTable = uncompressTable(data, kernTableEntry); 44592 font.kerningPairs = kern.parse(kernTable.data, kernTable.offset); 44593 } else { 44594 font.kerningPairs = {}; 44595 } 44596 44597 if (gposTableEntry) { 44598 var gposTable = uncompressTable(data, gposTableEntry); 44599 font.tables.gpos = gpos.parse(gposTable.data, gposTable.offset); 44600 font.position.init(); 44601 } 44602 44603 if (gsubTableEntry) { 44604 var gsubTable = uncompressTable(data, gsubTableEntry); 44605 font.tables.gsub = gsub.parse(gsubTable.data, gsubTable.offset); 44606 } 44607 44608 if (fvarTableEntry) { 44609 var fvarTable = uncompressTable(data, fvarTableEntry); 44610 font.tables.fvar = fvar.parse(fvarTable.data, fvarTable.offset, font.names); 44611 } 44612 44613 if (metaTableEntry) { 44614 var metaTable = uncompressTable(data, metaTableEntry); 44615 font.tables.meta = meta.parse(metaTable.data, metaTable.offset); 44616 font.metas = font.tables.meta; 44617 } 44618 44619 return font; 44620 } 44621 /** 44622 * Asynchronously load the font from a URL or a filesystem. When done, call the callback 44623 * with two arguments `(err, font)`. The `err` will be null on success, 44624 * the `font` is a Font object. 44625 * We use the node.js callback convention so that 44626 * opentype.js can integrate with frameworks like async.js. 44627 * @alias opentype.load 44628 * @param {string} url - The URL of the font to load. 44629 * @param {Function} callback - The callback. 44630 */ 44631 44632 44633 function load(url, callback) { 44634 var isNode$$1 = typeof window === 'undefined'; 44635 var loadFn = isNode$$1 ? loadFromFile : loadFromUrl; 44636 loadFn(url, function (err, arrayBuffer) { 44637 if (err) { 44638 return callback(err); 44639 } 44640 44641 var font; 44642 44643 try { 44644 font = parseBuffer(arrayBuffer); 44645 } catch (e) { 44646 return callback(e, null); 44647 } 44648 44649 return callback(null, font); 44650 }); 44651 } 44652 /** 44653 * Synchronously load the font from a URL or file. 44654 * When done, returns the font object or throws an error. 44655 * @alias opentype.loadSync 44656 * @param {string} url - The URL of the font to load. 44657 * @return {opentype.Font} 44658 */ 44659 44660 44661 function loadSync(url) { 44662 var fs = _dereq_('fs'); 44663 44664 var buffer = fs.readFileSync(url); 44665 return parseBuffer(nodeBufferToArrayBuffer(buffer)); 44666 } 44667 44668 exports.Font = Font; 44669 exports.Glyph = Glyph; 44670 exports.Path = Path; 44671 exports.BoundingBox = BoundingBox; 44672 exports._parse = parse; 44673 exports.parse = parseBuffer; 44674 exports.load = load; 44675 exports.loadSync = loadSync; 44676 Object.defineProperty(exports, '__esModule', { 44677 value: true 44678 }); 44679 }); 44680 }).call(this, _dereq_("buffer").Buffer); 44681 }, { 44682 "buffer": 4, 44683 "fs": 3 44684 }], 44685 11: [function (_dereq_, module, exports) { 44686 // shim for using process in browser 44687 var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it 44688 // don't break things. But we need to wrap it in a try catch in case it is
vendor: 4,237 bytes, lines 44689-44825
44689 // wrapped in strict mode code which doesn't define any globals. It's inside a 44690 // function because try/catches deoptimize in certain engines. 44691 44692 var cachedSetTimeout; 44693 var cachedClearTimeout; 44694 44695 function defaultSetTimout() { 44696 throw new Error('setTimeout has not been defined'); 44697 } 44698 44699 function defaultClearTimeout() { 44700 throw new Error('clearTimeout has not been defined'); 44701 } 44702 44703 (function () { 44704 try { 44705 if (typeof setTimeout === 'function') { 44706 cachedSetTimeout = setTimeout; 44707 } else { 44708 cachedSetTimeout = defaultSetTimout; 44709 } 44710 } catch (e) { 44711 cachedSetTimeout = defaultSetTimout; 44712 } 44713 44714 try { 44715 if (typeof clearTimeout === 'function') { 44716 cachedClearTimeout = clearTimeout; 44717 } else { 44718 cachedClearTimeout = defaultClearTimeout; 44719 } 44720 } catch (e) { 44721 cachedClearTimeout = defaultClearTimeout; 44722 } 44723 })(); 44724 44725 function runTimeout(fun) { 44726 if (cachedSetTimeout === setTimeout) { 44727 //normal enviroments in sane situations 44728 return setTimeout(fun, 0); 44729 } // if setTimeout wasn't available but was latter defined 44730 44731 44732 if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { 44733 cachedSetTimeout = setTimeout; 44734 return setTimeout(fun, 0); 44735 } 44736 44737 try { 44738 // when when somebody has screwed with setTimeout but no I.E. maddness 44739 return cachedSetTimeout(fun, 0); 44740 } catch (e) { 44741 try { 44742 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 44743 return cachedSetTimeout.call(null, fun, 0); 44744 } catch (e) { 44745 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error 44746 return cachedSetTimeout.call(this, fun, 0); 44747 } 44748 } 44749 } 44750 44751 function runClearTimeout(marker) { 44752 if (cachedClearTimeout === clearTimeout) { 44753 //normal enviroments in sane situations 44754 return clearTimeout(marker); 44755 } // if clearTimeout wasn't available but was latter defined 44756 44757 44758 if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { 44759 cachedClearTimeout = clearTimeout; 44760 return clearTimeout(marker); 44761 } 44762 44763 try { 44764 // when when somebody has screwed with setTimeout but no I.E. maddness 44765 return cachedClearTimeout(marker); 44766 } catch (e) { 44767 try { 44768 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 44769 return cachedClearTimeout.call(null, marker); 44770 } catch (e) { 44771 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. 44772 // Some versions of I.E. have different rules for clearTimeout vs setTimeout 44773 return cachedClearTimeout.call(this, marker); 44774 } 44775 } 44776 } 44777 44778 var queue = []; 44779 var draining = false; 44780 var currentQueue; 44781 var queueIndex = -1; 44782 44783 function cleanUpNextTick() { 44784 if (!draining || !currentQueue) { 44785 return; 44786 } 44787 44788 draining = false; 44789 44790 if (currentQueue.length) { 44791 queue = currentQueue.concat(queue); 44792 } else { 44793 queueIndex = -1; 44794 } 44795 44796 if (queue.length) { 44797 drainQueue(); 44798 } 44799 } 44800 44801 function drainQueue() { 44802 if (draining) { 44803 return; 44804 } 44805 44806 var timeout = runTimeout(cleanUpNextTick); 44807 draining = true; 44808 var len = queue.length; 44809 44810 while (len) { 44811 currentQueue = queue; 44812 queue = []; 44813 44814 while (++queueIndex < len) { 44815 if (currentQueue) { 44816 currentQueue[queueIndex].run(); 44817 } 44818 } 44819 44820 queueIndex = -1; 44821 len = queue.length; 44822 } 44823 44824 currentQueue = null; 44825 draining = false;
44826 runClearTimeout(timeout); 44827 } 44828 44829 process.nextTick = function (fun) { 44830 var args = new Array(arguments.length - 1); 44831 44832 if (arguments.length > 1) { 44833 for (var i = 1; i < arguments.length; i++) { 44834 args[i - 1] = arguments[i]; 44835 } 44836 } 44837 44838 queue.push(new Item(fun, args)); 44839 44840 if (queue.length === 1 && !draining) { 44841 runTimeout(drainQueue); 44842 } 44843 }; // v8 likes predictible objects 44844 44845 44846 function Item(fun, array) { 44847 this.fun = fun; 44848 this.array = array; 44849 } 44850 44851 Item.prototype.run = function () { 44852 this.fun.apply(null, this.array); 44853 }; 44854 44855 process.title = 'browser'; 44856 process.env = {}; 44857 process.argv = []; 44858 process.version = ''; // empty string to avoid regexp issues 44859 44860 process.versions = {}; 44861 44862 function noop() {} 44863 44864 process.on = noop; 44865 process.addListener = noop; 44866 process.once = noop; 44867 process.off = noop; 44868 process.removeListener = noop; 44869 process.removeAllListeners = noop; 44870 process.emit = noop; 44871 process.prependListener = noop; 44872 process.prependOnceListener = noop; 44873 44874 process.listeners = function (name) { 44875 return []; 44876 }; 44877 44878 process.binding = function (name) { 44879 throw new Error('process.binding is not supported'); 44880 }; 44881 44882 process.cwd = function () { 44883 return '/'; 44884 }; 44885 44886 process.chdir = function (dir) { 44887 throw new Error('process.chdir is not supported'); 44888 }; 44889 44890 process.umask = function () { 44891 return 0; 44892 }; 44893 }, {}], 44894 12: [function (_dereq_, module, exports) { 44895 (function (self) { 44896 'use strict'; 44897 44898 if (self.fetch) { 44899 return; 44900 } 44901 44902 var support = { 44903 searchParams: 'URLSearchParams' in self, 44904 iterable: 'Symbol' in self && 'iterator' in Symbol, 44905 blob: 'FileReader' in self && 'Blob' in self && function () { 44906 try { 44907 new Blob(); 44908 return true; 44909 } catch (e) { 44910 return false; 44911 } 44912 }(), 44913 formData: 'FormData' in self, 44914 arrayBuffer: 'ArrayBuffer' in self 44915 }; 44916 44917 if (support.arrayBuffer) { 44918 var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]']; 44919 44920 var isDataView = function (obj) { 44921 return obj && DataView.prototype.isPrototypeOf(obj); 44922 }; 44923 44924 var isArrayBufferView = ArrayBuffer.isView || function (obj) { 44925 return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1; 44926 }; 44927 } 44928 44929 function normalizeName(name) { 44930 if (typeof name !== 'string') { 44931 name = String(name); 44932 } 44933 44934 if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { 44935 throw new TypeError('Invalid character in header field name'); 44936 } 44937 44938 return name.toLowerCase(); 44939 } 44940 44941 function normalizeValue(value) { 44942 if (typeof value !== 'string') { 44943 value = String(value); 44944 } 44945 44946 return value; 44947 } // Build a destructive iterator for the value list 44948 44949 44950 function iteratorFor(items) { 44951 var iterator = { 44952 next: function () { 44953 var value = items.shift(); 44954 return { 44955 done: value === undefined, 44956 value: value 44957 }; 44958 } 44959 }; 44960 44961 if (support.iterable) { 44962 iterator[Symbol.iterator] = function () { 44963 return iterator; 44964 }; 44965 } 44966 44967 return iterator; 44968 } 44969 44970 function Headers(headers) { 44971 this.map = {}; 44972 44973 if (headers instanceof Headers) { 44974 headers.forEach(function (value, name) { 44975 this.append(name, value); 44976 }, this); 44977 } else if (Array.isArray(headers)) { 44978 headers.forEach(function (header) { 44979 this.append(header[0], header[1]); 44980 }, this); 44981 } else if (headers) {
vendor: 7,195 bytes, lines 44982-45201
44982 Object.getOwnPropertyNames(headers).forEach(function (name) { 44983 this.append(name, headers[name]); 44984 }, this); 44985 } 44986 } 44987 44988 Headers.prototype.append = function (name, value) { 44989 name = normalizeName(name); 44990 value = normalizeValue(value); 44991 var oldValue = this.map[name]; 44992 this.map[name] = oldValue ? oldValue + ',' + value : value; 44993 }; 44994 44995 Headers.prototype['delete'] = function (name) { 44996 delete this.map[normalizeName(name)]; 44997 }; 44998 44999 Headers.prototype.get = function (name) { 45000 name = normalizeName(name); 45001 return this.has(name) ? this.map[name] : null; 45002 }; 45003 45004 Headers.prototype.has = function (name) { 45005 return this.map.hasOwnProperty(normalizeName(name)); 45006 }; 45007 45008 Headers.prototype.set = function (name, value) { 45009 this.map[normalizeName(name)] = normalizeValue(value); 45010 }; 45011 45012 Headers.prototype.forEach = function (callback, thisArg) { 45013 for (var name in this.map) { 45014 if (this.map.hasOwnProperty(name)) { 45015 callback.call(thisArg, this.map[name], name, this); 45016 } 45017 } 45018 }; 45019 45020 Headers.prototype.keys = function () { 45021 var items = []; 45022 this.forEach(function (value, name) { 45023 items.push(name); 45024 }); 45025 return iteratorFor(items); 45026 }; 45027 45028 Headers.prototype.values = function () { 45029 var items = []; 45030 this.forEach(function (value) { 45031 items.push(value); 45032 }); 45033 return iteratorFor(items); 45034 }; 45035 45036 Headers.prototype.entries = function () { 45037 var items = []; 45038 this.forEach(function (value, name) { 45039 items.push([name, value]); 45040 }); 45041 return iteratorFor(items); 45042 }; 45043 45044 if (support.iterable) { 45045 Headers.prototype[Symbol.iterator] = Headers.prototype.entries; 45046 } 45047 45048 function consumed(body) { 45049 if (body.bodyUsed) { 45050 return Promise.reject(new TypeError('Already read')); 45051 } 45052 45053 body.bodyUsed = true; 45054 } 45055 45056 function fileReaderReady(reader) { 45057 return new Promise(function (resolve, reject) { 45058 reader.onload = function () { 45059 resolve(reader.result); 45060 }; 45061 45062 reader.onerror = function () { 45063 reject(reader.error); 45064 }; 45065 }); 45066 } 45067 45068 function readBlobAsArrayBuffer(blob) { 45069 var reader = new FileReader(); 45070 var promise = fileReaderReady(reader); 45071 reader.readAsArrayBuffer(blob); 45072 return promise; 45073 } 45074 45075 function readBlobAsText(blob) { 45076 var reader = new FileReader(); 45077 var promise = fileReaderReady(reader); 45078 reader.readAsText(blob); 45079 return promise; 45080 } 45081 45082 function readArrayBufferAsText(buf) { 45083 var view = new Uint8Array(buf); 45084 var chars = new Array(view.length); 45085 45086 for (var i = 0; i < view.length; i++) { 45087 chars[i] = String.fromCharCode(view[i]); 45088 } 45089 45090 return chars.join(''); 45091 } 45092 45093 function bufferClone(buf) { 45094 if (buf.slice) { 45095 return buf.slice(0); 45096 } else { 45097 var view = new Uint8Array(buf.byteLength); 45098 view.set(new Uint8Array(buf)); 45099 return view.buffer; 45100 } 45101 } 45102 45103 function Body() { 45104 this.bodyUsed = false; 45105 45106 this._initBody = function (body) { 45107 this._bodyInit = body; 45108 45109 if (!body) { 45110 this._bodyText = ''; 45111 } else if (typeof body === 'string') { 45112 this._bodyText = body; 45113 } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { 45114 this._bodyBlob = body; 45115 } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { 45116 this._bodyFormData = body; 45117 } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { 45118 this._bodyText = body.toString(); 45119 } else if (support.arrayBuffer && support.blob && isDataView(body)) { 45120 this._bodyArrayBuffer = bufferClone(body.buffer); // IE 10-11 can't handle a DataView body. 45121 45122 this._bodyInit = new Blob([this._bodyArrayBuffer]); 45123 } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) { 45124 this._bodyArrayBuffer = bufferClone(body); 45125 } else { 45126 throw new Error('unsupported BodyInit type'); 45127 } 45128 45129 if (!this.headers.get('content-type')) { 45130 if (typeof body === 'string') { 45131 this.headers.set('content-type', 'text/plain;charset=UTF-8'); 45132 } else if (this._bodyBlob && this._bodyBlob.type) { 45133 this.headers.set('content-type', this._bodyBlob.type); 45134 } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { 45135 this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8'); 45136 } 45137 } 45138 }; 45139 45140 if (support.blob) { 45141 this.blob = function () { 45142 var rejected = consumed(this); 45143 45144 if (rejected) { 45145 return rejected; 45146 } 45147 45148 if (this._bodyBlob) { 45149 return Promise.resolve(this._bodyBlob); 45150 } else if (this._bodyArrayBuffer) { 45151 return Promise.resolve(new Blob([this._bodyArrayBuffer])); 45152 } else if (this._bodyFormData) { 45153 throw new Error('could not read FormData body as blob'); 45154 } else { 45155 return Promise.resolve(new Blob([this._bodyText])); 45156 } 45157 }; 45158 45159 this.arrayBuffer = function () { 45160 if (this._bodyArrayBuffer) { 45161 return consumed(this) || Promise.resolve(this._bodyArrayBuffer); 45162 } else { 45163 return this.blob().then(readBlobAsArrayBuffer); 45164 } 45165 }; 45166 } 45167 45168 this.text = function () { 45169 var rejected = consumed(this); 45170 45171 if (rejected) { 45172 return rejected; 45173 } 45174 45175 if (this._bodyBlob) { 45176 return readBlobAsText(this._bodyBlob); 45177 } else if (this._bodyArrayBuffer) { 45178 return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer)); 45179 } else if (this._bodyFormData) { 45180 throw new Error('could not read FormData body as text'); 45181 } else { 45182 return Promise.resolve(this._bodyText); 45183 } 45184 }; 45185 45186 if (support.formData) { 45187 this.formData = function () { 45188 return this.text().then(decode); 45189 }; 45190 } 45191 45192 this.json = function () { 45193 return this.text().then(JSON.parse); 45194 }; 45195 45196 return this; 45197 } // HTTP methods whose capitalization should be normalized 45198 45199 45200 var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']; 45201
45202 function normalizeMethod(method) { 45203 var upcased = method.toUpperCase(); 45204 return methods.indexOf(upcased) > -1 ? upcased : method; 45205 } 45206 45207 function Request(input, options) { 45208 options = options || {}; 45209 var body = options.body; 45210 45211 if (input instanceof Request) { 45212 if (input.bodyUsed) { 45213 throw new TypeError('Already read'); 45214 } 45215 45216 this.url = input.url; 45217 this.credentials = input.credentials; 45218 45219 if (!options.headers) { 45220 this.headers = new Headers(input.headers); 45221 } 45222 45223 this.method = input.method; 45224 this.mode = input.mode; 45225 45226 if (!body && input._bodyInit != null) { 45227 body = input._bodyInit; 45228 input.bodyUsed = true; 45229 } 45230 } else { 45231 this.url = String(input); 45232 } 45233 45234 this.credentials = options.credentials || this.credentials || 'omit'; 45235 45236 if (options.headers || !this.headers) { 45237 this.headers = new Headers(options.headers); 45238 } 45239 45240 this.method = normalizeMethod(options.method || this.method || 'GET'); 45241 this.mode = options.mode || this.mode || null; 45242 this.referrer = null; 45243 45244 if ((this.method === 'GET' || this.method === 'HEAD') && body) { 45245 throw new TypeError('Body not allowed for GET or HEAD requests'); 45246 } 45247 45248 this._initBody(body); 45249 } 45250 45251 Request.prototype.clone = function () { 45252 return new Request(this, { 45253 body: this._bodyInit 45254 }); 45255 }; 45256 45257 function decode(body) { 45258 var form = new FormData(); 45259 body.trim().split('&').forEach(function (bytes) { 45260 if (bytes) { 45261 var split = bytes.split('='); 45262 var name = split.shift().replace(/\+/g, ' '); 45263 var value = split.join('=').replace(/\+/g, ' '); 45264 form.append(decodeURIComponent(name), decodeURIComponent(value)); 45265 } 45266 }); 45267 return form; 45268 } 45269 45270 function parseHeaders(rawHeaders) { 45271 var headers = new Headers(); 45272 rawHeaders.split(/\r?\n/).forEach(function (line) { 45273 var parts = line.split(':'); 45274 var key = parts.shift().trim(); 45275 45276 if (key) { 45277 var value = parts.join(':').trim(); 45278 headers.append(key, value); 45279 } 45280 }); 45281 return headers; 45282 } 45283 45284 Body.call(Request.prototype); 45285 45286 function Response(bodyInit, options) { 45287 if (!options) { 45288 options = {}; 45289 } 45290 45291 this.type = 'default'; 45292 this.status = 'status' in options ? options.status : 200; 45293 this.ok = this.status >= 200 && this.status < 300; 45294 this.statusText = 'statusText' in options ? options.statusText : 'OK'; 45295 this.headers = new Headers(options.headers); 45296 this.url = options.url || ''; 45297 45298 this._initBody(bodyInit); 45299 } 45300 45301 Body.call(Response.prototype); 45302 45303 Response.prototype.clone = function () { 45304 return new Response(this._bodyInit, { 45305 status: this.status, 45306 statusText: this.statusText, 45307 headers: new Headers(this.headers), 45308 url: this.url 45309 }); 45310 }; 45311 45312 Response.error = function () { 45313 var response = new Response(null, { 45314 status: 0, 45315 statusText: '' 45316 }); 45317 response.type = 'error'; 45318 return response; 45319 }; 45320 45321 var redirectStatuses = [301, 302, 303, 307, 308]; 45322 45323 Response.redirect = function (url, status) { 45324 if (redirectStatuses.indexOf(status) === -1) { 45325 throw new RangeError('Invalid status code'); 45326 } 45327 45328 return new Response(null, { 45329 status: status, 45330 headers: { 45331 location: url 45332 } 45333 }); 45334 }; 45335 45336 self.Headers = Headers; 45337 self.Request = Request; 45338 self.Response = Response; 45339 45340 self.fetch = function (input, init) { 45341 return new Promise(function (resolve, reject) {
45342 var request = new Request(input, init); 45343 var xhr = new XMLHttpRequest(); 45344 45345 xhr.onload = function () { 45346 var options = { 45347 status: xhr.status, 45348 statusText: xhr.statusText, 45349 headers: parseHeaders(xhr.getAllResponseHeaders() || '') 45350 }; 45351 options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL'); 45352 var body = 'response' in xhr ? xhr.response : xhr.responseText; 45353 resolve(new Response(body, options)); 45354 }; 45355 45356 xhr.onerror = function () { 45357 reject(new TypeError('Network request failed')); 45358 }; 45359 45360 xhr.ontimeout = function () { 45361 reject(new TypeError('Network request failed')); 45362 }; 45363 45364 xhr.open(request.method, request.url, true); 45365 45366 if (request.credentials === 'include') { 45367 xhr.withCredentials = true; 45368 } 45369 45370 if ('responseType' in xhr && support.blob) { 45371 xhr.responseType = 'blob'; 45372 } 45373 45374 request.headers.forEach(function (value, name) { 45375 xhr.setRequestHeader(name, value); 45376 }); 45377 xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit); 45378 }); 45379 }; 45380 45381 self.fetch.polyfill = true; 45382 })(typeof self !== 'undefined' ? self : this); 45383 }, {}], 45384 13: [function (_dereq_, module, exports) { 45385 'use strict'; // core 45386 45387 var p5 = _dereq_('./core/main'); 45388 45389 _dereq_('./core/constants'); 45390 45391 _dereq_('./core/environment'); 45392 45393 _dereq_('./core/error_helpers'); 45394 45395 _dereq_('./core/helpers'); 45396 45397 _dereq_('./core/legacy'); 45398 45399 _dereq_('./core/p5.Element'); 45400 45401 _dereq_('./core/p5.Graphics'); 45402 45403 _dereq_('./core/p5.Renderer'); 45404 45405 _dereq_('./core/p5.Renderer2D'); 45406 45407 _dereq_('./core/rendering'); 45408 45409 _dereq_('./core/shim'); 45410 45411 _dereq_('./core/structure'); 45412 45413 _dereq_('./core/transform'); 45414 45415 _dereq_('./core/shape/2d_primitives'); 45416 45417 _dereq_('./core/shape/attributes'); 45418 45419 _dereq_('./core/shape/curves'); 45420 45421 _dereq_('./core/shape/vertex'); // color 45422 45423 45424 _dereq_('./color/color_conversion'); 45425 45426 _dereq_('./color/creating_reading'); 45427 45428 _dereq_('./color/p5.Color'); 45429 45430 _dereq_('./color/setting'); // data 45431 45432 45433 _dereq_('./data/p5.TypedDict'); // events 45434 45435 45436 _dereq_('./events/acceleration'); 45437 45438 _dereq_('./events/keyboard'); 45439 45440 _dereq_('./events/mouse'); 45441 45442 _dereq_('./events/touch'); // image 45443 45444 45445 _dereq_('./image/filters'); 45446 45447 _dereq_('./image/image'); 45448 45449 _dereq_('./image/loading_displaying'); 45450 45451 _dereq_('./image/p5.Image'); 45452 45453 _dereq_('./image/pixels'); // io 45454 45455 45456 _dereq_('./io/files'); 45457 45458 _dereq_('./io/p5.Table'); 45459 45460 _dereq_('./io/p5.TableRow'); 45461 45462 _dereq_('./io/p5.XML'); // math 45463 45464 45465 _dereq_('./math/calculation'); 45466 45467 _dereq_('./math/math'); 45468 45469 _dereq_('./math/noise'); 45470 45471 _dereq_('./math/p5.Vector'); 45472 45473 _dereq_('./math/random'); 45474 45475 _dereq_('./math/trigonometry'); // typography 45476 45477 45478 _dereq_('./typography/attributes'); 45479 45480 _dereq_('./typography/loading_displaying'); 45481 45482 _dereq_('./typography/p5.Font'); // utilities 45483 45484 45485 _dereq_('./utilities/array_functions'); 45486 45487 _dereq_('./utilities/conversion'); 45488 45489 _dereq_('./utilities/string_functions'); 45490 45491 _dereq_('./utilities/time_date'); // webgl 45492 45493 45494 _dereq_('./webgl/3d_primitives'); 45495 45496 _dereq_('./webgl/interaction'); 45497 45498 _dereq_('./webgl/light'); 45499 45500 _dereq_('./webgl/loading'); 45501 45502 _dereq_('./webgl/material'); 45503 45504 _dereq_('./webgl/p5.Camera'); 45505 45506 _dereq_('./webgl/p5.Geometry'); 45507 45508 _dereq_('./webgl/p5.Matrix'); 45509 45510 _dereq_('./webgl/p5.RendererGL.Immediate'); 45511 45512 _dereq_('./webgl/p5.RendererGL'); 45513 45514 _dereq_('./webgl/p5.RendererGL.Retained'); 45515 45516 _dereq_('./webgl/p5.Shader'); 45517 45518 _dereq_('./webgl/p5.Texture'); 45519 45520 _dereq_('./webgl/text'); 45521 45522 _dereq_('./core/init'); 45523 45524 module.exports = p5; 45525 }, {
45526 "./color/color_conversion": 14, 45527 "./color/creating_reading": 15, 45528 "./color/p5.Color": 16, 45529 "./color/setting": 17, 45530 "./core/constants": 18, 45531 "./core/environment": 19, 45532 "./core/error_helpers": 20, 45533 "./core/helpers": 21, 45534 "./core/init": 22, 45535 "./core/legacy": 23, 45536 "./core/main": 24, 45537 "./core/p5.Element": 25, 45538 "./core/p5.Graphics": 26, 45539 "./core/p5.Renderer": 27, 45540 "./core/p5.Renderer2D": 28, 45541 "./core/rendering": 29, 45542 "./core/shape/2d_primitives": 30, 45543 "./core/shape/attributes": 31, 45544 "./core/shape/curves": 32, 45545 "./core/shape/vertex": 33, 45546 "./core/shim": 34, 45547 "./core/structure": 35, 45548 "./core/transform": 36, 45549 "./data/p5.TypedDict": 37, 45550 "./events/acceleration": 38, 45551 "./events/keyboard": 39, 45552 "./events/mouse": 40, 45553 "./events/touch": 41, 45554 "./image/filters": 42, 45555 "./image/image": 43, 45556 "./image/loading_displaying": 44, 45557 "./image/p5.Image": 45, 45558 "./image/pixels": 46, 45559 "./io/files": 47, 45560 "./io/p5.Table": 48, 45561 "./io/p5.TableRow": 49, 45562 "./io/p5.XML": 50, 45563 "./math/calculation": 51, 45564 "./math/math": 52, 45565 "./math/noise": 53, 45566 "./math/p5.Vector": 54, 45567 "./math/random": 55, 45568 "./math/trigonometry": 56, 45569 "./typography/attributes": 57, 45570 "./typography/loading_displaying": 58, 45571 "./typography/p5.Font": 59, 45572 "./utilities/array_functions": 60, 45573 "./utilities/conversion": 61, 45574 "./utilities/string_functions": 62, 45575 "./utilities/time_date": 63, 45576 "./webgl/3d_primitives": 64, 45577 "./webgl/interaction": 65, 45578 "./webgl/light": 66, 45579 "./webgl/loading": 67, 45580 "./webgl/material": 68, 45581 "./webgl/p5.Camera": 69, 45582 "./webgl/p5.Geometry": 70, 45583 "./webgl/p5.Matrix": 71, 45584 "./webgl/p5.RendererGL": 74, 45585 "./webgl/p5.RendererGL.Immediate": 72, 45586 "./webgl/p5.RendererGL.Retained": 73, 45587 "./webgl/p5.Shader": 75, 45588 "./webgl/p5.Texture": 76, 45589 "./webgl/text": 77 45590 }], 45591 14: [function (_dereq_, module, exports) { 45592 /** 45593 * @module Color 45594 * @submodule Color Conversion 45595 * @for p5 45596 * @requires core 45597 */ 45598 'use strict'; 45599 /** 45600 * Conversions adapted from <http://www.easyrgb.com/en/math.php>. 45601 * 45602 * In these functions, hue is always in the range [0, 1], just like all other 45603 * components are in the range [0, 1]. 'Brightness' and 'value' are used 45604 * interchangeably. 45605 */ 45606 45607 var p5 = _dereq_('../core/main'); 45608 45609 p5.ColorConversion = {}; 45610 /** 45611 * Convert an HSBA array to HSLA. 45612 */ 45613 45614 p5.ColorConversion._hsbaToHSLA = function (hsba) { 45615 var hue = hsba[0]; 45616 var sat = hsba[1]; 45617 var val = hsba[2]; // Calculate lightness. 45618 45619 var li = (2 - sat) * val / 2; // Convert saturation. 45620 45621 if (li !== 0) { 45622 if (li === 1) { 45623 sat = 0; 45624 } else if (li < 0.5) { 45625 sat = sat / (2 - sat); 45626 } else { 45627 sat = sat * val / (2 - li * 2); 45628 } 45629 } // Hue and alpha stay the same. 45630 45631 45632 return [hue, sat, li, hsba[3]]; 45633 }; 45634 /** 45635 * Convert an HSBA array to RGBA. 45636 */ 45637 45638 45639 p5.ColorConversion._hsbaToRGBA = function (hsba) { 45640 var hue = hsba[0] * 6; // We will split hue into 6 sectors. 45641 45642 var sat = hsba[1]; 45643 var val = hsba[2]; 45644 var RGBA = []; 45645 45646 if (sat === 0) { 45647 RGBA = [val, val, val, hsba[3]]; // Return early if grayscale. 45648 } else { 45649 var sector = Math.floor(hue); 45650 var tint1 = val * (1 - sat); 45651 var tint2 = val * (1 - sat * (hue - sector)); 45652 var tint3 = val * (1 - sat * (1 + sector - hue)); 45653 var red, green, blue; 45654 45655 if (sector === 1) { 45656 // Yellow to green. 45657 red = tint2; 45658 green = val; 45659 blue = tint1; 45660 } else if (sector === 2) { 45661 // Green to cyan. 45662 red = tint1; 45663 green = val; 45664 blue = tint3; 45665 } else if (sector === 3) { 45666 // Cyan to blue. 45667 red = tint1; 45668 green = tint2; 45669 blue = val; 45670 } else if (sector === 4) { 45671 // Blue to magenta. 45672 red = tint3; 45673 green = tint1; 45674 blue = val; 45675 } else if (sector === 5) { 45676 // Magenta to red. 45677 red = val; 45678 green = tint1; 45679 blue = tint2; 45680 } else { 45681 // Red to yellow (sector could be 0 or 6). 45682 red = val; 45683 green = tint3; 45684 blue = tint1; 45685 } 45686 45687 RGBA = [red, green, blue, hsba[3]]; 45688 } 45689 45690 return RGBA; 45691 }; 45692 /** 45693 * Convert an HSLA array to HSBA. 45694 */ 45695 45696 45697 p5.ColorConversion._hslaToHSBA = function (hsla) { 45698 var hue = hsla[0]; 45699 var sat = hsla[1]; 45700 var li = hsla[2]; // Calculate brightness. 45701 45702 var val; 45703 45704 if (li < 0.5) { 45705 val = (1 + sat) * li; 45706 } else { 45707 val = li + sat - li * sat; 45708 } // Convert saturation. 45709 45710 45711 sat = 2 * (val - li) / val; // Hue and alpha stay the same. 45712 45713 return [hue, sat, val, hsla[3]]; 45714 }; 45715 /** 45716 * Convert an HSLA array to RGBA. 45717 * 45718 * We need to change basis from HSLA to something that can be more easily be 45719 * projected onto RGBA. We will choose hue and brightness as our first two 45720 * components, and pick a convenient third one ('zest') so that we don't need 45721 * to calculate formal HSBA saturation. 45722 */ 45723 45724 45725 p5.ColorConversion._hslaToRGBA = function (hsla) { 45726 var hue = hsla[0] * 6; // We will split hue into 6 sectors. 45727 45728 var sat = hsla[1]; 45729 var li = hsla[2]; 45730 var RGBA = []; 45731 45732 if (sat === 0) { 45733 RGBA = [li, li, li, hsla[3]]; // Return early if grayscale. 45734 } else { 45735 // Calculate brightness. 45736 var val; 45737 45738 if (li < 0.5) { 45739 val = (1 + sat) * li; 45740 } else { 45741 val = li + sat - li * sat; 45742 } // Define zest. 45743 45744 45745 var zest = 2 * li - val; // Implement projection (project onto green by default). 45746 45747 var hzvToRGB = function (hue, zest, val) { 45748 if (hue < 0) { 45749 // Hue must wrap to allow projection onto red and blue. 45750 hue += 6; 45751 } else if (hue >= 6) { 45752 hue -= 6; 45753 } 45754 45755 if (hue < 1) { 45756 // Red to yellow (increasing green). 45757 return zest + (val - zest) * hue; 45758 } else if (hue < 3) { 45759 // Yellow to cyan (greatest green). 45760 return val; 45761 } else if (hue < 4) { 45762 // Cyan to blue (decreasing green). 45763 return zest + (val - zest) * (4 - hue); 45764 } else { 45765 // Blue to red (least green). 45766 return zest; 45767 } 45768 }; // Perform projections, offsetting hue as necessary. 45769 45770 45771 RGBA = [hzvToRGB(hue + 2, zest, val), hzvToRGB(hue, zest, val), hzvToRGB(hue - 2, zest, val), hsla[3]]; 45772 } 45773 45774 return RGBA; 45775 }; 45776 /** 45777 * Convert an RGBA array to HSBA. 45778 */ 45779 45780 45781 p5.ColorConversion._rgbaToHSBA = function (rgba) { 45782 var red = rgba[0]; 45783 var green = rgba[1]; 45784 var blue = rgba[2]; 45785 var val = Math.max(red, green, blue); 45786 var chroma = val - Math.min(red, green, blue); 45787 var hue, sat; 45788 45789 if (chroma === 0) { 45790 // Return early if grayscale. 45791 hue = 0; 45792 sat = 0; 45793 } else { 45794 sat = chroma / val; 45795 45796 if (red === val) { 45797 // Magenta to yellow. 45798 hue = (green - blue) / chroma; 45799 } else if (green === val) { 45800 // Yellow to cyan. 45801 hue = 2 + (blue - red) / chroma; 45802 } else if (blue === val) { 45803 // Cyan to magenta. 45804 hue = 4 + (red - green) / chroma; 45805 } 45806 45807 if (hue < 0) { 45808 // Confine hue to the interval [0, 1). 45809 hue += 6; 45810 } else if (hue >= 6) { 45811 hue -= 6; 45812 } 45813 } 45814 45815 return [hue / 6, sat, val, rgba[3]]; 45816 }; 45817 /** 45818 * Convert an RGBA array to HSLA. 45819 */ 45820 45821 45822 p5.ColorConversion._rgbaToHSLA = function (rgba) { 45823 var red = rgba[0]; 45824 var green = rgba[1]; 45825 var blue = rgba[2]; 45826 var val = Math.max(red, green, blue); 45827 var min = Math.min(red, green, blue); 45828 var li = val + min; // We will halve this later. 45829 45830 var chroma = val - min; 45831 var hue, sat; 45832 45833 if (chroma === 0) { 45834 // Return early if grayscale. 45835 hue = 0; 45836 sat = 0; 45837 } else { 45838 if (li < 1) { 45839 sat = chroma / li; 45840 } else { 45841 sat = chroma / (2 - li); 45842 } 45843 45844 if (red === val) { 45845 // Magenta to yellow. 45846 hue = (green - blue) / chroma; 45847 } else if (green === val) { 45848 // Yellow to cyan. 45849 hue = 2 + (blue - red) / chroma; 45850 } else if (blue === val) { 45851 // Cyan to magenta. 45852 hue = 4 + (red - green) / chroma; 45853 } 45854 45855 if (hue < 0) { 45856 // Confine hue to the interval [0, 1). 45857 hue += 6; 45858 } else if (hue >= 6) { 45859 hue -= 6; 45860 } 45861 } 45862 45863 return [hue / 6, sat, li / 2, rgba[3]]; 45864 }; 45865 45866 module.exports = p5.ColorConversion; 45867 }, {
45868 "../core/main": 24 45869 }], 45870 15: [function (_dereq_, module, exports) { 45871 /** 45872 * @module Color 45873 * @submodule Creating & Reading 45874 * @for p5 45875 * @requires core 45876 * @requires constants 45877 */ 45878 'use strict'; 45879 45880 var p5 = _dereq_('../core/main'); 45881 45882 var constants = _dereq_('../core/constants'); 45883 45884 _dereq_('./p5.Color'); 45885 45886 _dereq_('../core/error_helpers'); 45887 /** 45888 * Extracts the alpha value from a color or pixel array. 45889 * 45890 * @method alpha 45891 * @param {p5.Color|Number[]|String} color <a href="#/p5.Color">p5.Color</a> object, color components, 45892 * or CSS color 45893 * @return {Number} the alpha value 45894 * @example 45895 * <div> 45896 * <code> 45897 * noStroke(); 45898 * let c = color(0, 126, 255, 102); 45899 * fill(c); 45900 * rect(15, 15, 35, 70); 45901 * let value = alpha(c); // Sets 'value' to 102 45902 * fill(value); 45903 * rect(50, 15, 35, 70); 45904 * </code> 45905 * </div> 45906 * 45907 * @alt 45908 * Left half of canvas light blue and right half light charcoal grey. 45909 * Left half of canvas light purple and right half a royal blue. 45910 * Left half of canvas salmon pink and the right half white. 45911 * Yellow rect in middle right of canvas, with 55 pixel width and height. 45912 * Yellow ellipse in top left canvas, black ellipse in bottom right,both 80x80. 45913 * Bright fuschia rect in middle of canvas, 60 pixel width and height. 45914 * Two bright green rects on opposite sides of the canvas, both 45x80. 45915 * Four blue rects in each corner of the canvas, each are 35x35. 45916 * Bright sea green rect on left and darker rect on right of canvas, both 45x80. 45917 * Dark green rect on left and light green rect on right of canvas, both 45x80. 45918 * Dark blue rect on left and light teal rect on right of canvas, both 45x80. 45919 * blue rect on left and green on right, both with black outlines & 35x60. 45920 * salmon pink rect on left and black on right, both 35x60. 45921 * 4 rects, tan, brown, brownish purple and purple, with white outlines & 20x60. 45922 * light pastel green rect on left and dark grey rect on right, both 35x60. 45923 * yellow rect on left and red rect on right, both with black outlines & 35x60. 45924 * grey canvas 45925 * deep pink rect on left and grey rect on right, both 35x60. 45926 */ 45927 45928 45929 p5.prototype.alpha = function (c) { 45930 p5._validateParameters('alpha', arguments); 45931 45932 return this.color(c)._getAlpha(); 45933 }; 45934 /** 45935 * Extracts the blue value from a color or pixel array. 45936 * 45937 * @method blue 45938 * @param {p5.Color|Number[]|String} color <a href="#/p5.Color">p5.Color</a> object, color components, 45939 * or CSS color 45940 * @return {Number} the blue value 45941 * @example 45942 * <div> 45943 * <code> 45944 * let c = color(175, 100, 220); // Define color 'c' 45945 * fill(c); // Use color variable 'c' as fill color 45946 * rect(15, 20, 35, 60); // Draw left rectangle 45947 * 45948 * let blueValue = blue(c); // Get blue in 'c' 45949 * print(blueValue); // Prints "220.0" 45950 * fill(0, 0, blueValue); // Use 'blueValue' in new fill 45951 * rect(50, 20, 35, 60); // Draw right rectangle 45952 * </code> 45953 * </div> 45954 * 45955 * @alt 45956 * Left half of canvas light purple and right half a royal blue. 45957 * 45958 */ 45959 45960 45961 p5.prototype.blue = function (c) { 45962 p5._validateParameters('blue', arguments); 45963 45964 return this.color(c)._getBlue(); 45965 }; 45966 /** 45967 * Extracts the HSB brightness value from a color or pixel array. 45968 * 45969 * @method brightness 45970 * @param {p5.Color|Number[]|String} color <a href="#/p5.Color">p5.Color</a> object, color components, 45971 * or CSS color 45972 * @return {Number} the brightness value 45973 * @example 45974 * <div> 45975 * <code> 45976 * noStroke(); 45977 * colorMode(HSB, 255); 45978 * let c = color(0, 126, 255); 45979 * fill(c); 45980 * rect(15, 20, 35, 60); 45981 * let value = brightness(c); // Sets 'value' to 255 45982 * fill(value); 45983 * rect(50, 20, 35, 60); 45984 * </code> 45985 * </div> 45986 * 45987 * @alt 45988 * Left half of canvas salmon pink and the right half white. 45989 * 45990 */ 45991 45992 45993 p5.prototype.brightness = function (c) { 45994 p5._validateParameters('brightness', arguments); 45995 45996 return this.color(c)._getBrightness(); 45997 }; 45998 /** 45999 * Creates colors for storing in variables of the color datatype. The 46000 * parameters are interpreted as RGB or HSB values depending on the 46001 * current <a href="#/p5/colorMode">colorMode()</a>. The default mode is RGB values from 0 to 255 46002 * and, therefore, the function call color(255, 204, 0) will return a 46003 * bright yellow color. 46004 * <br><br> 46005 * Note that if only one value is provided to <a href="#/p5/color">color()</a>, it will be interpreted 46006 * as a grayscale value. Add a second value, and it will be used for alpha 46007 * transparency. When three values are specified, they are interpreted as 46008 * either RGB or HSB values. Adding a fourth value applies alpha 46009 * transparency. 46010 * <br><br>
46011 * If a single string argument is provided, RGB, RGBA and Hex CSS color 46012 * strings and all named color strings are supported. In this case, an alpha 46013 * number value as a second argument is not supported, the RGBA form should be 46014 * used. 46015 * 46016 * @method color 46017 * @param {Number} gray number specifying value between white 46018 * and black. 46019 * @param {Number} [alpha] alpha value relative to current color range 46020 * (default is 0-255) 46021 * @return {p5.Color} resulting color 46022 * 46023 * @example 46024 * <div> 46025 * <code> 46026 * let c = color(255, 204, 0); // Define color 'c' 46027 * fill(c); // Use color variable 'c' as fill color 46028 * noStroke(); // Don't draw a stroke around shapes 46029 * rect(30, 20, 55, 55); // Draw rectangle 46030 * </code> 46031 * </div> 46032 * 46033 * <div> 46034 * <code> 46035 * let c = color(255, 204, 0); // Define color 'c' 46036 * fill(c); // Use color variable 'c' as fill color 46037 * noStroke(); // Don't draw a stroke around shapes 46038 * ellipse(25, 25, 80, 80); // Draw left circle 46039 * 46040 * // Using only one value with color() 46041 * // generates a grayscale value. 46042 * c = color(65); // Update 'c' with grayscale value 46043 * fill(c); // Use updated 'c' as fill color 46044 * ellipse(75, 75, 80, 80); // Draw right circle 46045 * </code> 46046 * </div> 46047 * 46048 * <div> 46049 * <code> 46050 * // Named SVG & CSS colors may be used, 46051 * let c = color('magenta'); 46052 * fill(c); // Use 'c' as fill color 46053 * noStroke(); // Don't draw a stroke around shapes 46054 * rect(20, 20, 60, 60); // Draw rectangle 46055 * </code> 46056 * </div> 46057 * 46058 * <div> 46059 * <code> 46060 * // as can hex color codes: 46061 * noStroke(); // Don't draw a stroke around shapes 46062 * let c = color('#0f0'); 46063 * fill(c); // Use 'c' as fill color 46064 * rect(0, 10, 45, 80); // Draw rectangle 46065 * 46066 * c = color('#00ff00'); 46067 * fill(c); // Use updated 'c' as fill color 46068 * rect(55, 10, 45, 80); // Draw rectangle 46069 * </code> 46070 * </div> 46071 * 46072 * <div> 46073 * <code> 46074 * // RGB and RGBA color strings are also supported: 46075 * // these all set to the same color (solid blue) 46076 * let c; 46077 * noStroke(); // Don't draw a stroke around shapes 46078 * c = color('rgb(0,0,255)'); 46079 * fill(c); // Use 'c' as fill color 46080 * rect(10, 10, 35, 35); // Draw rectangle 46081 * 46082 * c = color('rgb(0%, 0%, 100%)'); 46083 * fill(c); // Use updated 'c' as fill color 46084 * rect(55, 10, 35, 35); // Draw rectangle 46085 * 46086 * c = color('rgba(0, 0, 255, 1)'); 46087 * fill(c); // Use updated 'c' as fill color 46088 * rect(10, 55, 35, 35); // Draw rectangle 46089 * 46090 * c = color('rgba(0%, 0%, 100%, 1)'); 46091 * fill(c); // Use updated 'c' as fill color 46092 * rect(55, 55, 35, 35); // Draw rectangle 46093 * </code> 46094 * </div> 46095 * 46096 * <div> 46097 * <code> 46098 * // HSL color is also supported and can be specified 46099 * // by value 46100 * let c; 46101 * noStroke(); // Don't draw a stroke around shapes 46102 * c = color('hsl(160, 100%, 50%)'); 46103 * fill(c); // Use 'c' as fill color 46104 * rect(0, 10, 45, 80); // Draw rectangle 46105 * 46106 * c = color('hsla(160, 100%, 50%, 0.5)'); 46107 * fill(c); // Use updated 'c' as fill color 46108 * rect(55, 10, 45, 80); // Draw rectangle 46109 * </code> 46110 * </div> 46111 * 46112 * <div> 46113 * <code> 46114 * // HSB color is also supported and can be specified 46115 * // by value 46116 * let c; 46117 * noStroke(); // Don't draw a stroke around shapes 46118 * c = color('hsb(160, 100%, 50%)'); 46119 * fill(c); // Use 'c' as fill color 46120 * rect(0, 10, 45, 80); // Draw rectangle 46121 * 46122 * c = color('hsba(160, 100%, 50%, 0.5)'); 46123 * fill(c); // Use updated 'c' as fill color 46124 * rect(55, 10, 45, 80); // Draw rectangle 46125 * </code> 46126 * </div> 46127 * 46128 * <div> 46129 * <code> 46130 * let c; // Declare color 'c' 46131 * noStroke(); // Don't draw a stroke around shapes 46132 * 46133 * // If no colorMode is specified, then the 46134 * // default of RGB with scale of 0-255 is used. 46135 * c = color(50, 55, 100); // Create a color for 'c' 46136 * fill(c); // Use color variable 'c' as fill color 46137 * rect(0, 10, 45, 80); // Draw left rect
46138 * 46139 * colorMode(HSB, 100); // Use HSB with scale of 0-100 46140 * c = color(50, 55, 100); // Update 'c' with new color 46141 * fill(c); // Use updated 'c' as fill color 46142 * rect(55, 10, 45, 80); // Draw right rect 46143 * </code> 46144 * </div> 46145 * 46146 * @alt 46147 * Yellow rect in middle right of canvas, with 55 pixel width and height. 46148 * Yellow ellipse in top left of canvas, black ellipse in bottom right,both 80x80. 46149 * Bright fuschia rect in middle of canvas, 60 pixel width and height. 46150 * Two bright green rects on opposite sides of the canvas, both 45x80. 46151 * Four blue rects in each corner of the canvas, each are 35x35. 46152 * Bright sea green rect on left and darker rect on right of canvas, both 45x80. 46153 * Dark green rect on left and lighter green rect on right of canvas, both 45x80. 46154 * Dark blue rect on left and light teal rect on right of canvas, both 45x80. 46155 * 46156 */ 46157 46158 /** 46159 * @method color 46160 * @param {Number} v1 red or hue value relative to 46161 * the current color range 46162 * @param {Number} v2 green or saturation value 46163 * relative to the current color range 46164 * @param {Number} v3 blue or brightness value 46165 * relative to the current color range 46166 * @param {Number} [alpha] 46167 * @return {p5.Color} 46168 */ 46169 46170 /** 46171 * @method color 46172 * @param {String} value a color string 46173 * @return {p5.Color} 46174 */ 46175 46176 /** 46177 * @method color 46178 * @param {Number[]} values an array containing the red,green,blue & 46179 * and alpha components of the color 46180 * @return {p5.Color} 46181 */ 46182 46183 /** 46184 * @method color 46185 * @param {p5.Color} color 46186 * @return {p5.Color} 46187 */ 46188 46189 46190 p5.prototype.color = function () { 46191 p5._validateParameters('color', arguments); 46192 46193 if (arguments[0] instanceof p5.Color) { 46194 return arguments[0]; // Do nothing if argument is already a color object. 46195 } 46196 46197 var args = arguments[0] instanceof Array ? arguments[0] : arguments; 46198 return new p5.Color(this, args); 46199 }; 46200 /** 46201 * Extracts the green value from a color or pixel array. 46202 * 46203 * @method green 46204 * @param {p5.Color|Number[]|String} color <a href="#/p5.Color">p5.Color</a> object, color components, 46205 * or CSS color 46206 * @return {Number} the green value 46207 * @example 46208 * <div> 46209 * <code> 46210 * let c = color(20, 75, 200); // Define color 'c' 46211 * fill(c); // Use color variable 'c' as fill color 46212 * rect(15, 20, 35, 60); // Draw left rectangle 46213 * 46214 * let greenValue = green(c); // Get green in 'c' 46215 * print(greenValue); // Print "75.0" 46216 * fill(0, greenValue, 0); // Use 'greenValue' in new fill 46217 * rect(50, 20, 35, 60); // Draw right rectangle 46218 * </code> 46219 * </div> 46220 * 46221 * @alt 46222 * blue rect on left and green on right, both with black outlines & 35x60. 46223 * 46224 */ 46225 46226 46227 p5.prototype.green = function (c) { 46228 p5._validateParameters('green', arguments); 46229 46230 return this.color(c)._getGreen(); 46231 }; 46232 /** 46233 * Extracts the hue value from a color or pixel array. 46234 * 46235 * Hue exists in both HSB and HSL. This function will return the 46236 * HSB-normalized hue when supplied with an HSB color object (or when supplied 46237 * with a pixel array while the color mode is HSB), but will default to the 46238 * HSL-normalized hue otherwise. (The values will only be different if the 46239 * maximum hue setting for each system is different.) 46240 * 46241 * @method hue 46242 * @param {p5.Color|Number[]|String} color <a href="#/p5.Color">p5.Color</a> object, color components, 46243 * or CSS color 46244 * @return {Number} the hue 46245 * @example 46246 * <div> 46247 * <code> 46248 * noStroke(); 46249 * colorMode(HSB, 255); 46250 * let c = color(0, 126, 255); 46251 * fill(c); 46252 * rect(15, 20, 35, 60); 46253 * let value = hue(c); // Sets 'value' to "0" 46254 * fill(value); 46255 * rect(50, 20, 35, 60); 46256 * </code> 46257 * </div> 46258 * 46259 * @alt 46260 * salmon pink rect on left and black on right, both 35x60. 46261 * 46262 */ 46263 46264 46265 p5.prototype.hue = function (c) { 46266 p5._validateParameters('hue', arguments); 46267 46268 return this.color(c)._getHue(); 46269 }; 46270 /** 46271 * Blends two colors to find a third color somewhere between them. The amt 46272 * parameter is the amount to interpolate between the two values where 0.0 46273 * equal to the first color, 0.1 is very near the first color, 0.5 is halfway 46274 * in between, etc. An amount below 0 will be treated as 0. Likewise, amounts 46275 * above 1 will be capped at 1. This is different from the behavior of <a href="#/p5/lerp">lerp()</a>, 46276 * but necessary because otherwise numbers outside the range will produce 46277 * strange and unexpected colors. 46278 * <br><br> 46279 * The way that colours are interpolated depends on the current color mode. 46280 * 46281 * @method lerpColor 46282 * @param {p5.Color} c1 interpolate from this color 46283 * @param {p5.Color} c2 interpolate to this color 46284 * @param {Number} amt number between 0 and 1 46285 * @return {p5.Color} interpolated color 46286 * @example 46287 * <div> 46288 * <code> 46289 * colorMode(RGB);
46290 * stroke(255); 46291 * background(51); 46292 * let from = color(218, 165, 32); 46293 * let to = color(72, 61, 139); 46294 * colorMode(RGB); // Try changing to HSB. 46295 * let interA = lerpColor(from, to, 0.33); 46296 * let interB = lerpColor(from, to, 0.66); 46297 * fill(from); 46298 * rect(10, 20, 20, 60); 46299 * fill(interA); 46300 * rect(30, 20, 20, 60); 46301 * fill(interB); 46302 * rect(50, 20, 20, 60); 46303 * fill(to); 46304 * rect(70, 20, 20, 60); 46305 * </code> 46306 * </div> 46307 * 46308 * @alt 46309 * 4 rects one tan, brown, brownish purple, purple, with white outlines & 20x60 46310 * 46311 */ 46312 46313 46314 p5.prototype.lerpColor = function (c1, c2, amt) { 46315 p5._validateParameters('lerpColor', arguments); 46316 46317 var mode = this._colorMode; 46318 var maxes = this._colorMaxes; 46319 var l0, l1, l2, l3; 46320 var fromArray, toArray; 46321 46322 if (mode === constants.RGB) { 46323 fromArray = c1.levels.map(function (level) { 46324 return level / 255; 46325 }); 46326 toArray = c2.levels.map(function (level) { 46327 return level / 255; 46328 }); 46329 } else if (mode === constants.HSB) { 46330 c1._getBrightness(); // Cache hsba so it definitely exists. 46331 46332 46333 c2._getBrightness(); 46334 46335 fromArray = c1.hsba; 46336 toArray = c2.hsba; 46337 } else if (mode === constants.HSL) { 46338 c1._getLightness(); // Cache hsla so it definitely exists. 46339 46340 46341 c2._getLightness(); 46342 46343 fromArray = c1.hsla; 46344 toArray = c2.hsla; 46345 } else { 46346 throw new Error(mode + 'cannot be used for interpolation.'); 46347 } // Prevent extrapolation. 46348 46349 46350 amt = Math.max(Math.min(amt, 1), 0); // Define lerp here itself if user isn't using math module. 46351 // Maintains the definition as found in math/calculation.js 46352 46353 if (typeof this.lerp === 'undefined') { 46354 this.lerp = function (start, stop, amt) { 46355 return amt * (stop - start) + start; 46356 }; 46357 } // Perform interpolation. 46358 46359 46360 l0 = this.lerp(fromArray[0], toArray[0], amt); 46361 l1 = this.lerp(fromArray[1], toArray[1], amt); 46362 l2 = this.lerp(fromArray[2], toArray[2], amt); 46363 l3 = this.lerp(fromArray[3], toArray[3], amt); // Scale components. 46364 46365 l0 *= maxes[mode][0]; 46366 l1 *= maxes[mode][1]; 46367 l2 *= maxes[mode][2]; 46368 l3 *= maxes[mode][3]; 46369 return this.color(l0, l1, l2, l3); 46370 }; 46371 /** 46372 * Extracts the HSL lightness value from a color or pixel array. 46373 * 46374 * @method lightness 46375 * @param {p5.Color|Number[]|String} color <a href="#/p5.Color">p5.Color</a> object, color components, 46376 * or CSS color 46377 * @return {Number} the lightness 46378 * @example 46379 * <div> 46380 * <code> 46381 * noStroke(); 46382 * colorMode(HSL); 46383 * let c = color(156, 100, 50, 1); 46384 * fill(c); 46385 * rect(15, 20, 35, 60); 46386 * let value = lightness(c); // Sets 'value' to 50 46387 * fill(value); 46388 * rect(50, 20, 35, 60); 46389 * </code> 46390 * </div> 46391 * 46392 * @alt 46393 * light pastel green rect on left and dark grey rect on right, both 35x60. 46394 * 46395 */ 46396 46397 46398 p5.prototype.lightness = function (c) { 46399 p5._validateParameters('lightness', arguments); 46400 46401 return this.color(c)._getLightness(); 46402 }; 46403 /** 46404 * Extracts the red value from a color or pixel array. 46405 * 46406 * @method red 46407 * @param {p5.Color|Number[]|String} color <a href="#/p5.Color">p5.Color</a> object, color components, 46408 * or CSS color 46409 * @return {Number} the red value 46410 * @example 46411 * <div> 46412 * <code> 46413 * let c = color(255, 204, 0); // Define color 'c' 46414 * fill(c); // Use color variable 'c' as fill color 46415 * rect(15, 20, 35, 60); // Draw left rectangle 46416 * 46417 * let redValue = red(c); // Get red in 'c' 46418 * print(redValue); // Print "255.0" 46419 * fill(redValue, 0, 0); // Use 'redValue' in new fill 46420 * rect(50, 20, 35, 60); // Draw right rectangle 46421 * </code> 46422 * </div> 46423 * 46424 * <div> 46425 * <code> 46426 * colorMode(RGB, 255); 46427 * let c = color(127, 255, 0); 46428 * colorMode(RGB, 1); 46429 * let myColor = red(c); 46430 * print(myColor); 46431 * </code> 46432 * </div> 46433 * 46434 * @alt 46435 * yellow rect on left and red rect on right, both with black outlines and 35x60. 46436 * grey canvas 46437 */ 46438 46439 46440 p5.prototype.red = function (c) { 46441 p5._validateParameters('red', arguments); 46442 46443 return this.color(c)._getRed(); 46444 }; 46445 /** 46446 * Extracts the saturation value from a color or pixel array. 46447 * 46448 * Saturation is scaled differently in HSB and HSL. This function will return 46449 * the HSB saturation when supplied with an HSB color object (or when supplied 46450 * with a pixel array while the color mode is HSB), but will default to the 46451 * HSL saturation otherwise. 46452 * 46453 * @method saturation 46454 * @param {p5.Color|Number[]|String} color <a href="#/p5.Color">p5.Color</a> object, color components, 46455 * or CSS color 46456 * @return {Number} the saturation value 46457 * @example 46458 * <div> 46459 * <code> 46460 * noStroke(); 46461 * colorMode(HSB, 255); 46462 * let c = color(0, 126, 255); 46463 * fill(c); 46464 * rect(15, 20, 35, 60); 46465 * let value = saturation(c); // Sets 'value' to 126 46466 * fill(value); 46467 * rect(50, 20, 35, 60); 46468 * </code> 46469 * </div> 46470 * 46471 * @alt 46472 *deep pink rect on left and grey rect on right, both 35x60. 46473 * 46474 */ 46475 46476 46477 p5.prototype.saturation = function (c) { 46478 p5._validateParameters('saturation', arguments); 46479 46480 return this.color(c)._getSaturation(); 46481 }; 46482 46483 module.exports = p5; 46484 }, {
46485 "../core/constants": 18, 46486 "../core/error_helpers": 20, 46487 "../core/main": 24, 46488 "./p5.Color": 16 46489 }], 46490 16: [function (_dereq_, module, exports) { 46491 /** 46492 * @module Color 46493 * @submodule Creating & Reading 46494 * @for p5 46495 * @requires core 46496 * @requires constants 46497 * @requires color_conversion 46498 */ 46499 'use strict'; 46500 46501 var p5 = _dereq_('../core/main'); 46502 46503 var constants = _dereq_('../core/constants'); 46504 46505 var color_conversion = _dereq_('./color_conversion'); 46506 /** 46507 * Each color stores the color mode and level maxes that applied at the 46508 * time of its construction. These are used to interpret the input arguments 46509 * (at construction and later for that instance of color) and to format the 46510 * output e.g. when <a href="#/p5/saturation">saturation()</a> is requested. 46511 * 46512 * Internally we store an array representing the ideal RGBA values in floating 46513 * point form, normalized from 0 to 1. From this we calculate the closest 46514 * screen color (RGBA levels from 0 to 255) and expose this to the renderer. 46515 * 46516 * We also cache normalized, floating point components of the color in various 46517 * representations as they are calculated. This is done to prevent repeating a 46518 * conversion that has already been performed. 46519 * 46520 * @class p5.Color 46521 */ 46522 46523 46524 p5.Color = function (pInst, vals) { 46525 // Record color mode and maxes at time of construction. 46526 this._storeModeAndMaxes(pInst._colorMode, pInst._colorMaxes); // Calculate normalized RGBA values. 46527 46528 46529 if (this.mode !== constants.RGB && this.mode !== constants.HSL && this.mode !== constants.HSB) { 46530 throw new Error(this.mode + ' is an invalid colorMode.'); 46531 } else { 46532 this._array = p5.Color._parseInputs.apply(this, vals); 46533 } // Expose closest screen color. 46534 46535 46536 this._calculateLevels(); 46537 46538 return this; 46539 }; 46540 /** 46541 * This function returns the color formatted as a string. This can be useful 46542 * for debugging, or for using p5.js with other libraries. 46543 * @method toString 46544 * @param {String} [format] How the color string will be formatted. 46545 * Leaving this empty formats the string as rgba(r, g, b, a). 46546 * '#rgb' '#rgba' '#rrggbb' and '#rrggbbaa' format as hexadecimal color codes. 46547 * 'rgb' 'hsb' and 'hsl' return the color formatted in the specified color mode. 46548 * 'rgba' 'hsba' and 'hsla' are the same as above but with alpha channels. 46549 * 'rgb%' 'hsb%' 'hsl%' 'rgba%' 'hsba%' and 'hsla%' format as percentages. 46550 * @return {String} the formatted string 46551 * @example 46552 * <div> 46553 * <code> 46554 * let myColor; 46555 * function setup() { 46556 * createCanvas(200, 200); 46557 * stroke(255); 46558 * myColor = color(100, 100, 250); 46559 * fill(myColor); 46560 * } 46561 * 46562 * function draw() { 46563 * rotate(HALF_PI); 46564 * text(myColor.toString(), 0, -5); 46565 * text(myColor.toString('#rrggbb'), 0, -30); 46566 * text(myColor.toString('rgba%'), 0, -55); 46567 * } 46568 * </code> 46569 * </div> 46570 * 46571 * @alt 46572 * canvas with text representation of color 46573 */ 46574 46575 46576 p5.Color.prototype.toString = function (format) { 46577 if (!this.hsba) this.hsba = color_conversion._rgbaToHSBA(this._array); 46578 if (!this.hsla) this.hsla = color_conversion._rgbaToHSLA(this._array); 46579 var a = this.levels; 46580 var f = this._array; 46581 var alpha = f[3]; // String representation uses normalized alpha 46582 46583 switch (format) { 46584 case '#rrggbb': 46585 return '#'.concat(a[0] < 16 ? '0'.concat(a[0].toString(16)) : a[0].toString(16), a[1] < 16 ? '0'.concat(a[1].toString(16)) : a[1].toString(16), a[2] < 16 ? '0'.concat(a[2].toString(16)) : a[2].toString(16)); 46586 46587 case '#rrggbbaa': 46588 return '#'.concat(a[0] < 16 ? '0'.concat(a[0].toString(16)) : a[0].toString(16), a[1] < 16 ? '0'.concat(a[1].toString(16)) : a[1].toString(16), a[2] < 16 ? '0'.concat(a[2].toString(16)) : a[2].toString(16), a[3] < 16 ? '0'.concat(a[2].toString(16)) : a[3].toString(16)); 46589 46590 case '#rgb': 46591 return '#'.concat(Math.round(f[0] * 15).toString(16), Math.round(f[1] * 15).toString(16), Math.round(f[2] * 15).toString(16)); 46592 46593 case '#rgba': 46594 return '#'.concat(Math.round(f[0] * 15).toString(16), Math.round(f[1] * 15).toString(16), Math.round(f[2] * 15).toString(16), Math.round(f[3] * 15).toString(16)); 46595 46596 case 'rgb': 46597 return 'rgb('.concat(a[0], ', ', a[1], ', ', a[2], ')'); 46598 46599 case 'rgb%': 46600 return 'rgb('.concat((100 * f[0]).toPrecision(3), '%, ', (100 * f[1]).toPrecision(3), '%, ', (100 * f[2]).toPrecision(3), '%)'); 46601 46602 case 'rgba%': 46603 return 'rgba('.concat((100 * f[0]).toPrecision(3), '%, ', (100 * f[1]).toPrecision(3), '%, ', (100 * f[2]).toPrecision(3), '%, ', (100 * f[3]).toPrecision(3), '%)'); 46604 46605 case 'hsb': 46606 case 'hsv':
46607 return 'hsb('.concat(this.hsba[0] * this.maxes[constants.HSB][0], ', ', this.hsba[1] * this.maxes[constants.HSB][1], ', ', this.hsba[2] * this.maxes[constants.HSB][2], ')'); 46608 46609 case 'hsb%': 46610 case 'hsv%': 46611 return 'hsb('.concat((100 * this.hsba[0]).toPrecision(3), '%, ', (100 * this.hsba[1]).toPrecision(3), '%, ', (100 * this.hsba[2]).toPrecision(3), '%)'); 46612 46613 case 'hsba': 46614 case 'hsva': 46615 return 'hsba('.concat(this.hsba[0] * this.maxes[constants.HSB][0], ', ', this.hsba[1] * this.maxes[constants.HSB][1], ', ', this.hsba[2] * this.maxes[constants.HSB][2], ', ', alpha, ')'); 46616 46617 case 'hsba%': 46618 case 'hsva%': 46619 return 'hsba('.concat((100 * this.hsba[0]).toPrecision(3), '%, ', (100 * this.hsba[1]).toPrecision(3), '%, ', (100 * this.hsba[2]).toPrecision(3), '%, ', (100 * alpha).toPrecision(3), '%)'); 46620 46621 case 'hsl': 46622 return 'hsl('.concat(this.hsla[0] * this.maxes[constants.HSL][0], ', ', this.hsla[1] * this.maxes[constants.HSL][1], ', ', this.hsla[2] * this.maxes[constants.HSL][2], ')'); 46623 46624 case 'hsl%': 46625 return 'hsl('.concat((100 * this.hsla[0]).toPrecision(3), '%, ', (100 * this.hsla[1]).toPrecision(3), '%, ', (100 * this.hsla[2]).toPrecision(3), '%)'); 46626 46627 case 'hsla': 46628 return 'hsla('.concat(this.hsla[0] * this.maxes[constants.HSL][0], ', ', this.hsla[1] * this.maxes[constants.HSL][1], ', ', this.hsla[2] * this.maxes[constants.HSL][2], ', ', alpha, ')'); 46629 46630 case 'hsla%': 46631 return 'hsl('.concat((100 * this.hsla[0]).toPrecision(3), '%, ', (100 * this.hsla[1]).toPrecision(3), '%, ', (100 * this.hsla[2]).toPrecision(3), '%, ', (100 * alpha).toPrecision(3), '%)'); 46632 46633 case 'rgba': 46634 default: 46635 return 'rgba(' + a[0] + ',' + a[1] + ',' + a[2] + ',' + alpha + ')'; 46636 } 46637 }; 46638 /** 46639 * @method setRed 46640 * @param {Number} red the new red value 46641 * @example 46642 * <div> 46643 * <code> 46644 * let backgroundColor; 46645 * 46646 * function setup() { 46647 * backgroundColor = color(100, 50, 150); 46648 * } 46649 * 46650 * function draw() { 46651 * backgroundColor.setRed(128 + 128 * sin(millis() / 1000)); 46652 * background(backgroundColor); 46653 * } 46654 * </code> 46655 * </div> 46656 * 46657 * @alt 46658 * canvas with gradually changing background color 46659 */ 46660 46661 46662 p5.Color.prototype.setRed = function (new_red) { 46663 this._array[0] = new_red / this.maxes[constants.RGB][0]; 46664 46665 this._calculateLevels(); 46666 }; 46667 /** 46668 * @method setGreen 46669 * @param {Number} green the new green value 46670 * @example 46671 * <div> 46672 * <code> 46673 * let backgroundColor; 46674 * 46675 * function setup() { 46676 * backgroundColor = color(100, 50, 150); 46677 * } 46678 * 46679 * function draw() { 46680 * backgroundColor.setGreen(128 + 128 * sin(millis() / 1000)); 46681 * background(backgroundColor); 46682 * } 46683 * </code> 46684 * </div> 46685 * 46686 * @alt 46687 * canvas with gradually changing background color 46688 **/ 46689 46690 46691 p5.Color.prototype.setGreen = function (new_green) { 46692 this._array[1] = new_green / this.maxes[constants.RGB][1]; 46693 46694 this._calculateLevels(); 46695 }; 46696 /** 46697 * @method setBlue 46698 * @param {Number} blue the new blue value 46699 * @example 46700 * <div> 46701 * <code> 46702 * let backgroundColor; 46703 * 46704 * function setup() { 46705 * backgroundColor = color(100, 50, 150); 46706 * } 46707 * 46708 * function draw() { 46709 * backgroundColor.setBlue(128 + 128 * sin(millis() / 1000)); 46710 * background(backgroundColor); 46711 * } 46712 * </code> 46713 * </div> 46714 * 46715 * @alt 46716 * canvas with gradually changing background color 46717 **/ 46718 46719 46720 p5.Color.prototype.setBlue = function (new_blue) { 46721 this._array[2] = new_blue / this.maxes[constants.RGB][2]; 46722 46723 this._calculateLevels(); 46724 }; 46725 /** 46726 * @method setAlpha 46727 * @param {Number} alpha the new alpha value 46728 * @example 46729 * <div> 46730 * <code> 46731 * let squareColor; 46732 * 46733 * function setup() { 46734 * ellipseMode(CORNERS); 46735 * strokeWeight(4); 46736 * squareColor = color(100, 50, 150); 46737 * } 46738 * 46739 * function draw() { 46740 * background(255); 46741 * 46742 * noFill(); 46743 * stroke(0); 46744 * ellipse(10, 10, width - 10, height - 10); 46745 * 46746 * squareColor.setAlpha(128 + 128 * sin(millis() / 1000)); 46747 * fill(squareColor); 46748 * noStroke(); 46749 * rect(13, 13, width - 26, height - 26); 46750 * } 46751 * </code> 46752 * </div> 46753 * 46754 * @alt 46755 * circle behind a square with gradually changing opacity 46756 **/ 46757 46758 46759 p5.Color.prototype.setAlpha = function (new_alpha) { 46760 this._array[3] = new_alpha / this.maxes[this.mode][3]; 46761 46762 this._calculateLevels(); 46763 }; // calculates and stores the closest screen levels 46764 46765 46766 p5.Color.prototype._calculateLevels = function () { 46767 var array = this._array; // (loop backwards for performance) 46768 46769 var levels = this.levels = new Array(array.length); 46770 46771 for (var i = array.length - 1; i >= 0; --i) { 46772 levels[i] = Math.round(array[i] * 255); 46773 } 46774 }; 46775 46776 p5.Color.prototype._getAlpha = function () { 46777 return this._array[3] * this.maxes[this.mode][3]; 46778 }; // stores the color mode and maxes in this instance of Color 46779 // for later use (by _parseInputs()) 46780 46781 46782 p5.Color.prototype._storeModeAndMaxes = function (new_mode, new_maxes) { 46783 this.mode = new_mode; 46784 this.maxes = new_maxes; 46785 }; 46786 46787 p5.Color.prototype._getMode = function () { 46788 return this.mode; 46789 }; 46790 46791 p5.Color.prototype._getMaxes = function () { 46792 return this.maxes; 46793 }; 46794 46795 p5.Color.prototype._getBlue = function () {
46796 return this._array[2] * this.maxes[constants.RGB][2]; 46797 }; 46798 46799 p5.Color.prototype._getBrightness = function () { 46800 if (!this.hsba) { 46801 this.hsba = color_conversion._rgbaToHSBA(this._array); 46802 } 46803 46804 return this.hsba[2] * this.maxes[constants.HSB][2]; 46805 }; 46806 46807 p5.Color.prototype._getGreen = function () { 46808 return this._array[1] * this.maxes[constants.RGB][1]; 46809 }; 46810 /** 46811 * Hue is the same in HSB and HSL, but the maximum value may be different. 46812 * This function will return the HSB-normalized saturation when supplied with 46813 * an HSB color object, but will default to the HSL-normalized saturation 46814 * otherwise. 46815 */ 46816 46817 46818 p5.Color.prototype._getHue = function () { 46819 if (this.mode === constants.HSB) { 46820 if (!this.hsba) { 46821 this.hsba = color_conversion._rgbaToHSBA(this._array); 46822 } 46823 46824 return this.hsba[0] * this.maxes[constants.HSB][0]; 46825 } else { 46826 if (!this.hsla) { 46827 this.hsla = color_conversion._rgbaToHSLA(this._array); 46828 } 46829 46830 return this.hsla[0] * this.maxes[constants.HSL][0]; 46831 } 46832 }; 46833 46834 p5.Color.prototype._getLightness = function () { 46835 if (!this.hsla) { 46836 this.hsla = color_conversion._rgbaToHSLA(this._array); 46837 } 46838 46839 return this.hsla[2] * this.maxes[constants.HSL][2]; 46840 }; 46841 46842 p5.Color.prototype._getRed = function () { 46843 return this._array[0] * this.maxes[constants.RGB][0]; 46844 }; 46845 /** 46846 * Saturation is scaled differently in HSB and HSL. This function will return 46847 * the HSB saturation when supplied with an HSB color object, but will default 46848 * to the HSL saturation otherwise. 46849 */ 46850 46851 46852 p5.Color.prototype._getSaturation = function () { 46853 if (this.mode === constants.HSB) { 46854 if (!this.hsba) { 46855 this.hsba = color_conversion._rgbaToHSBA(this._array); 46856 } 46857 46858 return this.hsba[1] * this.maxes[constants.HSB][1]; 46859 } else { 46860 if (!this.hsla) { 46861 this.hsla = color_conversion._rgbaToHSLA(this._array); 46862 } 46863 46864 return this.hsla[1] * this.maxes[constants.HSL][1]; 46865 } 46866 }; 46867 /** 46868 * CSS named colors. 46869 */ 46870 46871 46872 var namedColors = { 46873 aliceblue: '#f0f8ff', 46874 antiquewhite: '#faebd7', 46875 aqua: '#00ffff', 46876 aquamarine: '#7fffd4', 46877 azure: '#f0ffff', 46878 beige: '#f5f5dc', 46879 bisque: '#ffe4c4', 46880 black: '#000000', 46881 blanchedalmond: '#ffebcd', 46882 blue: '#0000ff', 46883 blueviolet: '#8a2be2', 46884 brown: '#a52a2a', 46885 burlywood: '#deb887', 46886 cadetblue: '#5f9ea0', 46887 chartreuse: '#7fff00', 46888 chocolate: '#d2691e', 46889 coral: '#ff7f50', 46890 cornflowerblue: '#6495ed', 46891 cornsilk: '#fff8dc', 46892 crimson: '#dc143c', 46893 cyan: '#00ffff', 46894 darkblue: '#00008b', 46895 darkcyan: '#008b8b', 46896 darkgoldenrod: '#b8860b', 46897 darkgray: '#a9a9a9', 46898 darkgreen: '#006400', 46899 darkgrey: '#a9a9a9', 46900 darkkhaki: '#bdb76b', 46901 darkmagenta: '#8b008b', 46902 darkolivegreen: '#556b2f', 46903 darkorange: '#ff8c00', 46904 darkorchid: '#9932cc', 46905 darkred: '#8b0000', 46906 darksalmon: '#e9967a', 46907 darkseagreen: '#8fbc8f', 46908 darkslateblue: '#483d8b', 46909 darkslategray: '#2f4f4f', 46910 darkslategrey: '#2f4f4f', 46911 darkturquoise: '#00ced1', 46912 darkviolet: '#9400d3', 46913 deeppink: '#ff1493', 46914 deepskyblue: '#00bfff', 46915 dimgray: '#696969', 46916 dimgrey: '#696969', 46917 dodgerblue: '#1e90ff', 46918 firebrick: '#b22222', 46919 floralwhite: '#fffaf0', 46920 forestgreen: '#228b22', 46921 fuchsia: '#ff00ff', 46922 gainsboro: '#dcdcdc', 46923 ghostwhite: '#f8f8ff', 46924 gold: '#ffd700', 46925 goldenrod: '#daa520', 46926 gray: '#808080', 46927 green: '#008000', 46928 greenyellow: '#adff2f', 46929 grey: '#808080', 46930 honeydew: '#f0fff0', 46931 hotpink: '#ff69b4', 46932 indianred: '#cd5c5c', 46933 indigo: '#4b0082', 46934 ivory: '#fffff0', 46935 khaki: '#f0e68c', 46936 lavender: '#e6e6fa', 46937 lavenderblush: '#fff0f5', 46938 lawngreen: '#7cfc00', 46939 lemonchiffon: '#fffacd', 46940 lightblue: '#add8e6', 46941 lightcoral: '#f08080', 46942 lightcyan: '#e0ffff', 46943 lightgoldenrodyellow: '#fafad2', 46944 lightgray: '#d3d3d3', 46945 lightgreen: '#90ee90', 46946 lightgrey: '#d3d3d3', 46947 lightpink: '#ffb6c1', 46948 lightsalmon: '#ffa07a', 46949 lightseagreen: '#20b2aa', 46950 lightskyblue: '#87cefa', 46951 lightslategray: '#778899', 46952 lightslategrey: '#778899', 46953 lightsteelblue: '#b0c4de', 46954 lightyellow: '#ffffe0', 46955 lime: '#00ff00', 46956 limegreen: '#32cd32', 46957 linen: '#faf0e6', 46958 magenta: '#ff00ff', 46959 maroon: '#800000', 46960 mediumaquamarine: '#66cdaa', 46961 mediumblue: '#0000cd', 46962 mediumorchid: '#ba55d3', 46963 mediumpurple: '#9370db', 46964 mediumseagreen: '#3cb371', 46965 mediumslateblue: '#7b68ee', 46966 mediumspringgreen: '#00fa9a', 46967 mediumturquoise: '#48d1cc', 46968 mediumvioletred: '#c71585', 46969 midnightblue: '#191970', 46970 mintcream: '#f5fffa', 46971 mistyrose: '#ffe4e1', 46972 moccasin: '#ffe4b5', 46973 navajowhite: '#ffdead', 46974 navy: '#000080', 46975 oldlace: '#fdf5e6', 46976 olive: '#808000', 46977 olivedrab: '#6b8e23', 46978 orange: '#ffa500', 46979 orangered: '#ff4500', 46980 orchid: '#da70d6', 46981 palegoldenrod: '#eee8aa', 46982 palegreen: '#98fb98', 46983 paleturquoise: '#afeeee', 46984 palevioletred: '#db7093', 46985 papayawhip: '#ffefd5', 46986 peachpuff: '#ffdab9', 46987 peru: '#cd853f', 46988 pink: '#ffc0cb', 46989 plum: '#dda0dd', 46990 powderblue: '#b0e0e6', 46991 purple: '#800080', 46992 red: '#ff0000', 46993 rosybrown: '#bc8f8f', 46994 royalblue: '#4169e1', 46995 saddlebrown: '#8b4513', 46996 salmon: '#fa8072', 46997 sandybrown: '#f4a460', 46998 seagreen: '#2e8b57', 46999 seashell: '#fff5ee', 47000 sienna: '#a0522d', 47001 silver: '#c0c0c0', 47002 skyblue: '#87ceeb', 47003 slateblue: '#6a5acd', 47004 slategray: '#708090', 47005 slategrey: '#708090', 47006 snow: '#fffafa', 47007 springgreen: '#00ff7f', 47008 steelblue: '#4682b4', 47009 tan: '#d2b48c', 47010 teal: '#008080', 47011 thistle: '#d8bfd8', 47012 tomato: '#ff6347', 47013 turquoise: '#40e0d0', 47014 violet: '#ee82ee', 47015 wheat: '#f5deb3', 47016 white: '#ffffff', 47017 whitesmoke: '#f5f5f5', 47018 yellow: '#ffff00', 47019 yellowgreen: '#9acd32' 47020 }; 47021 /** 47022 * These regular expressions are used to build up the patterns for matching 47023 * viable CSS color strings: fragmenting the regexes in this way increases the 47024 * legibility and comprehensibility of the code. 47025 * 47026 * Note that RGB values of .9 are not parsed by IE, but are supported here for 47027 * color string consistency. 47028 */ 47029 47030 var WHITESPACE = /\s*/; // Match zero or more whitespace characters. 47031 47032 var INTEGER = /(\d{1,3})/; // Match integers: 79, 255, etc. 47033 47034 var DECIMAL = /((?:\d+(?:\.\d+)?)|(?:\.\d+))/; // Match 129.6, 79, .9, etc. 47035 47036 var PERCENT = new RegExp(DECIMAL.source + '%'); // Match 12.9%, 79%, .9%, etc. 47037 47038 /** 47039 * Full color string patterns. The capture groups are necessary. 47040 */ 47041 47042 var colorPatterns = { 47043 // Match colors in format #XXX, e.g. #416. 47044 HEX3: /^#([a-f0-9])([a-f0-9])([a-f0-9])$/i, 47045 // Match colors in format #XXXX, e.g. #5123. 47046 HEX4: /^#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])$/i, 47047 // Match colors in format #XXXXXX, e.g. #b4d455. 47048 HEX6: /^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i, 47049 // Match colors in format #XXXXXXXX, e.g. #b4d45535. 47050 HEX8: /^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i, 47051 // Match colors in format rgb(R, G, B), e.g. rgb(255, 0, 128). 47052 RGB: new RegExp(['^rgb\\(', INTEGER.source, ',', INTEGER.source, ',', INTEGER.source, '\\)$'].join(WHITESPACE.source), 'i'), 47053 // Match colors in format rgb(R%, G%, B%), e.g. rgb(100%, 0%, 28.9%). 47054 RGB_PERCENT: new RegExp(['^rgb\\(', PERCENT.source, ',', PERCENT.source, ',', PERCENT.source, '\\)$'].join(WHITESPACE.source), 'i'), 47055 // Match colors in format rgb(R, G, B, A), e.g. rgb(255, 0, 128, 0.25). 47056 RGBA: new RegExp(['^rgba\\(', INTEGER.source, ',', INTEGER.source, ',', INTEGER.source, ',', DECIMAL.source, '\\)$'].join(WHITESPACE.source), 'i'), 47057 // Match colors in format rgb(R%, G%, B%, A), e.g. rgb(100%, 0%, 28.9%, 0.5). 47058 RGBA_PERCENT: new RegExp(['^rgba\\(', PERCENT.source, ',', PERCENT.source, ',', PERCENT.source, ',', DECIMAL.source, '\\)$'].join(WHITESPACE.source), 'i'), 47059 // Match colors in format hsla(H, S%, L%), e.g. hsl(100, 40%, 28.9%).
47060 HSL: new RegExp(['^hsl\\(', INTEGER.source, ',', PERCENT.source, ',', PERCENT.source, '\\)$'].join(WHITESPACE.source), 'i'), 47061 // Match colors in format hsla(H, S%, L%, A), e.g. hsla(100, 40%, 28.9%, 0.5). 47062 HSLA: new RegExp(['^hsla\\(', INTEGER.source, ',', PERCENT.source, ',', PERCENT.source, ',', DECIMAL.source, '\\)$'].join(WHITESPACE.source), 'i'), 47063 // Match colors in format hsb(H, S%, B%), e.g. hsb(100, 40%, 28.9%). 47064 HSB: new RegExp(['^hsb\\(', INTEGER.source, ',', PERCENT.source, ',', PERCENT.source, '\\)$'].join(WHITESPACE.source), 'i'), 47065 // Match colors in format hsba(H, S%, B%, A), e.g. hsba(100, 40%, 28.9%, 0.5). 47066 HSBA: new RegExp(['^hsba\\(', INTEGER.source, ',', PERCENT.source, ',', PERCENT.source, ',', DECIMAL.source, '\\)$'].join(WHITESPACE.source), 'i') 47067 }; 47068 /** 47069 * For a number of different inputs, returns a color formatted as [r, g, b, a] 47070 * arrays, with each component normalized between 0 and 1. 47071 * 47072 * @private 47073 * @param {Array} [...args] An 'array-like' object that represents a list of 47074 * arguments 47075 * @return {Number[]} a color formatted as [r, g, b, a] 47076 * Example: 47077 * input ==> output 47078 * g ==> [g, g, g, 255] 47079 * g,a ==> [g, g, g, a] 47080 * r, g, b ==> [r, g, b, 255] 47081 * r, g, b, a ==> [r, g, b, a] 47082 * [g] ==> [g, g, g, 255] 47083 * [g, a] ==> [g, g, g, a] 47084 * [r, g, b] ==> [r, g, b, 255] 47085 * [r, g, b, a] ==> [r, g, b, a] 47086 * @example 47087 * <div> 47088 * <code> 47089 * // todo 47090 * </code> 47091 * </div> 47092 * 47093 * @alt 47094 * //todo 47095 * 47096 */ 47097 47098 p5.Color._parseInputs = function (r, g, b, a) { 47099 var numArgs = arguments.length; 47100 var mode = this.mode; 47101 var maxes = this.maxes[mode]; 47102 var results = []; 47103 var i; 47104 47105 if (numArgs >= 3) { 47106 // Argument is a list of component values. 47107 results[0] = r / maxes[0]; 47108 results[1] = g / maxes[1]; 47109 results[2] = b / maxes[2]; // Alpha may be undefined, so default it to 100%. 47110 47111 if (typeof a === 'number') { 47112 results[3] = a / maxes[3]; 47113 } else { 47114 results[3] = 1; 47115 } // Constrain components to the range [0,1]. 47116 // (loop backwards for performance) 47117 47118 47119 for (i = results.length - 1; i >= 0; --i) { 47120 var result = results[i]; 47121 47122 if (result < 0) { 47123 results[i] = 0; 47124 } else if (result > 1) { 47125 results[i] = 1; 47126 } 47127 } // Convert to RGBA and return. 47128 47129 47130 if (mode === constants.HSL) { 47131 return color_conversion._hslaToRGBA(results); 47132 } else if (mode === constants.HSB) { 47133 return color_conversion._hsbaToRGBA(results); 47134 } else { 47135 return results; 47136 } 47137 } else if (numArgs === 1 && typeof r === 'string') { 47138 var str = r.trim().toLowerCase(); // Return if string is a named colour. 47139 47140 if (namedColors[str]) { 47141 return p5.Color._parseInputs.call(this, namedColors[str]); 47142 } // Try RGBA pattern matching. 47143 47144 47145 if (colorPatterns.HEX3.test(str)) { 47146 // #rgb 47147 results = colorPatterns.HEX3.exec(str).slice(1).map(function (color) { 47148 return parseInt(color + color, 16) / 255; 47149 }); 47150 results[3] = 1; 47151 return results; 47152 } else if (colorPatterns.HEX6.test(str)) { 47153 // #rrggbb 47154 results = colorPatterns.HEX6.exec(str).slice(1).map(function (color) { 47155 return parseInt(color, 16) / 255; 47156 }); 47157 results[3] = 1; 47158 return results; 47159 } else if (colorPatterns.HEX4.test(str)) { 47160 // #rgba 47161 results = colorPatterns.HEX4.exec(str).slice(1).map(function (color) {
47162 return parseInt(color + color, 16) / 255; 47163 }); 47164 return results; 47165 } else if (colorPatterns.HEX8.test(str)) { 47166 // #rrggbbaa 47167 results = colorPatterns.HEX8.exec(str).slice(1).map(function (color) { 47168 return parseInt(color, 16) / 255; 47169 }); 47170 return results; 47171 } else if (colorPatterns.RGB.test(str)) { 47172 // rgb(R,G,B) 47173 results = colorPatterns.RGB.exec(str).slice(1).map(function (color) { 47174 return color / 255; 47175 }); 47176 results[3] = 1; 47177 return results; 47178 } else if (colorPatterns.RGB_PERCENT.test(str)) { 47179 // rgb(R%,G%,B%) 47180 results = colorPatterns.RGB_PERCENT.exec(str).slice(1).map(function (color) { 47181 return parseFloat(color) / 100; 47182 }); 47183 results[3] = 1; 47184 return results; 47185 } else if (colorPatterns.RGBA.test(str)) { 47186 // rgba(R,G,B,A) 47187 results = colorPatterns.RGBA.exec(str).slice(1).map(function (color, idx) { 47188 if (idx === 3) { 47189 return parseFloat(color); 47190 } 47191 47192 return color / 255; 47193 }); 47194 return results; 47195 } else if (colorPatterns.RGBA_PERCENT.test(str)) { 47196 // rgba(R%,G%,B%,A%) 47197 results = colorPatterns.RGBA_PERCENT.exec(str).slice(1).map(function (color, idx) { 47198 if (idx === 3) { 47199 return parseFloat(color); 47200 } 47201 47202 return parseFloat(color) / 100; 47203 }); 47204 return results; 47205 } // Try HSLA pattern matching. 47206 47207 47208 if (colorPatterns.HSL.test(str)) { 47209 // hsl(H,S,L) 47210 results = colorPatterns.HSL.exec(str).slice(1).map(function (color, idx) { 47211 if (idx === 0) { 47212 return parseInt(color, 10) / 360; 47213 } 47214 47215 return parseInt(color, 10) / 100; 47216 }); 47217 results[3] = 1; 47218 } else if (colorPatterns.HSLA.test(str)) { 47219 // hsla(H,S,L,A) 47220 results = colorPatterns.HSLA.exec(str).slice(1).map(function (color, idx) { 47221 if (idx === 0) { 47222 return parseInt(color, 10) / 360; 47223 } else if (idx === 3) { 47224 return parseFloat(color); 47225 } 47226 47227 return parseInt(color, 10) / 100; 47228 }); 47229 } 47230 47231 results = results.map(function (value) { 47232 return Math.max(Math.min(value, 1), 0); 47233 }); 47234 47235 if (results.length) { 47236 return color_conversion._hslaToRGBA(results); 47237 } // Try HSBA pattern matching. 47238 47239 47240 if (colorPatterns.HSB.test(str)) { 47241 // hsb(H,S,B) 47242 results = colorPatterns.HSB.exec(str).slice(1).map(function (color, idx) { 47243 if (idx === 0) { 47244 return parseInt(color, 10) / 360; 47245 } 47246 47247 return parseInt(color, 10) / 100; 47248 }); 47249 results[3] = 1; 47250 } else if (colorPatterns.HSBA.test(str)) { 47251 // hsba(H,S,B,A) 47252 results = colorPatterns.HSBA.exec(str).slice(1).map(function (color, idx) { 47253 if (idx === 0) { 47254 return parseInt(color, 10) / 360; 47255 } else if (idx === 3) { 47256 return parseFloat(color); 47257 } 47258 47259 return parseInt(color, 10) / 100; 47260 }); 47261 } 47262 47263 if (results.length) { 47264 // (loop backwards for performance) 47265 for (i = results.length - 1; i >= 0; --i) { 47266 results[i] = Math.max(Math.min(results[i], 1), 0); 47267 } 47268 47269 return color_conversion._hsbaToRGBA(results); 47270 } // Input did not match any CSS color pattern: default to white. 47271 47272 47273 results = [1, 1, 1, 1]; 47274 } else if ((numArgs === 1 || numArgs === 2) && typeof r === 'number') { 47275 // 'Grayscale' mode. 47276 47277 /** 47278 * For HSB and HSL, interpret the gray level as a brightness/lightness 47279 * value (they are equivalent when chroma is zero). For RGB, normalize the 47280 * gray level according to the blue maximum. 47281 */ 47282 results[0] = r / maxes[2]; 47283 results[1] = r / maxes[2]; 47284 results[2] = r / maxes[2]; // Alpha may be undefined, so default it to 100%. 47285 47286 if (typeof g === 'number') { 47287 results[3] = g / maxes[3]; 47288 } else { 47289 results[3] = 1; 47290 } // Constrain components to the range [0,1]. 47291 47292 47293 results = results.map(function (value) {
47294 return Math.max(Math.min(value, 1), 0); 47295 }); 47296 } else { 47297 throw new Error(arguments + 'is not a valid color representation.'); 47298 } 47299 47300 return results; 47301 }; 47302 47303 module.exports = p5.Color; 47304 }, { 47305 "../core/constants": 18, 47306 "../core/main": 24, 47307 "./color_conversion": 14 47308 }], 47309 17: [function (_dereq_, module, exports) { 47310 /** 47311 * @module Color 47312 * @submodule Setting 47313 * @for p5 47314 * @requires core 47315 * @requires constants 47316 */ 47317 'use strict'; 47318 47319 var p5 = _dereq_('../core/main'); 47320 47321 var constants = _dereq_('../core/constants'); 47322 47323 _dereq_('./p5.Color'); 47324 /** 47325 * The <a href="#/p5/background">background()</a> function sets the color used for the background of the 47326 * p5.js canvas. The default background is transparent. This function is 47327 * typically used within <a href="#/p5/draw">draw()</a> to clear the display window at the beginning 47328 * of each frame, but it can be used inside <a href="#/p5/setup">setup()</a> to set the background on 47329 * the first frame of animation or if the background need only be set once. 47330 * <br><br> 47331 * The color is either specified in terms of the RGB, HSB, or HSL color 47332 * depending on the current <a href="#/p5/colorMode">colorMode</a>. (The default color space is RGB, with 47333 * each value in the range from 0 to 255). The alpha range by default is also 0 to 255. 47334 * <br><br> 47335 * If a single string argument is provided, RGB, RGBA and Hex CSS color strings 47336 * and all named color strings are supported. In this case, an alpha number 47337 * value as a second argument is not supported, the RGBA form should be used. 47338 * <br><br> 47339 * A <a href="#/p5.Color">p5.Color</a> object can also be provided to set the background color. 47340 * <br><br> 47341 * A <a href="#/p5.Image">p5.Image</a> can also be provided to set the background image. 47342 * 47343 * @method background 47344 * @param {p5.Color} color any value created by the <a href="#/p5/color">color()</a> function 47345 * @chainable 47346 * 47347 * @example 47348 * <div> 47349 * <code> 47350 * // Grayscale integer value 47351 * background(51); 47352 * </code> 47353 * </div> 47354 * 47355 * <div> 47356 * <code> 47357 * // R, G & B integer values 47358 * background(255, 204, 0); 47359 * </code> 47360 * </div> 47361 * 47362 * <div> 47363 * <code> 47364 * // H, S & B integer values 47365 * colorMode(HSB); 47366 * background(255, 204, 100); 47367 * </code> 47368 * </div> 47369 * 47370 * <div> 47371 * <code> 47372 * // Named SVG/CSS color string 47373 * background('red'); 47374 * </code> 47375 * </div> 47376 * 47377 * <div> 47378 * <code> 47379 * // three-digit hexadecimal RGB notation 47380 * background('#fae'); 47381 * </code> 47382 * </div> 47383 * 47384 * <div> 47385 * <code> 47386 * // six-digit hexadecimal RGB notation 47387 * background('#222222'); 47388 * </code> 47389 * </div> 47390 * 47391 * <div> 47392 * <code> 47393 * // integer RGB notation 47394 * background('rgb(0,255,0)'); 47395 * </code> 47396 * </div> 47397 * 47398 * <div> 47399 * <code> 47400 * // integer RGBA notation 47401 * background('rgba(0,255,0, 0.25)'); 47402 * </code> 47403 * </div> 47404 * 47405 * <div> 47406 * <code> 47407 * // percentage RGB notation 47408 * background('rgb(100%,0%,10%)'); 47409 * </code> 47410 * </div> 47411 * 47412 * <div> 47413 * <code> 47414 * // percentage RGBA notation 47415 * background('rgba(100%,0%,100%,0.5)'); 47416 * </code> 47417 * </div> 47418 * 47419 * <div> 47420 * <code> 47421 * // p5 Color object 47422 * background(color(0, 0, 255)); 47423 * </code> 47424 * </div> 47425 * 47426 * @alt 47427 * canvas with darkest charcoal grey background. 47428 * canvas with yellow background. 47429 * canvas with royal blue background. 47430 * canvas with red background. 47431 * canvas with pink background. 47432 * canvas with black background. 47433 * canvas with bright green background. 47434 * canvas with soft green background. 47435 * canvas with red background. 47436 * canvas with light purple background. 47437 * canvas with blue background. 47438 */ 47439 47440 /** 47441 * @method background 47442 * @param {String} colorstring color string, possible formats include: integer 47443 * rgb() or rgba(), percentage rgb() or rgba(), 47444 * 3-digit hex, 6-digit hex 47445 * @param {Number} [a] opacity of the background relative to current 47446 * color range (default is 0-255) 47447 * @chainable 47448 */ 47449 47450 /** 47451 * @method background 47452 * @param {Number} gray specifies a value between white and black 47453 * @param {Number} [a] 47454 * @chainable 47455 */ 47456 47457 /** 47458 * @method background 47459 * @param {Number} v1 red or hue value (depending on the current color 47460 * mode) 47461 * @param {Number} v2 green or saturation value (depending on the current 47462 * color mode) 47463 * @param {Number} v3 blue or brightness value (depending on the current 47464 * color mode) 47465 * @param {Number} [a] 47466 * @chainable 47467 */ 47468 47469 /** 47470 * @method background 47471 * @param {Number[]} values an array containing the red,green,blue & 47472 * and alpha components of the color 47473 * @chainable 47474 */ 47475 47476 /** 47477 * @method background 47478 * @param {p5.Image} image image created with <a href="#/p5/loadImage">loadImage()</a> or <a href="#/p5/createImage">createImage()</a>, 47479 * to set as background 47480 * (must be same size as the sketch window) 47481 * @param {Number} [a] 47482 * @chainable 47483 */ 47484 47485 47486 p5.prototype.background = function () { 47487 if (arguments[0] instanceof p5.Image) { 47488 this.image(arguments[0], 0, 0, this.width, this.height); 47489 } else { 47490 this._renderer.background.apply(this._renderer, arguments); 47491 } 47492 47493 return this; 47494 }; 47495 /** 47496 * Clears the pixels within a buffer. This function only works on p5.Canvas 47497 * objects created with the <a href="#/p5/createCanvas">createCanvas()</a> function; it won't work with the 47498 * main display window. Unlike the main graphics context, pixels in 47499 * additional graphics areas created with <a href="#/p5/createGraphics">createGraphics()</a> can be entirely 47500 * or partially transparent. This function clears everything to make all of 47501 * the pixels 100% transparent. 47502 * 47503 * @method clear 47504 * @chainable 47505 * @example 47506 * <div> 47507 * <code> 47508 * // Clear the screen on mouse press. 47509 * function setup() { 47510 * createCanvas(100, 100); 47511 * } 47512 * 47513 * function draw() { 47514 * ellipse(mouseX, mouseY, 20, 20); 47515 * } 47516 * 47517 * function mousePressed() { 47518 * clear(); 47519 * } 47520 * </code> 47521 * </div> 47522 * 47523 * @alt 47524 * 20x20 white ellipses are continually drawn at mouse x and y coordinates. 47525 * 47526 */ 47527 47528 47529 p5.prototype.clear = function () { 47530 this._renderer.clear(); 47531 47532 return this; 47533 }; 47534 /** 47535 * <a href="#/p5/colorMode">colorMode()</a> changes the way p5.js interprets color data. By default, the 47536 * parameters for <a href="#/p5/fill">fill()</a>, <a href="#/p5/stroke">stroke()</a>, <a href="#/p5/background">background()</a>, and <a href="#/p5/color">color()</a> are defined by 47537 * values between 0 and 255 using the RGB color model. This is equivalent to 47538 * setting colorMode(RGB, 255). Setting colorMode(HSB) lets you use the HSB 47539 * system instead. By default, this is colorMode(HSB, 360, 100, 100, 1). You 47540 * can also use HSL. 47541 * <br><br> 47542 * Note: existing color objects remember the mode that they were created in, 47543 * so you can change modes as you like without affecting their appearance. 47544 * 47545 * 47546 * @method colorMode 47547 * @param {Constant} mode either RGB, HSB or HSL, corresponding to 47548 * Red/Green/Blue and Hue/Saturation/Brightness 47549 * (or Lightness) 47550 * @param {Number} [max] range for all values 47551 * @chainable 47552 * 47553 * @example 47554 * <div> 47555 * <code> 47556 * noStroke(); 47557 * colorMode(RGB, 100); 47558 * for (let i = 0; i < 100; i++) { 47559 * for (let j = 0; j < 100; j++) { 47560 * stroke(i, j, 0); 47561 * point(i, j); 47562 * } 47563 * } 47564 * </code> 47565 * </div> 47566 * 47567 * <div> 47568 * <code> 47569 * noStroke(); 47570 * colorMode(HSB, 100); 47571 * for (let i = 0; i < 100; i++) { 47572 * for (let j = 0; j < 100; j++) { 47573 * stroke(i, j, 100); 47574 * point(i, j); 47575 * } 47576 * } 47577 * </code> 47578 * </div> 47579 * 47580 * <div> 47581 * <code> 47582 * colorMode(RGB, 255); 47583 * let c = color(127, 255, 0); 47584 * 47585 * colorMode(RGB, 1); 47586 * let myColor = c._getRed(); 47587 * text(myColor, 10, 10, 80, 80); 47588 * </code> 47589 * </div> 47590 * 47591 * <div> 47592 * <code> 47593 * noFill(); 47594 * colorMode(RGB, 255, 255, 255, 1); 47595 * background(255); 47596 * 47597 * strokeWeight(4); 47598 * stroke(255, 0, 10, 0.3); 47599 * ellipse(40, 40, 50, 50); 47600 * ellipse(50, 50, 40, 40); 47601 * </code> 47602 * </div> 47603 * 47604 * @alt 47605 *Green to red gradient from bottom L to top R. shading originates from top left. 47606 *Rainbow gradient from left to right. Brightness increasing to white at top. 47607 *unknown image. 47608 *50x50 ellipse at middle L & 40x40 ellipse at center. Transluscent pink outlines. 47609 * 47610 */ 47611 47612 /** 47613 * @method colorMode 47614 * @param {Constant} mode 47615 * @param {Number} max1 range for the red or hue depending on the 47616 * current color mode 47617 * @param {Number} max2 range for the green or saturation depending 47618 * on the current color mode 47619 * @param {Number} max3 range for the blue or brightness/lighntess 47620 * depending on the current color mode 47621 * @param {Number} [maxA] range for the alpha 47622 * @chainable 47623 */ 47624 47625 47626 p5.prototype.colorMode = function (mode, max1, max2, max3, maxA) { 47627 p5._validateParameters('colorMode', arguments); 47628 47629 if (mode === constants.RGB || mode === constants.HSB || mode === constants.HSL) { 47630 // Set color mode. 47631 this._colorMode = mode; // Set color maxes. 47632 47633 var maxes = this._colorMaxes[mode]; 47634 47635 if (arguments.length === 2) { 47636 maxes[0] = max1; // Red 47637 47638 maxes[1] = max1; // Green 47639 47640 maxes[2] = max1; // Blue 47641 47642 maxes[3] = max1; // Alpha 47643 } else if (arguments.length === 4) { 47644 maxes[0] = max1; // Red 47645 47646 maxes[1] = max2; // Green 47647 47648 maxes[2] = max3; // Blue 47649 } else if (arguments.length === 5) { 47650 maxes[0] = max1; // Red 47651 47652 maxes[1] = max2; // Green 47653 47654 maxes[2] = max3; // Blue 47655 47656 maxes[3] = maxA; // Alpha 47657 } 47658 } 47659 47660 return this; 47661 }; 47662 /** 47663 * Sets the color used to fill shapes. For example, if you run 47664 * fill(204, 102, 0), all subsequent shapes will be filled with orange. This 47665 * color is either specified in terms of the RGB or HSB color depending on 47666 * the current <a href="#/p5/colorMode">colorMode()</a>. (The default color space is RGB, with each value 47667 * in the range from 0 to 255). The alpha range by default is also 0 to 255. 47668 * <br><br>
47669 * If a single string argument is provided, RGB, RGBA and Hex CSS color strings 47670 * and all named color strings are supported. In this case, an alpha number 47671 * value as a second argument is not supported, the RGBA form should be used. 47672 * <br><br> 47673 * A p5 <a href="#/p5.Color">Color</a> object can also be provided to set the fill color. 47674 * 47675 * @method fill 47676 * @param {Number} v1 red or hue value relative to 47677 * the current color range 47678 * @param {Number} v2 green or saturation value 47679 * relative to the current color range 47680 * @param {Number} v3 blue or brightness value 47681 * relative to the current color range 47682 * @param {Number} [alpha] 47683 * @chainable 47684 * @example 47685 * <div> 47686 * <code> 47687 * // Grayscale integer value 47688 * fill(51); 47689 * rect(20, 20, 60, 60); 47690 * </code> 47691 * </div> 47692 * 47693 * <div> 47694 * <code> 47695 * // R, G & B integer values 47696 * fill(255, 204, 0); 47697 * rect(20, 20, 60, 60); 47698 * </code> 47699 * </div> 47700 * 47701 * <div> 47702 * <code> 47703 * // H, S & B integer values 47704 * colorMode(HSB); 47705 * fill(255, 204, 100); 47706 * rect(20, 20, 60, 60); 47707 * </code> 47708 * </div> 47709 * 47710 * <div> 47711 * <code> 47712 * // Named SVG/CSS color string 47713 * fill('red'); 47714 * rect(20, 20, 60, 60); 47715 * </code> 47716 * </div> 47717 * 47718 * <div> 47719 * <code> 47720 * // three-digit hexadecimal RGB notation 47721 * fill('#fae'); 47722 * rect(20, 20, 60, 60); 47723 * </code> 47724 * </div> 47725 * 47726 * <div> 47727 * <code> 47728 * // six-digit hexadecimal RGB notation 47729 * fill('#222222'); 47730 * rect(20, 20, 60, 60); 47731 * </code> 47732 * </div> 47733 * 47734 * <div> 47735 * <code> 47736 * // integer RGB notation 47737 * fill('rgb(0,255,0)'); 47738 * rect(20, 20, 60, 60); 47739 * </code> 47740 * </div> 47741 * 47742 * <div> 47743 * <code> 47744 * // integer RGBA notation 47745 * fill('rgba(0,255,0, 0.25)'); 47746 * rect(20, 20, 60, 60); 47747 * </code> 47748 * </div> 47749 * 47750 * <div> 47751 * <code> 47752 * // percentage RGB notation 47753 * fill('rgb(100%,0%,10%)'); 47754 * rect(20, 20, 60, 60); 47755 * </code> 47756 * </div> 47757 * 47758 * <div> 47759 * <code> 47760 * // percentage RGBA notation 47761 * fill('rgba(100%,0%,100%,0.5)'); 47762 * rect(20, 20, 60, 60); 47763 * </code> 47764 * </div> 47765 * 47766 * <div> 47767 * <code> 47768 * // p5 Color object 47769 * fill(color(0, 0, 255)); 47770 * rect(20, 20, 60, 60); 47771 * </code> 47772 * </div> 47773 * @alt 47774 * 60x60 dark charcoal grey rect with black outline in center of canvas. 47775 * 60x60 yellow rect with black outline in center of canvas. 47776 * 60x60 royal blue rect with black outline in center of canvas. 47777 * 60x60 red rect with black outline in center of canvas. 47778 * 60x60 pink rect with black outline in center of canvas. 47779 * 60x60 black rect with black outline in center of canvas. 47780 * 60x60 light green rect with black outline in center of canvas. 47781 * 60x60 soft green rect with black outline in center of canvas. 47782 * 60x60 red rect with black outline in center of canvas. 47783 * 60x60 dark fushcia rect with black outline in center of canvas. 47784 * 60x60 blue rect with black outline in center of canvas. 47785 */ 47786 47787 /** 47788 * @method fill 47789 * @param {String} value a color string 47790 * @chainable 47791 */ 47792 47793 /** 47794 * @method fill 47795 * @param {Number} gray a gray value 47796 * @param {Number} [alpha] 47797 * @chainable 47798 */ 47799 47800 /** 47801 * @method fill 47802 * @param {Number[]} values an array containing the red,green,blue & 47803 * and alpha components of the color 47804 * @chainable 47805 */ 47806 47807 /** 47808 * @method fill 47809 * @param {p5.Color} color the fill color 47810 * @chainable 47811 */ 47812 47813 47814 p5.prototype.fill = function () { 47815 this._renderer._setProperty('_fillSet', true); 47816 47817 this._renderer._setProperty('_doFill', true); 47818
47819 this._renderer.fill.apply(this._renderer, arguments); 47820 47821 return this; 47822 }; 47823 /** 47824 * Disables filling geometry. If both <a href="#/p5/noStroke">noStroke()</a> and <a href="#/p5/noFill">noFill()</a> are called, 47825 * nothing will be drawn to the screen. 47826 * 47827 * @method noFill 47828 * @chainable 47829 * @example 47830 * <div> 47831 * <code> 47832 * rect(15, 10, 55, 55); 47833 * noFill(); 47834 * rect(20, 20, 60, 60); 47835 * </code> 47836 * </div> 47837 * 47838 * <div modernizr='webgl'> 47839 * <code> 47840 * function setup() { 47841 * createCanvas(100, 100, WEBGL); 47842 * } 47843 * 47844 * function draw() { 47845 * background(0); 47846 * noFill(); 47847 * stroke(100, 100, 240); 47848 * rotateX(frameCount * 0.01); 47849 * rotateY(frameCount * 0.01); 47850 * box(45, 45, 45); 47851 * } 47852 * </code> 47853 * </div> 47854 * 47855 * @alt 47856 * white rect top middle and noFill rect center. Both 60x60 with black outlines. 47857 * black canvas with purple cube wireframe spinning 47858 */ 47859 47860 47861 p5.prototype.noFill = function () { 47862 this._renderer._setProperty('_doFill', false); 47863 47864 return this; 47865 }; 47866 /** 47867 * Disables drawing the stroke (outline). If both <a href="#/p5/noStroke">noStroke()</a> and <a href="#/p5/noFill">noFill()</a> 47868 * are called, nothing will be drawn to the screen. 47869 * 47870 * @method noStroke 47871 * @chainable 47872 * @example 47873 * <div> 47874 * <code> 47875 * noStroke(); 47876 * rect(20, 20, 60, 60); 47877 * </code> 47878 * </div> 47879 * 47880 * <div modernizr='webgl'> 47881 * <code> 47882 * function setup() { 47883 * createCanvas(100, 100, WEBGL); 47884 * } 47885 * 47886 * function draw() { 47887 * background(0); 47888 * noStroke(); 47889 * fill(240, 150, 150); 47890 * rotateX(frameCount * 0.01); 47891 * rotateY(frameCount * 0.01); 47892 * box(45, 45, 45); 47893 * } 47894 * </code> 47895 * </div> 47896 * 47897 * @alt 47898 * 60x60 white rect at center. no outline. 47899 * black canvas with pink cube spinning 47900 */ 47901 47902 47903 p5.prototype.noStroke = function () { 47904 this._renderer._setProperty('_doStroke', false); 47905 47906 return this; 47907 }; 47908 /** 47909 * Sets the color used to draw lines and borders around shapes. This color 47910 * is either specified in terms of the RGB or HSB color depending on the 47911 * current <a href="#/p5/colorMode">colorMode()</a> (the default color space is RGB, with each value in 47912 * the range from 0 to 255). The alpha range by default is also 0 to 255. 47913 * <br><br> 47914 * If a single string argument is provided, RGB, RGBA and Hex CSS color 47915 * strings and all named color strings are supported. In this case, an alpha 47916 * number value as a second argument is not supported, the RGBA form should be 47917 * used. 47918 * <br><br> 47919 * A p5 <a href="#/p5.Color">Color</a> object can also be provided to set the stroke color. 47920 * 47921 * 47922 * @method stroke 47923 * @param {Number} v1 red or hue value relative to 47924 * the current color range 47925 * @param {Number} v2 green or saturation value 47926 * relative to the current color range 47927 * @param {Number} v3 blue or brightness value 47928 * relative to the current color range 47929 * @param {Number} [alpha] 47930 * @chainable 47931 * 47932 * @example 47933 * <div> 47934 * <code> 47935 * // Grayscale integer value 47936 * strokeWeight(4); 47937 * stroke(51); 47938 * rect(20, 20, 60, 60); 47939 * </code> 47940 * </div> 47941 * 47942 * <div> 47943 * <code> 47944 * // R, G & B integer values 47945 * stroke(255, 204, 0); 47946 * strokeWeight(4); 47947 * rect(20, 20, 60, 60); 47948 * </code> 47949 * </div> 47950 * 47951 * <div> 47952 * <code> 47953 * // H, S & B integer values 47954 * colorMode(HSB); 47955 * strokeWeight(4); 47956 * stroke(255, 204, 100); 47957 * rect(20, 20, 60, 60); 47958 * </code> 47959 * </div> 47960 * 47961 * <div> 47962 * <code> 47963 * // Named SVG/CSS color string 47964 * stroke('red'); 47965 * strokeWeight(4); 47966 * rect(20, 20, 60, 60); 47967 * </code> 47968 * </div> 47969 * 47970 * <div> 47971 * <code> 47972 * // three-digit hexadecimal RGB notation 47973 * stroke('#fae'); 47974 * strokeWeight(4); 47975 * rect(20, 20, 60, 60); 47976 * </code> 47977 * </div> 47978 * 47979 * <div> 47980 * <code> 47981 * // six-digit hexadecimal RGB notation 47982 * stroke('#222222'); 47983 * strokeWeight(4); 47984 * rect(20, 20, 60, 60); 47985 * </code> 47986 * </div> 47987 * 47988 * <div> 47989 * <code> 47990 * // integer RGB notation 47991 * stroke('rgb(0,255,0)'); 47992 * strokeWeight(4); 47993 * rect(20, 20, 60, 60); 47994 * </code> 47995 * </div> 47996 * 47997 * <div> 47998 * <code> 47999 * // integer RGBA notation 48000 * stroke('rgba(0,255,0,0.25)'); 48001 * strokeWeight(4); 48002 * rect(20, 20, 60, 60); 48003 * </code> 48004 * </div> 48005 * 48006 * <div> 48007 * <code> 48008 * // percentage RGB notation 48009 * stroke('rgb(100%,0%,10%)'); 48010 * strokeWeight(4); 48011 * rect(20, 20, 60, 60); 48012 * </code> 48013 * </div> 48014 * 48015 * <div> 48016 * <code> 48017 * // percentage RGBA notation 48018 * stroke('rgba(100%,0%,100%,0.5)'); 48019 * strokeWeight(4); 48020 * rect(20, 20, 60, 60); 48021 * </code> 48022 * </div> 48023 * 48024 * <div> 48025 * <code> 48026 * // p5 Color object
48027 * stroke(color(0, 0, 255)); 48028 * strokeWeight(4); 48029 * rect(20, 20, 60, 60); 48030 * </code> 48031 * </div> 48032 * 48033 * @alt 48034 * 60x60 white rect at center. Dark charcoal grey outline. 48035 * 60x60 white rect at center. Yellow outline. 48036 * 60x60 white rect at center. Royal blue outline. 48037 * 60x60 white rect at center. Red outline. 48038 * 60x60 white rect at center. Pink outline. 48039 * 60x60 white rect at center. Black outline. 48040 * 60x60 white rect at center. Bright green outline. 48041 * 60x60 white rect at center. Soft green outline. 48042 * 60x60 white rect at center. Red outline. 48043 * 60x60 white rect at center. Dark fushcia outline. 48044 * 60x60 white rect at center. Blue outline. 48045 */ 48046 48047 /** 48048 * @method stroke 48049 * @param {String} value a color string 48050 * @chainable 48051 */ 48052 48053 /** 48054 * @method stroke 48055 * @param {Number} gray a gray value 48056 * @param {Number} [alpha] 48057 * @chainable 48058 */ 48059 48060 /** 48061 * @method stroke 48062 * @param {Number[]} values an array containing the red,green,blue & 48063 * and alpha components of the color 48064 * @chainable 48065 */ 48066 48067 /** 48068 * @method stroke 48069 * @param {p5.Color} color the stroke color 48070 * @chainable 48071 */ 48072 48073 48074 p5.prototype.stroke = function () { 48075 this._renderer._setProperty('_strokeSet', true); 48076 48077 this._renderer._setProperty('_doStroke', true); 48078 48079 this._renderer.stroke.apply(this._renderer, arguments); 48080 48081 return this; 48082 }; 48083 48084 module.exports = p5; 48085 }, {
48086 "../core/constants": 18, 48087 "../core/main": 24, 48088 "./p5.Color": 16 48089 }], 48090 18: [function (_dereq_, module, exports) { 48091 /** 48092 * @module Constants 48093 * @submodule Constants 48094 * @for p5 48095 */ 48096 'use strict'; 48097 48098 var PI = Math.PI; 48099 module.exports = { 48100 // GRAPHICS RENDERER 48101 48102 /** 48103 * @property {String} P2D 48104 * @final 48105 */ 48106 P2D: 'p2d', 48107 48108 /** 48109 * @property {String} WEBGL 48110 * @final 48111 */ 48112 WEBGL: 'webgl', 48113 // ENVIRONMENT 48114 48115 /** 48116 * @property {String} ARROW 48117 * @final 48118 */ 48119 ARROW: 'default', 48120 48121 /** 48122 * @property {String} CROSS 48123 * @final 48124 */ 48125 CROSS: 'crosshair', 48126 48127 /** 48128 * @property {String} HAND 48129 * @final 48130 */ 48131 HAND: 'pointer', 48132 48133 /** 48134 * @property {String} MOVE 48135 * @final 48136 */ 48137 MOVE: 'move', 48138 48139 /** 48140 * @property {String} TEXT 48141 * @final 48142 */ 48143 TEXT: 'text', 48144 48145 /** 48146 * @property {String} WAIT 48147 * @final 48148 */ 48149 WAIT: 'wait', 48150 // TRIGONOMETRY 48151 48152 /** 48153 * HALF_PI is a mathematical constant with the value 48154 * 1.57079632679489661923. It is half the ratio of the 48155 * circumference of a circle to its diameter. It is useful in 48156 * combination with the trigonometric functions <a href="#/p5/sin">sin()</a> and <a href="#/p5/cos">cos()</a>. 48157 * 48158 * @property {Number} HALF_PI 48159 * @final 48160 * 48161 * @example 48162 * <div><code> 48163 * arc(50, 50, 80, 80, 0, HALF_PI); 48164 * </code></div> 48165 * 48166 * @alt 48167 * 80x80 white quarter-circle with curve toward bottom right of canvas. 48168 * 48169 */ 48170 HALF_PI: PI / 2, 48171 48172 /** 48173 * PI is a mathematical constant with the value 48174 * 3.14159265358979323846. It is the ratio of the circumference 48175 * of a circle to its diameter. It is useful in combination with 48176 * the trigonometric functions <a href="#/p5/sin">sin()</a> and <a href="#/p5/cos">cos()</a>. 48177 * 48178 * @property {Number} PI 48179 * @final 48180 * 48181 * @example 48182 * <div><code> 48183 * arc(50, 50, 80, 80, 0, PI); 48184 * </code></div> 48185 * 48186 * @alt 48187 * white half-circle with curve toward bottom of canvas. 48188 * 48189 */ 48190 PI: PI, 48191 48192 /** 48193 * QUARTER_PI is a mathematical constant with the value 0.7853982. 48194 * It is one quarter the ratio of the circumference of a circle to 48195 * its diameter. It is useful in combination with the trigonometric 48196 * functions <a href="#/p5/sin">sin()</a> and <a href="#/p5/cos">cos()</a>. 48197 * 48198 * @property {Number} QUARTER_PI 48199 * @final 48200 * 48201 * @example 48202 * <div><code> 48203 * arc(50, 50, 80, 80, 0, QUARTER_PI); 48204 * </code></div> 48205 * 48206 * @alt 48207 * white eighth-circle rotated about 40 degrees with curve bottom right canvas. 48208 * 48209 */ 48210 QUARTER_PI: PI / 4, 48211 48212 /** 48213 * TAU is an alias for TWO_PI, a mathematical constant with the 48214 * value 6.28318530717958647693. It is twice the ratio of the 48215 * circumference of a circle to its diameter. It is useful in 48216 * combination with the trigonometric functions <a href="#/p5/sin">sin()</a> and <a href="#/p5/cos">cos()</a>. 48217 * 48218 * @property {Number} TAU 48219 * @final 48220 * 48221 * @example 48222 * <div><code> 48223 * arc(50, 50, 80, 80, 0, TAU); 48224 * </code></div> 48225 * 48226 * @alt 48227 * 80x80 white ellipse shape in center of canvas. 48228 * 48229 */ 48230 TAU: PI * 2, 48231 48232 /** 48233 * TWO_PI is a mathematical constant with the value 48234 * 6.28318530717958647693. It is twice the ratio of the 48235 * circumference of a circle to its diameter. It is useful in 48236 * combination with the trigonometric functions <a href="#/p5/sin">sin()</a> and <a href="#/p5/cos">cos()</a>. 48237 * 48238 * @property {Number} TWO_PI 48239 * @final 48240 * 48241 * @example 48242 * <div><code> 48243 * arc(50, 50, 80, 80, 0, TWO_PI); 48244 * </code></div> 48245 * 48246 * @alt 48247 * 80x80 white ellipse shape in center of canvas. 48248 * 48249 */ 48250 TWO_PI: PI * 2, 48251 48252 /** 48253 * Constant to be used with <a href="#/p5/angleMode">angleMode()</a> function, to set the mode which 48254 * p5.js interprates and calculates angles (either DEGREES or RADIANS). 48255 * @property {String} DEGREES 48256 * @final 48257 * 48258 * @example 48259 * <div class='norender'><code> 48260 * function setup() { 48261 * angleMode(DEGREES); 48262 * } 48263 * </code></div> 48264 */ 48265 DEGREES: 'degrees', 48266 48267 /** 48268 * Constant to be used with <a href="#/p5/angleMode">angleMode()</a> function, to set the mode which 48269 * p5.js interprates and calculates angles (either RADIANS or DEGREES). 48270 * @property {String} RADIANS 48271 * @final 48272 * 48273 * @example 48274 * <div class='norender'><code> 48275 * function setup() { 48276 * angleMode(RADIANS); 48277 * } 48278 * </code></div> 48279 */ 48280 RADIANS: 'radians', 48281 DEG_TO_RAD: PI / 180.0, 48282 RAD_TO_DEG: 180.0 / PI, 48283 // SHAPE 48284 48285 /** 48286 * @property {String} CORNER 48287 * @final 48288 */ 48289 CORNER: 'corner', 48290 48291 /** 48292 * @property {String} CORNERS 48293 * @final 48294 */ 48295 CORNERS: 'corners', 48296 48297 /** 48298 * @property {String} RADIUS 48299 * @final 48300 */ 48301 RADIUS: 'radius', 48302 48303 /** 48304 * @property {String} RIGHT 48305 * @final 48306 */ 48307 RIGHT: 'right', 48308 48309 /** 48310 * @property {String} LEFT 48311 * @final 48312 */ 48313 LEFT: 'left', 48314 48315 /** 48316 * @property {String} CENTER 48317 * @final 48318 */ 48319 CENTER: 'center', 48320 48321 /** 48322 * @property {String} TOP 48323 * @final 48324 */ 48325 TOP: 'top', 48326 48327 /** 48328 * @property {String} BOTTOM 48329 * @final 48330 */ 48331 BOTTOM: 'bottom', 48332 48333 /** 48334 * @property {String} BASELINE 48335 * @final 48336 * @default alphabetic 48337 */ 48338 BASELINE: 'alphabetic', 48339 48340 /** 48341 * @property {Number} POINTS 48342 * @final 48343 * @default 0x0000 48344 */ 48345 POINTS: 0x0000, 48346 48347 /** 48348 * @property {Number} LINES 48349 * @final 48350 * @default 0x0001 48351 */ 48352 LINES: 0x0001, 48353 48354 /** 48355 * @property {Number} LINE_STRIP 48356 * @final 48357 * @default 0x0003 48358 */ 48359 LINE_STRIP: 0x0003, 48360 48361 /** 48362 * @property {Number} LINE_LOOP 48363 * @final 48364 * @default 0x0002 48365 */ 48366 LINE_LOOP: 0x0002, 48367 48368 /** 48369 * @property {Number} TRIANGLES 48370 * @final 48371 * @default 0x0004 48372 */ 48373 TRIANGLES: 0x0004, 48374 48375 /** 48376 * @property {Number} TRIANGLE_FAN 48377 * @final 48378 * @default 0x0006 48379 */ 48380 TRIANGLE_FAN: 0x0006, 48381 48382 /** 48383 * @property {Number} TRIANGLE_STRIP 48384 * @final 48385 * @default 0x0005 48386 */ 48387 TRIANGLE_STRIP: 0x0005, 48388 48389 /** 48390 * @property {String} QUADS 48391 * @final 48392 */ 48393 QUADS: 'quads', 48394 48395 /** 48396 * @property {String} QUAD_STRIP 48397 * @final 48398 * @default quad_strip 48399 */ 48400 QUAD_STRIP: 'quad_strip', 48401 48402 /** 48403 * @property {String} CLOSE 48404 * @final 48405 */ 48406 CLOSE: 'close', 48407 48408 /** 48409 * @property {String} OPEN 48410 * @final 48411 */ 48412 OPEN: 'open', 48413 48414 /** 48415 * @property {String} CHORD 48416 * @final 48417 */ 48418 CHORD: 'chord', 48419 48420 /** 48421 * @property {String} PIE 48422 * @final 48423 */ 48424 PIE: 'pie', 48425 48426 /** 48427 * @property {String} PROJECT 48428 * @final 48429 * @default square 48430 */ 48431 PROJECT: 'square', 48432 // PEND: careful this is counterintuitive 48433 48434 /** 48435 * @property {String} SQUARE 48436 * @final 48437 * @default butt 48438 */ 48439 SQUARE: 'butt', 48440 48441 /** 48442 * @property {String} ROUND 48443 * @final 48444 */ 48445 ROUND: 'round', 48446 48447 /** 48448 * @property {String} BEVEL 48449 * @final 48450 */ 48451 BEVEL: 'bevel', 48452 48453 /** 48454 * @property {String} MITER 48455 * @final 48456 */ 48457 MITER: 'miter', 48458 // COLOR 48459 48460 /** 48461 * @property {String} RGB 48462 * @final 48463 */ 48464 RGB: 'rgb', 48465 48466 /** 48467 * @property {String} HSB 48468 * @final 48469 */ 48470 HSB: 'hsb', 48471 48472 /** 48473 * @property {String} HSL 48474 * @final 48475 */ 48476 HSL: 'hsl', 48477 // DOM EXTENSION 48478 48479 /** 48480 * @property {String} AUTO 48481 * @final 48482 */ 48483 AUTO: 'auto', 48484 // INPUT 48485 ALT: 18, 48486 BACKSPACE: 8, 48487 CONTROL: 17, 48488 DELETE: 46, 48489 DOWN_ARROW: 40, 48490 ENTER: 13, 48491 ESCAPE: 27, 48492 LEFT_ARROW: 37, 48493 OPTION: 18, 48494 RETURN: 13, 48495 RIGHT_ARROW: 39, 48496 SHIFT: 16, 48497 TAB: 9, 48498 UP_ARROW: 38, 48499 // RENDERING 48500 48501 /** 48502 * @property {String} BLEND 48503 * @final 48504 * @default source-over 48505 */ 48506 BLEND: 'source-over', 48507 48508 /** 48509 * @property {String} ADD 48510 * @final 48511 * @default lighter 48512 */ 48513 ADD: 'lighter', 48514 //ADD: 'add', // 48515 //SUBTRACT: 'subtract', // 48516 48517 /** 48518 * @property {String} DARKEST 48519 * @final 48520 */ 48521 DARKEST: 'darken', 48522 48523 /** 48524 * @property {String} LIGHTEST 48525 * @final 48526 * @default lighten 48527 */ 48528 LIGHTEST: 'lighten', 48529 48530 /** 48531 * @property {String} DIFFERENCE 48532 * @final 48533 */ 48534 DIFFERENCE: 'difference', 48535 48536 /** 48537 * @property {String} EXCLUSION 48538 * @final 48539 */ 48540 EXCLUSION: 'exclusion', 48541 48542 /** 48543 * @property {String} MULTIPLY 48544 * @final 48545 */ 48546 MULTIPLY: 'multiply', 48547 48548 /** 48549 * @property {String} SCREEN 48550 * @final 48551 */ 48552 SCREEN: 'screen', 48553 48554 /** 48555 * @property {String} REPLACE 48556 * @final 48557 * @default copy 48558 */ 48559 REPLACE: 'copy', 48560 48561 /** 48562 * @property {String} OVERLAY 48563 * @final 48564 */ 48565 OVERLAY: 'overlay', 48566 48567 /** 48568 * @property {String} HARD_LIGHT 48569 * @final 48570 */ 48571 HARD_LIGHT: 'hard-light', 48572 48573 /** 48574 * @property {String} SOFT_LIGHT 48575 * @final 48576 */ 48577 SOFT_LIGHT: 'soft-light', 48578 48579 /** 48580 * @property {String} DODGE 48581 * @final 48582 * @default color-dodge 48583 */ 48584 DODGE: 'color-dodge', 48585 48586 /** 48587 * @property {String} BURN 48588 * @final 48589 * @default color-burn 48590 */ 48591 BURN: 'color-burn', 48592 // FILTERS 48593 48594 /** 48595 * @property {String} THRESHOLD 48596 * @final 48597 */ 48598 THRESHOLD: 'threshold', 48599 48600 /** 48601 * @property {String} GRAY 48602 * @final 48603 */ 48604 GRAY: 'gray', 48605 48606 /** 48607 * @property {String} OPAQUE 48608 * @final 48609 */
48610 OPAQUE: 'opaque', 48611 48612 /** 48613 * @property {String} INVERT 48614 * @final 48615 */ 48616 INVERT: 'invert', 48617 48618 /** 48619 * @property {String} POSTERIZE 48620 * @final 48621 */ 48622 POSTERIZE: 'posterize', 48623 48624 /** 48625 * @property {String} DILATE 48626 * @final 48627 */ 48628 DILATE: 'dilate', 48629 48630 /** 48631 * @property {String} ERODE 48632 * @final 48633 */ 48634 ERODE: 'erode', 48635 48636 /** 48637 * @property {String} BLUR 48638 * @final 48639 */ 48640 BLUR: 'blur', 48641 // TYPOGRAPHY 48642 48643 /** 48644 * @property {String} NORMAL 48645 * @final 48646 */ 48647 NORMAL: 'normal', 48648 48649 /** 48650 * @property {String} ITALIC 48651 * @final 48652 */ 48653 ITALIC: 'italic', 48654 48655 /** 48656 * @property {String} BOLD 48657 * @final 48658 */ 48659 BOLD: 'bold', 48660 48661 /** 48662 * @property {String} BOLDITALIC 48663 * @final 48664 */ 48665 BOLDITALIC: 'bold italic', 48666 // TYPOGRAPHY-INTERNAL 48667 _DEFAULT_TEXT_FILL: '#000000', 48668 _DEFAULT_LEADMULT: 1.25, 48669 _CTX_MIDDLE: 'middle', 48670 // VERTICES 48671 LINEAR: 'linear', 48672 QUADRATIC: 'quadratic', 48673 BEZIER: 'bezier', 48674 CURVE: 'curve', 48675 // WEBGL DRAWMODES 48676 STROKE: 'stroke', 48677 FILL: 'fill', 48678 TEXTURE: 'texture', 48679 IMMEDIATE: 'immediate', 48680 // WEBGL TEXTURE MODE 48681 // NORMAL already exists for typography 48682 IMAGE: 'image', 48683 // WEBGL TEXTURE WRAP AND FILTERING 48684 // LINEAR already exists above 48685 NEAREST: 'nearest', 48686 REPEAT: 'repeat', 48687 CLAMP: 'clamp', 48688 MIRROR: 'mirror', 48689 // DEVICE-ORIENTATION 48690 48691 /** 48692 * @property {String} LANDSCAPE 48693 * @final 48694 */ 48695 LANDSCAPE: 'landscape', 48696 48697 /** 48698 * @property {String} PORTRAIT 48699 * @final 48700 */ 48701 PORTRAIT: 'portrait', 48702 // DEFAULTS 48703 _DEFAULT_STROKE: '#000000', 48704 _DEFAULT_FILL: '#FFFFFF', 48705 48706 /** 48707 * @property {String} GRID 48708 * @final 48709 */ 48710 GRID: 'grid', 48711 48712 /** 48713 * @property {String} AXES 48714 * @final 48715 */ 48716 AXES: 'axes' 48717 }; 48718 }, {}], 48719 19: [function (_dereq_, module, exports) { 48720 /** 48721 * @module Environment 48722 * @submodule Environment 48723 * @for p5 48724 * @requires core 48725 * @requires constants 48726 */ 48727 'use strict'; 48728 48729 var p5 = _dereq_('./main'); 48730 48731 var C = _dereq_('./constants'); 48732 48733 var standardCursors = [C.ARROW, C.CROSS, C.HAND, C.MOVE, C.TEXT, C.WAIT]; 48734 p5.prototype._frameRate = 0; 48735 p5.prototype._lastFrameTime = window.performance.now(); 48736 p5.prototype._targetFrameRate = 60; 48737 var _windowPrint = window.print; 48738 /** 48739 * The <a href="#/p5/print">print()</a> function writes to the console area of your browser. 48740 * This function is often helpful for looking at the data a program is 48741 * producing. This function creates a new line of text for each call to 48742 * the function. Individual elements can be 48743 * separated with quotes ("") and joined with the addition operator (+). 48744 * 48745 * Note that calling print() without any arguments invokes the window.print() 48746 * function which opens the browser's print dialog. To print a blank line 48747 * to console you can write print('\n'). 48748 * 48749 * @method print 48750 * @param {Any} contents any combination of Number, String, Object, Boolean, 48751 * Array to print 48752 * @example 48753 * <div><code class='norender'> 48754 * let x = 10; 48755 * print('The value of x is ' + x); 48756 * // prints "The value of x is 10" 48757 * </code></div> 48758 * @alt 48759 * default grey canvas 48760 */ 48761 48762 p5.prototype.print = function () { 48763 if (!arguments.length) { 48764 _windowPrint(); 48765 } else { 48766 console.log.apply(console, arguments); 48767 } 48768 }; 48769 /** 48770 * The system variable <a href="#/p5/frameCount">frameCount</a> contains the number of frames that have 48771 * been displayed since the program started. Inside <a href="#/p5/setup">setup()</a> the value is 0, 48772 * after the first iteration of draw it is 1, etc. 48773 * 48774 * @property {Integer} frameCount 48775 * @readOnly 48776 * @example 48777 * <div><code> 48778 * function setup() { 48779 * frameRate(30); 48780 * textSize(30); 48781 * textAlign(CENTER); 48782 * } 48783 * 48784 * function draw() { 48785 * background(200); 48786 * text(frameCount, width / 2, height / 2); 48787 * } 48788 </code></div> 48789 * 48790 * @alt 48791 * numbers rapidly counting upward with frame count set to 30. 48792 * 48793 */ 48794 48795 48796 p5.prototype.frameCount = 0; 48797 /** 48798 * Confirms if the window a p5.js program is in is "focused," meaning that 48799 * the sketch will accept mouse or keyboard input. This variable is 48800 * "true" if the window is focused and "false" if not. 48801 * 48802 * @property {Boolean}
48802 focused 48803 * @readOnly 48804 * @example 48805 * <div><code> 48806 * // To demonstrate, put two windows side by side. 48807 * // Click on the window that the p5 sketch isn't in! 48808 * function draw() { 48809 * background(200); 48810 * noStroke(); 48811 * fill(0, 200, 0); 48812 * ellipse(25, 25, 50, 50); 48813 * 48814 * if (!focused) { 48815 // or "if (focused === false)" 48816 * stroke(200, 0, 0); 48817 * line(0, 0, 100, 100); 48818 * line(100, 0, 0, 100); 48819 * } 48820 * } 48821 * </code></div> 48822 * 48823 * @alt 48824 * green 50x50 ellipse at top left. Red X covers canvas when page focus changes 48825 * 48826 */ 48827 48828 p5.prototype.focused = document.hasFocus(); 48829 /** 48830 * Sets the cursor to a predefined symbol or an image, or makes it visible 48831 * if already hidden. If you are trying to set an image as the cursor, the 48832 * recommended size is 16x16 or 32x32 pixels. The values for parameters x and y 48833 * must be less than the dimensions of the image. 48834 * 48835 * @method cursor 48836 * @param {String|Constant} type Built-In: either ARROW, CROSS, HAND, MOVE, TEXT and WAIT 48837 * Native CSS properties: 'grab', 'progress', 'cell' etc. 48838 * External: path for cursor's images 48839 * (Allowed File extensions: .cur, .gif, .jpg, .jpeg, .png) 48840 * For more information on Native CSS cursors and url visit: 48841 * https://developer.mozilla.org/en-US/docs/Web/CSS/cursor 48842 * @param {Number} [x] the horizontal active spot of the cursor (must be less than 32) 48843 * @param {Number} [y] the vertical active spot of the cursor (must be less than 32) 48844 * @example 48845 * <div><code> 48846 * // Move the mouse across the quadrants 48847 * // to see the cursor change 48848 * function draw() { 48849 * line(width / 2, 0, width / 2, height); 48850 * line(0, height / 2, width, height / 2); 48851 * if (mouseX < 50 && mouseY < 50) { 48852 * cursor(CROSS); 48853 * } else if (mouseX > 50 && mouseY < 50) { 48854 * cursor('progress'); 48855 * } else if (mouseX > 50 && mouseY > 50) { 48856 * cursor('https://s3.amazonaws.com/mupublicdata/cursor.cur'); 48857 * } else { 48858 * cursor('grab'); 48859 * } 48860 * } 48861 * </code></div> 48862 * 48863 * @alt 48864 * canvas is divided into four quadrants. cursor on first is a cross, second is a progress, 48865 * third is a custom cursor using path to the cursor and fourth is a grab. 48866 * 48867 */ 48868 48869 p5.prototype.cursor = function (type, x, y) { 48870 var cursor = 'auto'; 48871 var canvas = this._curElement.elt; 48872 48873 if (standardCursors.indexOf(type) > -1) { 48874 // Standard css cursor 48875 cursor = type; 48876 } else if (typeof type === 'string') { 48877 var coords = ''; 48878 48879 if (x && y && typeof x === 'number' && typeof y === 'number') { 48880 // Note that x and y values must be unit-less positive integers < 32 48881 // https://developer.mozilla.org/en-US/docs/Web/CSS/cursor 48882 coords = x + ' ' + y; 48883 } 48884 48885 if (type.substring(0, 7) === 'http://' || type.substring(0, 8) === 'https://') { 48886 // Image (absolute url) 48887 cursor = 'url(' + type + ') ' + coords + ', auto'; 48888 } else if (/\.(cur|jpg|jpeg|gif|png|CUR|JPG|JPEG|GIF|PNG)$/.test(type)) { 48889 // Image file (relative path) - Separated for performance reasons 48890 cursor = 'url(' + type + ') ' + coords + ', auto'; 48891 } else { 48892 // Any valid string for the css cursor property 48893 cursor = type; 48894 } 48895 } 48896 48897 canvas.style.cursor = cursor; 48898 }; 48899 /** 48900 * Specifies the number of frames to be displayed every second. For example, 48901 * the function call frameRate(30) will attempt to refresh 30 times a second. 48902 * If the processor is not fast enough to maintain the specified rate, the 48903 * frame rate will not be achieved. Setting the frame rate within <a href="#/p5/setup">setup()</a> is 48904 * recommended. The default frame rate is based on the frame rate of the display 48905 * (here also called "refresh rate"), which is set to 60 frames per second on most 48906 * computers. A frame rate of 24 frames per second (usual for movies) or above 48907 * will be enough for smooth animations 48908 * This is the same as setFrameRate(val). 48909 * <br><br> 48910 * Calling <a href="#/p5/frameRate">frameRate()</a> with no arguments returns the current framerate. The 48911 * draw function must run at least once before it will return a value. This 48912 * is the same as <a href="#/p5/getFrameRate">getFrameRate()</a>. 48913 * <br><br> 48914 * Calling <a href="#/p5/frameRate">frameRate()</a> with arguments that are not of the type numbers 48915 * or are non positive also returns current framerate. 48916 * 48917 * @method frameRate 48918 * @param {Number} fps number of frames to be displayed every second 48919 * @chainable 48920 * 48921 * @example 48922 * 48923 * <div><code> 48924 * let rectX = 0; 48925 * let fr = 30; //starting FPS 48926 * let clr; 48927 * 48928 * function setup() { 48929 * background(200); 48930 * frameRate(fr); // Attempt to refresh at starting FPS 48931 * clr = color(255, 0, 0); 48932 * } 48933 * 48934 * function draw() { 48935 * background(200); 48936 * rectX = rectX += 1; // Move Rectangle 48937 * 48938 * if (rectX >= width) { 48939 // If you go off screen. 48940 * if (fr === 30) { 48941 * clr = color(0, 0, 255); 48942 * fr = 10; 48943 * frameRate(fr); // make frameRate 10 FPS 48944 * } else { 48945 * clr = color(255, 0, 0); 48946 * fr = 30; 48947 * frameRate(fr); // make frameRate 30 FPS 48948 * } 48949 * rectX = 0; 48950 * } 48951 * fill(clr);
48952 * rect(rectX, 40, 20, 20); 48953 * } 48954 * </code></div> 48955 * 48956 * @alt 48957 * blue rect moves left to right, followed by red rect moving faster. Loops. 48958 * 48959 */ 48960 48961 /** 48962 * @method frameRate 48963 * @return {Number} current frameRate 48964 */ 48965 48966 48967 p5.prototype.frameRate = function (fps) { 48968 p5._validateParameters('frameRate', arguments); 48969 48970 if (typeof fps !== 'number' || fps < 0) { 48971 return this._frameRate; 48972 } else { 48973 this._setProperty('_targetFrameRate', fps); 48974 48975 return this; 48976 } 48977 }; 48978 /** 48979 * Returns the current framerate. 48980 * 48981 * @private 48982 * @return {Number} current frameRate 48983 */ 48984 48985 48986 p5.prototype.getFrameRate = function () { 48987 return this.frameRate(); 48988 }; 48989 /** 48990 * Specifies the number of frames to be displayed every second. For example, 48991 * the function call frameRate(30) will attempt to refresh 30 times a second. 48992 * If the processor is not fast enough to maintain the specified rate, the 48993 * frame rate will not be achieved. Setting the frame rate within <a href="#/p5/setup">setup()</a> is 48994 * recommended. The default rate is 60 frames per second. 48995 * 48996 * Calling <a href="#/p5/frameRate">frameRate()</a> with no arguments returns the current framerate. 48997 * 48998 * @private 48999 * @param {Number} [fps] number of frames to be displayed every second 49000 */ 49001 49002 49003 p5.prototype.setFrameRate = function (fps) { 49004 return this.frameRate(fps); 49005 }; 49006 /** 49007 * Hides the cursor from view. 49008 * 49009 * @method noCursor 49010 * @example 49011 * <div><code> 49012 * function setup() { 49013 * noCursor(); 49014 * } 49015 * 49016 * function draw() { 49017 * background(200); 49018 * ellipse(mouseX, mouseY, 10, 10); 49019 * } 49020 * </code></div> 49021 * 49022 * 49023 * @alt 49024 * cursor becomes 10x 10 white ellipse the moves with mouse x and y. 49025 * 49026 */ 49027 49028 49029 p5.prototype.noCursor = function () { 49030 this._curElement.elt.style.cursor = 'none'; 49031 }; 49032 /** 49033 * System variable that stores the width of the screen display according to The 49034 * default <a href="#/p5/pixelDensity">pixelDensity</a>. This is used to run a 49035 * full-screen program on any display size. To return actual screen size, 49036 * multiply this by pixelDensity. 49037 * 49038 * @property {Number} displayWidth 49039 * @readOnly 49040 * @example 49041 * <div class="norender"><code> 49042 * createCanvas(displayWidth, displayHeight); 49043 * </code></div> 49044 * 49045 * @alt 49046 * cursor becomes 10x 10 white ellipse the moves with mouse x and y. 49047 * 49048 */ 49049 49050 49051 p5.prototype.displayWidth = screen.width; 49052 /** 49053 * System variable that stores the height of the screen display according to The 49054 * default <a href="#/p5/pixelDensity">pixelDensity</a>. This is used to run a 49055 * full-screen program on any display size. To return actual screen size, 49056 * multiply this by pixelDensity. 49057 * 49058 * @property {Number} displayHeight 49059 * @readOnly 49060 * @example 49061 * <div class="norender"><code> 49062 * createCanvas(displayWidth, displayHeight); 49063 * </code></div> 49064 * 49065 * @alt 49066 * no display. 49067 * 49068 */ 49069 49070 p5.prototype.displayHeight = screen.height; 49071 /** 49072 * System variable that stores the width of the inner window, it maps to 49073 * window.innerWidth. 49074 * 49075 * @property {Number} windowWidth 49076 * @readOnly 49077 * @example 49078 * <div class="norender"><code> 49079 * createCanvas(windowWidth, windowHeight); 49080 * </code></div> 49081 * 49082 * @alt 49083 * no display. 49084 * 49085 */ 49086 49087 p5.prototype.windowWidth = getWindowWidth(); 49088 /** 49089 * System variable that stores the height of the inner window, it maps to 49090 * window.innerHeight. 49091 * 49092 * @property {Number} windowHeight 49093 * @readOnly 49094 * @example 49095 * <div class="norender"><code> 49096 * createCanvas(windowWidth, windowHeight); 49097 * </code></div> 49098 *@alt
49099 * no display. 49100 * 49101 */ 49102 49103 p5.prototype.windowHeight = getWindowHeight(); 49104 /** 49105 * The <a href="#/p5/windowResized">windowResized()</a> function is called once every time the browser window 49106 * is resized. This is a good place to resize the canvas or do any other 49107 * adjustments to accommodate the new window size. 49108 * 49109 * @method windowResized 49110 * @example 49111 * <div class="norender"><code> 49112 * function setup() { 49113 * createCanvas(windowWidth, windowHeight); 49114 * } 49115 * 49116 * function draw() { 49117 * background(0, 100, 200); 49118 * } 49119 * 49120 * function windowResized() { 49121 * resizeCanvas(windowWidth, windowHeight); 49122 * } 49123 * </code></div> 49124 * @alt 49125 * no display. 49126 */ 49127 49128 p5.prototype._onresize = function (e) { 49129 this._setProperty('windowWidth', getWindowWidth()); 49130 49131 this._setProperty('windowHeight', getWindowHeight()); 49132 49133 var context = this._isGlobal ? window : this; 49134 var executeDefault; 49135 49136 if (typeof context.windowResized === 'function') { 49137 executeDefault = context.windowResized(e); 49138 49139 if (executeDefault !== undefined && !executeDefault) { 49140 e.preventDefault(); 49141 } 49142 } 49143 }; 49144 49145 function getWindowWidth() { 49146 return window.innerWidth || document.documentElement && document.documentElement.clientWidth || document.body && document.body.clientWidth || 0; 49147 } 49148 49149 function getWindowHeight() { 49150 return window.innerHeight || document.documentElement && document.documentElement.clientHeight || document.body && document.body.clientHeight || 0; 49151 } 49152 /** 49153 * System variable that stores the width of the drawing canvas. This value 49154 * is set by the first parameter of the <a href="#/p5/createCanvas">createCanvas()</a> function. 49155 * For example, the function call createCanvas(320, 240) sets the width 49156 * variable to the value 320. The value of width defaults to 100 if 49157 * <a href="#/p5/createCanvas">createCanvas()</a> is not used in a program. 49158 * 49159 * @property {Number} width 49160 * @readOnly 49161 */ 49162 49163 49164 p5.prototype.width = 0; 49165 /** 49166 * System variable that stores the height of the drawing canvas. This value 49167 * is set by the second parameter of the <a href="#/p5/createCanvas">createCanvas()</a> function. For 49168 * example, the function call createCanvas(320, 240) sets the height 49169 * variable to the value 240. The value of height defaults to 100 if 49170 * <a href="#/p5/createCanvas">createCanvas()</a> is not used in a program. 49171 * 49172 * @property {Number} height 49173 * @readOnly 49174 */ 49175 49176 p5.prototype.height = 0; 49177 /** 49178 * If argument is given, sets the sketch to fullscreen or not based on the 49179 * value of the argument. If no argument is given, returns the current 49180 * fullscreen state. Note that due to browser restrictions this can only 49181 * be called on user input, for example, on mouse press like the example 49182 * below. 49183 * 49184 * @method fullscreen 49185 * @param {Boolean} [val] whether the sketch should be in fullscreen mode 49186 * or not 49187 * @return {Boolean} current fullscreen state 49188 * @example 49189 * <div> 49190 * <code> 49191 * // Clicking in the box toggles fullscreen on and off. 49192 * function setup() { 49193 * background(200); 49194 * } 49195 * function mousePressed() { 49196 * if (mouseX > 0 && mouseX < 100 && mouseY > 0 && mouseY < 100) { 49197 * let fs = fullscreen(); 49198 * fullscreen(!fs); 49199 * } 49200 * } 49201 * </code> 49202 * </div> 49203 * 49204 * @alt 49205 * no display. 49206 * 49207 */ 49208 49209 p5.prototype.fullscreen = function (val) { 49210 p5._validateParameters('fullscreen', arguments); // no arguments, return fullscreen or not 49211 49212 49213 if (typeof val === 'undefined') { 49214 return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement; 49215 } else { 49216 // otherwise set to fullscreen or not 49217 if (val) { 49218 launchFullscreen(document.documentElement); 49219 } else { 49220 exitFullscreen(); 49221 } 49222 } 49223 }; 49224 /** 49225 * Sets the pixel scaling for high pixel density displays. By default 49226 * pixel density is set to match display density, call pixelDensity(1) 49227 * to turn this off. Calling <a href="#/p5/pixelDensity">pixelDensity()</a> with no arguments returns 49228 * the current pixel density of the sketch. 49229 * 49230 * @method pixelDensity 49231 * @param {Number} val whether or how much the sketch should scale 49232 * @chainable 49233 * @example 49234 * <div> 49235 * <code> 49236 * function setup() { 49237 * pixelDensity(1); 49238 * createCanvas(100, 100); 49239 * background(200); 49240 * ellipse(width / 2, height / 2, 50, 50); 49241 * } 49242 * </code> 49243 * </div> 49244 * <div> 49245 * <code> 49246 * function setup() { 49247 * pixelDensity(3.0); 49248 * createCanvas(100, 100); 49249 * background(200); 49250 * ellipse(width / 2, height / 2, 50, 50); 49251 * } 49252 * </code> 49253 * </div> 49254 * 49255 * @alt 49256 * fuzzy 50x50 white ellipse with black outline in center of canvas. 49257 * sharp 50x50 white ellipse with black outline in center of canvas. 49258 */ 49259 49260 /** 49261 * @method pixelDensity 49262 * @returns {Number} current pixel density of the sketch 49263 */ 49264 49265 49266 p5.prototype.pixelDensity = function (val) { 49267 p5._validateParameters('pixelDensity', arguments); 49268 49269 var returnValue; 49270 49271 if (typeof val === 'number') { 49272 if (val !== this._pixelDensity) { 49273 this._pixelDensity = val; 49274 this._pixelsDirty = true; 49275 } 49276 49277 returnValue = this; 49278 this.resizeCanvas(this.width, this.height, true); // as a side effect, it will clear the canvas 49279 } else { 49280 returnValue = this._pixelDensity; 49281 } 49282 49283 return returnValue; 49284 }; 49285 /** 49286 * Returns the pixel density of the current display the sketch is running on. 49287 * 49288 * @method displayDensity 49289 * @returns {Number} current pixel density of the display 49290 * @example 49291 * <div> 49292 * <code> 49293 * function setup() { 49294 * let density = displayDensity(); 49295 * pixelDensity(density); 49296 * createCanvas(100, 100); 49297 * background(200); 49298 * ellipse(width / 2, height / 2, 50, 50); 49299 * } 49300 * </code> 49301 * </div> 49302 * 49303 * @alt 49304 * 50x50 white ellipse with black outline in center of canvas. 49305 */ 49306 49307 49308 p5.prototype.displayDensity = function () { 49309 return window.devicePixelRatio; 49310 }; 49311 49312 function launchFullscreen(element) { 49313 var enabled = document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled; 49314 49315 if (!enabled) { 49316 throw new Error('Fullscreen not enabled in this browser.'); 49317 } 49318 49319 if (element.requestFullscreen) { 49320 element.requestFullscreen(); 49321 } else if (element.mozRequestFullScreen) { 49322 element.mozRequestFullScreen(); 49323 } else if (element.webkitRequestFullscreen) { 49324 element.webkitRequestFullscreen(); 49325 } else if (element.msRequestFullscreen) { 49326 element.msRequestFullscreen(); 49327 } 49328 } 49329 49330 function exitFullscreen() { 49331 if (document.exitFullscreen) { 49332 document.exitFullscreen(); 49333 } else if (document.mozCancelFullScreen) { 49334 document.mozCancelFullScreen(); 49335 } else if (document.webkitExitFullscreen) { 49336 document.webkitExitFullscreen(); 49337 } else if (document.msExitFullscreen) { 49338 document.msExitFullscreen(); 49339 } 49340 } 49341 /** 49342 * Gets the current URL. 49343 * @method getURL 49344 * @return {String} url 49345 * @example 49346 * <div> 49347 * <code> 49348 * let url; 49349 * let x = 100; 49350 * 49351 * function setup() { 49352 * fill(0); 49353 * noStroke();
49354 * url = getURL(); 49355 * } 49356 * 49357 * function draw() { 49358 * background(200); 49359 * text(url, x, height / 2); 49360 * x--; 49361 * } 49362 * </code> 49363 * </div> 49364 * 49365 * @alt 49366 * current url (http://p5js.org/reference/#/p5/getURL) moves right to left. 49367 * 49368 */ 49369 49370 49371 p5.prototype.getURL = function () { 49372 return location.href; 49373 }; 49374 /** 49375 * Gets the current URL path as an array. 49376 * @method getURLPath 49377 * @return {String[]} path components 49378 * @example 49379 * <div class='norender'><code> 49380 * function setup() { 49381 * let urlPath = getURLPath(); 49382 * for (let i = 0; i < urlPath.length; i++) { 49383 * text(urlPath[i], 10, i * 20 + 20); 49384 * } 49385 * } 49386 * </code></div> 49387 * 49388 * @alt 49389 *no display 49390 * 49391 */ 49392 49393 49394 p5.prototype.getURLPath = function () { 49395 return location.pathname.split('/').filter(function (v) { 49396 return v !== ''; 49397 }); 49398 }; 49399 /** 49400 * Gets the current URL params as an Object. 49401 * @method getURLParams 49402 * @return {Object} URL params 49403 * @example 49404 * <div class='norender notest'> 49405 * <code> 49406 * // Example: http://p5js.org?year=2014&month=May&day=15 49407 * 49408 * function setup() { 49409 * let params = getURLParams(); 49410 * text(params.day, 10, 20); 49411 * text(params.month, 10, 40); 49412 * text(params.year, 10, 60); 49413 * } 49414 * </code> 49415 * </div> 49416 * @alt 49417 * no display. 49418 * 49419 */ 49420 49421 49422 p5.prototype.getURLParams = function () { 49423 var re = /[?&]([^&=]+)(?:[&=])([^&=]+)/gim; 49424 var m; 49425 var v = {}; 49426 49427 while ((m = re.exec(location.search)) != null) { 49428 if (m.index === re.lastIndex) { 49429 re.lastIndex++; 49430 } 49431 49432 v[m[1]] = m[2]; 49433 } 49434 49435 return v; 49436 }; 49437 49438 module.exports = p5; 49439 }, {
49440 "./constants": 18, 49441 "./main": 24 49442 }], 49443 20: [function (_dereq_, module, exports) { 49444 /** 49445 * @for p5 49446 * @requires core 49447 */ 49448 'use strict'; 49449 49450 var p5 = _dereq_('./main'); 49451 49452 var constants = _dereq_('./constants'); // p5.js blue, p5.js orange, auto dark green; fallback p5.js darkened magenta 49453 // See testColors below for all the color codes and names 49454 49455 49456 var typeColors = ['#2D7BB6', '#EE9900', '#4DB200', '#C83C00']; 49457 49458 if (typeof IS_MINIFIED !== 'undefined') { 49459 p5._validateParameters = p5._friendlyFileLoadError = p5._friendlyError = function () {}; 49460 } else { 49461 var doFriendlyWelcome = false; // TEMP until we get it all working LM 49462 // for parameter validation 49463 49464 var dataDoc = _dereq_('../../docs/reference/data.json'); 49465 49466 var arrDoc = JSON.parse(JSON.stringify(dataDoc)); // -- Borrowed from jQuery 1.11.3 -- 49467 49468 var class2type = {}; 49469 var toString = class2type.toString; 49470 var names = ['Boolean', 'Number', 'String', 'Function', 'Array', 'Date', 'RegExp', 'Object', 'Error']; 49471 49472 for (var n = 0; n < names.length; n++) { 49473 class2type['[object ' + names[n] + ']'] = names[n].toLowerCase(); 49474 } 49475 49476 var getType = function (obj) { 49477 if (obj == null) { 49478 return obj + ''; 49479 } 49480 49481 return typeof obj === 'object' || typeof obj === 'function' ? class2type[toString.call(obj)] || 'object' : typeof obj; 49482 }; // -- End borrow -- 49483 49484 49485 var friendlyWelcome = function () { 49486 // p5.js brand - magenta: #ED225D 49487 //var astrixBgColor = 'transparent'; 49488 //var astrixTxtColor = '#ED225D'; 49489 //var welcomeBgColor = '#ED225D'; 49490 //var welcomeTextColor = 'white'; 49491 console.log(' _ \n' + ' /\\| |/\\ \n' + " \\ ` ' / \n" + ' / , . \\ \n' + ' \\/|_|\\/ ' + '\n\n> p5.js says: Welcome! ' + 'This is your friendly debugger. ' + 'To turn me off switch to using âp5.min.jsâ.'); 49492 }; 49493 /** 49494 * Prints out a fancy, colorful message to the console log 49495 * 49496 * @method report 49497 * @private 49498 * @param {String} message the words to be said 49499 * @param {String} func the name of the function to link 49500 * @param {Number|String} color CSS color string or error type 49501 * 49502 * @return console logs 49503 */ 49504 49505 49506 var report = function (message, func, color) { 49507 if (doFriendlyWelcome) { 49508 friendlyWelcome(); 49509 doFriendlyWelcome = false; 49510 } 49511 49512 if ('undefined' === getType(color)) { 49513 color = '#B40033'; // dark magenta 49514 } else if (getType(color) === 'number') { 49515 // Type to color 49516 color = typeColors[color]; 49517 } 49518 49519 if (func === 'loadX') { 49520 console.log('> p5.js says: ' + message); 49521 } else if (func.substring(0, 4) === 'load') { 49522 console.log('> p5.js says: ' + message + '[https://github.com/processing/p5.js/wiki/Local-server]'); 49523 } else { 49524 console.log('> p5.js says: ' + message + ' [http://p5js.org/reference/#p5/' + func + ']'); 49525 } 49526 }; 49527 49528 var errorCases = { 49529 '0': { 49530 fileType: 'image', 49531 method: 'loadImage', 49532 message: ' hosting the image online,' 49533 }, 49534 '1': { 49535 fileType: 'XML file', 49536 method: 'loadXML' 49537 }, 49538 '2': { 49539 fileType: 'table file', 49540 method: 'loadTable' 49541 }, 49542 '3': { 49543 fileType: 'text file', 49544 method: 'loadStrings' 49545 }, 49546 '4': { 49547 fileType: 'font', 49548 method: 'loadFont', 49549 message: ' hosting the font online,' 49550 }, 49551 '5': { 49552 fileType: 'json', 49553 method: 'loadJSON' 49554 }, 49555 '6': { 49556 fileType: 'file', 49557 method: 'loadBytes' 49558 }, 49559 '7': { 49560 method: 'loadX', 49561 message: "In case your large file isn't fetched successfully," + 'we recommend splitting the file into smaller segments and fetching those.' 49562 } 49563 }; 49564 /**
49565 * This is called internally if there is a error during file loading. 49566 * 49567 * @method _friendlyFileLoadError 49568 * @private 49569 * @param {Number} errorType 49570 * @param {String} filePath 49571 */ 49572 49573 p5._friendlyFileLoadError = function (errorType, filePath) { 49574 var errorInfo = errorCases[errorType]; 49575 var message; 49576 49577 if (errorType === 7) { 49578 message = errorInfo.message; 49579 } else { 49580 message = 'It looks like there was a problem' + ' loading your ' + errorInfo.fileType + '.' + ' Try checking if the file path [' + filePath + '] is correct,' + (errorInfo.message || '') + ' or running a local server.'; 49581 } 49582 49583 report(message, errorInfo.method, 3); 49584 }; 49585 /** 49586 * This is a generic method that can be called from anywhere in the p5 49587 * library to alert users to a common error. 49588 * 49589 * @method _friendlyError 49590 * @private 49591 * @param {Number} message message to be printed 49592 * @param {String} method name of method 49593 */ 49594 49595 49596 p5._friendlyError = function (message, method) { 49597 report(message, method); 49598 }; 49599 49600 var docCache = {}; 49601 var builtinTypes = ['null', 'number', 'string', 'boolean', 'constant', 'function', 'any', 'integer']; // validateParameters() helper functions: 49602 // lookupParamDoc() for querying data.json 49603 49604 var lookupParamDoc = function (func) { 49605 // look for the docs in the `data.json` datastructure 49606 var ichDot = func.lastIndexOf('.'); 49607 var funcName = func.substr(ichDot + 1); 49608 var funcClass = func.substr(0, ichDot) || 'p5'; 49609 var queryResult; 49610 var classitems = arrDoc.classitems; 49611 49612 for (var ici = 0; ici < classitems.length; ici++) { 49613 var x = classitems[ici]; 49614 49615 if (x.name === funcName && x.class === funcClass) { 49616 queryResult = x; 49617 break; 49618 } 49619 } // different JSON structure for funct with multi-format 49620 49621 49622 var overloads = []; 49623 49624 if (queryResult.hasOwnProperty('overloads')) { 49625 // add all the overloads 49626 for (var i = 0; i < queryResult.overloads.length; i++) { 49627 overloads.push({ 49628 formats: queryResult.overloads[i].params 49629 }); 49630 } 49631 } else { 49632 // no overloads, just add the main method definition 49633 overloads.push({ 49634 formats: queryResult.params || [] 49635 }); 49636 } // parse the parameter types for each overload 49637 49638 49639 var mapConstants = {}; 49640 var maxParams = 0; 49641 overloads.forEach(function (overload) { 49642 var formats = overload.formats; // keep a record of the maximum number of arguments 49643 // this method requires. 49644 49645 if (maxParams < formats.length) { 49646 maxParams = formats.length; 49647 } // calculate the minimum number of arguments 49648 // this overload requires. 49649 49650 49651 var minParams = formats.length; 49652 49653 while (minParams > 0 && formats[minParams - 1].optional) { 49654 minParams--; 49655 } 49656 49657 overload.minParams = minParams; // loop through each parameter position, and parse its types 49658 49659 formats.forEach(function (format) { 49660 // split this parameter's types 49661 format.types = format.type.split('|').map(function ct(type) { 49662 // array 49663 if (type.substr(type.length - 2, 2) === '[]') { 49664 return { 49665 name: type, 49666 array: ct(type.substr(0, type.length - 2)) 49667 }; 49668 } 49669 49670 var lowerType = type.toLowerCase(); // contant 49671 49672 if (lowerType === 'constant') { 49673 var constant; 49674 49675 if (mapConstants.hasOwnProperty(format.name)) { 49676 constant = mapConstants[format.name]; 49677 } else { 49678 // parse possible constant values from description 49679 var myRe = /either\s+(?:[A-Z0-9_]+\s*,?\s*(?:or)?\s*)+/g; 49680 var values = {}; 49681 var names = []; 49682 constant = mapConstants[format.name] = { 49683 values: values, 49684 names: names 49685 }; 49686 var myArray = myRe.exec(format.description); 49687 49688 if (func === 'endShape' && format.name === 'mode') { 49689 values[constants.CLOSE] = true; 49690 names.push('CLOSE'); 49691 } else { 49692 var match = myArray[0]; 49693 var reConst = /[A-Z0-9_]+/g; 49694 var matchConst; 49695 49696 while ((matchConst = reConst.exec(match)) !== null) { 49697 var name = matchConst[0]; 49698 49699 if (constants.hasOwnProperty(name)) { 49700 values[constants[name]] = true; 49701 names.push(name); 49702 } 49703 } 49704 } 49705 } 49706 49707 return { 49708 name: type, 49709 builtin: lowerType, 49710 names: constant.names, 49711 values: constant.values 49712 }; 49713 } // function 49714 49715 49716 if (lowerType.substr(0, 'function'.length) === 'function') { 49717 lowerType = 'function'; 49718 } // builtin 49719 49720 49721 if (builtinTypes.indexOf(lowerType) >= 0) { 49722 return { 49723 name: type, 49724 builtin: lowerType 49725 }; 49726 } // find type's prototype 49727 49728 49729 var t = window; 49730 var typeParts = type.split('.'); // special-case 'p5' since it may be non-global 49731 49732 if (typeParts[0] === 'p5') { 49733 t = p5; 49734 typeParts.shift(); 49735 } 49736
49737 typeParts.forEach(function (p) { 49738 t = t && t[p]; 49739 }); 49740 49741 if (t) { 49742 return { 49743 name: type, 49744 prototype: t 49745 }; 49746 } 49747 49748 return { 49749 name: type, 49750 type: lowerType 49751 }; 49752 }); 49753 }); 49754 }); 49755 return { 49756 overloads: overloads, 49757 maxParams: maxParams 49758 }; 49759 }; 49760 49761 var isNumber = function (param) { 49762 switch (typeof param) { 49763 case 'number': 49764 return true; 49765 49766 case 'string': 49767 return !isNaN(param); 49768 49769 default: 49770 return false; 49771 } 49772 }; 49773 49774 var testParamType = function (param, type) { 49775 var isArray = param instanceof Array; 49776 var matches = true; 49777 49778 if (type.array && isArray) { 49779 for (var i = 0; i < param.length; i++) { 49780 var error = testParamType(param[i], type.array); 49781 if (error) return error / 2; // half error for elements 49782 } 49783 } else if (type.prototype) { 49784 matches = param instanceof type.prototype; 49785 } else if (type.builtin) { 49786 switch (type.builtin) { 49787 case 'number': 49788 matches = isNumber(param); 49789 break; 49790 49791 case 'integer': 49792 matches = isNumber(param) && Number(param) === Math.floor(param); 49793 break; 49794 49795 case 'boolean': 49796 case 'any': 49797 matches = true; 49798 break; 49799 49800 case 'array': 49801 matches = isArray; 49802 break; 49803 49804 case 'string': 49805 matches = 49806 /*typeof param === 'number' ||*/ 49807 typeof param === 'string'; 49808 break; 49809 49810 case 'constant': 49811 matches = type.values.hasOwnProperty(param); 49812 break; 49813 49814 case 'function': 49815 matches = param instanceof Function; 49816 break; 49817 49818 case 'null': 49819 matches = param === null; 49820 break; 49821 } 49822 } else { 49823 matches = typeof param === type.t; 49824 } 49825 49826 return matches ? 0 : 1; 49827 }; // testType() for non-object type parameter validation 49828 49829 49830 var testParamTypes = function (param, types) { 49831 var minScore = 9999; 49832 49833 for (var i = 0; minScore > 0 && i < types.length; i++) { 49834 var score = testParamType(param, types[i]); 49835 if (minScore > score) minScore = score; 49836 } 49837 49838 return minScore; 49839 }; // generate a score (higher is worse) for applying these args to 49840 // this overload. 49841 49842 49843 var scoreOverload = function (args, argCount, overload, minScore) { 49844 var score = 0; 49845 var formats = overload.formats; 49846 var minParams = overload.minParams; // check for too few/many args 49847 // the score is double number of extra/missing args 49848 49849 if (argCount < minParams) { 49850 score = (minParams - argCount) * 2; 49851 } else if (argCount > formats.length) { 49852 score = (argCount - formats.length) * 2; 49853 } // loop through the formats, adding up the error score for each arg. 49854 // quit early if the score gets higher than the previous best overload. 49855 49856 49857 for (var p = 0; score <= minScore && p < formats.length; p++) { 49858 var arg = args[p]; 49859 var format = formats[p]; // '== null' checks for 'null' and typeof 'undefined' 49860 49861 if (arg == null) {
49862 // handle non-optional and non-trailing undefined args 49863 if (!format.optional || p < minParams || p < argCount) { 49864 score += 1; 49865 } 49866 } else { 49867 score += testParamTypes(arg, format.types); 49868 } 49869 } 49870 49871 return score; 49872 }; // gets a list of errors for this overload 49873 49874 49875 var getOverloadErrors = function (args, argCount, overload) { 49876 var formats = overload.formats; 49877 var minParams = overload.minParams; // check for too few/many args 49878 49879 if (argCount < minParams) { 49880 return [{ 49881 type: 'TOO_FEW_ARGUMENTS', 49882 argCount: argCount, 49883 minParams: minParams 49884 }]; 49885 } else if (argCount > formats.length) { 49886 return [{ 49887 type: 'TOO_MANY_ARGUMENTS', 49888 argCount: argCount, 49889 maxParams: formats.length 49890 }]; 49891 } 49892 49893 var errorArray = []; 49894 49895 for (var p = 0; p < formats.length; p++) { 49896 var arg = args[p]; 49897 var format = formats[p]; // '== null' checks for 'null' and typeof 'undefined' 49898 49899 if (arg == null) {
49900 // handle non-optional and non-trailing undefined args 49901 if (!format.optional || p < minParams || p < argCount) { 49902 errorArray.push({ 49903 type: 'EMPTY_VAR', 49904 position: p, 49905 format: format 49906 }); 49907 } 49908 } else if (testParamTypes(arg, format.types) > 0) { 49909 errorArray.push({ 49910 type: 'WRONG_TYPE', 49911 position: p, 49912 format: format, 49913 arg: arg 49914 }); 49915 } 49916 } 49917 49918 return errorArray; 49919 }; // a custom error type, used by the mocha 49920 // tests when expecting validation errors 49921 49922 49923 p5.ValidationError = function (name) { 49924 var err = function (message, func) { 49925 this.message = message; 49926 this.func = func; 49927 if ('captureStackTrace' in Error) Error.captureStackTrace(this, err);else this.stack = new Error().stack; 49928 }; 49929 49930 err.prototype = Object.create(Error.prototype); 49931 err.prototype.name = name; 49932 err.prototype.constructor = err; 49933 return err; 49934 }('ValidationError'); // function for generating console.log() msg 49935 49936 49937 p5._friendlyParamError = function (errorObj, func) { 49938 var message; 49939 49940 function formatType() { 49941 var format = errorObj.format; 49942 return format.types.map(function (type) { 49943 return type.names ? type.names.join('|') : type.name; 49944 }).join('|'); 49945 } 49946 49947 switch (errorObj.type) { 49948 case 'EMPTY_VAR': 49949 message = func + '() was expecting ' + formatType() + ' for parameter #' + errorObj.position + ' (zero-based index), received an empty variable instead.' + ' If not intentional, this is often a problem with scope:' + ' [https://p5js.org/examples/data-variable-scope.html]'; 49950 break; 49951 49952 case 'WRONG_TYPE': 49953 var arg = errorObj.arg; 49954 var argType = arg instanceof Array ? 'array' : arg === null ? 'null' : arg.name || typeof arg; 49955 message = func + '() was expecting ' + formatType() + ' for parameter #' + errorObj.position + ' (zero-based index), received ' + argType + ' instead'; 49956 break; 49957 49958 case 'TOO_FEW_ARGUMENTS': 49959 message = func + '() was expecting at least ' + errorObj.minParams + ' arguments, but received only ' + errorObj.argCount; 49960 break; 49961 49962 case 'TOO_MANY_ARGUMENTS': 49963 message = func + '() was expecting no more than ' + errorObj.maxParams + ' arguments, but received ' + errorObj.argCount; 49964 break; 49965 } 49966 49967 if (message) { 49968 if (p5._throwValidationErrors) { 49969 throw new p5.ValidationError(message); 49970 } 49971 49972 try { 49973 var re = /Function\.validateParameters.*[\r\n].*[\r\n].*\(([^)]*)/; 49974 var location = re.exec(new Error().stack)[1]; 49975 49976 if (location) { 49977 message += ' at ' + location; 49978 } 49979 } catch (err) {} 49980 49981 report(message + '.', func, 3); 49982 } 49983 }; 49984 /** 49985 * Validates parameters 49986 * param {String} func the name of the function 49987 * param {Array} args user input arguments 49988 * 49989 * example: 49990 * var a; 49991 * ellipse(10,10,a,5); 49992 * console ouput: 49993 * "It looks like ellipse received an empty variable in spot #2." 49994 * 49995 * example: 49996 * ellipse(10,"foo",5,5); 49997 * console output: 49998 * "ellipse was expecting a number for parameter #1, 49999 * received "foo" instead." 50000 */ 50001 50002 50003 p5._validateParameters = function validateParameters(func, args) { 50004 if (p5.disableFriendlyErrors) { 50005 return; // skip FES 50006 } // lookup the docs in the 'data.json' file 50007 50008 50009 var docs = docCache[func] || (docCache[func] = lookupParamDoc(func)); 50010 var overloads = docs.overloads; // ignore any trailing `undefined` arguments 50011 50012 var argCount = args.length; // '== null' checks for 'null' and typeof 'undefined' 50013 50014 while (argCount > 0 && args[argCount - 1] == null) argCount--; // find the overload with the best score 50015 50016 50017 var minScore = 99999; 50018 var minOverload; 50019 50020 for (var i = 0; i < overloads.length; i++) { 50021 var score = scoreOverload(args, argCount, overloads[i], minScore); 50022 50023 if (score === 0) { 50024 return; // done! 50025 } else if (minScore > score) { 50026 // this score is better that what we have so far... 50027 minScore = score; 50028 minOverload = i; 50029 } 50030 } // this should _always_ be true here... 50031 50032 50033 if (minScore > 0) { 50034 // get the errors for the best overload 50035 var errorArray = getOverloadErrors(args, argCount, overloads[minOverload]); // generate err msg 50036 50037 for (var n = 0; n < errorArray.length; n++) { 50038 p5._friendlyParamError(errorArray[n], func); 50039 } 50040 } 50041 }; 50042 /** 50043 * Prints out all the colors in the color pallete with white text. 50044 * For color blindness testing. 50045 */ 50046 50047 /* function testColors() { 50048 var str = 'A box of biscuits, a box of mixed biscuits and a biscuit mixer'; 50049 report(str, 'print', '#ED225D'); // p5.js magenta 50050 report(str, 'print', '#2D7BB6'); // p5.js blue 50051 report(str, 'print', '#EE9900'); // p5.js orange 50052 report(str, 'print', '#A67F59'); // p5.js light brown 50053 report(str, 'print', '#704F21'); // p5.js gold 50054 report(str, 'print', '#1CC581'); // auto cyan 50055 report(str, 'print', '#FF6625'); // auto orange 50056 report(str, 'print', '#79EB22'); // auto green 50057 report(str, 'print', '#B40033'); // p5.js darkened magenta 50058 report(str, 'print', '#084B7F'); // p5.js darkened blue 50059 report(str, 'print', '#945F00'); // p5.js darkened orange 50060 report(str, 'print', '#6B441D'); // p5.js darkened brown 50061 report(str, 'print', '#2E1B00'); // p5.js darkened gold 50062 report(str, 'print', '#008851'); // auto dark cyan 50063 report(str, 'print', '#C83C00'); // auto dark orange 50064 report(str, 'print', '#4DB200'); // auto dark green 50065 } */ 50066 50067 50068 p5.prototype._validateParameters = p5.validateParameters; 50069 } // This is a lazily-defined list of p5 symbols that may be
50070 // misused by beginners at top-level code, outside of setup/draw. We'd like 50071 // to detect these errors and help the user by suggesting they move them 50072 // into setup/draw. 50073 // 50074 // For more details, see https://github.com/processing/p5.js/issues/1121. 50075 50076 50077 var misusedAtTopLevelCode = null; 50078 var FAQ_URL = 'https://github.com/processing/p5.js/wiki/p5.js-overview' + '#why-cant-i-assign-variables-using-p5-functions-and-' + 'variables-before-setup'; 50079 50080 var defineMisusedAtTopLevelCode = function () { 50081 var uniqueNamesFound = {}; 50082 50083 var getSymbols = function (obj) { 50084 return Object.getOwnPropertyNames(obj).filter(function (name) { 50085 if (name[0] === '_') { 50086 return false; 50087 } 50088 50089 if (name in uniqueNamesFound) { 50090 return false; 50091 } 50092 50093 uniqueNamesFound[name] = true; 50094 return true; 50095 }).map(function (name) { 50096 var type; 50097 50098 if (typeof obj[name] === 'function') { 50099 type = 'function'; 50100 } else if (name === name.toUpperCase()) { 50101 type = 'constant'; 50102 } else { 50103 type = 'variable'; 50104 } 50105 50106 return { 50107 name: name, 50108 type: type 50109 }; 50110 }); 50111 }; 50112 50113 misusedAtTopLevelCode = [].concat(getSymbols(p5.prototype), // At present, p5 only adds its constants to p5.prototype during 50114 // construction, which may not have happened at the time a 50115 // ReferenceError is thrown, so we'll manually add them to our list. 50116 getSymbols(_dereq_('./constants'))); // This will ultimately ensure that we report the most specific error 50117 // possible to the user, e.g. advising them about HALF_PI instead of PI 50118 // when their code misuses the former. 50119 50120 misusedAtTopLevelCode.sort(function (a, b) { 50121 return b.name.length - a.name.length; 50122 }); 50123 }; 50124 50125 var helpForMisusedAtTopLevelCode = function (e, log) { 50126 if (!log) { 50127 log = console.log.bind(console); 50128 } 50129 50130 if (!misusedAtTopLevelCode) { 50131 defineMisusedAtTopLevelCode(); 50132 } // If we find that we're logging lots of false positives, we can 50133 // uncomment the following code to avoid displaying anything if the 50134 // user's code isn't likely to be using p5's global mode. (Note that 50135 // setup/draw are more likely to be defined due to JS function hoisting.) 50136 // 50137 //if (!('setup' in window || 'draw' in window)) { 50138 // return; 50139 //} 50140 50141 50142 misusedAtTopLevelCode.some(function (symbol) { 50143 // Note that while just checking for the occurrence of the 50144 // symbol name in the error message could result in false positives, 50145 // a more rigorous test is difficult because different browsers 50146 // log different messages, and the format of those messages may 50147 // change over time. 50148 // 50149 // For example, if the user uses 'PI' in their code, it may result 50150 // in any one of the following messages: 50151 // 50152 // * 'PI' is undefined (Microsoft Edge) 50153 // * ReferenceError: PI is undefined (Firefox) 50154 // * Uncaught ReferenceError: PI is not defined (Chrome) 50155 if (e.message && e.message.match('\\W?' + symbol.name + '\\W') !== null) { 50156 log("Did you just try to use p5.js's " + symbol.name + (symbol.type === 'function' ? '() ' : ' ') + symbol.type + '? If so, you may want to ' + "move it into your sketch's setup() function.\n\n" + 'For more details, see: ' + FAQ_URL); 50157 return true; 50158 } 50159 }); 50160 }; // Exposing this primarily for unit testing. 50161 50162 50163 p5.prototype._helpForMisusedAtTopLevelCode = helpForMisusedAtTopLevelCode; 50164 50165 if (document.readyState !== 'complete') { 50166 window.addEventListener('error', helpForMisusedAtTopLevelCode, false); // Our job is only to catch ReferenceErrors that are thrown when 50167 // global (non-instance mode) p5 APIs are used at the top-level 50168 // scope of a file, so we'll unbind our error listener now to make 50169 // sure we don't log false positives later. 50170 50171 window.addEventListener('load', function () { 50172 window.removeEventListener('error', helpForMisusedAtTopLevelCode, false); 50173 }); 50174 } 50175 50176 module.exports = p5; 50177 }, {
50178 "../../docs/reference/data.json": 1, 50179 "./constants": 18, 50180 "./main": 24 50181 }], 50182 21: [function (_dereq_, module, exports) { 50183 /** 50184 * @requires constants 50185 */ 50186 'use strict'; 50187 50188 var constants = _dereq_('./constants'); 50189 50190 module.exports = { 50191 modeAdjust: function (a, b, c, d, mode) { 50192 if (mode === constants.CORNER) { 50193 return { 50194 x: a, 50195 y: b, 50196 w: c, 50197 h: d 50198 }; 50199 } else if (mode === constants.CORNERS) { 50200 return { 50201 x: a, 50202 y: b, 50203 w: c - a, 50204 h: d - b 50205 }; 50206 } else if (mode === constants.RADIUS) { 50207 return { 50208 x: a - c, 50209 y: b - d, 50210 w: 2 * c, 50211 h: 2 * d 50212 }; 50213 } else if (mode === constants.CENTER) { 50214 return { 50215 x: a - c * 0.5, 50216 y: b - d * 0.5, 50217 w: c, 50218 h: d 50219 }; 50220 } 50221 } 50222 }; 50223 }, { 50224 "./constants": 18 50225 }], 50226 22: [function (_dereq_, module, exports) { 50227 'use strict'; 50228 50229 var p5 = _dereq_('../core/main'); 50230 /** 50231 * _globalInit 50232 * 50233 * TODO: ??? 50234 * if sketch is on window 50235 * assume "global" mode 50236 * and instantiate p5 automatically 50237 * otherwise do nothing 50238 * 50239 * @private 50240 * @return {Undefined} 50241 */ 50242 50243 50244 var _globalInit = function () { 50245 if (!window.mocha) { 50246 // If there is a setup or draw function on the window 50247 // then instantiate p5 in "global" mode 50248 if ((window.setup && typeof window.setup === 'function' || window.draw && typeof window.draw === 'function') && !p5.instance) { 50249 new p5(); 50250 } 50251 } 50252 }; // TODO: ??? 50253 // if the page is ready, initialize p5 immediately 50254 50255 50256 if (document.readyState === 'complete') { 50257 _globalInit(); // if the page is still loading, add an event listener 50258 // and initialize p5 as soon as it finishes loading 50259 50260 } else { 50261 window.addEventListener('load', _globalInit, false); 50262 } 50263 }, { 50264 "../core/main": 24 50265 }], 50266 23: [function (_dereq_, module, exports) { 50267 /** 50268 * @for p5 50269 * @requires core 50270 * These are functions that are part of the Processing API but are not part of 50271 * the p5.js API. In some cases they have a new name, in others, they are 50272 * removed completely. Not all unsupported Processing functions are listed here 50273 * but we try to include ones that a user coming from Processing might likely 50274 * call. 50275 */ 50276 'use strict'; 50277 50278 var p5 = _dereq_('./main'); 50279 50280 p5.prototype.pushStyle = function () { 50281 throw new Error('pushStyle() not used, see push()'); 50282 }; 50283 50284 p5.prototype.popStyle = function () { 50285 throw new Error('popStyle() not used, see pop()'); 50286 }; 50287 50288 module.exports = p5; 50289 }, {
50290 "./main": 24 50291 }], 50292 24: [function (_dereq_, module, exports) { 50293 /** 50294 * @module Structure 50295 * @submodule Structure 50296 * @for p5 50297 * @requires constants 50298 */ 50299 'use strict'; 50300 50301 _dereq_('./shim'); // Core needs the PVariables object 50302 50303 50304 var constants = _dereq_('./constants'); 50305 /** 50306 * This is the p5 instance constructor. 50307 * 50308 * A p5 instance holds all the properties and methods related to 50309 * a p5 sketch. It expects an incoming sketch closure and it can also 50310 * take an optional node parameter for attaching the generated p5 canvas 50311 * to a node. The sketch closure takes the newly created p5 instance as 50312 * its sole argument and may optionally set <a href="#/p5/preload">preload()</a>, <a href="#/p5/setup">setup()</a>, and/or 50313 * <a href="#/p5/draw">draw()</a> properties on it for running a sketch. 50314 * 50315 * A p5 sketch can run in "global" or "instance" mode: 50316 * "global" - all properties and methods are attached to the window 50317 * "instance" - all properties and methods are bound to this p5 object 50318 * 50319 * @class p5 50320 * @constructor 50321 * @param {function} sketch a closure that can set optional <a href="#/p5/preload">preload()</a>, 50322 * <a href="#/p5/setup">setup()</a>, and/or <a href="#/p5/draw">draw()</a> properties on the 50323 * given p5 instance 50324 * @param {HTMLElement|Boolean} [node] element to attach canvas to, if a 50325 * boolean is passed in use it as sync 50326 * @param {Boolean} [sync] start synchronously (optional) 50327 * @return {p5} a p5 instance 50328 */ 50329 50330 50331 var p5 = function (sketch, node, sync) { 50332 if (typeof node === 'boolean' && typeof sync === 'undefined') { 50333 sync = node; 50334 node = undefined; 50335 } ////////////////////////////////////////////// 50336 // PUBLIC p5 PROPERTIES AND METHODS
50337 ////////////////////////////////////////////// 50338 50339 /** 50340 * Called directly before <a href="#/p5/setup">setup()</a>, the <a href="#/p5/preload">preload()</a> function is used to handle 50341 * asynchronous loading of external files in a blocking way. If a preload 50342 * function is defined, <a href="#/p5/setup">setup()</a> will wait until any load calls within have 50343 * finished. Nothing besides load calls (<a href="#/p5/loadImage">loadImage</a>, <a href="#/p5/loadJSON">loadJSON</a>, <a href="#/p5/loadFont">loadFont</a>, 50344 * <a href="#/p5/loadStrings">loadStrings</a>, etc.) should be inside the preload function. If asynchronous 50345 * loading is preferred, the load methods can instead be called in <a href="#/p5/setup">setup()</a> 50346 * or anywhere else with the use of a callback parameter. 50347 * <br><br> 50348 * By default the text "loading..." will be displayed. To make your own 50349 * loading page, include an HTML element with id "p5_loading" in your 50350 * page. More information <a href="http://bit.ly/2kQ6Nio">here</a>. 50351 * 50352 * @method preload 50353 * @example 50354 * <div><code> 50355 * let img; 50356 * let c; 50357 * function preload() { 50358 * // preload() runs once 50359 * img = loadImage('assets/laDefense.jpg'); 50360 * } 50361 * 50362 * function setup() { 50363 * // setup() waits until preload() is done 50364 * img.loadPixels(); 50365 * // get color of middle pixel 50366 * c = img.get(img.width / 2, img.height / 2); 50367 * } 50368 * 50369 * function draw() { 50370 * background(c); 50371 * image(img, 25, 25, 50, 50); 50372 * } 50373 * </code></div> 50374 * 50375 * @alt 50376 * nothing displayed 50377 * 50378 */ 50379 50380 /** 50381 * The <a href="#/p5/setup">setup()</a> function is called once when the program starts. It's used to 50382 * define initial environment properties such as screen size and background 50383 * color and to load media such as images and fonts as the program starts. 50384 * There can only be one <a href="#/p5/setup">setup()</a> function for each program and it shouldn't 50385 * be called again after its initial execution. 50386 * <br><br> 50387 * Note: Variables declared within <a href="#/p5/setup">setup()</a> are not accessible within other 50388 * functions, including <a href="#/p5/draw">draw()</a>. 50389 * 50390 * @method setup 50391 * @example 50392 * <div><code> 50393 * let a = 0; 50394 * 50395 * function setup() { 50396 * background(0); 50397 * noStroke(); 50398 * fill(102); 50399 * } 50400 * 50401 * function draw() { 50402 * rect(a++ % width, 10, 2, 80); 50403 * } 50404 * </code></div> 50405 * 50406 * @alt 50407 * nothing displayed 50408 * 50409 */ 50410 50411 /** 50412 * Called directly after <a href="#/p5/setup">setup()</a>, the <a href="#/p5/draw">draw()</a> function continuously executes 50413 * the lines of code contained inside its block until the program is stopped 50414 * or <a href="#/p5/noLoop">noLoop()</a> is called. Note if <a href="#/p5/noLoop">noLoop()</a> is called in <a href="#/p5/setup">setup()</a>, <a href="#/p5/draw">draw()</a> will 50415 * still be executed once before stopping. <a href="#/p5/draw">draw()</a> is called automatically and 50416 * should never be called explicitly. 50417 * <br><br> 50418 * It should always be controlled with <a href="#/p5/noLoop">noLoop()</a>, <a href="#/p5/redraw">redraw()</a> and <a href="#/p5/loop">loop()</a>. After 50419 * <a href="#/p5/noLoop">noLoop()</a> stops the code in <a href="#/p5/draw">draw()</a> from executing, <a href="#/p5/redraw">redraw()</a> causes the 50420 * code inside <a href="#/p5/draw">draw()</a> to execute once, and <a href="#/p5/loop">loop()</a> will cause the code 50421 * inside <a href="#/p5/draw">draw()</a> to resume executing continuously. 50422 * <br><br> 50423 * The number of times <a href="#/p5/draw">draw()</a> executes in each second may be controlled with 50424 * the <a href="#/p5/frameRate">frameRate()</a> function. 50425 * <br><br> 50426 * There can only be one <a href="#/p5/draw">draw()</a> function for each sketch, and <a href="#/p5/draw">draw()</a> must 50427 * exist if you want the code to run continuously, or to process events such 50428 * as <a href="#/p5/mousePressed">mousePressed()</a>. Sometimes, you might have an empty call to <a href="#/p5/draw">draw()</a> in 50429 * your program, as shown in the above example. 50430 * <br><br> 50431 * It is important to note that the drawing coordinate system will be reset 50432 * at the beginning of each <a href="#/p5/draw">draw()</a> call. If any transformations are performed 50433 * within <a href="#/p5/draw">draw()</a> (ex: scale, rotate, translate), their effects will be 50434 * undone at the beginning of <a href="#/p5/draw">draw()</a>, so transformations will not accumulate 50435 * over time. On the other hand, styling applied (ex: fill, stroke, etc) will 50436 * remain in effect. 50437 * 50438 * @method draw 50439 * @example 50440 * <div><code> 50441 * let yPos = 0; 50442 * function setup() { 50443 * // setup() runs once 50444 * frameRate(30); 50445 * } 50446 * function draw() { 50447 * // draw() loops forever, until stopped 50448 * background(204); 50449 * yPos = yPos - 1; 50450 * if (yPos < 0) { 50451 * yPos = height; 50452 * } 50453 * line(0, yPos, width, yPos); 50454 * } 50455 * </code></div> 50456 * 50457 * @alt 50458 * nothing displayed 50459 * 50460 */
50461 ////////////////////////////////////////////// 50462 // PRIVATE p5 PROPERTIES AND METHODS 50463 ////////////////////////////////////////////// 50464 50465 50466 this._setupDone = false; // for handling hidpi 50467 50468 this._pixelDensity = Math.ceil(window.devicePixelRatio) || 1; 50469 this._userNode = node; 50470 this._curElement = null; 50471 this._elements = []; 50472 this._requestAnimId = 0; 50473 this._preloadCount = 0; 50474 this._isGlobal = false; 50475 this._loop = true; 50476 50477 this._initializeInstanceVariables(); 50478 50479 this._defaultCanvasSize = { 50480 width: 100, 50481 height: 100 50482 }; 50483 this._events = { 50484 // keep track of user-events for unregistering later 50485 mousemove: null, 50486 mousedown: null, 50487 mouseup: null, 50488 dragend: null, 50489 dragover: null, 50490 click: null, 50491 dblclick: null, 50492 mouseover: null, 50493 mouseout: null, 50494 keydown: null, 50495 keyup: null, 50496 keypress: null, 50497 touchstart: null, 50498 touchmove: null, 50499 touchend: null, 50500 resize: null, 50501 blur: null 50502 }; 50503 this._events.wheel = null; 50504 this._loadingScreenId = 'p5_loading'; // Allows methods to be registered on an instance that 50505 // are instance-specific. 50506 50507 this._registeredMethods = {}; 50508 var methods = Object.getOwnPropertyNames(p5.prototype._registeredMethods); 50509 50510 for (var i = 0; i < methods.length; i++) { 50511 var prop = methods[i]; 50512 this._registeredMethods[prop] = p5.prototype._registeredMethods[prop].slice(); 50513 } 50514 50515 if (window.DeviceOrientationEvent) { 50516 this._events.deviceorientation = null; 50517 } 50518 50519 if (window.DeviceMotionEvent && !window._isNodeWebkit) { 50520 this._events.devicemotion = null; 50521 } 50522 50523 this._start = function () { 50524 // Find node if id given 50525 if (this._userNode) { 50526 if (typeof this._userNode === 'string') { 50527 this._userNode = document.getElementById(this._userNode); 50528 } 50529 } 50530 50531 var context = this._isGlobal ? window : this; 50532 var userPreload = context.preload; 50533 50534 if (userPreload) { 50535 // Setup loading screen 50536 // Set loading screen into dom if not present 50537 // Otherwise displays and removes user provided loading screen 50538 var loadingScreen = document.getElementById(this._loadingScreenId); 50539 50540 if (!loadingScreen) { 50541 loadingScreen = document.createElement('div'); 50542 loadingScreen.innerHTML = 'Loading...'; 50543 loadingScreen.style.position = 'absolute'; 50544 loadingScreen.id = this._loadingScreenId; 50545 var node = this._userNode || document.body; 50546 node.appendChild(loadingScreen); 50547 } 50548 50549 var methods = this._preloadMethods; 50550 50551 for (var method in methods) { 50552 // default to p5 if no object defined 50553 methods[method] = methods[method] || p5; 50554 var obj = methods[method]; //it's p5, check if it's global or instance 50555 50556 if (obj === p5.prototype || obj === p5) { 50557 if (this._isGlobal) { 50558 window[method] = this._wrapPreload(this, method); 50559 } 50560 50561 obj = this; 50562 } 50563 50564 this._registeredPreloadMethods[method] = obj[method]; 50565 obj[method] = this._wrapPreload(obj, method); 50566 } 50567 50568 userPreload(); 50569 50570 this._runIfPreloadsAreDone(); 50571 } else { 50572 this._setup(); 50573 50574 this._draw(); 50575 } 50576 }.bind(this); 50577 50578 this._runIfPreloadsAreDone = function () { 50579 var context = this._isGlobal ? window : this; 50580 50581 if (context._preloadCount === 0) { 50582 var loadingScreen = document.getElementById(context._loadingScreenId); 50583 50584 if (loadingScreen) { 50585 loadingScreen.parentNode.removeChild(loadingScreen); 50586 } 50587 50588 context._setup(); 50589 50590 context._draw(); 50591 } 50592 }; 50593 50594 this._decrementPreload = function () { 50595 var context = this._isGlobal ? window : this; 50596 50597 if (typeof context.preload === 'function') { 50598 context._setProperty('_preloadCount', context._preloadCount - 1); 50599 50600 context._runIfPreloadsAreDone(); 50601 } 50602 }; 50603 50604 this._wrapPreload = function (obj, fnName) { 50605 return function () { 50606 //increment counter 50607 this._incrementPreload(); //call original function 50608 50609 50610 return this._registeredPreloadMethods[fnName].apply(obj, arguments); 50611 }.bind(this); 50612 }; 50613 50614 this._incrementPreload = function () { 50615 var context = this._isGlobal ? window : this; 50616 50617 context._setProperty('_preloadCount', context._preloadCount + 1); 50618 }; 50619 50620 this._setup = function () { 50621 // Always create a default canvas. 50622 // Later on if the user calls createCanvas, this default one 50623 // will be replaced 50624 this.createCanvas(this._defaultCanvasSize.width, this._defaultCanvasSize.height, 'p2d'); // return preload functions to their normal vals if switched by preload 50625 50626 var context = this._isGlobal ? window : this; 50627 50628 if (typeof context.preload === 'function') { 50629 for (var f in this._preloadMethods) { 50630 context[f] = this._preloadMethods[f][f]; 50631 50632 if (context[f] && this) { 50633 context[f] = context[f].bind(this); 50634 } 50635 } 50636 } // Short-circuit on this, in case someone used the library in "global" 50637 // mode earlier 50638 50639 50640 if (typeof context.setup === 'function') { 50641 context.setup(); 50642 } // unhide any hidden canvases that were created 50643 50644
50645 var canvases = document.getElementsByTagName('canvas'); 50646 50647 for (var i = 0; i < canvases.length; i++) { 50648 var k = canvases[i]; 50649 50650 if (k.dataset.hidden === 'true') { 50651 k.style.visibility = ''; 50652 delete k.dataset.hidden; 50653 } 50654 } 50655 50656 this._setupDone = true; 50657 }.bind(this); 50658 50659 this._draw = function () { 50660 var now = window.performance.now(); 50661 var time_since_last = now - this._lastFrameTime; 50662 var target_time_between_frames = 1000 / this._targetFrameRate; // only draw if we really need to; don't overextend the browser. 50663 // draw if we're within 5ms of when our next frame should paint 50664 // (this will prevent us from giving up opportunities to draw 50665 // again when it's really about time for us to do so). fixes an 50666 // issue where the frameRate is too low if our refresh loop isn't 50667 // in sync with the browser. note that we have to draw once even 50668 // if looping is off, so we bypass the time delay if that 50669 // is the case. 50670 50671 var epsilon = 5; 50672 50673 if (!this._loop || time_since_last >= target_time_between_frames - epsilon) { 50674 //mandatory update values(matrixs and stack) 50675 this.redraw(); 50676 this._frameRate = 1000.0 / (now - this._lastFrameTime); 50677 this._lastFrameTime = now; // If the user is actually using mouse module, then update 50678 // coordinates, otherwise skip. We can test this by simply 50679 // checking if any of the mouse functions are available or not. 50680 // NOTE : This reflects only in complete build or modular build. 50681 50682 if (typeof this._updateMouseCoords !== 'undefined') { 50683 this._updateMouseCoords(); 50684 } 50685 } // get notified the next time the browser gives us 50686 // an opportunity to draw. 50687 50688 50689 if (this._loop) { 50690 this._requestAnimId = window.requestAnimationFrame(this._draw); 50691 } 50692 }.bind(this); 50693 50694 this._setProperty = function (prop, value) { 50695 this[prop] = value; 50696 50697 if (this._isGlobal) { 50698 window[prop] = value; 50699 } 50700 }.bind(this); 50701 /** 50702 * Removes the entire p5 sketch. This will remove the canvas and any 50703 * elements created by p5.js. It will also stop the draw loop and unbind 50704 * any properties or methods from the window global scope. It will 50705 * leave a variable p5 in case you wanted to create a new p5 sketch. 50706 * If you like, you can set p5 = null to erase it. While all functions and 50707 * variables and objects created by the p5 library will be removed, any 50708 * other global variables created by your code will remain. 50709 * 50710 * @method remove 50711 * @example 50712 * <div class='norender'><code> 50713 * function draw() { 50714 * ellipse(50, 50, 10, 10); 50715 * } 50716 * 50717 * function mousePressed() { 50718 * remove(); // remove whole sketch on mouse press 50719 * } 50720 * </code></div> 50721 * 50722 * @alt 50723 * nothing displayed 50724 * 50725 */ 50726 50727 50728 this.remove = function () { 50729 var loadingScreen = document.getElementById(this._loadingScreenId); 50730 50731 if (loadingScreen) { 50732 loadingScreen.parentNode.removeChild(loadingScreen); // Add 1 to preload counter to prevent the sketch ever executing setup() 50733 50734 this._incrementPreload(); 50735 } 50736 50737 if (this._curElement) { 50738 // stop draw 50739 this._loop = false; 50740 50741 if (this._requestAnimId) { 50742 window.cancelAnimationFrame(this._requestAnimId); 50743 } // unregister events sketch-wide 50744 50745 50746 for (var ev in this._events) { 50747 window.removeEventListener(ev, this._events[ev]); 50748 } // remove DOM elements created by p5, and listeners 50749 50750 50751 for (var i = 0; i < this._elements.length; i++) { 50752 var e = this._elements[i]; 50753 50754 if (e.elt.parentNode) { 50755 e.elt.parentNode.removeChild(e.elt); 50756 } 50757 50758 for (var elt_ev in e._events) { 50759 e.elt.removeEventListener(elt_ev, e._events[elt_ev]); 50760 } 50761 } // call any registered remove functions 50762 50763 50764 var self = this; 50765 50766 this._registeredMethods.remove.forEach(function (f) { 50767 if (typeof f !== 'undefined') { 50768 f.call(self); 50769 } 50770 }); 50771 } // remove window bound properties and methods 50772 50773 50774 if (this._isGlobal) { 50775 for (var p in p5.prototype) { 50776 try { 50777 delete window[p]; 50778 } catch (x) { 50779 window[p] = undefined; 50780 } 50781 } 50782 50783 for (var p2 in this) { 50784 if (this.hasOwnProperty(p2)) { 50785 try { 50786 delete window[p2]; 50787 } catch (x) { 50788 window[p2] = undefined; 50789 } 50790 } 50791 } 50792 50793 p5.instance = null; 50794 } 50795 }.bind(this); // call any registered init functions 50796 50797 50798 this._registeredMethods.init.forEach(function (f) { 50799 if (typeof f !== 'undefined') { 50800 f.call(this); 50801 } 50802 }, this); 50803 50804 var friendlyBindGlobal = this._createFriendlyGlobalFunctionBinder(); // If the user has created a global setup or draw function, 50805 // assume "global" mode and make everything global (i.e. on the window) 50806 50807 50808 if (!sketch) { 50809 this._isGlobal = true; 50810 p5.instance = this; // Loop through methods on the prototype and attach them to the window 50811 50812 for (var p in p5.prototype) { 50813 if (typeof p5.prototype[p] === 'function') { 50814 var ev = p.substring(2); 50815 50816 if (!this._events.hasOwnProperty(ev)) { 50817 if (Math.hasOwnProperty(p) && Math[p] === p5.prototype[p]) { 50818 // Multiple p5 methods are just native Math functions. These can be 50819 // called without any binding. 50820 friendlyBindGlobal(p, p5.prototype[p]); 50821 } else { 50822 friendlyBindGlobal(p, p5.prototype[p].bind(this)); 50823 } 50824 } 50825 } else { 50826 friendlyBindGlobal(p, p5.prototype[p]); 50827 } 50828 } // Attach its properties to the window 50829 50830 50831 for (var p2 in this) { 50832 if (this.hasOwnProperty(p2)) { 50833 friendlyBindGlobal(p2, this[p2]); 50834 } 50835 } 50836 } else { 50837 // Else, the user has passed in a sketch closure that may set
50838 // user-provided 'setup', 'draw', etc. properties on this instance of p5 50839 sketch(this); 50840 } // Bind events to window (not using container div bc key events don't work) 50841 50842 50843 for (var e in this._events) { 50844 var f = this['_on' + e]; 50845 50846 if (f) { 50847 var m = f.bind(this); 50848 window.addEventListener(e, m, { 50849 passive: false 50850 }); 50851 this._events[e] = m; 50852 } 50853 } 50854 50855 var focusHandler = function () { 50856 this._setProperty('focused', true); 50857 }.bind(this); 50858 50859 var blurHandler = function () { 50860 this._setProperty('focused', false); 50861 }.bind(this); 50862 50863 window.addEventListener('focus', focusHandler); 50864 window.addEventListener('blur', blurHandler); 50865 this.registerMethod('remove', function () { 50866 window.removeEventListener('focus', focusHandler); 50867 window.removeEventListener('blur', blurHandler); 50868 }); 50869 50870 if (sync) { 50871 this._start(); 50872 } else { 50873 if (document.readyState === 'complete') { 50874 this._start(); 50875 } else { 50876 window.addEventListener('load', this._start.bind(this), false); 50877 } 50878 } 50879 }; 50880 50881 p5.prototype._initializeInstanceVariables = function () { 50882 this._styles = []; 50883 this._bezierDetail = 20; 50884 this._curveDetail = 20; 50885 this._colorMode = constants.RGB; 50886 this._colorMaxes = { 50887 rgb: [255, 255, 255, 255], 50888 hsb: [360, 100, 100, 1], 50889 hsl: [360, 100, 100, 1] 50890 }; 50891 this._pixelsDirty = true; 50892 }; // This is a pointer to our global mode p5 instance, if we're in 50893 // global mode. 50894 50895 50896 p5.instance = null; // Allows for the friendly error system to be turned off when creating a sketch, 50897 // which can give a significant boost to performance when needed. 50898 50899 p5.disableFriendlyErrors = false; // attach constants to p5 prototype 50900 50901 for (var k in constants) { 50902 p5.prototype[k] = constants[k]; 50903 } // functions that cause preload to wait 50904 // more can be added by using registerPreloadMethod(func) 50905 50906 50907 p5.prototype._preloadMethods = { 50908 loadJSON: p5.prototype, 50909 loadImage: p5.prototype, 50910 loadStrings: p5.prototype, 50911 loadXML: p5.prototype, 50912 loadBytes: p5.prototype, 50913 loadTable: p5.prototype, 50914 loadFont: p5.prototype, 50915 loadModel: p5.prototype, 50916 loadShader: p5.prototype 50917 }; 50918 p5.prototype._registeredMethods = { 50919 init: [], 50920 pre: [], 50921 post: [], 50922 remove: [] 50923 }; 50924 p5.prototype._registeredPreloadMethods = {}; 50925 50926 p5.prototype.registerPreloadMethod = function (fnString, obj) { 50927 // obj = obj || p5.prototype; 50928 if (!p5.prototype._preloadMethods.hasOwnProperty(fnString)) { 50929 p5.prototype._preloadMethods[fnString] = obj; 50930 } 50931 }; 50932 50933 p5.prototype.registerMethod = function (name, m) { 50934 var target = this || p5.prototype; 50935 50936 if (!target._registeredMethods.hasOwnProperty(name)) { 50937 target._registeredMethods[name] = []; 50938 } 50939 50940 target._registeredMethods[name].push(m); 50941 }; // create a function which provides a standardized process for binding 50942 // globals; this is implemented as a factory primarily so that there's a 50943 // way to redefine what "global" means for the binding function so it 50944 // can be used in scenarios like unit testing where the window object 50945 // might not exist 50946 50947 50948 p5.prototype._createFriendlyGlobalFunctionBinder = function (options) { 50949 options = options || {}; 50950 var globalObject = options.globalObject || window; 50951 var log = options.log || console.log.bind(console); 50952 var propsToForciblyOverwrite = { 50953 // p5.print actually always overwrites an existing global function, 50954 // albeit one that is very unlikely to be used: 50955 // 50956 // https://developer.mozilla.org/en-US/docs/Web/API/Window/print 50957 print: true 50958 }; 50959 return function (prop, value) { 50960 if (!p5.disableFriendlyErrors && typeof IS_MINIFIED === 'undefined' && typeof value === 'function' && !(prop in p5.prototype._preloadMethods)) { 50961 try { 50962 // Because p5 has so many common function names, it's likely 50963 // that users may accidentally overwrite global p5 functions with 50964 // their own variables. Let's allow this but log a warning to 50965 // help users who may be doing this unintentionally. 50966 // 50967 // For more information, see: 50968 // 50969 // https://github.com/processing/p5.js/issues/1317 50970 if (prop in globalObject && !(prop in propsToForciblyOverwrite)) { 50971 throw new Error('global "' + prop + '" already exists'); 50972 } // It's possible that this might throw an error because there 50973 // are a lot of edge-cases in which `Object.defineProperty` might 50974 // not succeed; since this functionality is only intended to 50975 // help beginners anyways, we'll just catch such an exception 50976 // if it occurs, and fall back to legacy behavior. 50977 50978 50979 Object.defineProperty(globalObject, prop, { 50980 configurable: true, 50981 enumerable: true, 50982 get: function () { 50983 return value; 50984 }, 50985 set: function (newValue) { 50986 Object.defineProperty(globalObject, prop, { 50987 configurable: true, 50988 enumerable: true, 50989 value: newValue, 50990 writable: true 50991 }); 50992 log('You just changed the value of "' + prop + '", which was ' + "a p5 function. This could cause problems later if you're " + 'not careful.'); 50993 } 50994 }); 50995 } catch (e) { 50996 log('p5 had problems creating the global function "' + prop + '", ' + 'possibly because your co
50996de is already using that name as ' + 'a variable. You may want to rename your variable to something ' + 'else.'); 50997 globalObject[prop] = value; 50998 } 50999 } else { 51000 globalObject[prop] = value; 51001 } 51002 }; 51003 }; 51004 51005 module.exports = p5; 51006 }, { 51007 "./constants": 18, 51008 "./shim": 34 51009 }], 51010 25: [function (_dereq_, module, exports) { 51011 /** 51012 * @module DOM 51013 * @submodule DOM 51014 * @for p5.Element 51015 */ 51016 'use strict'; 51017 51018 var p5 = _dereq_('./main'); 51019 /** 51020 * Base class for all elements added to a sketch, including canvas, 51021 * graphics buffers, and other HTML elements. Methods in blue are 51022 * included in the core functionality, methods in brown are added 51023 * with the <a href="http://p5js.org/reference/#/libraries/p5.dom">p5.dom 51024 * library</a>. 51025 * It is not called directly, but <a href="#/p5.Element">p5.Element</a> 51026 * objects are created by calling <a href="#/p5/createCanvas">createCanvas</a>, <a href="#/p5/createGraphics">createGraphics</a>, 51027 * or in the p5.dom library, <a href="#/p5/createDiv">createDiv</a>, <a href="#/p5/createImg">createImg</a>, <a href="#/p5/createInput">createInput</a>, etc. 51028 * 51029 * @class p5.Element 51030 * @param {String} elt DOM node that is wrapped 51031 * @param {p5} [pInst] pointer to p5 instance 51032 */ 51033 51034 51035 p5.Element = function (elt, pInst) { 51036 /** 51037 * Underlying HTML element. All normal HTML methods can be called on this. 51038 * @example 51039 * <div> 51040 * <code> 51041 * function setup() { 51042 * var c = createCanvas(50, 50); 51043 * c.elt.style.border = '5px solid red'; 51044 * } 51045 * 51046 * function draw() { 51047 * background(220); 51048 * } 51049 * </code> 51050 * </div> 51051 * 51052 * @property elt 51053 * @readOnly 51054 */ 51055 this.elt = elt; 51056 this._pInst = pInst; 51057 this._events = {}; 51058 this.width = this.elt.offsetWidth; 51059 this.height = this.elt.offsetHeight; 51060 }; 51061 /** 51062 * 51063 * Attaches the element to the parent specified. A way of setting 51064 * the container for the element. Accepts either a string ID, DOM 51065 * node, or <a href="#/p5.Element">p5.Element</a>. If no arguments given, parent node is returned. 51066 * For more ways to position the canvas, see the 51067 * <a href='https://github.com/processing/p5.js/wiki/Positioning-your-canvas'> 51068 * positioning the canvas</a> wiki page. 51069 * 51070 * All above examples except for the first one require the inclusion of 51071 * the p5.dom library in your index.html. See the 51072 * <a href='http://p5js.org/libraries/#using-a-library'>using a library</a> 51073 * section for information on how to include this library. 51074 * 51075 * @method parent 51076 * @param {String|p5.Element|Object} parent the ID, DOM node, or <a href="#/p5.Element">p5.Element</a> 51077 * of desired parent element 51078 * @chainable 51079 * 51080 * @example 51081 * <div class="norender notest"><code> 51082 * // in the html file: 51083 * // <div id="myContainer"></div> 51084 * 51085 * // in the js file: 51086 * var cnv = createCanvas(100, 100); 51087 * cnv.parent('myContainer'); 51088 * </code></div> 51089 * <div class='norender'><code> 51090 * var div0 = createDiv('this is the parent'); 51091 * var div1 = createDiv('this is the child'); 51092 * div1.parent(div0); // use p5.Element 51093 * </code></div> 51094 * <div class='norender'><code> 51095 * var div0 = createDiv('this is the parent'); 51096 * div0.id('apples'); 51097 * var div1 = createDiv('this is the child'); 51098 * div1.parent('apples'); // use id 51099 * </code></div> 51100 * <div class='norender notest'><code> 51101 * var elt = document.getElementById('myParentDiv'); 51102 * var div1 = createDiv('this is the child'); 51103 * div1.parent(elt); // use element from page 51104 * </code></div> 51105 * 51106 * @alt 51107 * no display. 51108 */ 51109 51110 /** 51111 * @method parent 51112 * @return {p5.Element} 51113 * 51114 */ 51115 51116 51117 p5.Element.prototype.parent = function (p) { 51118 if (typeof p === 'undefined') { 51119 return this.elt.parentNode; 51120 } 51121 51122 if (typeof p === 'string') { 51123 if (p[0] === '#') { 51124 p = p.substring(1); 51125 } 51126 51127 p = document.getElementById(p); 51128 } else if (p instanceof p5.Element) { 51129 p = p.elt; 51130 } 51131 51132 p.appendChild(this.elt); 51133 return this; 51134 }; 51135 /** 51136 * 51137 * Sets the ID of the element. If no ID argument is passed in, it instead 51138 * returns the current ID of the element. 51139 * 51140 * @method id 51141 * @param {String} id ID of the element 51142 * @chainable 51143 * 51144 * @example 51145 * <div class='norender'><code> 51146 * function setup() { 51147 * var cnv = createCanvas(100, 100); 51148 * // Assigns a CSS selector ID to 51149 * // the canvas element. 51150 * cnv.id('mycanvas'); 51151 * } 51152 * </code></div> 51153 * 51154 * @alt
51155 * no display. 51156 */ 51157 51158 /** 51159 * @method id 51160 * @return {String} the id of the element 51161 */ 51162 51163 51164 p5.Element.prototype.id = function (id) { 51165 if (typeof id === 'undefined') { 51166 return this.elt.id; 51167 } 51168 51169 this.elt.id = id; 51170 this.width = this.elt.offsetWidth; 51171 this.height = this.elt.offsetHeight; 51172 return this; 51173 }; 51174 /** 51175 * 51176 * Adds given class to the element. If no class argument is passed in, it 51177 * instead returns a string containing the current class(es) of the element. 51178 * 51179 * @method class 51180 * @param {String} class class to add 51181 * @chainable 51182 * 51183 * @example 51184 * <div class='norender'><code> 51185 * function setup() { 51186 * var cnv = createCanvas(100, 100); 51187 * // Assigns a CSS selector class 'small' 51188 * // to the canvas element. 51189 * cnv.class('small'); 51190 * } 51191 * </code></div> 51192 * 51193 * @alt 51194 * no display. 51195 */ 51196 51197 /** 51198 * @method class 51199 * @return {String} the class of the element 51200 */ 51201 51202 51203 p5.Element.prototype.class = function (c) { 51204 if (typeof c === 'undefined') { 51205 return this.elt.className; 51206 } 51207 51208 this.elt.className = c; 51209 return this; 51210 }; 51211 /** 51212 * The .<a href="#/p5.Element/mousePressed">mousePressed()</a> function is called once after every time a 51213 * mouse button is pressed over the element. 51214 * Some mobile browsers may also trigger this event on a touch screen, 51215 * if the user performs a quick tap. 51216 * This can be used to attach element specific event listeners. 51217 * 51218 * @method mousePressed 51219 * @param {Function|Boolean} fxn function to be fired when mouse is 51220 * pressed over the element. 51221 * if `false` is passed instead, the previously 51222 * firing function will no longer fire. 51223 * @chainable 51224 * @example 51225 * <div class='norender'><code> 51226 * var cnv; 51227 * var d; 51228 * var g; 51229 * function setup() { 51230 * cnv = createCanvas(100, 100); 51231 * cnv.mousePressed(changeGray); // attach listener for 51232 * // canvas click only 51233 * d = 10; 51234 * g = 100; 51235 * } 51236 * 51237 * function draw() { 51238 * background(g); 51239 * ellipse(width / 2, height / 2, d, d); 51240 * } 51241 * 51242 * // this function fires with any click anywhere 51243 * function mousePressed() { 51244 * d = d + 10; 51245 * } 51246 * 51247 * // this function fires only when cnv is clicked 51248 * function changeGray() { 51249 * g = random(0, 255); 51250 * } 51251 * </code></div> 51252 * 51253 * @alt 51254 * no display. 51255 * 51256 */ 51257 51258 51259 p5.Element.prototype.mousePressed = function (fxn) { 51260 // Prepend the mouse property setters to the event-listener. 51261 // This is required so that mouseButton is set correctly prior to calling the callback (fxn). 51262 // For details, see https://github.com/processing/p5.js/issues/3087. 51263 var eventPrependedFxn = function (event) { 51264 this._pInst._setProperty('mouseIsPressed', true); 51265 51266 this._pInst._setMouseButton(event); // Pass along the return-value of the callback: 51267 51268 51269 return fxn.call(this); 51270 }; // Pass along the event-prepended form of the callback. 51271 51272 51273 p5.Element._adjustListener('mousedown', eventPrependedFxn, this); 51274 51275 return this; 51276 }; 51277 /** 51278 * The .<a href="#/p5.Element/doubleClicked">doubleClicked()</a> function is called once after every time a 51279 * mouse button is pressed twice over the element. This can be used to 51280 * attach element and action specific event listeners. 51281 * 51282 * @method doubleClicked 51283 * @param {Function|Boolean} fxn function to be fired when mouse is 51284 * double clicked over the element. 51285 * if `false` is passed instead, the previously 51286 * firing function will no longer fire. 51287 * @return {p5.Element} 51288 * @example 51289 * <div class='norender'><code> 51290 * var cnv; 51291 * var d; 51292 * var g; 51293 * function setup() { 51294 * cnv = createCanvas(100, 100); 51295 * cnv.doubleClicked(changeGray); // attach listener for 51296 * // canvas double click only 51297 * d = 10; 51298 * g = 100; 51299 * } 51300 * 51301 * function draw() { 51302 * background(g); 51303 * ellipse(width / 2, height / 2, d, d); 51304 * } 51305 *
51306 * // this function fires with any double click anywhere 51307 * function doubleClicked() { 51308 * d = d + 10; 51309 * } 51310 * 51311 * // this function fires only when cnv is double clicked 51312 * function changeGray() { 51313 * g = random(0, 255); 51314 * } 51315 * </code></div> 51316 * 51317 * @alt 51318 * no display. 51319 * 51320 */ 51321 51322 51323 p5.Element.prototype.doubleClicked = function (fxn) { 51324 p5.Element._adjustListener('dblclick', fxn, this); 51325 51326 return this; 51327 }; 51328 /** 51329 * The .<a href="#/p5.Element/mouseWheel">mouseWheel()</a> function is called once after every time a 51330 * mouse wheel is scrolled over the element. This can be used to 51331 * attach element specific event listeners. 51332 * <br><br> 51333 * The function accepts a callback function as argument which will be executed 51334 * when the `wheel` event is triggered on the element, the callback function is 51335 * passed one argument `event`. The `event.deltaY` property returns negative 51336 * values if the mouse wheel is rotated up or away from the user and positive 51337 * in the other direction. The `event.deltaX` does the same as `event.deltaY` 51338 * except it reads the horizontal wheel scroll of the mouse wheel. 51339 * <br><br> 51340 * On OS X with "natural" scrolling enabled, the `event.deltaY` values are 51341 * reversed. 51342 * 51343 * @method mouseWheel 51344 * @param {Function|Boolean} fxn function to be fired when mouse is 51345 * scrolled over the element. 51346 * if `false` is passed instead, the previously 51347 * firing function will no longer fire. 51348 * @chainable 51349 * @example 51350 * <div class='norender'><code> 51351 * var cnv; 51352 * var d; 51353 * var g; 51354 * function setup() { 51355 * cnv = createCanvas(100, 100); 51356 * cnv.mouseWheel(changeSize); // attach listener for 51357 * // activity on canvas only 51358 * d = 10; 51359 * g = 100; 51360 * } 51361 * 51362 * function draw() { 51363 * background(g); 51364 * ellipse(width / 2, height / 2, d, d); 51365 * } 51366 * 51367 * // this function fires with mousewheel movement 51368 * // anywhere on screen 51369 * function mouseWheel() { 51370 * g = g + 10; 51371 * } 51372 * 51373 * // this function fires with mousewheel movement 51374 * // over canvas only 51375 * function changeSize(event) { 51376 * if (event.deltaY > 0) { 51377 * d = d + 10; 51378 * } else { 51379 * d = d - 10; 51380 * } 51381 * } 51382 * </code></div> 51383 * 51384 * 51385 * @alt 51386 * no display. 51387 * 51388 */ 51389 51390 51391 p5.Element.prototype.mouseWheel = function (fxn) { 51392 p5.Element._adjustListener('wheel', fxn, this); 51393 51394 return this; 51395 }; 51396 /** 51397 * The .<a href="#/p5.Element/mouseReleased">mouseReleased()</a> function is called once after every time a 51398 * mouse button is released over the element. 51399 * Some mobile browsers may also trigger this event on a touch screen, 51400 * if the user performs a quick tap. 51401 * This can be used to attach element specific event listeners. 51402 * 51403 * @method mouseReleased 51404 * @param {Function|Boolean} fxn function to be fired when mouse is 51405 * released over the element. 51406 * if `false` is passed instead, the previously 51407 * firing function will no longer fire. 51408 * @chainable 51409 * @example 51410 * <div class='norender'><code> 51411 * var cnv; 51412 * var d; 51413 * var g; 51414 * function setup() { 51415 * cnv = createCanvas(100, 100); 51416 * cnv.mouseReleased(changeGray); // attach listener for 51417 * // activity on canvas only 51418 * d = 10; 51419 * g = 100; 51420 * } 51421 * 51422 * function draw() { 51423 * background(g); 51424 * ellipse(width / 2, height / 2, d, d); 51425 * } 51426 * 51427 * // this function fires after the mouse has been 51428 * // released 51429 * function mouseReleased() { 51430 * d = d + 10; 51431 * } 51432 * 51433 * // this function fires after the mouse has been 51434 * // released while on canvas 51435 * function changeGray() { 51436 * g = random(0, 255); 51437 * } 51438 * </code></div> 51439 * 51440 * 51441 * @alt
51442 * no display. 51443 * 51444 */ 51445 51446 51447 p5.Element.prototype.mouseReleased = function (fxn) { 51448 p5.Element._adjustListener('mouseup', fxn, this); 51449 51450 return this; 51451 }; 51452 /** 51453 * The .<a href="#/p5.Element/mouseClicked">mouseClicked()</a> function is called once after a mouse button is 51454 * pressed and released over the element. 51455 * Some mobile browsers may also trigger this event on a touch screen, 51456 * if the user performs a quick tap. 51457 * This can be used to attach element specific event listeners. 51458 * 51459 * @method mouseClicked 51460 * @param {Function|Boolean} fxn function to be fired when mouse is 51461 * clicked over the element. 51462 * if `false` is passed instead, the previously 51463 * firing function will no longer fire. 51464 * @chainable 51465 * @example 51466 * <div class="norender"> 51467 * <code> 51468 * var cnv; 51469 * var d; 51470 * var g; 51471 * 51472 * function setup() { 51473 * cnv = createCanvas(100, 100); 51474 * cnv.mouseClicked(changeGray); // attach listener for 51475 * // activity on canvas only 51476 * d = 10; 51477 * g = 100; 51478 * } 51479 * 51480 * function draw() { 51481 * background(g); 51482 * ellipse(width / 2, height / 2, d, d); 51483 * } 51484 * 51485 * // this function fires after the mouse has been 51486 * // clicked anywhere 51487 * function mouseClicked() { 51488 * d = d + 10; 51489 * } 51490 * 51491 * // this function fires after the mouse has been 51492 * // clicked on canvas 51493 * function changeGray() { 51494 * g = random(0, 255); 51495 * } 51496 * </code> 51497 * </div> 51498 * 51499 * @alt 51500 * no display. 51501 * 51502 */ 51503 51504 51505 p5.Element.prototype.mouseClicked = function (fxn) { 51506 p5.Element._adjustListener('click', fxn, this); 51507 51508 return this; 51509 }; 51510 /** 51511 * The .<a href="#/p5.Element/mouseMoved">mouseMoved()</a> function is called once every time a 51512 * mouse moves over the element. This can be used to attach an 51513 * element specific event listener. 51514 * 51515 * @method mouseMoved 51516 * @param {Function|Boolean} fxn function to be fired when a mouse moves 51517 * over the element. 51518 * if `false` is passed instead, the previously 51519 * firing function will no longer fire. 51520 * @chainable 51521 * @example 51522 * <div class='norender'><code> 51523 * var cnv; 51524 * var d = 30; 51525 * var g; 51526 * function setup() { 51527 * cnv = createCanvas(100, 100); 51528 * cnv.mouseMoved(changeSize); // attach listener for 51529 * // activity on canvas only 51530 * d = 10; 51531 * g = 100; 51532 * } 51533 * 51534 * function draw() { 51535 * background(g); 51536 * fill(200); 51537 * ellipse(width / 2, height / 2, d, d); 51538 * } 51539 * 51540 * // this function fires when mouse moves anywhere on 51541 * // page 51542 * function mouseMoved() { 51543 * g = g + 5; 51544 * if (g > 255) { 51545 * g = 0; 51546 * } 51547 * } 51548 * 51549 * // this function fires when mouse moves over canvas 51550 * function changeSize() { 51551 * d = d + 2; 51552 * if (d > 100) { 51553 * d = 0; 51554 * } 51555 * } 51556 * </code></div> 51557 * 51558 * 51559 * @alt 51560 * no display. 51561 * 51562 */ 51563 51564 51565 p5.Element.prototype.mouseMoved = function (fxn) { 51566 p5.Element._adjustListener('mousemove', fxn, this); 51567 51568 return this; 51569 }; 51570 /** 51571 * The .<a href="#/p5.Element/mouseOver">mouseOver()</a> function is called once after every time a 51572 * mouse moves onto the element. This can be used to attach an 51573 * element specific event listener. 51574 * 51575 * @method mouseOver 51576 * @param {Function|Boolean} fxn function to be fired when a mouse moves 51577 * onto the element. 51578 * if `false` is passed instead, the previously 51579 * firing function will no longer fire. 51580 * @chainable 51581 * @example 51582 * <div class='norender'><code> 51583 * var cnv; 51584 * var d; 51585 * function setup() { 51586 * cnv = createCanvas(100, 100); 51587 * cnv.mouseOver(changeGray); 51588 * d = 10; 51589 * } 51590 * 51591 * function draw() { 51592 * ellipse(width / 2, height / 2, d, d); 51593 * } 51594 * 51595 * function changeGray() { 51596 * d = d + 10; 51597 * if (d > 100) { 51598 * d = 0; 51599 * } 51600 * } 51601 * </code></div> 51602 * 51603 * 51604 * @alt
51605 * no display. 51606 * 51607 */ 51608 51609 51610 p5.Element.prototype.mouseOver = function (fxn) { 51611 p5.Element._adjustListener('mouseover', fxn, this); 51612 51613 return this; 51614 }; 51615 /** 51616 * The .<a href="#/p5.Element/mouseOut">mouseOut()</a> function is called once after every time a 51617 * mouse moves off the element. This can be used to attach an 51618 * element specific event listener. 51619 * 51620 * @method mouseOut 51621 * @param {Function|Boolean} fxn function to be fired when a mouse 51622 * moves off of an element. 51623 * if `false` is passed instead, the previously 51624 * firing function will no longer fire. 51625 * @chainable 51626 * @example 51627 * <div class='norender'><code> 51628 * var cnv; 51629 * var d; 51630 * function setup() { 51631 * cnv = createCanvas(100, 100); 51632 * cnv.mouseOut(changeGray); 51633 * d = 10; 51634 * } 51635 * 51636 * function draw() { 51637 * ellipse(width / 2, height / 2, d, d); 51638 * } 51639 * 51640 * function changeGray() { 51641 * d = d + 10; 51642 * if (d > 100) { 51643 * d = 0; 51644 * } 51645 * } 51646 * </code></div> 51647 * 51648 * @alt 51649 * no display. 51650 * 51651 */ 51652 51653 51654 p5.Element.prototype.mouseOut = function (fxn) { 51655 p5.Element._adjustListener('mouseout', fxn, this); 51656 51657 return this; 51658 }; 51659 /** 51660 * The .<a href="#/p5.Element/touchStarted">touchStarted()</a> function is called once after every time a touch is 51661 * registered. This can be used to attach element specific event listeners. 51662 * 51663 * @method touchStarted 51664 * @param {Function|Boolean} fxn function to be fired when a touch 51665 * starts over the element. 51666 * if `false` is passed instead, the previously 51667 * firing function will no longer fire. 51668 * @chainable 51669 * @example 51670 * <div class='norender'><code> 51671 * var cnv; 51672 * var d; 51673 * var g; 51674 * function setup() { 51675 * cnv = createCanvas(100, 100); 51676 * cnv.touchStarted(changeGray); // attach listener for 51677 * // canvas click only 51678 * d = 10; 51679 * g = 100; 51680 * } 51681 * 51682 * function draw() { 51683 * background(g); 51684 * ellipse(width / 2, height / 2, d, d); 51685 * } 51686 * 51687 * // this function fires with any touch anywhere 51688 * function touchStarted() { 51689 * d = d + 10; 51690 * } 51691 * 51692 * // this function fires only when cnv is clicked 51693 * function changeGray() { 51694 * g = random(0, 255); 51695 * } 51696 * </code></div> 51697 * 51698 * @alt 51699 * no display. 51700 * 51701 */ 51702 51703 51704 p5.Element.prototype.touchStarted = function (fxn) { 51705 p5.Element._adjustListener('touchstart', fxn, this); 51706 51707 return this; 51708 }; 51709 /** 51710 * The .<a href="#/p5.Element/touchMoved">touchMoved()</a> function is called once after every time a touch move is 51711 * registered. This can be used to attach element specific event listeners. 51712 * 51713 * @method touchMoved 51714 * @param {Function|Boolean} fxn function to be fired when a touch moves over 51715 * the element. 51716 * if `false` is passed instead, the previously 51717 * firing function will no longer fire. 51718 * @chainable 51719 * @example 51720 * <div class='norender'><code> 51721 * var cnv; 51722 * var g; 51723 * function setup() { 51724 * cnv = createCanvas(100, 100); 51725 * cnv.touchMoved(changeGray); // attach listener for 51726 * // canvas click only 51727 * g = 100; 51728 * } 51729 * 51730 * function draw() { 51731 * background(g); 51732 * } 51733 * 51734 * // this function fires only when cnv is clicked 51735 * function changeGray() { 51736 * g = random(0, 255); 51737 * } 51738 * </code></div> 51739 * 51740 * @alt
51741 * no display. 51742 * 51743 */ 51744 51745 51746 p5.Element.prototype.touchMoved = function (fxn) { 51747 p5.Element._adjustListener('touchmove', fxn, this); 51748 51749 return this; 51750 }; 51751 /** 51752 * The .<a href="#/p5.Element/touchEnded">touchEnded()</a> function is called once after every time a touch is 51753 * registered. This can be used to attach element specific event listeners. 51754 * 51755 * @method touchEnded 51756 * @param {Function|Boolean} fxn function to be fired when a touch ends 51757 * over the element. 51758 * if `false` is passed instead, the previously 51759 * firing function will no longer fire. 51760 * @chainable 51761 * @example 51762 * <div class='norender'><code> 51763 * var cnv; 51764 * var d; 51765 * var g; 51766 * function setup() { 51767 * cnv = createCanvas(100, 100); 51768 * cnv.touchEnded(changeGray); // attach listener for 51769 * // canvas click only 51770 * d = 10; 51771 * g = 100; 51772 * } 51773 * 51774 * function draw() { 51775 * background(g); 51776 * ellipse(width / 2, height / 2, d, d); 51777 * } 51778 * 51779 * // this function fires with any touch anywhere 51780 * function touchEnded() { 51781 * d = d + 10; 51782 * } 51783 * 51784 * // this function fires only when cnv is clicked 51785 * function changeGray() { 51786 * g = random(0, 255); 51787 * } 51788 * </code></div> 51789 * 51790 * 51791 * @alt 51792 * no display. 51793 * 51794 */ 51795 51796 51797 p5.Element.prototype.touchEnded = function (fxn) { 51798 p5.Element._adjustListener('touchend', fxn, this); 51799 51800 return this; 51801 }; 51802 /** 51803 * The .<a href="#/p5.Element/dragOver">dragOver()</a> function is called once after every time a 51804 * file is dragged over the element. This can be used to attach an 51805 * element specific event listener. 51806 * 51807 * @method dragOver 51808 * @param {Function|Boolean} fxn function to be fired when a file is 51809 * dragged over the element. 51810 * if `false` is passed instead, the previously 51811 * firing function will no longer fire. 51812 * @chainable 51813 * @example 51814 * <div><code> 51815 * // To test this sketch, simply drag a 51816 * // file over the canvas 51817 * function setup() { 51818 * var c = createCanvas(100, 100); 51819 * background(200); 51820 * textAlign(CENTER); 51821 * text('Drag file', width / 2, height / 2); 51822 * c.dragOver(dragOverCallback); 51823 * } 51824 * 51825 * // This function will be called whenever 51826 * // a file is dragged over the canvas 51827 * function dragOverCallback() { 51828 * background(240); 51829 * text('Dragged over', width / 2, height / 2); 51830 * } 51831 * </code></div> 51832 * @alt 51833 * nothing displayed 51834 */ 51835 51836 51837 p5.Element.prototype.dragOver = function (fxn) { 51838 p5.Element._adjustListener('dragover', fxn, this); 51839 51840 return this; 51841 }; 51842 /** 51843 * The .dragLeave() function is called once after every time a 51844 * dragged file leaves the element area. This can be used to attach an 51845 * element specific event listener. 51846 * 51847 * @method dragLeave 51848 * @param {Function|Boolean} fxn function to be fired when a file is 51849 * dragged off the element. 51850 * if `false` is passed instead, the previously 51851 * firing function will no longer fire. 51852 * @chainable 51853 * @example 51854 * <div><code> 51855 * // To test this sketch, simply drag a file 51856 * // over and then out of the canvas area 51857 * function setup() { 51858 * var c = createCanvas(100, 100); 51859 * background(200); 51860 * textAlign(CENTER); 51861 * text('Drag file', width / 2, height / 2); 51862 * c.dragLeave(dragLeaveCallback); 51863 * } 51864 * 51865 * // This function will be called whenever 51866 * // a file is dragged out of the canvas 51867 * function dragLeaveCallback() { 51868 * background(240); 51869 * text('Dragged off', width / 2, height / 2); 51870 * } 51871 * </code></div> 51872 * @alt 51873 * nothing displayed 51874 */ 51875 51876 51877 p5.Element.prototype.dragLeave = function (fxn) { 51878 p5.Element._adjustListener('dragleave', fxn, this); 51879 51880 return this; 51881 }; 51882 /** 51883 * Registers a callback that gets called every time a file that is 51884 * dropped on the element has been loaded. 51885 * p5 will load every dropped file into memory and pass it as a p5.File object to the callback. 51886 * Multiple files dropped at the same time will result in multiple calls to the callback. 51887 * 51888 * You can optionally pass a second callback which will be registered to the raw 51889 * <a href="https://developer.mozilla.org/en-US/docs/Web/Events/drop">drop</a> event. 51890 * The callback will thus be provided the original 51891 * <a href="https://developer.mozilla.org/en-US/docs/Web/API/DragEvent">DragEvent</a>. 51892 * Dropping multiple files at the same time will trigger the second callback once per drop, 51893 * whereas the first callback will trigger for each loaded file. 51894 * 51895 * @method drop 51896 * @param {Function} callback callback to receive loaded file. 51897 * @param {Function}
51897 [fxn] callback triggered when files are dropped. 51898 * @chainable 51899 * @example 51900 * <div><code> 51901 * function setup() { 51902 * var c = createCanvas(100, 100); 51903 * background(200); 51904 * textAlign(CENTER); 51905 * text('drop file', width / 2, height / 2); 51906 * c.drop(gotFile); 51907 * } 51908 * 51909 * function gotFile(file) { 51910 * background(200); 51911 * text('received file:', width / 2, height / 2); 51912 * text(file.name, width / 2, height / 2 + 50); 51913 * } 51914 * </code></div> 51915 * 51916 * <div><code> 51917 * var img; 51918 * 51919 * function setup() { 51920 * var c = createCanvas(100, 100); 51921 * background(200); 51922 * textAlign(CENTER); 51923 * text('drop image', width / 2, height / 2); 51924 * c.drop(gotFile); 51925 * } 51926 * 51927 * function draw() { 51928 * if (img) { 51929 * image(img, 0, 0, width, height); 51930 * } 51931 * } 51932 * 51933 * function gotFile(file) { 51934 * img = createImg(file.data).hide(); 51935 * } 51936 * </code></div> 51937 * 51938 * @alt 51939 * Canvas turns into whatever image is dragged/dropped onto it. 51940 */ 51941 51942 51943 p5.Element.prototype.drop = function (callback, fxn) { 51944 // Is the file stuff supported? 51945 if (window.File && window.FileReader && window.FileList && window.Blob) { 51946 if (!this._dragDisabled) { 51947 this._dragDisabled = true; 51948 51949 var preventDefault = function (evt) { 51950 evt.preventDefault(); 51951 }; // If you want to be able to drop you've got to turn off 51952 // a lot of default behavior. 51953 // avoid `attachListener` here, since it overrides other handlers. 51954 51955 51956 this.elt.addEventListener('dragover', preventDefault); // If this is a drag area we need to turn off the default behavior 51957 51958 this.elt.addEventListener('dragleave', preventDefault); 51959 } // Attach the second argument as a callback that receives the raw drop event 51960 51961 51962 if (typeof fxn !== 'undefined') { 51963 p5.Element._attachListener('drop', fxn, this); 51964 } // Deal with the files 51965 51966 51967 p5.Element._attachListener('drop', function (evt) { 51968 evt.preventDefault(); // A FileList 51969 51970 var files = evt.dataTransfer.files; // Load each one and trigger the callback 51971 51972 for (var i = 0; i < files.length; i++) { 51973 var f = files[i]; 51974 51975 p5.File._load(f, callback); 51976 } 51977 }, this); 51978 } else { 51979 console.log('The File APIs are not fully supported in this browser.'); 51980 } 51981 51982 return this; 51983 }; // General handler for event attaching and detaching 51984 51985 51986 p5.Element._adjustListener = function (ev, fxn, ctx) { 51987 if (fxn === false) { 51988 p5.Element._detachListener(ev, ctx); 51989 } else { 51990 p5.Element._attachListener(ev, fxn, ctx); 51991 } 51992 51993 return this; 51994 }; 51995 51996 p5.Element._attachListener = function (ev, fxn, ctx) { 51997 // detach the old listener if there was one 51998 if (ctx._events[ev]) { 51999 p5.Element._detachListener(ev, ctx); 52000 } 52001 52002 var f = fxn.bind(ctx); 52003 ctx.elt.addEventListener(ev, f, false); 52004 ctx._events[ev] = f; 52005 }; 52006 52007 p5.Element._detachListener = function (ev, ctx) { 52008 var f = ctx._events[ev]; 52009 ctx.elt.removeEventListener(ev, f, false); 52010 ctx._events[ev] = null; 52011 }; 52012 /** 52013 * Helper fxn for sharing pixel methods 52014 * 52015 */ 52016 52017 52018 p5.Element.prototype._setProperty = function (prop, value) { 52019 this[prop] = value; 52020 }; 52021 52022 module.exports = p5.Element; 52023 }, { 52024 "./main": 24 52025 }], 52026 26: [function (_dereq_, module, exports) { 52027 /** 52028 * @module Rendering 52029 * @submodule Rendering 52030 * @for p5 52031 */ 52032 'use strict'; 52033 52034 var p5 = _dereq_('./main'); 52035 52036 var constants = _dereq_('./constants'); 52037 /** 52038 * Thin wrapper around a renderer, to be used for creating a 52039 * graphics buffer object. Use this class if you need 52040 * to draw into an off-screen graphics buffer. The two parameters define the 52041 * width and height in pixels. The fields and methods for this class are 52042 * extensive, but mirror the normal drawing API for p5. 52043 * 52044 * @class p5.Graphics 52045 * @extends p5.Element 52046 * @param {Number} w width 52047 * @param {Number} h height 52048 * @param {Constant} renderer the renderer to use, either P2D or WEBGL 52049 * @param {p5} [pInst] pointer to p5 instance 52050 */ 52051 52052 52053 p5.Graphics = function (w, h, renderer, pInst) { 52054 var r = renderer || constants.P2D; 52055 this.canvas = document.createElement('canvas'); 52056 var node = pInst._userNode || document.body; 52057 node.appendChild(this.canvas); 52058 p5.Element.call(this, this.canvas, pInst, false); // bind methods and props of p5 to the new object 52059 52060 for (var p in p5.prototype) { 52061 if (!this[p]) { 52062 if (typeof p5.prototype[p] === 'function') { 52063 this[p] = p5.prototype[p].bind(this); 52064 } else { 52065 this[p] = p5.prototype[p]; 52066 } 52067 } 52068 } 52069 52070 p5.prototype._initializeInstanceVariables.apply(this); 52071 52072 this.width = w; 52073 this.height = h; 52074 this._pixelDensity = pInst._pixelDensity; 52075 52076 if (r === constants.WEBGL) { 52077 this._renderer = new p5.RendererGL(this.canvas, this, false); 52078 } else { 52079 this._renderer = new p5.Renderer2D(this.canvas, this, false); 52080 } 52081 52082 pInst._elements.push(this); 52083 52084 this._renderer.resize(w, h); 52085 52086 this._renderer._applyDefaults(); 52087 52088 return this; 52089 }; 52090 52091 p5.Graphics.prototype = Object.create(p5.Element.prototype); 52092 /** 52093 * Removes a Graphics object from the page and frees any resources 52094 * associated with it. 52095 * 52096 * @method remove 52097 * 52098 * @example 52099 * <div class='norender'><code> 52100 * let bg; 52101 * function setup() { 52102 * bg = createCanvas(100, 100); 52103 * bg.background(0); 52104 * image(bg, 0, 0); 52105 * bg.remove(); 52106 * } 52107 * </code></div> 52108 * 52109 * <div><code> 52110 * let bg; 52111 * function setup() { 52112 * pixelDensity(1); 52113 * createCanvas(100, 100);
52114 * stroke(255); 52115 * fill(0); 52116 * 52117 * // create and draw the background image 52118 * bg = createGraphics(100, 100); 52119 * bg.background(200); 52120 * bg.ellipse(50, 50, 80, 80); 52121 * } 52122 * function draw() { 52123 * let t = millis() / 1000; 52124 * // draw the background 52125 * if (bg) { 52126 * image(bg, frameCount % 100, 0); 52127 * image(bg, frameCount % 100 - 100, 0); 52128 * } 52129 * // draw the foreground 52130 * let p = p5.Vector.fromAngle(t, 35).add(50, 50); 52131 * ellipse(p.x, p.y, 30); 52132 * } 52133 * function mouseClicked() { 52134 * // remove the background 52135 * if (bg) { 52136 * bg.remove(); 52137 * bg = null; 52138 * } 52139 * } 52140 * </code></div> 52141 * 52142 * @alt 52143 * no image 52144 * a multi-colored circle moving back and forth over a scrolling background. 52145 * 52146 */ 52147 52148 p5.Graphics.prototype.remove = function () { 52149 if (this.elt.parentNode) { 52150 this.elt.parentNode.removeChild(this.elt); 52151 } 52152 52153 var idx = this._pInst._elements.indexOf(this); 52154 52155 if (idx !== -1) { 52156 this._pInst._elements.splice(idx, 1); 52157 } 52158 52159 for (var elt_ev in this._events) { 52160 this.elt.removeEventListener(elt_ev, this._events[elt_ev]); 52161 } 52162 }; 52163 52164 module.exports = p5.Graphics; 52165 }, { 52166 "./constants": 18, 52167 "./main": 24 52168 }], 52169 27: [function (_dereq_, module, exports) { 52170 /** 52171 * @module Rendering 52172 * @submodule Rendering 52173 * @for p5 52174 */ 52175 'use strict'; 52176 52177 var p5 = _dereq_('./main'); 52178 52179 var constants = _dereq_('../core/constants'); 52180 /** 52181 * Main graphics and rendering context, as well as the base API 52182 * implementation for p5.js "core". To be used as the superclass for 52183 * Renderer2D and Renderer3D classes, respecitvely. 52184 * 52185 * @class p5.Renderer 52186 * @constructor 52187 * @extends p5.Element 52188 * @param {String} elt DOM node that is wrapped 52189 * @param {p5} [pInst] pointer to p5 instance 52190 * @param {Boolean} [isMainCanvas] whether we're using it as main canvas 52191 */ 52192 52193 52194 p5.Renderer = function (elt, pInst, isMainCanvas) { 52195 p5.Element.call(this, elt, pInst); 52196 this.canvas = elt; 52197 52198 if (isMainCanvas) { 52199 this._isMainCanvas = true; // for pixel method sharing with pimage 52200 52201 this._pInst._setProperty('_curElement', this); 52202 52203 this._pInst._setProperty('canvas', this.canvas); 52204 52205 this._pInst._setProperty('width', this.width); 52206 52207 this._pInst._setProperty('height', this.height); 52208 } else { 52209 // hide if offscreen buffer by default 52210 this.canvas.style.display = 'none'; 52211 this._styles = []; // non-main elt styles stored in p5.Renderer 52212 } 52213 52214 this._textSize = 12; 52215 this._textLeading = 15; 52216 this._textFont = 'sans-serif'; 52217 this._textStyle = constants.NORMAL; 52218 this._textAscent = null; 52219 this._textDescent = null; 52220 this._textAlign = constants.LEFT; 52221 this._textBaseline = constants.BASELINE; 52222 this._rectMode = constants.CORNER; 52223 this._ellipseMode = constants.CENTER; 52224 this._curveTightness = 0; 52225 this._imageMode = constants.CORNER; 52226 this._tint = null; 52227 this._doStroke = true; 52228 this._doFill = true; 52229 this._strokeSet = false; 52230 this._fillSet = false; 52231 }; 52232 52233 p5.Renderer.prototype = Object.create(p5.Element.prototype); // the renderer should return a 'style' object that it wishes to 52234 // store on the push stack. 52235 52236 p5.Renderer.prototype.push = function () { 52237 return { 52238 properties: { 52239 _doStroke: this._doStroke, 52240 _strokeSet: this._strokeSet, 52241 _doFill: this._doFill, 52242 _fillSet: this._fillSet, 52243 _tint: this._tint, 52244 _imageMode: this._imageMode, 52245 _rectMode: this._rectMode, 52246 _ellipseMode: this._ellipseMode, 52247 _textFont: this._textFont, 52248 _textLeading: this._textLeading, 52249 _textSize: this._textSize, 52250 _textAlign: this._textAlign, 52251 _textBaseline: this._textBaseline, 52252 _textStyle: this._textStyle 52253 } 52254 }; 52255 }; // a pop() operation is in progress 52256 // the renderer is passed the 'style' object that it returned 52257 // from its push() method. 52258 52259 52260 p5.Renderer.prototype.pop = function (style) { 52261 if (style.properties) { 52262 // copy the style properties back into the renderer 52263 Object.assign(this, style.properties); 52264 } 52265 }; 52266 /** 52267 * Resize our canvas element. 52268 */ 52269 52270 52271 p5.Renderer.prototype.resize = function (w, h) { 52272 this.width = w; 52273 this.height = h; 52274 this.elt.width = w * this._pInst._pixelDensity; 52275 this.elt.height = h * this._pInst._pixelDensity; 52276 this.elt.style.width = w + 'px'; 52277 this.elt.style.height = h + 'px'; 52278 52279 if (this._isMainCanvas) { 52280 this._pInst._setProperty('width', this.width); 52281 52282 this._pInst._setProperty('height', this.height); 52283 } 52284 }; 52285 52286 p5.Renderer.prototype.textLeading = function (l) { 52287 if (typeof l === 'number') { 52288 this._setProperty('_textLeading', l); 52289 52290 return this._pInst; 52291 } 52292 52293 return this._textLeading; 52294 }; 52295 52296 p5.Renderer.prototype.textSize = function (s) { 52297 if (typeof s === 'number') { 52298 this._setProperty('_textSize', s); 52299 52300 this._setProperty('_textLeading', s * constants._DEFAULT_LEADMULT); 52301 52302 return this._applyTextProperties(); 52303 } 52304 52305 return this._textSize; 52306 }; 52307 52308 p5.Renderer.prototype.textStyle = function (s) { 52309 if (s) { 52310 if (s === constants.NORMAL || s === constants.ITALIC || s === constants.BOLD || s === constants.BOLDITALIC) { 52311 this._setProperty('_textStyle', s); 52312 } 52313 52314 return this._applyTextProperties(); 52315 } 52316 52317 return this._textStyle; 52318 }; 52319 52320 p5.Renderer.prototype.textAscent = function () { 52321 if (this._textAscent === null) { 52322 this._updateTextMetrics(); 52323 } 52324 52325 return this._textAscent; 52326 }; 52327 52328 p5.Renderer.prototype.textDescent = function () { 52329 if (this._textDescent === null) { 52330 this._updateTextMetrics(); 52331 } 52332 52333 return this._textDescent; 52334 }; 52335 52336 p5.Renderer.prototype.textAlign = function (h, v) { 52337 if (typeof h !== 'undefined') { 52338 this._setProperty('_textAlign', h); 52339 52340 if (typeof v !== 'undefined') { 52341 this._setProperty('_textBaseline', v); 52342 } 52343 52344 return this._applyTextProperties(); 52345 } else { 52346 return { 52347 horizontal: this._textAlign, 52348 vertical: this._textBaseline 52349 }; 52350 } 52351 }; 52352 52353 p5.Renderer.prototype.text = function (str, x, y, maxWidth, maxHeight) { 52354 var p = this._pInst, 52355 cars, 52356 n, 52357 ii, 52358 jj, 52359 line, 52360 testLine, 52361 testWidth, 52362 words, 52363 totalHeight, 52364 finalMaxHeight = Number.MAX_VALUE; 52365 52366 if (!(this._doFill || this._doStroke)) { 52367 return; 52368 } 52369 52370 if (typeof str === 'undefined') { 52371 return; 52372 } else if (typeof str !== 'string') { 52373 str = str.toString(); 52374 } 52375 52376 str = str.replace(/(\t)/g, ' '); 52377 cars = str.split('\n'); 52378 52379 if (typeof maxWidth !== 'undefined') { 52380 totalHeight = 0; 52381 52382 for (ii = 0; ii < cars.length; ii++) { 52383 line = ''; 52384 words = cars[ii].split(' '); 52385 52386 for (n = 0; n < words.length; n++) { 52387 testLine = line + words[n] + ' '; 52388 testWidth = this.textWidth(testLine); 52389 52390 if (testWidth > maxWidth) { 52391 line = words[n] + ' '; 52392 totalHeight += p.textLeading(); 52393 } else { 52394 line = testLine; 52395 } 52396 } 52397 } 52398 52399 if (this._rectMode === constants.CENTER) { 52400 x -= maxWidth / 2; 52401 y -= maxHeight / 2; 52402 } 52403 52404 switch (this._textAlign) { 52405 case constants.CENTER: 52406 x += maxWidth / 2; 52407 break; 52408 52409 case constants.RIGHT: 52410 x += maxWidth; 52411 break; 52412 } 52413 52414 var baselineHacked = false;
52415 52416 if (typeof maxHeight !== 'undefined') { 52417 switch (this._textBaseline) { 52418 case constants.BOTTOM: 52419 y += maxHeight - totalHeight; 52420 break; 52421 52422 case constants.CENTER: 52423 y += (maxHeight - totalHeight) / 2; 52424 break; 52425 52426 case constants.BASELINE: 52427 baselineHacked = true; 52428 this._textBaseline = constants.TOP; 52429 break; 52430 } // remember the max-allowed y-position for any line (fix to #928) 52431 52432 52433 finalMaxHeight = y + maxHeight - p.textAscent(); 52434 } 52435 52436 for (ii = 0; ii < cars.length; ii++) { 52437 line = ''; 52438 words = cars[ii].split(' '); 52439 52440 for (n = 0; n < words.length; n++) { 52441 testLine = line + words[n] + ' '; 52442 testWidth = this.textWidth(testLine); 52443 52444 if (testWidth > maxWidth && line.length > 0) { 52445 this._renderText(p, line, x, y, finalMaxHeight); 52446 52447 line = words[n] + ' '; 52448 y += p.textLeading(); 52449 } else { 52450 line = testLine; 52451 } 52452 } 52453 52454 this._renderText(p, line, x, y, finalMaxHeight); 52455 52456 y += p.textLeading(); 52457 52458 if (baselineHacked) { 52459 this._textBaseline = constants.BASELINE; 52460 } 52461 } 52462 } else { 52463 // Offset to account for vertically centering multiple lines of text - no 52464 // need to adjust anything for vertical align top or baseline 52465 var offset = 0, 52466 vAlign = p.textAlign().vertical; 52467 52468 if (vAlign === constants.CENTER) { 52469 offset = (cars.length - 1) * p.textLeading() / 2; 52470 } else if (vAlign === constants.BOTTOM) { 52471 offset = (cars.length - 1) * p.textLeading(); 52472 } 52473 52474 for (jj = 0; jj < cars.length; jj++) { 52475 this._renderText(p, cars[jj], x, y - offset, finalMaxHeight); 52476 52477 y += p.textLeading(); 52478 } 52479 } 52480 52481 return p; 52482 }; 52483 52484 p5.Renderer.prototype._applyDefaults = function () { 52485 return this; 52486 }; 52487 /** 52488 * Helper fxn to check font type (system or otf) 52489 */ 52490 52491 52492 p5.Renderer.prototype._isOpenType = function (f) { 52493 f = f || this._textFont; 52494 return typeof f === 'object' && f.font && f.font.supported; 52495 }; 52496 52497 p5.Renderer.prototype._updateTextMetrics = function () { 52498 if (this._isOpenType()) { 52499 this._setProperty('_textAscent', this._textFont._textAscent()); 52500 52501 this._setProperty('_textDescent', this._textFont._textDescent()); 52502 52503 return this; 52504 } // Adapted from http://stackoverflow.com/a/25355178 52505 52506 52507 var text = document.createElement('span'); 52508 text.style.fontFamily = this._textFont; 52509 text.style.fontSize = this._textSize + 'px'; 52510 text.innerHTML = 'ABCjgq|'; 52511 var block = document.createElement('div'); 52512 block.style.display = 'inline-block'; 52513 block.style.width = '1px'; 52514 block.style.height = '0px'; 52515 var container = document.createElement('div'); 52516 container.appendChild(text); 52517 container.appendChild(block); 52518 container.style.height = '0px'; 52519 container.style.overflow = 'hidden'; 52520 document.body.appendChild(container); 52521 block.style.verticalAlign = 'baseline'; 52522 var blockOffset = calculateOffset(block); 52523 var textOffset = calculateOffset(text); 52524 var ascent = blockOffset[1] - textOffset[1]; 52525 block.style.verticalAlign = 'bottom'; 52526 blockOffset = calculateOffset(block); 52527 textOffset = calculateOffset(text); 52528 var height = blockOffset[1] - textOffset[1]; 52529 var descent = height - ascent; 52530 document.body.removeChild(container); 52531 52532 this._setProperty('_textAscent', ascent); 52533 52534 this._setProperty('_textDescent', descent); 52535 52536 return this; 52537 }; 52538 /** 52539 * Helper fxn to measure ascent and descent. 52540 * Adapted from http://stackoverflow.com/a/25355178 52541 */ 52542 52543 52544 function calculateOffset(object) { 52545 var currentLeft = 0, 52546 currentTop = 0; 52547 52548 if (object.offsetParent) { 52549 do { 52550 currentLeft += object.offsetLeft; 52551 currentTop += object.offsetTop; 52552 } while (object = object.offsetParent); 52553 } else { 52554 currentLeft += object.offsetLeft; 52555 currentTop += object.offsetTop; 52556 } 52557 52558 return [currentLeft, currentTop]; 52559 } 52560 52561 module.exports = p5.Renderer; 52562 }, {
52563 "../core/constants": 18, 52564 "./main": 24 52565 }], 52566 28: [function (_dereq_, module, exports) { 52567 'use strict'; 52568 52569 var p5 = _dereq_('./main'); 52570 52571 var constants = _dereq_('./constants'); 52572 52573 var filters = _dereq_('../image/filters'); 52574 52575 _dereq_('./p5.Renderer'); 52576 /** 52577 * p5.Renderer2D 52578 * The 2D graphics canvas renderer class. 52579 * extends p5.Renderer 52580 */ 52581 52582 52583 var styleEmpty = 'rgba(0,0,0,0)'; // var alphaThreshold = 0.00125; // minimum visible 52584 52585 p5.Renderer2D = function (elt, pInst, isMainCanvas) { 52586 p5.Renderer.call(this, elt, pInst, isMainCanvas); 52587 this.drawingContext = this.canvas.getContext('2d'); 52588 52589 this._pInst._setProperty('drawingContext', this.drawingContext); 52590 52591 return this; 52592 }; 52593 52594 p5.Renderer2D.prototype = Object.create(p5.Renderer.prototype); 52595 52596 p5.Renderer2D.prototype._applyDefaults = function () { 52597 this._cachedFillStyle = this._cachedStrokeStyle = undefined; 52598 52599 this._setFill(constants._DEFAULT_FILL); 52600 52601 this._setStroke(constants._DEFAULT_STROKE); 52602 52603 this.drawingContext.lineCap = constants.ROUND; 52604 this.drawingContext.font = 'normal 12px sans-serif'; 52605 }; 52606 52607 p5.Renderer2D.prototype.resize = function (w, h) { 52608 p5.Renderer.prototype.resize.call(this, w, h); 52609 this.drawingContext.scale(this._pInst._pixelDensity, this._pInst._pixelDensity); 52610 }; ////////////////////////////////////////////// 52611 // COLOR | Setting 52612 ////////////////////////////////////////////// 52613 52614 52615 p5.Renderer2D.prototype.background = function () { 52616 this.drawingContext.save(); 52617 this.resetMatrix(); 52618 52619 if (arguments[0] instanceof p5.Image) { 52620 this._pInst.image(arguments[0], 0, 0, this.width, this.height); 52621 } else { 52622 var curFill = this._getFill(); // create background rect 52623 52624 52625 var color = this._pInst.color.apply(this._pInst, arguments); 52626 52627 var newFill = color.toString(); 52628 52629 this._setFill(newFill); 52630 52631 this.drawingContext.fillRect(0, 0, this.width, this.height); // reset fill 52632 52633 this._setFill(curFill); 52634 } 52635 52636 this.drawingContext.restore(); 52637 this._pInst._pixelsDirty = true; 52638 }; 52639 52640 p5.Renderer2D.prototype.clear = function () { 52641 this.drawingContext.save(); 52642 this.resetMatrix(); 52643 this.drawingContext.clearRect(0, 0, this.width, this.height); 52644 this.drawingContext.restore(); 52645 this._pInst._pixelsDirty = true; 52646 }; 52647 52648 p5.Renderer2D.prototype.fill = function () { 52649 var color = this._pInst.color.apply(this._pInst, arguments); 52650 52651 this._setFill(color.toString()); 52652 }; 52653 52654 p5.Renderer2D.prototype.stroke = function () { 52655 var color = this._pInst.color.apply(this._pInst, arguments); 52656 52657 this._setStroke(color.toString()); 52658 }; ////////////////////////////////////////////// 52659 // IMAGE | Loading & Displaying 52660 ////////////////////////////////////////////// 52661 52662 52663 p5.Renderer2D.prototype.image = function (img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) { 52664 var cnv; 52665 52666 try { 52667 if (this._tint) { 52668 if (p5.MediaElement && img instanceof p5.MediaElement) { 52669 img.loadPixels(); 52670 } 52671 52672 if (img.canvas) { 52673 cnv = this._getTintedImageCanvas(img); 52674 } 52675 } 52676 52677 if (!cnv) { 52678 cnv = img.canvas || img.elt; 52679 } 52680 52681 var s = 1; 52682 52683 if (img.width && img.width > 0) { 52684 s = cnv.width / img.width; 52685 } 52686 52687 this.drawingContext.drawImage(cnv, s * sx, s * sy, s * sWidth, s * sHeight, dx, dy, dWidth, dHeight); 52688 } catch (e) { 52689 if (e.name !== 'NS_ERROR_NOT_AVAILABLE') { 52690 throw e; 52691 } 52692 } 52693 52694 this._pInst._pixelsDirty = true; 52695 }; 52696 52697 p5.Renderer2D.prototype._getTintedImageCanvas = function (img) { 52698 if (!img.canvas) { 52699 return img; 52700 } 52701 52702 var pixels = filters._toPixels(img.canvas); 52703 52704 var tmpCanvas = document.createElement('canvas'); 52705 tmpCanvas.width = img.canvas.width; 52706 tmpCanvas.height = img.canvas.height; 52707 var tmpCtx = tmpCanvas.getContext('2d'); 52708 var id = tmpCtx.createImageData(img.canvas.width, img.canvas.height); 52709 var newPixels = id.data; 52710 52711 for (var i = 0; i < pixels.length; i += 4) { 52712 var r = pixels[i]; 52713 var g = pixels[i + 1]; 52714 var b = pixels[i + 2]; 52715 var a = pixels[i + 3];
52716 newPixels[i] = r * this._tint[0] / 255; 52717 newPixels[i + 1] = g * this._tint[1] / 255; 52718 newPixels[i + 2] = b * this._tint[2] / 255; 52719 newPixels[i + 3] = a * this._tint[3] / 255; 52720 } 52721 52722 tmpCtx.putImageData(id, 0, 0); 52723 return tmpCanvas; 52724 }; ////////////////////////////////////////////// 52725 // IMAGE | Pixels 52726 ////////////////////////////////////////////// 52727 52728 52729 p5.Renderer2D.prototype.blendMode = function (mode) { 52730 this.drawingContext.globalCompositeOperation = mode; 52731 }; 52732 52733 p5.Renderer2D.prototype.blend = function () { 52734 var currBlend = this.drawingContext.globalCompositeOperation; 52735 var blendMode = arguments[arguments.length - 1]; 52736 var copyArgs = Array.prototype.slice.call(arguments, 0, arguments.length - 1); 52737 this.drawingContext.globalCompositeOperation = blendMode; 52738 52739 if (this._pInst) { 52740 this._pInst.copy.apply(this._pInst, copyArgs); 52741 } else { 52742 this.copy.apply(this, copyArgs); 52743 } 52744 52745 this.drawingContext.globalCompositeOperation = currBlend; 52746 }; 52747 52748 p5.Renderer2D.prototype.copy = function () { 52749 var srcImage, sx, sy, sw, sh, dx, dy, dw, dh; 52750 52751 if (arguments.length === 9) { 52752 srcImage = arguments[0]; 52753 sx = arguments[1]; 52754 sy = arguments[2]; 52755 sw = arguments[3]; 52756 sh = arguments[4]; 52757 dx = arguments[5]; 52758 dy = arguments[6]; 52759 dw = arguments[7]; 52760 dh = arguments[8]; 52761 } else if (arguments.length === 8) { 52762 srcImage = this._pInst; 52763 sx = arguments[0]; 52764 sy = arguments[1]; 52765 sw = arguments[2]; 52766 sh = arguments[3]; 52767 dx = arguments[4]; 52768 dy = arguments[5]; 52769 dw = arguments[6]; 52770 dh = arguments[7]; 52771 } else { 52772 throw new Error('Signature not supported'); 52773 } 52774 52775 p5.Renderer2D._copyHelper(this, srcImage, sx, sy, sw, sh, dx, dy, dw, dh); 52776 52777 this._pInst._pixelsDirty = true; 52778 }; 52779 52780 p5.Renderer2D._copyHelper = function (dstImage, srcImage, sx, sy, sw, sh, dx, dy, dw, dh) { 52781 srcImage.loadPixels(); 52782 var s = srcImage.canvas.width / srcImage.width; 52783 dstImage.drawingContext.drawImage(srcImage.canvas, s * sx, s * sy, s * sw, s * sh, dx, dy, dw, dh); 52784 }; 52785 52786 p5.Renderer2D.prototype.get = function (x, y, w, h) { 52787 var ctx = this._pInst || this; 52788 var pd = ctx._pixelDensity; 52789 var sx = x * pd; 52790 var sy = y * pd; 52791 52792 if (w === 1 && h === 1) { 52793 var imageData, index; 52794 52795 if (ctx._pixelsDirty) { 52796 imageData = this.drawingContext.getImageData(sx, sy, 1, 1).data; 52797 index = 0; 52798 } else { 52799 imageData = ctx.pixels; 52800 index = (sx + sy * this.width * pd) * 4; 52801 } 52802 52803 return [imageData[index + 0], imageData[index + 1], imageData[index + 2], imageData[index + 3]]; 52804 } else { 52805 //auto constrain the width and height to 52806 //dimensions of the source image 52807 var dw = Math.min(w, ctx.width); 52808 var dh = Math.min(h, ctx.height); 52809 var sw = dw * pd; 52810 var sh = dh * pd; 52811 var region = new p5.Image(dw, dh); 52812 region.canvas.getContext('2d').drawImage(this.canvas, sx, sy, sw, sh, 0, 0, dw, dh); 52813 return region; 52814 } 52815 }; 52816 52817 p5.Renderer2D.prototype.loadPixels = function () { 52818 var ctx = this._pInst || this; // if called by p5.Image 52819 52820 if (!ctx._pixelsDirty) return; 52821 ctx._pixelsDirty = false; 52822 var pd = ctx._pixelDensity; 52823 var w = this.width * pd; 52824 var h = this.height * pd; 52825 var imageData = this.drawingContext.getImageData(0, 0, w, h); // @todo this should actually set pixels per object, so diff buffers can 52826 // have diff pixel arrays. 52827 52828 ctx._setProperty('imageData', imageData); 52829 52830 ctx._setProperty('pixels', imageData.data); 52831 }; 52832 52833 p5.Renderer2D.prototype.set = function (x, y, imgOrCol) { 52834 // round down to get integer numbers 52835 x = Math.floor(x); 52836 y = Math.floor(y); 52837 var ctx = this._pInst || this; 52838 52839 if (imgOrCol instanceof p5.Image) { 52840 this.drawingContext.save(); 52841 this.drawingContext.setTransform(1, 0, 0, 1, 0, 0); 52842 this.drawingContext.scale(ctx._pixelDensity, ctx._pixelDensity); 52843 this.drawingContext.drawImage(imgOrCol.canvas, x, y);
52844 this.drawingContext.restore(); 52845 ctx._pixelsDirty = true; 52846 } else { 52847 var r = 0, 52848 g = 0, 52849 b = 0, 52850 a = 0; 52851 var idx = 4 * (y * ctx._pixelDensity * (this.width * ctx._pixelDensity) + x * ctx._pixelDensity); 52852 52853 if (!ctx.imageData || ctx._pixelsDirty) { 52854 ctx.loadPixels.call(ctx); 52855 } 52856 52857 if (typeof imgOrCol === 'number') { 52858 if (idx < ctx.pixels.length) { 52859 r = imgOrCol; 52860 g = imgOrCol; 52861 b = imgOrCol; 52862 a = 255; //this.updatePixels.call(this); 52863 } 52864 } else if (imgOrCol instanceof Array) { 52865 if (imgOrCol.length < 4) { 52866 throw new Error('pixel array must be of the form [R, G, B, A]'); 52867 } 52868 52869 if (idx < ctx.pixels.length) { 52870 r = imgOrCol[0]; 52871 g = imgOrCol[1]; 52872 b = imgOrCol[2]; 52873 a = imgOrCol[3]; //this.updatePixels.call(this); 52874 } 52875 } else if (imgOrCol instanceof p5.Color) { 52876 if (idx < ctx.pixels.length) { 52877 r = imgOrCol.levels[0]; 52878 g = imgOrCol.levels[1]; 52879 b = imgOrCol.levels[2]; 52880 a = imgOrCol.levels[3]; //this.updatePixels.call(this); 52881 } 52882 } // loop over pixelDensity * pixelDensity 52883 52884 52885 for (var i = 0; i < ctx._pixelDensity; i++) { 52886 for (var j = 0; j < ctx._pixelDensity; j++) { 52887 // loop over 52888 idx = 4 * ((y * ctx._pixelDensity + j) * this.width * ctx._pixelDensity + (x * ctx._pixelDensity + i)); 52889 ctx.pixels[idx] = r; 52890 ctx.pixels[idx + 1] = g; 52891 ctx.pixels[idx + 2] = b; 52892 ctx.pixels[idx + 3] = a; 52893 } 52894 } 52895 } 52896 }; 52897 52898 p5.Renderer2D.prototype.updatePixels = function (x, y, w, h) { 52899 var ctx = this._pInst || this; 52900 var pd = ctx._pixelDensity; 52901 52902 if (x === undefined && y === undefined && w === undefined && h === undefined) { 52903 x = 0; 52904 y = 0; 52905 w = this.width; 52906 h = this.height; 52907 } 52908 52909 w *= pd; 52910 h *= pd; 52911 this.drawingContext.putImageData(ctx.imageData, x, y, 0, 0, w, h); 52912 52913 if (x !== 0 || y !== 0 || w !== this.width || h !== this.height) { 52914 ctx._pixelsDirty = true; 52915 } 52916 }; ////////////////////////////////////////////// 52917 // SHAPE | 2D Primitives 52918 ////////////////////////////////////////////// 52919 52920 /** 52921 * Generate a cubic Bezier representing an arc on the unit circle of total 52922 * angle `size` radians, beginning `start` radians above the x-axis. Up to 52923 * four of these curves are combined to make a full arc. 52924 * 52925 * See www.joecridge.me/bezier.pdf for an explanation of the method. 52926 */ 52927 52928 52929 p5.Renderer2D.prototype._acuteArcToBezier = function _acuteArcToBezier(start, size) { 52930 // Evauate constants. 52931 var alpha = size / 2.0, 52932 cos_alpha = Math.cos(alpha), 52933 sin_alpha = Math.sin(alpha), 52934 cot_alpha = 1.0 / Math.tan(alpha), 52935 phi = start + alpha, 52936 // This is how far the arc needs to be rotated. 52937 cos_phi = Math.cos(phi), 52938 sin_phi = Math.sin(phi), 52939 lambda = (4.0 - cos_alpha) / 3.0, 52940 mu = sin_alpha + (cos_alpha - lambda) * cot_alpha; // Return rotated waypoints. 52941 52942 return { 52943 ax: Math.cos(start), 52944 ay: Math.sin(start), 52945 bx: lambda * cos_phi + mu * sin_phi, 52946 by: lambda * sin_phi - mu * cos_phi, 52947 cx: lambda * cos_phi - mu * sin_phi, 52948 cy: lambda * sin_phi + mu * cos_phi, 52949 dx: Math.cos(start + size), 52950 dy: Math.sin(start + size) 52951 }; 52952 }; 52953 52954 p5.Renderer2D.prototype.arc = function (x, y, w, h, start, stop, mode) { 52955 var ctx = this.drawingContext; 52956 var rx = w / 2.0; 52957 var ry = h / 2.0; 52958 var epsilon = 0.00001; // Smallest visible angle on displays up to 4K. 52959 52960 var arcToDraw = 0; 52961 var curves = []; 52962 x += rx; 52963 y += ry; // Create curves 52964 52965 while (stop - start > epsilon) { 52966 arcToDraw = Math.min(stop - start, constants.HALF_PI); 52967 curves.push(this._acuteArcToBezier(start, arcToDraw)); 52968 start += arcToDraw; 52969 } // Fill curves 52970 52971 52972 if (this._doFill) { 52973 ctx.beginPath();
52974 curves.forEach(function (curve, index) { 52975 if (index === 0) { 52976 ctx.moveTo(x + curve.ax * rx, y + curve.ay * ry); 52977 } // prettier-ignore 52978 52979 52980 ctx.bezierCurveTo(x + curve.bx * rx, y + curve.by * ry, x + curve.cx * rx, y + curve.cy * ry, x + curve.dx * rx, y + curve.dy * ry); 52981 }); 52982 52983 if (mode === constants.PIE || mode == null) { 52984 ctx.lineTo(x, y); 52985 } 52986 52987 ctx.closePath(); 52988 ctx.fill(); 52989 } // Stroke curves 52990 52991 52992 if (this._doStroke) { 52993 ctx.beginPath(); 52994 curves.forEach(function (curve, index) { 52995 if (index === 0) { 52996 ctx.moveTo(x + curve.ax * rx, y + curve.ay * ry); 52997 } // prettier-ignore 52998 52999 53000 ctx.bezierCurveTo(x + curve.bx * rx, y + curve.by * ry, x + curve.cx * rx, y + curve.cy * ry, x + curve.dx * rx, y + curve.dy * ry); 53001 }); 53002 53003 if (mode === constants.PIE) { 53004 ctx.lineTo(x, y); 53005 ctx.closePath(); 53006 } else if (mode === constants.CHORD) { 53007 ctx.closePath(); 53008 } 53009 53010 ctx.stroke(); 53011 } 53012 53013 return this; 53014 }; 53015 53016 p5.Renderer2D.prototype.ellipse = function (args) { 53017 var ctx = this.drawingContext; 53018 var doFill = this._doFill, 53019 doStroke = this._doStroke; 53020 var x = args[0], 53021 y = args[1], 53022 w = args[2], 53023 h = args[3]; 53024 53025 if (doFill && !doStroke) { 53026 if (this._getFill() === styleEmpty) { 53027 return this; 53028 } 53029 } else if (!doFill && doStroke) { 53030 if (this._getStroke() === styleEmpty) { 53031 return this; 53032 } 53033 } 53034 53035 var kappa = 0.5522847498, 53036 ox = w / 2 * kappa, 53037 // control point offset horizontal 53038 oy = h / 2 * kappa, 53039 // control point offset vertical 53040 xe = x + w, 53041 // x-end 53042 ye = y + h, 53043 // y-end 53044 xm = x + w / 2, 53045 // x-middle 53046 ym = y + h / 2; // y-middle 53047 53048 ctx.beginPath(); 53049 ctx.moveTo(x, ym); 53050 ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); 53051 ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); 53052 ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); 53053 ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); 53054 ctx.closePath(); 53055 53056 if (doFill) { 53057 ctx.fill(); 53058 } 53059 53060 if (doStroke) { 53061 ctx.stroke(); 53062 } 53063 }; 53064 53065 p5.Renderer2D.prototype.line = function (x1, y1, x2, y2) { 53066 var ctx = this.drawingContext; 53067 53068 if (!this._doStroke) { 53069 return this; 53070 } else if (this._getStroke() === styleEmpty) { 53071 return this; 53072 } // Translate the line by (0.5, 0.5) to draw it crisp 53073 53074 53075 if (ctx.lineWidth % 2 === 1) { 53076 ctx.translate(0.5, 0.5); 53077 } 53078 53079 ctx.beginPath(); 53080 ctx.moveTo(x1, y1); 53081 ctx.lineTo(x2, y2); 53082 ctx.stroke(); 53083 53084 if (ctx.lineWidth % 2 === 1) { 53085 ctx.translate(-0.5, -0.5); 53086 } 53087 53088 return this; 53089 }; 53090 53091 p5.Renderer2D.prototype.point = function (x, y) { 53092 var ctx = this.drawingContext; 53093 53094 if (!this._doStroke) { 53095 return this; 53096 } else if (this._getStroke() === styleEmpty) { 53097 return this; 53098 } 53099 53100 var s = this._getStroke(); 53101 53102 var f = this._getFill(); 53103 53104 x = Math.round(x); 53105 y = Math.round(y); // swapping fill color to stroke and back after for correct point rendering 53106 53107 this._setFill(s); 53108 53109 if (ctx.lineWidth > 1) { 53110 ctx.beginPath(); 53111 ctx.arc(x, y, ctx.lineWidth / 2, 0, constants.TWO_PI, false); 53112 ctx.fill(); 53113 } else { 53114 ctx.fillRect(x, y, 1, 1); 53115 } 53116 53117 this._setFill(f); 53118 }; 53119 53120 p5.Renderer2D.prototype.quad = function (x1, y1, x2, y2, x3, y3, x4, y4) { 53121 var ctx = this.drawingContext; 53122 var doFill = this._doFill, 53123 doStroke = this._doStroke; 53124 53125 if (doFill && !doStroke) { 53126 if (this._getFill() === styleEmpty) { 53127 return this; 53128 } 53129 } else if (!doFill && doStroke) { 53130 if (this._getStroke() === styleEmpty) { 53131 return this; 53132 } 53133 } 53134 53135 ctx.beginPath(); 53136 ctx.moveTo(x1, y1); 53137 ctx.lineTo(x2, y2); 53138 ctx.lineTo(x3, y3); 53139 ctx.lineTo(x4, y4); 53140 ctx.closePath(); 53141 53142 if (doFill) { 53143 ctx.fill(); 53144 } 53145 53146 if (doStroke) { 53147 ctx.stroke(); 53148 } 53149 53150 return this; 53151 }; 53152 53153 p5.Renderer2D.prototype.rect = function (args) { 53154 var x = args[0], 53155 y = args[1], 53156 w = args[2], 53157 h = args[3], 53158 tl = args[4], 53159 tr = args[5], 53160 br = args[6], 53161 bl = args[7]; 53162 var ctx = this.drawingContext; 53163 var doFill = this._doFill, 53164 doStroke = this._doStroke; 53165 53166 if (doFill && !doStroke) { 53167 if (this._getFill() === styleEmpty) { 53168 return this; 53169 } 53170 } else if (!doFill && doStroke) { 53171 if (this._getStroke() === styleEmpty) { 53172 return this; 53173 } 53174 } // Translate the line by (0.5, 0.5) to draw a crisp rectangle border 53175 53176 53177 if (this._doStroke && ctx.lineWidth % 2 === 1) { 53178 ctx.translate(0.5, 0.5); 53179 } 53180 53181 ctx.beginPath(); 53182 53183 if (typeof tl === 'undefined') { 53184 // No rounded corners 53185 ctx.rect(x, y, w, h); 53186 } else { 53187 // At least one rounded corner 53188 // Set defaults when not specified 53189 if (typeof tr === 'undefined') { 53190 tr = tl; 53191 } 53192 53193 if (typeof br === 'undefined') { 53194 br = tr; 53195 } 53196 53197 if (typeof bl === 'undefined') { 53198 bl = br; 53199 } 53200
53201 var hw = w / 2; 53202 var hh = h / 2; // Clip radii 53203 53204 if (w < 2 * tl) { 53205 tl = hw; 53206 } 53207 53208 if (h < 2 * tl) { 53209 tl = hh; 53210 } 53211 53212 if (w < 2 * tr) { 53213 tr = hw; 53214 } 53215 53216 if (h < 2 * tr) { 53217 tr = hh; 53218 } 53219 53220 if (w < 2 * br) { 53221 br = hw; 53222 } 53223 53224 if (h < 2 * br) { 53225 br = hh; 53226 } 53227 53228 if (w < 2 * bl) { 53229 bl = hw; 53230 } 53231 53232 if (h < 2 * bl) { 53233 bl = hh; 53234 } // Draw shape 53235 53236 53237 ctx.beginPath(); 53238 ctx.moveTo(x + tl, y); 53239 ctx.arcTo(x + w, y, x + w, y + h, tr); 53240 ctx.arcTo(x + w, y + h, x, y + h, br); 53241 ctx.arcTo(x, y + h, x, y, bl); 53242 ctx.arcTo(x, y, x + w, y, tl); 53243 ctx.closePath(); 53244 } 53245 53246 if (this._doFill) { 53247 ctx.fill(); 53248 } 53249 53250 if (this._doStroke) { 53251 ctx.stroke(); 53252 } 53253 53254 if (this._doStroke && ctx.lineWidth % 2 === 1) { 53255 ctx.translate(-0.5, -0.5); 53256 } 53257 53258 return this; 53259 }; 53260 53261 p5.Renderer2D.prototype.triangle = function (args) { 53262 var ctx = this.drawingContext; 53263 var doFill = this._doFill, 53264 doStroke = this._doStroke; 53265 var x1 = args[0], 53266 y1 = args[1]; 53267 var x2 = args[2], 53268 y2 = args[3]; 53269 var x3 = args[4], 53270 y3 = args[5]; 53271 53272 if (doFill && !doStroke) { 53273 if (this._getFill() === styleEmpty) { 53274 return this; 53275 } 53276 } else if (!doFill && doStroke) { 53277 if (this._getStroke() === styleEmpty) { 53278 return this; 53279 } 53280 } 53281 53282 ctx.beginPath(); 53283 ctx.moveTo(x1, y1); 53284 ctx.lineTo(x2, y2); 53285 ctx.lineTo(x3, y3); 53286 ctx.closePath(); 53287 53288 if (doFill) { 53289 ctx.fill(); 53290 } 53291 53292 if (doStroke) { 53293 ctx.stroke(); 53294 } 53295 }; 53296 53297 p5.Renderer2D.prototype.endShape = function (mode, vertices, isCurve, isBezier, isQuadratic, isContour, shapeKind) { 53298 if (vertices.length === 0) { 53299 return this; 53300 } 53301 53302 if (!this._doStroke && !this._doFill) { 53303 return this; 53304 } 53305 53306 var closeShape = mode === constants.CLOSE; 53307 var v; 53308 53309 if (closeShape && !isContour) { 53310 vertices.push(vertices[0]); 53311 } 53312 53313 var i, j; 53314 var numVerts = vertices.length; 53315 53316 if (isCurve && (shapeKind === constants.POLYGON || shapeKind === null)) { 53317 if (numVerts > 3) { 53318 var b = [], 53319 s = 1 - this._curveTightness; 53320 this.drawingContext.beginPath(); 53321 this.drawingContext.moveTo(vertices[1][0], vertices[1][1]); 53322 53323 for (i = 1; i + 2 < numVerts; i++) { 53324 v = vertices[i]; 53325 b[0] = [v[0], v[1]]; 53326 b[1] = [v[0] + (s * vertices[i + 1][0] - s * vertices[i - 1][0]) / 6, v[1] + (s * vertices[i + 1][1] - s * vertices[i - 1][1]) / 6]; 53327 b[2] = [vertices[i + 1][0] + (s * vertices[i][0] - s * vertices[i + 2][0]) / 6, vertices[i + 1][1] + (s * vertices[i][1] - s * vertices[i + 2][1]) / 6]; 53328 b[3] = [vertices[i + 1][0], vertices[i + 1][1]]; 53329 this.drawingContext.bezierCurveTo(b[1][0], b[1][1], b[2][0], b[2][1], b[3][0], b[3][1]); 53330 } 53331 53332 if (closeShape) { 53333 this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); 53334 } 53335 53336 this._doFillStrokeClose(closeShape); 53337 } 53338 } else if (isBezier && (shapeKind === constants.POLYGON || shapeKind === null)) { 53339 this.drawingContext.beginPath(); 53340 53341 for (i = 0; i < numVerts; i++) { 53342 if (vertices[i].isVert) { 53343 if (vertices[i].moveTo) { 53344 this.drawingContext.moveTo(vertices[i][0], vertices[i][1]); 53345 } else { 53346 this.drawingContext.lineTo(vertices[i][0], vertices[i][1]); 53347 } 53348 } else {
53349 this.drawingContext.bezierCurveTo(vertices[i][0], vertices[i][1], vertices[i][2], vertices[i][3], vertices[i][4], vertices[i][5]); 53350 } 53351 } 53352 53353 this._doFillStrokeClose(closeShape); 53354 } else if (isQuadratic && (shapeKind === constants.POLYGON || shapeKind === null)) { 53355 this.drawingContext.beginPath(); 53356 53357 for (i = 0; i < numVerts; i++) { 53358 if (vertices[i].isVert) { 53359 if (vertices[i].moveTo) { 53360 this.drawingContext.moveTo([0], vertices[i][1]); 53361 } else { 53362 this.drawingContext.lineTo(vertices[i][0], vertices[i][1]); 53363 } 53364 } else { 53365 this.drawingContext.quadraticCurveTo(vertices[i][0], vertices[i][1], vertices[i][2], vertices[i][3]); 53366 } 53367 } 53368 53369 this._doFillStrokeClose(closeShape); 53370 } else { 53371 if (shapeKind === constants.POINTS) { 53372 for (i = 0; i < numVerts; i++) { 53373 v = vertices[i]; 53374 53375 if (this._doStroke) { 53376 this._pInst.stroke(v[6]); 53377 } 53378 53379 this._pInst.point(v[0], v[1]); 53380 } 53381 } else if (shapeKind === constants.LINES) { 53382 for (i = 0; i + 1 < numVerts; i += 2) { 53383 v = vertices[i]; 53384 53385 if (this._doStroke) { 53386 this._pInst.stroke(vertices[i + 1][6]); 53387 } 53388 53389 this._pInst.line(v[0], v[1], vertices[i + 1][0], vertices[i + 1][1]); 53390 } 53391 } else if (shapeKind === constants.TRIANGLES) { 53392 for (i = 0; i + 2 < numVerts; i += 3) { 53393 v = vertices[i]; 53394 this.drawingContext.beginPath(); 53395 this.drawingContext.moveTo(v[0], v[1]); 53396 this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); 53397 this.drawingContext.lineTo(vertices[i + 2][0], vertices[i + 2][1]); 53398 this.drawingContext.closePath(); 53399 53400 if (this._doFill) { 53401 this._pInst.fill(vertices[i + 2][5]); 53402 53403 this.drawingContext.fill(); 53404 } 53405 53406 if (this._doStroke) { 53407 this._pInst.stroke(vertices[i + 2][6]); 53408 53409 this.drawingContext.stroke(); 53410 } 53411 } 53412 } else if (shapeKind === constants.TRIANGLE_STRIP) { 53413 for (i = 0; i + 1 < numVerts; i++) { 53414 v = vertices[i]; 53415 this.drawingContext.beginPath(); 53416 this.drawingContext.moveTo(vertices[i + 1][0], vertices[i + 1][1]); 53417 this.drawingContext.lineTo(v[0], v[1]); 53418 53419 if (this._doStroke) { 53420 this._pInst.stroke(vertices[i + 1][6]); 53421 } 53422 53423 if (this._doFill) { 53424 this._pInst.fill(vertices[i + 1][5]); 53425 } 53426 53427 if (i + 2 < numVerts) { 53428 this.drawingContext.lineTo(vertices[i + 2][0], vertices[i + 2][1]); 53429 53430 if (this._doStroke) { 53431 this._pInst.stroke(vertices[i + 2][6]); 53432 } 53433 53434 if (this._doFill) { 53435 this._pInst.fill(vertices[i + 2][5]); 53436 } 53437 } 53438 53439 this._doFillStrokeClose(closeShape); 53440 } 53441 } else if (shapeKind === constants.TRIANGLE_FAN) { 53442 if (numVerts > 2) { 53443 // For performance reasons, try to batch as many of the 53444 // fill and stroke calls as possible. 53445 this.drawingContext.beginPath(); 53446 53447 for (i = 2; i < numVerts; i++) { 53448 v = vertices[i]; 53449 this.drawingContext.moveTo(vertices[0][0], vertices[0][1]); 53450 this.drawingContext.lineTo(vertices[i - 1][0], vertices[i - 1][1]); 53451 this.drawingContext.lineTo(v[0], v[1]); 53452 this.drawingContext.lineTo(vertices[0][0], vertices[0][1]); // If the next colour is going to be different, stroke / fill now 53453 53454 if (i < numVerts - 1) { 53455 if (this._doFill && v[5] !== vertices[i + 1][5] || this._doStroke && v[6] !== vertices[i + 1][6]) { 53456 if (this._doFill) { 53457 this._pInst.fill(v[5]); 53458 53459 this.drawingContext.fill(); 53460 53461 this._pInst.fill(vertices[i + 1][5]); 53462 } 53463 53464 if (this._doStroke) { 53465 this._pInst.stroke(v[6]); 53466 53467 this.drawingContext.stroke(); 53468 53469 this._pInst.stroke(vertices[i + 1][6]); 53470 } 53471 53472 this.drawingContext.closePath(); 53473 this.drawingContext.beginPath(); // Begin the next one 53474 } 53475 } 53476 } 53477 53478 this._doFillStrokeClose(closeShape); 53479 } 53480 } else if (shapeKind === constants.QUADS) { 53481 for (i = 0; i + 3 < numVerts; i += 4) { 53482 v = vertices[i]; 53483 this.drawingContext.beginPath(); 53484 this.drawingContext.moveTo(v[0], v[1]); 53485 53486 for (j = 1; j < 4; j++) { 53487 this.drawingContext.lineTo(vertices[i + j][0], vertices[i + j][1]); 53488 } 53489 53490 this.drawingContext.lineTo(v[0], v[1]); 53491 53492 if (this._doFill) { 53493 this._pInst.fill(vertices[i + 3][5]); 53494 } 53495 53496 if (this._doStroke) { 53497 this._pInst.stroke(vertices[i + 3][6]); 53498 } 53499 53500 this._doFillStrokeClose(closeShape); 53501 } 53502 } else if (shapeKind === constants.QUAD_STRIP) { 53503 if (numVerts > 3) { 53504 for (i = 0; i + 1 < numVerts; i += 2) { 53505 v = vertices[i]; 53506 this.drawingContext.beginPath(); 53507 53508 if (i + 3 < numVerts) {
53509 this.drawingContext.moveTo(vertices[i + 2][0], vertices[i + 2][1]); 53510 this.drawingContext.lineTo(v[0], v[1]); 53511 this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); 53512 this.drawingContext.lineTo(vertices[i + 3][0], vertices[i + 3][1]); 53513 53514 if (this._doFill) { 53515 this._pInst.fill(vertices[i + 3][5]); 53516 } 53517 53518 if (this._doStroke) { 53519 this._pInst.stroke(vertices[i + 3][6]); 53520 } 53521 } else { 53522 this.drawingContext.moveTo(v[0], v[1]); 53523 this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]); 53524 } 53525 53526 this._doFillStrokeClose(closeShape); 53527 } 53528 } 53529 } else { 53530 this.drawingContext.beginPath(); 53531 this.drawingContext.moveTo(vertices[0][0], vertices[0][1]); 53532 53533 for (i = 1; i < numVerts; i++) { 53534 v = vertices[i]; 53535 53536 if (v.isVert) { 53537 if (v.moveTo) { 53538 this.drawingContext.moveTo(v[0], v[1]); 53539 } else { 53540 this.drawingContext.lineTo(v[0], v[1]); 53541 } 53542 } 53543 } 53544 53545 this._doFillStrokeClose(closeShape); 53546 } 53547 } 53548 53549 isCurve = false; 53550 isBezier = false;
53551 isQuadratic = false; 53552 isContour = false; 53553 53554 if (closeShape) { 53555 vertices.pop(); 53556 } 53557 53558 this._pInst._pixelsDirty = true; 53559 return this; 53560 }; ////////////////////////////////////////////// 53561 // SHAPE | Attributes 53562 ////////////////////////////////////////////// 53563 53564 53565 p5.Renderer2D.prototype.noSmooth = function () { 53566 if ('imageSmoothingEnabled' in this.drawingContext) { 53567 this.drawingContext.imageSmoothingEnabled = false; 53568 } 53569 53570 return this; 53571 }; 53572 53573 p5.Renderer2D.prototype.smooth = function () { 53574 if ('imageSmoothingEnabled' in this.drawingContext) { 53575 this.drawingContext.imageSmoothingEnabled = true; 53576 } 53577 53578 return this; 53579 }; 53580 53581 p5.Renderer2D.prototype.strokeCap = function (cap) { 53582 if (cap === constants.ROUND || cap === constants.SQUARE || cap === constants.PROJECT) { 53583 this.drawingContext.lineCap = cap; 53584 } 53585 53586 return this; 53587 }; 53588 53589 p5.Renderer2D.prototype.strokeJoin = function (join) { 53590 if (join === constants.ROUND || join === constants.BEVEL || join === constants.MITER) { 53591 this.drawingContext.lineJoin = join; 53592 } 53593 53594 return this; 53595 }; 53596 53597 p5.Renderer2D.prototype.strokeWeight = function (w) { 53598 if (typeof w === 'undefined' || w === 0) { 53599 // hack because lineWidth 0 doesn't work 53600 this.drawingContext.lineWidth = 0.0001; 53601 } else { 53602 this.drawingContext.lineWidth = w; 53603 } 53604 53605 return this; 53606 }; 53607 53608 p5.Renderer2D.prototype._getFill = function () { 53609 if (!this._cachedFillStyle) { 53610 this._cachedFillStyle = this.drawingContext.fillStyle; 53611 } 53612 53613 return this._cachedFillStyle; 53614 }; 53615 53616 p5.Renderer2D.prototype._setFill = function (fillStyle) { 53617 if (fillStyle !== this._cachedFillStyle) { 53618 this.drawingContext.fillStyle = fillStyle; 53619 this._cachedFillStyle = fillStyle; 53620 } 53621 }; 53622 53623 p5.Renderer2D.prototype._getStroke = function () { 53624 if (!this._cachedStrokeStyle) { 53625 this._cachedStrokeStyle = this.drawingContext.strokeStyle; 53626 } 53627 53628 return this._cachedStrokeStyle; 53629 }; 53630 53631 p5.Renderer2D.prototype._setStroke = function (strokeStyle) { 53632 if (strokeStyle !== this._cachedStrokeStyle) { 53633 this.drawingContext.strokeStyle = strokeStyle; 53634 this._cachedStrokeStyle = strokeStyle; 53635 } 53636 }; ////////////////////////////////////////////// 53637 // SHAPE | Curves 53638 ////////////////////////////////////////////// 53639 53640 53641 p5.Renderer2D.prototype.bezier = function (x1, y1, x2, y2, x3, y3, x4, y4) { 53642 this._pInst.beginShape(); 53643 53644 this._pInst.vertex(x1, y1); 53645 53646 this._pInst.bezierVertex(x2, y2, x3, y3, x4, y4); 53647 53648 this._pInst.endShape(); 53649 53650 return this; 53651 }; 53652 53653 p5.Renderer2D.prototype.curve = function (x1, y1, x2, y2, x3, y3, x4, y4) { 53654 this._pInst.beginShape(); 53655 53656 this._pInst.curveVertex(x1, y1); 53657 53658 this._pInst.curveVertex(x2, y2); 53659 53660 this._pInst.curveVertex(x3, y3); 53661 53662 this._pInst.curveVertex(x4, y4); 53663 53664 this._pInst.endShape(); 53665 53666 return this; 53667 }; ////////////////////////////////////////////// 53668 // SHAPE | Vertex 53669 ////////////////////////////////////////////// 53670 53671 53672 p5.Renderer2D.prototype._doFillStrokeClose = function (closeShape) { 53673 if (closeShape) { 53674 this.drawingContext.closePath(); 53675 } 53676 53677 if (this._doFill) { 53678 this.drawingContext.fill(); 53679 } 53680 53681 if (this._doStroke) { 53682 this.drawingContext.stroke(); 53683 } 53684 53685 this._pInst._pixelsDirty = true; 53686 }; ////////////////////////////////////////////// 53687 // TRANSFORM 53688 ////////////////////////////////////////////// 53689 53690 53691 p5.Renderer2D.prototype.applyMatrix = function (a, b, c, d, e, f) { 53692 this.drawingContext.transform(a, b, c, d, e, f); 53693 }; 53694 53695 p5.Renderer2D.prototype.resetMatrix = function () { 53696 this.drawingContext.setTransform(1, 0, 0, 1, 0, 0); 53697 this.drawingContext.scale(this._pInst._pixelDensity, this._pInst._pixelDensity); 53698 return this; 53699 }; 53700 53701 p5.Renderer2D.prototype.rotate = function (rad) { 53702 this.drawingContext.rotate(rad); 53703 }; 53704 53705 p5.Renderer2D.prototype.scale = function (x, y) { 53706 this.drawingContext.scale(x, y); 53707 return this; 53708 }; 53709 53710 p5.Renderer2D.prototype.shearX = function (rad) { 53711 this.drawingContext.transform(1, 0, Math.tan(rad), 1, 0, 0); 53712 return this; 53713 }; 53714 53715 p5.Renderer2D.prototype.shearY = function (rad) { 53716 this.drawingContext.transform(1, Math.tan(rad), 0, 1, 0, 0); 53717 return this; 53718 }; 53719 53720 p5.Renderer2D.prototype.translate = function (x, y) { 53721 // support passing a vector as the 1st parameter 53722 if (x instanceof p5.Vector) { 53723 y = x.y; 53724 x = x.x; 53725 } 53726 53727 this.drawingContext.translate(x, y); 53728 return this; 53729 }; ////////////////////////////////////////////// 53730 // TYPOGRAPHY 53731 //
53732 ////////////////////////////////////////////// 53733 53734 53735 p5.Renderer2D.prototype.text = function (str, x, y, maxWidth, maxHeight) { 53736 var baselineHacked; // baselineHacked: (HACK) 53737 // A temporary fix to conform to Processing's implementation 53738 // of BASELINE vertical alignment in a bounding box 53739 53740 if (typeof maxWidth !== 'undefined' && typeof maxHeight !== 'undefined') { 53741 if (this.drawingContext.textBaseline === constants.BASELINE) { 53742 baselineHacked = true; 53743 this.drawingContext.textBaseline = constants.TOP; 53744 } 53745 } 53746 53747 var p = p5.Renderer.prototype.text.apply(this, arguments); 53748 53749 if (baselineHacked) { 53750 this.drawingContext.textBaseline = constants.BASELINE; 53751 } 53752 53753 return p; 53754 }; 53755 53756 p5.Renderer2D.prototype._renderText = function (p, line, x, y, maxY) { 53757 if (y >= maxY) { 53758 return; // don't render lines beyond our maxY position 53759 } 53760 53761 p.push(); // fix to #803 53762 53763 if (!this._isOpenType()) { 53764 // a system/browser font 53765 // no stroke unless specified by user 53766 if (this._doStroke && this._strokeSet) { 53767 this.drawingContext.strokeText(line, x, y); 53768 } 53769 53770 if (this._doFill) { 53771 // if fill hasn't been set by user, use default text fill 53772 if (!this._fillSet) { 53773 this._setFill(constants._DEFAULT_TEXT_FILL); 53774 } 53775 53776 this.drawingContext.fillText(line, x, y); 53777 } 53778 } else { 53779 // an opentype font, let it handle the rendering 53780 this._textFont._renderPath(line, x, y, { 53781 renderer: this 53782 }); 53783 } 53784 53785 p.pop(); 53786 this._pInst._pixelsDirty = true; 53787 return p; 53788 }; 53789 53790 p5.Renderer2D.prototype.textWidth = function (s) { 53791 if (this._isOpenType()) { 53792 return this._textFont._textWidth(s, this._textSize); 53793 } 53794 53795 return this.drawingContext.measureText(s).width; 53796 }; 53797 53798 p5.Renderer2D.prototype._applyTextProperties = function () { 53799 var font, 53800 p = this._pInst; 53801 53802 this._setProperty('_textAscent', null); 53803 53804 this._setProperty('_textDescent', null); 53805 53806 font = this._textFont; 53807 53808 if (this._isOpenType()) { 53809 font = this._textFont.font.familyName; 53810 53811 this._setProperty('_textStyle', this._textFont.font.styleName); 53812 } 53813 53814 this.drawingContext.font = (this._textStyle || 'normal') + ' ' + (this._textSize || 12) + 'px ' + (font || 'sans-serif'); 53815 this.drawingContext.textAlign = this._textAlign; 53816 53817 if (this._textBaseline === constants.CENTER) { 53818 this.drawingContext.textBaseline = constants._CTX_MIDDLE; 53819 } else { 53820 this.drawingContext.textBaseline = this._textBaseline; 53821 } 53822 53823 return p; 53824 }; ////////////////////////////////////////////// 53825 // STRUCTURE 53826 ////////////////////////////////////////////// 53827 // a push() operation is in progress. 53828 // the renderer should return a 'style' object that it wishes to 53829 // store on the push stack. 53830 // derived renderers should call the base class' push() method 53831 // to fetch the base style object. 53832 53833 53834 p5.Renderer2D.prototype.push = function () { 53835 this.drawingContext.save(); // get the base renderer style 53836 53837 return p5.Renderer.prototype.push.apply(this); 53838 }; // a pop() operation is in progress 53839 // the renderer is passed the 'style' object that it returned 53840 // from its push() method. 53841 // derived renderers should pass this object to their base 53842 // class' pop method 53843 53844 53845 p5.Renderer2D.prototype.pop = function (style) { 53846 this.drawingContext.restore(); // Re-cache the fill / stroke state 53847 53848 this._cachedFillStyle = this.drawingContext.fillStyle; 53849 this._cachedStrokeStyle = this.drawingContext.strokeStyle; 53850 p5.Renderer.prototype.pop.call(this, style); 53851 }; 53852 53853 module.exports = p5.Renderer2D; 53854 }, { 53855 "../image/filters": 42, 53856 "./constants": 18, 53857 "./main": 24, 53858 "./p5.Renderer": 27 53859 }],
53860 29: [function (_dereq_, module, exports) { 53861 /** 53862 * @module Rendering 53863 * @submodule Rendering 53864 * @for p5 53865 */ 53866 'use strict'; 53867 53868 var p5 = _dereq_('./main'); 53869 53870 var constants = _dereq_('./constants'); 53871 53872 _dereq_('./p5.Graphics'); 53873 53874 _dereq_('./p5.Renderer2D'); 53875 53876 _dereq_('../webgl/p5.RendererGL'); 53877 53878 var defaultId = 'defaultCanvas0'; // this gets set again in createCanvas 53879 53880 var defaultClass = 'p5Canvas'; 53881 /** 53882 * Creates a canvas element in the document, and sets the dimensions of it 53883 * in pixels. This method should be called only once at the start of setup. 53884 * Calling <a href="#/p5/createCanvas">createCanvas</a> more than once in a sketch will result in very 53885 * unpredictable behavior. If you want more than one drawing canvas 53886 * you could use <a href="#/p5/createGraphics">createGraphics</a> (hidden by default but it can be shown). 53887 * <br><br> 53888 * The system variables width and height are set by the parameters passed 53889 * to this function. If <a href="#/p5/createCanvas">createCanvas()</a> is not used, the window will be 53890 * given a default size of 100x100 pixels. 53891 * <br><br> 53892 * For more ways to position the canvas, see the 53893 * <a href='https://github.com/processing/p5.js/wiki/Positioning-your-canvas'> 53894 * positioning the canvas</a> wiki page. 53895 * 53896 * @method createCanvas 53897 * @param {Number} w width of the canvas 53898 * @param {Number} h height of the canvas 53899 * @param {Constant} [renderer] either P2D or WEBGL 53900 * @return {p5.Renderer} 53901 * @example 53902 * <div> 53903 * <code> 53904 * function setup() { 53905 * createCanvas(100, 50); 53906 * background(153); 53907 * line(0, 0, width, height); 53908 * } 53909 * </code> 53910 * </div> 53911 * 53912 * @alt 53913 * Black line extending from top-left of canvas to bottom right. 53914 * 53915 */ 53916 53917 p5.prototype.createCanvas = function (w, h, renderer) { 53918 p5._validateParameters('createCanvas', arguments); //optional: renderer, otherwise defaults to p2d 53919 53920 53921 var r = renderer || constants.P2D; 53922 var c; 53923 53924 if (r === constants.WEBGL) { 53925 c = document.getElementById(defaultId); 53926 53927 if (c) { 53928 //if defaultCanvas already exists 53929 c.parentNode.removeChild(c); //replace the existing defaultCanvas 53930 53931 var thisRenderer = this._renderer; 53932 this._elements = this._elements.filter(function (e) { 53933 return e !== thisRenderer; 53934 }); 53935 } 53936 53937 c = document.createElement('canvas'); 53938 c.id = defaultId; 53939 c.classList.add(defaultClass); 53940 } else { 53941 if (!this._defaultGraphicsCreated) { 53942 c = document.createElement('canvas'); 53943 var i = 0; 53944 53945 while (document.getElementById('defaultCanvas' + i)) { 53946 i++; 53947 } 53948 53949 defaultId = 'defaultCanvas' + i; 53950 c.id = defaultId; 53951 c.classList.add(defaultClass); 53952 } else { 53953 // resize the default canvas if new one is created 53954 c = this.canvas; 53955 } 53956 } // set to invisible if still in setup (to prevent flashing with manipulate) 53957 53958 53959 if (!this._setupDone) { 53960 c.dataset.hidden = true; // tag to show later 53961 53962 c.style.visibility = 'hidden'; 53963 } 53964 53965 if (this._userNode) { 53966 // user input node case 53967 this._userNode.appendChild(c); 53968 } else { 53969 document.body.appendChild(c); 53970 } // Init our graphics renderer 53971 //webgl mode 53972 53973 53974 if (r === constants.WEBGL) { 53975 this._setProperty('_renderer', new p5.RendererGL(c, this, true)); 53976 53977 this._elements.push(this._renderer); 53978 } else { 53979 //P2D mode 53980 if (!this._defaultGraphicsCreated) { 53981 this._setProperty('_renderer', new p5.Renderer2D(c, this, true)); 53982 53983 this._defaultGraphicsCreated = true; 53984 53985 this._elements.push(this._renderer); 53986 } 53987 } 53988 53989 this._renderer.resize(w, h); 53990 53991 this._renderer._applyDefaults(); 53992 53993 return this._renderer; 53994 }; 53995 /** 53996 * Resizes the canvas to given width and height. The canvas will be cleared 53997 * and draw will be called immediately, allowing the sketch to re-render itself 53998 * in the resized canvas. 53999 * @method resizeCanvas 54000 * @param {Number} w width of the canvas 54001 * @param {Number} h height of the canvas 54002 * @param {Boolean} [noRedraw] don't redraw the canvas immediately 54003 * @example 54004 * <div class="norender"><code> 54005 * function setup() { 54006 * createCanvas(windowWidth, windowHeight); 54007 * } 54008 * 54009 * function draw() { 54010 * background(0, 100, 200); 54011 * } 54012 * 54013 * function windowResized() { 54014 * resizeCanvas(windowWidth, windowHeight); 54015 * } 54016 * </code></div> 54017 * 54018 * @alt 54019 * No image displayed. 54020 * 54021 */ 54022 54023 54024 p5.prototype.resizeCanvas = function (w, h, noRedraw) { 54025 p5._validateParameters('resizeCanvas', arguments); 54026 54027 if (this._renderer) { 54028 // save canvas properties 54029 var props = {}; 54030 54031 for (var key in this.drawingContext) { 54032 var val = this.drawingContext[key]; 54033 54034 if (typeof val !== 'object' && typeof val !== 'function') { 54035 props[key] = val; 54036 } 54037 } 54038 54039 this._renderer.resize(w, h); 54040 54041 this.width = w; 54042 this.height = h; // reset canvas properties 54043 54044 for (var savedKey in props) { 54045 try { 54046 this.drawingContext[savedKey] = props[savedKey]; 54047 } catch (err) {// ignore read-only property errors 54048 } 54049 } 54050 54051 if (!noRedraw) { 54052 this.redraw(); 54053 } 54054 } 54055 }; 54056 /** 54057 * Removes the default canvas for a p5 sketch that doesn't 54058 * require a canvas 54059 * @method noCanvas 54060 * @example 54061 * <div> 54062 * <code> 54063 * function setup() { 54064 * noCanvas(); 54065 * } 54066 * </code> 54067 * </div> 54068 * 54069 * @alt 54070 * no image displayed 54071 * 54072 */ 54073 54074 54075 p5.prototype.noCanvas = function () { 54076 if (this.canvas) { 54077 this.canvas.parentNode.removeChild(this.canvas); 54078 } 54079 }; 54080 /** 54081 * Creates and returns a new p5.Renderer object. Use this class if you need 54082 * to draw into an off-screen graphics buffer. The two parameters define the 54083 * width and height in pixels. 54084 * 54085 * @method createGraphics 54086 * @param {Number} w width of the offscreen graphics buffer 54087 * @param {Number} h height of the offscreen graphics buffer 54088 * @param {Constant} [renderer] either P2D or WEBGL 54089 * undefined defaults to p2d 54090 * @return {p5.Graphics} offscreen graphics buffer 54091 * @example 54092 * <div> 54093 * <code> 54094 * let pg; 54095 * function setup() { 54096 * createCanvas(100, 100); 54097 * pg = createGraphics(100, 100); 54098 * } 54099 * function draw() { 54100 * background(200); 54101 * pg.background(100); 54102 * pg.noStroke(); 54103 * pg.ellipse(pg.width / 2, pg.height / 2, 50, 50); 54104 * image(pg, 50, 50); 54105 * image(pg, 0, 0, 50, 50); 54106 * } 54107 * </code> 54108 * </div> 54109 * 54110 * @alt 54111 * 4 grey squares alternating light and dark grey. White quarter circle mid-left. 54112 * 54113 */ 54114 54115 54116 p5.prototype.createGraphics = function (w, h, renderer) { 54117 p5._validateParameters('createGraphics', arguments); 54118 54119 return new p5.Graphics(w, h, renderer, this); 54120 }; 54121 /** 54122 * Blends the pixels in the display window according to the defined mode. 54123 * There is a choice of the following modes to blend the source pixels (A) 54124 * with the ones of pixels already in the display window (B): 54125 * <ul> 54126 * <li><code>BLEND</code> - linear interpolation of colours: C = 54127 * A\*factor + B. This is the default blending mode.</li> 54128 * <li><code>ADD</code> - sum of A and B</li> 54129 * <li><code>DARKEST</code> - only the darkest colour succeeds: C = 54130 * min(A\*factor, B).</li> 54131 * <li><code>LIGHTEST</code> - only the lightest colour succeeds: C = 54132 * max(A\*factor, B).</li> 54133 * <li><code>DIFFERENCE</code> - subtract colors from underlying image.</li> 54134 * <li><code>EXCLUSION</code> - similar to <code>DIFFERENCE</code>, but less 54135 * extreme.</li> 54136 * <li><code>MULTIPLY</code> - multiply the colors, result will always be 54137 * darker.</li> 54138 * <li><code>SCREEN</code> - opposite multiply, uses inverse values of the 54139 * colors.</li> 54140 * <li><code>REPLACE</code> - the pixels entirely replace the others and
54141 * don't utilize alpha (transparency) values.</li> 54142 * <li><code>OVERLAY</code> - mix of <code>MULTIPLY</code> and <code>SCREEN 54143 * </code>. Multiplies dark values, and screens light values.</li> 54144 * <li><code>HARD_LIGHT</code> - <code>SCREEN</code> when greater than 50% 54145 * gray, <code>MULTIPLY</code> when lower.</li> 54146 * <li><code>SOFT_LIGHT</code> - mix of <code>DARKEST</code> and 54147 * <code>LIGHTEST</code>. Works like <code>OVERLAY</code>, but not as harsh. 54148 * </li> 54149 * <li><code>DODGE</code> - lightens light tones and increases contrast, 54150 * ignores darks.</li> 54151 * <li><code>BURN</code> - darker areas are applied, increasing contrast, 54152 * ignores lights.</li> 54153 * </ul> 54154 * 54155 * @method blendMode 54156 * @param {Constant} mode blend mode to set for canvas. 54157 * either BLEND, DARKEST, LIGHTEST, DIFFERENCE, MULTIPLY, 54158 * EXCLUSION, SCREEN, REPLACE, OVERLAY, HARD_LIGHT, 54159 * SOFT_LIGHT, DODGE, BURN, ADD or NORMAL 54160 * @example 54161 * <div> 54162 * <code> 54163 * blendMode(LIGHTEST); 54164 * strokeWeight(30); 54165 * stroke(80, 150, 255); 54166 * line(25, 25, 75, 75); 54167 * stroke(255, 50, 50); 54168 * line(75, 25, 25, 75); 54169 * </code> 54170 * </div> 54171 * <div> 54172 * <code> 54173 * blendMode(MULTIPLY); 54174 * strokeWeight(30); 54175 * stroke(80, 150, 255); 54176 * line(25, 25, 75, 75); 54177 * stroke(255, 50, 50); 54178 * line(75, 25, 25, 75); 54179 * </code> 54180 * </div> 54181 * @alt 54182 * translucent image thick red & blue diagonal rounded lines intersecting center 54183 * Thick red & blue diagonal rounded lines intersecting center. dark at overlap 54184 * 54185 */ 54186 54187 54188 p5.prototype.blendMode = function (mode) { 54189 p5._validateParameters('blendMode', arguments); 54190 54191 if (mode === constants.BLEND || mode === constants.DARKEST || mode === constants.LIGHTEST || mode === constants.DIFFERENCE || mode === constants.MULTIPLY || mode === constants.EXCLUSION || mode === constants.SCREEN || mode === constants.REPLACE || mode === constants.OVERLAY || mode === constants.HARD_LIGHT || mode === constants.SOFT_LIGHT || mode === constants.DODGE || mode === constants.BURN || mode === constants.ADD || mode === constants.NORMAL) { 54192 this._renderer.blendMode(mode); 54193 } else { 54194 throw new Error('Mode ' + mode + ' not recognized.'); 54195 } 54196 }; 54197 54198 module.exports = p5; 54199 }, {
54200 "../webgl/p5.RendererGL": 74, 54201 "./constants": 18, 54202 "./main": 24, 54203 "./p5.Graphics": 26, 54204 "./p5.Renderer2D": 28 54205 }], 54206 30: [function (_dereq_, module, exports) { 54207 /** 54208 * @module Shape 54209 * @submodule 2D Primitives 54210 * @for p5 54211 * @requires core 54212 * @requires constants 54213 */ 54214 'use strict'; 54215 54216 var p5 = _dereq_('../main'); 54217 54218 var constants = _dereq_('../constants'); 54219 54220 var canvas = _dereq_('../helpers'); 54221 54222 _dereq_('../error_helpers'); 54223 /** 54224 * Draw an arc to the screen. If called with only x, y, w, h, start, and 54225 * stop, the arc will be drawn and filled as an open pie segment. If a mode parameter is provided, the arc 54226 * will be filled like an open semi-circle (OPEN) , a closed semi-circle (CHORD), or as a closed pie segment (PIE). The 54227 * origin may be changed with the <a href="#/p5/ellipseMode">ellipseMode()</a> function.<br><br> 54228 * Note that drawing a full circle (ex: 0 to TWO_PI) will appear blank 54229 * because 0 and TWO_PI are the same position on the unit circle. The 54230 * best way to handle this is by using the <a href="#/p5/ellipse">ellipse()</a> function instead 54231 * to create a closed ellipse, and to use the <a href="#/p5/arc">arc()</a> function 54232 * only to draw parts of an ellipse. 54233 * 54234 * @method arc 54235 * @param {Number} x x-coordinate of the arc's ellipse 54236 * @param {Number} y y-coordinate of the arc's ellipse 54237 * @param {Number} w width of the arc's ellipse by default 54238 * @param {Number} h height of the arc's ellipse by default 54239 * @param {Number} start angle to start the arc, specified in radians 54240 * @param {Number} stop angle to stop the arc, specified in radians 54241 * @param {Constant} [mode] optional parameter to determine the way of drawing 54242 * the arc. either CHORD, PIE or OPEN 54243 * @param {Number} [detail] optional parameter for WebGL mode only. This is to 54244 * specify the number of vertices that makes up the 54245 * perimeter of the arc. Default value is 25. 54246 * 54247 * @chainable 54248 * @example 54249 * <div> 54250 * <code> 54251 * arc(50, 55, 50, 50, 0, HALF_PI); 54252 * noFill(); 54253 * arc(50, 55, 60, 60, HALF_PI, PI); 54254 * arc(50, 55, 70, 70, PI, PI + QUARTER_PI); 54255 * arc(50, 55, 80, 80, PI + QUARTER_PI, TWO_PI); 54256 * </code> 54257 * </div> 54258 * 54259 * <div> 54260 * <code> 54261 * arc(50, 50, 80, 80, 0, PI + QUARTER_PI); 54262 * </code> 54263 * </div> 54264 * 54265 * <div> 54266 * <code> 54267 * arc(50, 50, 80, 80, 0, PI + QUARTER_PI, OPEN); 54268 * </code> 54269 * </div> 54270 * 54271 * <div> 54272 * <code> 54273 * arc(50, 50, 80, 80, 0, PI + QUARTER_PI, CHORD); 54274 * </code> 54275 * </div> 54276 * 54277 * <div> 54278 * <code> 54279 * arc(50, 50, 80, 80, 0, PI + QUARTER_PI, PIE); 54280 * </code> 54281 * </div> 54282 * 54283 * @alt 54284 *shattered outline of an ellipse with a quarter of a white circle bottom-right. 54285 *white ellipse with top right quarter missing. 54286 *white ellipse with black outline with top right missing. 54287 *white ellipse with top right missing with black outline around shape. 54288 *white ellipse with top right quarter missing with black outline around the shape. 54289 * 54290 */ 54291 54292 54293 p5.prototype.arc = function (x, y, w, h, start, stop, mode, detail) { 54294 p5._validateParameters('arc', arguments); // if the current stroke and fill settings wouldn't result in something 54295 // visible, exit immediately 54296 54297 54298 if (!this._renderer._doStroke && !this._renderer._doFill) { 54299 return this; 54300 } 54301 54302 start = this._toRadians(start); 54303 stop = this._toRadians(stop); // Make all angles positive... 54304 54305 while (start < 0) { 54306 start += constants.TWO_PI; 54307 } 54308 54309 while (stop < 0) { 54310 stop += constants.TWO_PI; 54311 } 54312 54313 if (typeof start !== 'undefined' && typeof stop !== 'undefined') { 54314 // don't display anything if the angles are same or they have a difference of 0 - TWO_PI 54315 if (stop.toFixed(10) === start.toFixed(10) || Math.abs(stop - start) === constants.TWO_PI) { 54316 start %= constants.TWO_PI; 54317 stop %= constants.TWO_PI; 54318 start += constants.TWO_PI; 54319 } else if (Math.abs(stop - start) > constants.TWO_PI) { 54320 // display a full circle if the difference between them is greater than 0 - TWO_PI 54321 start %= constants.TWO_PI; 54322 stop %= constants.TWO_PI; 54323 stop += constants.TWO_PI; 54324 } 54325 } //Adjust angles to counter linear scaling. 54326 54327 54328 if (start <= constants.HALF_PI) { 54329 start = Math.atan(w / h * Math.tan(start)); 54330 } else if (start > constants.HALF_PI && start <= 3 * constants.HALF_PI) { 54331 start = Math.atan(w / h * Math.tan(start)) + constants.PI; 54332 } 54333 54334 if (stop <= constants.HALF_PI) { 54335 stop = Math.atan(w / h * Math.tan(stop)); 54336 } else if (stop > constants.HALF_PI && stop <= 3 * constants.HALF_PI) { 54337 stop = Math.atan(w / h * Math.tan(stop)) + constants.PI; 54338 } // Exceed the interval if necessary in order to preserve the size and 54339 // orientation of the arc. 54340 54341 54342 if (start > stop) { 54343 stop += constants.TWO_PI; 54344 } // p5 supports negative width and heights for ellipses 54345 54346 54347 w = Math.abs(w); 54348 h = Math.abs(h); 54349 var vals = canvas.modeAdjust(x, y, w, h, this._renderer._ellipseMode); 54350 54351 this._renderer.arc(vals.x, vals.y, vals.w, vals.h, start, stop, mode, detail); 54352 54353 return this; 54354 }; 54355 /** 54356 * Draws an ellipse (oval) to the screen. An ellipse with equal width and 54357 * height is a circle. By default, the first two parameters set the location, 54358 * and the third and fourth parameters set the shape's width and height. If 54359 * no height is specified, the value of width is used for both the width and 54360 * height. If a negative height or width is specified, the absolute value is taken. 54361 * The origin may be changed with the <a href="#/p5/ellipseMode">ellipseMode()</a> function. 54362 * 54363 * @method ellipse 54364 * @param {Number} x x-coordinate of the ellipse. 54365 * @param {Number} y y-coordinate of the ellipse. 54366 * @param {Number} w width of the ellipse. 54367 * @param {Number} [h] height of the ellipse. 54368 * @chainable 54369 * @example 54370 * <div> 54371 * <code> 54372 * ellipse(56, 46, 55, 55); 54373 * </code> 54374 * </div> 54375 * 54376 * @alt 54377 *white ellipse with black outline in middle-right of canvas that is 55x55. 54378 * 54379 */ 54380 54381 /** 54382 * @method ellipse 54383 * @param {Number} x 54384 * @param {Number} y 54385 * @param {Number} w 54386 * @param {Number} h 54387 * @param {Integer} detail number of radial sectors to draw (for WebGL mode) 54388 */ 54389 54390 54391 p5.prototype.ellipse = function (x, y, w, h, detailX) { 54392 p5._validateParameters('ellipse', arguments); // if the current stroke and fill settings wouldn't result in something 54393 // visible, exit immediately 54394 54395 54396 if (!this._renderer._doStroke && !this._renderer._doFill) { 54397 return this; 54398 } // p5 supports negative width and heights for rects 54399 54400 54401 if (w < 0) { 54402 w = Math.abs(w); 54403 } 54404 54405 if (typeof h === 'undefined') { 54406 // Duplicate 3rd argument if only 3 given. 54407 h = w; 54408 } else if (h < 0) { 54409 h = Math.abs(h); 54410 } 54411 54412 var vals = canvas.modeAdjust(x, y, w, h, this._renderer._ellipseMode); 54413 54414 this._renderer.ellipse([vals.x, vals.y, vals.w, vals.h, detailX]); 54415 54416 return this; 54417 }; 54418 /** 54419 * Draws a circle to the screen. A circle is a simple closed shape. 54420 * It is the set of all points in a plane that are at a given distance from a given point, the centre. 54421 * This function is a special case of the ellipse() function, where the width and height of the ellipse are the same. 54422 * Height and width of the ellipse is equal to twice the radius of the circle.. 54423 * By default, the first two parameters set the location of the centre of the circle, the third sets the radius of the circle. 54424 * 54425 * @method circle 54426 * @param {Number} x x-coordinate of the centre of the circle. 54427 * @param {Number} y y-coordinate of the centre of the circle. 54428 * @param {Number} r radius of the circle. 54429 * @chainable 54430 * @example 54431 * <div> 54432 * <code> 54433 * // Draw a circle at location (30, 30) with a radius of 20. 54434 * circle(30, 30, 20); 54435 * </code> 54436 * </div> 54437 * 54438 * @alt 54439 * white circle with black outline in mid of canvas that is 55x55. 54440 */ 54441 54442 54443 p5.prototype.circle = function () { 54444 var args = Array.prototype.slice.call(arguments, 0, 2); 54445 args.push(2 * arguments[2]); 54446 args.push(2 * arguments[2]); 54447 this.ellipse.apply(this, args); 54448 }; 54449 /** 54450 * Draws a line (a direct path between two points) to the screen. The version 54451 * of <a href="#/p5/line">line()</a> with four parameters draws the line in 2D. To color a line, use 54452 * the <a href="#/p5/stroke">stroke()</a> function. A line cannot be filled, therefore the <a href="#/p5/fill">fill()</a> 54453 * function will not affect the color of a line. 2D lines are drawn with a 54454 * width of one pixel by default, but this can be changed with the 54455 * <a href="#/p5/strokeWeight">
54455strokeWeight()</a> function. 54456 * 54457 * @method line 54458 * @param {Number} x1 the x-coordinate of the first point 54459 * @param {Number} y1 the y-coordinate of the first point 54460 * @param {Number} x2 the x-coordinate of the second point 54461 * @param {Number} y2 the y-coordinate of the second point 54462 * @chainable 54463 * @example 54464 * <div> 54465 * <code> 54466 * line(30, 20, 85, 75); 54467 * </code> 54468 * </div> 54469 * 54470 * <div> 54471 * <code> 54472 * line(30, 20, 85, 20); 54473 * stroke(126); 54474 * line(85, 20, 85, 75); 54475 * stroke(255); 54476 * line(85, 75, 30, 75); 54477 * </code> 54478 * </div> 54479 * 54480 * @alt 54481 *line 78 pixels long running from mid-top to bottom-right of canvas. 54482 *3 lines of various stroke sizes. Form top, bottom and right sides of a square. 54483 * 54484 */ 54485 54486 /** 54487 * @method line 54488 * @param {Number} x1 54489 * @param {Number} y1 54490 * @param {Number} z1 the z-coordinate of the first point 54491 * @param {Number} x2 54492 * @param {Number} y2 54493 * @param {Number} z2 the z-coordinate of the second point 54494 * @chainable 54495 */ 54496 54497 54498 p5.prototype.line = function () { 54499 p5._validateParameters('line', arguments); 54500 54501 if (this._renderer._doStroke) { 54502 this._renderer.line.apply(this._renderer, arguments); 54503 } 54504 54505 return this; 54506 }; 54507 /** 54508 * Draws a point, a coordinate in space at the dimension of one pixel. 54509 * The first parameter is the horizontal value for the point, the second 54510 * value is the vertical value for the point. The color of the point is 54511 * determined by the current stroke. 54512 * 54513 * @method point 54514 * @param {Number} x the x-coordinate 54515 * @param {Number} y the y-coordinate 54516 * @param {Number} [z] the z-coordinate (for WebGL mode) 54517 * @chainable 54518 * @example 54519 * <div> 54520 * <code> 54521 * point(30, 20); 54522 * point(85, 20); 54523 * point(85, 75); 54524 * point(30, 75); 54525 * </code> 54526 * </div> 54527 * 54528 * @alt 54529 *4 points centered in the middle-right of the canvas. 54530 * 54531 */ 54532 54533 54534 p5.prototype.point = function () { 54535 p5._validateParameters('point', arguments); 54536 54537 if (this._renderer._doStroke) { 54538 this._renderer.point.apply(this._renderer, arguments); 54539 } 54540 54541 return this; 54542 }; 54543 /** 54544 * Draw a quad. A quad is a quadrilateral, a four sided polygon. It is 54545 * similar to a rectangle, but the angles between its edges are not 54546 * constrained to ninety degrees. The first pair of parameters (x1,y1) 54547 * sets the first vertex and the subsequent pairs should proceed 54548 * clockwise or counter-clockwise around the defined shape. 54549 * 54550 * @method quad 54551 * @param {Number} x1 the x-coordinate of the first point 54552 * @param {Number} y1 the y-coordinate of the first point 54553 * @param {Number} x2 the x-coordinate of the second point 54554 * @param {Number} y2 the y-coordinate of the second point 54555 * @param {Number} x3 the x-coordinate of the third point 54556 * @param {Number} y3 the y-coordinate of the third point 54557 * @param {Number} x4 the x-coordinate of the fourth point 54558 * @param {Number} y4 the y-coordinate of the fourth point 54559 * @chainable 54560 * @example 54561 * <div> 54562 * <code> 54563 * quad(38, 31, 86, 20, 69, 63, 30, 76); 54564 * </code> 54565 * </div> 54566 * 54567 * @alt 54568 *irregular white quadrilateral shape with black outline mid-right of canvas. 54569 * 54570 */ 54571 54572 /** 54573 * @method quad 54574 * @param {Number} x1 54575 * @param {Number} y1 54576 * @param {Number} z1 the z-coordinate of the first point 54577 * @param {Number} x2 54578 * @param {Number} y2 54579 * @param {Number} z2 the z-coordinate of the second point 54580 * @param {Number} x3 54581 * @param {Number} y3 54582 * @param {Number} z3 the z-coordinate of the third point 54583 * @param {Number} x4 54584 * @param {Number} y4 54585 * @param {Number} z4 the z-coordinate of the fourth point 54586 * @chainable 54587 */ 54588 54589 54590 p5.prototype.quad = function () { 54591 p5._validateParameters('quad', arguments); 54592 54593 if (this._renderer._doStroke || this._renderer._doFill) { 54594 this._renderer.quad.apply(this._renderer, arguments); 54595 } 54596 54597 return this; 54598 }; 54599 /** 54600 * Draws a rectangle to the screen. A rectangle is a four-sided shape with 54601 * every angle at ninety degrees. By default, the first two parameters set 54602 * the location of the upper-left corner, the third sets the width, and the 54603 * fourth sets the height. The way these parameters are interpreted, however, 54604 * may be changed with the <a href="#/p5/rectMode">rectMode()</a> function. 54605 * <br><br> 54606 * The fifth, sixth, seventh and eighth parameters, if specified, 54607 * determine corner radius for the top-left, top-right, lower-right and 54608 * lower-left corners, respectively. An omitted corner radius parameter is set 54609 * to the value of the previously specified radius value in the parameter list. 54610 * 54611 * @method rect 54612 * @param {Number} x x-coordinate of the rectangle. 54613 * @param {Number} y y-coordinate of the rectangle. 54614 * @param {Number} w width of the rectangle. 54615 * @param {Number} h height of the rectangle. 54616 * @param {Number} [tl] optional radius of top-left corner. 54617 * @param {Number} [tr] optional radius of top-right corner. 54618 * @param {Number} [br] optional radius of bottom-right corner. 54619 * @param {Number} [bl] optional radius of bottom-left corner. 54620 * @chainable 54621 * @example 54622 * <div> 54623 * <code> 54624 * // Draw a rectangle at location (30, 20) with a width and height of 55. 54625 * rect(30, 20, 55, 55); 54626 * </code> 54627 * </div> 54628 * 54629 * <div> 54630 * <code> 54631 * // Draw a rectangle with rounded corners, each having a radius of 20. 54632 * rect(30, 20, 55, 55, 20); 54633 * </code> 54634 * </div> 54635 * 54636 * <div> 54637 * <code> 54638 * // Draw a rectangle with rounded corners having the following radii: 54639 * // top-left = 20, top-right = 15, bottom-right = 10, bottom-left = 5. 54640 * rect(30, 20, 55, 55, 20, 15, 10, 5); 54641 * </code> 54642 * </div> 54643 * 54644 * @alt 54645 * 55x55 white rect with black outline in mid-right of canvas. 54646 * 55x55 white rect with black outline and rounded edges in mid-right of canvas. 54647 * 55x55 white rect with black outline and rounded edges of different radii. 54648 */ 54649 54650 /** 54651 * @method rect 54652 * @param {Number} x 54653 * @param {Number} y 54654 * @param {Number} w 54655 * @param {Number} h 54656 * @param {Integer} [detailX] number of segments in the x-direction (for WebGL mode) 54657 * @param {Integer} [detailY] number of segments in the y-direction (for WebGL mode) 54658 * @chainable 54659 */ 54660 54661 54662 p5.prototype.rect = function () { 54663 p5._validateParameters('rect', arguments); 54664 54665 if (this._renderer._doStroke || this._renderer._doFill) { 54666 var vals = canvas.modeAdjust(arguments[0], arguments[1], arguments[2], arguments[3], this._renderer._rectMode); 54667 var args = [vals.x, vals.y, vals.w, vals.h]; // append the additional arguments (either cornder radii, or 54668 // segment details) to the argument list 54669 54670 for (var i = 4; i < arguments.length; i++) { 54671 args[i] = arguments[i]; 54672 } 54673 54674 this._renderer.rect(args); 54675 } 54676 54677 return this; 54678 }; 54679 /**
54680 * Draws a square to the screen. A square is a four-sided shape with 54681 * every angle at ninety degrees, and equal side size. 54682 * This function is a special case of the rect() function, where the width and height are the same, and the parameter is called "s" for side size. 54683 * By default, the first two parameters set the location of the upper-left corner, the third sets the side size of the square. 54684 * The way these parameters are interpreted, however, 54685 * may be changed with the <a href="#/p5/rectMode">rectMode()</a> function. 54686 * <br><br> 54687 * The fourth, fifth, sixth and seventh parameters, if specified, 54688 * determine corner radius for the top-left, top-right, lower-right and 54689 * lower-left corners, respectively. An omitted corner radius parameter is set 54690 * to the value of the previously specified radius value in the parameter list. 54691 * 54692 * @method square 54693 * @param {Number} x x-coordinate of the square. 54694 * @param {Number} y y-coordinate of the square. 54695 * @param {Number} s side size of the square. 54696 * @param {Number} [tl] optional radius of top-left corner. 54697 * @param {Number} [tr] optional radius of top-right corner. 54698 * @param {Number} [br] optional radius of bottom-right corner. 54699 * @param {Number} [bl] optional radius of bottom-left corner. 54700 * @chainable 54701 * @example 54702 * <div> 54703 * <code> 54704 * // Draw a square at location (30, 20) with a side size of 55. 54705 * square(30, 20, 55); 54706 * </code> 54707 * </div> 54708 * 54709 * <div> 54710 * <code> 54711 * // Draw a square with rounded corners, each having a radius of 20. 54712 * square(30, 20, 55, 20); 54713 * </code> 54714 * </div> 54715 * 54716 * <div> 54717 * <code> 54718 * // Draw a square with rounded corners having the following radii: 54719 * // top-left = 20, top-right = 15, bottom-right = 10, bottom-left = 5. 54720 * square(30, 20, 55, 20, 15, 10, 5); 54721 * </code> 54722 * </div> 54723 * 54724 * @alt 54725 * 55x55 white square with black outline in mid-right of canvas. 54726 * 55x55 white square with black outline and rounded edges in mid-right of canvas. 54727 * 55x55 white square with black outline and rounded edges of different radii. 54728 */ 54729 54730 54731 p5.prototype.square = function () { 54732 var args = Array.prototype.slice.call(arguments, 0, 3); 54733 args.push(arguments[2]); 54734 args = args.concat(Array.prototype.slice.call(arguments, 4)); 54735 this.rect.apply(this, args); 54736 }; 54737 /** 54738 * A triangle is a plane created by connecting three points. The first two 54739 * arguments specify the first point, the middle two arguments specify the 54740 * second point, and the last two arguments specify the third point. 54741 * 54742 * @method triangle 54743 * @param {Number} x1 x-coordinate of the first point 54744 * @param {Number} y1 y-coordinate of the first point 54745 * @param {Number} x2 x-coordinate of the second point 54746 * @param {Number} y2 y-coordinate of the second point 54747 * @param {Number} x3 x-coordinate of the third point 54748 * @param {Number} y3 y-coordinate of the third point 54749 * @chainable 54750 * @example 54751 * <div> 54752 * <code> 54753 * triangle(30, 75, 58, 20, 86, 75); 54754 * </code> 54755 * </div> 54756 * 54757 *@alt 54758 * white triangle with black outline in mid-right of canvas. 54759 * 54760 */ 54761 54762 54763 p5.prototype.triangle = function () { 54764 p5._validateParameters('triangle', arguments); 54765 54766 if (this._renderer._doStroke || this._renderer._doFill) { 54767 this._renderer.triangle(arguments); 54768 } 54769 54770 return this; 54771 }; 54772 54773 module.exports = p5; 54774 }, {
54775 "../constants": 18, 54776 "../error_helpers": 20, 54777 "../helpers": 21, 54778 "../main": 24 54779 }], 54780 31: [function (_dereq_, module, exports) { 54781 /** 54782 * @module Shape 54783 * @submodule Attributes 54784 * @for p5 54785 * @requires core 54786 * @requires constants 54787 */ 54788 'use strict'; 54789 54790 var p5 = _dereq_('../main'); 54791 54792 var constants = _dereq_('../constants'); 54793 /** 54794 * Modifies the location from which ellipses are drawn by changing the way 54795 * in which parameters given to <a href="#/p5/ellipse">ellipse()</a> are interpreted. 54796 * <br><br> 54797 * The default mode is ellipseMode(CENTER), which interprets the first two 54798 * parameters of <a href="#/p5/ellipse">ellipse()</a> as the shape's center point, while the third and 54799 * fourth parameters are its width and height. 54800 * <br><br> 54801 * ellipseMode(RADIUS) also uses the first two parameters of <a href="#/p5/ellipse">ellipse()</a> as 54802 * the shape's center point, but uses the third and fourth parameters to 54803 * specify half of the shapes's width and height. 54804 * <br><br> 54805 * ellipseMode(CORNER) interprets the first two parameters of <a href="#/p5/ellipse">ellipse()</a> as 54806 * the upper-left corner of the shape, while the third and fourth parameters 54807 * are its width and height. 54808 * <br><br> 54809 * ellipseMode(CORNERS) interprets the first two parameters of <a href="#/p5/ellipse">ellipse()</a> as 54810 * the location of one corner of the ellipse's bounding box, and the third 54811 * and fourth parameters as the location of the opposite corner. 54812 * <br><br> 54813 * The parameter must be written in ALL CAPS because Javascript is a 54814 * case-sensitive language. 54815 * 54816 * @method ellipseMode 54817 * @param {Constant} mode either CENTER, RADIUS, CORNER, or CORNERS 54818 * @chainable 54819 * @example 54820 * <div> 54821 * <code> 54822 * ellipseMode(RADIUS); // Set ellipseMode to RADIUS 54823 * fill(255); // Set fill to white 54824 * ellipse(50, 50, 30, 30); // Draw white ellipse using RADIUS mode 54825 * 54826 * ellipseMode(CENTER); // Set ellipseMode to CENTER 54827 * fill(100); // Set fill to gray 54828 * ellipse(50, 50, 30, 30); // Draw gray ellipse using CENTER mode 54829 * </code> 54830 * </div> 54831 * 54832 * <div> 54833 * <code> 54834 * ellipseMode(CORNER); // Set ellipseMode is CORNER 54835 * fill(255); // Set fill to white 54836 * ellipse(25, 25, 50, 50); // Draw white ellipse using CORNER mode 54837 * 54838 * ellipseMode(CORNERS); // Set ellipseMode to CORNERS 54839 * fill(100); // Set fill to gray 54840 * ellipse(25, 25, 50, 50); // Draw gray ellipse using CORNERS mode 54841 * </code> 54842 * </div> 54843 * 54844 * @alt 54845 * 60x60 white ellipse and 30x30 grey ellipse with black outlines at center. 54846 * 60x60 white ellipse @center and 30x30 grey ellipse top-right, black outlines. 54847 * 54848 */ 54849 54850 54851 p5.prototype.ellipseMode = function (m) { 54852 p5._validateParameters('ellipseMode', arguments); 54853 54854 if (m === constants.CORNER || m === constants.CORNERS || m === constants.RADIUS || m === constants.CENTER) { 54855 this._renderer._ellipseMode = m; 54856 } 54857 54858 return this; 54859 }; 54860 /** 54861 * Draws all geometry with jagged (aliased) edges. Note that <a href="#/p5/smooth">smooth()</a> is 54862 * active by default in 2D mode, so it is necessary to call <a href="#/p5/noSmooth">noSmooth()</a> to disable 54863 * smoothing of geometry, images, and fonts. In 3D mode, <a href="#/p5/noSmooth">noSmooth()</a> is enabled 54864 * by default, so it is necessary to call <a href="#/p5/smooth">smooth()</a> if you would like 54865 * smooth (antialiased) edges on your geometry. 54866 * 54867 * @method noSmooth 54868 * @chainable 54869 * @example 54870 * <div> 54871 * <code> 54872 * background(0); 54873 * noStroke(); 54874 * smooth(); 54875 * ellipse(30, 48, 36, 36); 54876 * noSmooth(); 54877 * ellipse(70, 48, 36, 36); 54878 * </code> 54879 * </div> 54880 * 54881 * @alt 54882 * 2 pixelated 36x36 white ellipses to left & right of center, black background 54883 * 54884 */ 54885 54886 54887 p5.prototype.noSmooth = function () { 54888 this._renderer.noSmooth(); 54889 54890 return this; 54891 }; 54892 /** 54893 * Modifies the location from which rectangles are drawn by changing the way 54894 * in which parameters given to <a href="#/p5/rect">rect()</a> are interpreted. 54895 * <br><br> 54896 * The default mode is rectMode(CORNER), which interprets the first two 54897 * parameters of <a href="#/p5/rect">rect()</a> as the upper-left corner of the shape, while the 54898 * third and fourth parameters are its width and height. 54899 * <br><br> 54900 * rectMode(CORNERS) interprets the first two parameters of <a href="#/p5/rect">rect()</a> as the 54901 * location of one corner, and the third and fourth parameters as the 54902 * location of the opposite corner. 54903 * <br><br> 54904 * rectMode(CENTER) interprets the first two parameters of <a href="#/p5/rect">rect()</a> as the 54905 * shape's center point, while the third and fourth parameters are its 54906 * width and height. 54907 * <br><br> 54908 * rectMode(RADIUS) also uses the first two parameters of <a href="#/p5/rect">rect()</a> as the 54909 * shape's center point, but uses the third and fourth parameters to
54909specify 54910 * half of the shapes's width and height. 54911 * <br><br> 54912 * The parameter must be written in ALL CAPS because Javascript is a 54913 * case-sensitive language. 54914 * 54915 * @method rectMode 54916 * @param {Constant} mode either CORNER, CORNERS, CENTER, or RADIUS 54917 * @chainable 54918 * @example 54919 * <div> 54920 * <code> 54921 * rectMode(CORNER); // Default rectMode is CORNER 54922 * fill(255); // Set fill to white 54923 * rect(25, 25, 50, 50); // Draw white rect using CORNER mode 54924 * 54925 * rectMode(CORNERS); // Set rectMode to CORNERS 54926 * fill(100); // Set fill to gray 54927 * rect(25, 25, 50, 50); // Draw gray rect using CORNERS mode 54928 * </code> 54929 * </div> 54930 * 54931 * <div> 54932 * <code> 54933 * rectMode(RADIUS); // Set rectMode to RADIUS 54934 * fill(255); // Set fill to white 54935 * rect(50, 50, 30, 30); // Draw white rect using RADIUS mode 54936 * 54937 * rectMode(CENTER); // Set rectMode to CENTER 54938 * fill(100); // Set fill to gray 54939 * rect(50, 50, 30, 30); // Draw gray rect using CENTER mode 54940 * </code> 54941 * </div> 54942 * 54943 * @alt 54944 * 50x50 white rect at center and 25x25 grey rect in the top left of the other. 54945 * 50x50 white rect at center and 25x25 grey rect in the center of the other. 54946 * 54947 */ 54948 54949 54950 p5.prototype.rectMode = function (m) { 54951 p5._validateParameters('rectMode', arguments); 54952 54953 if (m === constants.CORNER || m === constants.CORNERS || m === constants.RADIUS || m === constants.CENTER) { 54954 this._renderer._rectMode = m; 54955 } 54956 54957 return this; 54958 }; 54959 /** 54960 * Draws all geometry with smooth (anti-aliased) edges. <a href="#/p5/smooth">smooth()</a> will also 54961 * improve image quality of resized images. Note that <a href="#/p5/smooth">smooth()</a> is active by 54962 * default in 2D mode; <a href="#/p5/noSmooth">noSmooth()</a> can be used to disable smoothing of geometry, 54963 * images, and fonts. In 3D mode, <a href="#/p5/noSmooth">noSmooth()</a> is enabled 54964 * by default, so it is necessary to call <a href="#/p5/smooth">smooth()</a> if you would like 54965 * smooth (antialiased) edges on your geometry. 54966 * 54967 * @method smooth 54968 * @chainable 54969 * @example 54970 * <div> 54971 * <code> 54972 * background(0); 54973 * noStroke(); 54974 * smooth(); 54975 * ellipse(30, 48, 36, 36); 54976 * noSmooth(); 54977 * ellipse(70, 48, 36, 36); 54978 * </code> 54979 * </div> 54980 * 54981 * @alt 54982 * 2 pixelated 36x36 white ellipses one left one right of center. On black. 54983 * 54984 */ 54985 54986 54987 p5.prototype.smooth = function () { 54988 this._renderer.smooth(); 54989 54990 return this; 54991 }; 54992 /** 54993 * Sets the style for rendering line endings. These ends are either squared, 54994 * extended, or rounded, each of which specified with the corresponding 54995 * parameters: SQUARE, PROJECT, and ROUND. The default cap is ROUND. 54996 * 54997 * @method strokeCap 54998 * @param {Constant} cap either SQUARE, PROJECT, or ROUND 54999 * @chainable 55000 * @example 55001 * <div> 55002 * <code> 55003 * strokeWeight(12.0); 55004 * strokeCap(ROUND); 55005 * line(20, 30, 80, 30); 55006 * strokeCap(SQUARE); 55007 * line(20, 50, 80, 50); 55008 * strokeCap(PROJECT); 55009 * line(20, 70, 80, 70); 55010 * </code> 55011 * </div> 55012 * 55013 * @alt 55014 * 3 lines. Top line: rounded ends, mid: squared, bottom:longer squared ends. 55015 * 55016 */ 55017 55018 55019 p5.prototype.strokeCap = function (cap) { 55020 p5._validateParameters('strokeCap', arguments); 55021 55022 if (cap === constants.ROUND || cap === constants.SQUARE || cap === constants.PROJECT) { 55023 this._renderer.strokeCap(cap); 55024 } 55025 55026 return this; 55027 }; 55028 /** 55029 * Sets the style of the joints which connect line segments. These joints 55030 * are either mitered, beveled, or rounded and specified with the 55031 * corresponding parameters MITER, BEVEL, and ROUND. The default joint is 55032 * MITER. 55033 * 55034 * @method strokeJoin 55035 * @param {Constant} join either MITER, BEVEL, ROUND 55036 * @chainable 55037 * @example 55038 * <div> 55039 * <code> 55040 * noFill(); 55041 * strokeWeight(10.0); 55042 * strokeJoin(MITER); 55043 * beginShape(); 55044 * vertex(35, 20); 55045 * vertex(65, 50); 55046 * vertex(35, 80); 55047 * endShape(); 55048 * </code> 55049 * </div> 55050 * 55051 * <div> 55052 * <code> 55053 * noFill(); 55054 * strokeWeight(10.0); 55055 * strokeJoin(BEVEL); 55056 * beginShape(); 55057 * vertex(35, 20); 55058 * vertex(65, 50); 55059 * vertex(35, 80); 55060 * endShape(); 55061 * </code> 55062 * </div> 55063 * 55064 * <div> 55065 * <code> 55066 * noFill(); 55067 * strokeWeight(10.0); 55068 * strokeJoin(ROUND); 55069 * beginShape(); 55070 * vertex(35, 20); 55071 * vertex(65, 50); 55072 * vertex(35, 80); 55073 * endShape(); 55074 * </code> 55075 * </div> 55076 * 55077 * @alt 55078 * Right-facing arrowhead shape with pointed tip in center of canvas. 55079 * Right-facing arrowhead shape with flat tip in center of canvas. 55080 * Right-facing arrowhead shape with rounded tip in center of canvas. 55081 * 55082 */ 55083 55084 55085 p5.prototype.strokeJoin = function (join) { 55086 p5._validateParameters('strokeJoin', arguments); 55087 55088 if (join === constants.ROUND || join === constants.BEVEL || join === constants.MITER) { 55089 this._renderer.strokeJoin(join); 55090 } 55091 55092 return this; 55093 }; 55094 /** 55095 * Sets the width of the stroke used for lines, points, and the border 55096 * around shapes. All widths are set in units of pixels. 55097 * 55098 * @method strokeWeight 55099 * @param {Number} weight the weight (in pixels) of the stroke 55100 * @chainable 55101 * @example 55102 * <div> 55103 * <code> 55104 * strokeWeight(1); // Default 55105 * line(20, 20, 80, 20); 55106 * strokeWeight(4); // Thicker 55107 * line(20, 40, 80, 40); 55108 * strokeWeight(10); // Beastly 55109 * line(20, 70, 80, 70); 55110 * </code> 55111 * </div> 55112 * 55113 * @alt 55114 * 3 horizontal black lines. Top line: thin, mid: medium, bottom:thick. 55115 * 55116 */ 55117 55118 55119 p5.prototype.strokeWeight = function (w) { 55120 p5._validateParameters('strokeWeight', arguments); 55121 55122 this._renderer.strokeWeight(w); 55123 55124 return this; 55125 }; 55126 55127 module.exports = p5; 55128 }, {
55129 "../constants": 18, 55130 "../main": 24 55131 }], 55132 32: [function (_dereq_, module, exports) { 55133 /** 55134 * @module Shape 55135 * @submodule Curves 55136 * @for p5 55137 * @requires core 55138 */ 55139 'use strict'; 55140 55141 var p5 = _dereq_('../main'); 55142 55143 _dereq_('../error_helpers'); 55144 /** 55145 * Draws a cubic Bezier curve on the screen. These curves are defined by a 55146 * series of anchor and control points. The first two parameters specify 55147 * the first anchor point and the last two parameters specify the other 55148 * anchor point, which become the first and last points on the curve. The 55149 * middle parameters specify the two control points which define the shape 55150 * of the curve. Approximately speaking, control points "pull" the curve 55151 * towards them.<br /><br />Bezier curves were developed by French 55152 * automotive engineer Pierre Bezier, and are commonly used in computer 55153 * graphics to define gently sloping curves. See also <a href="#/p5/curve">curve()</a>. 55154 * 55155 * @method bezier 55156 * @param {Number} x1 x-coordinate for the first anchor point 55157 * @param {Number} y1 y-coordinate for the first anchor point 55158 * @param {Number} x2 x-coordinate for the first control point 55159 * @param {Number} y2 y-coordinate for the first control point 55160 * @param {Number} x3 x-coordinate for the second control point 55161 * @param {Number} y3 y-coordinate for the second control point 55162 * @param {Number} x4 x-coordinate for the second anchor point 55163 * @param {Number} y4 y-coordinate for the second anchor point 55164 * @chainable 55165 * @example 55166 * <div> 55167 * <code> 55168 * noFill(); 55169 * stroke(255, 102, 0); 55170 * line(85, 20, 10, 10); 55171 * line(90, 90, 15, 80); 55172 * stroke(0, 0, 0); 55173 * bezier(85, 20, 10, 10, 90, 90, 15, 80); 55174 * </code> 55175 * </div> 55176 * 55177 * <div> 55178 * <code> 55179 * background(0, 0, 0); 55180 * noFill(); 55181 * stroke(255); 55182 * bezier(250, 250, 0, 100, 100, 0, 100, 0, 0, 0, 100, 0); 55183 * </code> 55184 * </div> 55185 * 55186 * @alt 55187 * stretched black s-shape in center with orange lines extending from end points. 55188 * stretched black s-shape with 10 5x5 white ellipses along the shape. 55189 * stretched black s-shape with 7 5x5 ellipses and orange lines along the shape. 55190 * stretched black s-shape with 17 small orange lines extending from under shape. 55191 * horseshoe shape with orange ends facing left and black curved center. 55192 * horseshoe shape with orange ends facing left and black curved center. 55193 * Line shaped like right-facing arrow,points move with mouse-x and warp shape. 55194 * horizontal line that hooks downward on the right and 13 5x5 ellipses along it. 55195 * right curving line mid-right of canvas with 7 short lines radiating from it. 55196 */ 55197 55198 /** 55199 * @method bezier 55200 * @param {Number} x1 55201 * @param {Number} y1 55202 * @param {Number} z1 z-coordinate for the first anchor point 55203 * @param {Number} x2 55204 * @param {Number} y2 55205 * @param {Number} z2 z-coordinate for the first control point 55206 * @param {Number} x3 55207 * @param {Number} y3 55208 * @param {Number} z3 z-coordinate for the second control point 55209 * @param {Number} x4 55210 * @param {Number} y4 55211 * @param {Number} z4 z-coordinate for the second anchor point 55212 * @chainable 55213 */ 55214 55215 55216 p5.prototype.bezier = function () { 55217 p5._validateParameters('bezier', arguments); // if the current stroke and fill settings wouldn't result in something 55218 // visible, exit immediately 55219 55220 55221 if (!this._renderer._doStroke && !this._renderer._doFill) { 55222 return this; 55223 } 55224 55225 this._renderer.bezier.apply(this._renderer, arguments); 55226 55227 return this; 55228 }; 55229 /** 55230 * Sets the resolution at which Beziers display. 55231 * 55232 * The default value is 20. 55233 * 55234 * This function is only useful when using the WEBGL renderer 55235 * as the default canvas renderer does not use this information. 55236 * 55237 * @method bezierDetail 55238 * @param {Number} detail resolution of the curves 55239 * @chainable 55240 * @example 55241 * <div modernizr='webgl'> 55242 * <code> 55243 * function setup() { 55244 * createCanvas(100, 100, WEBGL); 55245 * noFill(); 55246 * 55247 * bezierDetail(5); 55248 * } 55249 * 55250 * function draw() { 55251 * background(200); 55252 * 55253 * // prettier-ignore 55254 * bezier(-40, -40, 0, 55255 * 90, -40, 0, 55256 * -90, 40, 0, 55257 * 40, 40, 0); 55258 * } 55259 * </code> 55260 * </div> 55261 * 55262 * @alt 55263 * stretched black s-shape with a low level of bezier detail 55264 * 55265 */ 55266 55267 55268 p5.prototype.bezierDetail = function (d) { 55269 p5._validateParameters('bezierDetail', arguments); 55270 55271 this._bezierDetail = d; 55272 return this; 55273 }; 55274 /** 55275 * Evaluates the Bezier at position t for points a, b, c, d. 55276 * The parameters a and d are the first and last points 55277 * on the curve, and b and c are the control points. 55278 * The final parameter t varies between 0 and 1. 55279 * This can be done once with the x coordinates and a second time 55280 * with the y coordinates to get the location of a bezier curve at t. 55281 * 55282 * @method bezierPoint 55283 * @param {Number} a coordinate of first point on the curve 55284 * @param {Number} b coordinate of first control point 55285 * @param {Number} c coordinate of second control point 55286 * @param {Number} d coordinate of second point on the curve 55287 * @param {Number} t value between 0 and 1 55288 * @return {Number} the value of the Bezier at position t 55289 * @example 55290 * <div> 55291 * <code> 55292 * noFill(); 55293 * let x1 = 85, 55294 x2 = 10, 55295 x3 = 90, 55296 x4 = 15; 55297 * let y1 = 20, 55298 y2 = 10, 55299 y3 = 90, 55300 y4 = 80; 55301 * bezier(x1, y1, x2, y2, x3, y3, x4, y4); 55302 * fill(255); 55303 * let steps = 10; 55304 * for (let i = 0; i <= steps; i++) { 55305 * let t = i / steps; 55306 * let x = bezierPoint(x1, x2, x3, x4, t); 55307 * let y = bezierPoint(y1, y2, y3, y4, t); 55308 * ellipse(x, y, 5, 5); 55309 * } 55310 * </code> 55311 * </div> 55312 * 55313 * @alt 55314 * stretched black s-shape with 17 small orange lines extending from under shape. 55315 * 55316 */ 55317 55318 55319 p5.prototype.bezierPoint = function (a, b, c, d, t) { 55320 p5._validateParameters('bezierPoint', arguments); 55321 55322 var adjustedT = 1 - t; 55323 return Math.pow(adjustedT, 3) * a + 3 * Math.pow(adjustedT, 2) * t * b + 3 * adjustedT * Math.pow(t, 2) * c + Math.pow(t, 3) * d; 55324 }; 55325 /** 55326 * Evaluates the tangent to the Bezier at position t for points a, b, c, d. 55327 * The parameters a and d are the first and last points 55328 * on the curve, and b and c are the control points. 55329 * The final parameter t varies between 0 and 1. 55330 * 55331 * @method bezierTangent 55332 * @param {Number} a coordinate of first point on the curve 55333 * @param {Number} b coordinate of first control point 55334 * @param {Number} c coordinate of second control point 55335 * @param {Number} d coordinate of second point on the curve 55336 * @param {Number} t value between 0 and 1 55337 * @return {Number} the tangent at position t 55338 * @example 55339 * <div> 55340 * <code> 55341 * noFill(); 55342 * bezier(85, 20, 10, 10, 90, 90, 15, 80); 55343 * let steps = 6; 55344 * fill(255); 55345 * for (let i = 0; i <= steps; i++) { 55346 * let t = i / steps; 55347 * // Get the location of the point 55348 * let x = bezierPoint(85, 10, 90, 15, t); 55349 * let y = bezierPoint(20, 10, 90, 80, t); 55350 * // Get the tangent points 55351 * let tx = bezierTangent(85, 10, 90, 15, t); 55352 * let ty = bezierTangent(20, 10, 90, 80, t); 55353 * // Calculate an angle from the tangent points 55354 * let a = atan2(ty, tx); 55355 * a += PI; 55356 * stroke(255, 102, 0); 55357 * line(x, y, cos(a) * 30 + x, sin(a) * 30 + y); 55358 * // The following line of code makes a line 55359 * // inverse of the above line 55360 * //line(x, y, cos(a)*-30 + x, sin(a)*-30 + y); 55361 * stroke(0); 55362 * ellipse(x, y, 5, 5); 55363 * } 55364 * </code> 55365 * </div> 55366 * 55367 * <div> 55368 * <code> 55369 * noFill(); 55370 * bezier(85, 20, 10, 10, 90, 90, 15, 80); 55371 * stroke(255, 102, 0); 55372 * let steps = 16; 55373 * for (let i = 0; i <= steps; i++) { 55374 * let t = i / steps; 55375 * let x = bezierPoint(85, 10, 90, 15, t); 55376 * let y = bezierPoint(20, 10, 90, 80, t); 55377 * let tx = bezierTangent(85, 10, 90, 15, t); 55378 * let ty = bezierTangent(20, 10, 90, 80, t); 55379 * let a = atan2(ty, tx); 55380 * a -= HALF_PI; 55381 * line(x, y, cos(a) * 8 + x, sin(a) * 8 + y); 55382 * } 55383 * </code> 55384 * </div> 55385 * 55386 * @alt 55387 * s-shaped line with 17 short orange lines extending from underside of shape 55388 * 55389 */ 55390 55391 55392 p5.prototype.bezierTangent = function (a, b, c, d, t) { 55393 p5._validateParameters('bezierTangent', arguments); 55394 55395 var adjustedT = 1 - t; 55396 return 3 * d * Math.pow(t, 2) - 3 * c * Math.pow(t, 2) + 6 * c * adjustedT * t - 6 * b * adjustedT * t + 3 * b * Math.pow(adjustedT, 2) - 3 * a * Math.pow(adjustedT, 2); 55397 }; 55398 /** 55399 * Draws a curved line on the screen between two points, given as the 55400 * middle four parameters. The first two parameters are a control point, as 55401 * if the curve came from this point even though it's not drawn. The last 55402 * two parameters similarly describe the other control point. <br /><br /> 55403 * Longer curves can be created by putting a series of <a href="#/p5/curve">curve()</a> functions
55404 * together or using <a href="#/p5/curveVertex">curveVertex()</a>. An additional function called 55405 * <a href="#/p5/curveTightness">curveTightness()</a> provides control for the visual quality of the curve. 55406 * The <a href="#/p5/curve">curve()</a> function is an implementation of Catmull-Rom splines. 55407 * 55408 * @method curve 55409 * @param {Number} x1 x-coordinate for the beginning control point 55410 * @param {Number} y1 y-coordinate for the beginning control point 55411 * @param {Number} x2 x-coordinate for the first point 55412 * @param {Number} y2 y-coordinate for the first point 55413 * @param {Number} x3 x-coordinate for the second point 55414 * @param {Number} y3 y-coordinate for the second point 55415 * @param {Number} x4 x-coordinate for the ending control point 55416 * @param {Number} y4 y-coordinate for the ending control point 55417 * @chainable 55418 * @example 55419 * <div> 55420 * <code> 55421 * noFill(); 55422 * stroke(255, 102, 0); 55423 * curve(5, 26, 5, 26, 73, 24, 73, 61); 55424 * stroke(0); 55425 * curve(5, 26, 73, 24, 73, 61, 15, 65); 55426 * stroke(255, 102, 0); 55427 * curve(73, 24, 73, 61, 15, 65, 15, 65); 55428 * </code> 55429 * </div> 55430 * <div> 55431 * <code> 55432 * // Define the curve points as JavaScript objects 55433 * let p1 = { x: 5, y: 26 }, 55434 p2 = { x: 73, y: 24 }; 55435 * let p3 = { x: 73, y: 61 }, 55436 p4 = { x: 15, y: 65 }; 55437 * noFill(); 55438 * stroke(255, 102, 0); 55439 * curve(p1.x, p1.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); 55440 * stroke(0); 55441 * curve(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y); 55442 * stroke(255, 102, 0); 55443 * curve(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, p4.x, p4.y); 55444 * </code> 55445 * </div> 55446 * <div> 55447 * <code> 55448 * noFill(); 55449 * stroke(255, 102, 0); 55450 * curve(5, 26, 0, 5, 26, 0, 73, 24, 0, 73, 61, 0); 55451 * stroke(0); 55452 * curve(5, 26, 0, 73, 24, 0, 73, 61, 0, 15, 65, 0); 55453 * stroke(255, 102, 0); 55454 * curve(73, 24, 0, 73, 61, 0, 15, 65, 0, 15, 65, 0); 55455 * </code> 55456 * </div> 55457 * 55458 * @alt 55459 * horseshoe shape with orange ends facing left and black curved center. 55460 * horseshoe shape with orange ends facing left and black curved center. 55461 * curving black and orange lines. 55462 */ 55463 55464 /** 55465 * @method curve 55466 * @param {Number} x1 55467 * @param {Number} y1 55468 * @param {Number} z1 z-coordinate for the beginning control point 55469 * @param {Number} x2 55470 * @param {Number} y2 55471 * @param {Number} z2 z-coordinate for the first point 55472 * @param {Number} x3 55473 * @param {Number} y3 55474 * @param {Number} z3 z-coordinate for the second point 55475 * @param {Number} x4 55476 * @param {Number} y4 55477 * @param {Number} z4 z-coordinate for the ending control point 55478 * @chainable 55479 */ 55480 55481 55482 p5.prototype.curve = function () { 55483 p5._validateParameters('curve', arguments); 55484 55485 if (this._renderer._doStroke) { 55486 this._renderer.curve.apply(this._renderer, arguments); 55487 } 55488 55489 return this; 55490 }; 55491 /** 55492 * Sets the resolution at which curves display. 55493 * 55494 * The default value is 20 while the minimum value is 3. 55495 * 55496 * This function is only useful when using the WEBGL renderer 55497 * as the default canvas renderer does not use this 55498 * information. 55499 * 55500 * @method curveDetail 55501 * @param {Number} resolution resolution of the curves 55502 * @chainable 55503 * @example 55504 * <div modernizr='webgl'> 55505 * <code> 55506 * function setup() { 55507 * createCanvas(100, 100, WEBGL); 55508 * 55509 * curveDetail(5); 55510 * } 55511 * function draw() { 55512 * background(200); 55513 * 55514 * curve(250, 600, 0, -30, 40, 0, 30, 30, 0, -250, 600, 0); 55515 * } 55516 * </code> 55517 * </div> 55518 * 55519 * @alt 55520 * white arch shape with a low level of curve detail. 55521 * 55522 */ 55523 55524 55525 p5.prototype.curveDetail = function (d) { 55526 p5._validateParameters('curveDetail', arguments); 55527 55528 if (d < 3) { 55529 this._curveDetail = 3; 55530 } else { 55531 this._curveDetail = d; 55532 } 55533 55534 return this; 55535 }; 55536 /** 55537 * Modifies the quality of forms created with <a href="#/p5/curve">curve()</a> and <a href="#/p5/curveVertex">curveVertex()</a>. 55538 * The parameter tightness determines how the curve fits to the vertex 55539 * points. The value 0.0 is the default value for tightness (this value 55540 * defines the curves to be Catmull-Rom splines) and the value 1.0 connects 55541 * all the points with straight lines. Values within the range -5.0 and 5.0 55542 * will deform the curves but will leave them recognizable and as values 55543 * increase in magnitude, they will continue to deform. 55544 * 55545 * @method curveTightness 55546 * @param {Number} amount amount of deformation from the original vertices 55547 * @chainable 55548 * @example 55549 * <div> 55550 * <code> 55551 * // Move the mouse left and right to see the curve change 55552 * 55553 * function setup() { 55554 * createCanvas(100, 100); 55555 * noFill(); 55556 * } 55557 * 55558 * function draw() { 55559 * background(204); 55560 * let t = map(mouseX, 0, width, -5, 5); 55561 * curveTightness(t); 55562 * beginShape(); 55563 * curveVertex(10, 26); 55564 * curveVertex(10, 26); 55565 * curveVertex(83, 24); 55566 * curveVertex(83, 61); 55567 * curveVertex(25, 65); 55568 * curveVertex(25, 65); 55569 * endShape(); 55570 * } 55571 * </code> 55572 * </div> 55573 * 55574 * @alt 55575 * Line shaped like right-facing arrow,points move with mouse-x and warp shape. 55576 */ 55577 55578 55579 p5.prototype.curveTightness = function (t) { 55580 p5._validateParameters('curveTightness', arguments); 55581 55582 this._renderer._curveTightness = t; 55583 return this; 55584 }; 55585 /** 55586 * Evaluates the curve at position t for points a, b, c, d. 55587 * The parameter t varies between 0 and 1, a and d are control points 55588 * of the curve, and b and c are the start and end points of the curve. 55589 * This can be done once with the x coordinates and a second time 55590 * with the y coordinates to get the location of a curve at t. 55591 * 55592 * @method curvePoint 55593 * @param {Number} a coordinate of first control point of the curve 55594 * @param {Number} b coordinate of first point 55595 * @param {Number} c coordinate of second point 55596 * @param {Number} d coordinate of second control point 55597 * @param {Number} t value between 0 and 1 55598 * @return {Number} bezier value at position t 55599 * @example 55600 * <div> 55601 * <code> 55602 * noFill(); 55603 * curve(5, 26, 5, 26, 73, 24, 73, 61); 55604 * curve(5, 26, 73, 24, 73, 61, 15, 65); 55605 * fill(255); 55606 * ellipseMode(CENTER); 55607 * let steps = 6; 55608 * for (let i = 0; i <= steps; i++) { 55609 * let t = i / steps; 55610 * let x = curvePoint(5, 5, 73, 73, t); 55611 * let y = curvePoint(26, 26, 24, 61, t); 55612 * ellipse(x, y, 5, 5); 55613 * x = curvePoint(5, 73, 73, 15, t); 55614 * y = curvePoint(26, 24, 61, 65, t); 55615 * ellipse(x, y, 5, 5); 55616 * } 55617 * </code> 55618 * </div> 55619 * 55620 *line hooking down to right-bottom with 13 5x5 white ellipse points 55621 */ 55622 55623 55624 p5.prototype.curvePoint = function (a, b, c, d, t) { 55625 p5._validateParameters('curvePoint', arguments); 55626 55627 var t3 = t * t * t, 55628 t2 = t * t, 55629 f1 = -0.5 * t3 + t2 - 0.5 * t, 55630 f2 = 1.5 * t3 - 2.5 * t2 + 1.0, 55631 f3 = -1.5 * t3 + 2.0 * t2 + 0.5 * t, 55632 f4 = 0.5 * t3 - 0.5 * t2; 55633 return a * f1 + b * f2 + c * f3 + d * f4; 55634 }; 55635 /** 55636 * Evaluates the tangent to the curve at position t for points a, b, c, d. 55637 * The parameter t varies between 0 and 1, a and d are points on the curve, 55638 * and b and c are the control points. 55639 * 55640 * @method curveTangent 55641 * @param {Number} a coordinate of first point on the curve 55642 * @param {Number} b coordinate of first control point 55643 * @param {Number} c coordinate of second control point 55644 * @param {Number} d coordinate of second point on the curve 55645 * @param {Number} t value between 0 and 1 55646 * @return {Number} the tangent at position t 55647 * @example 55648 * <div> 55649 * <code> 55650 * noFill(); 55651 * curve(5, 26, 73, 24, 73, 61, 15, 65); 55652 * let steps = 6; 55653 * for (let i = 0; i <= steps; i++) { 55654 * let t = i / steps; 55655 * let x = curvePoint(5, 73, 73, 15, t); 55656 * let y = curvePoint(26, 24, 61, 65, t); 55657 * //ellipse(x, y, 5, 5); 55658 * let tx = curveTangent(5, 73, 73, 15, t); 55659 * let ty = curveTangent(26, 24, 61, 65, t); 55660 * let a = atan2(ty, tx); 55661 * a -= PI / 2.0; 55662 * line(x, y, cos(a) * 8 + x, sin(a) * 8 + y); 55663 * } 55664 * </code> 55665 * </div> 55666 * 55667 * @alt 55668 *right curving line mid-right of canvas with 7 short lines radiating from it. 55669 */ 55670 55671 55672 p5.prototype.curveTangent = function (a, b, c, d, t) { 55673 p5._validateParameters('curveTangent', arguments); 55674 55675 var t2 = t * t, 55676 f1 = -3 * t2 / 2 + 2 * t - 0.5, 55677 f2 = 9 * t2 / 2 - 5 * t, 55678 f3 = -9 * t2 / 2 + 4 * t + 0.5, 55679 f4 = 3 * t2 / 2 - t; 55680 return a * f1 + b * f2 + c * f3 + d * f4; 55681 }; 55682 55683 module.exports = p5; 55684 }, {
55685 "../error_helpers": 20, 55686 "../main": 24 55687 }], 55688 33: [function (_dereq_, module, exports) { 55689 /** 55690 * @module Shape 55691 * @submodule Vertex 55692 * @for p5 55693 * @requires core 55694 * @requires constants 55695 */ 55696 'use strict'; 55697 55698 var p5 = _dereq_('../main'); 55699 55700 var constants = _dereq_('../constants'); 55701 55702 var shapeKind = null; 55703 var vertices = []; 55704 var contourVertices = []; 55705 var isBezier = false; 55706 var isCurve = false; 55707 var isQuadratic = false; 55708 var isContour = false; 55709 var isFirstContour = true; 55710 /** 55711 * Use the <a href="#/p5/beginContour">beginContour()</a> and <a href="#/p5/endContour">endContour()</a> functions to create negative 55712 * shapes within shapes such as the center of the letter 'O'. <a href="#/p5/beginContour">beginContour()</a> 55713 * begins recording vertices for the shape and <a href="#/p5/endContour">endContour()</a> stops recording. 55714 * The vertices that define a negative shape must "wind" in the opposite 55715 * direction from the exterior shape. First draw vertices for the exterior 55716 * clockwise order, then for internal shapes, draw vertices 55717 * shape in counter-clockwise. 55718 * <br><br> 55719 * These functions can only be used within a <a href="#/p5/beginShape">beginShape()</a>/<a href="#/p5/endShape">endShape()</a> pair and 55720 * transformations such as <a href="#/p5/translate">translate()</a>, <a href="#/p5/rotate">rotate()</a>, and <a href="#/p5/scale">scale()</a> do not work 55721 * within a <a href="#/p5/beginContour">beginContour()</a>/<a href="#/p5/endContour">endContour()</a> pair. It is also not possible to use 55722 * other shapes, such as <a href="#/p5/ellipse">ellipse()</a> or <a href="#/p5/rect">rect()</a> within. 55723 * 55724 * @method beginContour 55725 * @chainable 55726 * @example 55727 * <div> 55728 * <code> 55729 * translate(50, 50); 55730 * stroke(255, 0, 0); 55731 * beginShape(); 55732 * // Exterior part of shape, clockwise winding 55733 * vertex(-40, -40); 55734 * vertex(40, -40); 55735 * vertex(40, 40); 55736 * vertex(-40, 40); 55737 * // Interior part of shape, counter-clockwise winding 55738 * beginContour(); 55739 * vertex(-20, -20); 55740 * vertex(-20, 20); 55741 * vertex(20, 20); 55742 * vertex(20, -20); 55743 * endContour(); 55744 * endShape(CLOSE); 55745 * </code> 55746 * </div> 55747 * 55748 * @alt 55749 * white rect and smaller grey rect with red outlines in center of canvas. 55750 * 55751 */ 55752 55753 p5.prototype.beginContour = function () { 55754 contourVertices = []; 55755 isContour = true; 55756 return this; 55757 }; 55758 /** 55759 * Using the <a href="#/p5/beginShape">beginShape()</a> and <a href="#/p5/endShape">endShape()</a> functions allow creating more 55760 * complex forms. <a href="#/p5/beginShape">beginShape()</a> begins recording vertices for a shape and 55761 * <a href="#/p5/endShape">endShape()</a> stops recording. The value of the kind parameter tells it which 55762 * types of shapes to create from the provided vertices. With no mode 55763 * specified, the shape can be any irregular polygon. 55764 * <br><br> 55765 * The parameters available for <a href="#/p5/beginShape">beginShape()</a> are POINTS, LINES, TRIANGLES, 55766 * TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, and QUAD_STRIP. After calling the 55767 * <a href="#/p5/beginShape">beginShape()</a> function, a series of <a href="#/p5/vertex">vertex()</a> commands must follow. To stop 55768 * drawing the shape, call <a href="#/p5/endShape">endShape()</a>. Each shape will be outlined with the 55769 * current stroke color and filled with the fill color. 55770 * <br><br> 55771 * Transformations such as <a href="#/p5/translate">translate()</a>, <a href="#/p5/rotate">rotate()</a>, and <a href="#/p5/scale">scale()</a> do not work 55772 * within <a href="#/p5/beginShape">beginShape()</a>. It is also not possible to use other shapes, such as 55773 * <a href="#/p5/ellipse">ellipse()</a> or <a href="#/p5/rect">rect()</a> within <a href="#/p5/beginShape">beginShape()</a>. 55774 * 55775 * @method beginShape 55776 * @param {Constant} [kind] either POINTS, LINES, TRIANGLES, TRIANGLE_FAN 55777 * TRIANGLE_STRIP, QUADS, or QUAD_STRIP 55778 * @chainable 55779 * @example 55780 * <div> 55781 * <code> 55782 * beginShape(); 55783 * vertex(30, 20); 55784 * vertex(85, 20);
55785 * vertex(85, 75); 55786 * vertex(30, 75); 55787 * endShape(CLOSE); 55788 * </code> 55789 * </div> 55790 * 55791 * <div> 55792 * <code> 55793 * beginShape(POINTS); 55794 * vertex(30, 20); 55795 * vertex(85, 20); 55796 * vertex(85, 75); 55797 * vertex(30, 75); 55798 * endShape(); 55799 * </code> 55800 * </div> 55801 * 55802 * <div> 55803 * <code> 55804 * beginShape(LINES); 55805 * vertex(30, 20); 55806 * vertex(85, 20); 55807 * vertex(85, 75); 55808 * vertex(30, 75); 55809 * endShape(); 55810 * </code> 55811 * </div> 55812 * 55813 * <div> 55814 * <code> 55815 * noFill(); 55816 * beginShape(); 55817 * vertex(30, 20); 55818 * vertex(85, 20); 55819 * vertex(85, 75); 55820 * vertex(30, 75); 55821 * endShape(); 55822 * </code> 55823 * </div> 55824 * 55825 * <div> 55826 * <code> 55827 * noFill(); 55828 * beginShape(); 55829 * vertex(30, 20); 55830 * vertex(85, 20); 55831 * vertex(85, 75); 55832 * vertex(30, 75); 55833 * endShape(CLOSE); 55834 * </code> 55835 * </div> 55836 * 55837 * <div> 55838 * <code> 55839 * beginShape(TRIANGLES); 55840 * vertex(30, 75); 55841 * vertex(40, 20); 55842 * vertex(50, 75); 55843 * vertex(60, 20); 55844 * vertex(70, 75); 55845 * vertex(80, 20); 55846 * endShape(); 55847 * </code> 55848 * </div> 55849 * 55850 * <div> 55851 * <code> 55852 * beginShape(TRIANGLE_STRIP); 55853 * vertex(30, 75); 55854 * vertex(40, 20); 55855 * vertex(50, 75); 55856 * vertex(60, 20); 55857 * vertex(70, 75); 55858 * vertex(80, 20); 55859 * vertex(90, 75); 55860 * endShape(); 55861 * </code> 55862 * </div> 55863 * 55864 * <div> 55865 * <code> 55866 * beginShape(TRIANGLE_FAN); 55867 * vertex(57.5, 50); 55868 * vertex(57.5, 15); 55869 * vertex(92, 50); 55870 * vertex(57.5, 85); 55871 * vertex(22, 50); 55872 * vertex(57.5, 15); 55873 * endShape(); 55874 * </code> 55875 * </div> 55876 * 55877 * <div> 55878 * <code> 55879 * beginShape(QUADS); 55880 * vertex(30, 20); 55881 * vertex(30, 75); 55882 * vertex(50, 75); 55883 * vertex(50, 20); 55884 * vertex(65, 20); 55885 * vertex(65, 75); 55886 * vertex(85, 75); 55887 * vertex(85, 20); 55888 * endShape(); 55889 * </code> 55890 * </div> 55891 * 55892 * <div> 55893 * <code> 55894 * beginShape(QUAD_STRIP); 55895 * vertex(30, 20); 55896 * vertex(30, 75); 55897 * vertex(50, 20); 55898 * vertex(50, 75); 55899 * vertex(65, 20); 55900 * vertex(65, 75); 55901 * vertex(85, 20); 55902 * vertex(85, 75); 55903 * endShape(); 55904 * </code> 55905 * </div> 55906 * 55907 * <div> 55908 * <code> 55909 * beginShape(); 55910 * vertex(20, 20); 55911 * vertex(40, 20); 55912 * vertex(40, 40); 55913 * vertex(60, 40); 55914 * vertex(60, 60); 55915 * vertex(20, 60); 55916 * endShape(CLOSE); 55917 * </code> 55918 * </div> 55919 * @alt 55920 * white square-shape with black outline in middle-right of canvas. 55921 * 4 black points in a square shape in middle-right of canvas. 55922 * 2 horizontal black lines. In the top-right and bottom-right of canvas. 55923 * 3 line shape with horizontal on top, vertical in middle and horizontal bottom. 55924 * square line shape in middle-right of canvas. 55925 * 2 white triangle shapes mid-right canvas. left one pointing up and right down. 55926 * 5 horizontal interlocking and alternating white triangles in mid-right canvas. 55927 * 4 interlocking white triangles in 45 degree rotated square-shape. 55928 * 2 white rectangle shapes in mid-right canvas. Both 20x55. 55929 * 3 side-by-side white rectangles center rect is smaller in mid-right canvas. 55930 * Thick white l-shape with black outline mid-top-left of canvas. 55931 * 55932 */ 55933 55934 55935 p5.prototype.beginShape = function (kind) { 55936 p5._validateParameters('beginShape', arguments); 55937 55938 if (this._renderer.isP3D) { 55939 this._renderer.beginShape.apply(this._renderer, arguments); 55940 } else { 55941 if (kind === constants.POINTS || kind === constants.LINES || kind === constants.TRIANGLES || kind === constants.TRIANGLE_FAN || kind === constants.TRIANGLE_STRIP || kind === constants.QUADS || kind === constants.QUAD_STRIP) { 55942 shapeKind = kind; 55943 } else { 55944 shapeKind = null; 55945 } 55946 55947 vertices = []; 55948 contourVertices = []; 55949 } 55950 55951 return this; 55952 }; 55953 /** 55954 * Specifies vertex coordinates for Bezier curves. Each call to 55955 * bezierVertex() defines the position of two control points and 55956 * one anchor point of a Bezier curve, adding a new segment to a 55957 * line or shape. For WebGL mode bezierVertex() can be used in 2D 55958 * as well as 3D mode. 2D mode expects 6 parameters, while 3D mode 55959 * expects 9 parameters (including z coordinates). 55960 * <br><br> 55961 * The first time bezierVertex() is used within a <a href="#/p5/beginShape">beginShape()</a> 55962 * call, it must be prefaced with a call to <a href="#/p5/vertex">vertex()</a> to set the first anchor 55963 * point. This function must be used between <a href="#/p5/beginShape">beginShape()</a> and <a href="#/p5/endShape">endShape()</a> 55964 * and only when there is no MODE or POINTS parameter specified to 55965 * <a href="#/p5/beginShape">beginShape()</a>. 55966 * 55967 * @method bezierVertex 55968 * @param {Number} x2 x-coordinate for the first control point 55969 * @param {Number} y2 y-coordinate for the first control point 55970 * @param {Number} x3 x-coordinate for the second control point 55971 * @param {Number} y3 y-coordinate for the second control point 55972 * @param {Number}
55972 x4 x-coordinate for the anchor point 55973 * @param {Number} y4 y-coordinate for the anchor point 55974 * @chainable 55975 * 55976 * @example 55977 * <div> 55978 * <code> 55979 * noFill(); 55980 * beginShape(); 55981 * vertex(30, 20); 55982 * bezierVertex(80, 0, 80, 75, 30, 75); 55983 * endShape(); 55984 * </code> 55985 * </div> 55986 * 55987 * @alt 55988 * crescent-shaped line in middle of canvas. Points facing left. 55989 * 55990 * @example 55991 * <div> 55992 * <code> 55993 * beginShape(); 55994 * vertex(30, 20); 55995 * bezierVertex(80, 0, 80, 75, 30, 75); 55996 * bezierVertex(50, 80, 60, 25, 30, 20); 55997 * endShape(); 55998 * </code> 55999 * </div> 56000 * 56001 * @alt 56002 * white crescent shape in middle of canvas. Points facing left. 56003 * 56004 * @example 56005 * <div> 56006 * <code> 56007 * function setup() { 56008 * createCanvas(100, 100, WEBGL); 56009 * setAttributes('antialias', true); 56010 * } 56011 * function draw() { 56012 * orbitControl(); 56013 * background(50); 56014 * strokeWeight(4); 56015 * stroke(255); 56016 * point(-25, 30); 56017 * point(25, 30); 56018 * point(25, -30); 56019 * point(-25, -30); 56020 * 56021 * strokeWeight(1); 56022 * noFill(); 56023 * 56024 * beginShape(); 56025 * vertex(-25, 30); 56026 * bezierVertex(25, 30, 25, -30, -25, -30); 56027 * endShape(); 56028 * 56029 * beginShape(); 56030 * vertex(-25, 30, 20); 56031 * bezierVertex(25, 30, 20, 25, -30, 20, -25, -30, 20); 56032 * endShape(); 56033 * } 56034 * </code> 56035 * </div> 56036 * 56037 * @alt 56038 * crescent shape in middle of canvas with another crescent shape on positive z-axis. 56039 */ 56040 56041 /** 56042 * @method bezierVertex 56043 * @param {Number} x2 56044 * @param {Number} y2 56045 * @param {Number} z2 z-coordinate for the first control point (for WebGL mode) 56046 * @param {Number} x3 56047 * @param {Number} y3 56048 * @param {Number} z3 z-coordinate for the second control point (for WebGL mode) 56049 * @param {Number} x4 56050 * @param {Number} y4 56051 * @param {Number} z4 z-coordinate for the anchor point (for WebGL mode) 56052 * @chainable 56053 */ 56054 56055 56056 p5.prototype.bezierVertex = function () { 56057 p5._validateParameters('bezierVertex', arguments); 56058 56059 if (this._renderer.isP3D) { 56060 this._renderer.bezierVertex.apply(this._renderer, arguments); 56061 } else { 56062 if (vertices.length === 0) { 56063 p5._friendlyError('vertex() must be used once before calling bezierVertex()', 'bezierVertex'); 56064 } else { 56065 isBezier = true; 56066 var vert = []; 56067 56068 for (var i = 0; i < arguments.length; i++) { 56069 vert[i] = arguments[i]; 56070 } 56071 56072 vert.isVert = false; 56073 56074 if (isContour) { 56075 contourVertices.push(vert); 56076 } else { 56077 vertices.push(vert); 56078 } 56079 } 56080 } 56081 56082 return this; 56083 }; 56084 /** 56085 * Specifies vertex coordinates for curves. This function may only 56086 * be used between <a href="#/p5/beginShape">beginShape()</a> and <a href="#/p5/endShape">endShape()</a> and only when there 56087 * is no MODE parameter specified to <a href="#/p5/beginShape">beginShape()</a>. 56088 * For WebGL mode curveVertex() can be used in 2D as well as 3D mode. 56089 * 2D mode expects 2 parameters, while 3D mode expects 3 parameters. 56090 * <br><br> 56091 * The first and last points in a series of curveVertex() lines will be used to 56092 * guide the beginning and end of a the curve. A minimum of four 56093 * points is required to draw a tiny curve between the second and 56094 * third points. Adding a fifth point with curveVertex() will draw 56095 * the curve between the second, third, and fourth points. The 56096 * curveVertex() function is an implementation of Catmull-Rom 56097 * splines. 56098 * 56099 * @method curveVertex 56100 * @param {Number} x x-coordinate of the vertex 56101 * @param {Number} y y-coordinate of the vertex 56102 * @chainable 56103 * @example 56104 * <div> 56105 * <code> 56106 * strokeWeight(5); 56107 * point(84, 91); 56108 * point(68, 19); 56109 * point(21, 17); 56110 * point(32, 91); 56111 * strokeWeight(1); 56112 * 56113 * noFill(); 56114 * beginShape(); 56115 * curveVertex(84, 91); 56116 * curveVertex(84, 91);
56117 * curveVertex(68, 19); 56118 * curveVertex(21, 17); 56119 * curveVertex(32, 91); 56120 * curveVertex(32, 91); 56121 * endShape(); 56122 * </code> 56123 * </div> 56124 * 56125 * 56126 * @alt 56127 * Upside-down u-shape line, mid canvas. left point extends beyond canvas view. 56128 */ 56129 56130 /** 56131 * @method curveVertex 56132 * @param {Number} x 56133 * @param {Number} y 56134 * @param {Number} [z] z-coordinate of the vertex (for WebGL mode) 56135 * @chainable 56136 * @example 56137 * <div> 56138 * <code> 56139 * function setup() { 56140 * createCanvas(100, 100, WEBGL); 56141 * setAttributes('antialias', true); 56142 * } 56143 * function draw() { 56144 * orbitControl(); 56145 * background(50); 56146 * strokeWeight(4); 56147 * stroke(255); 56148 * 56149 * point(-25, 25); 56150 * point(-25, 25); 56151 * point(-25, -25); 56152 * point(25, -25); 56153 * point(25, 25); 56154 * point(25, 25); 56155 * 56156 * strokeWeight(1); 56157 * noFill(); 56158 * 56159 * beginShape(); 56160 * curveVertex(-25, 25); 56161 * curveVertex(-25, 25); 56162 * curveVertex(-25, -25); 56163 * curveVertex(25, -25); 56164 * curveVertex(25, 25); 56165 * curveVertex(25, 25); 56166 * endShape(); 56167 * 56168 * beginShape(); 56169 * curveVertex(-25, 25, 20); 56170 * curveVertex(-25, 25, 20); 56171 * curveVertex(-25, -25, 20); 56172 * curveVertex(25, -25, 20); 56173 * curveVertex(25, 25, 20); 56174 * curveVertex(25, 25, 20); 56175 * endShape(); 56176 * } 56177 * </code> 56178 * </div> 56179 * 56180 * @alt 56181 * Upside-down u-shape line, mid canvas with the same shape in positive z-axis. 56182 * 56183 */ 56184 56185 56186 p5.prototype.curveVertex = function () { 56187 p5._validateParameters('curveVertex', arguments); 56188 56189 if (this._renderer.isP3D) { 56190 this._renderer.curveVertex.apply(this._renderer, arguments); 56191 } else { 56192 isCurve = true; 56193 this.vertex(arguments[0], arguments[1]); 56194 } 56195 56196 return this; 56197 }; 56198 /** 56199 * Use the <a href="#/p5/beginContour">beginContour()</a> and <a href="#/p5/endContour">endContour()</a> functions to create negative 56200 * shapes within shapes such as the center of the letter 'O'. <a href="#/p5/beginContour">beginContour()</a> 56201 * begins recording vertices for the shape and <a href="#/p5/endContour">endContour()</a> stops recording. 56202 * The vertices that define a negative shape must "wind" in the opposite 56203 * direction from the exterior shape. First draw vertices for the exterior 56204 * clockwise order, then for internal shapes, draw vertices 56205 * shape in counter-clockwise. 56206 * <br><br> 56207 * These functions can only be used within a <a href="#/p5/beginShape">beginShape()</a>/<a href="#/p5/endShape">endShape()</a> pair and 56208 * transformations such as <a href="#/p5/translate">translate()</a>, <a href="#/p5/rotate">rotate()</a>, and <a href="#/p5/scale">scale()</a> do not work 56209 * within a <a href="#/p5/beginContour">beginContour()</a>/<a href="#/p5/endContour">endContour()</a> pair. It is also not possible to use 56210 * other shapes, such as <a href="#/p5/ellipse">ellipse()</a> or <a href="#/p5/rect">rect()</a> within. 56211 * 56212 * @method endContour 56213 * @chainable 56214 * @example 56215 * <div> 56216 * <code> 56217 * translate(50, 50); 56218 * stroke(255, 0, 0); 56219 * beginShape(); 56220 * // Exterior part of shape, clockwise winding 56221 * vertex(-40, -40); 56222 * vertex(40, -40); 56223 * vertex(40, 40); 56224 * vertex(-40, 40); 56225 * // Interior part of shape, counter-clockwise winding 56226 * beginContour(); 56227 * vertex(-20, -20); 56228 * vertex(-20, 20); 56229 * vertex(20, 20); 56230 * vertex(20, -20); 56231 * endContour(); 56232 * endShape(CLOSE); 56233 * </code> 56234 * </div> 56235 * 56236 * @alt 56237 * white rect and smaller grey rect with red outlines in center of canvas. 56238 * 56239 */ 56240 56241 56242 p5.prototype.endContour = function () { 56243 var vert = contourVertices[0].slice(); // copy all data 56244 56245 vert.isVert = contourVertices[0].isVert; 56246 vert.moveTo = false;
56247 contourVertices.push(vert); // prevent stray lines with multiple contours 56248 56249 if (isFirstContour) { 56250 vertices.push(vertices[0]); 56251 isFirstContour = false; 56252 } 56253 56254 for (var i = 0; i < contourVertices.length; i++) { 56255 vertices.push(contourVertices[i]); 56256 } 56257 56258 return this; 56259 }; 56260 /** 56261 * The <a href="#/p5/endShape">endShape()</a> function is the companion to <a href="#/p5/beginShape">beginShape()</a> and may only be 56262 * called after <a href="#/p5/beginShape">beginShape()</a>. When <a href="#/p5/endshape">endshape()</a> is called, all of image data 56263 * defined since the previous call to <a href="#/p5/beginShape">beginShape()</a> is written into the image 56264 * buffer. The constant CLOSE as the value for the MODE parameter to close 56265 * the shape (to connect the beginning and the end). 56266 * 56267 * @method endShape 56268 * @param {Constant} [mode] use CLOSE to close the shape 56269 * @chainable 56270 * @example 56271 * <div> 56272 * <code> 56273 * noFill(); 56274 * 56275 * beginShape(); 56276 * vertex(20, 20); 56277 * vertex(45, 20); 56278 * vertex(45, 80); 56279 * endShape(CLOSE); 56280 * 56281 * beginShape(); 56282 * vertex(50, 20); 56283 * vertex(75, 20); 56284 * vertex(75, 80); 56285 * endShape(); 56286 * </code> 56287 * </div> 56288 * 56289 * @alt 56290 * Triangle line shape with smallest interior angle on bottom and upside-down L. 56291 * 56292 */ 56293 56294 56295 p5.prototype.endShape = function (mode) { 56296 p5._validateParameters('endShape', arguments); 56297 56298 if (this._renderer.isP3D) { 56299 this._renderer.endShape(mode, isCurve, isBezier, isQuadratic, isContour, shapeKind); 56300 } else { 56301 if (vertices.length === 0) { 56302 return this; 56303 } 56304 56305 if (!this._renderer._doStroke && !this._renderer._doFill) { 56306 return this; 56307 } 56308 56309 var closeShape = mode === constants.CLOSE; // if the shape is closed, the first element is also the last element 56310 56311 if (closeShape && !isContour) { 56312 vertices.push(vertices[0]); 56313 } 56314 56315 this._renderer.endShape(mode, vertices, isCurve, isBezier, isQuadratic, isContour, shapeKind); // Reset some settings 56316 56317 56318 isCurve = false; 56319 isBezier = false;
56320 isQuadratic = false; 56321 isContour = false; 56322 isFirstContour = true; // If the shape is closed, the first element was added as last element. 56323 // We must remove it again to prevent the list of vertices from growing 56324 // over successive calls to endShape(CLOSE) 56325 56326 if (closeShape) { 56327 vertices.pop(); 56328 } 56329 } 56330 56331 return this; 56332 }; 56333 /** 56334 * Specifies vertex coordinates for quadratic Bezier curves. Each call to 56335 * quadraticVertex() defines the position of one control points and one 56336 * anchor point of a Bezier curve, adding a new segment to a line or shape. 56337 * The first time quadraticVertex() is used within a <a href="#/p5/beginShape">beginShape()</a> call, it 56338 * must be prefaced with a call to <a href="#/p5/vertex">vertex()</a> to set the first anchor point. 56339 * For WebGL mode quadraticVertex() can be used in 2D as well as 3D mode. 56340 * 2D mode expects 4 parameters, while 3D mode expects 6 parameters 56341 * (including z coordinates). 56342 * <br><br> 56343 * This function must be used between <a href="#/p5/beginShape">beginShape()</a> and <a href="#/p5/endShape">endShape()</a> 56344 * and only when there is no MODE or POINTS parameter specified to 56345 * <a href="#/p5/beginShape">beginShape()</a>. 56346 * 56347 * @method quadraticVertex 56348 * @param {Number} cx x-coordinate for the control point 56349 * @param {Number} cy y-coordinate for the control point 56350 * @param {Number} x3 x-coordinate for the anchor point 56351 * @param {Number} y3 y-coordinate for the anchor point 56352 * @chainable 56353 * 56354 * @example 56355 * <div> 56356 * <code> 56357 * strokeWeight(5); 56358 * point(20, 20); 56359 * point(80, 20); 56360 * point(50, 50); 56361 * 56362 * noFill(); 56363 * strokeWeight(1); 56364 * beginShape(); 56365 * vertex(20, 20); 56366 * quadraticVertex(80, 20, 50, 50); 56367 * endShape(); 56368 * </code> 56369 * </div> 56370 * 56371 * <div> 56372 * <code> 56373 * strokeWeight(5); 56374 * point(20, 20); 56375 * point(80, 20); 56376 * point(50, 50); 56377 * 56378 * point(20, 80); 56379 * point(80, 80); 56380 * point(80, 60); 56381 * 56382 * noFill(); 56383 * strokeWeight(1); 56384 * beginShape(); 56385 * vertex(20, 20); 56386 * quadraticVertex(80, 20, 50, 50); 56387 * quadraticVertex(20, 80, 80, 80); 56388 * vertex(80, 60); 56389 * endShape(); 56390 * </code> 56391 * </div> 56392 * 56393 * @alt 56394 * arched-shaped black line with 4 pixel thick stroke weight. 56395 * backwards s-shaped black line with 4 pixel thick stroke weight. 56396 * 56397 */ 56398 56399 /** 56400 * @method quadraticVertex 56401 * @param {Number} cx 56402 * @param {Number} cy 56403 * @param {Number} cz z-coordinate for the control point (for WebGL mode) 56404 * @param {Number} x3 56405 * @param {Number} y3 56406 * @param {Number} z3 z-coordinate for the anchor point (for WebGL mode) 56407 * @chainable 56408 * 56409 * @example 56410 * <div> 56411 * <code> 56412 * function setup() { 56413 * createCanvas(100, 100, WEBGL); 56414 * setAttributes('antialias', true); 56415 * } 56416 * function draw() { 56417 * orbitControl(); 56418 * background(50); 56419 * strokeWeight(4); 56420 * stroke(255); 56421 * 56422 * point(-35, -35); 56423 * point(35, -35); 56424 * point(0, 0); 56425 * point(-35, 35); 56426 * point(35, 35); 56427 * point(35, 10); 56428 * 56429 * strokeWeight(1); 56430 * noFill(); 56431 * 56432 * beginShape(); 56433 * vertex(-35, -35); 56434 * quadraticVertex(35, -35, 0, 0); 56435 * quadraticVertex(-35, 35, 35, 35); 56436 * vertex(35, 10); 56437 * endShape(); 56438 * 56439 * beginShape(); 56440 * vertex(-35, -35, 20); 56441 * quadraticVertex(35, -35, 20, 0, 0, 20); 56442 * quadraticVertex(-35, 35, 20, 35, 35, 20); 56443 * vertex(35, 10, 20); 56444 * endShape(); 56445 * } 56446 * </code> 56447 * </div> 56448 * 56449 * @alt 56450 * backwards s-shaped black line with the same s-shaped line in postive z-axis. 56451 */ 56452 56453 56454 p5.prototype.quadraticVertex = function () { 56455 p5._validateParameters('quadraticVertex', arguments); 56456 56457 if (this._renderer.isP3D) { 56458 this._renderer.quadraticVertex.apply(this._renderer, arguments); 56459 } else { 56460 //if we're drawing a contour, put the points into an 56461 // array for inside drawing 56462 if (this._contourInited) { 56463 var pt = {}; 56464 pt.x = arguments[0]; 56465 pt.y = arguments[1]; 56466 pt.x3 = arguments[2]; 56467 pt.y3 = arguments[3]; 56468 pt.type = constants.QUADRATIC; 56469 56470 this._contourVertices.push(pt); 56471 56472 return this; 56473 } 56474 56475 if (vertices.length > 0) { 56476 isQuadratic = true; 56477 var vert = []; 56478 56479 for (var i = 0; i < arguments.length; i++) { 56480 vert[i] = arguments[i]; 56481 } 56482 56483 vert.isVert = false;
56484 56485 if (isContour) { 56486 contourVertices.push(vert); 56487 } else { 56488 vertices.push(vert); 56489 } 56490 } else { 56491 p5._friendlyError('vertex() must be used once before calling quadraticVertex()', 'quadraticVertex'); 56492 } 56493 } 56494 56495 return this; 56496 }; 56497 /** 56498 * All shapes are constructed by connecting a series of vertices. <a href="#/p5/vertex">vertex()</a> 56499 * is used to specify the vertex coordinates for points, lines, triangles, 56500 * quads, and polygons. It is used exclusively within the <a href="#/p5/beginShape">beginShape()</a> and 56501 * <a href="#/p5/endShape">endShape()</a> functions. 56502 * 56503 * @method vertex 56504 * @param {Number} x x-coordinate of the vertex 56505 * @param {Number} y y-coordinate of the vertex 56506 * @chainable 56507 * @example 56508 * <div> 56509 * <code> 56510 * strokeWeight(3); 56511 * beginShape(POINTS); 56512 * vertex(30, 20); 56513 * vertex(85, 20); 56514 * vertex(85, 75); 56515 * vertex(30, 75); 56516 * endShape(); 56517 * </code> 56518 * </div> 56519 * 56520 * @alt 56521 * 4 black points in a square shape in middle-right of canvas. 56522 * 56523 * <div> 56524 * <code> 56525 * createCanvas(100, 100, WEBGL); 56526 * background(240, 240, 240); 56527 * fill(237, 34, 93); 56528 * noStroke(); 56529 * beginShape(); 56530 * vertex(0, 35); 56531 * vertex(35, 0); 56532 * vertex(0, -35); 56533 * vertex(-35, 0); 56534 * endShape(); 56535 * </code> 56536 * </div> 56537 * 56538 * @alt 56539 * 4 points making a diamond shape 56540 * 56541 * <div> 56542 * <code> 56543 * createCanvas(100, 100, WEBGL); 56544 * background(240, 240, 240); 56545 * fill(237, 34, 93); 56546 * noStroke(); 56547 * beginShape(); 56548 * vertex(-10, 10); 56549 * vertex(0, 35); 56550 * vertex(10, 10); 56551 * vertex(35, 0); 56552 * vertex(10, -8); 56553 * vertex(0, -35); 56554 * vertex(-10, -8); 56555 * vertex(-35, 0); 56556 * endShape(); 56557 * </code> 56558 * </div> 56559 * 56560 * @alt 56561 * 8 points making a star 56562 * 56563 * <div> 56564 * <code> 56565 * strokeWeight(3); 56566 * stroke(237, 34, 93); 56567 * beginShape(LINES); 56568 * vertex(10, 35); 56569 * vertex(90, 35); 56570 * vertex(10, 65); 56571 * vertex(90, 65); 56572 * vertex(35, 10); 56573 * vertex(35, 90); 56574 * vertex(65, 10); 56575 * vertex(65, 90); 56576 * endShape(); 56577 * </code> 56578 * </div> 56579 * 56580 * @alt 56581 * 8 points making 4 lines 56582 * 56583 */ 56584 56585 /** 56586 * @method vertex 56587 * @param {Number} x 56588 * @param {Number} y 56589 * @param {Number} z z-coordinate of the vertex 56590 * @param {Number} [u] the vertex's texture u-coordinate 56591 * @param {Number} [v] the vertex's texture v-coordinate 56592 * @chainable 56593 */ 56594 56595 56596 p5.prototype.vertex = function (x, y, moveTo, u, v) { 56597 if (this._renderer.isP3D) { 56598 this._renderer.vertex.apply(this._renderer, arguments); 56599 } else { 56600 var vert = []; 56601 vert.isVert = true; 56602 vert[0] = x; 56603 vert[1] = y; 56604 vert[2] = 0; 56605 vert[3] = 0; 56606 vert[4] = 0; 56607 vert[5] = this._renderer._getFill(); 56608 vert[6] = this._renderer._getStroke(); 56609 56610 if (moveTo) { 56611 vert.moveTo = moveTo; 56612 } 56613 56614 if (isContour) { 56615 if (contourVertices.length === 0) { 56616 vert.moveTo = true; 56617 } 56618 56619 contourVertices.push(vert); 56620 } else { 56621 vertices.push(vert); 56622 } 56623 } 56624 56625 return this; 56626 }; 56627 56628 module.exports = p5; 56629 }, {
56630 "../constants": 18, 56631 "../main": 24 56632 }], 56633 34: [function (_dereq_, module, exports) { 56634 'use strict'; // requestAnim shim layer by Paul Irish 56635 // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 56636 // http://my.opera.com/emoller/blog/2011/12/20/ 56637 // requestanimationframe-for-smart-er-animating 56638 // requestAnimationFrame polyfill by Erik Möller 56639 // fixes from Paul Irish and Tino Zijdel 56640 56641 window.requestAnimationFrame = function () { 56642 return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback, element) { 56643 // should '60' here be framerate? 56644 window.setTimeout(callback, 1000 / 60); 56645 }; 56646 }(); 56647 /** 56648 * shim for Uint8ClampedArray.slice 56649 * (allows arrayCopy to work with pixels[]) 56650 * with thanks to http://halfpapstudios.com/blog/tag/html5-canvas/ 56651 * Enumerable set to false to protect for...in from 56652 * Uint8ClampedArray.prototype pollution. 56653 */ 56654 56655 56656 (function () { 56657 'use strict'; 56658 56659 if (typeof Uint8ClampedArray !== 'undefined' && !Uint8ClampedArray.prototype.slice) { 56660 Object.defineProperty(Uint8ClampedArray.prototype, 'slice', { 56661 value: Array.prototype.slice, 56662 writable: true, 56663 configurable: true, 56664 enumerable: false 56665 }); 56666 } 56667 })(); 56668 /** 56669 * this is implementation of Object.assign() which is unavailable in 56670 * IE11 and (non-Chrome) Android browsers. 56671 * The assign() method is used to copy the values of all enumerable 56672 * own properties from one or more source objects to a target object. 56673 * It will return the target object. 56674 * Modified from https://github.com/ljharb/object.assign 56675 */ 56676 56677 56678 (function () { 56679 'use strict'; 56680 56681 if (!Object.assign) { 56682 var keys = Object.keys; 56683 var defineProperty = Object.defineProperty; 56684 56685 var canBeObject = function (obj) { 56686 return typeof obj !== 'undefined' && obj !== null; 56687 }; 56688 56689 var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol'; 56690 var propIsEnumerable = Object.prototype.propertyIsEnumerable; 56691 56692 var isEnumerableOn = function (obj) { 56693 return function isEnumerable(prop) { 56694 return propIsEnumerable.call(obj, prop); 56695 }; 56696 }; // per ES6 spec, this function has to have a length of 2 56697 56698 56699 var assignShim = function assign(target, source1) { 56700 if (!canBeObject(target)) { 56701 throw new TypeError('target must be an object'); 56702 } 56703 56704 var objTarget = Object(target); 56705 var s, source, i, props; 56706 56707 for (s = 1; s < arguments.length; ++s) { 56708 source = Object(arguments[s]); 56709 props = keys(source); 56710 56711 if (hasSymbols && Object.getOwnPropertySymbols) { 56712 props.push.apply(props, Object.getOwnPropertySymbols(source).filter(isEnumerableOn(source))); 56713 } 56714 56715 for (i = 0; i < props.length; ++i) { 56716 objTarget[props[i]] = source[props[i]]; 56717 } 56718 } 56719 56720 return objTarget; 56721 }; 56722 56723 defineProperty(Object, 'assign', { 56724 value: assignShim, 56725 configurable: true, 56726 enumerable: false, 56727 writable: true 56728 }); 56729 } 56730 })(); 56731 }, {}], 56732 35: [function (_dereq_, module, exports) { 56733 /** 56734 * @module Structure 56735 * @submodule Structure 56736 * @for p5 56737 * @requires core 56738 */ 56739 'use strict'; 56740 56741 var p5 = _dereq_('./main'); 56742 /** 56743 * Stops p5.js from continuously executing the code within <a href="#/p5/draw">draw()</a>. 56744 * If <a href="#/p5/loop">loop()</a> is called, the code in <a href="#/p5/draw">draw()</a> begins to run continuously again. 56745 * If using <a href="#/p5/noLoop">noLoop()</a> in <a href="#/p5/setup">setup()</a>, it should be the last line inside the block. 56746 * <br><br> 56747 * When <a href="#/p5/noLoop">noLoop()</a> is used, it's not possible to manipulate or access the 56748 * screen inside event handling functions such as <a href="#/p5/mousePressed">mousePressed()</a> or 56749 * <a href="#/p5/keyPressed">keyPressed()</a>. Instead, use those functions to call <a href="#/p5/redraw">redraw()</a> or <a href="#/p5/loop">loop()</a>, 56750 * which will run <a href="#/p5/draw">draw()</a>, which can update the screen properly. This means 56751 * that when <a href="#/p5/noLoop">noLoop()</a> has been called, no drawing can happen, and functions 56752 * like <a href="#/p5/saveFrame">saveFrame()</a> or <a href="#/p5/loadPixels">loadPixels()</a> may not be used. 56753 * <br><br> 56754 * Note that if the sketch is resized, <a href="#/p5/redraw">redraw()</a> will be called to update 56755 * the sketch, even after <a href="#/p5/noLoop">noLoop()</a> has been specified. Otherwise, the sketch 56756 * would enter an odd state until <a href="#/p5/loop">loop()</a> was called. 56757 * 56758 * @method noLoop 56759 * @example 56760 * <div><code> 56761 * function setup() { 56762 * createCanvas(100, 100); 56763 * background(200); 56764 * noLoop(); 56765 * } 56766 56767 * function draw() { 56768 * line(10, 10, 90, 90); 56769 * } 56770 * </code></div> 56771 * 56772 * <div><code> 56773 * let x = 0; 56774 * function setup() { 56775 * createCanvas(100, 100); 56776 * } 56777 * 56778 * function draw() { 56779 * background(204); 56780 * x = x + 0.1; 56781 * if (x > width) { 56782 * x = 0; 56783 * } 56784 * line(x, 0, x, height); 56785 * } 56786 * 56787 * function mousePressed() { 56788 * noLoop(); 56789 * } 56790 * 56791 * function mouseReleased() { 56792 * loop(); 56793 * } 56794 * </code></div> 56795 * 56796 * @alt 56797 * 113 pixel long line extending from top-left to bottom right of canvas. 56798 * horizontal line moves slowly from left. Loops but stops on mouse press. 56799 * 56800 */ 56801 56802 56803 p5.prototype.noLoop = function () { 56804 this._loop = false;
56805 }; 56806 /** 56807 * By default, p5.js loops through draw() continuously, executing the code 56808 * within it. However, the <a href="#/p5/draw">draw()</a> loop may be stopped by calling <a href="#/p5/noLoop">noLoop()</a>. 56809 * In that case, the <a href="#/p5/draw">draw()</a> loop can be resumed with loop(). 56810 * 56811 * @method loop 56812 * @example 56813 * <div><code> 56814 * let x = 0; 56815 * function setup() { 56816 * createCanvas(100, 100); 56817 * noLoop(); 56818 * } 56819 * 56820 * function draw() { 56821 * background(204); 56822 * x = x + 0.1; 56823 * if (x > width) { 56824 * x = 0; 56825 * } 56826 * line(x, 0, x, height); 56827 * } 56828 * 56829 * function mousePressed() { 56830 * loop(); 56831 * } 56832 * 56833 * function mouseReleased() { 56834 * noLoop(); 56835 * } 56836 * </code></div> 56837 * 56838 * @alt 56839 * horizontal line moves slowly from left. Loops but stops on mouse press. 56840 * 56841 */ 56842 56843 56844 p5.prototype.loop = function () { 56845 this._loop = true; 56846 56847 this._draw(); 56848 }; 56849 /** 56850 * The <a href="#/p5/push">push()</a> function saves the current drawing style settings and 56851 * transformations, while <a href="#/p5/pop">pop()</a> restores these settings. Note that these 56852 * functions are always used together. They allow you to change the style 56853 * and transformation settings and later return to what you had. When a new 56854 * state is started with <a href="#/p5/push">push()</a>, it builds on the current style and transform 56855 * information. The <a href="#/p5/push">push()</a> and <a href="#/p5/pop">pop()</a> functions can be embedded to provide 56856 * more control. (See the second example for a demonstration.) 56857 * <br><br> 56858 * <a href="#/p5/push">push()</a> stores information related to the current transformation state 56859 * and style settings controlled by the following functions: <a href="#/p5/fill">fill()</a>, 56860 * <a href="#/p5/stroke">stroke()</a>, <a href="#/p5/tint">tint()</a>, <a href="#/p5/strokeWeight">
56860strokeWeight()</a>, <a href="#/p5/strokeCap">strokeCap()</a>, <a href="#/p5/strokeJoin">strokeJoin()</a>, 56861 * <a href="#/p5/imageMode">imageMode()</a>, <a href="#/p5/rectMode">rectMode()</a>, <a href="#/p5/ellipseMode">ellipseMode()</a>, <a href="#/p5/colorMode">colorMode()</a>, <a href="#/p5/textAlign">textAlign()</a>, 56862 * <a href="#/p5/textFont">textFont()</a>, <a href="#/p5/textMode">textMode()</a>, <a href="#/p5/textSize">textSize()</a>, <a href="#/p5/textLeading">textLeading()</a>. 56863 * 56864 * @method push 56865 * @example 56866 * <div> 56867 * <code> 56868 * ellipse(0, 50, 33, 33); // Left circle 56869 * 56870 * push(); // Start a new drawing state 56871 * strokeWeight(10); 56872 * fill(204, 153, 0); 56873 * translate(50, 0); 56874 * ellipse(0, 50, 33, 33); // Middle circle 56875 * pop(); // Restore original state 56876 * 56877 * ellipse(100, 50, 33, 33); // Right circle 56878 * </code> 56879 * </div> 56880 * <div> 56881 * <code> 56882 * ellipse(0, 50, 33, 33); // Left circle 56883 * 56884 * push(); // Start a new drawing state 56885 * strokeWeight(10); 56886 * fill(204, 153, 0); 56887 * ellipse(33, 50, 33, 33); // Left-middle circle 56888 * 56889 * push(); // Start another new drawing state 56890 * stroke(0, 102, 153); 56891 * ellipse(66, 50, 33, 33); // Right-middle circle 56892 * pop(); // Restore previous state 56893 * 56894 * pop(); // Restore original state 56895 * 56896 * ellipse(100, 50, 33, 33); // Right circle 56897 * </code> 56898 * </div> 56899 * 56900 * @alt 56901 * Gold ellipse + thick black outline @center 2 white ellipses on left and right. 56902 * 2 Gold ellipses left black right blue stroke. 2 white ellipses on left+right. 56903 * 56904 */ 56905 56906 56907 p5.prototype.push = function () { 56908 this._styles.push({ 56909 props: { 56910 _colorMode: this._colorMode 56911 }, 56912 renderer: this._renderer.push() 56913 }); 56914 }; 56915 /** 56916 * The <a href="#/p5/push">push()</a> function saves the current drawing style settings and 56917 * transformations, while <a href="#/p5/pop">pop()</a> restores these settings. Note that these 56918 * functions are always used together. They allow you to change the style 56919 * and transformation settings and later return to what you had. When a new 56920 * state is started with <a href="#/p5/push">push()</a>, it builds on the current style and transform 56921 * information. The <a href="#/p5/push">push()</a> and <a href="#/p5/pop">pop()</a> functions can be embedded to provide 56922 * more control. (See the second example for a demonstration.) 56923 * <br><br> 56924 * <a href="#/p5/push">push()</a> stores information related to the current transformation state 56925 * and style settings controlled by the following functions: <a href="#/p5/fill">fill()</a>, 56926 * <a href="#/p5/stroke">stroke()</a>, <a href="#/p5/tint">tint()</a>, <a href="#/p5/strokeWeight">
56926strokeWeight()</a>, <a href="#/p5/strokeCap">strokeCap()</a>, <a href="#/p5/strokeJoin">strokeJoin()</a>, 56927 * <a href="#/p5/imageMode">imageMode()</a>, <a href="#/p5/rectMode">rectMode()</a>, <a href="#/p5/ellipseMode">ellipseMode()</a>, <a href="#/p5/colorMode">colorMode()</a>, <a href="#/p5/textAlign">textAlign()</a>, 56928 * <a href="#/p5/textFont">textFont()</a>, <a href="#/p5/textMode">textMode()</a>, <a href="#/p5/textSize">textSize()</a>, <a href="#/p5/textLeading">textLeading()</a>. 56929 * 56930 * @method pop 56931 * @example 56932 * <div> 56933 * <code> 56934 * ellipse(0, 50, 33, 33); // Left circle 56935 * 56936 * push(); // Start a new drawing state 56937 * translate(50, 0); 56938 * strokeWeight(10); 56939 * fill(204, 153, 0); 56940 * ellipse(0, 50, 33, 33); // Middle circle 56941 * pop(); // Restore original state 56942 * 56943 * ellipse(100, 50, 33, 33); // Right circle 56944 * </code> 56945 * </div> 56946 * <div> 56947 * <code> 56948 * ellipse(0, 50, 33, 33); // Left circle 56949 * 56950 * push(); // Start a new drawing state 56951 * strokeWeight(10); 56952 * fill(204, 153, 0); 56953 * ellipse(33, 50, 33, 33); // Left-middle circle 56954 * 56955 * push(); // Start another new drawing state 56956 * stroke(0, 102, 153); 56957 * ellipse(66, 50, 33, 33); // Right-middle circle 56958 * pop(); // Restore previous state 56959 * 56960 * pop(); // Restore original state 56961 * 56962 * ellipse(100, 50, 33, 33); // Right circle 56963 * </code> 56964 * </div> 56965 * 56966 * @alt 56967 * Gold ellipse + thick black outline @center 2 white ellipses on left and right. 56968 * 2 Gold ellipses left black right blue stroke. 2 white ellipses on left+right. 56969 * 56970 */ 56971 56972 56973 p5.prototype.pop = function () { 56974 var style = this._styles.pop(); 56975 56976 if (style) { 56977 this._renderer.pop(style.renderer); 56978 56979 Object.assign(this, style.props); 56980 } else { 56981 console.warn('pop() was called without matching push()'); 56982 } 56983 }; 56984 /** 56985 * 56986 * Executes the code within <a href="#/p5/draw">draw()</a> one time. This functions allows the 56987 * program to update the display window only when necessary, for example 56988 * when an event registered by <a href="#/p5/mousePressed">mousePressed()</a> or <a href="#/p5/keyPressed">keyPressed()</a> occurs. 56989 * <br><br> 56990 * In structuring a program, it only makes sense to call <a href="#/p5/redraw">redraw()</a> within 56991 * events such as <a href="#/p5/mousePressed">mousePressed()</a>. This is because <a href="#/p5/redraw">redraw()</a> does not run 56992 * <a href="#/p5/draw">draw()</a> immediately (it only sets a flag that indicates an update is 56993 * needed). 56994 * <br><br> 56995 * The <a href="#/p5/redraw">redraw()</a> function does not work properly when called inside <a href="#/p5/draw">draw()</a>. 56996 * To enable/disable animations, use <a href="#/p5/loop">loop()</a> and <a href="#/p5/noLoop">noLoop()</a>. 56997 * <br><br> 56998 * In addition you can set the number of redraws per method call. Just 56999 * add an integer as single parameter for the number of redraws. 57000 * 57001 * @method redraw 57002 * @param {Integer} [n] Redraw for n-times. The default value is 1. 57003 * @example 57004 * <div><code> 57005 * let x = 0; 57006 * 57007 * function setup() { 57008 * createCanvas(100, 100); 57009 * noLoop(); 57010 * } 57011 * 57012 * function draw() { 57013 * background(204); 57014 * line(x, 0, x, height); 57015 * } 57016 * 57017 * function mousePressed() { 57018 * x += 1; 57019 * redraw(); 57020 * } 57021 * </code></div> 57022 * 57023 * <div class='norender'><code> 57024 * let x = 0; 57025 * 57026 * function setup() { 57027 * createCanvas(100, 100); 57028 * noLoop(); 57029 * } 57030 * 57031 * function draw() { 57032 * background(204); 57033 * x += 1; 57034 * line(x, 0, x, height); 57035 * } 57036 * 57037 * function mousePressed() { 57038 * redraw(5); 57039 * } 57040 * </code></div> 57041 * 57042 * @alt 57043 * black line on far left of canvas 57044 * black line on far left of canvas 57045 * 57046 */ 57047 57048 57049 p5.prototype.redraw = function (n) { 57050 var numberOfRedraws = parseInt(n); 57051 57052 if (isNaN(numberOfRedraws) || numberOfRedraws < 1) { 57053 numberOfRedraws = 1; 57054 } 57055 57056 var context = this._isGlobal ? window : this; 57057 var userSetup = context.setup; 57058 var userDraw = context.draw; 57059 57060 if (typeof userDraw === 'function') { 57061 if (typeof userSetup === 'undefined') { 57062 context.scale(context._pixelDensity, context._pixelDensity); 57063 } 57064 57065 var callMethod = function (f) { 57066 f.call(context); 57067 }; 57068 57069 for (var idxRedraw = 0; idxRedraw < numberOfRedraws; idxRedraw++) { 57070 context.resetMatrix(); 57071 57072 if (context._renderer.isP3D) { 57073 context._renderer._update(); 57074 } 57075 57076 context._setProperty('frameCount', context.frameCount + 1); 57077 57078 context._registeredMethods.pre.forEach(callMethod); 57079 57080 userDraw(); 57081 57082 context._registeredMethods.post.forEach(callMethod); 57083 } 57084 } 57085 }; 57086 57087 module.exports = p5; 57088 }, {
57089 "./main": 24 57090 }], 57091 36: [function (_dereq_, module, exports) { 57092 /** 57093 * @module Transform 57094 * @submodule Transform 57095 * @for p5 57096 * @requires core 57097 * @requires constants 57098 */ 57099 'use strict'; 57100 57101 var p5 = _dereq_('./main'); 57102 /** 57103 * Multiplies the current matrix by the one specified through the parameters. 57104 * This is a powerful operation that can perform the equivalent of translate, 57105 * scale, shear and rotate all at once. You can learn more about transformation 57106 * matrices on <a href="https://en.wikipedia.org/wiki/Transformation_matrix"> 57107 * Wikipedia</a>. 57108 * 57109 * The naming of the arguments here follows the naming of the <a href= 57110 * "https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-transform"> 57111 * WHATWG specification</a> and corresponds to a 57112 * transformation matrix of the 57113 * form: 57114 * 57115 * > <img style="max-width: 150px" src="assets/transformation-matrix.png" 57116 * alt="The transformation matrix used when applyMatrix is called"/> 57117 *
57118 * @method applyMatrix 57119 * @param {Number} a numbers which define the 2x3 matrix to be multiplied 57120 * @param {Number} b numbers which define the 2x3 matrix to be multiplied 57121 * @param {Number} c numbers which define the 2x3 matrix to be multiplied 57122 * @param {Number} d numbers which define the 2x3 matrix to be multiplied 57123 * @param {Number} e numbers which define the 2x3 matrix to be multiplied 57124 * @param {Number} f numbers which define the 2x3 matrix to be multiplied 57125 * @chainable 57126 * @example 57127 * <div> 57128 * <code> 57129 * function setup() { 57130 * frameRate(10); 57131 * rectMode(CENTER); 57132 * } 57133 * 57134 * function draw() { 57135 * var step = frameCount % 20; 57136 * background(200); 57137 * // Equivalent to translate(x, y); 57138 * applyMatrix(1, 0, 0, 1, 40 + step, 50); 57139 * rect(0, 0, 50, 50); 57140 * } 57141 * </code> 57142 * </div> 57143 * <div> 57144 * <code> 57145 * function setup() { 57146 * frameRate(10); 57147 * rectMode(CENTER); 57148 * } 57149 * 57150 * function draw() { 57151 * var step = frameCount % 20; 57152 * background(200); 57153 * translate(50, 50); 57154 * // Equivalent to scale(x, y); 57155 * applyMatrix(1 / step, 0, 0, 1 / step, 0, 0); 57156 * rect(0, 0, 50, 50); 57157 * } 57158 * </code> 57159 * </div> 57160 * <div> 57161 * <code> 57162 * function setup() { 57163 * frameRate(10); 57164 * rectMode(CENTER); 57165 * } 57166 * 57167 * function draw() { 57168 * var step = frameCount % 20; 57169 * var angle = map(step, 0, 20, 0, TWO_PI); 57170 * var cos_a = cos(angle); 57171 * var sin_a = sin(angle); 57172 * background(200); 57173 * translate(50, 50); 57174 * // Equivalent to rotate(angle); 57175 * applyMatrix(cos_a, sin_a, -sin_a, cos_a, 0, 0); 57176 * rect(0, 0, 50, 50); 57177 * } 57178 * </code> 57179 * </div> 57180 * <div> 57181 * <code> 57182 * function setup() { 57183 * frameRate(10); 57184 * rectMode(CENTER); 57185 * } 57186 * 57187 * function draw() { 57188 * var step = frameCount % 20; 57189 * var angle = map(step, 0, 20, -PI / 4, PI / 4); 57190 * background(200); 57191 * translate(50, 50); 57192 * // equivalent to shearX(angle); 57193 * var shear_factor = 1 / tan(PI / 2 - angle); 57194 * applyMatrix(1, 0, shear_factor, 1, 0, 0); 57195 * rect(0, 0, 50, 50); 57196 * } 57197 * </code> 57198 * </div> 57199 * 57200 * @alt 57201 * A rectangle translating to the right 57202 * A rectangle shrinking to the center 57203 * A rectangle rotating clockwise about the center 57204 * A rectangle shearing 57205 * 57206 */ 57207 57208 57209 p5.prototype.applyMatrix = function (a, b, c, d, e, f) { 57210 this._renderer.applyMatrix(a, b, c, d, e, f); 57211 57212 return this; 57213 }; 57214 57215 p5.prototype.popMatrix = function () { 57216 throw new Error('popMatrix() not used, see pop()'); 57217 }; 57218 57219 p5.prototype.printMatrix = function () { 57220 throw new Error('printMatrix() not implemented'); 57221 }; 57222 57223 p5.prototype.pushMatrix = function () { 57224 throw new Error('pushMatrix() not used, see push()'); 57225 }; 57226 /** 57227 * Replaces the current matrix with the identity matrix. 57228 * 57229 * @method resetMatrix 57230 * @chainable 57231 * @example 57232 * <div> 57233 * <code> 57234 * translate(50, 50); 57235 * applyMatrix(0.5, 0.5, -0.5, 0.5, 0, 0); 57236 * rect(0, 0, 20, 20); 57237 * // Note that the translate is also reset. 57238 * resetMatrix(); 57239 * rect(0, 0, 20, 20); 57240 * </code> 57241 * </div> 57242 * 57243 * @alt 57244 * A rotated retangle in the center with another at the top left corner 57245 * 57246 */ 57247 57248 57249 p5.prototype.resetMatrix = function () { 57250 this._renderer.resetMatrix(); 57251 57252 return this; 57253 }; 57254 /** 57255 * Rotates a shape the amount specified by the angle parameter. This 57256 * function accounts for <a href="#/p5/angleMode">angleMode</a>, so angles can be entered in either 57257 * RADIANS or DEGREES. 57258 * <br><br> 57259 * Objects are always rotated around their relative position to the 57260 * origin and positive numbers rotate objects in a clockwise direction. 57261 * Transformations apply to everything that happens after and subsequent 57262 * calls to the function accumulates the effect. For example, calling 57263 * rotate(HALF_PI) and then rotate(HALF_PI) is the same as rotate(PI). 57264 * All tranformations are reset when <a href="#/p5/draw">draw()</a> begins again. 57265 * <br><br>
57266 * Technically, <a href="#/p5/rotate">rotate()</a> multiplies the current transformation matrix 57267 * by a rotation matrix. This function can be further controlled by 57268 * the <a href="#/p5/push">push()</a> and <a href="#/p5/pop">pop()</a>. 57269 * 57270 * @method rotate 57271 * @param {Number} angle the angle of rotation, specified in radians 57272 * or degrees, depending on current angleMode 57273 * @param {p5.Vector|Number[]} [axis] (in 3d) the axis to rotate around 57274 * @chainable 57275 * @example 57276 * <div> 57277 * <code> 57278 * translate(width / 2, height / 2); 57279 * rotate(PI / 3.0); 57280 * rect(-26, -26, 52, 52); 57281 * </code> 57282 * </div> 57283 * 57284 * @alt 57285 * white 52x52 rect with black outline at center rotated counter 45 degrees 57286 * 57287 */ 57288 57289 57290 p5.prototype.rotate = function (angle, axis) { 57291 p5._validateParameters('rotate', arguments); 57292 57293 this._renderer.rotate(this._toRadians(angle), axis); 57294 57295 return this; 57296 }; 57297 /** 57298 * Rotates around X axis. 57299 * @method rotateX 57300 * @param {Number} angle the angle of rotation, specified in radians 57301 * or degrees, depending on current angleMode 57302 * @chainable 57303 * @example 57304 * <div modernizr='webgl'> 57305 * <code> 57306 * function setup() { 57307 * createCanvas(100, 100, WEBGL); 57308 * } 57309 * function draw() { 57310 * background(255); 57311 * rotateX(millis() / 1000); 57312 * box(); 57313 * } 57314 * </code> 57315 * </div> 57316 * 57317 * @alt 57318 * 3d box rotating around the x axis. 57319 */ 57320 57321 57322 p5.prototype.rotateX = function (angle) { 57323 this._assert3d('rotateX'); 57324 57325 p5._validateParameters('rotateX', arguments); 57326 57327 this._renderer.rotateX(this._toRadians(angle)); 57328 57329 return this; 57330 }; 57331 /** 57332 * Rotates around Y axis. 57333 * @method rotateY 57334 * @param {Number} angle the angle of rotation, specified in radians 57335 * or degrees, depending on current angleMode 57336 * @chainable 57337 * @example 57338 * <div modernizr='webgl'> 57339 * <code> 57340 * function setup() { 57341 * createCanvas(100, 100, WEBGL); 57342 * } 57343 * function draw() { 57344 * background(255); 57345 * rotateY(millis() / 1000); 57346 * box(); 57347 * } 57348 * </code> 57349 * </div> 57350 * 57351 * @alt 57352 * 3d box rotating around the y axis. 57353 */ 57354 57355 57356 p5.prototype.rotateY = function (angle) { 57357 this._assert3d('rotateY'); 57358 57359 p5._validateParameters('rotateY', arguments); 57360 57361 this._renderer.rotateY(this._toRadians(angle)); 57362 57363 return this; 57364 }; 57365 /** 57366 * Rotates around Z axis. Webgl mode only. 57367 * @method rotateZ 57368 * @param {Number} angle the angle of rotation, specified in radians 57369 * or degrees, depending on current angleMode 57370 * @chainable 57371 * @example 57372 * <div modernizr='webgl'> 57373 * <code> 57374 * function setup() { 57375 * createCanvas(100, 100, WEBGL); 57376 * } 57377 * function draw() { 57378 * background(255); 57379 * rotateZ(millis() / 1000); 57380 * box(); 57381 * } 57382 * </code> 57383 * </div> 57384 * 57385 * @alt 57386 * 3d box rotating around the z axis. 57387 */ 57388 57389 57390 p5.prototype.rotateZ = function (angle) { 57391 this._assert3d('rotateZ'); 57392 57393 p5._validateParameters('rotateZ', arguments); 57394 57395 this._renderer.rotateZ(this._toRadians(angle)); 57396 57397 return this; 57398 }; 57399 /** 57400 * Increases or decreases the size of a shape by expanding and contracting 57401 * vertices. Objects always scale from their relative origin to the 57402 * coordinate system. Scale values are specified as decimal percentages. 57403 * For example, the function call scale(2.0) increases the dimension of a 57404 * shape by 200%. 57405 * <br><br> 57406 * Transformations apply to everything that happens after and subsequent 57407 * calls to the function multiply the effect. For example, calling scale(2.0) 57408 * and then scale(1.5) is the same as scale(3.0). If <a href="#/p5/scale">scale()</a> is called 57409 * within <a href="#/p5/draw">draw()</a>, the transformation is reset when the loop begins again. 57410 * <br><br> 57411 * Using this function with the z parameter is only available in WEBGL mode. 57412 * This function can be further controlled with <a href="#/p5/push">push()</a> and <a href="#/p5/pop">pop()</a>. 57413 * 57414 * @method scale 57415 * @param {Number|p5.Vector|Number[]} s 57416 * percent to scale the object, or percentage to 57417 * scale the object in the x-axis if multiple arguments 57418 * are given 57419 * @param {Number} [y] percent to scale the object in the y-axis 57420 * @param {Number} [z] percent to scale the object in the z-axis (webgl only) 57421 * @chainable 57422 * @example 57423 * <div> 57424 * <code> 57425 * rect(30, 20, 50, 50); 57426 * scale(0.5); 57427 * rect(30, 20, 50, 50); 57428 * </code> 57429 * </div> 57430 * 57431 * <div> 57432 * <code> 57433 * rect(30, 20, 50, 50); 57434 * scale(0.5, 1.3); 57435 * rect(30, 20, 50, 50); 57436 * </code> 57437 * </div> 57438 * 57439 * @alt 57440 * white 52x52 rect with black outline at center rotated counter 45 degrees 57441 * 2 white rects with black outline- 1 50x50 at center. other 25x65 bottom left 57442 * 57443 */ 57444 57445 /** 57446 * @method scale 57447 * @param {p5.Vector|Number[]} scales per-axis percents to scale the object 57448 * @chainable 57449 */ 57450 57451 57452 p5.prototype.scale = function (x, y, z) { 57453 p5._validateParameters('scale', arguments); // Only check for Vector argument type if Vector is available 57454 57455 57456 if (x instanceof p5.Vector) { 57457 var v = x; 57458 x = v.x; 57459 y = v.y; 57460 z = v.z; 57461 } else if (x instanceof Array) { 57462 var rg = x; 57463 x = rg[0]; 57464 y = rg[1]; 57465 z = rg[2] || 1; 57466 } 57467 57468 if (isNaN(y)) { 57469 y = z = x; 57470 } else if (isNaN(z)) { 57471 z = 1; 57472 } 57473 57474 this._renderer.scale.call(this._renderer, x, y, z); 57475 57476 return this; 57477 }; 57478 /** 57479 * Shears a shape around the x-axis the amount specified by the angle 57480 * parameter. Angles should be specified in the current angleMode. 57481 * Objects are always sheared around their relative position to the origin 57482 * and positive numbers shear objects in a clockwise direction. 57483 * <br><br> 57484 * Transformations apply to everything that happens after and subsequent 57485 * calls to the function accumulates the effect. For example, calling 57486 * shearX(PI/2) and then shearX(PI/2) is the same as shearX(PI). 57487 * If <a href="#/p5/shearX">shearX()</a> is called within the <a href="#/p5/draw">draw()</a>, the transformation is reset when 57488 * the loop begins again. 57489 * <br><br>
57490 * Technically, <a href="#/p5/shearX">shearX()</a> multiplies the current transformation matrix by a 57491 * rotation matrix. This function can be further controlled by the 57492 * <a href="#/p5/push">push()</a> and <a href="#/p5/pop">pop()</a> functions. 57493 * 57494 * @method shearX 57495 * @param {Number} angle angle of shear specified in radians or degrees, 57496 * depending on current angleMode 57497 * @chainable 57498 * @example 57499 * <div> 57500 * <code> 57501 * translate(width / 4, height / 4); 57502 * shearX(PI / 4.0); 57503 * rect(0, 0, 30, 30); 57504 * </code> 57505 * </div> 57506 * 57507 * @alt 57508 * white irregular quadrilateral with black outline at top middle. 57509 * 57510 */ 57511 57512 57513 p5.prototype.shearX = function (angle) { 57514 p5._validateParameters('shearX', arguments); 57515 57516 this._renderer.shearX(this._toRadians(angle)); 57517 57518 return this; 57519 }; 57520 /** 57521 * Shears a shape around the y-axis the amount specified by the angle 57522 * parameter. Angles should be specified in the current angleMode. Objects 57523 * are always sheared around their relative position to the origin and 57524 * positive numbers shear objects in a clockwise direction. 57525 * <br><br> 57526 * Transformations apply to everything that happens after and subsequent 57527 * calls to the function accumulates the effect. For example, calling 57528 * shearY(PI/2) and then shearY(PI/2) is the same as shearY(PI). If 57529 * <a href="#/p5/shearY">shearY()</a> is called within the <a href="#/p5/draw">draw()</a>, the transformation is reset when 57530 * the loop begins again. 57531 * <br><br> 57532 * Technically, <a href="#/p5/shearY">shearY()</a> multiplies the current transformation matrix by a 57533 * rotation matrix. This function can be further controlled by the 57534 * <a href="#/p5/push">push()</a> and <a href="#/p5/pop">pop()</a> functions. 57535 * 57536 * @method shearY 57537 * @param {Number} angle angle of shear specified in radians or degrees, 57538 * depending on current angleMode 57539 * @chainable 57540 * @example 57541 * <div> 57542 * <code> 57543 * translate(width / 4, height / 4); 57544 * shearY(PI / 4.0); 57545 * rect(0, 0, 30, 30); 57546 * </code> 57547 * </div> 57548 * 57549 * @alt 57550 * white irregular quadrilateral with black outline at middle bottom. 57551 * 57552 */ 57553 57554 57555 p5.prototype.shearY = function (angle) { 57556 p5._validateParameters('shearY', arguments); 57557 57558 this._renderer.shearY(this._toRadians(angle)); 57559 57560 return this; 57561 }; 57562 /** 57563 * Specifies an amount to displace objects within the display window. 57564 * The x parameter specifies left/right translation, the y parameter 57565 * specifies up/down translation. 57566 * <br><br> 57567 * Transformations are cumulative and apply to everything that happens after 57568 * and subsequent calls to the function accumulates the effect. For example, 57569 * calling translate(50, 0) and then translate(20, 0) is the same as 57570 * translate(70, 0). If <a href="#/p5/translate">translate()</a> is called within <a href="#/p5/draw">draw()</a>, the 57571 * transformation is reset when the loop begins again. This function can be 57572 * further controlled by using <a href="#/p5/push">push()</a> and <a href="#/p5/pop">pop()</a>. 57573 * 57574 * @method translate 57575 * @param {Number} x left/right translation 57576 * @param {Number} y up/down translation 57577 * @param {Number} [z] forward/backward translation (webgl only) 57578 * @chainable 57579 * @example 57580 * <div> 57581 * <code> 57582 * translate(30, 20); 57583 * rect(0, 0, 55, 55); 57584 * </code> 57585 * </div> 57586 * 57587 * <div> 57588 * <code> 57589 * rect(0, 0, 55, 55); // Draw rect at original 0,0 57590 * translate(30, 20); 57591 * rect(0, 0, 55, 55); // Draw rect at new 0,0 57592 * translate(14, 14); 57593 * rect(0, 0, 55, 55); // Draw rect at new 0,0 57594 * </code> 57595 * </div> 57596 * 57597 57598 * <div> 57599 * <code> 57600 * function draw() { 57601 * background(200); 57602 * rectMode(CENTER); 57603 * translate(width / 2, height / 2); 57604 * translate(p5.Vector.fromAngle(millis() / 1000, 40)); 57605 * rect(0, 0, 20, 20); 57606 * } 57607 * </code> 57608 * </div> 57609 * 57610 * @alt 57611 * white 55x55 rect with black outline at center right. 57612 * 3 white 55x55 rects with black outlines at top-l, center-r and bottom-r.
57613 * a 20x20 white rect moving in a circle around the canvas 57614 * 57615 */ 57616 57617 /** 57618 * @method translate 57619 * @param {p5.Vector} vector the vector to translate by 57620 * @chainable 57621 */ 57622 57623 57624 p5.prototype.translate = function (x, y, z) { 57625 p5._validateParameters('translate', arguments); 57626 57627 if (this._renderer.isP3D) { 57628 this._renderer.translate(x, y, z); 57629 } else { 57630 this._renderer.translate(x, y); 57631 } 57632 57633 return this; 57634 }; 57635 57636 module.exports = p5; 57637 }, { 57638 "./main": 24 57639 }], 57640 37: [function (_dereq_, module, exports) { 57641 /** 57642 * @module Data 57643 * @submodule Dictionary 57644 * @for p5.TypedDict 57645 * @requires core 57646 * 57647 * This module defines the p5 methods for the p5 Dictionary classes. 57648 * The classes StringDict and NumberDict are for storing and working 57649 * with key-value pairs. 57650 */ 57651 'use strict'; 57652 57653 var p5 = _dereq_('../core/main'); 57654 /** 57655 * 57656 * Creates a new instance of p5.StringDict using the key-value pair 57657 * or the object you provide. 57658 * 57659 * @method createStringDict 57660 * @for p5 57661 * @param {String} key 57662 * @param {String} value 57663 * @return {p5.StringDict} 57664 * 57665 * @example 57666 * <div class="norender"> 57667 * <code> 57668 * function setup() { 57669 * var myDictionary = createStringDict('p5', 'js'); 57670 * print(myDictionary.hasKey('p5')); // logs true to console 57671 * 57672 * var anotherDictionary = createStringDict({ happy: 'coding' }); 57673 * print(anotherDictionary.hasKey('happy')); // logs true to console 57674 * } 57675 * </code></div> 57676 */ 57677 57678 /** 57679 * @method createStringDict 57680 * @param {Object} object object 57681 * @return {p5.StringDict} 57682 */ 57683 57684 57685 p5.prototype.createStringDict = function (key, value) { 57686 p5._validateParameters('createStringDict', arguments); 57687 57688 return new p5.StringDict(key, value); 57689 }; 57690 /** 57691 * 57692 * Creates a new instance of <a href="#/p5.NumberDict">p5.NumberDict</a> using the key-value pair 57693 * or object you provide. 57694 * 57695 * @method createNumberDict 57696 * @for p5 57697 * @param {Number} key 57698 * @param {Number} value 57699 * @return {p5.NumberDict} 57700 * 57701 * @example 57702 * <div class="norender"> 57703 * <code> 57704 * function setup() { 57705 * var myDictionary = createNumberDict(100, 42); 57706 * print(myDictionary.hasKey(100)); // logs true to console 57707 * 57708 * var anotherDictionary = createNumberDict({ 200: 84 }); 57709 * print(anotherDictionary.hasKey(200)); // logs true to console 57710 * } 57711 * </code></div> 57712 */ 57713 57714 /** 57715 * @method createNumberDict 57716 * @param {Object} object object 57717 * @return {p5.NumberDict} 57718 */ 57719 57720 57721 p5.prototype.createNumberDict = function (key, value) { 57722 p5._validateParameters('createNumberDict', arguments); 57723 57724 return new p5.NumberDict(key, value); 57725 }; 57726 /** 57727 * 57728 * Base class for all p5.Dictionary types. Specifically 57729 * typed Dictionary classes inherit from this class. 57730 * 57731 * @class p5.TypedDict 57732 * 57733 */ 57734 57735 57736 p5.TypedDict = function (key, value) { 57737 if (key instanceof Object) { 57738 this.data = key; 57739 } else { 57740 this.data = {}; 57741 this.data[key] = value; 57742 } 57743 57744 return this; 57745 }; 57746 /** 57747 * Returns the number of key-value pairs currently stored in the Dictionary. 57748 * 57749 * @method size 57750 * @return {Integer} the number of key-value pairs in the Dictionary 57751 * 57752 * @example 57753 * <div class="norender"> 57754 * <code> 57755 * function setup() { 57756 * var myDictionary = createNumberDict(1, 10); 57757 * myDictionary.create(2, 20); 57758 * myDictionary.create(3, 30); 57759 * print(myDictionary.size()); // logs 3 to the console 57760 * } 57761 * </code></div> 57762 * 57763 */ 57764 57765 57766 p5.TypedDict.prototype.size = function () { 57767 return Object.keys(this.data).length; 57768 }; 57769 /** 57770 * Returns true if the given key exists in the Dictionary, 57771 * otherwise returns false. 57772 * 57773 * @method hasKey 57774 * @param {Number|String} key that you want to look up 57775 * @return {Boolean} whether that key exists in Dictionary 57776 * 57777 * @example 57778 * <div class="norender"> 57779 * <code> 57780 * function setup() { 57781 * var myDictionary = createStringDict('p5', 'js'); 57782 * print(myDictionary.hasKey('p5')); // logs true to console 57783 * } 57784 * </code></div> 57785 * 57786 */ 57787 57788 57789 p5.TypedDict.prototype.hasKey = function (key) { 57790 return this.data.hasOwnProperty(key); 57791 }; 57792 /** 57793 * Returns the value stored at the given key. 57794 * 57795 * @method get 57796 * @param {Number|String} the key you want to access 57797 * @return {Number|String} the value stored at that key 57798 * 57799 * @example 57800 * <div class="norender"> 57801 * <code> 57802 * function setup() { 57803 * var myDictionary = createStringDict('p5', 'js'); 57804 * var myValue = myDictionary.get('p5'); 57805 * print(myValue === 'js'); // logs true to console 57806 * } 57807 * </code></div> 57808 * 57809 */ 57810 57811 57812 p5.TypedDict.prototype.get = function (key) { 57813 if (this.data.hasOwnProperty(key)) { 57814 return this.data[key]; 57815 } else { 57816 console.log(key + ' does not exist in this Dictionary'); 57817 } 57818 }; 57819 /** 57820 * Updates the value associated with the given key in case it already exists 57821 * in the Dictionary. Otherwise a new key-value pair is added. 57822 * 57823 * @method set 57824 * @param {Number|String} key 57825 * @param {Number|String} value 57826 * 57827 * @example 57828 * <div class="norender"> 57829 * <code> 57830 * function setup() { 57831 * var myDictionary = createStringDict('p5', 'js'); 57832 * myDictionary.set('p5', 'JS'); 57833 * myDictionary.print(); // logs "key: p5 - value: JS" to console 57834 * } 57835 * </code></div> 57836 * 57837 */ 57838 57839 57840 p5.TypedDict.prototype.set = function (key, value) {
57841 if (this._validate(value)) { 57842 this.data[key] = value; 57843 } else { 57844 console.log('Those values dont work for this dictionary type.'); 57845 } 57846 }; 57847 /** 57848 * private helper function to handle the user passing in objects 57849 * during construction or calls to create() 57850 */ 57851 57852 57853 p5.TypedDict.prototype._addObj = function (obj) { 57854 for (var key in obj) { 57855 this.set(key, obj[key]); 57856 } 57857 }; 57858 /** 57859 * Creates a new key-value pair in the Dictionary. 57860 * 57861 * @method create 57862 * @param {Number|String} key 57863 * @param {Number|String} value 57864 * 57865 * @example 57866 * <div class="norender"> 57867 * <code> 57868 * function setup() { 57869 * var myDictionary = createStringDict('p5', 'js'); 57870 * myDictionary.create('happy', 'coding'); 57871 * myDictionary.print(); 57872 * // above logs "key: p5 - value: js, key: happy - value: coding" to console 57873 * } 57874 * </code></div> 57875 */ 57876 57877 /** 57878 * @method create 57879 * @param {Object} obj key/value pair 57880 */ 57881 57882 57883 p5.TypedDict.prototype.create = function (key, value) { 57884 if (key instanceof Object && typeof value === 'undefined') { 57885 this._addObj(key); 57886 } else if (typeof key !== 'undefined') { 57887 this.set(key, value); 57888 } else { 57889 console.log('In order to create a new Dictionary entry you must pass ' + 'an object or a key, value pair'); 57890 } 57891 }; 57892 /** 57893 * Removes all previously stored key-value pairs from the Dictionary. 57894 * 57895 * @method clear 57896 * @example 57897 * <div class="norender"> 57898 * <code> 57899 * function setup() { 57900 * var myDictionary = createStringDict('p5', 'js'); 57901 * print(myDictionary.hasKey('p5')); // prints 'true' 57902 * myDictionary.clear(); 57903 * print(myDictionary.hasKey('p5')); // prints 'false' 57904 * } 57905 * </code> 57906 * </div> 57907 */ 57908 57909 57910 p5.TypedDict.prototype.clear = function () { 57911 this.data = {}; 57912 }; 57913 /** 57914 * Removes the key-value pair stored at the given key from the Dictionary. 57915 * 57916 * @method remove 57917 * @param {Number|String} key for the pair to remove 57918 * 57919 * @example 57920 * <div class="norender"> 57921 * <code> 57922 * function setup() { 57923 * var myDictionary = createStringDict('p5', 'js'); 57924 * myDictionary.create('happy', 'coding'); 57925 * myDictionary.print(); 57926 * // above logs "key: p5 - value: js, key: happy - value: coding" to console 57927 * myDictionary.remove('p5'); 57928 * myDictionary.print(); 57929 * // above logs "key: happy value: coding" to console 57930 * } 57931 * </code></div> 57932 * 57933 */ 57934 57935 57936 p5.TypedDict.prototype.remove = function (key) { 57937 if (this.data.hasOwnProperty(key)) { 57938 delete this.data[key]; 57939 } else { 57940 throw new Error(key + ' does not exist in this Dictionary'); 57941 } 57942 }; 57943 /** 57944 * Logs the set of items currently stored in the Dictionary to the console. 57945 * 57946 * @method print 57947 * 57948 * @example 57949 * <div class="norender"> 57950 * <code> 57951 * function setup() { 57952 * var myDictionary = createStringDict('p5', 'js'); 57953 * myDictionary.create('happy', 'coding'); 57954 * myDictionary.print(); 57955 * // above logs "key: p5 - value: js, key: happy - value: coding" to console 57956 * } 57957 * </code> 57958 * </div> 57959 */ 57960 57961 57962 p5.TypedDict.prototype.print = function () { 57963 for (var item in this.data) { 57964 console.log('key:' + item + ' value:' + this.data[item]); 57965 } 57966 }; 57967 /** 57968 * Converts the Dictionary into a CSV file for local download. 57969 * 57970 * @method saveTable 57971 * @example 57972 * <div> 57973 * <code> 57974 * function setup() { 57975 * createCanvas(100, 100); 57976 * background(200); 57977 * text('click here to save', 10, 10, 70, 80); 57978 * } 57979 * 57980 * function mousePressed() { 57981 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 57982 * createStringDict({ 57983 * john: 1940, 57984 * paul: 1942, 57985 * george: 1943, 57986 * ringo: 1940 57987 * }).saveTable('beatles'); 57988 * } 57989 * } 57990 * </code> 57991 * </div> 57992 */ 57993 57994 57995 p5.TypedDict.prototype.saveTable = function (filename) { 57996 var output = ''; 57997 57998 for (var key in this.data) { 57999 output += key + ',' + this.data[key] + '\n'; 58000 } 58001 58002 var blob = new Blob([output], { 58003 type: 'text/csv' 58004 }); 58005 p5.prototype.downloadFile(blob, filename || 'mycsv', 'csv'); 58006 }; 58007 /** 58008 * Converts the Dictionary into a JSON file for local download. 58009 * 58010 * @method saveJSON 58011 * @example 58012 * <div> 58013 * <code> 58014 * function setup() { 58015 * createCanvas(100, 100); 58016 * background(200); 58017 * text('click here to save', 10, 10, 70, 80); 58018 * } 58019 * 58020 * function mousePressed() { 58021 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 58022 * createStringDict({ 58023 * john: 1940, 58024 * paul: 1942, 58025 * george: 1943, 58026 * ringo: 1940 58027 * }).saveJSON('beatles'); 58028 * } 58029 * } 58030 * </code> 58031 * </div> 58032 */ 58033 58034 58035 p5.TypedDict.prototype.saveJSON = function (filename, opt) { 58036 p5.prototype.saveJSON(this.data, filename, opt); 58037 }; 58038 /** 58039 * private helper function to ensure that the user passed in valid 58040 * values for the Dictionary type 58041 */ 58042 58043 58044 p5.TypedDict.prototype._validate = function (value) { 58045 return true; 58046 }; 58047 /** 58048 * 58049 * A simple Dictionary class for Strings. 58050 * 58051 * @class p5.StringDict 58052 * @extends p5.TypedDict 58053 * 58054 */ 58055 58056 58057 p5.StringDict = function () { 58058 p5.TypedDict.apply(this, arguments); 58059 }; 58060 58061 p5.StringDict.prototype = Object.create(p5.TypedDict.prototype); 58062 58063 p5.StringDict.prototype._validate = function (value) { 58064 return typeof value === 'string'; 58065 }; 58066 /** 58067 * 58068 * A simple Dictionary class for Numbers. 58069 * 58070 * @class p5.NumberDict 58071 * @extends p5.TypedDict 58072 * 58073 */ 58074 58075 58076 p5.NumberDict = function () { 58077 p5.TypedDict.apply(this, arguments); 58078 }; 58079 58080 p5.NumberDict.prototype = Object.create(p5.TypedDict.prototype); 58081 /** 58082 * private helper function to ensure that the user passed in valid 58083 * values for the Dictionary type 58084 */ 58085 58086 p5.NumberDict.prototype._validate = function (value) { 58087 return typeof value === 'number'; 58088 }; 58089 /** 58090 * Add the given number to the value currently stored at the given key. 58091 * The sum then replaces the value previously stored in the Dictionary. 58092 * 58093 * @method add 58094 * @param {Number} Key for the value you wish to add to 58095 * @param {Number} Number to add to the value 58096 * @example 58097 * <div class='norender'> 58098 * <code> 58099 * function setup() { 58100 * var myDictionary = createNumberDict(2, 5); 58101 * myDictionary.add(2, 2); 58102 * print(myDictionary.get(2)); // logs 7 to console. 58103 * } 58104 * </code></div> 58105 * 58106 * 58107 */ 58108 58109 58110 p5.NumberDict.prototype.add = function (key, amount) { 58111 if (this.data.hasOwnProperty(key)) { 58112 this.data[key] += amount; 58113 } else { 58114 console.log('The key - ' + key + ' does not exist in this dictionary.'); 58115 } 58116 }; 58117 /** 58118 * Subtract the given number from the value currently stored at the given key. 58119 * The difference then replaces the value previously stored in the Dictionary. 58120 * 58121 * @method sub 58122 * @param {Number}
58122 Key for the value you wish to subtract from 58123 * @param {Number} Number to subtract from the value 58124 * @example 58125 * <div class='norender'> 58126 * <code> 58127 * function setup() { 58128 * var myDictionary = createNumberDict(2, 5); 58129 * myDictionary.sub(2, 2); 58130 * print(myDictionary.get(2)); // logs 3 to console. 58131 * } 58132 * </code></div> 58133 * 58134 * 58135 */ 58136 58137 58138 p5.NumberDict.prototype.sub = function (key, amount) { 58139 this.add(key, -amount); 58140 }; 58141 /** 58142 * Multiply the given number with the value currently stored at the given key. 58143 * The product then replaces the value previously stored in the Dictionary. 58144 * 58145 * @method mult 58146 * @param {Number} Key for value you wish to multiply 58147 * @param {Number} Amount to multiply the value by 58148 * @example 58149 * <div class='norender'> 58150 * <code> 58151 * function setup() { 58152 * var myDictionary = createNumberDict(2, 4); 58153 * myDictionary.mult(2, 2); 58154 * print(myDictionary.get(2)); // logs 8 to console. 58155 * } 58156 * </code></div> 58157 * 58158 * 58159 */ 58160 58161 58162 p5.NumberDict.prototype.mult = function (key, amount) { 58163 if (this.data.hasOwnProperty(key)) { 58164 this.data[key] *= amount; 58165 } else { 58166 console.log('The key - ' + key + ' does not exist in this dictionary.'); 58167 } 58168 }; 58169 /** 58170 * Divide the given number with the value currently stored at the given key. 58171 * The quotient then replaces the value previously stored in the Dictionary. 58172 * 58173 * @method div 58174 * @param {Number} Key for value you wish to divide 58175 * @param {Number} Amount to divide the value by 58176 * @example 58177 * <div class='norender'> 58178 * <code> 58179 * function setup() { 58180 * var myDictionary = createNumberDict(2, 8); 58181 * myDictionary.div(2, 2); 58182 * print(myDictionary.get(2)); // logs 4 to console. 58183 * } 58184 * </code></div> 58185 * 58186 * 58187 */ 58188 58189 58190 p5.NumberDict.prototype.div = function (key, amount) { 58191 if (this.data.hasOwnProperty(key)) { 58192 this.data[key] /= amount; 58193 } else { 58194 console.log('The key - ' + key + ' does not exist in this dictionary.'); 58195 } 58196 }; 58197 /** 58198 * private helper function for finding lowest or highest value 58199 * the argument 'flip' is used to flip the comparison arrow 58200 * from 'less than' to 'greater than' 58201 * 58202 */ 58203 58204 58205 p5.NumberDict.prototype._valueTest = function (flip) { 58206 if (Object.keys(this.data).length === 0) { 58207 throw new Error('Unable to search for a minimum or maximum value on an empty NumberDict'); 58208 } else if (Object.keys(this.data).length === 1) { 58209 return this.data[Object.keys(this.data)[0]]; 58210 } else { 58211 var result = this.data[Object.keys(this.data)[0]]; 58212 58213 for (var key in this.data) { 58214 if (this.data[key] * flip < result * flip) { 58215 result = this.data[key]; 58216 } 58217 } 58218 58219 return result; 58220 } 58221 }; 58222 /** 58223 * Return the lowest number currently stored in the Dictionary. 58224 * 58225 * @method minValue 58226 * @return {Number} 58227 * @example 58228 * <div class='norender'> 58229 * <code> 58230 * function setup() { 58231 * var myDictionary = createNumberDict({ 2: -10, 4: 0.65, 1.2: 3 }); 58232 * var lowestValue = myDictionary.minValue(); // value is -10 58233 * print(lowestValue); 58234 * } 58235 * </code></div> 58236 * 58237 */ 58238 58239 58240 p5.NumberDict.prototype.minValue = function () { 58241 return this._valueTest(1); 58242 }; 58243 /** 58244 * Return the highest number currently stored in the Dictionary. 58245 * 58246 * @method maxValue 58247 * @return {Number} 58248 * @example 58249 * <div class='norender'> 58250 * <code> 58251 * function setup() { 58252 * var myDictionary = createNumberDict({ 2: -10, 4: 0.65, 1.2: 3 }); 58253 * var highestValue = myDictionary.maxValue(); // value is 3 58254 * print(highestValue); 58255 * } 58256 * </code></div> 58257 * 58258 */ 58259 58260 58261 p5.NumberDict.prototype.maxValue = function () { 58262 return this._valueTest(-1); 58263 }; 58264 /** 58265 * private helper function for finding lowest or highest key 58266 * the argument 'flip' is used to flip the comparison arrow 58267 * from 'less than' to 'greater than' 58268 * 58269 */ 58270 58271 58272 p5.NumberDict.prototype._keyTest = function (flip) { 58273 if (Object.keys(this.data).length === 0) { 58274 throw new Error('Unable to use minValue on an empty NumberDict'); 58275 } else if (Object.keys(this.data).length === 1) { 58276 return Object.keys(this.data)[0]; 58277 } else { 58278 var result = Object.keys(this.data)[0]; 58279 58280 for (var i = 1; i < Object.keys(this.data).length; i++) { 58281 if (Object.keys(this.data)[i] * flip < result * flip) { 58282 result = Object.keys(this.data)[i]; 58283 } 58284 } 58285 58286 return result; 58287 } 58288 }; 58289 /** 58290 * Return the lowest key currently used in the Dictionary. 58291 * 58292 * @method minKey 58293 * @return {Number} 58294 * @example 58295 * <div class='norender'> 58296 * <code> 58297 * function setup() { 58298 * var myDictionary = createNumberDict({ 2: 4, 4: 6, 1.2: 3 }); 58299 * var lowestKey = myDictionary.minKey(); // value is 1.2 58300 * print(lowestKey); 58301 * } 58302 * </code></div> 58303 * 58304 */ 58305 58306 58307 p5.NumberDict.prototype.minKey = function () { 58308 return this._keyTest(1); 58309 }; 58310 /** 58311 * Return the highest key currently used in the Dictionary. 58312 * 58313 * @method maxKey 58314 * @return {Number} 58315 * @example 58316 * <div class='norender'> 58317 * <code> 58318 * function setup() { 58319 * var myDictionary = createNumberDict({ 2: 4, 4: 6, 1.2: 3 }); 58320 * var highestKey = myDictionary.maxKey(); // value is 4 58321 * print(highestKey); 58322 * } 58323 * </code></div> 58324 * 58325 */ 58326 58327 58328 p5.NumberDict.prototype.maxKey = function () { 58329 return this._keyTest(-1); 58330 }; 58331 58332 module.exports = p5.TypedDict; 58333 }, {
58334 "../core/main": 24 58335 }], 58336 38: [function (_dereq_, module, exports) { 58337 /** 58338 * @module Events 58339 * @submodule Acceleration 58340 * @for p5 58341 * @requires core 58342 */ 58343 'use strict'; 58344 58345 var p5 = _dereq_('../core/main'); 58346 /** 58347 * The system variable deviceOrientation always contains the orientation of 58348 * the device. The value of this variable will either be set 'landscape' 58349 * or 'portrait'. If no data is available it will be set to 'undefined'. 58350 * either LANDSCAPE or PORTRAIT. 58351 * 58352 * @property {Constant} deviceOrientation 58353 * @readOnly 58354 */ 58355 58356 58357 p5.prototype.deviceOrientation = undefined; 58358 /** 58359 * The system variable accelerationX always contains the acceleration of the 58360 * device along the x axis. Value is represented as meters per second squared. 58361 * 58362 * @property {Number} accelerationX 58363 * @readOnly 58364 * @example 58365 * <div> 58366 * <code> 58367 * // Move a touchscreen device to register 58368 * // acceleration changes. 58369 * function draw() { 58370 * background(220, 50); 58371 * fill('magenta'); 58372 * ellipse(width / 2, height / 2, accelerationX); 58373 * } 58374 * </code> 58375 * </div> 58376 * @alt 58377 * Magnitude of device acceleration is displayed as ellipse size 58378 */ 58379 58380 p5.prototype.accelerationX = 0; 58381 /** 58382 * The system variable accelerationY always contains the acceleration of the 58383 * device along the y axis. Value is represented as meters per second squared. 58384 * 58385 * @property {Number} accelerationY 58386 * @readOnly 58387 * @example 58388 * <div> 58389 * <code> 58390 * // Move a touchscreen device to register 58391 * // acceleration changes. 58392 * function draw() { 58393 * background(220, 50); 58394 * fill('magenta'); 58395 * ellipse(width / 2, height / 2, accelerationY); 58396 * } 58397 * </code> 58398 * </div> 58399 * @alt 58400 * Magnitude of device acceleration is displayed as ellipse size 58401 */ 58402 58403 p5.prototype.accelerationY = 0; 58404 /** 58405 * The system variable accelerationZ always contains the acceleration of the 58406 * device along the z axis. Value is represented as meters per second squared. 58407 * 58408 * @property {Number} accelerationZ 58409 * @readOnly 58410 * 58411 * @example 58412 * <div> 58413 * <code> 58414 * // Move a touchscreen device to register 58415 * // acceleration changes. 58416 * function draw() { 58417 * background(220, 50); 58418 * fill('magenta'); 58419 * ellipse(width / 2, height / 2, accelerationZ); 58420 * } 58421 * </code> 58422 * </div> 58423 * 58424 * @alt 58425 * Magnitude of device acceleration is displayed as ellipse size 58426 */ 58427 58428 p5.prototype.accelerationZ = 0; 58429 /** 58430 * The system variable pAccelerationX always contains the acceleration of the 58431 * device along the x axis in the frame previous to the current frame. Value 58432 * is represented as meters per second squared. 58433 * 58434 * @property {Number} pAccelerationX 58435 * @readOnly 58436 */ 58437 58438 p5.prototype.pAccelerationX = 0; 58439 /** 58440 * The system variable pAccelerationY always contains the acceleration of the 58441 * device along the y axis in the frame previous to the current frame. Value 58442 * is represented as meters per second squared. 58443 * 58444 * @property {Number} pAccelerationY 58445 * @readOnly 58446 */ 58447 58448 p5.prototype.pAccelerationY = 0; 58449 /** 58450 * The system variable pAccelerationZ always contains the acceleration of the 58451 * device along the z axis in the frame previous to the current frame. Value 58452 * is represented as meters per second squared. 58453 * 58454 * @property {Number} pAccelerationZ 58455 * @readOnly 58456 */ 58457 58458 p5.prototype.pAccelerationZ = 0; 58459 /** 58460 * _updatePAccelerations updates the pAcceleration values 58461 * 58462 * @private 58463 */ 58464 58465 p5.prototype._updatePAccelerations = function () { 58466 this._setProperty('pAccelerationX', this.accelerationX); 58467 58468 this._setProperty('pAccelerationY', this.accelerationY); 58469 58470 this._setProperty('pAccelerationZ', this.accelerationZ); 58471 }; 58472 /** 58473 * The system variable rotationX always contains the rotation of the
58474 * device along the x axis. Value is represented as 0 to +/-180 degrees. 58475 * <br><br> 58476 * Note: The order the rotations are called is important, ie. if used 58477 * together, it must be called in the order Z-X-Y or there might be 58478 * unexpected behaviour. 58479 * 58480 * @property {Number} rotationX 58481 * @readOnly 58482 * @example 58483 * <div> 58484 * <code> 58485 * function setup() { 58486 * createCanvas(100, 100, WEBGL); 58487 * } 58488 * 58489 * function draw() { 58490 * background(200); 58491 * //rotateZ(radians(rotationZ)); 58492 * rotateX(radians(rotationX)); 58493 * //rotateY(radians(rotationY)); 58494 * box(200, 200, 200); 58495 * } 58496 * </code> 58497 * </div> 58498 * @alt 58499 * red horizontal line right, green vertical line bottom. black background. 58500 */ 58501 58502 58503 p5.prototype.rotationX = 0; 58504 /** 58505 * The system variable rotationY always contains the rotation of the 58506 * device along the y axis. Value is represented as 0 to +/-90 degrees. 58507 * <br><br> 58508 * Note: The order the rotations are called is important, ie. if used 58509 * together, it must be called in the order Z-X-Y or there might be 58510 * unexpected behaviour. 58511 * 58512 * @property {Number} rotationY 58513 * @readOnly 58514 * @example 58515 * <div> 58516 * <code> 58517 * function setup() { 58518 * createCanvas(100, 100, WEBGL); 58519 * } 58520 * 58521 * function draw() { 58522 * background(200); 58523 * //rotateZ(radians(rotationZ)); 58524 * //rotateX(radians(rotationX)); 58525 * rotateY(radians(rotationY)); 58526 * box(200, 200, 200); 58527 * } 58528 * </code> 58529 * </div> 58530 * @alt 58531 * red horizontal line right, green vertical line bottom. black background. 58532 */ 58533 58534 p5.prototype.rotationY = 0; 58535 /** 58536 * The system variable rotationZ always contains the rotation of the 58537 * device along the z axis. Value is represented as 0 to 359 degrees. 58538 * <br><br> 58539 * Unlike rotationX and rotationY, this variable is available for devices 58540 * with a built-in compass only. 58541 * <br><br> 58542 * Note: The order the rotations are called is important, ie. if used 58543 * together, it must be called in the order Z-X-Y or there might be 58544 * unexpected behaviour. 58545 * 58546 * @example 58547 * <div> 58548 * <code> 58549 * function setup() { 58550 * createCanvas(100, 100, WEBGL); 58551 * } 58552 * 58553 * function draw() { 58554 * background(200); 58555 * rotateZ(radians(rotationZ)); 58556 * //rotateX(radians(rotationX)); 58557 * //rotateY(radians(rotationY)); 58558 * box(200, 200, 200); 58559 * } 58560 * </code> 58561 * </div> 58562 * 58563 * @property {Number} rotationZ 58564 * @readOnly 58565 * 58566 * @alt 58567 * red horizontal line right, green vertical line bottom. black background. 58568 */ 58569 58570 p5.prototype.rotationZ = 0; 58571 /** 58572 * The system variable pRotationX always contains the rotation of the 58573 * device along the x axis in the frame previous to the current frame. Value 58574 * is represented as 0 to +/-180 degrees. 58575 * <br><br> 58576 * pRotationX can also be used with rotationX to determine the rotate 58577 * direction of the device along the X-axis. 58578 * @example 58579 * <div class='norender'> 58580 * <code> 58581 * // A simple if statement looking at whether 58582 * // rotationX - pRotationX < 0 is true or not will be 58583 * // sufficient for determining the rotate direction 58584 * // in most cases. 58585 * 58586 * // Some extra logic is needed to account for cases where 58587 * // the angles wrap around. 58588 * let rotateDirection = 'clockwise'; 58589 * 58590 * // Simple range conversion to make things simpler. 58591 * // This is not absolutely necessary but the logic 58592 * // will be different in that case. 58593 * 58594 * let rX = rotationX + 180; 58595 * let pRX = pRotationX + 180; 58596 * 58597 * if ((rX - pRX > 0 && rX - pRX < 270) || rX - pRX < -270) { 58598 * rotateDirection = 'clockwise'; 58599 * } else if (rX - pRX < 0 || rX - pRX > 270) { 58600 * rotateDirection = 'counter-clockwise'; 58601 * } 58602 * 58603 * print(rotateDirection); 58604 * </code> 58605 * </div> 58606 * 58607 * @alt 58608 * no image to display. 58609 * 58610 * 58611 * @property {Number} pRotationX 58612 * @readOnly 58613 */ 58614 58615 p5.prototype.pRotationX = 0; 58616 /** 58617 * The system variable pRotationY always contains the rotation of the 58618 * device along the y axis in the frame previous to the current frame. Value 58619 * is represented as 0 to +/-90 degrees. 58620 * <br><br> 58621 * pRotationY can also be used with rotationY to determine the rotate 58622 * direction of the device along the Y-axis. 58623 * @example 58624 * <div class='norender'> 58625 * <code> 58626 * // A simple if statement looking at whether 58627 * // rotationY - pRotationY < 0 is true or not will be 58628 * // sufficient for determining the rotate direction 58629 * // in most cases. 58630 * 58631 * // Some extra logic is needed to account for cases where 58632 * // the angles wrap around. 58633 * let rotateDirection = 'clockwise'; 58634 * 58635 * // Simple range conversion to make things simpler. 58636 * // This is not absolutely necessary but the logic 58637 * // will be different in that case. 58638 * 58639 * let rY = rotationY + 180; 58640 * let pRY = pRotationY + 180; 58641 * 58642 * if ((rY - pRY > 0 && rY - pRY < 270) || rY - pRY < -270) { 58643 * rotateDirection = 'clockwise'; 58644 * } else if (rY - pRY < 0 || rY - pRY > 270) { 58645 * rotateDirection = 'counter-clockwise'; 58646 * } 58647 * print(rotateDirection); 58648 * </code> 58649 * </div> 58650 * 58651 * @alt 58652 * no image to display. 58653 * 58654 * 58655 * @property {Number} pRotationY 58656 * @readOnly 58657 */ 58658 58659 p5.prototype.pRotationY = 0; 58660 /** 58661 * The system variable pRotationZ always contains the rotation of the 58662 * device along the z axis in the frame previous to the current frame. Value 58663 * is represented as 0 to 359 degrees. 58664 * <br><br> 58665 * pRotationZ can also be used with rotationZ to determine the rotate 58666 * direction of the device along the Z-axis. 58667 * @example 58668 * <div class='norender'> 58669 * <code> 58670 * // A simple if statement looking at whether 58671 * // rotationZ - pRotationZ < 0 is true or not will be 58672 * // sufficient for determining the rotate direction 58673 * // in most cases. 58674 * 58675 * // Some extra logic is needed to account for cases where 58676 * // the angles wrap around. 58677 * let rotateDirection = 'clockwise'; 58678 * 58679 * if ( 58680 * (rotationZ - pRotationZ > 0 && rotationZ - pRotationZ < 270) || 58681 * rotationZ - pRotationZ < -270 58682 * ) { 58683 * rotateDirection = 'clockwise'; 58684 * } else if (rotationZ - pRotationZ < 0 || rotationZ - pRotationZ > 270) { 58685 * rotateDirection = 'counter-clockwise'; 58686 * } 58687 * print(rotateDirection); 58688 * </code> 58689 * </div> 58690 * 58691 * @alt 58692 * no image to display. 58693 * 58694 * 58695 * @property {Number} pRotationZ 58696 * @readOnly 58697 */ 58698 58699 p5.prototype.pRotationZ = 0; 58700 var startAngleX = 0; 58701 var startAngleY = 0; 58702 var startAngleZ = 0; 58703 var rotateDirectionX = 'clockwise'; 58704 var rotateDirectionY = 'clockwise'; 58705 var rotateDirectionZ = 'clockwise'; 58706 var pRotateDirectionX; 58707 var pRotateDirectionY; 58708 var pRotateDirectionZ; 58709 58710 p5.prototype._updatePRotations = function () { 58711 this._setProperty('pRotationX', this.rotationX); 58712 58713 this._setProperty('pRotationY', this.rotationY); 58714 58715 this._setProperty('pRotationZ', this.rotationZ); 58716 }; 58717 /** 58718 * When a device is rotated, the axis that triggers the <a href="#/p5/deviceTurned">deviceTurned()</a> 58719 * method is stored in the turnAxis variable. The turnAxis variable is only defined within 58720 * the scope of deviceTurned(). 58721 * @property {String} turnAxis 58722 * @readOnly 58723 * @example 58724 * <div> 58725 * <code> 58726 * // Run this example on a mobile device 58727 * // Rotate the device by 90 degrees in the 58728 * // X-axis to change the value. 58729 * 58730 * var value = 0; 58731 * function draw() { 58732 * fill(value); 58733 * rect(25, 25, 50, 50); 58734 * } 58735 * function deviceTurned() { 58736 * if (turnAxis === 'X') { 58737 * if (value === 0) { 58738 * value = 255; 58739 * }
58739 else if (value === 255) { 58740 * value = 0; 58741 * } 58742 * } 58743 * } 58744 * </code> 58745 * </div> 58746 * 58747 * @alt 58748 * 50x50 black rect in center of canvas. turns white on mobile when device turns 58749 * 50x50 black rect in center of canvas. turns white on mobile when x-axis turns 58750 */ 58751 58752 58753 p5.prototype.turnAxis = undefined; 58754 var move_threshold = 0.5; 58755 var shake_threshold = 30; 58756 /** 58757 * The <a href="#/p5/setMoveThreshold">setMoveThreshold()</a> function is used to set the movement threshold for 58758 * the <a href="#/p5/deviceMoved">deviceMoved()</a> function. The default threshold is set to 0.5. 58759 * 58760 * @method setMoveThreshold 58761 * @param {number} value The threshold value 58762 * @example 58763 * <div class="norender"> 58764 * <code> 58765 * // Run this example on a mobile device 58766 * // You will need to move the device incrementally further 58767 * // the closer the square's color gets to white in order to change the value. 58768 * 58769 * let value = 0; 58770 * let threshold = 0.5; 58771 * function setup() { 58772 * setMoveThreshold(threshold); 58773 * } 58774 * function draw() { 58775 * fill(value); 58776 * rect(25, 25, 50, 50); 58777 * } 58778 * function deviceMoved() { 58779 * value = value + 5; 58780 * threshold = threshold + 0.1; 58781 * if (value > 255) { 58782 * value = 0; 58783 * threshold = 30; 58784 * } 58785 * setMoveThreshold(threshold); 58786 * } 58787 * </code> 58788 * </div> 58789 * 58790 * @alt 58791 * 50x50 black rect in center of canvas. turns white on mobile when device moves 58792 */ 58793 58794 p5.prototype.setMoveThreshold = function (val) { 58795 p5._validateParameters('setMoveThreshold', arguments); 58796 58797 move_threshold = val; 58798 }; 58799 /** 58800 * The <a href="#/p5/setShakeThreshold">setShakeThreshold()</a> function is used to set the movement threshold for 58801 * the <a href="#/p5/deviceShaken">deviceShaken()</a> function. The default threshold is set to 30. 58802 * 58803 * @method setShakeThreshold 58804 * @param {number} value The threshold value 58805 * @example 58806 * <div class="norender"> 58807 * <code> 58808 * // Run this example on a mobile device 58809 * // You will need to shake the device more firmly 58810 * // the closer the box's fill gets to white in order to change the value. 58811 * 58812 * let value = 0; 58813 * let threshold = 30; 58814 * function setup() { 58815 * setShakeThreshold(threshold); 58816 * } 58817 * function draw() { 58818 * fill(value); 58819 * rect(25, 25, 50, 50); 58820 * } 58821 * function deviceMoved() { 58822 * value = value + 5; 58823 * threshold = threshold + 5; 58824 * if (value > 255) { 58825 * value = 0; 58826 * threshold = 30; 58827 * } 58828 * setShakeThreshold(threshold); 58829 * } 58830 * </code> 58831 * </div> 58832 * 58833 * @alt 58834 * 50x50 black rect in center of canvas. turns white on mobile when device 58835 * is being shaked 58836 */ 58837 58838 58839 p5.prototype.setShakeThreshold = function (val) { 58840 p5._validateParameters('setShakeThreshold', arguments); 58841 58842 shake_threshold = val; 58843 }; 58844 /** 58845 * The <a href="#/p5/deviceMoved">deviceMoved()</a> function is called when the device is moved by more than 58846 * the threshold value along X, Y or Z axis. The default threshold is set to 0.5. 58847 * The threshold value can be changed using <a href="https://p5js.org/reference/#/p5/setMoveThreshold">setMoveThreshold()</a>. 58848 * 58849 * @method deviceMoved 58850 * @example 58851 * <div class="norender"> 58852 * <code> 58853 * // Run this example on a mobile device 58854 * // Move the device around 58855 * // to change the value. 58856 * 58857 * let value = 0; 58858 * function draw() { 58859 * fill(value); 58860 * rect(25, 25, 50, 50); 58861 * } 58862 * function deviceMoved() { 58863 * value = value + 5; 58864 * if (value > 255) { 58865 * value = 0; 58866 * } 58867 * } 58868 * </code> 58869 * </div> 58870 * 58871 * @alt 58872 * 50x50 black rect in center of canvas. turns white on mobile when device moves 58873 * 58874 */ 58875 58876 /** 58877 * The <a href="#/p5/deviceTurned">deviceTurned()</a> function is called when the device rotates by 58878 * more than 90 degrees continuously. 58879 * <br><br> 58880 * The axis that triggers the <a href="#/p5/deviceTurned">deviceTurned()</a> method is stored in the turnAxis 58881 * variable. The <a href="#/p5/deviceTurned">deviceTurned()</a> method can be locked to trigger on any axis: 58882 * X, Y or Z by comparing the turnAxis variable to 'X', 'Y' or 'Z'. 58883 * 58884 * @method deviceTurned 58885 * @example 58886 * <div class="norender"> 58887 * <code> 58888 * // Run this example on a mobile device 58889 * // Rotate the device by 90 degrees 58890 * // to change the value. 58891 * 58892 * let value = 0; 58893 * function draw() { 58894 * fill(value); 58895 * rect(25, 25, 50, 50); 58896 * } 58897 * function deviceTurned() { 58898 * if (value === 0) { 58899 * value = 255; 58900 * }
58900 else if (value === 255) { 58901 * value = 0; 58902 * } 58903 * } 58904 * </code> 58905 * </div> 58906 * <div> 58907 * <code> 58908 * // Run this example on a mobile device 58909 * // Rotate the device by 90 degrees in the 58910 * // X-axis to change the value. 58911 * 58912 * let value = 0; 58913 * function draw() { 58914 * fill(value); 58915 * rect(25, 25, 50, 50); 58916 * } 58917 * function deviceTurned() { 58918 * if (turnAxis === 'X') { 58919 * if (value === 0) { 58920 * value = 255; 58921 * } else if (value === 255) { 58922 * value = 0; 58923 * } 58924 * } 58925 * } 58926 * </code> 58927 * </div> 58928 * 58929 * @alt 58930 * 50x50 black rect in center of canvas. turns white on mobile when device turns 58931 * 50x50 black rect in center of canvas. turns white on mobile when x-axis turns 58932 * 58933 */ 58934 58935 /** 58936 * The <a href="#/p5/deviceShaken">deviceShaken()</a> function is called when the device total acceleration 58937 * changes of accelerationX and accelerationY values is more than 58938 * the threshold value. The default threshold is set to 30. 58939 * The threshold value can be changed using <a href="https://p5js.org/reference/#/p5/setShakeThreshold">setShakeThreshold()</a>. 58940 * 58941 * @method deviceShaken 58942 * @example 58943 * <div class="norender"> 58944 * <code> 58945 * // Run this example on a mobile device 58946 * // Shake the device to change the value. 58947 * 58948 * let value = 0; 58949 * function draw() { 58950 * fill(value); 58951 * rect(25, 25, 50, 50); 58952 * } 58953 * function deviceShaken() { 58954 * value = value + 5; 58955 * if (value > 255) { 58956 * value = 0; 58957 * } 58958 * } 58959 * </code> 58960 * </div> 58961 * 58962 * @alt 58963 * 50x50 black rect in center of canvas. turns white on mobile when device shakes 58964 * 58965 */ 58966 58967 58968 p5.prototype._ondeviceorientation = function (e) { 58969 this._updatePRotations(); 58970 58971 this._setProperty('rotationX', e.beta); 58972 58973 this._setProperty('rotationY', e.gamma); 58974 58975 this._setProperty('rotationZ', e.alpha); 58976 58977 this._handleMotion(); 58978 }; 58979 58980 p5.prototype._ondevicemotion = function (e) { 58981 this._updatePAccelerations(); 58982 58983 this._setProperty('accelerationX', e.acceleration.x * 2); 58984 58985 this._setProperty('accelerationY', e.acceleration.y * 2); 58986 58987 this._setProperty('accelerationZ', e.acceleration.z * 2); 58988 58989 this._handleMotion(); 58990 }; 58991 58992 p5.prototype._handleMotion = function () { 58993 if (window.orientation === 90 || window.orientation === -90) { 58994 this._setProperty('deviceOrientation', 'landscape'); 58995 } else if (window.orientation === 0) { 58996 this._setProperty('deviceOrientation', 'portrait'); 58997 } else if (window.orientation === undefined) { 58998 this._setProperty('deviceOrientation', 'undefined'); 58999 } 59000 59001 var deviceMoved = this.deviceMoved || window.deviceMoved; 59002 59003 if (typeof deviceMoved === 'function') { 59004 if (Math.abs(this.accelerationX - this.pAccelerationX) > move_threshold || Math.abs(this.accelerationY - this.pAccelerationY) > move_threshold || Math.abs(this.accelerationZ - this.pAccelerationZ) > move_threshold) { 59005 deviceMoved(); 59006 } 59007 } 59008 59009 var deviceTurned = this.deviceTurned || window.deviceTurned; 59010 59011 if (typeof deviceTurned === 'function') { 59012 // The angles given by rotationX etc is from range -180 to 180. 59013 // The following will convert them to 0 to 360 for ease of calculation 59014 // of cases when the angles wrapped around. 59015 // _startAngleX will be converted back at the end and updated. 59016 var wRX = this.rotationX + 180; 59017 var wPRX = this.pRotationX + 180; 59018 var wSAX = startAngleX + 180; 59019 59020 if (wRX - wPRX > 0 && wRX - wPRX < 270 || wRX - wPRX < -270) { 59021 rotateDirectionX = 'clockwise'; 59022 } else if (wRX - wPRX < 0 || wRX - wPRX > 270) { 59023 rotateDirectionX = 'counter-clockwise'; 59024 } 59025 59026 if (rotateDirectionX !== pRotateDirectionX) { 59027 wSAX = wRX; 59028 } 59029 59030 if (Math.abs(wRX - wSAX) > 90 && Math.abs(wRX - wSAX) < 270) { 59031 wSAX = wRX; 59032 59033 this._setProperty('turnAxis', 'X'); 59034 59035 deviceTurned(); 59036 } 59037 59038 pRotateDirectionX = rotateDirectionX; 59039 startAngleX = wSAX - 180; // Y-axis is identical to X-axis except for changing some names. 59040 59041 var wRY = this.rotationY + 180; 59042 var wPRY = this.pRotationY + 180; 59043 var wSAY = startAngleY + 180; 59044 59045 if (wRY - wPRY > 0 && wRY - wPRY < 270 || wRY - wPRY < -270) { 59046 rotateDirectionY = 'clockwise'; 59047 } else if (wRY - wPRY < 0 || wRY - this.pRotationY > 270) { 59048 rotateDirectionY = 'counter-clockwise'; 59049 } 59050 59051 if (rotateDirectionY !== pRotateDirectionY) { 59052 wSAY = wRY; 59053 } 59054 59055 if (Math.abs(wRY - wSAY) > 90 && Math.abs(wRY - wSAY) < 270) { 59056 wSAY = wRY; 59057 59058 this._setProperty('turnAxis', 'Y'); 59059 59060 deviceTurned(); 59061 } 59062 59063 pRotateDirectionY = rotateDirectionY; 59064 startAngleY = wSAY - 180; // Z-axis is already in the range 0 to 360 59065 // so no conversion is needed. 59066 59067 if (this.rotationZ - this.pRotationZ > 0 && this.rotationZ - this.pRotationZ < 270 || this.rotationZ - this.pRotationZ < -270) { 59068 rotateDirectionZ = 'clockwise'; 59069 } else if (this.rotationZ - this.pRotationZ < 0 || this.rotationZ - this.pRotationZ > 270) { 59070 rotateDirectionZ = 'counter-clockwise'; 59071 } 59072 59073 if (rotateDirectionZ !== pRotateDirectionZ) { 59074 startAngleZ = this.rotationZ; 59075 } 59076 59077 if (Math.abs(this.rotationZ - startAngleZ) > 90 && Math.abs(this.rotationZ - startAngleZ) < 270) { 59078 startAngleZ = this.rotationZ; 59079 59080 this._setProperty('turnAxis', 'Z'); 59081 59082 deviceTurned(); 59083 } 59084 59085 pRotateDirectionZ = rotateDirectionZ; 59086 59087 this._setProperty('turnAxis', undefined); 59088 } 59089 59090 var deviceShaken = this.deviceShaken || window.deviceShaken; 59091 59092 if (typeof deviceShaken === 'function') { 59093 var accelerationChangeX; 59094 var accelerationChangeY; // Add accelerationChangeZ if acceleration change on Z is needed 59095 59096 if (this.pAccelerationX !== null) { 59097 accelerationChangeX = Math.abs(this.accelerationX - this.pAccelerationX); 59098 accelerationChangeY = Math.abs(this.accelerationY - this.pAccelerationY); 59099 } 59100 59101 if (accelerationChangeX + accelerationChangeY > shake_threshold) { 59102 deviceShaken(); 59103 } 59104 } 59105 }; 59106 59107 module.exports = p5; 59108 }, {
59109 "../core/main": 24 59110 }], 59111 39: [function (_dereq_, module, exports) { 59112 /** 59113 * @module Events 59114 * @submodule Keyboard 59115 * @for p5 59116 * @requires core 59117 */ 59118 'use strict'; 59119 59120 var p5 = _dereq_('../core/main'); 59121 /** 59122 * Holds the key codes of currently pressed keys. 59123 * @private 59124 */ 59125 59126 59127 var downKeys = {}; 59128 /** 59129 * The boolean system variable <a href="#/p5/keyIsPressed">keyIsPressed</a> is true if any key is pressed 59130 * and false if no keys are pressed. 59131 * 59132 * @property {Boolean} keyIsPressed 59133 * @readOnly 59134 * @example 59135 * <div> 59136 * <code> 59137 * function draw() { 59138 * if (keyIsPressed === true) { 59139 * fill(0); 59140 * } else { 59141 * fill(255); 59142 * } 59143 * rect(25, 25, 50, 50); 59144 * } 59145 * </code> 59146 * </div> 59147 * 59148 * @alt 59149 * 50x50 white rect that turns black on keypress. 59150 * 59151 */ 59152 59153 p5.prototype.isKeyPressed = false; 59154 p5.prototype.keyIsPressed = false; // khan 59155 59156 /** 59157 * The system variable key always contains the value of the most recent 59158 * key on the keyboard that was typed. To get the proper capitalization, it 59159 * is best to use it within <a href="#/p5/keyTyped">keyTyped()</a>. For non-ASCII keys, use the <a href="#/p5/keyCode">keyCode</a> 59160 * variable. 59161 * 59162 * @property {String} key 59163 * @readOnly 59164 * @example 59165 * <div><code> 59166 * // Click any key to display it! 59167 * // (Not Guaranteed to be Case Sensitive) 59168 * function setup() { 59169 * fill(245, 123, 158); 59170 * textSize(50); 59171 * } 59172 * 59173 * function draw() { 59174 * background(200); 59175 * text(key, 33, 65); // Display last key pressed. 59176 * } 59177 * </code></div> 59178 * 59179 * @alt 59180 * canvas displays any key value that is pressed in pink font. 59181 * 59182 */ 59183 59184 p5.prototype.key = ''; 59185 /** 59186 * The variable keyCode is used to detect special keys such as BACKSPACE, 59187 * DELETE, ENTER, RETURN, TAB, ESCAPE, SHIFT, CONTROL, OPTION, ALT, UP_ARROW, 59188 * DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW. 59189 * You can also check for custom keys by looking up the keyCode of any key 59190 * on a site like this: <a href="http://keycode.info/">keycode.info</a>. 59191 * 59192 * @property {Integer} keyCode 59193 * @readOnly 59194 * @example 59195 * <div><code> 59196 * let fillVal = 126; 59197 * function draw() { 59198 * fill(fillVal); 59199 * rect(25, 25, 50, 50); 59200 * } 59201 * 59202 * function keyPressed() { 59203 * if (keyCode === UP_ARROW) { 59204 * fillVal = 255; 59205 * } else if (keyCode === DOWN_ARROW) { 59206 * fillVal = 0; 59207 * } 59208 * return false; // prevent default 59209 * } 59210 * </code></div> 59211 * 59212 * @alt 59213 * Grey rect center. turns white when up arrow pressed and black when down 59214 * 59215 */ 59216 59217 p5.prototype.keyCode = 0; 59218 /** 59219 * The <a href="#/p5/keyPressed">keyPressed()</a> function is called once every time a key is pressed. The 59220 * keyCode for the key that was pressed is stored in the <a href="#/p5/keyCode">keyCode</a> variable. 59221 * <br><br> 59222 * For non-ASCII keys, use the keyCode variable. You can check if the keyCode 59223 * equals BACKSPACE, DELETE, ENTER, RETURN, TAB, ESCAPE, SHIFT, CONTROL, 59224 * OPTION, ALT, UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW. 59225 * <br><br> 59226 * For ASCII keys, the key that was pressed is stored in the key variable. However, it 59227 * does not distinguish between uppercase and lowercase. For this reason, it 59228 * is recommended to use <a href="#/p5/keyTyped">keyTyped()</a> to read the key variable, in which the 59229 * case of the variable will be distinguished.
59230 * <br><br> 59231 * Because of how operating systems handle key repeats, holding down a key 59232 * may cause multiple calls to <a href="#/p5/keyTyped">keyTyped()</a> (and <a href="#/p5/keyReleased">keyReleased()</a> as well). The 59233 * rate of repeat is set by the operating system and how each computer is 59234 * configured.<br><br> 59235 * Browsers may have different default 59236 * behaviors attached to various key events. To prevent any default 59237 * behavior for this event, add "return false" to the end of the method. 59238 * 59239 * @method keyPressed 59240 * @example 59241 * <div> 59242 * <code> 59243 * let value = 0; 59244 * function draw() { 59245 * fill(value); 59246 * rect(25, 25, 50, 50); 59247 * } 59248 * function keyPressed() { 59249 * if (value === 0) { 59250 * value = 255; 59251 * } else { 59252 * value = 0; 59253 * } 59254 * } 59255 * </code> 59256 * </div> 59257 * <div> 59258 * <code> 59259 * let value = 0; 59260 * function draw() { 59261 * fill(value); 59262 * rect(25, 25, 50, 50); 59263 * } 59264 * function keyPressed() { 59265 * if (keyCode === LEFT_ARROW) { 59266 * value = 255; 59267 * } else if (keyCode === RIGHT_ARROW) { 59268 * value = 0; 59269 * } 59270 * } 59271 * </code> 59272 * </div> 59273 * <div class="norender"> 59274 * <code> 59275 * function keyPressed() { 59276 * // Do something 59277 * return false; // prevent any default behaviour 59278 * } 59279 * </code> 59280 * </div> 59281 * 59282 * @alt 59283 * black rect center. turns white when key pressed and black when released 59284 * black rect center. turns white when left arrow pressed and black when right. 59285 * 59286 */ 59287 59288 p5.prototype._onkeydown = function (e) {
59289 if (downKeys[e.which]) { 59290 // prevent multiple firings 59291 return; 59292 } 59293 59294 this._setProperty('isKeyPressed', true); 59295 59296 this._setProperty('keyIsPressed', true); 59297 59298 this._setProperty('keyCode', e.which); 59299 59300 downKeys[e.which] = true; 59301 59302 this._setProperty('key', e.key || String.fromCharCode(e.which) || e.which); 59303 59304 var keyPressed = this.keyPressed || window.keyPressed; 59305 59306 if (typeof keyPressed === 'function' && !e.charCode) { 59307 var executeDefault = keyPressed(e); 59308 59309 if (executeDefault === false) { 59310 e.preventDefault(); 59311 } 59312 } 59313 }; 59314 /** 59315 * The <a href="#/p5/keyReleased">keyReleased()</a> function is called once every time a key is released. 59316 * See <a href="#/p5/key">key</a> and <a href="#/p5/keyCode">keyCode</a> for more information.<br><br> 59317 * Browsers may have different default 59318 * behaviors attached to various key events. To prevent any default 59319 * behavior for this event, add "return false" to the end of the method. 59320 * 59321 * @method keyReleased 59322 * @example 59323 * <div> 59324 * <code> 59325 * let value = 0; 59326 * function draw() { 59327 * fill(value); 59328 * rect(25, 25, 50, 50); 59329 * } 59330 * function keyReleased() { 59331 * if (value === 0) { 59332 * value = 255; 59333 * } else { 59334 * value = 0; 59335 * } 59336 * return false; // prevent any default behavior 59337 * } 59338 * </code> 59339 * </div> 59340 * 59341 * @alt 59342 * black rect center. turns white when key pressed and black when pressed again 59343 * 59344 */ 59345 59346 59347 p5.prototype._onkeyup = function (e) { 59348 var keyReleased = this.keyReleased || window.keyReleased; 59349 downKeys[e.which] = false; 59350 59351 if (!areDownKeys()) { 59352 this._setProperty('isKeyPressed', false); 59353 59354 this._setProperty('keyIsPressed', false); 59355 } 59356 59357 this._setProperty('_lastKeyCodeTyped', null); 59358 59359 this._setProperty('key', e.key || String.fromCharCode(e.which) || e.which); 59360 59361 this._setProperty('keyCode', e.which); 59362 59363 if (typeof keyReleased === 'function') { 59364 var executeDefault = keyReleased(e); 59365 59366 if (executeDefault === false) { 59367 e.preventDefault(); 59368 } 59369 } 59370 }; 59371 /** 59372 * The <a href="#/p5/keyTyped">keyTyped()</a> function is called once every time a key is pressed, but 59373 * action keys such as Ctrl, Shift, and Alt are ignored. The most recent 59374 * key pressed will be stored in the key variable. 59375 * <br><br> 59376 * Because of how operating systems handle key repeats, holding down a key 59377 * will cause multiple calls to <a href="#/p5/keyTyped">keyTyped()</a> (and <a href="#/p5/keyReleased">keyReleased()</a> as well). The 59378 * rate of repeat is set by the operating system and how each computer is 59379 * configured.<br><br> 59380 * Browsers may have different default behaviors attached to various key 59381 * events. To prevent any default behavior for this event, add "return false" 59382 * to the end of the method. 59383 * 59384 * @method keyTyped 59385 * @example 59386 * <div> 59387 * <code> 59388 * let value = 0; 59389 * function draw() { 59390 * fill(value); 59391 * rect(25, 25, 50, 50); 59392 * } 59393 * function keyTyped() { 59394 * if (key === 'a') { 59395 * value = 255; 59396 * } else if (key === 'b') { 59397 * value = 0; 59398 * } 59399 * // uncomment to prevent any default behavior 59400 * // return false; 59401 * } 59402 * </code> 59403 * </div> 59404 * 59405 * @alt 59406 * black rect center. turns white when 'a' key typed and black when 'b' pressed 59407 * 59408 */ 59409 59410 59411 p5.prototype._onkeypress = function (e) { 59412 if (e.which === this._lastKeyCodeTyped) { 59413 // prevent multiple firings 59414 return; 59415 } 59416 59417 this._setProperty('keyCode', e.which); 59418 59419 this._setProperty('_lastKeyCodeTyped', e.which); // track last keyCode 59420 59421 59422 this._setProperty('key', String.fromCharCode(e.which)); 59423 59424 var keyTyped = this.keyTyped || window.keyTyped; 59425 59426 if (typeof keyTyped === 'function') { 59427 var executeDefault = keyTyped(e); 59428 59429 if (executeDefault === false) { 59430 e.preventDefault(); 59431 } 59432 } 59433 }; 59434 /** 59435 * The onblur function is called when the user is no longer focused 59436 * on the p5 element. Because the keyup events will not fire if the user is 59437 * not focused on the element we must assume all keys currently down have 59438 * been released. 59439 */ 59440 59441 59442 p5.prototype._onblur = function (e) { 59443 downKeys = {}; 59444 }; 59445 /** 59446 * The <a href="#/p5/keyIsDown">keyIsDown()</a> function checks if the key is currently down, i.e. pressed. 59447 * It can be used if you have an object that moves, and you want several keys 59448 * to be able to affect its behaviour simultaneously, such as moving a 59449 * sprite diagonally. You can put in any number representing the keyCode of 59450 * the key, or use any of the variable <a href="#/p5/keyCode">keyCode</a> names listed 59451 * <a href="http://p5js.org/reference/#p5/keyCode">here</a>. 59452 * 59453 * @method keyIsDown 59454 * @param {Number} code The key to check for. 59455 * @return {Boolean} whether key is down or not 59456 * @example 59457 * <div><code> 59458 * let x = 100; 59459 * let y = 100; 59460 * 59461 * function setup() { 59462 * createCanvas(512, 512); 59463 * } 59464 * 59465 * function draw() { 59466 * if (keyIsDown(LEFT_ARROW)) { 59467 * x -= 5; 59468 * } 59469 * 59470 * if (keyIsDown(RIGHT_ARROW)) { 59471 * x += 5; 59472 * } 59473 * 59474 * if (keyIsDown(UP_ARROW)) { 59475 * y -= 5; 59476 * } 59477 * 59478 * if (keyIsDown(DOWN_ARROW)) { 59479 * y += 5; 59480 * } 59481 * 59482 * clear(); 59483 * fill(255, 0, 0); 59484 * ellipse(x, y, 50, 50); 59485 * } 59486 * </code></div> 59487 * 59488 * <div><code> 59489 * let diameter = 50; 59490 * 59491 * function setup() { 59492 * createCanvas(512, 512); 59493 * } 59494 * 59495 * function draw() { 59496 * // 107 and 187 are keyCodes for "+" 59497 * if (keyIsDown(107) || keyIsDown(187)) { 59498 * diameter += 1; 59499 * } 59500 *
59501 * // 109 and 189 are keyCodes for "-" 59502 * if (keyIsDown(109) || keyIsDown(189)) { 59503 * diameter -= 1; 59504 * } 59505 * 59506 * clear(); 59507 * fill(255, 0, 0); 59508 * ellipse(50, 50, diameter, diameter); 59509 * } 59510 * </code></div> 59511 * 59512 * @alt 59513 * 50x50 red ellipse moves left, right, up and down with arrow presses. 59514 * 50x50 red ellipse gets bigger or smaller when + or - are pressed. 59515 * 59516 */ 59517 59518 59519 p5.prototype.keyIsDown = function (code) { 59520 p5._validateParameters('keyIsDown', arguments); 59521 59522 return downKeys[code]; 59523 }; 59524 /** 59525 * The checkDownKeys function returns a boolean true if any keys pressed 59526 * and a false if no keys are currently pressed. 59527 59528 * Helps avoid instances where a multiple keys are pressed simultaneously and 59529 * releasing a single key will then switch the 59530 * keyIsPressed property to true. 59531 * @private 59532 **/ 59533 59534 59535 function areDownKeys() { 59536 for (var key in downKeys) { 59537 if (downKeys.hasOwnProperty(key) && downKeys[key] === true) { 59538 return true; 59539 } 59540 } 59541 59542 return false; 59543 } 59544 59545 module.exports = p5; 59546 }, {
59547 "../core/main": 24 59548 }], 59549 40: [function (_dereq_, module, exports) { 59550 /** 59551 * @module Events 59552 * @submodule Mouse 59553 * @for p5 59554 * @requires core 59555 * @requires constants 59556 */ 59557 'use strict'; 59558 59559 var p5 = _dereq_('../core/main'); 59560 59561 var constants = _dereq_('../core/constants'); 59562 /* 59563 * This is a flag which is false until the first time 59564 * we receive a mouse event. The pmouseX and pmouseY 59565 * values will match the mouseX and mouseY values until 59566 * this interaction takes place. 59567 */ 59568 59569 59570 p5.prototype._hasMouseInteracted = false; 59571 /** 59572 * The system variable mouseX always contains the current horizontal 59573 * position of the mouse, relative to (0, 0) of the canvas. If touch is 59574 * used instead of mouse input, mouseX will hold the x value of the most 59575 * recent touch point. 59576 * 59577 * @property {Number} mouseX 59578 * @readOnly 59579 * 59580 * @example 59581 * <div> 59582 * <code> 59583 * // Move the mouse across the canvas 59584 * function draw() { 59585 * background(244, 248, 252); 59586 * line(mouseX, 0, mouseX, 100); 59587 * } 59588 * </code> 59589 * </div> 59590 * 59591 * @alt 59592 * horizontal black line moves left and right with mouse x-position 59593 * 59594 */ 59595 59596 p5.prototype.mouseX = 0; 59597 /** 59598 * The system variable mouseY always contains the current vertical position 59599 * of the mouse, relative to (0, 0) of the canvas. If touch is 59600 * used instead of mouse input, mouseY will hold the y value of the most 59601 * recent touch point. 59602 * 59603 * @property {Number} mouseY 59604 * @readOnly 59605 * 59606 * @example 59607 * <div> 59608 * <code> 59609 * // Move the mouse across the canvas 59610 * function draw() { 59611 * background(244, 248, 252); 59612 * line(0, mouseY, 100, mouseY); 59613 * } 59614 * </code> 59615 * </div> 59616 * 59617 * @alt 59618 * vertical black line moves up and down with mouse y-position 59619 * 59620 */ 59621 59622 p5.prototype.mouseY = 0; 59623 /** 59624 * The system variable pmouseX always contains the horizontal position of 59625 * the mouse or finger in the frame previous to the current frame, relative to 59626 * (0, 0) of the canvas. Note: pmouseX will be reset to the current mouseX 59627 * value at the start of each touch event. 59628 * 59629 * @property {Number} pmouseX 59630 * @readOnly 59631 * 59632 * @example 59633 * <div> 59634 * <code> 59635 * // Move the mouse across the canvas to leave a trail 59636 * function setup() { 59637 * //slow down the frameRate to make it more visible 59638 * frameRate(10); 59639 * } 59640 * 59641 * function draw() { 59642 * background(244, 248, 252); 59643 * line(mouseX, mouseY, pmouseX, pmouseY); 59644 * print(pmouseX + ' -> ' + mouseX); 59645 * } 59646 * </code> 59647 * </div> 59648 * 59649 * @alt 59650 * line trail is created from cursor movements. faster movement make longer line. 59651 * 59652 */ 59653 59654 p5.prototype.pmouseX = 0; 59655 /** 59656 * The system variable pmouseY always contains the vertical position of the 59657 * mouse or finger in the frame previous to the current frame, relative to 59658 * (0, 0) of the canvas. Note: pmouseY will be reset to the current mouseY 59659 * value at the start of each touch event. 59660 * 59661 * @property {Number} pmouseY 59662 * @readOnly 59663 * 59664 * @example 59665 * <div> 59666 * <code> 59667 * function draw() { 59668 * background(237, 34, 93); 59669 * fill(0); 59670 * //draw a square only if the mouse is not moving 59671 * if (mouseY === pmouseY && mouseX === pmouseX) { 59672 * rect(20, 20, 60, 60); 59673 * } 59674 * 59675 * print(pmouseY + ' -> ' + mouseY); 59676 * } 59677 * </code> 59678 * </div> 59679 * 59680 * @alt 59681 * 60x60 black rect center, fuschia background. rect flickers on mouse movement 59682 * 59683 */ 59684 59685 p5.prototype.pmouseY = 0; 59686 /** 59687 * The system variable winMouseX always contains the current horizontal 59688 * position of the mouse, relative to (0, 0) of the window. 59689 * 59690 * @property {Number} winMouseX 59691 * @readOnly 59692 * 59693 * @example 59694 * <div> 59695 * <code> 59696 * let myCanvas; 59697 * 59698 * function setup() { 59699 * //use a variable to store a pointer to the canvas 59700 * myCanvas = createCanvas(100, 100); 59701 * } 59702 * 59703 * function draw() { 59704 * background(237, 34, 93); 59705 * fill(0); 59706 * 59707 * //move the canvas to the horizontal mouse position 59708 * //rela tive to the window 59709 * myCanvas.position(winMouseX + 1, windowHeight / 2); 59710 * 59711 * //the y of the square is relative to the canvas 59712 * rect(20, mouseY, 60, 60); 59713 * } 59714 * </code> 59715 * </div> 59716 * 59717 * @alt 59718 * 60x60 black rect y moves with mouse y and fuschia canvas moves with mouse x 59719 * 59720 */ 59721 59722 p5.prototype.winMouseX = 0; 59723 /** 59724 * The system variable winMouseY always contains the current vertical 59725 * position of the mouse, relative to (0, 0) of the window. 59726 * 59727 * @property {Number} winMouseY 59728 * @readOnly 59729 * 59730 * @example 59731 * <div> 59732 * <code> 59733 * let myCanvas; 59734 * 59735 * function setup() { 59736 * //use a variable to store a pointer to the canvas 59737 * myCanvas = createCanvas(100, 100); 59738 * } 59739 * 59740 * function draw() { 59741 * background(237, 34, 93); 59742 * fill(0); 59743 * 59744 * //move the canvas to the vertical mouse position 59745 * //rel ative to the window
59746 * myCanvas.position(windowWidth / 2, winMouseY + 1); 59747 * 59748 * //the x of the square is relative to the canvas 59749 * rect(mouseX, 20, 60, 60); 59750 * } 59751 * </code> 59752 * </div> 59753 * 59754 * @alt 59755 * 60x60 black rect x moves with mouse x and fuschia canvas y moves with mouse y 59756 * 59757 */ 59758 59759 p5.prototype.winMouseY = 0; 59760 /** 59761 * The system variable pwinMouseX always contains the horizontal position 59762 * of the mouse in the frame previous to the current frame, relative to 59763 * (0, 0) of the window. Note: pwinMouseX will be reset to the current winMouseX 59764 * value at the start of each touch event. 59765 * 59766 * @property {Number} pwinMouseX 59767 * @readOnly 59768 * 59769 * @example 59770 * <div> 59771 * <code> 59772 * let myCanvas; 59773 * 59774 * function setup() { 59775 * //use a variable to store a pointer to the canvas 59776 * myCanvas = createCanvas(100, 100); 59777 * noStroke(); 59778 * fill(237, 34, 93); 59779 * } 59780 * 59781 * function draw() { 59782 * clear(); 59783 * //the difference between previous and 59784 * //current x position is the horizontal mouse speed 59785 * let speed = abs(winMouseX - pwinMouseX); 59786 * //change the size of the circle 59787 * //according to the horizontal speed 59788 * ellipse(50, 50, 10 + speed * 5, 10 + speed * 5); 59789 * //move the canvas to the mouse position 59790 * myCanvas.position(winMouseX + 1, winMouseY + 1); 59791 * } 59792 * </code> 59793 * </div> 59794 * 59795 * @alt 59796 * fuschia ellipse moves with mouse x and y. Grows and shrinks with mouse speed 59797 * 59798 */ 59799 59800 p5.prototype.pwinMouseX = 0; 59801 /** 59802 * The system variable pwinMouseY always contains the vertical position of 59803 * the mouse in the frame previous to the current frame, relative to (0, 0) 59804 * of the window. Note: pwinMouseY will be reset to the current winMouseY 59805 * value at the start of each touch event. 59806 * 59807 * @property {Number} pwinMouseY 59808 * @readOnly 59809 * 59810 * 59811 * @example 59812 * <div> 59813 * <code> 59814 * let myCanvas; 59815 * 59816 * function setup() { 59817 * //use a variable to store a pointer to the canvas 59818 * myCanvas = createCanvas(100, 100); 59819 * noStroke(); 59820 * fill(237, 34, 93); 59821 * } 59822 * 59823 * function draw() { 59824 * clear(); 59825 * //the difference between previous and 59826 * //current y position is the vertical mouse speed 59827 * let speed = abs(winMouseY - pwinMouseY); 59828 * //change the size of the circle 59829 * //according to the vertical speed 59830 * ellipse(50, 50, 10 + speed * 5, 10 + speed * 5); 59831 * //move the canvas to the mouse position 59832 * myCanvas.position(winMouseX + 1, winMouseY + 1); 59833 * } 59834 * </code> 59835 * </div> 59836 * 59837 * @alt 59838 * fuschia ellipse moves with mouse x and y. Grows and shrinks with mouse speed 59839 * 59840 */ 59841 59842 p5.prototype.pwinMouseY = 0; 59843 /** 59844 * Processing automatically tracks if the mouse button is pressed and which 59845 * button is pressed. The value of the system variable mouseButton is either 59846 * LEFT, RIGHT, or CENTER depending on which button was pressed last. 59847 * Warning: different browsers may track mouseButton differently. 59848 * 59849 * @property {Constant} mouseButton 59850 * @readOnly 59851 * 59852 * @example 59853 * <div> 59854 * <code> 59855 * function draw() { 59856 * background(237, 34, 93); 59857 * fill(0); 59858 * 59859 * if (mouseIsPressed) { 59860 * if (mouseButton === LEFT) { 59861 * ellipse(50, 50, 50, 50); 59862 * } 59863 * if (mouseButton === RIGHT) { 59864 * rect(25, 25, 50, 50); 59865 * } 59866 * if (mouseButton === CENTER) { 59867 * triangle(23, 75, 50, 20, 78, 75); 59868 * } 59869 * } 59870 * 59871 * print(mouseButton); 59872 * } 59873 * </code> 59874 * </div> 59875 * 59876 * @alt 59877 * 50x50 black ellipse appears on center of fuschia canvas on mouse click/press. 59878 * 59879 */ 59880 59881 p5.prototype.mouseButton = 0; 59882 /** 59883 * The boolean system variable mouseIsPressed is true if the mouse is pressed 59884 * and false if not. 59885 * 59886 * @property {Boolean} mouseIsPressed 59887 * @readOnly 59888 * 59889 * @example 59890 * <div> 59891 * <code> 59892 * function draw() { 59893 * background(237, 34, 93); 59894 * fill(0); 59895 * 59896 * if (mouseIsPressed) { 59897 * ellipse(50, 50, 50, 50); 59898 * } else { 59899 * rect(25, 25, 50, 50); 59900 * } 59901 * 59902 * print(mouseIsPressed); 59903 * } 59904 * </code> 59905 * </div> 59906 * 59907 * @alt
59908 * black 50x50 rect becomes ellipse with mouse click/press. fuschia background. 59909 * 59910 */ 59911 59912 p5.prototype.mouseIsPressed = false; 59913 59914 p5.prototype._updateNextMouseCoords = function (e) { 59915 if (this._curElement !== null && (!e.touches || e.touches.length > 0)) { 59916 var mousePos = getMousePos(this._curElement.elt, this.width, this.height, e); 59917 59918 this._setProperty('mouseX', mousePos.x); 59919 59920 this._setProperty('mouseY', mousePos.y); 59921 59922 this._setProperty('winMouseX', mousePos.winX); 59923 59924 this._setProperty('winMouseY', mousePos.winY); 59925 } 59926 59927 if (!this._hasMouseInteracted) { 59928 // For first draw, make previous and next equal 59929 this._updateMouseCoords(); 59930 59931 this._setProperty('_hasMouseInteracted', true); 59932 } 59933 }; 59934 59935 p5.prototype._updateMouseCoords = function () { 59936 this._setProperty('pmouseX', this.mouseX); 59937 59938 this._setProperty('pmouseY', this.mouseY); 59939 59940 this._setProperty('pwinMouseX', this.winMouseX); 59941 59942 this._setProperty('pwinMouseY', this.winMouseY); 59943 59944 this._setProperty('_pmouseWheelDeltaY', this._mouseWheelDeltaY); 59945 }; 59946 59947 function getMousePos(canvas, w, h, evt) { 59948 if (evt && !evt.clientX) { 59949 // use touches if touch and not mouse 59950 if (evt.touches) { 59951 evt = evt.touches[0]; 59952 } else if (evt.changedTouches) { 59953 evt = evt.changedTouches[0]; 59954 } 59955 } 59956 59957 var rect = canvas.getBoundingClientRect(); 59958 var sx = canvas.scrollWidth / w; 59959 var sy = canvas.scrollHeight / h; 59960 return { 59961 x: (evt.clientX - rect.left) / sx, 59962 y: (evt.clientY - rect.top) / sy, 59963 winX: evt.clientX, 59964 winY: evt.clientY, 59965 id: evt.identifier 59966 }; 59967 } 59968 59969 p5.prototype._setMouseButton = function (e) { 59970 if (e.button === 1) { 59971 this._setProperty('mouseButton', constants.CENTER); 59972 } else if (e.button === 2) { 59973 this._setProperty('mouseButton', constants.RIGHT); 59974 } else { 59975 this._setProperty('mouseButton', constants.LEFT); 59976 } 59977 }; 59978 /** 59979 * The <a href="#/p5/mouseMoved">mouseMoved()</a> function is called every time the mouse moves and a mouse 59980 * button is not pressed.<br><br> 59981 * Browsers may have different default 59982 * behaviors attached to various mouse events. To prevent any default 59983 * behavior for this event, add "return false" to the end of the method. 59984 * 59985 * @method mouseMoved 59986 * @param {Object} [event] optional MouseEvent callback argument. 59987 * @example 59988 * <div> 59989 * <code> 59990 * // Move the mouse across the page 59991 * // to change its value 59992 * 59993 * let value = 0; 59994 * function draw() { 59995 * fill(value); 59996 * rect(25, 25, 50, 50); 59997 * } 59998 * function mouseMoved() { 59999 * value = value + 5; 60000 * if (value > 255) { 60001 * value = 0; 60002 * } 60003 * } 60004 * </code> 60005 * </div> 60006 * 60007 * <div class="norender"> 60008 * <code> 60009 * function mouseMoved() { 60010 * ellipse(mouseX, mouseY, 5, 5); 60011 * // prevent default 60012 * return false; 60013 * } 60014 * </code> 60015 * </div> 60016 * 60017 * <div class="norender"> 60018 * <code> 60019 * // returns a MouseEvent object 60020 * // as a callback argument 60021 * function mouseMoved(event) { 60022 * console.log(event); 60023 * } 60024 * </code> 60025 * </div> 60026 * 60027 * @alt 60028 * black 50x50 rect becomes lighter with mouse movements until white then resets 60029 * no image displayed 60030 * 60031 */ 60032 60033 /** 60034 * The <a href="#/p5/mouseDragged">mouseDragged()</a> function is called once every time the mouse moves and 60035 * a mouse button is pressed. If no <a href="#/p5/mouseDragged">mouseDragged()</a> function is defined, the 60036 * <a href="#/p5/touchMoved">touchMoved()</a> function will be called instead if it is defined.<br><br> 60037 * Browsers may have different default 60038 * behaviors attached to various mouse events. To prevent any default 60039 * behavior for this event, add "return false" to the end of the method. 60040 * 60041 * @method mouseDragged 60042 * @param {Object} [event] optional MouseEvent callback argument. 60043 * @example 60044 * <div> 60045 * <code> 60046 * // Drag the mouse across the page 60047 * // to change its value 60048 * 60049 * let value = 0; 60050 * function draw() { 60051 * fill(value); 60052 * rect(25, 25, 50, 50); 60053 * } 60054 * function mouseDragged() { 60055 * value = value + 5; 60056 * if (value > 255) { 60057 * value = 0; 60058 * } 60059 * } 60060 * </code> 60061 * </div> 60062 * 60063 * <div class="norender"> 60064 * <code> 60065 * function mouseDragged() { 60066 * ellipse(mouseX, mouseY, 5, 5); 60067 * // prevent default 60068 * return false;
60069 * } 60070 * </code> 60071 * </div> 60072 * 60073 * <div class="norender"> 60074 * <code> 60075 * // returns a MouseEvent object 60076 * // as a callback argument 60077 * function mouseDragged(event) { 60078 * console.log(event); 60079 * } 60080 * </code> 60081 * </div> 60082 * 60083 * @alt 60084 * black 50x50 rect turns lighter with mouse click and drag until white, resets 60085 * no image displayed 60086 * 60087 */ 60088 60089 60090 p5.prototype._onmousemove = function (e) { 60091 var context = this._isGlobal ? window : this; 60092 var executeDefault; 60093 60094 this._updateNextMouseCoords(e); 60095 60096 if (!this.mouseIsPressed) { 60097 if (typeof context.mouseMoved === 'function') { 60098 executeDefault = context.mouseMoved(e); 60099 60100 if (executeDefault === false) { 60101 e.preventDefault(); 60102 } 60103 } 60104 } else { 60105 if (typeof context.mouseDragged === 'function') { 60106 executeDefault = context.mouseDragged(e); 60107 60108 if (executeDefault === false) { 60109 e.preventDefault(); 60110 } 60111 } else if (typeof context.touchMoved === 'function') { 60112 executeDefault = context.touchMoved(e); 60113 60114 if (executeDefault === false) { 60115 e.preventDefault(); 60116 } 60117 } 60118 } 60119 }; 60120 /** 60121 * The <a href="#/p5/mousePressed">mousePressed()</a> function is called once after every time a mouse button 60122 * is pressed. The mouseButton variable (see the related reference entry) 60123 * can be used to determine which button has been pressed. If no 60124 * <a href="#/p5/mousePressed">mousePressed()</a> function is defined, the <a href="#/p5/touchStarted">touchStarted()</a> function will be 60125 * called instead if it is defined.<br><br> 60126 * Browsers may have different default 60127 * behaviors attached to various mouse events. To prevent any default 60128 * behavior for this event, add "return false" to the end of the method. 60129 * 60130 * @method mousePressed 60131 * @param {Object} [event] optional MouseEvent callback argument. 60132 * @example 60133 * <div> 60134 * <code> 60135 * // Click within the image to change 60136 * // the value of the rectangle 60137 * 60138 * let value = 0; 60139 * function draw() { 60140 * fill(value); 60141 * rect(25, 25, 50, 50); 60142 * } 60143 * function mousePressed() { 60144 * if (value === 0) { 60145 * value = 255; 60146 * } else { 60147 * value = 0; 60148 * } 60149 * } 60150 * </code> 60151 * </div> 60152 * 60153 * <div class="norender"> 60154 * <code> 60155 * function mousePressed() { 60156 * ellipse(mouseX, mouseY, 5, 5); 60157 * // prevent default 60158 * return false; 60159 * } 60160 * </code> 60161 * </div> 60162 * 60163 * <div class="norender"> 60164 * <code> 60165 * // returns a MouseEvent object 60166 * // as a callback argument 60167 * function mousePressed(event) { 60168 * console.log(event); 60169 * } 60170 * </code> 60171 * </div> 60172 * 60173 * @alt 60174 * black 50x50 rect turns white with mouse click/press. 60175 * no image displayed 60176 * 60177 */ 60178 60179 60180 p5.prototype._onmousedown = function (e) { 60181 var context = this._isGlobal ? window : this; 60182 var executeDefault; 60183 60184 this._setProperty('mouseIsPressed', true); 60185 60186 this._setMouseButton(e); 60187 60188 this._updateNextMouseCoords(e); 60189 60190 if (typeof context.mousePressed === 'function') { 60191 executeDefault = context.mousePressed(e); 60192 60193 if (executeDefault === false) { 60194 e.preventDefault(); 60195 } 60196 } else if (typeof context.touchStarted === 'function') { 60197 executeDefault = context.touchStarted(e); 60198 60199 if (executeDefault === false) { 60200 e.preventDefault(); 60201 } 60202 } 60203 }; 60204 /** 60205 * The <a href="#/p5/mouseReleased">mouseReleased()</a> function is called every time a mouse button is 60206 * released. If no <a href="#/p5/mouseReleased">mouseReleased()</a> function is defined, the <a href="#/p5/touchEnded">touchEnded()</a> 60207 * function will be called instead if it is defined.<br><br> 60208 * Browsers may have different default 60209 * behaviors attached to various mouse events. To prevent any default 60210 * behavior for this event, add "return false" to the end of the method. 60211 * 60212 * 60213 * @method mouseReleased 60214 * @param {Object} [event] optional MouseEvent callback argument. 60215 * @example 60216 * <div> 60217 * <code> 60218 * // Click within the image to change 60219 * // the value of the rectangle 60220 * // after the mouse has been clicked 60221 * 60222 * let value = 0; 60223 * function draw() { 60224 * fill(value); 60225 * rect(25, 25, 50, 50); 60226 * } 60227 * function mouseReleased() { 60228 * if (value === 0) { 60229 * value = 255; 60230 * } else { 60231 * value = 0; 60232 * } 60233 * } 60234 * </code> 60235 * </div> 60236 * 60237 * <div class="norender"> 60238 * <code> 60239 * function mouseReleased() { 60240 * ellipse(mouseX, mouseY, 5, 5); 60241 * // prevent default 60242 * return false;
60243 * } 60244 * </code> 60245 * </div> 60246 * 60247 * <div class="norender"> 60248 * <code> 60249 * // returns a MouseEvent object 60250 * // as a callback argument 60251 * function mouseReleased(event) { 60252 * console.log(event); 60253 * } 60254 * </code> 60255 * </div> 60256 * 60257 * @alt 60258 * black 50x50 rect turns white with mouse click/press. 60259 * no image displayed 60260 * 60261 */ 60262 60263 60264 p5.prototype._onmouseup = function (e) { 60265 var context = this._isGlobal ? window : this; 60266 var executeDefault; 60267 60268 this._setProperty('mouseIsPressed', false); 60269 60270 if (typeof context.mouseReleased === 'function') { 60271 executeDefault = context.mouseReleased(e); 60272 60273 if (executeDefault === false) { 60274 e.preventDefault(); 60275 } 60276 } else if (typeof context.touchEnded === 'function') { 60277 executeDefault = context.touchEnded(e); 60278 60279 if (executeDefault === false) { 60280 e.preventDefault(); 60281 } 60282 } 60283 }; 60284 60285 p5.prototype._ondragend = p5.prototype._onmouseup; 60286 p5.prototype._ondragover = p5.prototype._onmousemove; 60287 /** 60288 * The <a href="#/p5/mouseClicked">mouseClicked()</a> function is called once after a mouse button has been 60289 * pressed and then released.<br><br> 60290 * Browsers handle clicks differently, so this function is only guaranteed to be 60291 * run when the left mouse button is clicked. To handle other mouse buttons 60292 * being pressed or released, see <a href="#/p5/mousePressed">mousePressed()</a> or <a href="#/p5/mouseReleased">mouseReleased()</a>.<br><br> 60293 * Browsers may have different default 60294 * behaviors attached to various mouse events. To prevent any default 60295 * behavior for this event, add "return false" to the end of the method. 60296 * 60297 * @method mouseClicked 60298 * @param {Object} [event] optional MouseEvent callback argument. 60299 * @example 60300 * <div> 60301 * <code> 60302 * // Click within the image to change 60303 * // the value of the rectangle 60304 * // after the mouse has been clicked 60305 * 60306 * let value = 0; 60307 * function draw() { 60308 * fill(value); 60309 * rect(25, 25, 50, 50); 60310 * } 60311 * 60312 * function mouseClicked() { 60313 * if (value === 0) { 60314 * value = 255; 60315 * } else { 60316 * value = 0; 60317 * } 60318 * } 60319 * </code> 60320 * </div> 60321 * 60322 * <div class="norender"> 60323 * <code> 60324 * function mouseClicked() { 60325 * ellipse(mouseX, mouseY, 5, 5); 60326 * // prevent default 60327 * return false; 60328 * } 60329 * </code> 60330 * </div> 60331 * 60332 * <div class="norender"> 60333 * <code> 60334 * // returns a MouseEvent object 60335 * // as a callback argument 60336 * function mouseClicked(event) { 60337 * console.log(event); 60338 * } 60339 * </code> 60340 * </div> 60341 * 60342 * @alt 60343 * black 50x50 rect turns white with mouse click/press. 60344 * no image displayed 60345 * 60346 */ 60347 60348 p5.prototype._onclick = function (e) { 60349 var context = this._isGlobal ? window : this; 60350 60351 if (typeof context.mouseClicked === 'function') { 60352 var executeDefault = context.mouseClicked(e); 60353 60354 if (executeDefault === false) { 60355 e.preventDefault(); 60356 } 60357 } 60358 }; 60359 /** 60360 * The <a href="#/p5/doubleClicked">doubleClicked()</a> function is executed every time a event 60361 * listener has detected a dblclick event which is a part of the 60362 * DOM L3 specification. The doubleClicked event is fired when a 60363 * pointing device button (usually a mouse's primary button) 60364 * is clicked twice on a single element. For more info on the 60365 * dblclick event refer to mozilla's documentation here: 60366 * https://developer.mozilla.org/en-US/docs/Web/Events/dblclick 60367 * 60368 * @method doubleClicked 60369 * @param {Object} [event] optional MouseEvent callback argument. 60370 * @example 60371 * <div> 60372 * <code> 60373 * // Click within the image to change 60374 * // the value of the rectangle 60375 * // after the mouse has been double clicked 60376 * 60377 * let value = 0; 60378 * function draw() { 60379 * fill(value); 60380 * rect(25, 25, 50, 50); 60381 * } 60382 * 60383 * function doubleClicked() { 60384 * if (value === 0) { 60385 * value = 255; 60386 * } else { 60387 * value = 0; 60388 * } 60389 * } 60390 * </code> 60391 * </div> 60392 * 60393 * <div class="norender"> 60394 * <code> 60395 * function doubleClicked() { 60396 * ellipse(mouseX, mouseY, 5, 5); 60397 * // prevent default 60398 * return false;
60399 * } 60400 * </code> 60401 * </div> 60402 * 60403 * <div class="norender"> 60404 * <code> 60405 * // returns a MouseEvent object 60406 * // as a callback argument 60407 * function doubleClicked(event) { 60408 * console.log(event); 60409 * } 60410 * </code> 60411 * </div> 60412 * 60413 * @alt 60414 * black 50x50 rect turns white with mouse doubleClick/press. 60415 * no image displayed 60416 */ 60417 60418 60419 p5.prototype._ondblclick = function (e) { 60420 var context = this._isGlobal ? window : this; 60421 60422 if (typeof context.doubleClicked === 'function') { 60423 var executeDefault = context.doubleClicked(e); 60424 60425 if (executeDefault === false) { 60426 e.preventDefault(); 60427 } 60428 } 60429 }; 60430 /** 60431 * For use with WebGL orbitControl. 60432 * @property {Number} _mouseWheelDeltaY 60433 * @readOnly 60434 * @private 60435 */ 60436 60437 60438 p5.prototype._mouseWheelDeltaY = 0; 60439 /** 60440 * For use with WebGL orbitControl. 60441 * @property {Number} _pmouseWheelDeltaY 60442 * @readOnly 60443 * @private 60444 */ 60445 60446 p5.prototype._pmouseWheelDeltaY = 0; 60447 /** 60448 * The function <a href="#/p5/mouseWheel">mouseWheel()</a> is executed every time a vertical mouse wheel 60449 * event is detected either triggered by an actual mouse wheel or by a 60450 * touchpad.<br><br> 60451 * The event.delta property returns the amount the mouse wheel 60452 * have scrolled. The values can be positive or negative depending on the 60453 * scroll direction (on OS X with "natural" scrolling enabled, the signs 60454 * are inverted).<br><br> 60455 * Browsers may have different default behaviors attached to various 60456 * mouse events. To prevent any default behavior for this event, add 60457 * "return false" to the end of the method.<br><br> 60458 * Due to the current support of the "wheel" event on Safari, the function 60459 * may only work as expected if "return false" is included while using Safari. 60460 * 60461 * @method mouseWheel 60462 * @param {Object} [event] optional WheelEvent callback argument. 60463 * 60464 * @example 60465 * <div> 60466 * <code> 60467 * let pos = 25; 60468 * 60469 * function draw() { 60470 * background(237, 34, 93); 60471 * fill(0); 60472 * rect(25, pos, 50, 50); 60473 * } 60474 * 60475 * function mouseWheel(event) { 60476 * print(event.delta); 60477 * //move the square according to the vertical scroll amount 60478 * pos += event.delta; 60479 * //uncomment to block page scrolling 60480 * //return false; 60481 * } 60482 * </code> 60483 * </div> 60484 * 60485 * @alt 60486 * black 50x50 rect moves up and down with vertical scroll. fuschia background 60487 * 60488 */ 60489 60490 p5.prototype._onwheel = function (e) { 60491 var context = this._isGlobal ? window : this; 60492 60493 this._setProperty('_mouseWheelDeltaY', e.deltaY); 60494 60495 if (typeof context.mouseWheel === 'function') { 60496 e.delta = e.deltaY; 60497 var executeDefault = context.mouseWheel(e); 60498 60499 if (executeDefault === false) { 60500 e.preventDefault(); 60501 } 60502 } 60503 }; 60504 60505 module.exports = p5; 60506 }, {
60507 "../core/constants": 18, 60508 "../core/main": 24 60509 }], 60510 41: [function (_dereq_, module, exports) { 60511 /** 60512 * @module Events 60513 * @submodule Touch 60514 * @for p5 60515 * @requires core 60516 */ 60517 'use strict'; 60518 60519 var p5 = _dereq_('../core/main'); 60520 /** 60521 * The system variable touches[] contains an array of the positions of all 60522 * current touch points, relative to (0, 0) of the canvas, and IDs identifying a 60523 * unique touch as it moves. Each element in the array is an object with x, y, 60524 * and id properties. 60525 * 60526 * The touches[] array is not supported on Safari and IE on touch-based 60527 * desktops (laptops). 60528 * 60529 * @property {Object[]} touches 60530 * @readOnly 60531 * 60532 * @example 60533 * <div> 60534 * <code> 60535 * // On a touchscreen device, touch 60536 * // the canvas using one or more fingers 60537 * // at the same time 60538 * function draw() { 60539 * clear(); 60540 * let display = touches.length + ' touches'; 60541 * text(display, 5, 10); 60542 * } 60543 * </code> 60544 * </div> 60545 * 60546 * @alt 60547 * Number of touches currently registered are displayed on the canvas 60548 */ 60549 60550 60551 p5.prototype.touches = []; 60552 60553 p5.prototype._updateTouchCoords = function (e) { 60554 if (this._curElement !== null) { 60555 var touches = []; 60556 60557 for (var i = 0; i < e.touches.length; i++) { 60558 touches[i] = getTouchInfo(this._curElement.elt, this.width, this.height, e, i); 60559 } 60560 60561 this._setProperty('touches', touches); 60562 } 60563 }; 60564 60565 function getTouchInfo(canvas, w, h, e, i) { 60566 i = i || 0; 60567 var rect = canvas.getBoundingClientRect(); 60568 var sx = canvas.scrollWidth / w; 60569 var sy = canvas.scrollHeight / h; 60570 var touch = e.touches[i] || e.changedTouches[i]; 60571 return { 60572 x: (touch.clientX - rect.left) / sx, 60573 y: (touch.clientY - rect.top) / sy, 60574 winX: touch.clientX, 60575 winY: touch.clientY, 60576 id: touch.identifier 60577 }; 60578 } 60579 /** 60580 * The touchStarted() function is called once after every time a touch is 60581 * registered. If no <a href="#/p5/touchStarted">touchStarted()</a> function is defined, the <a href="#/p5/mousePressed">mousePressed()</a> 60582 * function will be called instead if it is defined.<br><br> 60583 * Browsers may have different default behaviors attached to various touch 60584 * events. To prevent any default behavior for this event, add "return false" 60585 * to the end of the method. 60586 * 60587 * @method touchStarted 60588 * @param {Object} [event] optional TouchEvent callback argument. 60589 * @example 60590 * <div> 60591 * <code> 60592 * // Touch within the image to change 60593 * // the value of the rectangle 60594 * 60595 * let value = 0; 60596 * function draw() { 60597 * fill(value); 60598 * rect(25, 25, 50, 50); 60599 * } 60600 * function touchStarted() { 60601 * if (value === 0) { 60602 * value = 255; 60603 * } else { 60604 * value = 0; 60605 * } 60606 * } 60607 * </code> 60608 * </div> 60609 * 60610 * <div class="norender"> 60611 * <code> 60612 * function touchStarted() { 60613 * ellipse(mouseX, mouseY, 5, 5); 60614 * // prevent default 60615 * return false; 60616 * } 60617 * </code> 60618 * </div> 60619 * 60620 * <div class="norender"> 60621 * <code> 60622 * // returns a TouchEvent object 60623 * // as a callback argument 60624 * function touchStarted(event) { 60625 * console.log(event); 60626 * } 60627 * </code> 60628 * </div> 60629 * 60630 * @alt 60631 * 50x50 black rect turns white with touch event. 60632 * no image displayed 60633 */ 60634 60635 60636 p5.prototype._ontouchstart = function (e) { 60637 var context = this._isGlobal ? window : this; 60638 var executeDefault; 60639 60640 this._setProperty('mouseIsPressed', true); 60641 60642 this._updateTouchCoords(e); 60643 60644 this._updateNextMouseCoords(e); 60645 60646 this._updateMouseCoords(); // reset pmouseXY at the start of each touch event 60647 60648 60649 if (typeof context.touchStarted === 'function') { 60650 executeDefault = context.touchStarted(e); 60651 60652 if (executeDefault === false) { 60653 e.preventDefault(); 60654 } 60655 } else if (typeof context.mousePressed === 'function') { 60656 executeDefault = context.mousePressed(e); 60657 60658 if (executeDefault === false) { 60659 e.preventDefault(); 60660 } 60661 } 60662 }; 60663 /** 60664 * The <a href="#/p5/touchMoved">touchMoved()</a> function is called every time a touch move is registered. 60665 * If no <a href="#/p5/touchMoved">touchMoved()</a> function is defined, the <a href="#/p5/mouseDragged">mouseDragged()</a> function will 60666 * be called instead if it is defined.<br><br> 60667 * Browsers may have different default behaviors attached to various touch 60668 * events. To prevent any default behavior for this event, add "return false" 60669 * to the end of the method. 60670 * 60671 * @method touchMoved 60672 * @param {Object} [event] optional TouchEvent callback argument. 60673 * @example 60674 * <div> 60675 * <code> 60676 * // Move your finger across the page 60677 * // to change its value 60678 * 60679 * let value = 0; 60680 * function draw() { 60681 * fill(value); 60682 * rect(25, 25, 50, 50); 60683 * } 60684 * function touchMoved() { 60685 * value = value + 5; 60686 * if (value > 255) { 60687 * value = 0; 60688 * } 60689 * } 60690 * </code> 60691 * </div> 60692 * 60693 * <div class="norender"> 60694 * <code> 60695 * function touchMoved() { 60696 * ellipse(mouseX, mouseY, 5, 5); 60697 * // prevent default 60698 * return false;
60699 * } 60700 * </code> 60701 * </div> 60702 * 60703 * <div class="norender"> 60704 * <code> 60705 * // returns a TouchEvent object 60706 * // as a callback argument 60707 * function touchMoved(event) { 60708 * console.log(event); 60709 * } 60710 * </code> 60711 * </div> 60712 * 60713 * @alt 60714 * 50x50 black rect turns lighter with touch until white. resets 60715 * no image displayed 60716 * 60717 */ 60718 60719 60720 p5.prototype._ontouchmove = function (e) { 60721 var context = this._isGlobal ? window : this; 60722 var executeDefault; 60723 60724 this._updateTouchCoords(e); 60725 60726 this._updateNextMouseCoords(e); 60727 60728 if (typeof context.touchMoved === 'function') { 60729 executeDefault = context.touchMoved(e); 60730 60731 if (executeDefault === false) { 60732 e.preventDefault(); 60733 } 60734 } else if (typeof context.mouseDragged === 'function') { 60735 executeDefault = context.mouseDragged(e); 60736 60737 if (executeDefault === false) { 60738 e.preventDefault(); 60739 } 60740 } 60741 }; 60742 /** 60743 * The <a href="#/p5/touchEnded">touchEnded()</a> function is called every time a touch ends. If no 60744 * <a href="#/p5/touchEnded">touchEnded()</a> function is defined, the <a href="#/p5/mouseReleased">mouseReleased()</a> function will be 60745 * called instead if it is defined.<br><br> 60746 * Browsers may have different default behaviors attached to various touch 60747 * events. To prevent any default behavior for this event, add "return false" 60748 * to the end of the method. 60749 * 60750 * @method touchEnded 60751 * @param {Object} [event] optional TouchEvent callback argument. 60752 * @example 60753 * <div> 60754 * <code> 60755 * // Release touch within the image to 60756 * // change the value of the rectangle 60757 * 60758 * let value = 0; 60759 * function draw() { 60760 * fill(value); 60761 * rect(25, 25, 50, 50); 60762 * } 60763 * function touchEnded() { 60764 * if (value === 0) { 60765 * value = 255; 60766 * } else { 60767 * value = 0; 60768 * } 60769 * } 60770 * </code> 60771 * </div> 60772 * 60773 * <div class="norender"> 60774 * <code> 60775 * function touchEnded() { 60776 * ellipse(mouseX, mouseY, 5, 5); 60777 * // prevent default 60778 * return false; 60779 * } 60780 * </code> 60781 * </div> 60782 * 60783 * <div class="norender"> 60784 * <code> 60785 * // returns a TouchEvent object 60786 * // as a callback argument 60787 * function touchEnded(event) { 60788 * console.log(event); 60789 * } 60790 * </code> 60791 * </div> 60792 * 60793 * @alt 60794 * 50x50 black rect turns white with touch. 60795 * no image displayed 60796 * 60797 */ 60798 60799 60800 p5.prototype._ontouchend = function (e) { 60801 this._setProperty('mouseIsPressed', false); 60802 60803 this._updateTouchCoords(e); 60804 60805 this._updateNextMouseCoords(e); 60806 60807 var context = this._isGlobal ? window : this; 60808 var executeDefault; 60809 60810 if (typeof context.touchEnded === 'function') { 60811 executeDefault = context.touchEnded(e); 60812 60813 if (executeDefault === false) { 60814 e.preventDefault(); 60815 } 60816 } else if (typeof context.mouseReleased === 'function') { 60817 executeDefault = context.mouseReleased(e); 60818 60819 if (executeDefault === false) { 60820 e.preventDefault(); 60821 } 60822 } 60823 }; 60824 60825 module.exports = p5; 60826 }, {
60827 "../core/main": 24 60828 }], 60829 42: [function (_dereq_, module, exports) { 60830 /*global ImageData:false */ 60831 60832 /** 60833 * This module defines the filters for use with image buffers. 60834 * 60835 * This module is basically a collection of functions stored in an object 60836 * as opposed to modules. The functions are destructive, modifying 60837 * the passed in canvas rather than creating a copy. 60838 * 60839 * Generally speaking users of this module will use the Filters.apply method 60840 * on a canvas to create an effect. 60841 * 60842 * A number of functions are borrowed/adapted from 60843 * http://www.html5rocks.com/en/tutorials/canvas/imagefilters/ 60844 * or the java processing implementation. 60845 */ 60846 'use strict'; 60847 60848 var Filters = {}; 60849 /* 60850 * Helper functions 60851 */ 60852 60853 /** 60854 * Returns the pixel buffer for a canvas 60855 * 60856 * @private 60857 * 60858 * @param {Canvas|ImageData} canvas the canvas to get pixels from 60859 * @return {Uint8ClampedArray} a one-dimensional array containing 60860 * the data in thc RGBA order, with integer 60861 * values between 0 and 255 60862 */ 60863 60864 Filters._toPixels = function (canvas) { 60865 if (canvas instanceof ImageData) { 60866 return canvas.data; 60867 } else { 60868 return canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height).data; 60869 } 60870 }; 60871 /** 60872 * Returns a 32 bit number containing ARGB data at ith pixel in the 60873 * 1D array containing pixels data. 60874 * 60875 * @private 60876 * 60877 * @param {Uint8ClampedArray} data array returned by _toPixels() 60878 * @param {Integer} i index of a 1D Image Array 60879 * @return {Integer} 32 bit integer value representing 60880 * ARGB value. 60881 */ 60882 60883 60884 Filters._getARGB = function (data, i) { 60885 var offset = i * 4; 60886 return data[offset + 3] << 24 & 0xff000000 | data[offset] << 16 & 0x00ff0000 | data[offset + 1] << 8 & 0x0000ff00 | data[offset + 2] & 0x000000ff; 60887 }; 60888 /** 60889 * Modifies pixels RGBA values to values contained in the data object. 60890 * 60891 * @private 60892 * 60893 * @param {Uint8ClampedArray} pixels array returned by _toPixels() 60894 * @param {Int32Array} data source 1D array where each value 60895 * represents ARGB values 60896 */ 60897 60898 60899 Filters._setPixels = function (pixels, data) { 60900 var offset = 0; 60901 60902 for (var i = 0, al = pixels.length; i < al; i++) { 60903 offset = i * 4; 60904 pixels[offset + 0] = (data[i] & 0x00ff0000) >>> 16; 60905 pixels[offset + 1] = (data[i] & 0x0000ff00) >>> 8; 60906 pixels[offset + 2] = data[i] & 0x000000ff; 60907 pixels[offset + 3] = (data[i] & 0xff000000) >>> 24; 60908 } 60909 }; 60910 /** 60911 * Returns the ImageData object for a canvas 60912 * https://developer.mozilla.org/en-US/docs/Web/API/ImageData 60913 * 60914 * @private 60915 * 60916 * @param {Canvas|ImageData} canvas canvas to get image data from 60917 * @return {ImageData} Holder of pixel data (and width and 60918 * height) for a canvas 60919 */ 60920 60921 60922 Filters._toImageData = function (canvas) { 60923 if (canvas instanceof ImageData) { 60924 return canvas; 60925 } else { 60926 return canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); 60927 } 60928 }; 60929 /** 60930 * Returns a blank ImageData object. 60931 * 60932 * @private 60933 * 60934 * @param {Integer} width 60935 * @param {Integer} height 60936 * @return {ImageData} 60937 */ 60938 60939 60940 Filters._createImageData = function (width, height) { 60941 Filters._tmpCanvas = document.createElement('canvas'); 60942 Filters._tmpCtx = Filters._tmpCanvas.getContext('2d'); 60943 return this._tmpCtx.createImageData(width, height); 60944 }; 60945 /** 60946 * Applys a filter function to a canvas. 60947 * 60948 * The difference between this and the actual filter functions defined below 60949 * is that the filter functions generally modify the pixel buffer but do 60950 * not actually put that data back to the canvas (where it would actually 60951 * update what is visible). By contrast this method does make the changes 60952 * actually visible in the canvas. 60953 * 60954 * The apply method is the method that callers of this module would generally
60955 * use. It has been separated from the actual filters to support an advanced 60956 * use case of creating a filter chain that executes without actually updating 60957 * the canvas in between everystep. 60958 * 60959 * @private 60960 * @param {HTMLCanvasElement} canvas [description] 60961 * @param {function(ImageData,Object)} func [description] 60962 * @param {Object} filterParam [description] 60963 */ 60964 60965 60966 Filters.apply = function (canvas, func, filterParam) { 60967 var ctx = canvas.getContext('2d'); 60968 var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); //Filters can either return a new ImageData object, or just modify 60969 //the one they received. 60970 60971 var newImageData = func(imageData, filterParam); 60972 60973 if (newImageData instanceof ImageData) { 60974 ctx.putImageData(newImageData, 0, 0, 0, 0, canvas.width, canvas.height); 60975 } else { 60976 ctx.putImageData(imageData, 0, 0, 0, 0, canvas.width, canvas.height); 60977 } 60978 }; 60979 /* 60980 * Filters 60981 */ 60982 60983 /** 60984 * Converts the image to black and white pixels depending if they are above or 60985 * below the threshold defined by the level parameter. The parameter must be 60986 * between 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is used. 60987 * 60988 * Borrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/ 60989 * 60990 * @private 60991 * @param {Canvas} canvas 60992 * @param {Float} level 60993 */ 60994 60995 60996 Filters.threshold = function (canvas, level) { 60997 var pixels = Filters._toPixels(canvas); 60998 60999 if (level === undefined) { 61000 level = 0.5; 61001 } 61002 61003 var thresh = Math.floor(level * 255); 61004 61005 for (var i = 0; i < pixels.length; i += 4) { 61006 var r = pixels[i]; 61007 var g = pixels[i + 1]; 61008 var b = pixels[i + 2]; 61009 var gray = 0.2126 * r + 0.7152 * g + 0.0722 * b; 61010 var val; 61011 61012 if (gray >= thresh) { 61013 val = 255; 61014 } else { 61015 val = 0; 61016 } 61017 61018 pixels[i] = pixels[i + 1] = pixels[i + 2] = val; 61019 } 61020 }; 61021 /** 61022 * Converts any colors in the image to grayscale equivalents. 61023 * No parameter is used. 61024 * 61025 * Borrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/ 61026 * 61027 * @private 61028 * @param {Canvas} canvas 61029 */ 61030 61031 61032 Filters.gray = function (canvas) { 61033 var pixels = Filters._toPixels(canvas); 61034 61035 for (var i = 0; i < pixels.length; i += 4) { 61036 var r = pixels[i]; 61037 var g = pixels[i + 1]; 61038 var b = pixels[i + 2]; // CIE luminance for RGB 61039 61040 var gray = 0.2126 * r + 0.7152 * g + 0.0722 * b; 61041 pixels[i] = pixels[i + 1] = pixels[i + 2] = gray; 61042 } 61043 }; 61044 /** 61045 * Sets the alpha channel to entirely opaque. No parameter is used. 61046 * 61047 * @private 61048 * @param {Canvas} canvas 61049 */ 61050 61051 61052 Filters.opaque = function (canvas) { 61053 var pixels = Filters._toPixels(canvas); 61054 61055 for (var i = 0; i < pixels.length; i += 4) { 61056 pixels[i + 3] = 255; 61057 } 61058 61059 return pixels; 61060 }; 61061 /** 61062 * Sets each pixel to its inverse value. No parameter is used. 61063 * @private 61064 * @param {Canvas} canvas 61065 */ 61066 61067 61068 Filters.invert = function (canvas) { 61069 var pixels = Filters._toPixels(canvas); 61070 61071 for (var i = 0; i < pixels.length; i += 4) { 61072 pixels[i] = 255 - pixels[i]; 61073 pixels[i + 1] = 255 - pixels[i + 1]; 61074 pixels[i + 2] = 255 - pixels[i + 2]; 61075 } 61076 }; 61077 /** 61078 * Limits each channel of the image to the number of colors specified as 61079 * the parameter. The parameter can be set to values between 2 and 255, but 61080 * results are most noticeable in the lower ranges. 61081 * 61082 * Adapted from java based processing implementation 61083 * 61084 * @private 61085 * @param {Canvas} canvas 61086 * @param {Integer} level 61087 */ 61088 61089 61090 Filters.posterize = function (canvas, level) { 61091 var pixels = Filters._toPixels(canvas); 61092 61093 if (level < 2 || level > 255) { 61094 throw new Error('Level must be greater than 2 and less than 255 for posterize'); 61095 } 61096 61097 var levels1 = level - 1; 61098 61099 for (var i = 0; i < pixels.length; i += 4) { 61100 var rlevel = pixels[i]; 61101 var glevel = pixels[i + 1]; 61102 var blevel = pixels[i + 2]; 61103 pixels[i] = (rlevel * level >> 8) * 255 / levels1; 61104 pixels[i + 1] = (glevel * level >> 8) * 255 / levels1; 61105 pixels[i + 2] = (blevel * level >> 8) * 255 / levels1; 61106 } 61107 }; 61108 /** 61109 * reduces the bright areas in an image 61110 * @private
61111 * @param {Canvas} canvas 61112 * 61113 */ 61114 61115 61116 Filters.dilate = function (canvas) { 61117 var pixels = Filters._toPixels(canvas); 61118 61119 var currIdx = 0; 61120 var maxIdx = pixels.length ? pixels.length / 4 : 0; 61121 var out = new Int32Array(maxIdx); 61122 var currRowIdx, maxRowIdx, colOrig, colOut, currLum; 61123 var idxRight, idxLeft, idxUp, idxDown; 61124 var colRight, colLeft, colUp, colDown; 61125 var lumRight, lumLeft, lumUp, lumDown; 61126 61127 while (currIdx < maxIdx) { 61128 currRowIdx = currIdx; 61129 maxRowIdx = currIdx + canvas.width; 61130 61131 while (currIdx < maxRowIdx) { 61132 colOrig = colOut = Filters._getARGB(pixels, currIdx); 61133 idxLeft = currIdx - 1; 61134 idxRight = currIdx + 1; 61135 idxUp = currIdx - canvas.width; 61136 idxDown = currIdx + canvas.width; 61137 61138 if (idxLeft < currRowIdx) { 61139 idxLeft = currIdx; 61140 } 61141 61142 if (idxRight >= maxRowIdx) { 61143 idxRight = currIdx; 61144 } 61145 61146 if (idxUp < 0) { 61147 idxUp = 0; 61148 } 61149 61150 if (idxDown >= maxIdx) { 61151 idxDown = currIdx; 61152 } 61153 61154 colUp = Filters._getARGB(pixels, idxUp); 61155 colLeft = Filters._getARGB(pixels, idxLeft); 61156 colDown = Filters._getARGB(pixels, idxDown); 61157 colRight = Filters._getARGB(pixels, idxRight); //compute luminance 61158 61159 currLum = 77 * (colOrig >> 16 & 0xff) + 151 * (colOrig >> 8 & 0xff) + 28 * (colOrig & 0xff); 61160 lumLeft = 77 * (colLeft >> 16 & 0xff) + 151 * (colLeft >> 8 & 0xff) + 28 * (colLeft & 0xff); 61161 lumRight = 77 * (colRight >> 16 & 0xff) + 151 * (colRight >> 8 & 0xff) + 28 * (colRight & 0xff); 61162 lumUp = 77 * (colUp >> 16 & 0xff) + 151 * (colUp >> 8 & 0xff) + 28 * (colUp & 0xff); 61163 lumDown = 77 * (colDown >> 16 & 0xff) + 151 * (colDown >> 8 & 0xff) + 28 * (colDown & 0xff); 61164 61165 if (lumLeft > currLum) { 61166 colOut = colLeft; 61167 currLum = lumLeft; 61168 } 61169 61170 if (lumRight > currLum) { 61171 colOut = colRight; 61172 currLum = lumRight; 61173 } 61174 61175 if (lumUp > currLum) { 61176 colOut = colUp; 61177 currLum = lumUp; 61178 } 61179 61180 if (lumDown > currLum) { 61181 colOut = colDown; 61182 currLum = lumDown; 61183 } 61184 61185 out[currIdx++] = colOut; 61186 } 61187 } 61188 61189 Filters._setPixels(pixels, out); 61190 }; 61191 /** 61192 * increases the bright areas in an image 61193 * @private 61194 * @param {Canvas} canvas 61195 * 61196 */ 61197 61198 61199 Filters.erode = function (canvas) { 61200 var pixels = Filters._toPixels(canvas); 61201 61202 var currIdx = 0; 61203 var maxIdx = pixels.length ? pixels.length / 4 : 0; 61204 var out = new Int32Array(maxIdx); 61205 var currRowIdx, maxRowIdx, colOrig, colOut, currLum; 61206 var idxRight, idxLeft, idxUp, idxDown; 61207 var colRight, colLeft, colUp, colDown; 61208 var lumRight, lumLeft, lumUp, lumDown; 61209 61210 while (currIdx < maxIdx) { 61211 currRowIdx = currIdx; 61212 maxRowIdx = currIdx + canvas.width; 61213 61214 while (currIdx < maxRowIdx) { 61215 colOrig = colOut = Filters._getARGB(pixels, currIdx); 61216 idxLeft = currIdx - 1; 61217 idxRight = currIdx + 1; 61218 idxUp = currIdx - canvas.width; 61219 idxDown = currIdx + canvas.width; 61220 61221 if (idxLeft < currRowIdx) { 61222 idxLeft = currIdx; 61223 } 61224 61225 if (idxRight >= maxRowIdx) { 61226 idxRight = currIdx; 61227 } 61228 61229 if (idxUp < 0) { 61230 idxUp = 0; 61231 } 61232 61233 if (idxDown >= maxIdx) { 61234 idxDown = currIdx; 61235 } 61236 61237 colUp = Filters._getARGB(pixels, idxUp); 61238 colLeft = Filters._getARGB(pixels, idxLeft); 61239 colDown = Filters._getARGB(pixels, idxDown); 61240 colRight = Filters._getARGB(pixels, idxRight); //compute luminance 61241 61242 currLum = 77 * (colOrig >> 16 & 0xff) + 151 * (colOrig >> 8 & 0xff) + 28 * (colOrig & 0xff); 61243 lumLeft = 77 * (colLeft >> 16 & 0xff) + 151 * (colLeft >> 8 & 0xff) + 28 * (colLeft & 0xff); 61244 lumRight = 77 * (colRight >>
61244 16 & 0xff) + 151 * (colRight >> 8 & 0xff) + 28 * (colRight & 0xff); 61245 lumUp = 77 * (colUp >> 16 & 0xff) + 151 * (colUp >> 8 & 0xff) + 28 * (colUp & 0xff); 61246 lumDown = 77 * (colDown >> 16 & 0xff) + 151 * (colDown >> 8 & 0xff) + 28 * (colDown & 0xff); 61247 61248 if (lumLeft < currLum) { 61249 colOut = colLeft; 61250 currLum = lumLeft; 61251 } 61252 61253 if (lumRight < currLum) { 61254 colOut = colRight; 61255 currLum = lumRight; 61256 } 61257 61258 if (lumUp < currLum) { 61259 colOut = colUp; 61260 currLum = lumUp; 61261 } 61262 61263 if (lumDown < currLum) { 61264 colOut = colDown; 61265 currLum = lumDown; 61266 } 61267 61268 out[currIdx++] = colOut; 61269 } 61270 } 61271 61272 Filters._setPixels(pixels, out); 61273 }; // BLUR 61274 // internal kernel stuff for the gaussian blur filter 61275 61276 61277 var blurRadius; 61278 var blurKernelSize; 61279 var blurKernel; 61280 var blurMult; 61281 /* 61282 * Port of https://github.com/processing/processing/blob/ 61283 * master/core/src/processing/core/PImage.java#L1250 61284 * 61285 * Optimized code for building the blur kernel. 61286 * further optimized blur code (approx. 15% for radius=20) 61287 * bigger speed gains for larger radii (~30%) 61288 * added support for various image types (ALPHA, RGB, ARGB) 61289 * [toxi 050728] 61290 */ 61291 61292 function buildBlurKernel(r) { 61293 var radius = r * 3.5 | 0; 61294 radius = radius < 1 ? 1 : radius < 248 ? radius : 248; 61295 61296 if (blurRadius !== radius) { 61297 blurRadius = radius; 61298 blurKernelSize = 1 + blurRadius << 1; 61299 blurKernel = new Int32Array(blurKernelSize); 61300 blurMult = new Array(blurKernelSize); 61301 61302 for (var l = 0; l < blurKernelSize; l++) { 61303 blurMult[l] = new Int32Array(256); 61304 } 61305 61306 var bk, bki; 61307 var bm, bmi; 61308
61309 for (var i = 1, radiusi = radius - 1; i < radius; i++) { 61310 blurKernel[radius + i] = blurKernel[radiusi] = bki = radiusi * radiusi; 61311 bm = blurMult[radius + i]; 61312 bmi = blurMult[radiusi--]; 61313 61314 for (var j = 0; j < 256; j++) { 61315 bm[j] = bmi[j] = bki * j; 61316 } 61317 } 61318 61319 bk = blurKernel[radius] = radius * radius; 61320 bm = blurMult[radius]; 61321 61322 for (var k = 0; k < 256; k++) { 61323 bm[k] = bk * k; 61324 } 61325 } 61326 } // Port of https://github.com/processing/processing/blob/ 61327 // master/core/src/processing/core/PImage.java#L1433 61328 61329 61330 function blurARGB(canvas, radius) { 61331 var pixels = Filters._toPixels(canvas); 61332 61333 var width = canvas.width; 61334 var height = canvas.height; 61335 var numPackedPixels = width * height; 61336 var argb = new Int32Array(numPackedPixels); 61337 61338 for (var j = 0; j < numPackedPixels; j++) { 61339 argb[j] = Filters._getARGB(pixels, j); 61340 } 61341 61342 var sum, cr, cg, cb, ca; 61343 var read, ri, ym, ymi, bk0; 61344 var a2 = new Int32Array(numPackedPixels); 61345 var r2 = new Int32Array(numPackedPixels); 61346 var g2 = new Int32Array(numPackedPixels); 61347 var b2 = new Int32Array(numPackedPixels); 61348 var yi = 0; 61349 buildBlurKernel(radius); 61350 var x, y, i; 61351 var bm; 61352 61353 for (y = 0; y < height; y++) { 61354 for (x = 0; x < width; x++) { 61355 cb = cg = cr = ca = sum = 0; 61356 read = x - blurRadius; 61357 61358 if (read < 0) { 61359 bk0 = -read; 61360 read = 0; 61361 } else { 61362 if (read >= width) { 61363 break; 61364 } 61365 61366 bk0 = 0; 61367 } 61368 61369 for (i = bk0; i < blurKernelSize; i++) { 61370 if (read >= width) { 61371 break; 61372 } 61373 61374 var c = argb[read + yi]; 61375 bm = blurMult[i]; 61376 ca += bm[(c & -16777216) >>> 24]; 61377 cr += bm[(c & 16711680) >> 16]; 61378 cg += bm[(c & 65280) >> 8]; 61379 cb += bm[c & 255]; 61380 sum += blurKernel[i]; 61381 read++; 61382 } 61383 61384 ri = yi + x; 61385 a2[ri] = ca / sum; 61386 r2[ri] = cr / sum; 61387 g2[ri] = cg / sum; 61388 b2[ri] = cb / sum; 61389 } 61390 61391 yi += width; 61392 } 61393 61394 yi = 0; 61395 ym = -blurRadius; 61396 ymi = ym * width; 61397 61398 for (y = 0; y < height; y++) { 61399 for (x = 0; x < width; x++) { 61400 cb = cg = cr = ca = sum = 0; 61401 61402 if (ym < 0) { 61403 bk0 = ri = -ym; 61404 read = x; 61405 } else { 61406 if (ym >= height) { 61407 break; 61408 } 61409 61410 bk0 = 0; 61411 ri = ym; 61412 read = x + ymi; 61413 } 61414 61415 for (i = bk0; i < blurKernelSize; i++) { 61416 if (ri >= height) { 61417 break; 61418 } 61419 61420 bm = blurMult[i]; 61421 ca += bm[a2[read]]; 61422 cr += bm[r2[read]]; 61423 cg += bm[g2[read]]; 61424 cb += bm[b2[read]]; 61425 sum += blurKernel[i]; 61426 ri++; 61427 read += width; 61428 } 61429 61430 argb[x + yi] = ca / sum << 24 | cr / sum << 16 | cg / sum << 8 | cb / sum; 61431 } 61432 61433 yi += width; 61434 ymi += width; 61435 ym++; 61436 } 61437 61438 Filters._setPixels(pixels, argb); 61439 } 61440 61441 Filters.blur = function (canvas, radius) { 61442 blurARGB(canvas, radius); 61443 }; 61444 61445 module.exports = Filters; 61446 }, {}], 61447 43: [function (_dereq_, module, exports) { 61448 /** 61449 * @module Image 61450 * @submodule Image 61451 * @for p5 61452 * @requires core 61453 */ 61454 61455 /** 61456 * This module defines the p5 methods for the <a href="#/p5.Image">p5.Image</a> class 61457 * for drawing images to the main display canvas. 61458 */ 61459 'use strict'; 61460 61461 var p5 = _dereq_('../core/main'); // This is not global, but ESLint is not aware that 61462 // this module is implicitly enclosed with Browserify: this overrides the 61463 // redefined-global error and permits using the name "frames" for the array 61464 // of saved animation frames. 61465 61466 /* global frames:true */ 61467 61468 61469 var frames = []; 61470 /** 61471 * Creates a new <a href="#/p5.Image">p5.Image</a> (the datatype for storing images). This provides a 61472 * fresh buffer of pixels to play with. Set the size of the buffer with the 61473 * width and height parameters. 61474 * <br><br> 61475 * .<a href="#/p5.Image/pixels">pixels</a> gives access to an array containing the values for all the pixels 61476 * in the display window. 61477 * These values are numbers. This array is the size (including an appropriate 61478 * factor for the <a href="#/p5/pixelDensity">pixelDensity</a>) of the display window x4, 61479 * representing the R, G, B, A values in order for each pixel, mov
61479ing from 61480 * left to right across each row, then down each column. See .<a href="#/p5.Image/pixels">pixels</a> for 61481 * more info. It may also be simpler to use <a href="#/p5.Image/set">set()</a> or <a href="#/p5.Image/get">get()</a>. 61482 * <br><br> 61483 * Before accessing the pixels of an image, the data must loaded with the 61484 * <a href="#/p5.Image/loadPixels">loadPixels()</a> function. After the array data has been modified, the 61485 * <a href="#/p5.Image/updatePixels">updatePixels()</a> function must be run to update the changes. 61486 * 61487 * @method createImage 61488 * @param {Integer} width width in pixels 61489 * @param {Integer} height height in pixels 61490 * @return {p5.Image} the <a href="#/p5.Image">p5.Image</a> object 61491 * @example 61492 * <div> 61493 * <code> 61494 * let img = createImage(66, 66); 61495 * img.loadPixels(); 61496 * for (let i = 0; i < img.width; i++) { 61497 * for (let j = 0; j < img.height; j++) { 61498 * img.set(i, j, color(0, 90, 102)); 61499 * } 61500 * } 61501 * img.updatePixels(); 61502 * image(img, 17, 17); 61503 * </code> 61504 * </div> 61505 * 61506 * <div> 61507 * <code> 61508 * let img = createImage(66, 66); 61509 * img.loadPixels(); 61510 * for (let i = 0; i < img.width; i++) { 61511 * for (let j = 0; j < img.height; j++) { 61512 * img.set(i, j, color(0, 90, 102, (i % img.width) * 2)); 61513 * } 61514 * } 61515 * img.updatePixels(); 61516 * image(img, 17, 17); 61517 * image(img, 34, 34); 61518 * </code> 61519 * </div> 61520 * 61521 * <div> 61522 * <code> 61523 * let pink = color(255, 102, 204); 61524 * let img = createImage(66, 66); 61525 * img.loadPixels(); 61526 * let d = pixelDensity(); 61527 * let halfImage = 4 * (img.width * d) * (img.height / 2 * d); 61528 * for (let i = 0; i < halfImage; i += 4) { 61529 * img.pixels[i] = red(pink); 61530 * img.pixels[i + 1] = green(pink); 61531 * img.pixels[i + 2] = blue(pink); 61532 * img.pixels[i + 3] = alpha(pink); 61533 * } 61534 * img.updatePixels(); 61535 * image(img, 17, 17); 61536 * </code> 61537 * </div> 61538 * 61539 * @alt 61540 * 66x66 dark turquoise rect in center of canvas. 61541 * 2 gradated dark turquoise rects fade left. 1 center 1 bottom right of canvas 61542 * no image displayed 61543 * 61544 */ 61545 61546 p5.prototype.createImage = function (width, height) { 61547 p5._validateParameters('createImage', arguments); 61548 61549 return new p5.Image(width, height); 61550 }; 61551 /** 61552 * Save the current canvas as an image. The browser will either save the 61553 * file immediately, or prompt the user with a dialogue window. 61554 * 61555 * @method saveCanvas 61556 * @param {p5.Element|HTMLCanvasElement} selectedCanvas a variable 61557 * representing a specific html5 canvas (optional) 61558 * @param {String} [filename] 61559 * @param {String} [extension] 'jpg' or 'png' 61560 * 61561 * @example 61562 * <div class='norender notest'><code> 61563 * function setup() { 61564 * let c = createCanvas(100, 100); 61565 * background(255, 0, 0); 61566 * saveCanvas(c, 'myCanvas', 'jpg'); 61567 * } 61568 * </code></div> 61569 * <div class='norender notest'><code> 61570 * // note that this example has the same result as above 61571 * // if no canvas is specified, defaults to main canvas 61572 * function setup() { 61573 * let c = createCanvas(100, 100); 61574 * background(255, 0, 0); 61575 * saveCanvas('myCanvas', 'jpg'); 61576 * 61577 * // all of the following are valid 61578 * saveCanvas(c, 'myCanvas', 'jpg'); 61579 * saveCanvas(c, 'myCanvas.jpg'); 61580 * saveCanvas(c, 'myCanvas'); 61581 * saveCanvas(c); 61582 * saveCanvas('myCanvas', 'png'); 61583 * saveCanvas('myCanvas'); 61584 * saveCanvas(); 61585 * } 61586 * </code></div> 61587 * 61588 * @alt 61589 * no image displayed 61590 * no image displayed 61591 * no image displayed 61592 */ 61593 61594 /** 61595 * @method saveCanvas 61596 * @param {String} [filename] 61597 * @param {String} [extension] 61598 */ 61599 61600 61601 p5.prototype.saveCanvas = function () { 61602 p5._validateParameters('saveCanvas', arguments); // copy arguments to array 61603 61604 61605 var args = [].slice.call(arguments); 61606 var htmlCanvas, filename, extension; 61607 61608 if (arguments[0] instanceof HTMLCanvasElement) { 61609 htmlCanvas = arguments[0]; 61610 args.shift(); 61611 } else if (arguments[0] instanceof p5.Element) { 61612 htmlCanvas = arguments[0].elt;
61613 args.shift(); 61614 } else { 61615 htmlCanvas = this._curElement && this._curElement.elt; 61616 } 61617 61618 if (args.length >= 1) { 61619 filename = args[0]; 61620 } 61621 61622 if (args.length >= 2) { 61623 extension = args[1]; 61624 } 61625 61626 extension = extension || p5.prototype._checkFileExtension(filename, extension)[1] || 'png'; 61627 var mimeType; 61628 61629 switch (extension) { 61630 default: 61631 //case 'png': 61632 mimeType = 'image/png'; 61633 break; 61634 61635 case 'jpeg': 61636 case 'jpg': 61637 mimeType = 'image/jpeg'; 61638 break; 61639 } 61640 61641 htmlCanvas.toBlob(function (blob) { 61642 p5.prototype.downloadFile(blob, filename, extension); 61643 }, mimeType); 61644 }; 61645 /** 61646 * Capture a sequence of frames that can be used to create a movie. 61647 * Accepts a callback. For example, you may wish to send the frames 61648 * to a server where they can be stored or converted into a movie. 61649 * If no callback is provided, the browser will pop up save dialogues in an 61650 * attempt to download all of the images that have just been created. With the 61651 * callback provided the image data isn't saved by default but instead passed 61652 * as an argument to the callback function as an array of objects, with the 61653 * size of array equal to the total number of frames. 61654 * 61655 * Note that <a href="#/p5.Image/saveFrames">saveFrames()</a> will only save the first 15 frames of an animation. 61656 * To export longer animations, you might look into a library like 61657 * <a href="https://github.com/spite/ccapture.js/">ccapture.js</a>. 61658 * 61659 * @method saveFrames 61660 * @param {String} filename 61661 * @param {String} extension 'jpg' or 'png' 61662 * @param {Number} duration Duration in seconds to save the frames for. 61663 * @param {Number} framerate Framerate to save the frames in. 61664 * @param {function(Array)} [callback] A callback function that will be executed 61665 to handle the image data. This function 61666 should accept an array as argument. The 61667 array will contain the specified number of 61668 frames of objects. Each object has three 61669 properties: imageData - an 61670 image/octet-stream, filename and extension. 61671 * @example 61672 * <div><code> 61673 * function draw() { 61674 * background(mouseX); 61675 * } 61676 * 61677 * function mousePressed() { 61678 * saveFrames('out', 'png', 1, 25, data => { 61679 * print(data); 61680 * }); 61681 * } 61682 </code></div> 61683 * 61684 * @alt 61685 * canvas background goes from light to dark with mouse x. 61686 * 61687 */ 61688 61689 61690 p5.prototype.saveFrames = function (fName, ext, _duration, _fps, callback) { 61691 p5._validateParameters('saveFrames', arguments); 61692 61693 var duration = _duration || 3; 61694 duration = p5.prototype.constrain(duration, 0, 15); 61695 duration = duration * 1000; 61696 var fps = _fps || 15; 61697 fps = p5.prototype.constrain(fps, 0, 22); 61698 var count = 0; 61699 var makeFrame = p5.prototype._makeFrame; 61700 var cnv = this._curElement.elt; 61701 var frameFactory = setInterval(function () { 61702 makeFrame(fName + count, ext, cnv); 61703 count++; 61704 }, 1000 / fps); 61705 setTimeout(function () { 61706 clearInterval(frameFactory); 61707 61708 if (callback) { 61709 callback(frames); 61710 } else { 61711 for (var i = 0; i < frames.length; i++) { 61712 var f = frames[i]; 61713 p5.prototype.downloadFile(f.imageData, f.filename, f.ext); 61714 } 61715 } 61716 61717 frames = []; // clear frames 61718 }, duration + 0.01); 61719 }; 61720 61721 p5.prototype._makeFrame = function (filename, extension, _cnv) { 61722 var cnv; 61723 61724 if (this) { 61725 cnv = this._curElement.elt; 61726 } else { 61727 cnv = _cnv; 61728 } 61729 61730 var mimeType; 61731 61732 if (!extension) { 61733 extension = 'png'; 61734 mimeType = 'image/png'; 61735 } else { 61736 switch (extension.toLowerCase()) { 61737 case 'png': 61738 mimeType = 'image/png'; 61739 break; 61740 61741 case 'jpeg': 61742 mimeType = 'image/jpeg'; 61743 break; 61744 61745 case 'jpg': 61746 mimeType = 'image/jpeg'; 61747 break; 61748 61749 default: 61750 mimeType = 'image/png'; 61751 break; 61752 } 61753 } 61754 61755 var downloadMime = 'image/octet-stream'; 61756 var imageData = cnv.toDataURL(mimeType); 61757 imageData = imageData.replace(mimeType, downloadMime); 61758 var thisFrame = {}; 61759 thisFrame.imageData = imageData; 61760 thisFrame.filename = filename; 61761 thisFrame.ext = extension; 61762 frames.push(thisFrame); 61763 }; 61764 61765 module.exports = p5; 61766 }, {
61767 "../core/main": 24 61768 }], 61769 44: [function (_dereq_, module, exports) { 61770 /** 61771 * @module Image 61772 * @submodule Loading & Displaying 61773 * @for p5 61774 * @requires core 61775 */ 61776 'use strict'; 61777 61778 var p5 = _dereq_('../core/main'); 61779 61780 var Filters = _dereq_('./filters'); 61781 61782 var canvas = _dereq_('../core/helpers'); 61783 61784 var constants = _dereq_('../core/constants'); 61785 61786 _dereq_('../core/error_helpers'); 61787 /** 61788 * Loads an image from a path and creates a <a href="#/p5.Image">p5.Image</a> from it. 61789 * <br><br> 61790 * The image may not be immediately available for rendering 61791 * If you want to ensure that the image is ready before doing 61792 * anything with it, place the <a href="#/p5/loadImage">loadImage()</a> call in <a href="#/p5/preload">preload()</a>. 61793 * You may also supply a callback function to handle the image when it's ready. 61794 * <br><br> 61795 * The path to the image should be relative to the HTML file 61796 * that links in your sketch. Loading an image from a URL or other 61797 * remote location may be blocked due to your browser's built-in 61798 * security. 61799 * 61800 * @method loadImage 61801 * @param {String} path Path of the image to be loaded 61802 * @param {function(p5.Image)} [successCallback] Function to be called once 61803 * the image is loaded. Will be passed the 61804 * <a href="#/p5.Image">p5.Image</a>. 61805 * @param {function(Event)} [failureCallback] called with event error if 61806 * the image fails to load. 61807 * @return {p5.Image} the <a href="#/p5.Image">p5.Image</a> object 61808 * @example 61809 * <div> 61810 * <code> 61811 * let img; 61812 * function preload() { 61813 * img = loadImage('assets/laDefense.jpg'); 61814 * } 61815 * function setup() { 61816 * image(img, 0, 0); 61817 * } 61818 * </code> 61819 * </div> 61820 * <div> 61821 * <code> 61822 * function setup() { 61823 * // here we use a callback to display the image after loading 61824 * loadImage('assets/laDefense.jpg', img => { 61825 * image(img, 0, 0); 61826 * }); 61827 * } 61828 * </code> 61829 * </div> 61830 * 61831 * @alt 61832 * image of the underside of a white umbrella and grided ceililng above 61833 * image of the underside of a white umbrella and grided ceililng above 61834 * 61835 */ 61836 61837 61838 p5.prototype.loadImage = function (path, successCallback, failureCallback) { 61839 p5._validateParameters('loadImage', arguments); 61840 61841 var img = new Image(); 61842 var pImg = new p5.Image(1, 1, this); 61843 var self = this; 61844 61845 img.onload = function () { 61846 pImg.width = pImg.canvas.width = img.width; 61847 pImg.height = pImg.canvas.height = img.height; // Draw the image into the backing canvas of the p5.Image 61848 61849 pImg.drawingContext.drawImage(img, 0, 0); 61850 pImg.modified = true; 61851 61852 if (typeof successCallback === 'function') { 61853 successCallback(pImg); 61854 } 61855 61856 self._decrementPreload(); 61857 }; 61858 61859 img.onerror = function (e) { 61860 p5._friendlyFileLoadError(0, img.src); 61861 61862 if (typeof failureCallback === 'function') { 61863 failureCallback(e); 61864 } else { 61865 console.error(e); 61866 } 61867 }; // Set crossOrigin in case image is served with CORS headers. 61868 // This will let us draw to the canvas without tainting it. 61869 // See https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image 61870 // When using data-uris the file will be loaded locally 61871 // so we don't need to worry about crossOrigin with base64 file types. 61872 61873 61874 if (path.indexOf('data:image/') !== 0) { 61875 img.crossOrigin = 'Anonymous'; 61876 } // start loading the image 61877 61878 61879 img.src = path; 61880 return pImg; 61881 }; 61882 /** 61883 * Validates clipping params. Per drawImage spec sWidth and sHight cannot be 61884 * negative or greater than image intrinsic width and height 61885 * @private 61886 * @param {Number} sVal 61887 * @param {Number} iVal 61888 * @returns {Number} 61889 * @private 61890 */ 61891 61892 61893 function _sAssign(sVal, iVal) { 61894 if (sVal > 0 && sVal < iVal) { 61895 return sVal; 61896 } else { 61897 return iVal; 61898 } 61899 } 61900 /** 61901 * Draw an image to the p5.js canvas. 61902 * 61903 * This function can be used with different numbers of parameters. The 61904 * simplest use requires only three parameters: img, x, and
61904yâwhere (x, y) is 61905 * the position of the image. Two more parameters can optionally be added to 61906 * specify the width and height of the image. 61907 * 61908 * This function can also be used with all eight Number parameters. To 61909 * differentiate between all these parameters, p5.js uses the language of 61910 * "destination rectangle" (which corresponds to "dx", "dy", etc.) and "source 61911 * image" (which corresponds to "sx", "sy", etc.) below. Specifying the 61912 * "source image" dimensions can be useful when you want to display a 61913 * subsection of the source image instead of the whole thing. Here's a diagram 61914 * to explain further: 61915 * <img src="assets/drawImage.png"></img> 61916 * 61917 * @method image 61918 * @param {p5.Image|p5.Element} img the image to display 61919 * @param {Number} x the x-coordinate of the top-left corner of the image 61920 * @param {Number} y the y-coordinate of the top-left corner of the image 61921 * @param {Number} [width] the width to draw the image 61922 * @param {Number} [height] the height to draw the image 61923 * @example 61924 * <div> 61925 * <code> 61926 * let img; 61927 * function preload() { 61928 * img = loadImage('assets/laDefense.jpg'); 61929 * } 61930 * function setup() { 61931 * // Top-left corner of the img is at (0, 0) 61932 * // Width and height are the img's original width and height 61933 * image(img, 0, 0); 61934 * } 61935 * </code> 61936 * </div> 61937 * <div> 61938 * <code> 61939 * let img; 61940 * function preload() { 61941 * img = loadImage('assets/laDefense.jpg'); 61942 * } 61943 * function setup() { 61944 * background(50); 61945 * // Top-left corner of the img is at (10, 10) 61946 * // Width and height are 50 x 50 61947 * image(img, 10, 10, 50, 50); 61948 * } 61949 * </code> 61950 * </div> 61951 * <div> 61952 * <code> 61953 * function setup() { 61954 * // Here, we use a callback to display the image after loading 61955 * loadImage('assets/laDefense.jpg', img => { 61956 * image(img, 0, 0); 61957 * }); 61958 * } 61959 * </code> 61960 * </div> 61961 * <div> 61962 * <code> 61963 * let img; 61964 * function preload() { 61965 * img = loadImage('assets/gradient.png'); 61966 * } 61967 * function setup() { 61968 * // 1. Background image 61969 * // Top-left corner of the img is at (0, 0) 61970 * // Width and height are the img's original width and height, 100 x 100 61971 * image(img, 0, 0); 61972 * // 2. Top right image 61973 * // Top-left corner of destination rectangle is at (50, 0) 61974 * // Destination rectangle width and height are 40 x 20 61975 * // The next parameters are relative to the source image: 61976 * // - Starting at position (50, 50) on the source image, capture a 50 x 50 61977 * // subsection 61978 * // - Draw this subsection to fill the dimensions of the destination rectangle 61979 * image(img, 50, 0, 40, 20, 50, 50, 50, 50); 61980 * } 61981 * </code> 61982 * </div> 61983 * @alt 61984 * image of the underside of a white umbrella and gridded ceiling above 61985 * image of the underside of a white umbrella and gridded ceiling above 61986 * 61987 */ 61988 61989 /** 61990 * @method image 61991 * @param {p5.Image|p5.Element} img 61992 * @param {Number} dx the x-coordinate of the destination 61993 * rectangle in which to draw the source image 61994 * @param {Number} dy the y-coordinate of the destination 61995 * rectangle in which to draw the source image 61996 * @param {Number} dWidth the width of the destination rectangle 61997 * @param {Number} dHeight the height of the destination rectangle 61998 * @param {Number} sx the x-coordinate of the subsection of the source 61999 * image to draw into the destination rectangle 62000 * @param {Number} sy the y-coordinate of the subsection of the source 62001 * image to draw into the destination rectangle 62002 * @param {Number} [sWidth] the width of the subsection of the 62003 * source image to draw into the destination 62004 * rectangle 62005 * @param {Number} [sHeight] the height of the subsection of the 62006 * source image to draw into the destination rectangle 62007 */ 62008 62009 62010 p5.prototype.image = function (img, dx, dy, dWidth, dHeight, sx, sy, sWidth, sHeight) { 62011 // set defaults per spec: https://goo.gl/3ykfOq 62012 p5._validateParameters('image', arguments); 62013 62014 var defW = img.width;
62015 var defH = img.height; 62016 62017 if (img.elt && img.elt.videoWidth && !img.canvas) { 62018 // video no canvas 62019 defW = img.elt.videoWidth; 62020 defH = img.elt.videoHeight; 62021 } 62022 62023 var _dx = dx; 62024 var _dy = dy; 62025 62026 var _dw = dWidth || defW; 62027 62028 var _dh = dHeight || defH; 62029 62030 var _sx = sx || 0; 62031 62032 var _sy = sy || 0; 62033 62034 var _sw = sWidth || defW; 62035 62036 var _sh = sHeight || defH; 62037 62038 _sw = _sAssign(_sw, defW); 62039 _sh = _sAssign(_sh, defH); // This part needs cleanup and unit tests 62040 // see issues https://github.com/processing/p5.js/issues/1741 62041 // and https://github.com/processing/p5.js/issues/1673 62042 62043 var pd = 1; 62044 62045 if (img.elt && !img.canvas && img.elt.style.width) { 62046 //if img is video and img.elt.size() has been used and 62047 //no width passed to image() 62048 if (img.elt.videoWidth && !dWidth) { 62049 pd = img.elt.videoWidth; 62050 } else { 62051 //all other cases 62052 pd = img.elt.width; 62053 } 62054 62055 pd /= parseInt(img.elt.style.width, 10); 62056 } 62057 62058 _sx *= pd; 62059 _sy *= pd; 62060 _sh *= pd; 62061 _sw *= pd; 62062 var vals = canvas.modeAdjust(_dx, _dy, _dw, _dh, this._renderer._imageMode); // tint the image if there is a tint 62063 62064 this._renderer.image(img, _sx, _sy, _sw, _sh, vals.x, vals.y, vals.w, vals.h); 62065 }; 62066 /** 62067 * Sets the fill value for displaying images. Images can be tinted to 62068 * specified colors or made transparent by including an alpha value. 62069 * <br><br> 62070 * To apply transparency to an image without affecting its color, use 62071 * white as the tint color and specify an alpha value. For instance, 62072 * tint(255, 128) will make an image 50% transparent (assuming the default 62073 * alpha range of 0-255, which can be changed with <a href="#/p5/colorMode">colorMode()</a>). 62074 * <br><br> 62075 * The value for the gray parameter must be less than or equal to the current 62076 * maximum value as specified by <a href="#/p5/colorMode">colorMode()</a>. The default maximum value is 62077 * 255. 62078 * 62079 * 62080 * @method tint 62081 * @param {Number} v1 red or hue value relative to 62082 * the current color range 62083 * @param {Number} v2 green or saturation value 62084 * relative to the current color range 62085 * @param {Number} v3 blue or brightness value 62086 * relative to the current color range 62087 * @param {Number} [alpha] 62088 * 62089 * @example 62090 * <div> 62091 * <code> 62092 * let img; 62093 * function preload() { 62094 * img = loadImage('assets/laDefense.jpg'); 62095 * } 62096 * function setup() { 62097 * image(img, 0, 0); 62098 * tint(0, 153, 204); // Tint blue 62099 * image(img, 50, 0); 62100 * } 62101 * </code> 62102 * </div> 62103 * 62104 * <div> 62105 * <code> 62106 * let img; 62107 * function preload() { 62108 * img = loadImage('assets/laDefense.jpg'); 62109 * } 62110 * function setup() { 62111 * image(img, 0, 0); 62112 * tint(0, 153, 204, 126); // Tint blue and set transparency 62113 * image(img, 50, 0); 62114 * } 62115 * </code> 62116 * </div> 62117 * 62118 * <div> 62119 * <code> 62120 * let img; 62121 * function preload() { 62122 * img = loadImage('assets/laDefense.jpg'); 62123 * } 62124 * function setup() { 62125 * image(img, 0, 0); 62126 * tint(255, 126); // Apply transparency without changing color 62127 * image(img, 50, 0); 62128 * } 62129 * </code> 62130 * </div> 62131 * 62132 * @alt 62133 * 2 side by side images of umbrella and ceiling, one image with blue tint 62134 * Images of umbrella and ceiling, one half of image with blue tint 62135 * 2 side by side images of umbrella and ceiling, one image translucent 62136 * 62137 */ 62138 62139 /** 62140 * @method tint 62141 * @param {String} value a color string 62142 */ 62143 62144 /** 62145 * @method tint 62146 * @param {Number} gray a gray value 62147 * @param {Number} [alpha] 62148 */ 62149 62150 /** 62151 * @method tint 62152 * @param {Number[]} values an array containing the red,green,blue & 62153 * and alpha components of the color 62154 */ 62155 62156 /** 62157 * @method tint 62158 * @param {p5.Color} color the tint color 62159 */ 62160 62161 62162 p5.prototype.tint = function () { 62163 p5._validateParameters('tint', arguments); 62164 62165 var c = this.color.apply(this, arguments); 62166 this._renderer._tint = c.levels; 62167 }; 62168 /** 62169 * Removes the current fill value for displaying images and reverts to 62170 * displaying images with their original hues. 62171 * 62172 * @method noTint 62173 * @example 62174 * <div> 62175 * <code> 62176 * let img; 62177 * function preload() { 62178 * img = loadImage('assets/bricks.jpg'); 62179 * } 62180 * function setup() { 62181 * tint(0, 153, 204); // Tint blue 62182 * image(img, 0, 0); 62183 * noTint(); // Disable tint 62184 * image(img, 50, 0); 62185 * } 62186 * </code> 62187 * </div> 62188 * 62189 * @alt 62190 * 2 side by side images of bricks, left image with blue tint 62191 * 62192 */ 62193 62194 62195 p5.prototype.noTint = function () { 62196 this._renderer._tint = null; 62197 }; 62198 /** 62199 * Apply the current tint color to the input image, return the resulting 62200 * canvas. 62201 * 62202 * @private 62203 * @param {p5.Image} The image to be tinted 62204 * @return {canvas} The resulting tinted canvas 62205 * 62206 */ 62207 62208 62209 p5.prototype._getTintedImageCanvas = function (img) { 62210 if (!img.canvas) { 62211 return img; 62212 } 62213 62214 var pixels = Filters._toPixels(img.canvas); 62215 62216 var tmpCanvas = document.createElement('canvas'); 62217 tmpCanvas.width = img.canvas.width; 62218 tmpCanvas.height = img.canvas.height; 62219 var tmpCtx = tmpCanvas.getContext('2d'); 62220 var id = tmpCtx.createImageData(img.canvas.width, img.canvas.height); 62221 var newPixels = id.data; 62222 62223 for (var i = 0; i < pixels.length; i += 4) { 62224 var r = pixels[i]; 62225 var g = pixels[i + 1]; 62226 var b = pixels[i + 2]; 62227 var a = pixels[i + 3];
62228 newPixels[i] = r * this._renderer._tint[0] / 255; 62229 newPixels[i + 1] = g * this._renderer._tint[1] / 255; 62230 newPixels[i + 2] = b * this._renderer._tint[2] / 255; 62231 newPixels[i + 3] = a * this._renderer._tint[3] / 255; 62232 } 62233 62234 tmpCtx.putImageData(id, 0, 0); 62235 return tmpCanvas; 62236 }; 62237 /** 62238 * Set image mode. Modifies the location from which images are drawn by 62239 * changing the way in which parameters given to <a href="#/p5/image">image()</a> are interpreted. 62240 * The default mode is imageMode(CORNER), which interprets the second and 62241 * third parameters of <a href="#/p5/image">image()</a> as the upper-left corner of the image. If 62242 * two additional parameters are specified, they are used to set the image's 62243 * width and height. 62244 * <br><br> 62245 * imageMode(CORNERS) interprets the second and third parameters of <a href="#/p5/image">image()</a> 62246 * as the location of one corner, and the fourth and fifth parameters as the 62247 * opposite corner. 62248 * <br><br> 62249 * imageMode(CENTER) interprets the second and third parameters of <a href="#/p5/image">image()</a> 62250 * as the image's center point. If two additional parameters are specified, 62251 * they are used to set the image's width and height. 62252 * 62253 * @method imageMode 62254 * @param {Constant} mode either CORNER, CORNERS, or CENTER 62255 * @example 62256 * 62257 * <div> 62258 * <code> 62259 * let img; 62260 * function preload() { 62261 * img = loadImage('assets/bricks.jpg'); 62262 * } 62263 * function setup() { 62264 * imageMode(CORNER); 62265 * image(img, 10, 10, 50, 50); 62266 * } 62267 * </code> 62268 * </div> 62269 * 62270 * <div> 62271 * <code> 62272 * let img; 62273 * function preload() { 62274 * img = loadImage('assets/bricks.jpg'); 62275 * } 62276 * function setup() { 62277 * imageMode(CORNERS); 62278 * image(img, 10, 10, 90, 40); 62279 * } 62280 * </code> 62281 * </div> 62282 * 62283 * <div> 62284 * <code> 62285 * let img; 62286 * function preload() { 62287 * img = loadImage('assets/bricks.jpg'); 62288 * } 62289 * function setup() { 62290 * imageMode(CENTER); 62291 * image(img, 50, 50, 80, 80); 62292 * } 62293 * </code> 62294 * </div> 62295 * 62296 * @alt 62297 * small square image of bricks 62298 * horizontal rectangle image of bricks 62299 * large square image of bricks 62300 * 62301 */ 62302 62303 62304 p5.prototype.imageMode = function (m) { 62305 p5._validateParameters('imageMode', arguments); 62306 62307 if (m === constants.CORNER || m === constants.CORNERS || m === constants.CENTER) { 62308 this._renderer._imageMode = m; 62309 } 62310 }; 62311 62312 module.exports = p5; 62313 }, {
62314 "../core/constants": 18, 62315 "../core/error_helpers": 20, 62316 "../core/helpers": 21, 62317 "../core/main": 24, 62318 "./filters": 42 62319 }], 62320 45: [function (_dereq_, module, exports) { 62321 /** 62322 * @module Image 62323 * @submodule Image 62324 * @requires core 62325 * @requires constants 62326 * @requires filters 62327 */ 62328 62329 /** 62330 * This module defines the <a href="#/p5.Image">p5.Image</a> class and P5 methods for 62331 * drawing images to the main display canvas. 62332 */ 62333 'use strict'; 62334 62335 var p5 = _dereq_('../core/main'); 62336 62337 var Filters = _dereq_('./filters'); 62338 /* 62339 * Class methods 62340 */ 62341 62342 /** 62343 * Creates a new <a href="#/p5.Image">p5.Image</a>. A <a href="#/p5.Image">p5.Image</a> is a canvas backed representation of an 62344 * image. 62345 * <br><br> 62346 * p5 can display .gif, .jpg and .png images. Images may be displayed 62347 * in 2D and 3D space. Before an image is used, it must be loaded with the 62348 * <a href="#/p5/loadImage">loadImage()</a> function. The <a href="#/p5.Image">p5.Image</a> class contains fields for the width and 62349 * height of the image, as well as an array called <a href="#/p5.Image/pixels">pixels[]</a> that contains the 62350 * values for every pixel in the image. 62351 * <br><br> 62352 * The methods described below allow easy access to the image's pixels and 62353 * alpha channel and simplify the process of compositing. 62354 * <br><br> 62355 * Before using the <a href="#/p5.Image/pixels">pixels[]</a> array, be sure to use the <a href="#/p5.Image/loadPixels">loadPixels()</a> method on 62356 * the image to make sure that the pixel data is properly loaded. 62357 * @example 62358 * <div><code> 62359 * function setup() { 62360 * let img = createImage(100, 100); // same as new p5.Image(100, 100); 62361 * img.loadPixels(); 62362 * createCanvas(100, 100); 62363 * background(0); 62364 * 62365 * // helper for writing color to array 62366 * function writeColor(image, x, y, red, green, blue, alpha) { 62367 * let index = (x + y * width) * 4; 62368 * image.pixels[index] = red; 62369 * image.pixels[index + 1] = green; 62370 * image.pixels[index + 2] = blue; 62371 * image.pixels[index + 3] = alpha; 62372 * } 62373 * 62374 * let x, y; 62375 * // fill with random colors 62376 * for (y = 0; y < img.height; y++) { 62377 * for (x = 0; x < img.width; x++) { 62378 * let red = random(255); 62379 * let green = random(255); 62380 * let blue = random(255); 62381 * let alpha = 255; 62382 * writeColor(img, x, y, red, green, blue, alpha); 62383 * } 62384 * } 62385 * 62386 * // draw a red line 62387 * y = 0; 62388 * for (x = 0; x < img.width; x++) { 62389 * writeColor(img, x, y, 255, 0, 0, 255); 62390 * } 62391 * 62392 * // draw a green line 62393 * y = img.height - 1; 62394 * for (x = 0; x < img.width; x++) { 62395 * writeColor(img, x, y, 0, 255, 0, 255); 62396 * } 62397 * 62398 * img.updatePixels(); 62399 * image(img, 0, 0); 62400 * } 62401 * </code></div> 62402 * 62403 * 62404 * @class p5.Image 62405 * @param {Number} width 62406 * @param {Number} height 62407 */ 62408 62409 62410 p5.Image = function (width, height) { 62411 /** 62412 * Image width. 62413 * @property {Number} width 62414 * @readOnly 62415 * @example 62416 * <div><code> 62417 * let img; 62418 * function preload() { 62419 * img = loadImage('assets/rockies.jpg'); 62420 * } 62421 * 62422 * function setup() { 62423 * createCanvas(100, 100); 62424 * image(img, 0, 0); 62425 * for (let i = 0; i < img.width; i++) { 62426 * let c = img.get(i, img.height / 2); 62427 * stroke(c); 62428 * line(i, height / 2, i, height); 62429 * } 62430 * } 62431 * </code></div> 62432 * 62433 * @alt 62434 * rocky mountains in top and horizontal lines in corresponding colors in bottom. 62435 * 62436 */ 62437 this.width = width; 62438 /** 62439 * Image height. 62440 * @property {Number} height 62441 * @readOnly 62442 * @example 62443 * <div><code> 62444 * let img; 62445 * function preload() { 62446 * img = loadImage('assets/rockies.jpg'); 62447 * } 62448 * 62449 * function setup() { 62450 * createCanvas(100, 100); 62451 * image(img, 0, 0); 62452 * for (let i = 0;
62452 i < img.height; i++) { 62453 * let c = img.get(img.width / 2, i); 62454 * stroke(c); 62455 * line(0, i, width / 2, i); 62456 * } 62457 * } 62458 * </code></div> 62459 * 62460 * @alt 62461 * rocky mountains on right and vertical lines in corresponding colors on left. 62462 * 62463 */ 62464 62465 this.height = height; 62466 this.canvas = document.createElement('canvas'); 62467 this.canvas.width = this.width; 62468 this.canvas.height = this.height; 62469 this.drawingContext = this.canvas.getContext('2d'); 62470 this._pixelDensity = 1; //used for webgl texturing only 62471 62472 this._modified = false; 62473 this._pixelsDirty = true; 62474 /** 62475 * Array containing the values for all the pixels in the display window. 62476 * These values are numbers. This array is the size (include an appropriate 62477 * factor for pixelDensity) of the display window x4, 62478 * representing the R, G, B, A values in order for each pixel, moving from 62479 * left to right across each row, then down each column. Retina and other 62480 * high denisty displays may have more pixels (by a factor of 62481 * pixelDensity^2). 62482 * For example, if the image is 100x100 pixels, there will be 40,000. With 62483 * pixelDensity = 2, there will be 160,000. The first four values 62484 * (indices 0-3) in the array will be the R, G, B, A values of the pixel at 62485 * (0, 0). The second four values (indices 4-7) will contain the R, G, B, A 62486 * values of the pixel at (1, 0). More generally, to set values for a pixel 62487 * at (x, y): 62488 * ```javascript 62489 * let d = pixelDensity(); 62490 * for (let i = 0; i < d; i++) { 62491 * for (let j = 0; j < d; j++) { 62492 * // loop over 62493 * index = 4 * ((y * d + j) * width * d + (x * d + i
62493)); 62494 * pixels[index] = r; 62495 * pixels[index+1] = g; 62496 * pixels[index+2] = b; 62497 * pixels[index+3] = a; 62498 * } 62499 * } 62500 * ``` 62501 * <br><br> 62502 * Before accessing this array, the data must loaded with the <a href="#/p5.Image/loadPixels">loadPixels()</a> 62503 * function. After the array data has been modified, the <a href="#/p5.Image/updatePixels">updatePixels()</a> 62504 * function must be run to update the changes. 62505 * @property {Number[]} pixels 62506 * @example 62507 * <div> 62508 * <code> 62509 * let img = createImage(66, 66); 62510 * img.loadPixels(); 62511 * for (let i = 0; i < img.width; i++) { 62512 * for (let j = 0; j < img.height; j++) { 62513 * img.set(i, j, color(0, 90, 102)); 62514 * } 62515 * } 62516 * img.updatePixels(); 62517 * image(img, 17, 17); 62518 * </code> 62519 * </div> 62520 * <div> 62521 * <code> 62522 * let pink = color(255, 102, 204); 62523 * let img = createImage(66, 66); 62524 * img.loadPixels(); 62525 * for (let i = 0; i < 4 * (width * height / 2); i += 4) { 62526 * img.pixels[i] = red(pink); 62527 * img.pixels[i + 1] = green(pink); 62528 * img.pixels[i + 2] = blue(pink); 62529 * img.pixels[i + 3] = alpha(pink); 62530 * } 62531 * img.updatePixels(); 62532 * image(img, 17, 17); 62533 * </code> 62534 * </div> 62535 * 62536 * @alt 62537 * 66x66 turquoise rect in center of canvas 62538 * 66x66 pink rect in center of canvas 62539 * 62540 */ 62541 62542 this.pixels = []; 62543 }; 62544 /** 62545 * Helper fxn for sharing pixel methods 62546 * 62547 */ 62548 62549 62550 p5.Image.prototype._setProperty = function (prop, value) { 62551 this[prop] = value; 62552 this.setModified(true); 62553 }; 62554 /** 62555 * Loads the pixels data for this image into the [pixels] attribute. 62556 * 62557 * @method loadPixels 62558 * @example 62559 * <div><code> 62560 * let myImage; 62561 * let halfImage; 62562 * 62563 * function preload() { 62564 * myImage = loadImage('assets/rockies.jpg'); 62565 * } 62566 * 62567 * function setup() { 62568 * myImage.loadPixels(); 62569 * halfImage = 4 * width * height / 2; 62570 * for (let i = 0; i < halfImage; i++) { 62571 * myImage.pixels[i + halfImage] = myImage.pixels[i]; 62572 * } 62573 * myImage.updatePixels(); 62574 * } 62575 * 62576 * function draw() { 62577 * image(myImage, 0, 0); 62578 * } 62579 * </code></div> 62580 * 62581 * @alt 62582 * 2 images of rocky mountains vertically stacked 62583 * 62584 */ 62585 62586 62587 p5.Image.prototype.loadPixels = function () { 62588 p5.Renderer2D.prototype.loadPixels.call(this); 62589 this.setModified(true); 62590 }; 62591 /** 62592 * Updates the backing canvas for this image with the contents of 62593 * the [pixels] array. 62594 * 62595 * @method updatePixels 62596 * @param {Integer} x x-offset of the target update area for the 62597 * underlying canvas 62598 * @param {Integer} y y-offset of the target update area for the 62599 * underlying canvas 62600 * @param {Integer} w height of the target update area for the 62601 * underlying canvas 62602 * @param {Integer} h height of the target update area for the 62603 * underlying canvas 62604 * @example 62605 * <div><code> 62606 * let myImage; 62607 * let halfImage; 62608 * 62609 * function preload() { 62610 * myImage = loadImage('assets/rockies.jpg'); 62611 * } 62612 * 62613 * function setup() { 62614 * myImage.loadPixels(); 62615 * halfImage = 4 * width * height / 2; 62616 * for (let i = 0; i < halfImage; i++) { 62617 * myImage.pixels[i + halfImage] = myImage.pixels[i]; 62618 * } 62619 * myImage.updatePixels(); 62620 * } 62621 * 62622 * function draw() { 62623 * image(myImage, 0, 0); 62624 * } 62625 * </code></div> 62626 * 62627 * @alt 62628 * 2 images of rocky mountains vertically stacked 62629 * 62630 */ 62631 62632 /** 62633 * @method updatePixels 62634 */ 62635 62636 62637 p5.Image.prototype.updatePixels = function (x, y, w, h) { 62638 p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h); 62639 this.setModified(true); 62640 }; 62641 /** 62642 * Get a region of pixels from an image. 62643 * 62644 * If no params are passed, those whole image is returned, 62645 * if x and y are the only params passed a single pixel is extracted 62646 * if all params are passed a rectangle region is extracted and a <a href="#/p5.Image">p5.Image</a> 62647 * is returned. 62648 * 62649 * Returns undefined if the region is outside the bounds of the image 62650 * 62651 * @method get 62652 * @param {Number} [x] x-coordinate of the pixel 62653 * @param {Number} [y] y-coordinate of the pixel 62654 * @param {Number} [w] width 62655 * @param {Number} [h] height 62656 * @return {Number[]|Color|p5.Image} color of pixel at x,y in array format 62657 * [R, G, B, A] or <a href="#/p5.Image">p5.Image</a> 62658 * @example 62659 * <div><code> 62660 * let myImage; 62661 * let c; 62662 * 62663 * function preload() { 62664 * myImage = loadImage('assets/rockies.jpg'); 62665 * } 62666 * 62667 * function setup() { 62668 * background(myImage); 62669 * noStroke(); 62670 * c = myImage.get(60, 90); 62671 * fill(c); 62672 * rect(25, 25, 50, 50); 62673 * } 62674 * 62675 * //get() returns color here 62676 * </code></div> 62677 * 62678 * @alt 62679 * image of rocky mountains with 50x50 green rect in front 62680 * 62681 */ 62682 62683 62684 p5.Image.prototype.get = function (x, y, w, h) { 62685 return p5.prototype.get.call(this, x, y, w, h); 62686 }; 62687 /** 62688 * Set the color of a single pixel or write an image into 62689 * this <a href="#/p5.Image">p5.Image</a>. 62690 * 62691 * Note that for a large number of pixels this will 62692 * be slower than directly manipulating the pixels array 62693 * and then calling <a href="#/p5.Image/updatePixels">updatePixels()</a>. 62694 * 62695 * @method set 62696 * @param {Number} x x-coordinate of the pixel 62697 * @param {Number} y y-coordinate of the pixel 62698 * @param {Number|Number[]|Object} a grayscale value | pixel array | 62699 * a <a href="#/p5.Color">p5.Color</a> | image to copy 62700 * @example 62701 * <div> 62702 * <code> 62703 * let img = createImage(66, 66); 62704 * img.loadPixels(); 62705 * for (let i = 0; i < img.width; i++) { 62706 * for (let j = 0;
62706 j < img.height; j++) { 62707 * img.set(i, j, color(0, 90, 102, (i % img.width) * 2)); 62708 * } 62709 * } 62710 * img.updatePixels(); 62711 * image(img, 17, 17); 62712 * image(img, 34, 34); 62713 * </code> 62714 * </div> 62715 * 62716 * @alt 62717 * 2 gradated dark turquoise rects fade left. 1 center 1 bottom right of canvas 62718 * 62719 */ 62720 62721 62722 p5.Image.prototype.set = function (x, y, imgOrCol) { 62723 p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol); 62724 this.setModified(true); 62725 }; 62726 /** 62727 * Resize the image to a new width and height. To make the image scale 62728 * proportionally, use 0 as the value for the wide or high parameter. 62729 * For instance, to make the width of an image 150 pixels, and change 62730 * the height using the same proportion, use resize(150, 0). 62731 * 62732 * @method resize 62733 * @param {Number} width the resized image width 62734 * @param {Number} height the resized image height 62735 * @example 62736 * <div><code> 62737 * let img; 62738 * 62739 * function preload() { 62740 * img = loadImage('assets/rockies.jpg'); 62741 * } 62742 62743 * function draw() { 62744 * image(img, 0, 0); 62745 * } 62746 * 62747 * function mousePressed() { 62748 * img.resize(50, 100); 62749 * } 62750 * </code></div> 62751 * 62752 * @alt 62753 * image of rocky mountains. zoomed in 62754 * 62755 */ 62756 62757 62758 p5.Image.prototype.resize = function (width, height) { 62759 // Copy contents to a temporary canvas, resize the original 62760 // and then copy back. 62761 // 62762 // There is a faster approach that involves just one copy and swapping the 62763 // this.canvas reference. We could switch to that approach if (as i think 62764 // is the case) there an expectation that the user would not hold a 62765 // reference to the backing canvas of a p5.Image. But since we do not 62766 // enforce that at the moment, I am leaving in the slower, but safer 62767 // implementation. 62768 // auto-resize 62769 if (width === 0 && height === 0) { 62770 width = this.canvas.width; 62771 height = this.canvas.height; 62772 } else if (width === 0) { 62773 width = this.canvas.width * height / this.canvas.height; 62774 } else if (height === 0) { 62775 height = this.canvas.height * width / this.canvas.width; 62776 } 62777 62778 width = Math.floor(width); 62779 height = Math.floor(height); 62780 var tempCanvas = document.createElement('canvas'); 62781 tempCanvas.width = width; 62782 tempCanvas.height = height; // prettier-ignore 62783 62784 tempCanvas.getContext('2d').drawImage(this.canvas, 0, 0, this.canvas.width, this.canvas.height, 0, 0, tempCanvas.width, tempCanvas.height); // Resize the original canvas, which will clear its contents 62785 62786 this.canvas.width = this.width = width; 62787 this.canvas.height = this.height = height; //Copy the image back 62788 // prettier-ignore 62789 62790 this.drawingContext.drawImage(tempCanvas, 0, 0, width, height, 0, 0, width, height); 62791 62792 if (this.pixels.length > 0) { 62793 this.loadPixels(); 62794 } 62795 62796 this.setModified(true); 62797 this._pixelsDirty = true; 62798 }; 62799 /** 62800 * Copies a region of pixels from one image to another. If no 62801 * srcImage is specified this is used as the source. If the source 62802 * and destination regions aren't the same size, it will 62803 * automatically resize source pixels to fit the specified 62804 * target region. 62805 * 62806 * @method copy 62807 * @param {p5.Image|p5.Element} srcImage source image 62808 * @param {Integer} sx X coordinate of the source's upper left corner 62809 * @param {Integer} sy Y coordinate of the source's upper left corner 62810 * @param {Integer} sw source image width 62811 * @param {Integer} sh source image height 62812 * @param {Integer} dx X coordinate of the destination's upper left corner 62813 * @param {Integer} dy Y coordinate of the destination's upper left corner 62814 * @param {Integer} dw destination image width 62815 * @param {Integer} dh destination image height 62816 * @example 62817 * <div><code> 62818 * let photo; 62819 * let bricks; 62820 * let x; 62821 * let y; 62822 * 62823 * function preload() { 62824 * photo = loadImage('assets/rockies.jpg'); 62825 * bricks = loadImage('assets/bricks.jpg'); 62826 * } 62827 * 62828 * function setup() { 62829 * x = bricks.width / 2; 62830 * y = bricks.height / 2; 62831 * photo.copy(bricks, 0, 0, x, y, 0, 0, x, y); 62832 * image(photo, 0, 0); 62833 * } 62834 * </code></div> 62835 * 62836 * @alt 62837 * image of rocky mountains and smaller image on top of bricks at top left 62838 * 62839 */ 62840 62841 /** 62842 * @method copy 62843 * @param {Integer} sx 62844 * @param {Integer} sy 62845 * @param {Integer} sw 62846 * @param {Integer} sh 62847 * @param {Integer} dx 62848 * @param {Integer} dy 62849 * @param {Integer} dw 62850 * @param {Integer} dh 62851 */ 62852 62853 62854 p5.Image.prototype.copy = function () { 62855 var srcImage, sx, sy, sw, sh, dx, dy, dw, dh; 62856 62857 if (arguments.length === 9) { 62858 srcImage = arguments[0]; 62859 sx = arguments[1]; 62860 sy = arguments[2]; 62861 sw = arguments[3]; 62862 sh = arguments[4]; 62863 dx = arguments[5]; 62864 dy = arguments[6]; 62865 dw = arguments[7]; 62866 dh = arguments[8]; 62867 } else if (arguments.length === 8) { 62868 srcImage = this; 62869 sx = arguments[0]; 62870 sy = arguments[1]; 62871 sw = arguments[2]; 62872 sh = arguments[3]; 62873 dx = arguments[4]; 62874 dy = arguments[5]; 62875 dw = arguments[6]; 62876 dh = arguments[7]; 62877 } else { 62878 throw new Error('Signature not supported'); 62879 } 62880 62881 p5.Renderer2D._copyHelper(this, srcImage, sx, sy, sw, sh, dx, dy, dw, dh); 62882 62883 this._pixelsDirty = true; 62884 }; 62885 /** 62886 * Masks part of an image from displaying by loading another 62887 * image and using it's alpha channel as an alpha channel for 62888 * this image. 62889 * 62890 * @method mask 62891 * @param {p5.Image} srcImage source image 62892 * @example 62893 * <div><code> 62894 * let photo, maskImage; 62895 * function preload() { 62896 * photo = loadImage('assets/rockies.jpg'); 62897 * maskImage = loadImage('assets/mask2.png'); 62898 * } 62899 * 62900 * function setup() { 62901 * createCanvas(100, 100); 62902 * photo.mask(maskImage); 62903 * image(photo, 0, 0); 62904 * } 62905 * </code></div> 62906 * 62907 * @alt 62908 * image of rocky mountains with white at right 62909 * 62910 * 62911 * http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ 62912 * 62913 */ 62914 // TODO: - Accept an array of alpha values. 62915 // - Use other channels of an image. p5 uses the 62916 // blue channel (which feels kind of arbitrary). Note: at the 62917 // moment this method does not match native processings original 62918 // functionality exactly. 62919 62920 62921 p5.Image.prototype.mask = function (p5Image) { 62922 if (p5Image === undefined) { 62923 p5Image = this; 62924 } 62925 62926 var currBlend = this.drawingContext.globalCompositeOperation; 62927 var scaleFactor = 1; 62928 62929 if (p5Image instanceof p5.Renderer) { 62930 scaleFactor = p5Image._pInst._pixelDensity; 62931 } 62932 62933 var copyArgs = [p5Image, 0, 0, scaleFactor * p5Image.width, scaleFactor * p5Image.height, 0, 0, this.width, this.height]; 62934 this.drawingContext.globalCompositeOperation = 'destination-in'; 62935 p5.Image.prototype.copy.apply(this, copyArgs); 62936 this.drawingContext.globalCompositeOperation = currBlend; 62937 this.setModified(true); 62938 }; 62939 /** 62940 * Applies an image filter to a <a href="#/p5.Image">p5.Image</a> 62941 * 62942 * @method filter 62943 * @param {Constant} filterType either THRESHOLD, GRAY, OPAQUE, INVERT, 62944 * POSTERIZE, BLUR, ERODE, DILATE or BLUR. 62945 * See Filters.js for docs on 62946 * each available filter 62947 * @param {Number} [filterParam] an optional parameter unique 62948 * to each filter, see above 62949 * @example 62950 * <div><code> 62951 * let photo1; 62952 * let photo2; 62953 * 62954 * function preload() { 62955 * photo1 = loadImage('assets/rockies.jpg'); 62956 * photo2 = loadImage('assets/rockies.jpg'); 62957 * } 62958 * 62959 * function setup() { 62960 * photo2.filter('gray'); 62961 * image(photo1, 0, 0); 62962 * image(photo2, width / 2, 0); 62963 * } 62964 * </code></div> 62965 * 62966 * @alt 62967 * 2 images of rocky mountains left one in color, right in black and white 62968 * 62969 */ 62970 62971 62972 p5.Image.prototype.filter = function (operation, value) { 62973 Filters.apply(this.canvas, Filters[operation.toLowerCase()], value); 62974 this.setModified(true); 62975 }; 62976 /** 62977 * Copies a region of pixels from one image to another, using a specified 62978 * blend mode to do the operation. 62979 * 62980 * @method blend 62981 * @param {p5.Image} srcImage source image 62982 * @param {Integer} sx X coordinate of the source's upper left corner 62983 * @param {Integer} sy Y coordinate of the source's upper left corner 62984 * @param {Integer} sw source image width 62985 * @param {Integer} sh source image height 62986 * @param {Integer} dx X coordinate of the destination's upper left corner 62987 * @param {Integer} dy Y coordinate of the destination's upper left corner 62988 * @param {Integer} dw destination image width 62989 * @param {Integer} dh destination image height 62990 * @param {Constant} blendMode the blend mode. either 62991 * BLEND, DARKEST, LIGHTEST, DIFFERENCE, 62992 * MULTIPLY, EXCLUSION, SCREEN, REPLACE, OVERLAY, HARD_LIGHT, 62993 * SOFT_LIGHT, DODGE, BURN, ADD or NORMAL. 62994 * 62995 * Available blend modes are: normal | multiply | screen | overlay | 62996 * darken | lighten | color-dodge | color-burn | hard-light | 62997 * soft-light | difference | exclusion | hue | saturation | 62998 * color | luminosity 62999 * 63000 * 63001 * http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ 63002 * @example 63003 * <div><code> 63004 * let mountains; 63005 * let bricks; 63006 * 63007 * function preload() { 63008 * mountains = loadImage('assets/rockies.jpg'); 63009 * bricks = loadImage('assets/bricks_third.jpg'); 63010 * } 63011 * 63012 * function setup() { 63013 * mountains.blend(bricks, 0, 0, 33, 100, 67, 0, 33, 100, ADD); 63014 * image(mountains, 0, 0); 63015 * image(bricks, 0, 0); 63016 * } 63017 * </code></div> 63018 * <div><code> 63019 * let mountains; 63020 * let bricks; 63021 * 63022 * function preload() { 63023 * mountains = loadImage('assets/rockies.jpg'); 63024 * bricks = loadImage('assets/bricks_third.jpg'); 63025 * } 63026 * 63027 * function setup() { 63028 * mountains.blend(bricks, 0, 0, 33, 100, 67, 0, 33, 100, DARKEST); 63029 * image(mountains, 0, 0); 63030 * image(bricks, 0, 0); 63031 * } 63032 * </code></div> 63033 * <div><code> 63034 * let mountains; 63035 * let bricks; 63036 * 63037 * function preload() { 63038 * mountains = loadImage('assets/rockies.jpg'); 63039 * bricks = loadImage('assets/bricks_third.jpg'); 63040 * } 63041 * 63042 * function setup() { 63043 * mountains.blend(bricks, 0, 0, 33, 100, 67, 0, 33, 100, LIGHTEST); 63044 * image(mountains, 0, 0); 63045 * image(bricks, 0, 0); 63046 * } 63047 * </code></div> 63048 * 63049 * @alt 63050 * image of rocky mountains. Brick images on left and right. Right overexposed 63051 * image of rockies. Brickwall images on left and right. Right mortar transparent 63052 * image of rockies. Brickwall images on left and right. Right translucent 63053 * 63054 */ 63055 63056 /** 63057 * @method blend 63058 * @param {Integer} sx 63059 * @param {Integer} sy 63060 * @param {Integer} sw 63061 * @param {Integer} sh 63062 * @param {Integer} dx 63063 * @param {Integer} dy 63064 * @param {Integer} dw 63065 * @param {Integer} dh 63066 * @param {Constant} blendMode 63067 */ 63068 63069 63070 p5.Image.prototype.blend = function () { 63071 p5.prototype.blend.apply(this, arguments); 63072 this.setModified(true); 63073 }; 63074 /** 63075 * helper method for web GL mode to indicate that an image has been 63076 * changed or unchanged since last upload. gl texture upload will 63077 * set this value to false after uploading the texture. 63078 * @method setModified 63079 * @param {boolean} val sets whether or not the image has been 63080 * modified. 63081 * @private 63082 */ 63083 63084 63085 p5.Image.prototype.setModified = function (val) { 63086 this._modified = val; //enforce boolean? 63087 }; 63088 /** 63089 * helper method for web GL mode to figure out if the image 63090 * has been modified and might need to be re-uploaded to texture 63091 * memory between frames. 63092 * @method isModified 63093 * @private 63094 * @return {boolean} a boolean indicating whether or not the 63095 * image has been updated or modified since last texture upload. 63096 */ 63097 63098 63099 p5.Image.prototype.isModified = function () { 63100 return this._modified; 63101 }; 63102 /** 63103 * Saves the image to a file and force the browser to download it. 63104 * Accepts two strings for filename and file extension 63105 * Supports png (default) and jpg. 63106 * 63107 * @method save 63108 * @param {String} filename give your file a name 63109 * @param {String} extension 'png' or 'jpg' 63110 * @example 63111 * <div><code> 63112 * let photo; 63113 * 63114 * function preload() { 63115 * photo = loadImage('assets/rockies.jpg'); 63116 * } 63117 * 63118 * function draw() { 63119 * image(photo, 0, 0); 63120 * } 63121 * 63122 * function keyTyped() { 63123 * if (key === 's') { 63124 * photo.save('photo', 'png'); 63125 * } 63126 * } 63127 * </code></div> 63128 * 63129 * @alt 63130 * image of rocky mountains. 63131 * 63132 */ 63133 63134 63135 p5.Image.prototype.save = function (filename, extension) { 63136 p5.prototype.saveCanvas(this.canvas, filename, extension); 63137 }; 63138 63139 module.exports = p5.Image; 63140 }, {
63141 "../core/main": 24, 63142 "./filters": 42 63143 }], 63144 46: [function (_dereq_, module, exports) { 63145 /** 63146 * @module Image 63147 * @submodule Pixels 63148 * @for p5 63149 * @requires core 63150 */ 63151 'use strict'; 63152 63153 var p5 = _dereq_('../core/main'); 63154 63155 var Filters = _dereq_('./filters'); 63156 63157 _dereq_('../color/p5.Color'); 63158 /** 63159 * <a href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference 63160 * /Global_Objects/Uint8ClampedArray' target='_blank'>Uint8ClampedArray</a> 63161 * containing the values for all the pixels in the display window. 63162 * These values are numbers. This array is the size (include an appropriate 63163 * factor for <a href="#/p5/pixelDensity">pixelDensity</a>) of the display window x4, 63164 * representing the R, G, B, A values in order for each pixel, moving from 63165 * left to right across each row, then down each column. Retina and other 63166 * high density displays will have more pixels[] (by a factor of 63167 * pixelDensity^2). 63168 * For example, if the image is 100x100 pixels, there will be 40,000. On a 63169 * retina display, there will be 160,000. 63170 * <br><br> 63171 * The first four values (indices 0-3) in the array will be the R, G, B, A 63172 * values of the pixel at (0, 0). The second four values (indices 4-7) will 63173 * contain the R, G, B, A values of the pixel at (1, 0). More generally, to 63174 * set values for a pixel at (x, y): 63175 * ```javascript 63176 * let d = pixelDensity(); 63177 * for (let i = 0; i < d; i++) { 63178 * for (let j = 0; j < d; j++) { 63179 * // loop over
63180 * index = 4 * ((y * d + j) * width * d + (x * d + i)); 63181 * pixels[index] = r; 63182 * pixels[index+1] = g; 63183 * pixels[index+2] = b; 63184 * pixels[index+3] = a; 63185 * } 63186 * } 63187 * ``` 63188 * <p>While the above method is complex, it is flexible enough to work with 63189 * any pixelDensity. Note that <a href="#/p5/set">set()</a> will automatically take care of 63190 * setting all the appropriate values in <a href="#/p5/pixels">pixels[]</a> for a given (x, y) at 63191 * any pixelDensity, but the performance may not be as fast when lots of 63192 * modifications are made to the pixel array. 63193 * <br><br> 63194 * Before accessing this array, the data must loaded with the <a href="#/p5/loadPixels">loadPixels()</a> 63195 * function. After the array data has been modified, the <a href="#/p5/updatePixels">updatePixels()</a> 63196 * function must be run to update the changes. 63197 * <br><br> 63198 * Note that this is not a standard javascript array. This means that 63199 * standard javascript functions such as <a href="#/p5/slice">slice()</a> or 63200 * <a href="#/p5/arrayCopy">arrayCopy()</a> do not 63201 * work.</p> 63202 * 63203 * @property {Number[]} pixels 63204 * @example 63205 * <div> 63206 * <code> 63207 * let pink = color(255, 102, 204); 63208 * loadPixels(); 63209 * let d = pixelDensity(); 63210 * let halfImage = 4 * (width * d) * (height / 2 * d); 63211 * for (let i = 0; i < halfImage; i += 4) { 63212 * pixels[i] = red(pink); 63213 * pixels[i + 1] = green(pink); 63214 * pixels[i + 2] = blue(pink); 63215 * pixels[i + 3] = alpha(pink); 63216 * } 63217 * updatePixels(); 63218 * </code> 63219 * </div> 63220 * 63221 * @alt 63222 * top half of canvas pink, bottom grey 63223 * 63224 */ 63225 63226 63227 p5.prototype.pixels = []; 63228 /** 63229 * Copies a region of pixels from one image to another, using a specified 63230 * blend mode to do the operation. 63231 * 63232 * @method blend 63233 * @param {p5.Image} srcImage source image 63234 * @param {Integer} sx X coordinate of the source's upper left corner 63235 * @param {Integer} sy Y coordinate of the source's upper left corner 63236 * @param {Integer} sw source image width 63237 * @param {Integer} sh source image height 63238 * @param {Integer} dx X coordinate of the destination's upper left corner 63239 * @param {Integer} dy Y coordinate of the destination's upper left corner 63240 * @param {Integer} dw destination image width 63241 * @param {Integer} dh destination image height 63242 * @param {Constant} blendMode the blend mode. either 63243 * BLEND, DARKEST, LIGHTEST, DIFFERENCE, 63244 * MULTIPLY, EXCLUSION, SCREEN, REPLACE, OVERLAY, HARD_LIGHT, 63245 * SOFT_LIGHT, DODGE, BURN, ADD or NORMAL. 63246 * 63247 * @example 63248 * <div><code> 63249 * let img0; 63250 * let img1; 63251 * 63252 * function preload() { 63253 * img0 = loadImage('assets/rockies.jpg'); 63254 * img1 = loadImage('assets/bricks_third.jpg'); 63255 * } 63256 * 63257 * function setup() { 63258 * background(img0); 63259 * image(img1, 0, 0); 63260 * blend(img1, 0, 0, 33, 100, 67, 0, 33, 100, LIGHTEST); 63261 * } 63262 * </code></div> 63263 * <div><code> 63264 * let img0; 63265 * let img1; 63266 * 63267 * function preload() { 63268 * img0 = loadImage('assets/rockies.jpg'); 63269 * img1 = loadImage('assets/bricks_third.jpg'); 63270 * } 63271 * 63272 * function setup() { 63273 * background(img0); 63274 * image(img1, 0, 0); 63275 * blend(img1, 0, 0, 33, 100, 67, 0, 33, 100, DARKEST); 63276 * } 63277 * </code></div> 63278 * <div><code> 63279 * let img0; 63280 * let img1; 63281 * 63282 * function preload() { 63283 * img0 = loadImage('assets/rockies.jpg'); 63284 * img1 = loadImage('assets/bricks_third.jpg'); 63285 * } 63286 * 63287 * function setup() { 63288 * background(img0); 63289 * image(img1, 0, 0); 63290 * blend(img1, 0, 0, 33, 100, 67, 0, 33, 100, ADD); 63291 * } 63292 * </code></div> 63293 * 63294 * @alt 63295 * image of rocky mountains. Brick images on left and right. Right overexposed 63296 * image of rockies. Brickwall images on left and right. Right mortar transparent 63297 * image of rockies. Brickwall images on left and right. Right translucent 63298 * 63299 * 63300 */ 63301 63302 /** 63303 * @method blend 63304 * @param {Integer} sx 63305 * @param {Integer} sy 63306 * @param {Integer} sw 63307 * @param {Integer} sh 63308 * @param {Integer} dx 63309 * @param {Integer} dy 63310 * @param {Integer} dw 63311 * @param {Integer} dh 63312 * @param {Constant} blendMode 63313 */ 63314 63315 p5.prototype.blend = function () { 63316 p5._validateParameters('blend', arguments); 63317 63318 if (this._renderer) { 63319 this._renderer.blend.apply(this._renderer, arguments); 63320 } else { 63321 p5.Renderer2D.prototype.blend.apply(this, arguments); 63322 } 63323 }; 63324 /** 63325 * Copies a region of the canvas to another region of the canvas 63326 * and copies a region of pixels from an image used as the srcImg parameter 63327 * into the canvas srcImage is specified this is used as the source. If 63328 * the source and destination regions aren't the same size, it will 63329 * automatically resize source pixels to fit the specified 63330 * target region. 63331 * 63332 * @method copy 63333 * @param {p5.Image|p5.Element} srcImage source image 63334 * @param {Integer} sx X coordinate of the source's upper left corner 63335 * @param {Integer} sy Y coordinate of the source's upper left corner 63336 * @param {Integer} sw source image width 63337 * @param {Integer} sh source image height 63338 * @param {Integer} dx X coordinate of the destination's upper left corner 63339 * @param {Integer} dy Y coordinate of the destination's upper left corner 63340 * @param {Integer} dw destination image width 63341 * @param {Integer} dh destination image height 63342 * 63343 * @example 63344 * <div><code> 63345 * let img; 63346 * 63347 * function preload() { 63348 * img = loadImage('assets/rockies.jpg'); 63349 * } 63350 * 63351 * function setup() { 63352 * background(img); 63353 * copy(img, 7, 22, 10, 10, 35, 25, 50, 50);
63354 * stroke(255); 63355 * noFill(); 63356 * // Rectangle shows area being copied 63357 * rect(7, 22, 10, 10); 63358 * } 63359 * </code></div> 63360 * 63361 * @alt 63362 * image of rocky mountains. Brick images on left and right. Right overexposed 63363 * image of rockies. Brickwall images on left and right. Right mortar transparent 63364 * image of rockies. Brickwall images on left and right. Right translucent 63365 * 63366 */ 63367 63368 /** 63369 * @method copy 63370 * @param {Integer} sx 63371 * @param {Integer} sy 63372 * @param {Integer} sw 63373 * @param {Integer} sh 63374 * @param {Integer} dx 63375 * @param {Integer} dy 63376 * @param {Integer} dw 63377 * @param {Integer} dh 63378 */ 63379 63380 63381 p5.prototype.copy = function () { 63382 p5._validateParameters('copy', arguments); 63383 63384 p5.Renderer2D.prototype.copy.apply(this._renderer, arguments); 63385 }; 63386 /** 63387 * Applies a filter to the canvas. 63388 * <br><br> 63389 * 63390 * The presets options are: 63391 * <br><br> 63392 * 63393 * THRESHOLD 63394 * Converts the image to black and white pixels depending if they are above or 63395 * below the threshold defined by the level parameter. The parameter must be 63396 * between 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is used. 63397 * <br><br> 63398 * 63399 * GRAY 63400 * Converts any colors in the image to grayscale equivalents. No parameter 63401 * is used. 63402 * <br><br> 63403 * 63404 * OPAQUE 63405 * Sets the alpha channel to entirely opaque. No parameter is used. 63406 * <br><br> 63407 * 63408 * INVERT 63409 * Sets each pixel to its inverse value. No parameter is used. 63410 * <br><br> 63411 * 63412 * POSTERIZE 63413 * Limits each channel of the image to the number of colors specified as the 63414 * parameter. The parameter can be set to values between 2 and 255, but 63415 * results are most noticeable in the lower ranges. 63416 * <br><br> 63417 * 63418 * BLUR 63419 * Executes a Gaussian blur with the level parameter specifying the extent 63420 * of the blurring. If no parameter is used, the blur is equivalent to 63421 * Gaussian blur of radius 1. Larger values increase the blur. 63422 * <br><br> 63423 * 63424 * ERODE 63425 * Reduces the light areas. No parameter is used. 63426 * <br><br> 63427 * 63428 * DILATE 63429 * Increases the light areas. No parameter is used. 63430 * 63431 * @method filter 63432 * @param {Constant} filterType either THRESHOLD, GRAY, OPAQUE, INVERT, 63433 * POSTERIZE, BLUR, ERODE, DILATE or BLUR. 63434 * See Filters.js for docs on 63435 * each available filter 63436 * @param {Number} [filterParam] an optional parameter unique 63437 * to each filter, see above 63438 * 63439 * @example 63440 * <div> 63441 * <code> 63442 * let img; 63443 * function preload() { 63444 * img = loadImage('assets/bricks.jpg'); 63445 * } 63446 * function setup() { 63447 * image(img, 0, 0); 63448 * filter(THRESHOLD); 63449 * } 63450 * </code> 63451 * </div> 63452 * 63453 * <div> 63454 * <code> 63455 * let img; 63456 * function preload() { 63457 * img = loadImage('assets/bricks.jpg'); 63458 * } 63459 * function setup() { 63460 * image(img, 0, 0); 63461 * filter(GRAY); 63462 * } 63463 * </code> 63464 * </div> 63465 * 63466 * <div> 63467 * <code> 63468 * let img; 63469 * function preload() { 63470 * img = loadImage('assets/bricks.jpg'); 63471 * } 63472 * function setup() { 63473 * image(img, 0, 0); 63474 * filter(OPAQUE); 63475 * } 63476 * </code> 63477 * </div> 63478 * 63479 * <div> 63480 * <code> 63481 * let img; 63482 * function preload() { 63483 * img = loadImage('assets/bricks.jpg'); 63484 * } 63485 * function setup() { 63486 * image(img, 0, 0); 63487 * filter(INVERT); 63488 * } 63489 * </code> 63490 * </div> 63491 * 63492 * <div> 63493 * <code> 63494 * let img; 63495 * function preload() { 63496 * img = loadImage('assets/bricks.jpg'); 63497 * } 63498 * function setup() { 63499 * image(img, 0, 0); 63500 * filter(POSTERIZE, 3); 63501 * } 63502 * </code> 63503 * </div> 63504 * 63505 * <div> 63506 * <code> 63507 * let img; 63508 * function preload() { 63509 * img = loadImage('assets/bricks.jpg'); 63510 * } 63511 * function setup() { 63512 * image(img, 0, 0); 63513 * filter(DILATE); 63514 * } 63515 * </code> 63516 * </div> 63517 * 63518 * <div> 63519 * <code> 63520 * let img; 63521 * function preload() { 63522 * img = loadImage('assets/bricks.jpg'); 63523 * } 63524 * function setup() { 63525 * image(img, 0, 0);
63526 * filter(BLUR, 3); 63527 * } 63528 * </code> 63529 * </div> 63530 * 63531 * <div> 63532 * <code> 63533 * let img; 63534 * function preload() { 63535 * img = loadImage('assets/bricks.jpg'); 63536 * } 63537 * function setup() { 63538 * image(img, 0, 0); 63539 * filter(ERODE); 63540 * } 63541 * </code> 63542 * </div> 63543 * 63544 * @alt 63545 * black and white image of a brick wall. 63546 * greyscale image of a brickwall 63547 * image of a brickwall 63548 * jade colored image of a brickwall 63549 * red and pink image of a brickwall 63550 * image of a brickwall 63551 * blurry image of a brickwall 63552 * image of a brickwall 63553 * image of a brickwall with less detail 63554 * 63555 */ 63556 63557 63558 p5.prototype.filter = function (operation, value) { 63559 p5._validateParameters('filter', arguments); 63560 63561 if (this.canvas !== undefined) { 63562 Filters.apply(this.canvas, Filters[operation.toLowerCase()], value); 63563 } else { 63564 Filters.apply(this.elt, Filters[operation.toLowerCase()], value); 63565 } 63566 }; 63567 /** 63568 * Returns an array of [R,G,B,A] values for any pixel or grabs a section of 63569 * an image. If no parameters are specified, the entire image is returned. 63570 * Use the x and y parameters to get the value of one pixel. Get a section of 63571 * the display window by specifying additional w and h parameters. When 63572 * getting an image, the x and y parameters define the coordinates for the 63573 * upper-left corner of the image, regardless of the current <a href="#/p5/imageMode">imageMode()</a>. 63574 * <br><br> 63575 * If the pixel requested is outside of the image window, [0,0,0,255] is 63576 * returned. To get the numbers scaled according to the current color ranges 63577 * and taking into account <a href="#/p5/colorMode">colorMode</a>, use <a href="#/p5/getColor">getColor</a> instead of get. 63578 * <br><br> 63579 * Getting the color of a single pixel with get(x, y) is easy, but not as fast 63580 * as grabbing the data directly from <a href="#/p5/pixels">pixels[]</a>. The equivalent statement to 63581 * get(x, y) using <a href="#/p5/pixels">pixels[]</a> with pixel density d is 63582 * ```javascript 63583 * let x, y, d; // set these to the coordinates 63584 * let off = (y * width + x) * d * 4; 63585 * let components = [ 63586 * pixels[off], 63587 * pixels[off + 1], 63588 * pixels[off + 2], 63589 * pixels[off + 3] 63590 * ]; 63591 * print(components); 63592 * ``` 63593 * <br><br> 63594 * See the reference for <a href="#/p5/pixels">pixels[]</a> for more information. 63595 * 63596 * If you want to extract an array of colors or a subimage from an p5.Image object, 63597 * take a look at <a href="#/p5.Image/get">p5.Image.get()</a> 63598 * 63599 * @method get 63600 * @param {Number} [x] x-coordinate of the pixel 63601 * @param {Number} [y] y-coordinate of the pixel 63602 * @param {Number} [w] width 63603 * @param {Number} [h] height 63604 * @return {Number[]|p5.Image} values of pixel at x,y in array format 63605 * [R, G, B, A] or <a href="#/p5.Image">p5.Image</a> 63606 * @example 63607 * <div> 63608 * <code> 63609 * let img; 63610 * function preload() { 63611 * img = loadImage('assets/rockies.jpg'); 63612 * } 63613 * function setup() { 63614 * image(img, 0, 0); 63615 * let c = get(); 63616 * image(c, width / 2, 0); 63617 * } 63618 * </code> 63619 * </div> 63620 * 63621 * <div> 63622 * <code> 63623 * let img; 63624 * function preload() { 63625 * img = loadImage('assets/rockies.jpg'); 63626 * } 63627 * function setup() { 63628 * image(img, 0, 0); 63629 * let c = get(50, 90); 63630 * fill(c); 63631 * noStroke(); 63632 * rect(25, 25, 50, 50); 63633 * } 63634 * </code> 63635 * </div> 63636 * 63637 * @alt 63638 * 2 images of the rocky mountains, side-by-side 63639 * Image of the rocky mountains with 50x50 green rect in center of canvas 63640 * 63641 */ 63642 63643 63644 p5.prototype.get = function (x, y, w, h) { 63645 if (typeof w === 'undefined' && typeof h === 'undefined') { 63646 if (typeof x === 'undefined' && typeof y === 'undefined') { 63647 x = y = 0; 63648 w = this.width; 63649 h = this.height; 63650 } else { 63651 w = h = 1; 63652 } 63653 } // if the section does not overlap the canvas 63654 63655 63656 if (x + w < 0 || y + h < 0 || x >= this.width || y >= this.height) { 63657 // TODO: is this valid for w,h > 1 ? 63658 return [0, 0, 0, 255]; 63659 } // round down to get integer numbers 63660 63661 63662 x = Math.floor(x); 63663 y = Math.floor(y); 63664 w = Math.floor(w); 63665 h = Math.floor(h); 63666 63667 if (this instanceof p5.Image) { 63668 return p5.Renderer2D.prototype.get.call(this, x, y, w, h); 63669 } else { 63670 return this._renderer.get(x, y, w, h); 63671 } 63672 }; 63673 /** 63674 * Loads the pixel data for the display window into the <a href="#/p5/pixels">pixels[]</a> array. This
63675 * function must always be called before reading from or writing to <a href="#/p5/pixels">pixels[]</a>. 63676 * Note that only changes made with <a href="#/p5/set">set()</a> or direct manipulation of <a href="#/p5/pixels">pixels[]</a> 63677 * will occur. 63678 * 63679 * @method loadPixels 63680 * @example 63681 * <div> 63682 * <code> 63683 * let img; 63684 * function preload() { 63685 * img = loadImage('assets/rockies.jpg'); 63686 * } 63687 * 63688 * function setup() { 63689 * image(img, 0, 0); 63690 * let d = pixelDensity(); 63691 * let halfImage = 4 * (img.width * d) * (img.height * d / 2); 63692 * loadPixels(); 63693 * for (let i = 0; i < halfImage; i++) { 63694 * pixels[i + halfImage] = pixels[i]; 63695 * } 63696 * updatePixels(); 63697 * } 63698 * </code> 63699 * </div> 63700 * 63701 * @alt 63702 * two images of the rocky mountains. one on top, one on bottom of canvas. 63703 * 63704 */ 63705 63706 63707 p5.prototype.loadPixels = function () { 63708 p5._validateParameters('loadPixels', arguments); 63709 63710 this._renderer.loadPixels(); 63711 }; 63712 /** 63713 * <p>Changes the color of any pixel, or writes an image directly to the 63714 * display window.</p> 63715 * <p>The x and y parameters specify the pixel to change and the c parameter 63716 * specifies the color value. This can be a <a href="#/p5.Color">p5.Color</a> object, or [R, G, B, A] 63717 * pixel array. It can also be a single grayscale value. 63718 * When setting an image, the x and y parameters define the coordinates for 63719 * the upper-left corner of the image, regardless of the current <a href="#/p5/imageMode">imageMode()</a>. 63720 * </p> 63721 * <p> 63722 * After using <a href="#/p5/set">set()</a>, you must call <a href="#/p5/updatePixels">updatePixels()</a> for your changes to appear. 63723 * This should be called once all pixels have been set, and must be called before 63724 * calling .<a href="#/p5/get">get()</a> or drawing the image. 63725 * </p> 63726 * <p>Setting the color of a single pixel with set(x, y) is easy, but not as 63727 * fast as putting the data directly into <a href="#/p5/pixels">pixels[]</a>. Setting the <a href="#/p5/pixels">pixels[]</a> 63728 * values directly may be complicated when working with a retina display, 63729 * but will perform better when lots of pixels need to be set directly on 63730 * every loop.</p> 63731 * <p>See the reference for <a href="#/p5/pixels">pixels[]</a> for more information.</p> 63732 * 63733 * @method set 63734 * @param {Number} x x-coordinate of the pixel 63735 * @param {Number} y y-coordinate of the pixel 63736 * @param {Number|Number[]|Object} c insert a grayscale value | a pixel array | 63737 * a <a href="#/p5.Color">p5.Color</a> object | a <a href="#/p5.Image">p5.Image</a> to copy 63738 * @example 63739 * <div> 63740 * <code> 63741 * let black = color(0); 63742 * set(30, 20, black); 63743 * set(85, 20, black); 63744 * set(85, 75, black); 63745 * set(30, 75, black); 63746 * updatePixels(); 63747 * </code> 63748 * </div> 63749 * 63750 * <div> 63751 * <code> 63752 * for (let i = 30; i < width - 15; i++) { 63753 * for (let j = 20; j < height - 25; j++) { 63754 * let c = color(204 - j, 153 - i, 0); 63755 * set(i, j, c); 63756 * } 63757 * } 63758 * updatePixels(); 63759 * </code> 63760 * </div> 63761 * 63762 * <div> 63763 * <code> 63764 * let img; 63765 * function preload() { 63766 * img = loadImage('assets/rockies.jpg'); 63767 * } 63768 * 63769 * function setup() { 63770 * set(0, 0, img); 63771 * updatePixels(); 63772 * line(0, 0, width, height); 63773 * line(0, height, width, 0); 63774 * } 63775 * </code> 63776 * </div> 63777 * 63778 * @alt 63779 * 4 black points in the shape of a square middle-right of canvas. 63780 * square with orangey-brown gradient lightening at bottom right. 63781 * image of the rocky mountains. with lines like an 'x' through the center. 63782 */ 63783 63784 63785 p5.prototype.set = function (x, y, imgOrCol) { 63786 this._renderer.set(x, y, imgOrCol); 63787 }; 63788 /** 63789 * Updates the display window with the data in the <a href="#/p5/pixels">pixels[]</a> array. 63790 * Use in conjunction with <a href="#/p5/loadPixels">loadPixels()</a>. If you're only reading pixels from 63791 * the array, there's no need to call <a href="#/p5/updatePixels">updatePixels()</a> â updating is only 63792 * necessary to apply changes. <a href="#/p5/updatePixels">updatePixels()</a> should be called anytime the 63793 * pixels array is manipulated or <a href="#/p5/set">set()</a> is called, and only changes made with 63794 * <a href="#/p5/set">set()</a> or direct changes to <a href="#/p5/pixels">pixels[]</a> will occur. 63795 * 63796 * @method updatePixels 63797 * @param {Number} [x] x-coordinate of the upper-left corner of region 63798 * to update 63799 * @param {Number} [y] y-coordinate of the upper-left corner of region 63800 * to update 63801 * @param {Number} [w] width of region to update 63802 * @param {Number} [h] height of region to update 63803 * @example 63804 * <div> 63805 * <code> 63806 * let img; 63807 * function preload() { 63808 * img = loadImage('assets/rockies.jpg'); 63809 * } 63810 * 63811 * function setup() { 63812 * image(img, 0, 0); 63813 * let d = pixelDensity(); 63814 * let halfImage = 4 * (img.width * d) * (img.height * d / 2); 63815 * loadPixels(); 63816 * for (let i = 0; i < halfImage; i++) { 63817 * pixels[i + halfImage] = pixels[i]; 63818 * } 63819 * updatePixels(); 63820 * } 63821 * </code> 63822 * </div> 63823 * @alt 63824 * two images of the rocky mountains. one on top, one on bottom of canvas. 63825 */ 63826 63827 63828 p5.prototype.updatePixels = function (x, y, w, h) { 63829 p5._validateParameters('updatePixels', arguments); // graceful fail - if loadPixels() or set() has not been called, pixel 63830 // array will be empty, ignore call to updatePixels() 63831 63832 63833 if (this.pixels.length === 0) { 63834 return; 63835 } 63836 63837 this._renderer.updatePixels(x, y, w, h); 63838 }; 63839 63840 module.exports = p5; 63841 }, {
63842 "../color/p5.Color": 16, 63843 "../core/main": 24, 63844 "./filters": 42 63845 }], 63846 47: [function (_dereq_, module, exports) { 63847 /** 63848 * @module IO 63849 * @submodule Input 63850 * @for p5 63851 * @requires core 63852 */ 63853 63854 /* globals Request: false */ 63855 63856 /* globals Headers: false */ 63857 'use strict'; 63858 63859 var p5 = _dereq_('../core/main'); 63860 63861 _dereq_('whatwg-fetch'); 63862 63863 _dereq_('es6-promise').polyfill(); 63864 63865 var fetchJsonp = _dereq_('fetch-jsonp'); 63866 63867 _dereq_('../core/error_helpers'); 63868 /** 63869 * Loads a JSON file from a file or a URL, and returns an Object. 63870 * Note that even if the JSON file contains an Array, an Object will be 63871 * returned with index numbers as keys. 63872 * 63873 * This method is asynchronous, meaning it may not finish before the next 63874 * line in your sketch is executed. JSONP is supported via a polyfill and you 63875 * can pass in as the second argument an object with definitions of the json 63876 * callback following the syntax specified <a href="https://github.com/camsong/ 63877 * fetch-jsonp">here</a>. 63878 * 63879 * This method is suitable for fetching files up to size of 64MB. 63880 * @method loadJSON 63881 * @param {String} path name of the file or url to load 63882 * @param {Object} [jsonpOptions] options object for jsonp related settings 63883 * @param {String} [datatype] "json" or "jsonp" 63884 * @param {function} [callback] function to be executed after 63885 * <a href="#/p5/loadJSON">loadJSON()</a> completes, data is passed 63886 * in as first argument 63887 * @param {function} [errorCallback] function to be executed if 63888 * there is an error, response is passed 63889 * in as first argument 63890 * @return {Object|Array} JSON data 63891 * @example 63892 * 63893 * <p>Calling <a href="#/p5/loadJSON">loadJSON()</a> inside <a href="#/p5/preload">preload()</a> guarantees to complete the 63894 * operation before <a href="#/p5/setup">setup()</a> and <a href="#/p5/draw">draw()</a> are called.</p> 63895 * 63896 * <div><code> 63897 * // Examples use USGS Earthquake API: 63898 * // https://earthquake.usgs.gov/fdsnws/event/1/#methods 63899 * let earthquakes; 63900 * function preload() { 63901 * // Get the most recent earthquake in the database 63902 * let url = 63903 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/' + 63904 * 'summary/all_day.geojson'; 63905 * earthquakes = loadJSON(url); 63906 * } 63907 * 63908 * function setup() { 63909 * noLoop(); 63910 * } 63911 * 63912 * function draw() { 63913 * background(200); 63914 * // Get the magnitude and name of the earthquake out of the loaded JSON 63915 * let earthquakeMag = earthquakes.features[0].properties.mag; 63916 * let earthquakeName = earthquakes.features[0].properties.place; 63917 * ellipse(width / 2, height / 2, earthquakeMag * 10, earthquakeMag * 10); 63918 * textAlign(CENTER); 63919 * text(earthquakeName, 0, height - 30, width, 30); 63920 * } 63921 * </code></div> 63922 * 63923 * 63924 * <p>Outside of preload(), you may supply a callback function to handle the 63925 * object:</p> 63926 * <div><code> 63927 * function setup() { 63928 * noLoop(); 63929 * let url = 63930 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/' + 63931 * 'summary/all_day.geojson'; 63932 * loadJSON(url, drawEarthquake); 63933 * } 63934 * 63935 * function draw() { 63936 * background(200); 63937 * } 63938 * 63939 * function drawEarthquake(earthquakes) { 63940 * // Get the magnitude and name of the earthquake out of the loaded JSON 63941 * let earthquakeMag = earthquakes.features[0].properties.mag; 63942 * let earthquakeName = earthquakes.features[0].properties.place; 63943 * ellipse(width / 2, height / 2, earthquakeMag * 10, earthquakeMag * 10); 63944 * textAlign(CENTER);
63945 * text(earthquakeName, 0, height - 30, width, 30); 63946 * } 63947 * </code></div> 63948 * 63949 * @alt 63950 * 50x50 ellipse that changes from black to white depending on the current humidity 63951 * 50x50 ellipse that changes from black to white depending on the current humidity 63952 * 63953 */ 63954 63955 /** 63956 * @method loadJSON 63957 * @param {String} path 63958 * @param {String} datatype 63959 * @param {function} [callback] 63960 * @param {function} [errorCallback] 63961 * @return {Object|Array} 63962 */ 63963 63964 /** 63965 * @method loadJSON 63966 * @param {String} path 63967 * @param {function} callback 63968 * @param {function} [errorCallback] 63969 * @return {Object|Array} 63970 */ 63971 63972 63973 p5.prototype.loadJSON = function () { 63974 p5._validateParameters('loadJSON', arguments); 63975 63976 var path = arguments[0]; 63977 var callback; 63978 var errorCallback; 63979 var options; 63980 var ret = {}; // object needed for preload 63981 63982 var t = 'json'; // check for explicit data type argument 63983 63984 for (var i = 1; i < arguments.length; i++) { 63985 var arg = arguments[i]; 63986 63987 if (typeof arg === 'string') { 63988 if (arg === 'jsonp' || arg === 'json') { 63989 t = arg; 63990 } 63991 } else if (typeof arg === 'function') { 63992 if (!callback) { 63993 callback = arg; 63994 } else { 63995 errorCallback = arg; 63996 } 63997 } else if (typeof arg === 'object' && arg.hasOwnProperty('jsonpCallback')) { 63998 t = 'jsonp'; 63999 options = arg; 64000 } 64001 } 64002 64003 var self = this; 64004 this.httpDo(path, 'GET', options, t, function (resp) { 64005 for (var k in resp) { 64006 ret[k] = resp[k]; 64007 } 64008 64009 if (typeof callback !== 'undefined') { 64010 callback(resp); 64011 } 64012 64013 self._decrementPreload(); 64014 }, function (err) { 64015 // Error handling 64016 p5._friendlyFileLoadError(5, path); 64017 64018 if (errorCallback) { 64019 errorCallback(err); 64020 } else { 64021 throw err; 64022 } 64023 }); 64024 return ret; 64025 }; 64026 /** 64027 * Reads the contents of a file and creates a String array of its individual 64028 * lines. If the name of the file is used as the parameter, as in the above 64029 * example, the file must be located in the sketch directory/folder. 64030 * <br><br> 64031 * Alternatively, the file maybe be loaded from anywhere on the local 64032 * computer using an absolute path (something that starts with / on Unix and 64033 * Linux, or a drive letter on Windows), or the filename parameter can be a 64034 * URL for a file found on a network. 64035 * <br><br> 64036 * This method is asynchronous, meaning it may not finish before the next 64037 * line in your sketch is executed. 64038 * 64039 * This method is suitable for fetching files up to size of 64MB. 64040 * @method loadStrings 64041 * @param {String} filename name of the file or url to load 64042 * @param {function} [callback] function to be executed after <a href="#/p5/loadStrings">loadStrings()</a> 64043 * completes, Array is passed in as first 64044 * argument 64045 * @param {function} [errorCallback] function to be executed if 64046 * there is an error, response is passed 64047 * in as first argument 64048 * @return {String[]} Array of Strings 64049 * @example 64050 * 64051 * <p>Calling loadStrings() inside <a href="#/p5/preload">preload()</a> guarantees to complete the 64052 * operation before <a href="#/p5/setup">setup()</a> and <a href="#/p5/draw">draw()</a> are called.</p> 64053 * 64054 * <div><code> 64055 * let result; 64056 * function preload() { 64057 * result = loadStrings('assets/test.txt'); 64058 * } 64059 64060 * function setup() { 64061 * background(200); 64062 * let ind = floor(random(result.length)); 64063 * text(result[ind], 10, 10, 80, 80); 64064 * } 64065 * </code></div> 64066 * 64067 * <p>Outside of preload(), you may supply a callback function to handle the 64068 * object:</p> 64069 * 64070 * <div><code> 64071 * function setup() { 64072 * loadStrings('assets/test.txt', pickString); 64073 * } 64074 * 64075 * function pickString(result) { 64076 * background(200); 64077 * let ind = floor(random(result.length)); 64078 * text(result[ind], 10, 10, 80, 80); 64079 * } 64080 * </code></div> 64081 * 64082 * @alt 64083 * randomly generated text from a file, for example "i smell like butter" 64084 * randomly generated text from a file, for example "i have three feet" 64085 * 64086 */ 64087 64088 64089 p5.prototype.loadStrings = function () { 64090 p5._validateParameters('loadStrings', arguments); 64091 64092 var ret = []; 64093 var callback, errorCallback; 64094 64095 for (var i = 1; i < arguments.length; i++) { 64096 var arg = arguments[i]; 64097 64098 if (typeof arg === 'function') { 64099 if (typeof callback === 'undefined') { 64100 callback = arg; 64101 } else if (typeof errorCallback === 'undefined') { 64102 errorCallback = arg; 64103 } 64104 } 64105 } 64106 64107 var self = this; 64108 p5.prototype.httpDo.call(this, arguments[0], 'GET', 'text', function (data) { 64109 // split lines handling mac/windows/linux endings 64110 var lines = data.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); 64111 Array.prototype.push.apply(ret, lines); 64112 64113 if (typeof callback !== 'undefined') { 64114 callback(ret); 64115 } 64116 64117 self._decrementPreload(); 64118 }, function (err) { 64119 // Error handling 64120 p5._friendlyFileLoadError(3, arguments[0]); 64121 64122 if (errorCallback) { 64123 errorCallback(err); 64124 } else { 64125 throw err; 64126 } 64127 }); 64128 return ret; 64129 }; 64130 /** 64131 * <p>Reads the contents of a file or URL and creates a <a href="#/p5.Table">p5.Table</a> object with 64132 * its values. If a file is specified, it must be located in the sketch's 64133 * "data" folder. The filename parameter can also be a URL to a file found 64134 * online. By default, the file is assumed to be comma-separated (in CSV 64135 * format). Table only looks for a header row if the 'header' option is 64136 * included.</p> 64137 * 64138 * <p>Possible options include: 64139 * <ul> 64140 * <li>csv - parse the table as comma-separated values</li> 64141 * <li>tsv - parse the table as tab-separated values</li> 64142 * <li>header - this table has a header (title) row</li> 64143 * </ul> 64144 * </p> 64145 * 64146 * <p>When passing in multiple options, pass them in as separate parameters, 64147 * seperated by commas. For example: 64148 * <br><br> 64149 * <code> 64150 * loadTable('my_csv_file.csv', 'csv', 'header'); 64151 * </code> 64152 * </p> 64153 * 64154 * <p> All files loaded and saved use UTF-8 encoding.</p> 64155 * 64156 * <p>This method is asynchronous, meaning it may not finish before the next 64157 * line in your sketch is executed. Calling <a href="#/p5/loadTable">loadTable()</a> inside <a href="#/p5/preload">preload()</a> 64158 * guarantees to complete the operation before <a href="#/p5/setup">setup()</a> and <a href="#/p5/draw">draw()</a> are called. 64159 * <p>Outside of <a href="#/p5/preload">preload()</a>, you may supply a callback function to handle the 64160 * object:</p> 64161 * </p> 64162 * 64163 * This method is suitable for fetching files up to size of 64MB. 64164 * @method loadTable 64165 * @param {String} filename name of the file or URL to load 64166 * @param {String} options "header" "csv" "tsv" 64167 * @param {function} [callback] function to be executed after 64168 * <a href="#/p5/loadTable">loadTable()</a> completes. On success, the 64169 * <a href="#/p5.Table">Table</a> object is passed in as the 64170 * first argument. 64171 * @param {function} [errorCallback] function to be executed if 64172 * there is an error, response is passed 64173 * in as first argument 64174 * @return {Object} <a href="#/p5.Table">Table</a>
64174 object containing data 64175 * 64176 * @example 64177 * <div class='norender'> 64178 * <code> 64179 * // Given the following CSV file called "mammals.csv" 64180 * // located in the project's "assets" folder: 64181 * // 64182 * // id,species,name 64183 * // 0,Capra hircus,Goat 64184 * // 1,Panthera pardus,Leopard 64185 * // 2,Equus zebra,Zebra 64186 * 64187 * let table; 64188 * 64189 * function preload() { 64190 * //my table is comma separated value "csv" 64191 * //and has a header specifying the columns labels 64192 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 64193 * //the file can be remote 64194 * //table = loadTable("http://p5js.org/reference/assets/mammals.csv", 64195 * // "csv", "header"); 64196 * } 64197 * 64198 * function setup() { 64199 * //count the columns 64200 * print(table.getRowCount() + ' total rows in table'); 64201 * print(table.getColumnCount() + ' total columns in table'); 64202 * 64203 * print(table.getColumn('name')); 64204 * //["Goat", "Leopard", "Zebra"] 64205 * 64206 * //cycle through the table 64207 * for (let r = 0; r < table.getRowCount(); r++) 64208 * for (let c = 0; c < table.getColumnCount(); c++) { 64209 * print(table.getString(r, c)); 64210 * } 64211 * } 64212 * </code> 64213 * </div> 64214 * 64215 * @alt 64216 * randomly generated text from a file, for example "i smell like butter" 64217 * randomly generated text from a file, for example "i have three feet" 64218 * 64219 */ 64220 64221 /** 64222 * @method loadTable 64223 * @param {String} filename 64224 * @param {function} [callback] 64225 * @param {function} [errorCallback] 64226 * @return {Object} 64227 */ 64228 64229 64230 p5.prototype.loadTable = function (path) { 64231 var callback; 64232 var errorCallback; 64233 var options = []; 64234 var header = false;
64235 var ext = path.substring(path.lastIndexOf('.') + 1, path.length); 64236 var sep = ','; 64237 var separatorSet = false; 64238 64239 if (ext === 'tsv') { 64240 //Only need to check extension is tsv because csv is default 64241 sep = '\t'; 64242 } 64243 64244 for (var i = 1; i < arguments.length; i++) { 64245 if (typeof arguments[i] === 'function') { 64246 if (typeof callback === 'undefined') { 64247 callback = arguments[i]; 64248 } else if (typeof errorCallback === 'undefined') { 64249 errorCallback = arguments[i]; 64250 } 64251 } else if (typeof arguments[i] === 'string') { 64252 options.push(arguments[i]); 64253 64254 if (arguments[i] === 'header') { 64255 header = true; 64256 } 64257 64258 if (arguments[i] === 'csv') { 64259 if (separatorSet) { 64260 throw new Error('Cannot set multiple separator types.'); 64261 } else { 64262 sep = ','; 64263 separatorSet = true; 64264 } 64265 } else if (arguments[i] === 'tsv') { 64266 if (separatorSet) { 64267 throw new Error('Cannot set multiple separator types.'); 64268 } else { 64269 sep = '\t'; 64270 separatorSet = true; 64271 } 64272 } 64273 } 64274 } 64275 64276 var t = new p5.Table(); 64277 var self = this; 64278 this.httpDo(path, 'GET', 'table', function (resp) { 64279 var state = {}; // define constants 64280 64281 var PRE_TOKEN = 0, 64282 MID_TOKEN = 1, 64283 POST_TOKEN = 2, 64284 POST_RECORD = 4; 64285 var QUOTE = '"', 64286 CR = '\r', 64287 LF = '\n'; 64288 var records = []; 64289 var offset = 0; 64290 var currentRecord = null; 64291 var currentChar; 64292 64293 var tokenBegin = function () { 64294 state.currentState = PRE_TOKEN; 64295 state.token = ''; 64296 }; 64297 64298 var tokenEnd = function () { 64299 currentRecord.push(state.token); 64300 tokenBegin(); 64301 }; 64302 64303 var recordBegin = function () { 64304 state.escaped = false; 64305 currentRecord = []; 64306 tokenBegin(); 64307 }; 64308 64309 var recordEnd = function () { 64310 state.currentState = POST_RECORD; 64311 records.push(currentRecord); 64312 currentRecord = null; 64313 }; 64314 64315 for (;;) { 64316 currentChar = resp[offset++]; // EOF 64317 64318 if (currentChar == null) { 64319 if (state.escaped) { 64320 throw new Error('Unclosed quote in file.'); 64321 } 64322 64323 if (currentRecord) { 64324 tokenEnd(); 64325 recordEnd(); 64326 break; 64327 } 64328 } 64329 64330 if (currentRecord === null) { 64331 recordBegin(); 64332 } // Handle opening quote 64333 64334 64335 if (state.currentState === PRE_TOKEN) { 64336 if (currentChar === QUOTE) { 64337 state.escaped = true; 64338 state.currentState = MID_TOKEN; 64339 continue; 64340 } 64341 64342 state.currentState = MID_TOKEN; 64343 } // mid-token and escaped, look for sequences and end quote 64344 64345 64346 if (state.currentState === MID_TOKEN && state.escaped) { 64347 if (currentChar === QUOTE) { 64348 if (resp[offset] === QUOTE) { 64349 state.token += QUOTE; 64350 offset++; 64351 } else { 64352 state.escaped = false; 64353 state.currentState = POST_TOKEN; 64354 } 64355 } else if (currentChar === CR) { 64356 continue; 64357 } else { 64358 state.token += currentChar; 64359 } 64360 64361 continue; 64362 } // fall-through: mid-token or post-token, not escaped 64363 64364 64365 if (currentChar === CR) { 64366 if (resp[offset] === LF) { 64367 offset++; 64368 } 64369 64370 tokenEnd(); 64371 recordEnd(); 64372 } else if (currentChar === LF) { 64373 tokenEnd(); 64374 recordEnd(); 64375 } else if (currentChar === sep) { 64376 tokenEnd(); 64377 } else if (state.currentState === MID_TOKEN) { 64378 state.token += currentChar; 64379 } 64380 } // set up column names 64381 64382 64383 if (header) { 64384 t.columns = records.shift(); 64385 } else { 64386 for (i = 0; i < records[0].length; i++) { 64387 t.columns[i] = 'null';
64388 } 64389 } 64390 64391 var row; 64392 64393 for (i = 0; i < records.length; i++) { 64394 //Handles row of 'undefined' at end of some CSVs 64395 if (records[i].length === 1) { 64396 if (records[i][0] === 'undefined' || records[i][0] === '') { 64397 continue; 64398 } 64399 } 64400 64401 row = new p5.TableRow(); 64402 row.arr = records[i]; 64403 row.obj = makeObject(records[i], t.columns); 64404 t.addRow(row); 64405 } 64406 64407 if (typeof callback === 'function') { 64408 callback(t); 64409 } 64410 64411 self._decrementPreload(); 64412 }, function (err) { 64413 // Error handling 64414 p5._friendlyFileLoadError(2, path); 64415 64416 if (errorCallback) { 64417 errorCallback(err); 64418 } else { 64419 console.error(err); 64420 } 64421 }); 64422 return t; 64423 }; // helper function to turn a row into a JSON object 64424 64425 64426 function makeObject(row, headers) { 64427 var ret = {}; 64428 headers = headers || []; 64429 64430 if (typeof headers === 'undefined') { 64431 for (var j = 0; j < row.length; j++) { 64432 headers[j.toString()] = j; 64433 } 64434 } 64435 64436 for (var i = 0; i < headers.length; i++) { 64437 var key = headers[i]; 64438 var val = row[i]; 64439 ret[key] = val; 64440 } 64441 64442 return ret; 64443 } 64444 /** 64445 * Reads the contents of a file and creates an XML object with its values. 64446 * If the name of the file is used as the parameter, as in the above example, 64447 * the file must be located in the sketch directory/folder. 64448 * 64449 * Alternatively, the file maybe be loaded from anywhere on the local 64450 * computer using an absolute path (something that starts with / on Unix and 64451 * Linux, or a drive letter on Windows), or the filename parameter can be a 64452 * URL for a file found on a network. 64453 * 64454 * This method is asynchronous, meaning it may not finish before the next 64455 * line in your sketch is executed. Calling <a href="#/p5/loadXML">loadXML()</a> inside <a href="#/p5/preload">preload()</a> 64456 * guarantees to complete the operation before <a href="#/p5/setup">setup()</a> and <a href="#/p5/draw">draw()</a> are called. 64457 * 64458 * Outside of <a href="#/p5/preload">preload()</a>, you may supply a callback function to handle the 64459 * object. 64460 * 64461 * This method is suitable for fetching files up to size of 64MB. 64462 * @method loadXML 64463 * @param {String} filename name of the file or URL to load 64464 * @param {function} [callback] function to be executed after <a href="#/p5/loadXML">loadXML()</a> 64465 * completes, XML object is passed in as 64466 * first argument 64467 * @param {function} [errorCallback] function to be executed if 64468 * there is an error, response is passed 64469 * in as first argument 64470 * @return {Object} XML object containing data 64471 * @example 64472 * <div class='norender'><code> 64473 * // The following short XML file called "mammals.xml" is parsed 64474 * // in the code below. 64475 * // 64476 * // <?xml version="1.0"?> 64477 * // <mammals> 64478 * // <animal id="0" species="Capra hircus">Goat</animal> 64479 * // <animal id="1" species="Panthera pardus">Leopard</animal> 64480 * // <animal id="2" species="Equus zebra">Zebra</animal> 64481 * // </mammals> 64482 * 64483 * let xml; 64484 * 64485 * function preload() { 64486 * xml = loadXML('assets/mammals.xml'); 64487 * } 64488 * 64489 * function setup() { 64490 * let children = xml.getChildren('animal'); 64491 * 64492 * for (let i = 0; i < children.length; i++) { 64493 * let id = children[i].getNum('id'); 64494 * let coloring = children[i].getString('species'); 64495 * let name = children[i].getContent(); 64496 * print(id + ', ' + coloring + ', ' + name); 64497 * } 64498 * } 64499 * 64500 * // Sketch prints: 64501 * // 0, Capra hircus, Goat 64502 * // 1, Panthera pardus, Leopard 64503 * // 2, Equus zebra, Zebra 64504 * </code></div> 64505 * 64506 * @alt 64507 * no image displayed 64508 * 64509 */ 64510 64511 64512 p5.prototype.loadXML = function () { 64513 var ret = new p5.XML(); 64514 var callback, errorCallback; 64515 64516 for (var i = 1; i < arguments.length; i++) { 64517 var arg = arguments[i]; 64518 64519 if (typeof arg === 'function') { 64520 if (typeof callback === 'undefined') { 64521 callback = arg; 64522 } else if (typeof errorCallback === 'undefined') { 64523 errorCallback = arg; 64524 } 64525 } 64526 } 64527 64528 var self = this; 64529 this.httpDo(arguments[0], 'GET', 'xml', function (xml) { 64530 for (var key in xml) { 64531 ret[key] = xml[key]; 64532 } 64533 64534 if (typeof callback !== 'undefined') { 64535 callback(ret); 64536 } 64537 64538 self._decrementPreload(); 64539 }, function (err) { 64540 // Error handling 64541 p5._friendlyFileLoadError(1, arguments[0]); 64542 64543 if (errorCallback) { 64544 errorCallback(err); 64545 } else { 64546 throw err; 64547 } 64548 }); 64549 return ret; 64550 }; 64551 /** 64552 * This method is suitable for fetching files up to size of 64MB. 64553 * @method loadBytes 64554 * @param {string} file name of the file or URL to load 64555 * @param {function} [callback] function to be executed after <a href="#/p5/loadBytes">loadBytes()</a> 64556 * completes 64557 * @param {function} [errorCallback] function to be executed if there 64558 * is an error 64559 * @returns {Object} an object whose 'bytes' property will be the loaded buffer 64560 * 64561 * @example 64562 * <div class='norender'><code> 64563 * let data; 64564 * 64565 * function preload() { 64566 * data = loadBytes('assets/mammals.xml'); 64567 * } 64568 * 64569 * function setup() { 64570 * for (let i = 0; i < 5; i++) { 64571 * console.log(data.bytes[i].toString(16)); 64572 * } 64573 * } 64574 * </code></div> 64575 * 64576 * @alt 64577 * no image displayed 64578 * 64579 */ 64580 64581 64582 p5.prototype.loadBytes = function (file, callback, errorCallback) { 64583 var ret = {}; 64584 var self = this; 64585 this.httpDo(file, 'GET', 'arrayBuffer', function (arrayBuffer) { 64586 ret.bytes = new Uint8Array(arrayBuffer); 64587 64588 if (typeof callback === 'function') { 64589 callback(ret); 64590 } 64591 64592 self._decrementPreload(); 64593 }, function (err) { 64594 // Error handling 64595 p5._friendlyFileLoadError(6, file); 64596 64597 if (errorCallback) { 64598 errorCallback(err); 64599 } else { 64600 throw err; 64601 } 64602 }); 64603 return ret; 64604 }; 64605 /** 64606 * Method for executing an HTTP GET request. If data type is not specified, 64607 * p5 will try to guess based on the URL, defaulting to text. This is equivalent to 64608 * calling <code>httpDo(path, 'GET')</code>. The 'binary' datatype will return 64609 * a Blob object, and the 'arrayBuffer' datatype will return an ArrayBuffer 64610 * which can be used to initialize typed arrays (such as Uint8Array). 64611 * 64612 * @method httpGet 64613 * @param {String} path name of the file or url to load 64614 * @param {String} [datatype] "json", "jsonp", "binary", "arrayBuffer", 64615 * "xml", or "text" 64616 * @param {Object|Boolean} [data] param data passed sent with request 64617 * @param {function} [callback] function to be executed after 64618 * <a href="#/p5/httpGet">httpGet()</a> completes, data is passed in 64619 * as first argument 64620 * @param {function} [errorCallback] function to be executed if 64621 * there is an error, response is passed 64622 * in as first argument 64623 * @return {Promise} A promise that resolves with the data when the operation 64624 * completes successfully or rejects with the error after 64625 * one occurs. 64626 * @example 64627 * <div class='norender'><code> 64628 * // Examples use USGS Earthquake API: 64629 * // https://earthquake.usgs.gov/fdsnws/event/1/#methods 64630 * let earthquakes; 64631 * function preload() { 64632 * // Get the most recent earthquake in the database 64633 * let url = 64634 'https://earthquake.usgs.gov/fdsnws/event/1/query?' + 64635 * 'format=geojson&limit=1&orderby=time'; 64636 * httpGet(url, 'jsonp', false, function(response) { 64637 * // when the HTTP request completes, populate the variable that holds the 64638 * // earthquake data used in the visualization. 64639 * earthquakes = response; 64640 * }); 64641 * } 64642 * 64643 * function draw() { 64644 * if (!earthquakes) { 64645 * // Wait until the earthquake data has loaded before drawing. 64646 * return; 64647 * } 64648 * background(200); 64649 * // Get the magnitude and name of the earthquake out of the loaded JSON 64650 * let earthquakeMag = earthquakes.features[0].properties.mag; 64651 * let earthquakeName = earthquakes.features[0].properties.place; 64652 * ellipse(width / 2, height / 2, earthquakeMag * 10, earthquakeMag * 10); 64653 * textAlign(CENTER);
64654 * text(earthquakeName, 0, height - 30, width, 30); 64655 * noLoop(); 64656 * } 64657 * </code></div> 64658 */ 64659 64660 /** 64661 * @method httpGet 64662 * @param {String} path 64663 * @param {Object|Boolean} data 64664 * @param {function} [callback] 64665 * @param {function} [errorCallback] 64666 * @return {Promise} 64667 */ 64668 64669 /** 64670 * @method httpGet 64671 * @param {String} path 64672 * @param {function} callback 64673 * @param {function} [errorCallback] 64674 * @return {Promise} 64675 */ 64676 64677 64678 p5.prototype.httpGet = function () { 64679 p5._validateParameters('httpGet', arguments); 64680 64681 var args = Array.prototype.slice.call(arguments); 64682 args.splice(1, 0, 'GET'); 64683 return p5.prototype.httpDo.apply(this, args); 64684 }; 64685 /** 64686 * Method for executing an HTTP POST request. If data type is not specified, 64687 * p5 will try to guess based on the URL, defaulting to text. This is equivalent to 64688 * calling <code>httpDo(path, 'POST')</code>. 64689 * 64690 * @method httpPost 64691 * @param {String} path name of the file or url to load 64692 * @param {String} [datatype] "json", "jsonp", "xml", or "text". 64693 * If omitted, <a href="#/p5/httpPost">httpPost()</a> will guess. 64694 * @param {Object|Boolean} [data] param data passed sent with request 64695 * @param {function} [callback] function to be executed after 64696 * <a href="#/p5/httpPost">httpPost()</a> completes, data is passed in 64697 * as first argument 64698 * @param {function} [errorCallback] function to be executed if 64699 * there is an error, response is passed 64700 * in as first argument 64701 * @return {Promise} A promise that resolves with the data when the operation 64702 * completes successfully or rejects with the error after 64703 * one occurs. 64704 * 64705 * @example 64706 * <div> 64707 * <code> 64708 * // Examples use jsonplaceholder.typicode.com for a Mock Data API 64709 * 64710 * let url = 'https://jsonplaceholder.typicode.com/posts'; 64711 * let postData = { userId: 1, title: 'p5 Clicked!', body: 'p5.js is way cool.' }; 64712 * 64713 * function setup() { 64714 * createCanvas(800, 800); 64715 * } 64716 * 64717 * function mousePressed() { 64718 * // Pick new random color values 64719 * let r = random(255); 64720 * let g = random(255); 64721 * let b = random(255); 64722 * 64723 * httpPost(url, 'json', postData, function(result) { 64724 * strokeWeight(2); 64725 * stroke(r, g, b); 64726 * fill(r, g, b, 127); 64727 * ellipse(mouseX, mouseY, 200, 200); 64728 * text(result.body, mouseX, mouseY); 64729 * }); 64730 * } 64731 * </code> 64732 * </div> 64733 * 64734 * 64735 * <div><code> 64736 * let url = 'https://invalidURL'; // A bad URL that will cause errors 64737 * let postData = { title: 'p5 Clicked!', body: 'p5.js is way cool.' }; 64738 * 64739 * function setup() { 64740 * createCanvas(800, 800); 64741 * } 64742 * 64743 * function mousePressed() { 64744 * // Pick new random color values 64745 * let r = random(255); 64746 * let g = random(255); 64747 * let b = random(255); 64748 * 64749 * httpPost( 64750 * url, 64751 * 'json', 64752 * postData, 64753 * function(result) { 64754 * // ... won't be called 64755 * }, 64756 * function(error) { 64757 * strokeWeight(2); 64758 * stroke(r, g, b); 64759 * fill(r, g, b, 127); 64760 * text(error.toString(), mouseX, mouseY); 64761 * } 64762 * ); 64763 * } 64764 * </code></div> 64765 * 64766 */ 64767 64768 /** 64769 * @method httpPost 64770 * @param {String} path 64771 * @param {Object|Boolean} data 64772 * @param {function} [callback] 64773 * @param {function} [errorCallback] 64774 * @return {Promise} 64775 */ 64776 64777 /** 64778 * @method httpPost 64779 * @param {String} path 64780 * @param {function} callback 64781 * @param {function} [errorCallback] 64782 * @return {Promise} 64783 */ 64784 64785 64786 p5.prototype.httpPost = function () { 64787 p5._validateParameters('httpPost', arguments); 64788 64789 var args = Array.prototype.slice.call(arguments); 64790 args.splice(1, 0, 'POST'); 64791 return p5.prototype.httpDo.apply(this, args); 64792 }; 64793 /** 64794 * Method for executing an HTTP request. If data type is not specified, 64795 * p5 will try to guess based on the URL, defaulting to text.<br><br> 64796 * For more advanced use, you may also pass in the path as the first argument 64797 * and a object as the second argument, the signature follows the one specified 64798 * in the Fetch API specification. 64799 * This method is suitable for fetching files up to size of 64MB when "GET" is used. 64800 * 64801 * @method httpDo 64802 * @param {String} path name of the file or url to load 64803 * @param {String} [method] either "GET", "POST", or "PUT", 64804 * defaults to "GET" 64805 * @param {String} [datatype] "json", "jsonp", "xml", or "text" 64806 * @param {Object} [data] param data passed sent with request 64807 * @param {function} [callback] function to be executed after 64808 * <a href="#/p5/httpGet">httpGet()</a> completes, data is passed in 64809 * as first argument 64810 * @param {function} [errorCallback] function to be executed if 64811 * there is an error, response is passed 64812 * in as first argument 64813 * @return {Promise} A promise that resolves with the data when the operation 64814 * completes successfully or rejects with the error after 64815 * one occurs. 64816 * 64817 * @example 64818 * <div> 64819 * <code> 64820 * // Examples use USGS Earthquake API: 64821 * // https://earthquake.usgs.gov/fdsnws/event/1/#methods 64822 * 64823 * // displays an animation of all USGS earthquakes 64824 * let earthquakes; 64825 * let eqFeatureIndex = 0; 64826 * 64827 * function preload() { 64828 * let url = 'https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson'; 64829 * httpDo( 64830 * url, 64831 * { 64832 * method: 'GET', 64833 * // Other Request options, like special headers for apis 64834 * headers: { authorization: 'Bearer secretKey' } 64835 * }, 64836 * function(res) { 64837 * earthquakes = res; 64838 * } 64839 * ); 64840 * } 64841 * 64842 * function draw() { 64843 * // wait until the data is loaded 64844 * if (!earthquakes || !earthquakes.features[eqFeatureIndex]) { 64845 * return; 64846 * } 64847 * clear(); 64848 * 64849 * let feature = earthquakes.features[eqFeatureIndex]; 64850 * let mag = feature.properties.mag; 64851 * let rad = mag / 11 * ((width + height) / 2); 64852 * fill(255, 0, 0, 100); 64853 * ellipse(width / 2 + random(-2, 2), height / 2 + random(-2, 2), rad, rad); 64854 * 64855 * if (eqFeatureIndex >= earthquakes.features.length) { 64856 * eqFeatureIndex = 0; 64857 * } else { 64858 * eqFeatureIndex += 1; 64859 * } 64860 * } 64861 * </code> 64862 * </div> 64863 */ 64864 64865 /** 64866 * @method httpDo 64867 * @param {String} path 64868 * @param {Object} options Request object options as documented in the 64869 * "fetch" API 64870 * <a href="https://developer.mozilla.org/en/docs/Web/API/Fetch_API">reference</a> 64871 * @param {function} [callback] 64872 * @param {function} [errorCallback] 64873 * @return {Promise} 64874 */ 64875 64876 64877 p5.prototype.httpDo = function () { 64878 var type; 64879 var callback; 64880 var errorCallback; 64881 var request; 64882 var promise; 64883 var jsonpOptions = {}; 64884 var cbCount = 0; 64885 var contentType = 'text/plain'; // Trim the callbacks off the end to get an idea of how many arguments are passed 64886 64887 for (var i = arguments.length - 1; i > 0; i--) { 64888 if (typeof arguments[i] === 'function') { 64889 cbCount++; 64890 } else { 64891 break; 64892 } 64893 } // The number of arguments minus callbacks 64894 64895 64896 var argsCount = arguments.length - cbCount; 64897 var path = arguments[0]; 64898 64899 if (argsCount === 2 && typeof path === 'string' && typeof arguments[1] === 'object') { 64900 // Intended for more advanced use, pass in Request parameters directly
64901 request = new Request(path, arguments[1]); 64902 callback = arguments[2]; 64903 errorCallback = arguments[3]; 64904 } else { 64905 // Provided with arguments 64906 var method = 'GET'; 64907 var data; 64908 64909 for (var j = 1; j < arguments.length; j++) { 64910 var a = arguments[j]; 64911 64912 if (typeof a === 'string') { 64913 if (a === 'GET' || a === 'POST' || a === 'PUT' || a === 'DELETE') { 64914 method = a; 64915 } else if (a === 'json' || a === 'jsonp' || a === 'binary' || a === 'arrayBuffer' || a === 'xml' || a === 'text' || a === 'table') { 64916 type = a; 64917 } else { 64918 data = a; 64919 } 64920 } else if (typeof a === 'number') { 64921 data = a.toString(); 64922 } else if (typeof a === 'object') { 64923 if (a.hasOwnProperty('jsonpCallback')) { 64924 for (var attr in a) { 64925 jsonpOptions[attr] = a[attr]; 64926 } 64927 } else if (a instanceof p5.XML) { 64928 data = a.serialize(); 64929 contentType = 'application/xml'; 64930 } else { 64931 data = JSON.stringify(a); 64932 contentType = 'application/json'; 64933 } 64934 } else if (typeof a === 'function') { 64935 if (!callback) { 64936 callback = a; 64937 } else { 64938 errorCallback = a; 64939 } 64940 } 64941 } 64942 64943 request = new Request(path, { 64944 method: method, 64945 mode: 'cors', 64946 body: data, 64947 headers: new Headers({ 64948 'Content-Type': contentType 64949 }) 64950 }); 64951 } // do some sort of smart type checking 64952 64953 64954 if (!type) { 64955 if (path.indexOf('json') !== -1) { 64956 type = 'json'; 64957 } else if (path.indexOf('xml') !== -1) { 64958 type = 'xml'; 64959 } else { 64960 type = 'text'; 64961 } 64962 } 64963 64964 if (type === 'jsonp') { 64965 promise = fetchJsonp(path, jsonpOptions); 64966 } else { 64967 promise = fetch(request); 64968 } 64969 64970 promise = promise.then(function (res) { 64971 if (!res.ok) { 64972 var err = new Error(res.body); 64973 err.status = res.status; 64974 err.ok = false; 64975 throw err; 64976 } else { 64977 var fileSize = res.headers.get('content-length'); 64978 64979 if (fileSize && fileSize > 64000000) { 64980 p5._friendlyFileLoadError(7, path); 64981 } 64982 64983 switch (type) { 64984 case 'json': 64985 case 'jsonp': 64986 return res.json(); 64987 64988 case 'binary': 64989 return res.blob(); 64990 64991 case 'arrayBuffer': 64992 return res.arrayBuffer(); 64993 64994 case 'xml': 64995 return res.text().then(function (text) { 64996 var parser = new DOMParser(); 64997 var xml = parser.parseFromString(text, 'text/xml'); 64998 return new p5.XML(xml.documentElement); 64999 }); 65000 65001 default: 65002 return res.text(); 65003 } 65004 } 65005 }); 65006 promise.then(callback || function () {}); 65007 promise.catch(errorCallback || console.error); 65008 return promise; 65009 }; 65010 /** 65011 * @module IO 65012 * @submodule Output 65013 * @for p5 65014 */ 65015 65016 65017 window.URL = window.URL || window.webkitURL; // private array of p5.PrintWriter objects 65018 65019 p5.prototype._pWriters = []; 65020 /** 65021 * @method createWriter 65022 * @param {String} name name of the file to be created 65023 * @param {String} [extension] 65024 * @return {p5.PrintWriter} 65025 * @example 65026 * <div> 65027 * <code> 65028 * function setup() { 65029 * createCanvas(100, 100); 65030 * background(200); 65031 * text('click here to save', 10, 10, 70, 80); 65032 * } 65033 * 65034 * function mousePressed() { 65035 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 65036 * var writer = createWriter('squares.txt'); 65037 * for (let i = 0; i < 10; i++) { 65038 * writer.print(i * i); 65039 * } 65040 * writer.close(); 65041 * writer.clear(); 65042 * } 65043 * } 65044 * </code> 65045 * </div> 65046 */ 65047 65048 p5.prototype.createWriter = function (name, extension) { 65049 var newPW; // check that it doesn't already exist 65050 65051 for (var i in p5.prototype._pWriters) { 65052 if (p5.prototype._pWriters[i].name === name) { 65053 // if a p5.PrintWriter w/ this name already exists... 65054 // return p5.prototype._pWriters[i]; // return it w/ contents intact. 65055 // or, could return a new, empty one with a unique name: 65056 newPW = new p5.PrintWriter(name + this.millis(), extension); 65057 65058 p5.prototype._pWriters.push(newPW); 65059 65060 return newPW; 65061 } 65062 } 65063 65064 newPW = new p5.PrintWriter(name, extension); 65065 65066 p5.prototype._pWriters.push(newPW); 65067 65068 return newPW; 65069 }; 65070 /** 65071 * @class p5.PrintWriter 65072 * @param {String} filename 65073 * @param {String} [extension] 65074 */ 65075 65076 65077 p5.PrintWriter = function (filename, extension) { 65078 var self = this; 65079 this.name = filename; 65080 this.content = ''; //Changed to write because it was being overloaded by function below. 65081 65082 /** 65083 * Writes data to the PrintWriter stream 65084 * @method write 65085 * @param {Array} data all data to be written by the PrintWriter 65086 * @example 65087 * <div class="norender notest"> 65088 * <code> 65089 * // creates a file called 'newFile.txt' 65090 * let writer = createWriter('newFile.txt'); 65091 * // write 'Hello world!'' to the file 65092 * writer.write(['Hello world!']); 65093 * // close the PrintWriter and save the file 65094 * writer.close(); 65095 * </code> 65096 * </div> 65097 * <div class='norender notest'> 65098 * <code> 65099 * // creates a file called 'newFile2.txt' 65100 * let writer = createWriter('newFile2.txt'); 65101 * // write 'apples,bananas,123' to the file 65102 * writer.write(['apples', 'bananas', 123]); 65103 * // close the PrintWriter and save the file 65104 * writer.close(); 65105 * </code> 65106 * </div> 65107 * <div class='norender notest'> 65108 * <code> 65109 * // creates a file called 'newFile3.txt' 65110 * let writer = createWriter('newFile3.txt'); 65111 * // write 'My name is: Teddy' to the file 65112 * writer.write('My name is:'); 65113 * writer.write(' Teddy'); 65114 * // close the PrintWriter and save the file 65115 * writer.close(); 65116 * </code> 65117 * </div> 65118 */ 65119 65120 this.write = function (data) { 65121 this.content += data; 65122 }; 65123 /** 65124 * Writes data to the PrintWriter stream, and adds a new line at the end 65125 * @method print 65126 * @param {Array} data all data to be printed by the PrintWriter 65127 * @example 65128 * <div class='norender notest'> 65129 * <code> 65130 * // creates a file called 'newFile.txt' 65131 * let writer = createWriter('newFile.txt'); 65132 * // creates a file containing 65133 * // My name is: 65134 * // Teddy 65135 * writer.print('My name is:'); 65136 * writer.print('Teddy'); 65137 * // close the PrintWriter and save the file 65138 * writer.close(); 65139 * </code> 65140 * </div> 65141 * <div class='norender notest'> 65142 * <code> 65143 * let writer; 65144 * 65145 * function setup() { 65146 * createCanvas(400, 400); 65147 * // create a PrintWriter 65148 * writer = createWriter('newFile.txt'); 65149 * } 65150 * 65151 * function draw() { 65152 * // print all mouseX and mouseY coordinates to the stream 65153 * writer.print([mouseX, mouseY]); 65154 * } 65155 * 65156 * function mouseClicked() { 65157 * // close the PrintWriter and save the file 65158 * writer.close(); 65159 * } 65160 * </code> 65161 * </div> 65162 */ 65163 65164 65165 this.print = function (data) { 65166 this.content += data + '\n'; 65167 }; 65168 /** 65169 * Clears the data already written to the PrintWriter object 65170 * @method clear 65171 * @example 65172 * <div class ="norender notest"><code> 65173 * // create writer object 65174 * let writer = createWriter('newFile.txt'); 65175 * writer.write(['clear me']); 65176 * // clear writer object here 65177 * writer.clear(); 65178 * // close writer 65179 * writer.close(); 65180 * </code></div> 65181 * 65182 */ 65183 65184 65185 this.clear = function () { 65186 this.content = ''; 65187 }; 65188 /** 65189 * Closes the PrintWriter 65190 * @method close 65191 * @example 65192 * <div class="norender notest"> 65193 * <code> 65194 * // create a file called 'newFile.txt' 65195 * let writer = createWriter('newFile.txt'); 65196 * // close the PrintWriter and save the file 65197 * writer.close(); 65198 * </code> 65199 * </div> 65200 * <div class='norender notest'> 65201 * <code> 65202 * // create a file called 'newFile2.txt' 65203 * let writer = createWriter('newFile2.txt'); 65204 * // write some data to the file 65205 * writer.write([100, 101, 102]); 65206 * // close the PrintWriter and save the file 65207 * writer.close(); 65208 * </code> 65209 * </div> 65210 */ 65211 65212 65213 this.close = function () { 65214 // convert String to Array for the writeFile Blob 65215 var arr = []; 65216 arr.push(this.content); 65217 p5.prototype.writeFile(arr, filename, extension); // remove from _pWriters array and delete self 65218 65219 for (var i in p5.prototype._pWriters) { 65220 if (p5.prototype._pWriters[i].name === this.name) { 65221 // remove from _pWriters array 65222 p5.prototype._pWriters.splice(i, 1); 65223 } 65224 } 65225 65226 self.clear(); 65227 self = {}; 65228 }; 65229 }; 65230 /** 65231 * @module IO 65232 * @submodule Output 65233 * @for p5 65234 */ 65235 // object, filename, options --> saveJSON, saveStrings, 65236 // filename, [extension] [canvas] --> saveImage 65237 65238 /** 65239 * <p>Save an image, text, json, csv, wav, or html. Prompts download to 65240 * the client's computer. <b>Note that it is not recommended to call <a href="#/p5/save">save()</a> 65241 * within draw if it's looping, as the <a href="#/p5/save">save()</a> function will open a new save 65242 * dialog every frame.</b></p> 65243 * <p>The default behavior is to save the canvas as an image. You can 65244 * optionally specify a filename. 65245 * For example:</p> 65246 * <pre class='language-javascript'><code> 65247 * save(); 65248 * save('myCanvas.jpg'); // save a specific canvas with a filename 65249 * </code></pre> 65250 * 65251 * <p>Alternately, the first parameter can be a pointer to a canvas 65252 * <a href="#/p5.Element">p5.Element</a>, an Array of Strings, 65253 * an Array of JSON, a JSON object, a <a href="#/p5.Table">p5.Table</a>, a <a href="#/p5.Image">p5.Image</a>, or a 65254 * p5.SoundFile (requires p5.sound). The second parameter is a filename 65255 * (including extension). The third parameter is for options specific 65256 * to this type of object. This method will save a file that fits the 65257 * given parameters. For example:</p> 65258 * 65259 * <pre class='language-javascript'><code> 65260 * // Saves canvas as an image 65261 * save('myCanvas.jpg'); 65262 * 65263 * // Saves pImage as a png image 65264 * let img = createImage(10, 10); 65265 * save(img, 'my.png'); 65266 * 65267 * // Saves canvas as an image 65268 * let cnv = createCanvas(100, 100); 65269 * save(cnv, 'myCanvas.jpg'); 65270 * 65271 * // Saves p5.Renderer object as an image 65272 * let gb = createGraphics(100, 100); 65273 * save(gb, 'myGraphics.jpg'); 65274 * 65275 * let myTable = new p5.Table(); 65276 * 65277 * // Saves table as html file 65278 * save(myTable, 'myTable.html'); 65279 * 65280 * // Comma Separated Values 65281 * save(myTable, 'myTable.csv'); 65282 * 65283 * // Tab Separated Values 65284 * save(myTable, 'myTable.tsv'); 65285 * 65286 * let myJSON = { a: 1, b: true }; 65287 * 65288 * // Saves pretty JSON 65289 * save(myJSON, 'my.json'); 65290 * 65291 * // Optimizes JSON filesize 65292 * save(myJSON, 'my.json', true); 65293 *
65294 * // Saves array of strings to a text file with line breaks after each item 65295 * let arrayOfStrings = ['a', 'b']; 65296 * save(arrayOfStrings, 'my.txt'); 65297 * </code></pre> 65298 * 65299 * @method save 65300 * @param {Object|String} [objectOrFilename] If filename is provided, will 65301 * save canvas as an image with 65302 * either png or jpg extension 65303 * depending on the filename. 65304 * If object is provided, will 65305 * save depending on the object 65306 * and filename (see examples 65307 * above). 65308 * @param {String} [filename] If an object is provided as the first 65309 * parameter, then the second parameter 65310 * indicates the filename, 65311 * and should include an appropriate 65312 * file extension (see examples above). 65313 * @param {Boolean|String} [options] Additional options depend on 65314 * filetype. For example, when saving JSON, 65315 * <code>true</code> indicates that the 65316 * output will be optimized for filesize, 65317 * rather than readability. 65318 */ 65319 65320 65321 p5.prototype.save = function (object, _filename, _options) { 65322 // parse the arguments and figure out which things we are saving 65323 var args = arguments; // ================================================= 65324 // OPTION 1: saveCanvas... 65325 // if no arguments are provided, save canvas 65326 65327 var cnv = this._curElement ? this._curElement.elt : this.elt; 65328 65329 if (args.length === 0) { 65330 p5.prototype.saveCanvas(cnv); 65331 return; 65332 } else if (args[0] instanceof p5.Renderer || args[0] instanceof p5.Graphics) { 65333 // otherwise, parse the arguments 65334 // if first param is a p5Graphics, then saveCanvas 65335 p5.prototype.saveCanvas(args[0].elt, args[1], args[2]); 65336 return; 65337 } else if (args.length === 1 && typeof args[0] === 'string') { 65338 // if 1st param is String and only one arg, assume it is canvas filename 65339 p5.prototype.saveCanvas(cnv, args[0]); 65340 } else { 65341 // ================================================= 65342 // OPTION 2: extension clarifies saveStrings vs. saveJSON 65343 var extension = _checkFileExtension(args[1], args[2])[1]; 65344 65345 switch (extension) { 65346 case 'json': 65347 p5.prototype.saveJSON(args[0], args[1], args[2]); 65348 return; 65349 65350 case 'txt': 65351 p5.prototype.saveStrings(args[0], args[1], args[2]); 65352 return; 65353 // ================================================= 65354 // OPTION 3: decide based on object... 65355 65356 default: 65357 if (args[0] instanceof Array) { 65358 p5.prototype.saveStrings(args[0], args[1], args[2]); 65359 } else if (args[0] instanceof p5.Table) { 65360 p5.prototype.saveTable(args[0], args[1], args[2]); 65361 } else if (args[0] instanceof p5.Image) { 65362 p5.prototype.saveCanvas(args[0].canvas, args[1]); 65363 } else if (args[0] instanceof p5.SoundFile) { 65364 p5.prototype.saveSound(args[0], args[1], args[2], args[3]); 65365 } 65366 65367 } 65368 } 65369 }; 65370 /** 65371 * Writes the contents of an Array or a JSON object to a .json file. 65372 * The file saving process and location of the saved file will 65373 * vary between web browsers. 65374 * 65375 * @method saveJSON 65376 * @param {Array|Object} json 65377 * @param {String} filename 65378 * @param {Boolean} [optimize] If true, removes line breaks 65379 * and spaces from the output 65380 * file to optimize filesize 65381 * (but not readability). 65382 * @example 65383 * <div><code> 65384 * let json = {}; // new JSON Object 65385 * 65386 * json.id = 0; 65387 * json.species = 'Panthera leo'; 65388 * json.name = 'Lion'; 65389 * 65390 * function setup() { 65391 * createCanvas(100, 100); 65392 * background(200); 65393 * text('click here to save', 10, 10, 70, 80); 65394 * } 65395 * 65396 * function mousePressed() { 65397 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 65398 * saveJSON(json, 'lion.json'); 65399 * } 65400 * } 65401 * 65402 * // saves the following to a file called "lion.json": 65403 * // { 65404 * // "id": 0, 65405 * // "species": "Panthera leo", 65406 * // "name": "Lion" 65407 * // } 65408 * </code></div> 65409 * 65410 * @alt 65411 * no image displayed 65412 * 65413 */ 65414 65415 65416 p5.prototype.saveJSON = function (json, filename, opt) { 65417 p5._validateParameters('saveJSON', arguments); 65418 65419 var stringify; 65420 65421 if (opt) {
65422 stringify = JSON.stringify(json); 65423 } else { 65424 stringify = JSON.stringify(json, undefined, 2); 65425 } 65426 65427 this.saveStrings(stringify.split('\n'), filename, 'json'); 65428 }; 65429 65430 p5.prototype.saveJSONObject = p5.prototype.saveJSON; 65431 p5.prototype.saveJSONArray = p5.prototype.saveJSON; 65432 /** 65433 * Writes an array of Strings to a text file, one line per String. 65434 * The file saving process and location of the saved file will 65435 * vary between web browsers. 65436 * 65437 * @method saveStrings 65438 * @param {String[]} list string array to be written 65439 * @param {String} filename filename for output 65440 * @param {String} [extension] the filename's extension 65441 * @example 65442 * <div><code> 65443 * let words = 'apple bear cat dog'; 65444 * 65445 * // .split() outputs an Array 65446 * let list = split(words, ' '); 65447 * 65448 * function setup() { 65449 * createCanvas(100, 100); 65450 * background(200); 65451 * text('click here to save', 10, 10, 70, 80); 65452 * } 65453 * 65454 * function mousePressed() { 65455 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 65456 * saveStrings(list, 'nouns.txt'); 65457 * } 65458 * } 65459 * 65460 * // Saves the following to a file called 'nouns.txt': 65461 * // 65462 * // apple 65463 * // bear 65464 * // cat 65465 * // dog 65466 * </code></div> 65467 * 65468 * @alt 65469 * no image displayed 65470 * 65471 */ 65472 65473 p5.prototype.saveStrings = function (list, filename, extension) { 65474 p5._validateParameters('saveStrings', arguments); 65475 65476 var ext = extension || 'txt'; 65477 var pWriter = this.createWriter(filename, ext); 65478 65479 for (var i = 0; i < list.length; i++) { 65480 if (i < list.length - 1) { 65481 pWriter.print(list[i]); 65482 } else { 65483 pWriter.print(list[i]); 65484 } 65485 } 65486 65487 pWriter.close(); 65488 pWriter.clear(); 65489 }; // ======= 65490 // HELPERS 65491 // ======= 65492 65493 65494 function escapeHelper(content) { 65495 return content.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, '''); 65496 } 65497 /** 65498 * Writes the contents of a <a href="#/p5.Table">Table</a> object to a file. Defaults to a 65499 * text file with comma-separated-values ('csv') but can also 65500 * use tab separation ('tsv'), or generate an HTML table ('html'). 65501 * The file saving process and location of the saved file will 65502 * vary between web browsers. 65503 * 65504 * @method saveTable 65505 * @param {p5.Table} Table the <a href="#/p5.Table">Table</a> object to save to a file 65506 * @param {String} filename the filename to which the Table should be saved 65507 * @param {String} [options] can be one of "tsv", "csv", or "html" 65508 * @example 65509 * <div><code> 65510 * let table; 65511 * 65512 * function setup() { 65513 * table = new p5.Table(); 65514 * 65515 * table.addColumn('id'); 65516 * table.addColumn('species'); 65517 * table.addColumn('name'); 65518 * 65519 * let newRow = table.addRow(); 65520 * newRow.setNum('id', table.getRowCount() - 1); 65521 * newRow.setString('species', 'Panthera leo'); 65522 * newRow.setString('name', 'Lion'); 65523 * 65524 * // To save, un-comment next line then click 'run' 65525 * // saveTable(table, 'new.csv'); 65526 * } 65527 * 65528 * // Saves the following to a file called 'new.csv': 65529 * // id,species,name 65530 * // 0,Panthera leo,Lion 65531 * </code></div> 65532 * 65533 * @alt 65534 * no image displayed 65535 * 65536 */ 65537 65538 65539 p5.prototype.saveTable = function (table, filename, options) { 65540 p5._validateParameters('saveTable', arguments); 65541 65542 var ext; 65543 65544 if (options === undefined) { 65545 ext = filename.substring(filename.lastIndexOf('.') + 1, filename.length); 65546 } else { 65547 ext = options; 65548 } 65549 65550 var pWriter = this.createWriter(filename, ext); 65551 var header = table.columns; 65552 var sep = ','; // default to CSV 65553 65554 if (ext === 'tsv') { 65555 sep = '\t'; 65556 } 65557 65558 if (ext !== 'html') { 65559 // make header if it has values 65560 if (header[0] !== '0') { 65561 for (var h = 0; h < header.length; h++) { 65562 if (h < header.length - 1) { 65563 pWriter.write(header[h] + sep); 65564 } else { 65565 pWriter.write(header[h]); 65566 } 65567 } 65568 65569 pWriter.write('\n'); 65570 } // make rows 65571 65572 65573 for (var i = 0; i < table.rows.length; i++) { 65574 var j; 65575 65576 for (j = 0; j < table.rows[i].arr.length; j++) { 65577 if (j < table.rows[i].arr.length - 1) { 65578 pWriter.write(table.rows[i].arr[j] + sep); 65579 } else if (i < table.rows.length - 1) { 65580 pWriter.write(table.rows[i].arr[j]); 65581 } else { 65582 pWriter.write(table.rows[i].arr[j]); 65583 } 65584 } 65585 65586 pWriter.write('\n'); 65587 } 65588 } else { 65589 // otherwise, make HTML 65590 pWriter.print('<html>'); 65591 pWriter.print('<head>'); 65592 var str = ' <meta http-equiv="content-type" content'; 65593 str += '="text/html;charset=utf-8" />'; 65594 pWriter.print(str);
65595 pWriter.print('</head>'); 65596 pWriter.print('<body>'); 65597 pWriter.print(' <table>'); // make header if it has values 65598 65599 if (header[0] !== '0') { 65600 pWriter.print(' <tr>'); 65601 65602 for (var k = 0; k < header.length; k++) { 65603 var e = escapeHelper(header[k]); 65604 pWriter.print(' <td>' + e); 65605 pWriter.print(' </td>'); 65606 } 65607 65608 pWriter.print(' </tr>'); 65609 } // make rows 65610 65611 65612 for (var row = 0; row < table.rows.length; row++) { 65613 pWriter.print(' <tr>'); 65614 65615 for (var col = 0; col < table.columns.length; col++) { 65616 var entry = table.rows[row].getString(col); 65617 var htmlEntry = escapeHelper(entry); 65618 pWriter.print(' <td>' + htmlEntry); 65619 pWriter.print(' </td>'); 65620 } 65621 65622 pWriter.print(' </tr>'); 65623 } 65624 65625 pWriter.print(' </table>'); 65626 pWriter.print('</body>'); 65627 pWriter.print('</html>'); 65628 } // close and clear the pWriter 65629 65630 65631 pWriter.close(); 65632 pWriter.clear(); 65633 }; // end saveTable() 65634 65635 /** 65636 * Generate a blob of file data as a url to prepare for download. 65637 * Accepts an array of data, a filename, and an extension (optional). 65638 * This is a private function because it does not do any formatting, 65639 * but it is used by <a href="#/p5/saveStrings">
65639saveStrings</a>, <a href="#/p5/saveJSON">saveJSON</a>, <a href="#/p5/saveTable">saveTable</a> etc. 65640 * 65641 * @param {Array} dataToDownload 65642 * @param {String} filename 65643 * @param {String} [extension] 65644 * @private 65645 */ 65646 65647 65648 p5.prototype.writeFile = function (dataToDownload, filename, extension) { 65649 var type = 'application/octet-stream'; 65650 65651 if (p5.prototype._isSafari()) { 65652 type = 'text/plain'; 65653 } 65654 65655 var blob = new Blob(dataToDownload, { 65656 type: type 65657 }); 65658 p5.prototype.downloadFile(blob, filename, extension); 65659 }; 65660 /** 65661 * Forces download. Accepts a url to filedata/blob, a filename, 65662 * and an extension (optional). 65663 * This is a private function because it does not do any formatting, 65664 * but it is used by <a href="#/p5/saveStrings">saveStrings</a>, <a href="#/p5/saveJSON">saveJSON</a>, <a href="#/p5/saveTable">saveTable</a> etc. 65665 * 65666 * @method downloadFile 65667 * @private 65668 * @param {String|Blob} data either an href generated by createObjectURL, 65669 * or a Blob object containing the data 65670 * @param {String} [filename] 65671 * @param {String} [extension] 65672 */ 65673 65674 65675 p5.prototype.downloadFile = function (data, fName, extension) { 65676 var fx = _checkFileExtension(fName, extension); 65677 65678 var filename = fx[0]; 65679 65680 if (data instanceof Blob) { 65681 var fileSaver = _dereq_('file-saver'); 65682 65683 fileSaver.saveAs(data, filename); 65684 return; 65685 } 65686 65687 var a = document.createElement('a'); 65688 a.href = data; 65689 a.download = filename; // Firefox requires the link to be added to the DOM before click() 65690 65691 a.onclick = function (e) { 65692 destroyClickedElement(e); 65693 e.stopPropagation(); 65694 }; 65695 65696 a.style.display = 'none'; 65697 document.body.appendChild(a); // Safari will open this file in the same page as a confusing Blob. 65698 65699 if (p5.prototype._isSafari()) { 65700 var aText = 'Hello, Safari user! To download this file...\n'; 65701 aText += '1. Go to File --> Save As.\n'; 65702 aText += '2. Choose "Page Source" as the Format.\n'; 65703 aText += '3. Name it with this extension: ."' + fx[1] + '"'; 65704 alert(aText); 65705 } 65706 65707 a.click(); 65708 }; 65709 /** 65710 * Returns a file extension, or another string 65711 * if the provided parameter has no extension. 65712 * 65713 * @param {String} filename 65714 * @param {String} [extension] 65715 * @return {String[]} [fileName, fileExtension] 65716 * 65717 * @private 65718 */ 65719 65720 65721 function _checkFileExtension(filename, extension) { 65722 if (!extension || extension === true || extension === 'true') { 65723 extension = ''; 65724 } 65725 65726 if (!filename) { 65727 filename = 'untitled'; 65728 } 65729 65730 var ext = ''; // make sure the file will have a name, see if filename needs extension 65731 65732 if (filename && filename.indexOf('.') > -1) { 65733 ext = filename.split('.').pop(); 65734 } // append extension if it doesn't exist 65735 65736 65737 if (extension) { 65738 if (ext !== extension) { 65739 ext = extension; 65740 filename = filename + '.' + ext; 65741 } 65742 } 65743 65744 return [filename, ext]; 65745 } 65746 65747 p5.prototype._checkFileExtension = _checkFileExtension; 65748 /** 65749 * Returns true if the browser is Safari, false if not. 65750 * Safari makes trouble for downloading files. 65751 * 65752 * @return {Boolean} [description] 65753 * @private 65754 */ 65755 65756 p5.prototype._isSafari = function () { 65757 var x = Object.prototype.toString.call(window.HTMLElement); 65758 return x.indexOf('Constructor') > 0; 65759 }; 65760 /** 65761 * Helper function, a callback for download that deletes 65762 * an invisible anchor element from the DOM once the file 65763 * has been automatically downloaded. 65764 * 65765 * @private 65766 */ 65767 65768 65769 function destroyClickedElement(event) { 65770 document.body.removeChild(event.target); 65771 } 65772 65773 module.exports = p5; 65774 }, {
65775 "../core/error_helpers": 20, 65776 "../core/main": 24, 65777 "es6-promise": 5, 65778 "fetch-jsonp": 6, 65779 "file-saver": 7, 65780 "whatwg-fetch": 12 65781 }], 65782 48: [function (_dereq_, module, exports) { 65783 /** 65784 * @module IO 65785 * @submodule Table 65786 * @requires core 65787 */ 65788 'use strict'; 65789 65790 var p5 = _dereq_('../core/main'); 65791 /** 65792 * Table Options 65793 * <p>Generic class for handling tabular data, typically from a 65794 * CSV, TSV, or other sort of spreadsheet file.</p> 65795 * <p>CSV files are 65796 * <a href="http://en.wikipedia.org/wiki/Comma-separated_values"> 65797 * comma separated values</a>, often with the data in quotes. TSV 65798 * files use tabs as separators, and usually don't bother with the 65799 * quotes.</p> 65800 * <p>File names should end with .csv if they're comma separated.</p> 65801 * <p>A rough "spec" for CSV can be found 65802 * <a href="http://tools.ietf.org/html/rfc4180">here</a>.</p> 65803 * <p>To load files, use the <a href="#/p5/loadTable">loadTable</a> method.</p> 65804 * <p>To save tables to your computer, use the <a href="#/p5/save">save</a> method 65805 * or the <a href="#/p5/saveTable">saveTable</a> method.</p> 65806 * 65807 * Possible options include: 65808 * <ul> 65809 * <li>csv - parse the table as comma-separated values 65810 * <li>tsv - parse the table as tab-separated values 65811 * <li>header - this table has a header (title) row 65812 * </ul> 65813 */ 65814 65815 /** 65816 * <a href="#/p5.Table">Table</a> objects store data with multiple rows and columns, much 65817 * like in a traditional spreadsheet. Tables can be generated from 65818 * scratch, dynamically, or using data from an existing file. 65819 * 65820 * @class p5.Table 65821 * @constructor 65822 * @param {p5.TableRow[]} [rows] An array of p5.TableRow objects 65823 */ 65824 65825 65826 p5.Table = function (rows) { 65827 /** 65828 * @property columns {String[]} 65829 */ 65830 this.columns = []; 65831 /** 65832 * @property rows {p5.TableRow[]} 65833 */ 65834 65835 this.rows = []; 65836 }; 65837 /** 65838 * Use <a href="#/p5/addRow">addRow()</a> to add a new row of data to a <a href="#/p5.Table">p5.Table</a> object. By default, 65839 * an empty row is created. Typically, you would store a reference to 65840 * the new row in a TableRow object (see newRow in the example above), 65841 * and then set individual values using <a href="#/p5/set">set()</a>. 65842 * 65843 * If a <a href="#/p5.TableRow">p5.TableRow</a> object is included as a parameter, then that row is 65844 * duplicated and added to the table. 65845 * 65846 * @method addRow 65847 * @param {p5.TableRow} [row] row to be added to the table 65848 * @return {p5.TableRow} the row that was added 65849 * 65850 * @example 65851 * <div class="norender"> 65852 * <code> 65853 * // Given the CSV file "mammals.csv" 65854 * // in the project's "assets" folder: 65855 * // 65856 * // id,species,name 65857 * // 0,Capra hircus,Goat 65858 * // 1,Panthera pardus,Leopard 65859 * // 2,Equus zebra,Zebra 65860 * 65861 * let table; 65862 * 65863 * function preload() { 65864 * //my table is comma separated value "csv" 65865 * //and has a header specifying the columns labels 65866 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 65867 * } 65868 * 65869 * function setup() { 65870 * //add a row 65871 * let newRow = table.addRow(); 65872 * newRow.setString('id', table.getRowCount() - 1); 65873 * newRow.setString('species', 'Canis Lupus'); 65874 * newRow.setString('name', 'Wolf'); 65875 * 65876 * //print the results 65877 * for (let r = 0; r < table.getRowCount(); r++) 65878 * for (let c = 0; c < table.getColumnCount(); c++) 65879 * print(table.getString(r, c)); 65880 * } 65881 * </code> 65882 * </div> 65883 * 65884 * @alt 65885 * no image displayed 65886 * 65887 */ 65888 65889 65890 p5.Table.prototype.addRow = function (row) { 65891 // make sure it is a valid TableRow 65892 var r = row || new p5.TableRow(); 65893 65894 if (typeof r.arr === 'undefined' || typeof r.obj === 'undefined') { 65895 //r = new p5.prototype.TableRow(r); 65896 throw new Error('invalid TableRow: ' + r); 65897 } 65898 65899 r.table = this; 65900 this.rows.push(r); 65901 return r; 65902 }; 65903 /** 65904 * Removes a row from the table object. 65905 * 65906 * @method removeRow 65907 * @param {Integer} id ID number of the row to remove 65908 * 65909 * @example 65910 * <div class="norender"> 65911 * <code> 65912 * // Given the CSV file "mammals.csv" 65913 * // in the project's "assets" folder: 65914 * // 65915 * // id,species,name 65916 * // 0,Capra hircus,Goat 65917 * // 1,Panthera pardus,Leopard 65918 * // 2,Equus zebra,Zebra 65919 * 65920 * let table; 65921 * 65922 * function preload() { 65923 * //my table is comma separated value "csv" 65924 * //and has a header specifying the columns labels 65925 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 65926 * } 65927 * 65928 * function setup() { 65929 * //remove the first row 65930 * table.removeRow(0); 65931 * 65932 * //print the results 65933 * for (let r = 0; r < table.getRowCount(); r++) 65934 * for (let c = 0; c < table.getColumnCount(); c++) 65935 * print(table.getString(r, c)); 65936 * } 65937 * </code> 65938 * </div> 65939 * 65940 * @alt 65941 * no image displayed 65942 * 65943 */ 65944 65945 65946 p5.Table.prototype.removeRow = function (id) { 65947 this.rows[id].table = null; // remove reference to table 65948 65949 var chunk = this.rows.splice(id + 1, this.rows.length); 65950 this.rows.pop(); 65951 this.rows = this.rows.concat(chunk); 65952 }; 65953 /** 65954 * Returns a reference to the specified <a href="#/p5.TableRow">p5.TableRow</a>. The reference 65955 * can then be used to get and set values of the selected row. 65956 * 65957 * @method getRow 65958 * @param {Integer} rowID ID number of the row to get 65959 * @return {p5.TableRow} <a href="#/p5.TableRow">p5.TableRow</a> object 65960 * 65961 * @example 65962 * <div class="norender"> 65963 * <code> 65964 * // Given the CSV file "mammals.csv" 65965 * // in the project's "assets" folder: 65966 * // 65967 * // id,species,name 65968 * // 0,Capra hircus,Goat 65969 * // 1,Panthera pardus,Leopard 65970 * // 2,Equus zebra,Zebra 65971 * 65972 * let table; 65973 * 65974 * function preload() { 65975 * //my table is comma separated value "csv" 65976 * //and has a header specifying the columns labels 65977 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 65978 * } 65979 * 65980 * function setup() { 65981 * let row = table.getRow(1); 65982 * //print it column by column 65983 * //note: a row is an object, not an array 65984 * for (let c = 0; c < table.getColumnCount(); c++) { 65985 * print(row.getString(c)); 65986 * } 65987 * } 65988 * </code> 65989 * </div> 65990 * 65991 *@alt 65992 * no image displayed 65993 * 65994 */ 65995 65996 65997 p5.Table.prototype.getRow = function (r) { 65998 return this.rows[r]; 65999 }; 66000 /** 66001 * Gets all rows from the table. Returns an array of <a href="#/p5.TableRow">p5.TableRow</a>s. 66002 * 66003 * @method getRows 66004 * @return {p5.TableRow[]} Array of <a href="#/p5.TableRow">p5.TableRow</a>s 66005 * 66006 * @example 66007 * <div class="norender"> 66008 * <code> 66009 * // Given the CSV file "mammals.csv" 66010 * // in the project's "assets" folder: 66011 * // 66012 * // id,species,name 66013 * // 0,Capra hircus,Goat 66014 * // 1,Panthera pardus,Leopard 66015 * // 2,Equus zebra,Zebra 66016 * 66017 * let table; 66018 * 66019 * function preload() { 66020 * //my table is comma separated value "csv" 66021 * //and has a header specifying the columns labels 66022 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66023 * } 66024 * 66025 * function setup() { 66026 * let rows = table.getRows(); 66027 * 66028 * //warning: rows is an array of objects 66029 * for (let r = 0; r < rows.length; r++) { 66030 * rows[r].set('name', 'Unicorn'); 66031 * } 66032 * 66033 * //print the results 66034 * for (let r = 0; r < table.getRowCount(); r++) 66035 * for (let c = 0; c < table.getColumnCount(); c++) 66036 * print(table.getString(r, c)); 66037 * } 66038 * </code> 66039 * </div> 66040 * 66041 * @alt 66042 * no image displayed 66043 * 66044 */ 66045 66046 66047 p5.Table.prototype.getRows = function () { 66048 return this.rows; 66049 }; 66050 /** 66051 * Finds the first row in the Table that contains the value 66052 * provided, and returns a reference to that row. Even if 66053 * multiple rows are possible matches, only the first matching 66054 * row is returned. The column to search may be specified by 66055 * either its ID or title. 66056 * 66057 * @method findRow 66058 * @param {String} value The value to match 66059 * @param {Integer|String} column ID number or title of the 66060 * column to search 66061 * @return {p5.TableRow} 66062 * 66063 * @example 66064 * <div class="norender"> 66065 * <code> 66066 * // Given the CSV file "mammals.csv" 66067 * // in the project's "assets" folder: 66068 * // 66069 * // id,species,name 66070 * // 0,Capra hircus,Goat 66071 * // 1,Panthera pardus,Leopard 66072 * // 2,Equus zebra,Zebra 66073 * 66074 * let table; 66075 * 66076 * function preload() { 66077 * //my table is comma separated value "csv" 66078 * //and has a header specifying the columns labels 66079 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66080 * } 66081 * 66082 * function setup() { 66083 * //find the animal named zebra 66084 * let row = table.findRow('Zebra', 'name'); 66085 * //find the corresponding species 66086 * print(row.getString('species')); 66087 * } 66088 * </code> 66089 * </div> 66090 * 66091 * @alt 66092 * no image displayed 66093 * 66094 */ 66095 66096 66097 p5.Table.prototype.findRow = function (value, column) { 66098 // try the Object 66099 if (typeof column === 'string') { 66100 for (var i = 0; i < this.rows.length; i++) { 66101 if (this.rows[i].obj[column] === value) { 66102 return this.rows[i]; 66103 } 66104 } 66105 } else { 66106 // try the Array 66107 for (var j = 0; j < this.rows.length; j++) { 66108 if (this.rows[j].arr[column] === value) { 66109 return this.rows[j]; 66110 } 66111 } 66112 } // otherwise... 66113 66114 66115 return null; 66116 }; 66117 /** 66118 * Finds the rows in the Table that contain the value 66119 * provided, and returns references to those rows. Returns an 66120 * Array, so for must be used to iterate through all the rows, 66121 * as shown in the example above. The column to search may be 66122 * specified by either its ID or title. 66123 * 66124 * @method findRows 66125 * @param {String} value The value to match 66126 * @param {Integer|String} column ID number or title of the 66127 * column to search 66128 * @return {p5.TableRow[]} An Array of TableRow objects 66129 * 66130 * @example 66131 * <div class="norender"> 66132 * <code> 66133 * // Given the CSV file "mammals.csv" 66134 * // in the project's "assets" folder: 66135 * // 66136 * // id,species,name 66137 * // 0,Capra hircus,Goat 66138 * // 1,Panthera pardus,Leopard 66139 * // 2,Equus zebra,Zebra 66140 * 66141 * let table; 66142 * 66143 * function preload() { 66144 * //my table is comma separated value "csv" 66145 * //and has a header specifying the columns labels 66146 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66147 * } 66148 * 66149 * function setup() { 66150 * //add another goat 66151 * let newRow = table.addRow(); 66152 * newRow.setString('id', table.getRowCount() - 1); 66153 * newRow.setString('species', 'Scape Goat'); 66154 * newRow.setString('name', 'Goat'); 66155 * 66156 * //find the rows containing animals named Goat 66157 * let rows = table.findRows('Goat', 'name'); 66158 * print(rows.length + ' Goats found'); 66159 * } 66160 * </code> 66161 * </div> 66162 * 66163 *@alt 66164 * no image displayed 66165 * 66166 */ 66167 66168 66169 p5.Table.prototype.findRows = function (value, column) { 66170 var ret = []; 66171 66172 if (typeof column === 'string') { 66173 for (var i = 0; i < this.rows.length; i++) { 66174 if (this.rows[i].obj[column] === value) {
66175 ret.push(this.rows[i]); 66176 } 66177 } 66178 } else { 66179 // try the Array 66180 for (var j = 0; j < this.rows.length; j++) { 66181 if (this.rows[j].arr[column] === value) { 66182 ret.push(this.rows[j]); 66183 } 66184 } 66185 } 66186 66187 return ret; 66188 }; 66189 /** 66190 * Finds the first row in the Table that matches the regular 66191 * expression provided, and returns a reference to that row. 66192 * Even if multiple rows are possible matches, only the first 66193 * matching row is returned. The column to search may be 66194 * specified by either its ID or title. 66195 * 66196 * @method matchRow 66197 * @param {String|RegExp} regexp The regular expression to match 66198 * @param {String|Integer} column The column ID (number) or 66199 * title (string) 66200 * @return {p5.TableRow} TableRow object 66201 * 66202 * @example 66203 * <div class="norender"> 66204 * <code> 66205 * // Given the CSV file "mammals.csv" 66206 * // in the project's "assets" folder: 66207 * // 66208 * // id,species,name 66209 * // 0,Capra hircus,Goat 66210 * // 1,Panthera pardus,Leopard 66211 * // 2,Equus zebra,Zebra 66212 * 66213 * let table; 66214 * 66215 * function preload() { 66216 * //my table is comma separated value "csv" 66217 * //and has a header specifying the columns labels 66218 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66219 * } 66220 * 66221 * function setup() { 66222 * //Search using specified regex on a given column, return TableRow object 66223 * let mammal = table.matchRow(new RegExp('ant'), 1); 66224 * print(mammal.getString(1)); 66225 * //Output "Panthera pardus" 66226 * } 66227 * </code> 66228 * </div> 66229 * 66230 */ 66231 66232 66233 p5.Table.prototype.matchRow = function (regexp, column) { 66234 if (typeof column === 'number') { 66235 for (var j = 0; j < this.rows.length; j++) { 66236 if (this.rows[j].arr[column].match(regexp)) { 66237 return this.rows[j]; 66238 } 66239 } 66240 } else { 66241 for (var i = 0; i < this.rows.length; i++) { 66242 if (this.rows[i].obj[column].match(regexp)) { 66243 return this.rows[i]; 66244 } 66245 } 66246 } 66247 66248 return null; 66249 }; 66250 /** 66251 * Finds the rows in the Table that match the regular expression provided, 66252 * and returns references to those rows. Returns an array, so for must be 66253 * used to iterate through all the rows, as shown in the example. The 66254 * column to search may be specified by either its ID or title. 66255 * 66256 * @method matchRows 66257 * @param {String} regexp The regular expression to match 66258 * @param {String|Integer} [column] The column ID (number) or 66259 * title (string) 66260 * @return {p5.TableRow[]} An Array of TableRow objects 66261 * @example 66262 * <div class="norender"> 66263 * <code> 66264 * let table; 66265 * 66266 * function setup() { 66267 * table = new p5.Table(); 66268 * 66269 * table.addColumn('name'); 66270 * table.addColumn('type'); 66271 * 66272 * let newRow = table.addRow(); 66273 * newRow.setString('name', 'Lion'); 66274 * newRow.setString('type', 'Mammal'); 66275 * 66276 * newRow = table.addRow(); 66277 * newRow.setString('name', 'Snake'); 66278 * newRow.setString('type', 'Reptile'); 66279 * 66280 * newRow = table.addRow(); 66281 * newRow.setString('name', 'Mosquito'); 66282 * newRow.setString('type', 'Insect'); 66283 * 66284 * newRow = table.addRow(); 66285 * newRow.setString('name', 'Lizard'); 66286 * newRow.setString('type', 'Reptile'); 66287 * 66288 * let rows = table.matchRows('R.*', 'type'); 66289 * for (let i = 0; i < rows.length; i++) { 66290 * print(rows[i].getString('name') + ': ' + rows[i].getString('type')); 66291 * } 66292 * } 66293 * // Sketch prints: 66294 * // Snake: Reptile 66295 * // Lizard: Reptile 66296 * </code> 66297 * </div> 66298 */ 66299 66300 66301 p5.Table.prototype.matchRows = function (regexp, column) { 66302 var ret = []; 66303 66304 if (typeof column === 'number') { 66305 for (var j = 0; j < this.rows.length; j++) { 66306 if (this.rows[j].arr[column].match(regexp)) {
66307 ret.push(this.rows[j]); 66308 } 66309 } 66310 } else { 66311 for (var i = 0; i < this.rows.length; i++) { 66312 if (this.rows[i].obj[column].match(regexp)) { 66313 ret.push(this.rows[i]); 66314 } 66315 } 66316 } 66317 66318 return ret; 66319 }; 66320 /** 66321 * Retrieves all values in the specified column, and returns them 66322 * as an array. The column may be specified by either its ID or title. 66323 * 66324 * @method getColumn 66325 * @param {String|Number} column String or Number of the column to return 66326 * @return {Array} Array of column values 66327 * 66328 * @example 66329 * <div class="norender"> 66330 * <code> 66331 * // Given the CSV file "mammals.csv" 66332 * // in the project's "assets" folder: 66333 * // 66334 * // id,species,name 66335 * // 0,Capra hircus,Goat 66336 * // 1,Panthera pardus,Leopard 66337 * // 2,Equus zebra,Zebra 66338 * 66339 * let table; 66340 * 66341 * function preload() { 66342 * //my table is comma separated value "csv" 66343 * //and has a header specifying the columns labels 66344 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66345 * } 66346 * 66347 * function setup() { 66348 * //getColumn returns an array that can be printed directly 66349 * print(table.getColumn('species')); 66350 * //outputs ["Capra hircus", "Panthera pardus", "Equus zebra"] 66351 * } 66352 * </code> 66353 * </div> 66354 * 66355 *@alt 66356 * no image displayed 66357 * 66358 */ 66359 66360 66361 p5.Table.prototype.getColumn = function (value) { 66362 var ret = []; 66363 66364 if (typeof value === 'string') { 66365 for (var i = 0; i < this.rows.length; i++) { 66366 ret.push(this.rows[i].obj[value]); 66367 } 66368 } else { 66369 for (var j = 0; j < this.rows.length; j++) { 66370 ret.push(this.rows[j].arr[value]); 66371 } 66372 } 66373 66374 return ret; 66375 }; 66376 /** 66377 * Removes all rows from a Table. While all rows are removed, 66378 * columns and column titles are maintained. 66379 * 66380 * @method clearRows 66381 * 66382 * @example 66383 * <div class="norender"> 66384 * <code> 66385 * // Given the CSV file "mammals.csv" 66386 * // in the project's "assets" folder: 66387 * // 66388 * // id,species,name 66389 * // 0,Capra hircus,Goat 66390 * // 1,Panthera pardus,Leopard 66391 * // 2,Equus zebra,Zebra 66392 * 66393 * let table; 66394 * 66395 * function preload() { 66396 * //my table is comma separated value "csv" 66397 * //and has a header specifying the columns labels 66398 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66399 * } 66400 * 66401 * function setup() { 66402 * table.clearRows(); 66403 * print(table.getRowCount() + ' total rows in table'); 66404 * print(table.getColumnCount() + ' total columns in table'); 66405 * } 66406 * </code> 66407 * </div> 66408 * 66409 *@alt 66410 * no image displayed 66411 * 66412 */ 66413 66414 66415 p5.Table.prototype.clearRows = function () { 66416 delete this.rows; 66417 this.rows = []; 66418 }; 66419 /** 66420 * Use <a href="#/p5/addColumn">addColumn()</a> to add a new column to a <a href="#/p5.Table">Table</a> object. 66421 * Typically, you will want to specify a title, so the column 66422 * may be easily referenced later by name. (If no title is 66423 * specified, the new column's title will be null.) 66424 * 66425 * @method addColumn 66426 * @param {String} [title] title of the given column 66427 * 66428 * @example 66429 * <div class="norender"> 66430 * <code> 66431 * // Given the CSV file "mammals.csv" 66432 * // in the project's "assets" folder: 66433 * // 66434 * // id,species,name 66435 * // 0,Capra hircus,Goat 66436 * // 1,Panthera pardus,Leopard 66437 * // 2,Equus zebra,Zebra 66438 * 66439 * let table; 66440 * 66441 * function preload() { 66442 * //my table is comma separated value "csv" 66443 * //and has a header specifying the columns labels 66444 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66445 * } 66446 * 66447 * function setup() { 66448 * table.addColumn('carnivore'); 66449 * table.set(0, 'carnivore', 'no'); 66450 * table.set(1, 'carnivore', 'yes'); 66451 * table.set(2, 'carnivore', 'no'); 66452 * 66453 * //print the results 66454 * for (let r = 0; r < table.getRowCount(); r++) 66455 * for (let c = 0; c < table.getColumnCount(); c++) 66456 * print(table.getString(r, c)); 66457 * } 66458 * </code> 66459 * </div> 66460 * 66461 *@alt 66462 * no image displayed 66463 * 66464 */ 66465 66466 66467 p5.Table.prototype.addColumn = function (title) { 66468 var t = title || null; 66469 this.columns.push(t); 66470 }; 66471 /** 66472 * Returns the total number of columns in a Table. 66473 * 66474 * @method getColumnCount 66475 * @return {Integer} Number of columns in this table 66476 * @example 66477 * <div> 66478 * <code> 66479 * // given the cvs file "blobs.csv" in /assets directory 66480 * // ID, Name, Flavor, Shape, Color 66481 * // Blob1, Blobby, Sweet, Blob, Pink 66482 * // Blob2, Saddy, Savory, Blob, Blue 66483 * 66484 * let table; 66485 * 66486 * function preload() { 66487 * table = loadTable('assets/blobs.csv'); 66488 * } 66489 * 66490 * function setup() { 66491 * createCanvas(200, 100); 66492 * textAlign(CENTER); 66493 * background(255); 66494 * } 66495 * 66496 * function draw() { 66497 * let numOfColumn = table.getColumnCount(); 66498 * text('There are ' + numOfColumn + ' columns in the table.', 100, 50); 66499 * } 66500 * </code> 66501 * </div> 66502 */ 66503 66504 66505 p5.Table.prototype.getColumnCount = function () { 66506 return this.columns.length; 66507 }; 66508 /** 66509 * Returns the total number of rows in a Table. 66510 * 66511 * @method getRowCount 66512 * @return {Integer} Number of rows in this table 66513 * @example 66514 * <div> 66515 * <code> 66516 * // given the cvs file "blobs.csv" in /assets directory 66517 * // 66518 * // ID, Name, Flavor, Shape, Color 66519 * // Blob1, Blobby, Sweet, Blob, Pink 66520 * // Blob2, Saddy, Savory, Blob, Blue 66521 * 66522 * let table; 66523 * 66524 * function preload() { 66525 * table = loadTable('assets/blobs.csv'); 66526 * } 66527 * 66528 * function setup() { 66529 * createCanvas(200, 100); 66530 * textAlign(CENTER); 66531 * background(255); 66532 * } 66533 * 66534 * function draw() { 66535 * text('There are ' + table.getRowCount() + ' rows in the table.', 100, 50); 66536 * } 66537 * </code> 66538 * </div> 66539 */ 66540 66541 66542 p5.Table.prototype.getRowCount = function () { 66543 return this.rows.length; 66544 }; 66545 /** 66546 * <p>Removes any of the specified characters (or "tokens").</p> 66547 * 66548 * <p>If no column is specified, then the values in all columns and 66549 * rows are processed. A specific column may be referenced by 66550 * either its ID or title.</p> 66551 * 66552 * @method removeTokens 66553 * @param {String} chars String listing characters to be removed 66554 * @param {String|Integer} [column] Column ID (number) 66555 * or name (string) 66556 * 66557 * @example 66558 * <div class="norender"><code> 66559 * function setup() { 66560 * let table = new p5.Table(); 66561 * 66562 * table.addColumn('name'); 66563 * table.addColumn('type'); 66564 * 66565 * let newRow = table.addRow(); 66566 * newRow.setString('name', ' $Lion ,'); 66567 * newRow.setString('type', ',,,Mammal'); 66568 * 66569 * newRow = table.addRow(); 66570 * newRow.setString('name', '$Snake '); 66571 * newRow.setString('type', ',,,Reptile'); 66572 * 66573 * table.removeTokens(',$ '); 66574 * print(table.getArray()); 66575 * } 66576 * 66577 * // prints: 66578 * // 0 "Lion" "Mamal" 66579 * // 1 "Snake" "Reptile" 66580 * </code></div> 66581 */ 66582 66583 66584 p5.Table.prototype.removeTokens = function (chars, column) { 66585 var escape = function (s) { 66586 return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); 66587 }; 66588 66589 var charArray = []; 66590 66591 for (var i = 0; i < chars.length; i++) { 66592 charArray.push(escape(chars.charAt(i))); 66593 } 66594 66595 var regex = new RegExp(charArray.join('|'), 'g'); 66596 66597 if (typeof column === 'undefined') { 66598 for (var c = 0; c < this.columns.length; c++) { 66599 for (var d = 0; d < this.rows.length; d++) { 66600 var s = this.rows[d].arr[c]; 66601 s = s.replace(regex, ''); 66602 this.rows[d].arr[c] = s; 66603 this.rows[d].obj[this.columns[c]] = s; 66604 } 66605 } 66606 } else if (typeof column === 'string') { 66607 for (var j = 0; j < this.rows.length; j++) { 66608 var val = this.rows[j].obj[column]; 66609 val = val.replace(regex, ''); 66610 this.rows[j].obj[column] = val; 66611 var pos = this.columns.indexOf(column); 66612 this.rows[j].arr[pos] = val; 66613 } 66614 } else { 66615 for (var k = 0; k < this.rows.length; k++) { 66616 var str = this.rows[k].arr[column]; 66617 str = str.replace(regex, ''); 66618 this.rows[k].arr[column] = str; 66619 this.rows[k].obj[this.columns[column]] = str; 66620 } 66621 } 66622 }; 66623 /** 66624 * Trims leading and trailing whitespace, such as spaces and tabs, 66625 * from String table values. If no column is specified, then the 66626 * values in all columns and rows are trimmed. A specific column 66627 * may be referenced by either its ID or title. 66628 * 66629 * @method trim 66630 * @param {String|Integer} [column] Column ID (number) 66631 * or name (string) 66632 * @example 66633 * <div class="norender"><code> 66634 * function setup() { 66635 * let table = new p5.Table(); 66636 * 66637 * table.addColumn('name'); 66638 * table.addColumn('type'); 66639 * 66640 * let newRow = table.addRow(); 66641 * newRow.setString('name', ' Lion ,'); 66642 * newRow.setString('type', ' Mammal '); 66643 * 66644 * newRow = table.addRow(); 66645 * newRow.setString('name', ' Snake '); 66646 * newRow.setString('type', ' Reptile '); 66647 * 66648 * table.trim(); 66649 * print(table.getArray()); 66650 * } 66651 * 66652 * // prints: 66653 * // 0 "Lion" "Mamal" 66654 * // 1 "Snake" "Reptile" 66655 * </code></div> 66656 */ 66657 66658 66659 p5.Table.prototype.trim = function (column) { 66660 var regex = new RegExp(' ', 'g'); 66661 66662 if (typeof column === 'undefined') { 66663 for (var c = 0; c < this.columns.length; c++) { 66664 for (var d = 0; d < this.rows.length; d++) { 66665 var s = this.rows[d].arr[c]; 66666 s = s.replace(regex, ''); 66667 this.rows[d].arr[c] = s; 66668 this.rows[d].obj[this.columns[c]] = s; 66669 } 66670 } 66671 } else if (typeof column === 'string') { 66672 for (var j = 0; j < this.rows.length; j++) { 66673 var val = this.rows[j].obj[column]; 66674 val = val.replace(regex, ''); 66675 this.rows[j].obj[column] = val; 66676 var pos = this.columns.indexOf(column); 66677 this.rows[j].arr[pos] = val; 66678 } 66679 } else { 66680 for (var k = 0; k < this.rows.length; k++) { 66681 var str = this.rows[k].arr[column]; 66682 str = str.replace(regex, ''); 66683 this.rows[k].arr[column] = str; 66684 this.rows[k].obj[this.columns[column]] = str; 66685 } 66686 } 66687 }; 66688 /**
66689 * Use <a href="#/p5/removeColumn">removeColumn()</a> to remove an existing column from a Table 66690 * object. The column to be removed may be identified by either 66691 * its title (a String) or its index value (an int). 66692 * removeColumn(0) would remove the first column, removeColumn(1) 66693 * would remove the second column, and so on. 66694 * 66695 * @method removeColumn 66696 * @param {String|Integer} column columnName (string) or ID (number) 66697 * 66698 * @example 66699 * <div class="norender"> 66700 * <code> 66701 * // Given the CSV file "mammals.csv" 66702 * // in the project's "assets" folder: 66703 * // 66704 * // id,species,name 66705 * // 0,Capra hircus,Goat 66706 * // 1,Panthera pardus,Leopard 66707 * // 2,Equus zebra,Zebra 66708 * 66709 * let table; 66710 * 66711 * function preload() { 66712 * //my table is comma separated value "csv" 66713 * //and has a header specifying the columns labels 66714 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66715 * } 66716 * 66717 * function setup() { 66718 * table.removeColumn('id'); 66719 * print(table.getColumnCount()); 66720 * } 66721 * </code> 66722 * </div> 66723 * 66724 *@alt 66725 * no image displayed 66726 * 66727 */ 66728 66729 66730 p5.Table.prototype.removeColumn = function (c) { 66731 var cString; 66732 var cNumber; 66733 66734 if (typeof c === 'string') { 66735 // find the position of c in the columns 66736 cString = c; 66737 cNumber = this.columns.indexOf(c); 66738 } else { 66739 cNumber = c; 66740 cString = this.columns[c]; 66741 } 66742 66743 var chunk = this.columns.splice(cNumber + 1, this.columns.length); 66744 this.columns.pop(); 66745 this.columns = this.columns.concat(chunk); 66746 66747 for (var i = 0; i < this.rows.length; i++) { 66748 var tempR = this.rows[i].arr; 66749 var chip = tempR.splice(cNumber + 1, tempR.length); 66750 tempR.pop(); 66751 this.rows[i].arr = tempR.concat(chip); 66752 delete this.rows[i].obj[cString]; 66753 } 66754 }; 66755 /** 66756 * Stores a value in the Table's specified row and column. 66757 * The row is specified by its ID, while the column may be specified 66758 * by either its ID or title. 66759 * 66760 * @method set 66761 * @param {Integer} row row ID 66762 * @param {String|Integer} column column ID (Number) 66763 * or title (String) 66764 * @param {String|Number} value value to assign 66765 * 66766 * @example 66767 * <div class="norender"> 66768 * <code> 66769 * // Given the CSV file "mammals.csv" 66770 * // in the project's "assets" folder: 66771 * // 66772 * // id,species,name 66773 * // 0,Capra hircus,Goat 66774 * // 1,Panthera pardus,Leopard 66775 * // 2,Equus zebra,Zebra 66776 * 66777 * let table; 66778 * 66779 * function preload() { 66780 * //my table is comma separated value "csv" 66781 * //and has a header specifying the columns labels 66782 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66783 * } 66784 * 66785 * function setup() { 66786 * table.set(0, 'species', 'Canis Lupus'); 66787 * table.set(0, 'name', 'Wolf'); 66788 * 66789 * //print the results 66790 * for (let r = 0; r < table.getRowCount(); r++) 66791 * for (let c = 0; c < table.getColumnCount(); c++) 66792 * print(table.getString(r, c)); 66793 * } 66794 * </code> 66795 * </div> 66796 * 66797 *@alt 66798 * no image displayed 66799 * 66800 */ 66801 66802 66803 p5.Table.prototype.set = function (row, column, value) { 66804 this.rows[row].set(column, value); 66805 }; 66806 /** 66807 * Stores a Float value in the Table's specified row and column. 66808 * The row is specified by its ID, while the column may be specified 66809 * by either its ID or title. 66810 * 66811 * @method setNum 66812 * @param {Integer} row row ID 66813 * @param {String|Integer} column column ID (Number) 66814 * or title (String) 66815 * @param {Number} value value to assign 66816 * 66817 * @example 66818 * <div class="norender"> 66819 * <code> 66820 * // Given the CSV file "mammals.csv" 66821 * // in the project's "assets" folder: 66822 * // 66823 * // id,species,name 66824 * // 0,Capra hircus,Goat 66825 * // 1,Panthera pardus,Leopard 66826 * // 2,Equus zebra,Zebra 66827 * 66828 * let table; 66829 * 66830 * function preload() { 66831 * //my table is comma separated value "csv" 66832 * //and has a header specifying the columns labels 66833 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66834 * } 66835 * 66836 * function setup() { 66837 * table.setNum(1, 'id', 1); 66838 * 66839 * print(table.getColumn(0)); 66840 * //["0", 1, "2"] 66841 * } 66842 * </code> 66843 * </div> 66844 * 66845 *@alt 66846 * no image displayed 66847 */ 66848 66849 66850 p5.Table.prototype.setNum = function (row, column, value) { 66851 this.rows[row].setNum(column, value); 66852 }; 66853 /** 66854 * Stores a String value in the Table's specified row and column. 66855 * The row is specified by its ID, while the column may be specified 66856 * by either its ID or title. 66857 * 66858 * @method setString 66859 * @param {Integer} row row ID 66860 * @param {String|Integer} column column ID (Number) 66861 * or title (String) 66862 * @param {String} value value to assign 66863 * @example 66864 * <div class="norender"><code> 66865 * // Given the CSV file "mammals.csv" in the project's "assets" folder: 66866 * // 66867 * // id,species,name 66868 * // 0,Capra hircus,Goat 66869 * // 1,Panthera pardus,Leopard 66870 * // 2,Equus zebra,Zebra 66871 * 66872 * let table; 66873 * 66874 * function preload() { 66875 * //my table is comma separated value "csv" 66876 * //and has a header specifying the columns labels 66877 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66878 * } 66879 * 66880 * function setup() { 66881 * //add a row 66882 * let newRow = table.addRow(); 66883 * newRow.setString('id', table.getRowCount() - 1); 66884 * newRow.setString('species', 'Canis Lupus'); 66885 * newRow.setString('name', 'Wolf'); 66886 * 66887 * print(table.getArray()); 66888 * } 66889 * </code></div> 66890 * 66891 * @alt 66892 * no image displayed 66893 */ 66894 66895 66896 p5.Table.prototype.setString = function (row, column, value) { 66897 this.rows[row].setString(column, value); 66898 }; 66899 /** 66900 * Retrieves a value from the Table's specified row and column. 66901 * The row is specified by its ID, while the column may be specified by 66902 * either its ID or title. 66903 * 66904 * @method get 66905 * @param {Integer} row row ID 66906 * @param {String|Integer} column columnName (string) or 66907 * ID (number) 66908 * @return {String|Number} 66909 * 66910 * @example 66911 * <div class="norender"> 66912 * <code> 66913 * // Given the CSV file "mammals.csv" 66914 * // in the project's "assets" folder: 66915 * // 66916 * // id,species,name 66917 * // 0,Capra hircus,Goat 66918 * // 1,Panthera pardus,Leopard 66919 * // 2,Equus zebra,Zebra 66920 * 66921 * let table; 66922 * 66923 * function preload() { 66924 * //my table is comma separated value "csv" 66925 * //and has a header specifying the columns labels 66926 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66927 * } 66928 * 66929 * function setup() { 66930 * print(table.get(0, 1)); 66931 * //Capra hircus 66932 * print(table.get(0, 'species')); 66933 * //Capra hircus 66934 * } 66935 * </code> 66936 * </div> 66937 * 66938 *@alt 66939 * no image displayed 66940 * 66941 */ 66942 66943 66944 p5.Table.prototype.get = function (row, column) { 66945 return this.rows[row].get(column); 66946 }; 66947 /** 66948 * Retrieves a Float value from the Table's specified row and column. 66949 * The row is specified by its ID, while the column may be specified by 66950 * either its ID or title. 66951 * 66952 * @method getNum 66953 * @param {Integer} row row ID 66954 * @param {String|Integer} column columnName (string) or 66955 * ID (number) 66956 * @return {Number} 66957 * 66958 * @example 66959 * <div class="norender"> 66960 * <code> 66961 * // Given the CSV file "mammals.csv" 66962 * // in the project's "assets" folder: 66963 * // 66964 * // id,species,name 66965 * // 0,Capra hircus,Goat 66966 * // 1,Panthera pardus,Leopard 66967 * // 2,Equus zebra,Zebra 66968 * 66969 * let table; 66970 * 66971 * function preload() { 66972 * //my table is comma separated value "csv" 66973 * //and has a header specifying the columns labels 66974 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 66975 * } 66976 * 66977 * function setup() { 66978 * print(table.getNum(1, 0) + 100); 66979 * //id 1 + 100 = 101 66980 * } 66981 * </code> 66982 * </div> 66983 * 66984 *@alt 66985 * no image displayed 66986 * 66987 */ 66988 66989 66990 p5.Table.prototype.getNum = function (row, column) { 66991 return this.rows[row].getNum(column); 66992 }; 66993 /** 66994 * Retrieves a String value from the Table's specified row and column. 66995 * The row is specified by its ID, while the column may be specified by 66996 * either its ID or title. 66997 * 66998 * @method getString 66999 * @param {Integer} row row ID 67000 * @param {String|Integer} column columnName (string) or 67001 * ID (number) 67002 * @return {String} 67003 * 67004 * @example 67005 * <div class="norender"> 67006 * <code> 67007 * // Given the CSV file "mammals.csv" 67008 * // in the project's "assets" folder: 67009 * // 67010 * // id,species,name 67011 * // 0,Capra hircus,Goat 67012 * // 1,Panthera pardus,Leopard 67013 * // 2,Equus zebra,Zebra 67014 * 67015 * let table; 67016 * 67017 * function preload() { 67018 * // table is comma separated value "CSV" 67019 * // and has specifiying header for column labels 67020 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 67021 * } 67022 * 67023 * function setup() { 67024 * print(table.getString(0, 0)); // 0 67025 * print(table.getString(0, 1)); // Capra hircus 67026 * print(table.getString(0, 2)); // Goat 67027 * print(table.getString(1, 0)); // 1 67028 * print(table.getString(1, 1)); // Panthera pardus 67029 * print(table.getString(1, 2)); // Leopard 67030 * print(table.getString(2, 0)); // 2 67031 * print(table.getString(2, 1)); // Equus zebra 67032 * print(table.getString(2, 2)); // Zebra 67033 * } 67034 * </code> 67035 * </div> 67036 * 67037 *@alt 67038 * no image displayed 67039 * 67040 */ 67041 67042 67043 p5.Table.prototype.getString = function (row, column) { 67044 return this.rows[row].getString(column); 67045 }; 67046 /** 67047 * Retrieves all table data and returns as an object. If a column name is 67048 * passed in, each row object will be stored with that attribute as its 67049 * title. 67050 * 67051 * @method getObject 67052 * @param {String} [headerColumn] Name of the column which should be used to 67053 * title each row object (optional) 67054 * @return {Object} 67055 * 67056 * @example 67057 * <div class="norender"> 67058 * <code> 67059 * // Given the CSV file "mammals.csv" 67060 * // in the project's "assets" folder: 67061 * // 67062 * // id,species,name 67063 * // 0,Capra hircus,Goat 67064 * // 1,Panthera pardus,Leopard 67065 * // 2,Equus zebra,Zebra 67066 * 67067 * let table; 67068 * 67069 * function preload() { 67070 * //my table is comma separated value "csv" 67071 * //and has a header specifying the columns labels 67072 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 67073 * } 67074 * 67075 * function setup() { 67076 * let tableObject = table.getObject(); 67077 * 67078 * print(tableObject); 67079 * //outputs an object 67080 * } 67081 * </code> 67082 * </div> 67083 * 67084 *@alt 67085 * no image displayed 67086 * 67087 */ 67088 67089 67090 p5.Table.prototype.getObject = function (headerColumn) { 67091 var tableObject = {}; 67092 var obj, cPos, index; 67093 67094 for (var i = 0; i < this.rows.length; i++) { 67095 obj = this.rows[i].obj; 67096 67097 if (typeof headerColumn === 'string') { 67098 cPos = this.columns.indexOf(headerColumn); // index of columnID 67099 67100 if (cPos >= 0) { 67101 index = obj[headerColumn]; 67102 tableObject[index] = obj; 67103 } else { 67104 throw new Error('This table has no column named "' + headerColumn + '"'); 67105 } 67106 } else { 67107 tableObject[i] = this.rows[i].obj; 67108 } 67109 } 67110 67111 return tableObject; 67112 }; 67113 /** 67114 * Retrieves all table data and returns it as a multidimensional array. 67115 * 67116 * @method getArray 67117 * @return {Array} 67118 * 67119 * @example 67120 * <div class="norender"> 67121 * <code> 67122 * // Given the CSV file "mammals.csv" 67123 * // in the project's "assets" folder 67124 * // 67125 * // id,species,name 67126 * // 0,Capra hircus,Goat 67127 * // 1,Panthera pardus,Leoperd 67128 * // 2,Equus zebra,Zebra 67129 * 67130 * let table; 67131 * 67132 * function preload() { 67133 * // table is comma separated value "CSV" 67134 * // and has specifiying header for column labels 67135 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 67136 * } 67137 * 67138 * function setup() { 67139 * let tableArray = table.getArray(); 67140 * for (let i = 0; i < tableArray.length; i++) { 67141 * print(tableArray[i]); 67142 * } 67143 * } 67144 * </code> 67145 * </div> 67146 * 67147 *@alt 67148 * no image displayed 67149 * 67150 */ 67151 67152 67153 p5.Table.prototype.getArray = function () { 67154 var tableArray = []; 67155 67156 for (var i = 0; i < this.rows.length; i++) { 67157 tableArray.push(this.rows[i].arr); 67158 } 67159 67160 return tableArray; 67161 }; 67162 67163 module.exports = p5; 67164 }, {
67165 "../core/main": 24 67166 }], 67167 49: [function (_dereq_, module, exports) { 67168 /** 67169 * @module IO 67170 * @submodule Table 67171 * @requires core 67172 */ 67173 'use strict'; 67174 67175 var p5 = _dereq_('../core/main'); 67176 /** 67177 * A TableRow object represents a single row of data values, 67178 * stored in columns, from a table. 67179 * 67180 * A Table Row contains both an ordered array, and an unordered 67181 * JSON object. 67182 * 67183 * @class p5.TableRow 67184 * @constructor 67185 * @param {String} [str] optional: populate the row with a 67186 * string of values, separated by the 67187 * separator 67188 * @param {String} [separator] comma separated values (csv) by default 67189 */ 67190 67191 67192 p5.TableRow = function (str, separator) { 67193 var arr = []; 67194 var obj = {}; 67195 67196 if (str) { 67197 separator = separator || ','; 67198 arr = str.split(separator); 67199 } 67200 67201 for (var i = 0; i < arr.length; i++) { 67202 var key = i; 67203 var val = arr[i]; 67204 obj[key] = val; 67205 } 67206 67207 this.arr = arr; 67208 this.obj = obj; 67209 this.table = null; 67210 }; 67211 /** 67212 * Stores a value in the TableRow's specified column. 67213 * The column may be specified by either its ID or title. 67214 * 67215 * @method set 67216 * @param {String|Integer} column Column ID (Number) 67217 * or Title (String) 67218 * @param {String|Number} value The value to be stored 67219 * 67220 * @example 67221 * <div class="norender"><code> 67222 * // Given the CSV file "mammals.csv" in the project's "assets" folder: 67223 * // 67224 * // id,species,name 67225 * // 0,Capra hircus,Goat 67226 * // 1,Panthera pardus,Leopard 67227 * // 2,Equus zebra,Zebra 67228 * 67229 * let table; 67230 * 67231 * function preload() { 67232 * //my table is comma separated value "csv" 67233 * //and has a header specifying the columns labels 67234 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 67235 * } 67236 * 67237 * function setup() { 67238 * let rows = table.getRows(); 67239 * for (let r = 0; r < rows.length; r++) { 67240 * rows[r].set('name', 'Unicorn'); 67241 * } 67242 * 67243 * //print the results 67244 * print(table.getArray()); 67245 * } 67246 * </code></div> 67247 * 67248 * @alt 67249 * no image displayed 67250 */ 67251 67252 67253 p5.TableRow.prototype.set = function (column, value) { 67254 // if typeof column is string, use .obj 67255 if (typeof column === 'string') { 67256 var cPos = this.table.columns.indexOf(column); // index of columnID 67257 67258 if (cPos >= 0) { 67259 this.obj[column] = value; 67260 this.arr[cPos] = value; 67261 } else { 67262 throw new Error('This table has no column named "' + column + '"'); 67263 } 67264 } else { 67265 // if typeof column is number, use .arr 67266 if (column < this.table.columns.length) { 67267 this.arr[column] = value; 67268 var cTitle = this.table.columns[column]; 67269 this.obj[cTitle] = value; 67270 } else { 67271 throw new Error('Column #' + column + ' is out of the range of this table'); 67272 } 67273 } 67274 }; 67275 /** 67276 * Stores a Float value in the TableRow's specified column. 67277 * The column may be specified by either its ID or title. 67278 * 67279 * @method setNum 67280 * @param {String|Integer} column Column ID (Number) 67281 * or Title (String) 67282 * @param {Number|String} value The value to be stored 67283 * as a Float 67284 * @example 67285 * <div class="norender"><code> 67286 * // Given the CSV file "mammals.csv" in the project's "assets" folder: 67287 * // 67288 * // id,species,name 67289 * // 0,Capra hircus,Goat 67290 * // 1,Panthera pardus,Leopard 67291 * // 2,Equus zebra,Zebra 67292 * 67293 * let table; 67294 * 67295 * function preload() { 67296 * //my table is comma separated value "csv" 67297 * //and has a header specifying the columns labels 67298 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 67299 * } 67300 * 67301 * function setup() { 67302 * let rows = table.getRows(); 67303 * for (let r = 0; r < rows.length; r++) { 67304 * rows[r].setNum('id', r + 10); 67305 * } 67306 * 67307 * print(table.getArray()); 67308 * } 67309 * </code></div> 67310 * 67311 * @alt 67312 * no image displayed 67313 */ 67314 67315 67316 p5.TableRow.prototype.setNum = function (column, value) { 67317 var floatVal = parseFloat(value); 67318 this.set(column, floatVal); 67319 }; 67320 /** 67321 * Stores a String value in the TableRow's specified column. 67322 * The column may be specified by either its ID or title. 67323 * 67324 * @method setString 67325 * @param {String|Integer} column Column ID (Number) 67326 * or Title (String) 67327 * @param {String|Number|Boolean|Object} value The value to be stored 67328 * as a String 67329 * @example 67330 * <div class="norender"><code> 67331 * // Given the CSV file "mammals.csv" in the project's "assets" folder: 67332 * // 67333 * // id,species,name 67334 * // 0,Capra hircus,Goat 67335 * // 1,Panthera pardus,Leopard 67336 * // 2,Equus zebra,Zebra 67337 * 67338 * let table; 67339 * 67340 * function preload() { 67341 * //my table is comma separated value "csv" 67342 * //and has a header specifying the columns labels 67343 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 67344 * } 67345 * 67346 * function setup() { 67347 * let rows = table.getRows(); 67348 * for (let r = 0; r < rows.length; r++) { 67349 * let name = rows[r].getString('name'); 67350 * rows[r].setString('name', 'A ' + name + ' named George'); 67351 * } 67352 * 67353 * print(table.getArray()); 67354 * } 67355 * </code></div> 67356 * 67357 * @alt 67358 * no image displayed 67359 */ 67360 67361 67362 p5.TableRow.prototype.setString = function (column, value) { 67363 var stringVal = value.toString(); 67364 this.set(column, stringVal); 67365 }; 67366 /** 67367 * Retrieves a value from the TableRow's specified column. 67368 * The column may be specified by either its ID or title. 67369 * 67370 * @method get 67371 * @param {String|Integer} column columnName (string) or 67372 * ID (number) 67373 * @return {String|Number} 67374 * 67375 * @example 67376 * <div class="norender"><code> 67377 * // Given the CSV file "mammals.csv" in the project's "assets" folder: 67378 * // 67379 * // id,species,name 67380 * // 0,Capra hircus,Goat 67381 * // 1,Panthera pardus,Leopard 67382 * // 2,Equus zebra,Zebra 67383 * 67384 * let table; 67385 * 67386 * function preload() { 67387 * //my table is comma separated value "csv" 67388 * //and has a header specifying the columns labels 67389 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 67390 * } 67391 * 67392 * function setup() { 67393 * let names = []; 67394 * let rows = table.getRows(); 67395 * for (let r = 0; r < rows.length; r++) { 67396 * names.push(rows[r].get('name')); 67397 * } 67398 * 67399 * print(names); 67400 * } 67401 * </code></div> 67402 * 67403 * @alt 67404 * no image displayed 67405 */ 67406 67407 67408 p5.TableRow.prototype.get = function (column) { 67409 if (typeof column === 'string') { 67410 return this.obj[column]; 67411 } else { 67412 return this.arr[column]; 67413 } 67414 }; 67415 /** 67416 * Retrieves a Float value from the TableRow's specified 67417 * column. The column may be specified by either its ID or 67418 * title. 67419 * 67420 * @method getNum 67421 * @param {String|Integer} column columnName (string) or 67422 * ID (number) 67423 * @return {Number} Float Floating point number 67424 * @example 67425 * <div class="norender"><code> 67426 * // Given the CSV file "mammals.csv" in the project's "assets" folder: 67427 * // 67428 * // id,species,name 67429 * // 0,Capra hircus,Goat 67430 * // 1,Panthera pardus,Leopard 67431 * // 2,Equus zebra,Zebra 67432 * 67433 * let table; 67434 * 67435 * function preload() { 67436 * //my table is comma separated value "csv" 67437 * //and has a header specifying the columns labels 67438 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 67439 * } 67440 * 67441 * function setup() { 67442 * let rows = table.getRows(); 67443 * let minId = Infinity; 67444 * let maxId = -Infinity; 67445 * for (let r = 0; r < rows.length; r++) { 67446 * let id = rows[r].getNum('id'); 67447 * minId = min(minId, id); 67448 * maxId = min(maxId, id); 67449 * } 67450 * print('minimum id = ' + minId + ', maximum id = ' + maxId); 67451 * } 67452 * </code></div> 67453 * 67454 * @alt 67455 * no image displayed 67456 */ 67457 67458 67459 p5.TableRow.prototype.getNum = function (column) { 67460 var ret; 67461 67462 if (typeof column === 'string') { 67463 ret = parseFloat(this.obj[column]); 67464 } else { 67465 ret = parseFloat(this.arr[column]); 67466 } 67467 67468 if (ret.toString() === 'NaN') { 67469 throw 'Error: ' + this.obj[column] + ' is NaN (Not a Number)'; 67470 } 67471 67472 return ret; 67473 }; 67474 /** 67475 * Retrieves an String value from the TableRow's specified 67476 * column. The column may be specified by either its ID or 67477 * title. 67478 * 67479 * @method getString 67480 * @param {String|Integer} column columnName (string) or 67481 * ID (number) 67482 * @return {String} String 67483 * @example 67484 * <div class="norender"><code> 67485 * // Given the CSV file "mammals.csv" in the project's "assets" folder: 67486 * // 67487 * // id,species,name 67488 * // 0,Capra hircus,Goat 67489 * // 1,Panthera pardus,Leopard 67490 * // 2,Equus zebra,Zebra 67491 * 67492 * let table; 67493 * 67494 * function preload() { 67495 * //my table is comma separated value "csv" 67496 * //and has a header specifying the columns labels 67497 * table = loadTable('assets/mammals.csv', 'csv', 'header'); 67498 * } 67499 * 67500 * function setup() { 67501 * let rows = table.getRows(); 67502 * let longest = ''; 67503 * for (let r = 0; r < rows.length; r++) { 67504 * let species = rows[r].getString('species'); 67505 * if (longest.length < species.length) { 67506 * longest = species; 67507 * } 67508 * } 67509 * 67510 * print('longest: ' + longest); 67511 * } 67512 * </code></div> 67513 * 67514 * @alt 67515 * no image displayed 67516 */ 67517 67518 67519 p5.TableRow.prototype.getString = function (column) { 67520 if (typeof column === 'string') { 67521 return this.obj[column].toString(); 67522 } else { 67523 return this.arr[column].toString(); 67524 } 67525 }; 67526 67527 module.exports = p5; 67528 }, {
67529 "../core/main": 24 67530 }], 67531 50: [function (_dereq_, module, exports) { 67532 /** 67533 * @module IO 67534 * @submodule XML 67535 * @requires core 67536 */ 67537 'use strict'; 67538 67539 var p5 = _dereq_('../core/main'); 67540 /** 67541 * XML is a representation of an XML object, able to parse XML code. Use 67542 * <a href="#/p5/loadXML">loadXML()</a> to load external XML files and create XML objects. 67543 * 67544 * @class p5.XML 67545 * @constructor 67546 * @example 67547 * <div class='norender'><code> 67548 * // The following short XML file called "mammals.xml" is parsed 67549 * // in the code below. 67550 * // 67551 * // <?xml version="1.0"?> 67552 * // <mammals> 67553 * // <animal id="0" species="Capra hircus">Goat</animal> 67554 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67555 * // <animal id="2" species="Equus zebra">Zebra</animal> 67556 * // </mammals> 67557 * 67558 * let xml; 67559 * 67560 * function preload() { 67561 * xml = loadXML('assets/mammals.xml'); 67562 * } 67563 * 67564 * function setup() { 67565 * let children = xml.getChildren('animal'); 67566 * 67567 * for (let i = 0; i < children.length; i++) { 67568 * let id = children[i].getNum('id'); 67569 * let coloring = children[i].getString('species'); 67570 * let name = children[i].getContent(); 67571 * print(id + ', ' + coloring + ', ' + name); 67572 * } 67573 * } 67574 * 67575 * // Sketch prints: 67576 * // 0, Capra hircus, Goat 67577 * // 1, Panthera pardus, Leopard 67578 * // 2, Equus zebra, Zebra 67579 * </code></div> 67580 * 67581 * @alt 67582 * no image displayed 67583 * 67584 */ 67585 67586 67587 p5.XML = function (DOM) { 67588 if (!DOM) { 67589 var xmlDoc = document.implementation.createDocument(null, 'doc'); 67590 this.DOM = xmlDoc.createElement('root'); 67591 } else { 67592 this.DOM = DOM; 67593 } 67594 }; 67595 /** 67596 * Gets a copy of the element's parent. Returns the parent as another 67597 * <a href="#/p5.XML">p5.XML</a> object. 67598 * 67599 * @method getParent 67600 * @return {p5.XML} element parent 67601 * @example 67602 * <div class='norender'><code> 67603 * // The following short XML file called "mammals.xml" is parsed 67604 * // in the code below. 67605 * // 67606 * // <?xml version="1.0"?> 67607 * // <mammals> 67608 * // <animal id="0" species="Capra hircus">Goat</animal> 67609 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67610 * // <animal id="2" species="Equus zebra">Zebra</animal> 67611 * // </mammals> 67612 * 67613 * let xml; 67614 * 67615 * function preload() { 67616 * xml = loadXML('assets/mammals.xml'); 67617 * } 67618 * 67619 * function setup() { 67620 * let children = xml.getChildren('animal'); 67621 * let parent = children[1].getParent(); 67622 * print(parent.getName()); 67623 * } 67624 * 67625 * // Sketch prints: 67626 * // mammals 67627 * </code></div> 67628 */ 67629 67630 67631 p5.XML.prototype.getParent = function () { 67632 return new p5.XML(this.DOM.parentElement); 67633 }; 67634 /** 67635 * Gets the element's full name, which is returned as a String. 67636 * 67637 * @method getName 67638 * @return {String} the name of the node 67639 * @example<animal 67640 * <div class='norender'><code> 67641 * // The following short XML file called "mammals.xml" is parsed 67642 * // in the code below. 67643 * // 67644 * // <?xml version="1.0"?> 67645 * // <mammals> 67646 * // <animal id="0" species="Capra hircus">Goat</animal> 67647 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67648 * // <animal id="2" species="Equus zebra">Zebra</animal> 67649 * // </mammals> 67650 * 67651 * let xml; 67652 * 67653 * function preload() { 67654 * xml = loadXML('assets/mammals.xml'); 67655 * } 67656 * 67657 * function setup() { 67658 * print(xml.getName()); 67659 * } 67660 * 67661 * // Sketch prints: 67662 * // mammals 67663 * </code></div> 67664 */ 67665 67666 67667 p5.XML.prototype.getName = function () { 67668 return this.DOM.tagName; 67669 }; 67670 /** 67671 * Sets the element's name, which is specified as a String. 67672 * 67673 * @method setName 67674 * @param {String} the new name of the node 67675 * @example<animal 67676 * <div class='norender'><code> 67677 * // The following short XML file called "mammals.xml" is parsed 67678 * // in the code below. 67679 * // 67680 * // <?xml version="1.0"?> 67681 * // <mammals> 67682 * // <animal id="0" species="Capra hircus">Goat</animal> 67683 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67684 * // <animal id="2" species="Equus zebra">
67684Zebra</animal> 67685 * // </mammals> 67686 * 67687 * let xml; 67688 * 67689 * function preload() { 67690 * xml = loadXML('assets/mammals.xml'); 67691 * } 67692 * 67693 * function setup() { 67694 * print(xml.getName()); 67695 * xml.setName('fish'); 67696 * print(xml.getName()); 67697 * } 67698 * 67699 * // Sketch prints: 67700 * // mammals 67701 * // fish 67702 * </code></div> 67703 */ 67704 67705 67706 p5.XML.prototype.setName = function (name) { 67707 var content = this.DOM.innerHTML; 67708 var attributes = this.DOM.attributes; 67709 var xmlDoc = document.implementation.createDocument(null, 'default'); 67710 var newDOM = xmlDoc.createElement(name); 67711 newDOM.innerHTML = content; 67712 67713 for (var i = 0; i < attributes.length; i++) { 67714 newDOM.setAttribute(attributes[i].nodeName, attributes.nodeValue); 67715 } 67716 67717 this.DOM = newDOM; 67718 }; 67719 /** 67720 * Checks whether or not the element has any children, and returns the result 67721 * as a boolean. 67722 * 67723 * @method hasChildren 67724 * @return {boolean} 67725 * @example<animal 67726 * <div class='norender'><code> 67727 * // The following short XML file called "mammals.xml" is parsed 67728 * // in the code below. 67729 * // 67730 * // <?xml version="1.0"?> 67731 * // <mammals> 67732 * // <animal id="0" species="Capra hircus">Goat</animal> 67733 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67734 * // <animal id="2" species="Equus zebra">Zebra</animal> 67735 * // </mammals> 67736 * 67737 * let xml; 67738 * 67739 * function preload() { 67740 * xml = loadXML('assets/mammals.xml'); 67741 * } 67742 * 67743 * function setup() { 67744 * print(xml.hasChildren()); 67745 * } 67746 * 67747 * // Sketch prints: 67748 * // true 67749 * </code></div> 67750 */ 67751 67752 67753 p5.XML.prototype.hasChildren = function () { 67754 return this.DOM.children.length > 0; 67755 }; 67756 /** 67757 * Get the names of all of the element's children, and returns the names as an 67758 * array of Strings. This is the same as looping through and calling <a href="#/p5.XML/getName">getName()</a> 67759 * on each child element individually. 67760 * 67761 * @method listChildren 67762 * @return {String[]} names of the children of the element 67763 * @example<animal 67764 * <div class='norender'><code> 67765 * // The following short XML file called "mammals.xml" is parsed 67766 * // in the code below. 67767 * // 67768 * // <?xml version="1.0"?> 67769 * // <mammals> 67770 * // <animal id="0" species="Capra hircus">Goat</animal> 67771 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67772 * // <animal id="2" species="Equus zebra">Zebra</animal> 67773 * // </mammals> 67774 * 67775 * let xml; 67776 * 67777 * function preload() { 67778 * xml = loadXML('assets/mammals.xml'); 67779 * } 67780 * 67781 * function setup() { 67782 * print(xml.listChildren()); 67783 * } 67784 * 67785 * // Sketch prints: 67786 * // ["animal", "animal", "animal"] 67787 * </code></div> 67788 */ 67789 67790 67791 p5.XML.prototype.listChildren = function () { 67792 var arr = []; 67793 67794 for (var i = 0; i < this.DOM.childNodes.length; i++) { 67795 arr.push(this.DOM.childNodes[i].nodeName); 67796 } 67797 67798 return arr; 67799 }; 67800 /** 67801 * Returns all of the element's children as an array of <a href="#/p5.XML">p5.XML</a> objects. When 67802 * the name parameter is specified, then it will return all children that match 67803 * that name. 67804 * 67805 * @method getChildren 67806 * @param {String} [name] element name 67807 * @return {p5.XML[]} children of the element 67808 * @example<animal 67809 * <div class='norender'><code> 67810 * // The following short XML file called "mammals.xml" is parsed 67811 * // in the code below. 67812 * // 67813 * // <?xml version="1.0"?> 67814 * // <mammals> 67815 * // <animal id="0" species="Capra hircus">Goat</animal> 67816 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67817 * // <animal id="2" species="Equus zebra">
67817Zebra</animal> 67818 * // </mammals> 67819 * 67820 * let xml; 67821 * 67822 * function preload() { 67823 * xml = loadXML('assets/mammals.xml'); 67824 * } 67825 * 67826 * function setup() { 67827 * let animals = xml.getChildren('animal'); 67828 * 67829 * for (let i = 0; i < animals.length; i++) { 67830 * print(animals[i].getContent()); 67831 * } 67832 * } 67833 * 67834 * // Sketch prints: 67835 * // "Goat" 67836 * // "Leopard" 67837 * // "Zebra" 67838 * </code></div> 67839 */ 67840 67841 67842 p5.XML.prototype.getChildren = function (param) { 67843 if (param) { 67844 return elementsToP5XML(this.DOM.getElementsByTagName(param)); 67845 } else { 67846 return elementsToP5XML(this.DOM.children); 67847 } 67848 }; 67849 67850 function elementsToP5XML(elements) { 67851 var arr = []; 67852 67853 for (var i = 0; i < elements.length; i++) { 67854 arr.push(new p5.XML(elements[i])); 67855 } 67856 67857 return arr; 67858 } 67859 /** 67860 * Returns the first of the element's children that matches the name parameter 67861 * or the child of the given index.It returns undefined if no matching 67862 * child is found. 67863 * 67864 * @method getChild 67865 * @param {String|Integer} name element name or index 67866 * @return {p5.XML} 67867 * @example<animal 67868 * <div class='norender'><code> 67869 * // The following short XML file called "mammals.xml" is parsed 67870 * // in the code below. 67871 * // 67872 * // <?xml version="1.0"?> 67873 * // <mammals> 67874 * // <animal id="0" species="Capra hircus">Goat</animal> 67875 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67876 * // <animal id="2" species="Equus zebra">Zebra</animal> 67877 * // </mammals> 67878 * 67879 * let xml; 67880 * 67881 * function preload() { 67882 * xml = loadXML('assets/mammals.xml'); 67883 * } 67884 * 67885 * function setup() { 67886 * let firstChild = xml.getChild('animal'); 67887 * print(firstChild.getContent()); 67888 * } 67889 * 67890 * // Sketch prints: 67891 * // "Goat" 67892 * </code></div> 67893 * <div class='norender'><code> 67894 * let xml; 67895 * 67896 * function preload() { 67897 * xml = loadXML('assets/mammals.xml'); 67898 * } 67899 * 67900 * function setup() { 67901 * let secondChild = xml.getChild(1); 67902 * print(secondChild.getContent()); 67903 * } 67904 * 67905 * // Sketch prints: 67906 * // "Leopard" 67907 * </code></div> 67908 */ 67909 67910 67911 p5.XML.prototype.getChild = function (param) { 67912 if (typeof param === 'string') { 67913 for (var i = 0; i < this.DOM.children.length; i++) { 67914 var child = this.DOM.children[i]; 67915 if (child.tagName === param) return new p5.XML(child); 67916 } 67917 } else { 67918 return new p5.XML(this.DOM.children[param]); 67919 } 67920 }; 67921 /** 67922 * Appends a new child to the element. The child can be specified with 67923 * either a String, which will be used as the new tag's name, or as a 67924 * reference to an existing <a href="#/p5.XML">p5.XML</a> object. 67925 * A reference to the newly created child is returned as an <a href="#/p5.XML">p5.XML</a> object. 67926 * 67927 * @method addChild 67928 * @param {p5.XML} node a <a href="#/p5.XML">p5.XML</a> Object which will be the child to be added 67929 * @example 67930 * <div class='norender'><code> 67931 * // The following short XML file called "mammals.xml" is parsed 67932 * // in the code below. 67933 * // 67934 * // <?xml version="1.0"?> 67935 * // <mammals> 67936 * // <animal id="0" species="Capra hircus">Goat</animal> 67937 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67938 * // <animal id="2" species="Equus zebra">Zebra</animal> 67939 * // </mammals> 67940 * 67941 * let xml; 67942 * 67943 * function preload() { 67944 * xml = loadXML('assets/mammals.xml'); 67945 * } 67946 * 67947 * function setup() { 67948 * let child = new p5.XML(); 67949 * child.setName('animal'); 67950 * child.setAttribute('id', '3'); 67951 * child.setAttribute('species', 'Ornithorhynchus anatinu
67951s'); 67952 * child.setContent('Platypus'); 67953 * xml.addChild(child); 67954 * 67955 * let animals = xml.getChildren('animal'); 67956 * print(animals[animals.length - 1].getContent()); 67957 * } 67958 * 67959 * // Sketch prints: 67960 * // "Goat" 67961 * // "Leopard" 67962 * // "Zebra" 67963 * </code></div> 67964 */ 67965 67966 67967 p5.XML.prototype.addChild = function (node) { 67968 if (node instanceof p5.XML) { 67969 this.DOM.appendChild(node.DOM); 67970 } else {// PEND 67971 } 67972 }; 67973 /** 67974 * Removes the element specified by name or index. 67975 * 67976 * @method removeChild 67977 * @param {String|Integer} name element name or index 67978 * @example 67979 * <div class='norender'><code> 67980 * // The following short XML file called "mammals.xml" is parsed 67981 * // in the code below. 67982 * // 67983 * // <?xml version="1.0"?> 67984 * // <mammals> 67985 * // <animal id="0" species="Capra hircus">Goat</animal> 67986 * // <animal id="1" species="Panthera pardus">Leopard</animal> 67987 * // <animal id="2" species="Equus zebra">Zebra</animal> 67988 * // </mammals> 67989 * 67990 * let xml; 67991 * 67992 * function preload() { 67993 * xml = loadXML('assets/mammals.xml'); 67994 * } 67995 * 67996 * function setup() { 67997 * xml.removeChild('animal'); 67998 * let children = xml.getChildren(); 67999 * for (let i = 0; i < children.length; i++) { 68000 * print(children[i].getContent()); 68001 * } 68002 * } 68003 * 68004 * // Sketch prints: 68005 * // "Leopard" 68006 * // "Zebra" 68007 * </code></div> 68008 * <div class='norender'><code> 68009 * let xml; 68010 * 68011 * function preload() { 68012 * xml = loadXML('assets/mammals.xml'); 68013 * } 68014 * 68015 * function setup() { 68016 * xml.removeChild(1); 68017 * let children = xml.getChildren(); 68018 * for (let i = 0; i < children.length; i++) { 68019 * print(children[i].getContent()); 68020 * } 68021 * } 68022 * 68023 * // Sketch prints: 68024 * // "Goat" 68025 * // "Zebra" 68026 * </code></div> 68027 */ 68028 68029 68030 p5.XML.prototype.removeChild = function (param) { 68031 var ind = -1; 68032 68033 if (typeof param === 'string') { 68034 for (var i = 0; i < this.DOM.children.length; i++) { 68035 if (this.DOM.children[i].tagName === param) { 68036 ind = i; 68037 break; 68038 } 68039 } 68040 } else { 68041 ind = param; 68042 } 68043 68044 if (ind !== -1) { 68045 this.DOM.removeChild(this.DOM.children[ind]); 68046 } 68047 }; 68048 /** 68049 * Counts the specified element's number of attributes, returned as an Number. 68050 * 68051 * @method getAttributeCount 68052 * @return {Integer} 68053 * @example 68054 * <div class='norender'><code> 68055 * // The following short XML file called "mammals.xml" is parsed 68056 * // in the code below. 68057 * // 68058 * // <?xml version="1.0"?> 68059 * // <mammals> 68060 * // <animal id="0" species="Capra hircus">Goat</animal> 68061 * // <animal id="1" species="Panthera pardus">Leopard</animal> 68062 * // <animal id="2" species="Equus zebra">Zebra</animal> 68063 * // </mammals> 68064 * 68065 * let xml; 68066 * 68067 * function preload() { 68068 * xml = loadXML('assets/mammals.xml'); 68069 * } 68070 * 68071 * function setup() { 68072 * let firstChild = xml.getChild('animal'); 68073 * print(firstChild.getAttributeCount()); 68074 * } 68075 * 68076 * // Sketch prints: 68077 * // 2 68078 * </code></div> 68079 */ 68080 68081 68082 p5.XML.prototype.getAttributeCount = function () { 68083 return this.DOM.attributes.length; 68084 }; 68085 /** 68086 * Gets all of the specified element's attributes, and returns them as an 68087 * array of Strings. 68088 * 68089 * @method listAttributes 68090 * @return {String[]} an array of strings containing the names of attributes 68091 * @example 68092 * <div class='norender'><code> 68093 * // The following short XML file called "mammals.xml" is parsed 68094 * // in the code below. 68095 * // 68096 * // <?xml version="1.0"?> 68097 * // <mammals> 68098 * // <animal id="0" species="Capra hircus">Goat</animal> 68099 * // <animal id="1" species="Panthera pardus">Leopard</animal> 68100 * // <animal id="2" species="Equus zebra">
68100Zebra</animal> 68101 * // </mammals> 68102 * 68103 * let xml; 68104 * 68105 * function preload() { 68106 * xml = loadXML('assets/mammals.xml'); 68107 * } 68108 * 68109 * function setup() { 68110 * let firstChild = xml.getChild('animal'); 68111 * print(firstChild.listAttributes()); 68112 * } 68113 * 68114 * // Sketch prints: 68115 * // ["id", "species"] 68116 * </code></div> 68117 */ 68118 68119 68120 p5.XML.prototype.listAttributes = function () { 68121 var arr = []; 68122 68123 for (var i = 0; i < this.DOM.attributes.length; i++) { 68124 var attribute = this.DOM.attributes[i]; 68125 arr.push(attribute.nodeName); 68126 } 68127 68128 return arr; 68129 }; 68130 /** 68131 * Checks whether or not an element has the specified attribute. 68132 * 68133 * @method hasAttribute 68134 * @param {String} the attribute to be checked 68135 * @return {boolean} true if attribute found else false 68136 * @example 68137 * <div class='norender'><code> 68138 * // The following short XML file called "mammals.xml" is parsed 68139 * // in the code below. 68140 * // 68141 * // <?xml version="1.0"?> 68142 * // <mammals> 68143 * // <animal id="0" species="Capra hircus">Goat</animal> 68144 * // <animal id="1" species="Panthera pardus">Leopard</animal> 68145 * // <animal id="2" species="Equus zebra">Zebra</animal> 68146 * // </mammals> 68147 * 68148 * let xml; 68149 * 68150 * function preload() { 68151 * xml = loadXML('assets/mammals.xml'); 68152 * } 68153 * 68154 * function setup() { 68155 * let firstChild = xml.getChild('animal'); 68156 * print(firstChild.hasAttribute('species')); 68157 * print(firstChild.hasAttribute('color')); 68158 * } 68159 * 68160 * // Sketch prints: 68161 * // true 68162 * // false 68163 * </code></div> 68164 */ 68165 68166 68167 p5.XML.prototype.hasAttribute = function (name) { 68168 var obj = {}; 68169 68170 for (var i = 0; i < this.DOM.attributes.length; i++) { 68171 var attribute = this.DOM.attributes[i]; 68172 obj[attribute.nodeName] = attribute.nodeValue; 68173 } 68174 68175 return obj[name] ? true : false; 68176 }; 68177 /** 68178 * Returns an attribute value of the element as an Number. If the defaultValue 68179 * parameter is specified and the attribute doesn't exist, then defaultValue 68180 * is returned. If no defaultValue is specified and the attribute doesn't 68181 * exist, the value 0 is returned. 68182 * 68183 * @method getNum 68184 * @param {String} name the non-null full name of the attribute 68185 * @param {Number} [defaultValue] the default value of the attribute 68186 * @return {Number} 68187 * @example 68188 * <div class='norender'><code> 68189 * // The following short XML file called "mammals.xml" is parsed 68190 * // in the code below. 68191 * // 68192 * // <?xml version="1.0"?> 68193 * // <mammals> 68194 * // <animal id="0" species="Capra hircus">Goat</animal> 68195 * // <animal id="1" species="Panthera pardus">Leopard</animal> 68196 * // <animal id="2" species="Equus zebra">Zebra</animal> 68197 * // </mammals> 68198 * 68199 * let xml; 68200 * 68201 * function preload() { 68202 * xml = loadXML('assets/mammals.xml'); 68203 * } 68204 * 68205 * function setup() { 68206 * let firstChild = xml.getChild('animal'); 68207 * print(firstChild.getNum('id')); 68208 * } 68209 * 68210 * // Sketch prints: 68211 * // 0 68212 * </code></div> 68213 */ 68214 68215 68216 p5.XML.prototype.getNum = function (name, defaultValue) { 68217 var obj = {}; 68218 68219 for (var i = 0; i < this.DOM.attributes.length; i++) { 68220 var attribute = this.DOM.attributes[i]; 68221 obj[attribute.nodeName] = attribute.nodeValue; 68222 } 68223 68224 return Number(obj[name]) || defaultValue || 0; 68225 }; 68226 /** 68227 * Returns an attribute value of the element as an String. If the defaultValue 68228 * parameter is specified and the attribute doesn't exist, then defaultValue 68229 * is returned. If no defaultValue is specified and the attribute doesn't 68230 * exist, null is returned. 68231 * 68232 * @method getString 68233 * @param {String} name the non-null full name of the attribute 68234 * @param {Number} [defaultValue] the default value of the attribute 68235 * @return {String} 68236 * @example 68237 * <div class='norender'><code> 68238 * // The following short XML file called "mammals.xml" is parsed 68239 * // in the code below. 68240 * // 68241 * // <?xml version="1.0"?> 68242 * // <mammals> 68243 * // <animal id="0" species="Capra hircus">Goat</animal> 68244 * // <animal id="1" species="Panthera pardus">Leopard</animal> 68245 * // <animal id="2" species="Equus zebra">
68245Zebra</animal> 68246 * // </mammals> 68247 * 68248 * let xml; 68249 * 68250 * function preload() { 68251 * xml = loadXML('assets/mammals.xml'); 68252 * } 68253 * 68254 * function setup() { 68255 * let firstChild = xml.getChild('animal'); 68256 * print(firstChild.getString('species')); 68257 * } 68258 * 68259 * // Sketch prints: 68260 * // "Capra hircus" 68261 * </code></div> 68262 */ 68263 68264 68265 p5.XML.prototype.getString = function (name, defaultValue) { 68266 var obj = {}; 68267 68268 for (var i = 0; i < this.DOM.attributes.length; i++) { 68269 var attribute = this.DOM.attributes[i]; 68270 obj[attribute.nodeName] = attribute.nodeValue; 68271 } 68272 68273 return obj[name] ? String(obj[name]) : defaultValue || null; 68274 }; 68275 /** 68276 * Sets the content of an element's attribute. The first parameter specifies 68277 * the attribute name, while the second specifies the new content. 68278 * 68279 * @method setAttribute 68280 * @param {String} name the full name of the attribute 68281 * @param {Number|String|Boolean} value the value of the attribute 68282 * @example 68283 * <div class='norender'><code> 68284 * // The following short XML file called "mammals.xml" is parsed 68285 * // in the code below. 68286 * // 68287 * // <?xml version="1.0"?> 68288 * // <mammals> 68289 * // <animal id="0" species="Capra hircus">Goat</animal> 68290 * // <animal id="1" species="Panthera pardus">Leopard</animal> 68291 * // <animal id="2" species="Equus zebra">Zebra</animal> 68292 * // </mammals> 68293 * 68294 * let xml; 68295 * 68296 * function preload() { 68297 * xml = loadXML('assets/mammals.xml'); 68298 * } 68299 * 68300 * function setup() { 68301 * let firstChild = xml.getChild('animal'); 68302 * print(firstChild.getString('species')); 68303 * firstChild.setAttribute('species', 'Jamides zebra'); 68304 * print(firstChild.getString('species')); 68305 * } 68306 * 68307 * // Sketch prints: 68308 * // "Capra hircus" 68309 * // "Jamides zebra" 68310 * </code></div> 68311 */ 68312 68313 68314 p5.XML.prototype.setAttribute = function (name, value) { 68315 this.DOM.setAttribute(name, value); 68316 }; 68317 /** 68318 * Returns the content of an element. If there is no such content, 68319 * defaultValue is returned if specified, otherwise null is returned. 68320 * 68321 * @method getContent 68322 * @param {String} [defaultValue] value returned if no content is found 68323 * @return {String} 68324 * @example 68325 * <div class='norender'><code> 68326 * // The following short XML file called "mammals.xml" is parsed 68327 * // in the code below. 68328 * // 68329 * // <?xml version="1.0"?> 68330 * // <mammals> 68331 * // <animal id="0" species="Capra hircus">Goat</animal> 68332 * // <animal id="1" species="Panthera pardus">Leopard</animal> 68333 * // <animal id="2" species="Equus zebra">Zebra</animal> 68334 * // </mammals> 68335 * 68336 * let xml; 68337 * 68338 * function preload() { 68339 * xml = loadXML('assets/mammals.xml'); 68340 * } 68341 * 68342 * function setup() { 68343 * let firstChild = xml.getChild('animal'); 68344 * print(firstChild.getContent()); 68345 * } 68346 * 68347 * // Sketch prints: 68348 * // "Goat" 68349 * </code></div> 68350 */ 68351 68352 68353 p5.XML.prototype.getContent = function (defaultValue) { 68354 var str; 68355 str = this.DOM.textContent; 68356 str = str.replace(/\s\s+/g, ','); 68357 return str || defaultValue || null; 68358 }; 68359 /** 68360 * Sets the element's content. 68361 * 68362 * @method setContent 68363 * @param {String} text the new content 68364 * @example 68365 * <div class='norender'><code> 68366 * // The following short XML file called "mammals.xml" is parsed 68367 * // in the code below. 68368 * // 68369 * // <?xml version="1.0"?> 68370 * // <mammals> 68371 * // <animal id="0" species="Capra hircus">Goat</animal> 68372 * // <animal id="1" species="Panthera pardus">Leopard</animal> 68373 * // <animal id="2" species="Equus zebra">
68373Zebra</animal> 68374 * // </mammals> 68375 * 68376 * let xml; 68377 * 68378 * function preload() { 68379 * xml = loadXML('assets/mammals.xml'); 68380 * } 68381 * 68382 * function setup() { 68383 * let firstChild = xml.getChild('animal'); 68384 * print(firstChild.getContent()); 68385 * firstChild.setContent('Mountain Goat'); 68386 * print(firstChild.getContent()); 68387 * } 68388 * 68389 * // Sketch prints: 68390 * // "Goat" 68391 * // "Mountain Goat" 68392 * </code></div> 68393 */ 68394 68395 68396 p5.XML.prototype.setContent = function (content) { 68397 if (!this.DOM.children.length) { 68398 this.DOM.textContent = content; 68399 } 68400 }; 68401 /** 68402 * Serializes the element into a string. This function is useful for preparing 68403 * the content to be sent over a http request or saved to file. 68404 * 68405 * @method serialize 68406 * @return {String} Serialized string of the element 68407 * @example 68408 * <div class='norender'><code> 68409 * let xml; 68410 * 68411 * function preload() { 68412 * xml = loadXML('assets/mammals.xml'); 68413 * } 68414 * 68415 * function setup() { 68416 * print(xml.serialize()); 68417 * } 68418 * 68419 * // Sketch prints: 68420 * // <mammals> 68421 * // <animal id="0" species="Capra hircus">Goat</animal> 68422 * // <animal id="1" species="Panthera pardus">Leopard</animal> 68423 * // <animal id="2" species="Equus zebra">Zebra</animal> 68424 * // </mammals> 68425 * </code></div> 68426 */ 68427 68428 68429 p5.XML.prototype.serialize = function () { 68430 var xmlSerializer = new XMLSerializer(); 68431 return xmlSerializer.serializeToString(this.DOM); 68432 }; 68433 68434 module.exports = p5; 68435 }, {
68436 "../core/main": 24 68437 }], 68438 51: [function (_dereq_, module, exports) { 68439 /** 68440 * @module Math 68441 * @submodule Calculation 68442 * @for p5 68443 * @requires core 68444 */ 68445 'use strict'; 68446 68447 var p5 = _dereq_('../core/main'); 68448 /** 68449 * Calculates the absolute value (magnitude) of a number. Maps to Math.abs(). 68450 * The absolute value of a number is always positive. 68451 * 68452 * @method abs 68453 * @param {Number} n number to compute 68454 * @return {Number} absolute value of given number 68455 * @example 68456 * <div class = "norender"><code> 68457 * function setup() { 68458 * let x = -3; 68459 * let y = abs(x); 68460 * 68461 * print(x); // -3 68462 * print(y); // 3 68463 * } 68464 * </code></div> 68465 * 68466 * @alt 68467 * no image displayed 68468 * 68469 */ 68470 68471 68472 p5.prototype.abs = Math.abs; 68473 /** 68474 * Calculates the closest int value that is greater than or equal to the 68475 * value of the parameter. Maps to Math.ceil(). For example, ceil(9.03) 68476 * returns the value 10. 68477 * 68478 * @method ceil 68479 * @param {Number} n number to round up 68480 * @return {Integer} rounded up number 68481 * @example 68482 * <div><code> 68483 * function draw() { 68484 * background(200); 68485 * // map, mouseX between 0 and 5. 68486 * let ax = map(mouseX, 0, 100, 0, 5); 68487 * let ay = 66; 68488 * 68489 * //Get the ceiling of the mapped number. 68490 * let bx = ceil(map(mouseX, 0, 100, 0, 5)); 68491 * let by = 33; 68492 * 68493 * // Multiply the mapped numbers by 20 to more easily 68494 * // see the changes. 68495 * stroke(0); 68496 * fill(0); 68497 * line(0, ay, ax * 20, ay); 68498 * line(0, by, bx * 20, by); 68499 * 68500 * // Reformat the float returned by map and draw it. 68501 * noStroke(); 68502 * text(nfc(ax, 2), ax, ay - 5); 68503 * text(nfc(bx, 1), bx, by - 5); 68504 * } 68505 * </code></div> 68506 * 68507 * @alt 68508 * 2 horizontal lines & number sets. increase with mouse x. bottom to 2 decimals 68509 * 68510 */ 68511 68512 p5.prototype.ceil = Math.ceil; 68513 /** 68514 * Constrains a value between a minimum and maximum value. 68515 * 68516 * @method constrain 68517 * @param {Number} n number to constrain 68518 * @param {Number} low minimum limit 68519 * @param {Number} high maximum limit 68520 * @return {Number} constrained number 68521 * @example 68522 * <div><code> 68523 * function draw() { 68524 * background(200); 68525 * 68526 * let leftWall = 25; 68527 * let rightWall = 75; 68528 * 68529 * // xm is just the mouseX, while 68530 * // xc is the mouseX, but constrained 68531 * // between the leftWall and rightWall! 68532 * let xm = mouseX; 68533 * let xc = constrain(mouseX, leftWall, rightWall); 68534 * 68535 * // Draw the walls. 68536 * stroke(150); 68537 * line(leftWall, 0, leftWall, height); 68538 * line(rightWall, 0, rightWall, height); 68539 * 68540 * // Draw xm and xc as circles. 68541 * noStroke(); 68542 * fill(150); 68543 * ellipse(xm, 33, 9, 9); // Not Constrained 68544 * fill(0); 68545 * ellipse(xc, 66, 9, 9); // Constrained 68546 * } 68547 * </code></div> 68548 * 68549 * @alt 68550 * 2 vertical lines. 2 ellipses move with mouse X 1 does not move passed lines 68551 * 68552 */ 68553 68554 p5.prototype.constrain = function (n, low, high) { 68555 p5._validateParameters('constrain', arguments); 68556 68557 return Math.max(Math.min(n, high), low); 68558 }; 68559 /** 68560 * Calculates the distance between two points. 68561 * 68562 * @method dist 68563 * @param {Number} x1 x-coordinate of the first point 68564 * @param {Number} y1 y-coordinate of the first point 68565 * @param {Number} x2 x-coordinate of the second point 68566 * @param {Number} y2 y-coordinate of the second point 68567 * @return {Number} distance between the two points 68568 * 68569 * @example 68570 * <div><code> 68571 * // Move your mouse inside the canvas to see the 68572 * // change in distance between two points! 68573 * function draw() { 68574 * background(200); 68575 * fill(0); 68576 * 68577 * let x1 = 10; 68578 * let y1 = 90; 68579 * let x2 = mouseX; 68580 * let y2 = mouseY; 68581 * 68582 * line(x1, y1, x2, y2); 68583 * ellipse(x1, y1, 7, 7); 68584 * ellipse(x2, y2, 7, 7); 68585 * 68586 * // d is the length of the line 68587 * // the distance from point 1 to point 2. 68588 * let d = int(dist(x1, y1, x2, y2)); 68589 * 68590 * // Let's write d along the line we are drawing! 68591 * push(); 68592 * translate((x1 + x2) / 2, (y1 + y2) / 2); 68593 * rotate(atan2(y2 - y1, x2 - x1));
68594 * text(nfc(d, 1), 0, -5); 68595 * pop(); 68596 * // Fancy! 68597 * } 68598 * </code></div> 68599 * 68600 * @alt 68601 * 2 ellipses joined by line. 1 ellipse moves with mouse X&Y. Distance displayed. 68602 */ 68603 68604 /** 68605 * @method dist 68606 * @param {Number} x1 68607 * @param {Number} y1 68608 * @param {Number} z1 z-coordinate of the first point 68609 * @param {Number} x2 68610 * @param {Number} y2 68611 * @param {Number} z2 z-coordinate of the second point 68612 * @return {Number} distance between the two points 68613 */ 68614 68615 68616 p5.prototype.dist = function () { 68617 p5._validateParameters('dist', arguments); 68618 68619 if (arguments.length === 4) { 68620 //2D 68621 return hypot(arguments[2] - arguments[0], arguments[3] - arguments[1]); 68622 } else if (arguments.length === 6) { 68623 //3D 68624 return hypot(arguments[3] - arguments[0], arguments[4] - arguments[1], arguments[5] - arguments[2]); 68625 } 68626 }; 68627 /** 68628 * Returns Euler's number e (2.71828...) raised to the power of the n 68629 * parameter. Maps to Math.exp(). 68630 * 68631 * @method exp 68632 * @param {Number} n exponent to raise 68633 * @return {Number} e^n 68634 * @example 68635 * <div><code> 68636 * function draw() { 68637 * background(200); 68638 * 68639 * // Compute the exp() function with a value between 0 and 2 68640 * let xValue = map(mouseX, 0, width, 0, 2); 68641 * let yValue = exp(xValue); 68642 * 68643 * let y = map(yValue, 0, 8, height, 0); 68644 * 68645 * let legend = 'exp (' + nfc(xValue, 3) + ')\n= ' + nf(yValue, 1, 4); 68646 * stroke(150); 68647 * line(mouseX, y, mouseX, height); 68648 * fill(0); 68649 * text(legend, 5, 15); 68650 * noStroke(); 68651 * ellipse(mouseX, y, 7, 7); 68652 * 68653 * // Draw the exp(x) curve, 68654 * // over the domain of x from 0 to 2 68655 * noFill(); 68656 * stroke(0); 68657 * beginShape(); 68658 * for (let x = 0; x < width; x++) { 68659 * xValue = map(x, 0, width, 0, 2); 68660 * yValue = exp(xValue); 68661 * y = map(yValue, 0, 8, height, 0); 68662 * vertex(x, y); 68663 * } 68664 * 68665 * endShape(); 68666 * line(0, 0, 0, height); 68667 * line(0, height - 1, width, height - 1); 68668 * } 68669 * </code></div> 68670 * 68671 * @alt 68672 * ellipse moves along a curve with mouse x. e^n displayed. 68673 * 68674 */ 68675 68676 68677 p5.prototype.exp = Math.exp; 68678 /** 68679 * Calculates the closest int value that is less than or equal to the 68680 * value of the parameter. Maps to Math.floor(). 68681 * 68682 * @method floor 68683 * @param {Number} n number to round down 68684 * @return {Integer} rounded down number 68685 * @example 68686 * <div><code> 68687 * function draw() { 68688 * background(200); 68689 * //map, mouseX between 0 and 5. 68690 * let ax = map(mouseX, 0, 100, 0, 5); 68691 * let ay = 66; 68692 * 68693 * //Get the floor of the mapped number. 68694 * let bx = floor(map(mouseX, 0, 100, 0, 5)); 68695 * let by = 33; 68696 * 68697 * // Multiply the mapped numbers by 20 to more easily 68698 * // see the changes. 68699 * stroke(0); 68700 * fill(0); 68701 * line(0, ay, ax * 20, ay); 68702 * line(0, by, bx * 20, by); 68703 * 68704 * // Reformat the float returned by map and draw it. 68705 * noStroke(); 68706 * text(nfc(ax, 2), ax, ay - 5); 68707 * text(nfc(bx, 1), bx, by - 5); 68708 * } 68709 * </code></div> 68710 * 68711 * @alt 68712 * 2 horizontal lines & number sets. increase with mouse x. bottom to 2 decimals 68713 * 68714 */ 68715 68716 p5.prototype.floor = Math.floor; 68717 /** 68718 * Calculates a number between two numbers at a specific increment. The amt 68719 * parameter is the amount to interpolate between the two values where 0.0 68720 * equal to the first point, 0.1 is very near the first point, 0.5 is 68721 * half-way in between, and 1.0 is equal to the second point. If the 68722 * value of amt is more than 1.0 or less than 0.0, the number will be 68723 * calculated accordingly in the ratio of the two given numbers. The lerp 68724 * function is convenient for creating motion along a straight 68725 * path and for drawing dotted lines. 68726 * 68727 * @method lerp 68728 * @param {Number} start first value 68729 * @param {Number} stop second value 68730 * @param {Number} amt number 68731 * @return {Number} lerped value 68732 * @example 68733 * <div><code> 68734 * function setup() { 68735 * background(200); 68736 * let a = 20; 68737 * let b = 80; 68738 * let c = lerp(a, b, 0.2); 68739 * let d = lerp(a, b, 0.5); 68740 * let e = lerp(a, b, 0.8); 68741 * 68742 * let y = 50; 68743 * 68744 * strokeWeight(5); 68745 * stroke(0); // Draw the original points in black 68746 * point(a, y); 68747 * point(b, y); 68748 * 68749 * stroke(100); // Draw the lerp points in gray 68750 * point(c, y); 68751 * point(d, y); 68752 * point(e, y); 68753 * } 68754 * </code></div> 68755 * 68756 * @alt 68757 * 5 points horizontally staggered mid-canvas. mid 3 are grey, outer black 68758 * 68759 */ 68760 68761 p5.prototype.lerp = function (start, stop, amt) { 68762 p5._validateParameters('lerp', arguments); 68763 68764 return amt * (stop - start) + start; 68765 }; 68766 /** 68767 * Calculates the natural logarithm (the base-e logarithm) of a number. This 68768 * function expects the n parameter to be a value greater than 0.0. Maps to 68769 * Math.log(). 68770 * 68771 * @method log 68772 * @param {Number} n number greater than 0 68773 * @return {Number} natural logarithm of n 68774 * @example 68775 * <div><code> 68776 * function draw() { 68777 * background(200); 68778 * let maxX = 2.8; 68779 * let maxY = 1.5; 68780 * 68781 * // Compute the natural log of a value between 0 and maxX 68782 * let xValue = map(mouseX, 0, width, 0, maxX); 68783 * let yValue, y; 68784 * if (xValue > 0) { 68785 // Cannot take the log of a negative number. 68786 * yValue = log(xValue); 68787 * y = map(yValue, -maxY, maxY, height, 0); 68788 * 68789 * // Display the calculation occurring. 68790 * let legend = 'log(' + nf(xValue, 1, 2) + ')\n= ' + nf(yValue, 1, 3); 68791 * stroke(150); 68792 * line(mouseX, y, mouseX, height); 68793 * fill(0); 68794 * text(legend, 5, 15); 68795 * noStroke(); 68796 * ellipse(mouseX, y, 7, 7); 68797 * } 68798 * 68799 * // Draw the log(x) curve, 68800 * // over the domain of x from 0 to maxX 68801 * noFill(); 68802 * stroke(0); 68803 * beginShape(); 68804 * for (let x = 0; x < width; x++) { 68805 * xValue = map(x, 0, width, 0, maxX); 68806 * yValue = log(xValue); 68807 * y = map(yValue, -maxY, maxY, height, 0); 68808 * vertex(x, y); 68809 * } 68810 * endShape(); 68811 * line(0, 0, 0, height); 68812 * line(0, height / 2, width, height / 2); 68813 * } 68814 * </code></div> 68815 * 68816 * @alt 68817 * ellipse moves along a curve with mouse x. natural logarithm of n displayed. 68818 * 68819 */ 68820 68821 68822 p5.prototype.log = Math.log; 68823 /** 68824 * Calculates the magnitude (or length) of a vector. A vector is a direction 68825 * in space commonly used in computer graphics and linear algebra. Because it 68826 * has no "start" position, the magnitude of a vector can be thought of as 68827 * the distance from the coordinate 0,0 to its x,y value. Therefore, <a href="#/p5/mag">mag()</a> is 68828 * a shortcut for writing dist(0, 0, x, y). 68829 * 68830 * @method mag 68831 * @param {Number} a first value 68832 * @param {Number} b second value 68833 * @return {Number} magnitude of vector from (0,0) to (a,b) 68834 * @example 68835 * <div><code> 68836 * function setup() { 68837 * let x1 = 20; 68838 * let x2 = 80; 68839 * let y1 = 30; 68840 * let y2 = 70; 68841 * 68842 * line(0, 0, x1, y1); 68843 * print(mag(x1, y1)); // Prints "36.05551275463989" 68844 * line(0, 0, x2, y1); 68845 * print(mag(x2, y1)); // Prints "85.44003745317531" 68846 * line(0, 0, x1, y2); 68847 * print(mag(x1, y2)); // Prints "72.80109889280519" 68848 * line(0, 0, x2, y2); 68849 * print(mag(x2, y2)); // Prints "106.3014581273465" 68850 * } 68851 * </code></div> 68852 * 68853 * @alt 68854 * 4 lines of different length radiate from top left of canvas. 68855 * 68856 */ 68857 68858 p5.prototype.mag = function (x, y) { 68859 p5._validateParameters('mag', arguments); 68860 68861 return hypot(x, y); 68862 }; 68863 /** 68864 * Re-maps a number from one range to another. 68865 * <br><br> 68866 * In the first example above, the number 25 is converted from a value in the 68867 * range of 0 to 100 into a value that ranges from the left edge of the 68868 * window (0) to the right edge (width). 68869 * 68870 * @method map 68871 * @param {Number} value the incoming value to be converted 68872 * @param {Number} start1 lower bound of the value's current range 68873 * @param {Number} stop1 upper bound of the value's current range 68874 * @param {Number} start2 lower bound of the value's target range 68875 * @param {Number} stop2 upper bound of the value's target range 68876 * @param {Boolean} [withinBounds] constrain the value to the newly mapped range 68877 * @return {Number} remapped number 68878 * @example 68879 * <div><code> 68880 * let value = 25; 68881 * let m = map(value, 0, 100, 0, width); 68882 * ellipse(m, 50, 10, 10); 68883 </code></div> 68884 * 68885 * <div><code> 68886 * function setup() { 68887 * noStroke(); 68888 * } 68889 * 68890 * function draw() { 68891 * background(204); 68892 * let x1 = map(mouseX, 0, width, 25, 75); 68893 * ellipse(x1, 25, 25, 25); 68894 * //This ellipse is constrained to the 0-100 range 68895 * //after setting withinBounds to true 68896 * let x2 = map(mouseX, 0, width, 0, 100, true); 68897 * ellipse(x2, 75, 25, 25); 68898 * } 68899 </code></div> 68900 * 68901 * @alt 68902 * 10 by 10 white ellipse with in mid left canvas 68903 * 2 25 by 25 white ellipses move with mouse x. Bottom has more range from X 68904 * 68905 */ 68906 68907 68908 p5.prototype.map = function (n, start1, stop1, start2, stop2, withinBounds) { 68909 p5._validateParameters('map', arguments); 68910 68911 var newval = (n - start1) / (stop1 - start1) * (stop2 - start2) + start2; 68912 68913 if (!withinBounds) { 68914 return newval; 68915 } 68916 68917 if (start2 < stop2) { 68918 return this.constrain(newval, start2, stop2); 68919 } else { 68920 return this.constrain(newval, stop2, start2); 68921 } 68922 }; 68923 /** 68924 * Determines the largest value in a sequence of numbers, and then returns 68925 * that value. <a href="#/p5/max">max()</a> accepts any number of Number parameters, or an Array 68926 * of any length. 68927 * 68928 * @method max 68929 * @param {Number} n0 Number to compare 68930 * @param {Number} n1 Number to compare 68931 * @return {Number} maximum Number 68932 * @example 68933 * <div><code> 68934 * function setup() { 68935 * // Change the elements in the array and run the sketch 68936 * // to show how max() works! 68937 * let numArray = [2, 1, 5, 4, 8, 9]; 68938 * fill(0); 68939 * noStroke(); 68940 * text('Array Elements', 0, 10); 68941 * // Draw all numbers in the array 68942 * let spacing = 15; 68943 * let elemsY = 25; 68944 * for (let i = 0; i < numArray.length; i++) { 68945 * text(numArray[i], i * spacing, elemsY); 68946 * } 68947 * let maxX = 33; 68948 * let maxY = 80; 68949 * // Draw the Maximum value in the array. 68950 * textSize(32); 68951 * text(max(numArray), maxX, maxY); 68952 * } 68953 * </code></div> 68954 * 68955 * @alt 68956 * Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 9 68957 * 68958 */ 68959 68960 /** 68961 * @method max 68962 * @param {Number[]} nums Numbers to compare 68963 * @return {Number} 68964 */ 68965 68966 68967 p5.prototype.max = function () { 68968 p5._validateParameters('max', arguments); 68969 68970 if (arguments[0] instanceof Array) { 68971 return Math.max.apply(null, arguments[0]); 68972 } else { 68973 return Math.max.apply(null, arguments); 68974 } 68975 }; 68976 /** 68977 * Determines the smallest value in a sequence of numbers, and then returns 68978 * that value. <a href="#/p5/min">min()</a> accepts any number of Number parameters, or an Array 68979 * of any length. 68980 * 68981 * @method min 68982 * @param {Number} n0 Number to compare 68983 * @param {Number} n1 Number to compare 68984 * @return {Number} minimum Number 68985 * @example 68986 * <div><code> 68987 * function setup() { 68988 * // Change the elements in the array and run the sketch 68989 * // to show how min() works! 68990 * let numArray = [2, 1, 5, 4, 8, 9]; 68991 * fill(0); 68992 * noStroke(); 68993 * text('Array Elements', 0, 10); 68994 * // Draw all numbers in the array 68995 * let spacing = 15; 68996 * let elemsY = 25; 68997 * for (let i = 0; i < numArray.length; i++) { 68998 * text(numArray[i], i * spacing, elemsY); 68999 * } 69000 * let maxX = 33; 69001 * let maxY = 80; 69002 * // Draw the Minimum value in the array. 69003 * textSize(32); 69004 * text(min(numArray), maxX, maxY); 69005 * } 69006 * </code></div> 69007 * 69008 * @alt 69009 * Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 1 69010 * 69011 */ 69012 69013 /** 69014 * @method min 69015 * @param {Number[]} nums Numbers to compare 69016 * @return {Number} 69017 */ 69018 69019 69020 p5.prototype.min = function () { 69021 p5._validateParameters('min', arguments); 69022 69023 if (arguments[0] instanceof Array) { 69024 return Math.min.apply(null, arguments[0]); 69025 } else { 69026 return Math.min.apply(null, arguments); 69027 } 69028 }; 69029 /** 69030 * Normalizes a number from another range into a value between 0 and 1. 69031 * Identical to map(value, low, high, 0, 1). 69032 * Numbers outside of the range are not clamped to 0 and 1, because 69033 * out-of-range values are often intentional and useful. (See the second 69034 * example above.) 69035 * 69036 * @method norm 69037 * @param {Number} value incoming value to be normalized 69038 * @param {Number} start lower bound of the value's current range 69039 * @param {Number} stop upper bound of the value's current range 69040 * @return {Number} normalized number 69041 * @example 69042 * <div><code> 69043 * function draw() { 69044 * background(200); 69045 * let currentNum = mouseX; 69046 * let lowerBound = 0; 69047 * let upperBound = width; //100; 69048 * let normalized = norm(currentNum, lowerBound, upperBound); 69049 * let lineY = 70; 69050 * line(0, lineY, width, lineY); 69051 * //Draw an ellipse mapped to the non-normalized value. 69052 * noStroke(); 69053 * fill(50); 69054 * let s = 7; // ellipse size 69055 * ellipse(currentNum, lineY, s, s); 69056 * 69057 * // Draw the guide 69058 * let guideY = lineY + 15; 69059 * text('0', 0, guideY); 69060 * textAlign(RIGHT); 69061 * text('100', width, guideY); 69062 * 69063 * // Draw the normalized value 69064 * textAlign(LEFT); 69065 * fill(0); 69066 * textSize(32); 69067 * let normalY = 40; 69068 * let normalX = 20; 69069 * text(normalized, normalX, normalY); 69070 * } 69071 * </code></div> 69072 * 69073 * @alt 69074 * ellipse moves with mouse. 0 shown left & 100 right and updating values center 69075 * 69076 */ 69077 69078 69079 p5.prototype.norm = function (n, start, stop) { 69080 p5._validateParameters('norm', arguments); 69081 69082 return this.map(n, start, stop, 0, 1); 69083 }; 69084 /** 69085 * Facilitates exponential expressions. The <a href="#/p5/pow">pow()</a>
69085 function is an efficient 69086 * way of multiplying numbers by themselves (or their reciprocals) in large 69087 * quantities. For example, pow(3, 5) is equivalent to the expression 69088 * 3*3*3*3*3 and pow(3, -5) is equivalent to 1 / 3*3*3*3*3. Maps to 69089 * Math.pow(). 69090 * 69091 * @method pow 69092 * @param {Number} n base of the exponential expression 69093 * @param {Number} e power by which to raise the base 69094 * @return {Number} n^e 69095 * @example 69096 * <div><code> 69097 * function setup() { 69098 * //Exponentially increase the size of an ellipse. 69099 * let eSize = 3; // Original Size 69100 * let eLoc = 10; // Original Location 69101 * 69102 * ellipse(eLoc, eLoc, eSize, eSize); 69103 * 69104 * ellipse(eLoc * 2, eLoc * 2, pow(eSize, 2), pow(eSize, 2)); 69105 * 69106 * ellipse(eLoc * 4, eLoc * 4, pow(eSize, 3), pow(eSize, 3)); 69107 * 69108 * ellipse(eLoc * 8, eLoc * 8, pow(eSize, 4), pow(eSize, 4)); 69109 * } 69110 * </code></div> 69111 * 69112 * @alt 69113 * small to large ellipses radiating from top left of canvas 69114 * 69115 */ 69116 69117 69118 p5.prototype.pow = Math.pow; 69119 /** 69120 * Calculates the integer closest to the n parameter. For example, 69121 * round(133.8) returns the value 134. Maps to Math.round(). 69122 * 69123 * @method round 69124 * @param {Number} n number to round 69125 * @return {Integer} rounded number 69126 * @example 69127 * <div><code> 69128 * function draw() { 69129 * background(200); 69130 * //map, mouseX between 0 and 5. 69131 * let ax = map(mouseX, 0, 100, 0, 5); 69132 * let ay = 66; 69133 * 69134 * // Round the mapped number. 69135 * let bx = round(map(mouseX, 0, 100, 0, 5)); 69136 * let by = 33; 69137 * 69138 * // Multiply the mapped numbers by 20 to more easily 69139 * // see the changes. 69140 * stroke(0); 69141 * fill(0); 69142 * line(0, ay, ax * 20, ay); 69143 * line(0, by, bx * 20, by); 69144 * 69145 * // Reformat the float returned by map and draw it. 69146 * noStroke(); 69147 * text(nfc(ax, 2), ax, ay - 5); 69148 * text(nfc(bx, 1), bx, by - 5); 69149 * } 69150 * </code></div> 69151 * 69152 * @alt 69153 * horizontal center line squared values displayed on top and regular on bottom. 69154 * 69155 */ 69156 69157 p5.prototype.round = Math.round; 69158 /** 69159 * Squares a number (multiplies a number by itself). The result is always a 69160 * positive number, as multiplying two negative numbers always yields a 69161 * positive result. For example, -1 * -1 = 1. 69162 * 69163 * @method sq 69164 * @param {Number} n number to square 69165 * @return {Number} squared number 69166 * @example 69167 * <div><code> 69168 * function draw() { 69169 * background(200); 69170 * let eSize = 7; 69171 * let x1 = map(mouseX, 0, width, 0, 10); 69172 * let y1 = 80; 69173 * let x2 = sq(x1); 69174 * let y2 = 20; 69175 * 69176 * // Draw the non-squared. 69177 * line(0, y1, width, y1); 69178 * ellipse(x1, y1, eSize, eSize); 69179 * 69180 * // Draw the squared. 69181 * line(0, y2, width, y2); 69182 * ellipse(x2, y2, eSize, eSize); 69183 * 69184 * // Draw dividing line. 69185 * stroke(100); 69186 * line(0, height / 2, width, height / 2); 69187 * 69188 * // Draw text. 69189 * let spacing = 15; 69190 * noStroke(); 69191 * fill(0); 69192 * text('x = ' + x1, 0, y1 + spacing); 69193 * text('sq(x) = ' + x2, 0, y2 + spacing); 69194 * } 69195 * </code></div> 69196 * 69197 * @alt 69198 * horizontal center line squared values displayed on top and regular on bottom. 69199 * 69200 */ 69201 69202 p5.prototype.sq = function (n) { 69203 return n * n; 69204 }; 69205 /** 69206 * Calculates the square root of a number. The square root of a number is 69207 * always positive, even though there may be a valid negative root. The 69208 * square root s of number a is such that s*s = a. It is the opposite of 69209 * squaring. Maps to Math.sqrt(). 69210 * 69211 * @method sqrt 69212 * @param {Number} n non-negative number to square root 69213 * @return {Number} square root of number 69214 * @example 69215 * <div><code> 69216 * function draw() { 69217 * background(200); 69218 * let eSize = 7; 69219 * let x1 = mouseX; 69220 * let y1 = 80; 69221 * let x2 = sqrt(x1); 69222 * let y2 = 20; 69223 * 69224 * // Draw the non-squared. 69225 * line(0, y1, width, y1); 69226 * ellipse(x1, y1, eSize, eSize); 69227 * 69228 * // Draw the squared. 69229 * line(0, y2, width, y2); 69230 * ellipse(x2, y2, eSize, eSize); 69231 * 69232 * // Draw dividing line. 69233 * stroke(100); 69234 * line(0, height / 2, width, height / 2); 69235 * 69236 * // Draw text. 69237 * noStroke(); 69238 * fill(0); 69239 * let spacing = 15; 69240 * text('x = ' + x1, 0, y1 + spacing); 69241 * text('sqrt(x) = ' + x2, 0, y2 + spacing); 69242 * } 69243 * </code></div> 69244 * 69245 * @alt 69246 * horizontal center line squareroot values displayed on top and regular on bottom. 69247 * 69248 */ 69249 69250 69251 p5.prototype.sqrt = Math.sqrt; // Calculate the length of the hypotenuse of a right triangle 69252 // This won't under- or overflow in intermediate steps 69253 // https://en.wikipedia.org/wiki/Hypot 69254 69255 function hypot(x, y, z) { 69256 // Use the native implementation if it's available 69257 if (typeof Math.hypot === 'function') { 69258 return Math.hypot.apply(null, arguments); 69259 } // Otherwise use the V8 implementation 69260 // https://github.com/v8/v8/blob/8cd3cf297287e581a49e487067f5cbd991b27123/src/js/math.js#L217 69261 69262 69263 var length = arguments.length; 69264 var args = []; 69265 var max = 0; 69266 69267 for (var i = 0; i < length; i++) { 69268 var n = arguments[i]; 69269 n = +n; 69270 69271 if (n === Infinity || n === -Infinity) { 69272 return Infinity; 69273 } 69274 69275 n = Math.abs(n); 69276 69277 if (n > max) { 69278 max = n; 69279 } 69280 69281 args[i] = n; 69282 } 69283 69284 if (max === 0) { 69285 max = 1; 69286 } 69287 69288 var sum = 0; 69289 var compensation = 0; 69290 69291 for (var j = 0; j < length; j++) { 69292 var m = args[j] / max; 69293 var summand = m * m - compensation; 69294 var preliminary = sum + summand; 69295 compensation = preliminary - sum - summand; 69296 sum = preliminary; 69297 } 69298 69299 return Math.sqrt(sum) * max; 69300 } 69301 69302 module.exports = p5; 69303 }, {
69304 "../core/main": 24 69305 }], 69306 52: [function (_dereq_, module, exports) { 69307 /** 69308 * @module Math 69309 * @submodule Math 69310 * @for p5 69311 * @requires core 69312 */ 69313 'use strict'; 69314 69315 var p5 = _dereq_('../core/main'); 69316 /** 69317 * Creates a new <a href="#/p5.Vector">p5.Vector</a> (the datatype for storing vectors). This provides a 69318 * two or three dimensional vector, specifically a Euclidean (also known as 69319 * geometric) vector. A vector is an entity that has both magnitude and 69320 * direction. 69321 * 69322 * @method createVector 69323 * @param {Number} [x] x component of the vector 69324 * @param {Number} [y] y component of the vector 69325 * @param {Number} [z] z component of the vector 69326 * @return {p5.Vector} 69327 * @example 69328 * <div modernizr='webgl'><code> 69329 * function setup() { 69330 * createCanvas(100, 100, WEBGL); 69331 * noStroke(); 69332 * fill(255, 102, 204); 69333 * } 69334 * 69335 * function draw() { 69336 * background(255); 69337 * pointLight(color(255), createVector(sin(millis() / 1000) * 20, -40, -10)); 69338 * scale(0.75); 69339 * sphere(); 69340 * } 69341 * </code></div> 69342 * 69343 * @alt 69344 * a purple sphere lit by a point light oscillating horizontally 69345 */ 69346 69347 69348 p5.prototype.createVector = function (x, y, z) { 69349 if (this instanceof p5) { 69350 return new p5.Vector(this, arguments); 69351 } else { 69352 return new p5.Vector(x, y, z); 69353 } 69354 }; 69355 69356 module.exports = p5; 69357 }, {
69358 "../core/main": 24 69359 }], 69360 53: [function (_dereq_, module, exports) { 69361 ////////////////////////////////////////////////////////////// 69362 // http://mrl.nyu.edu/~perlin/noise/ 69363 // Adapting from PApplet.java 69364 // which was adapted from toxi 69365 // which was adapted from the german demo group farbrausch 69366 // as used in their demo "art": http://www.farb-rausch.de/fr010src.zip 69367 // someday we might consider using "improved noise" 69368 // http://mrl.nyu.edu/~perlin/paper445.pdf 69369 // See: https://github.com/shiffman/The-Nature-of-Code-Examples-p5.js/ 69370 // blob/master/introduction/Noise1D/noise.js 69371 69372 /** 69373 * @module Math 69374 * @submodule Noise 69375 * @for p5 69376 * @requires core 69377 */ 69378 'use strict'; 69379 69380 var p5 = _dereq_('../core/main'); 69381 69382 var PERLIN_YWRAPB = 4; 69383 var PERLIN_YWRAP = 1 << PERLIN_YWRAPB; 69384 var PERLIN_ZWRAPB = 8; 69385 var PERLIN_ZWRAP = 1 << PERLIN_ZWRAPB; 69386 var PERLIN_SIZE = 4095; 69387 var perlin_octaves = 4; // default to medium smooth 69388 69389 var perlin_amp_falloff = 0.5; // 50% reduction/octave 69390 69391 var scaled_cosine = function (i) { 69392 return 0.5 * (1.0 - Math.cos(i * Math.PI)); 69393 }; 69394 69395 var perlin; // will be initialized lazily by noise() or noiseSeed() 69396 69397 /** 69398 * Returns the Perlin noise value at specified coordinates. Perlin noise is 69399 * a random sequence generator producing a more natural ordered, harmonic 69400 * succession of numbers compared to the standard <b>random()</b> function. 69401 * It was invented by Ken Perlin in the 1980s and been used since in 69402 * graphical applications to produce procedural textures, natural motion, 69403 * shapes, terrains etc.<br /><br /> The main difference to the 69404 * <b>random()</b> function is that Perlin noise is defined in an infinite 69405 * n-dimensional space where each pair of coordinates corresponds to a 69406 * fixed semi-random value (fixed only for the lifespan of the program; see 69407 * the <a href="#/p5/noiseSeed">noiseSeed()</a> function). p5.js can compute 1D, 2D and 3D noise, 69408 * depending on the number of coordinates given. The resulting value will 69409 * always be between 0.0 and 1.0. The noise value can be animated by moving 69410 * through the noise space as demonstrated in the example above. The 2nd 69411 * and 3rd dimension can also be interpreted as time.<br /><br />The actual 69412 * noise is structured similar to an audio signal, in respect to the 69413 * function's use of frequencies. Similar to the concept of harmonics in 69414 * physics, perlin noise is computed over several octaves which are added 69415 * together for the final result. <br /><br />Another way to adjust the 69416 * character of the resulting sequence is the scale of the input 69417 * coordinates. As the function works within an infinite space the value of 69418 * the coordinates doesn't matter as such, only the distance between 69419 * successive coordinates does (eg. when using <b>noise()</b> within a 69420 * loop). As a general rule the smaller the difference between coordinates, 69421 * the smoother the resulting noise sequence will be. Steps of 0.005-0.03 69422 * work best for most applications, but this will differ depending on use. 69423 * 69424 * 69425 * @method noise 69426 * @param {Number} x x-coordinate in noise space 69427 * @param {Number} [y] y-coordinate in noise space 69428 * @param {Number} [z] z-coordinate in noise space 69429 * @return {Number} Perlin noise value (between 0 and 1) at specified 69430 * coordinates 69431 * @example 69432 * <div> 69433 * <code> 69434 * let xoff = 0.0; 69435 * 69436 * function draw() { 69437 * background(204); 69438 * xoff = xoff + 0.01; 69439 * let n = noise(xoff) * width; 69440 * line(n, 0, n, height); 69441 * } 69442 * </code> 69443 * </div> 69444 * <div> 69445 * <code>let noiseScale=0.02; 69446 * 69447 * function draw() { 69448 * background(0); 69449 * for (let x=0; x < width; x++) { 69450 * let noiseVal = noise((mouseX+x)*noiseScale, mouseY*noiseScale); 69451 * stroke(noiseVal*255); 69452 * line(x, mouseY+noiseVal*80, x, height); 69453 * } 69454 * } 69455 * </code> 69456 * </div> 69457 * 69458 * @alt 69459 * vertical line moves left to right with updating noise values. 69460 * horizontal wave pattern effected by mouse x-position & updating noise values. 69461 * 69462 */ 69463 69464 p5.prototype.noise = function (x, y, z) { 69465 y = y || 0; 69466 z = z || 0; 69467 69468 if (perlin == null) { 69469 perlin = new Array(PERLIN_SIZE + 1); 69470 69471 for (var i = 0; i < PERLIN_SIZE + 1; i++) { 69472 perlin[i] = Math.random(); 69473 } 69474 } 69475 69476 if (x < 0) { 69477 x = -x; 69478 } 69479 69480 if (y < 0) { 69481 y = -y; 69482 } 69483 69484 if (z < 0) { 69485 z = -z; 69486 } 69487 69488 var xi = Math.floor(x), 69489 yi = Math.floor(y), 69490 zi = Math.floor(z); 69491 var xf = x - xi; 69492 var yf = y - yi; 69493 var zf = z - zi; 69494 var rxf, ryf; 69495 var r = 0; 69496 var ampl = 0.5; 69497 var n1, n2, n3; 69498 69499 for (var o = 0; o < perlin_octaves; o++) { 69500 var of = xi + (yi << PERLIN_YWRAPB) + (zi << PERLIN_ZWRAPB); 69501 rxf = scaled_cosine(xf); 69502 ryf = scaled_cosine(yf); 69503 n1 = perlin[of & PERLIN_SIZE]; 69504 n1 += rxf * (perlin[of + 1 & PERLIN_SIZE] - n1); 69505 n2 = perlin[of + PERLIN_YWRAP & PERLIN_SIZE]; 69506 n2 += rxf * (perlin[of + PERLIN_YWRAP + 1 & PERLIN_SIZE] - n2); 69507 n1 += ryf * (n2 - n1); 69508 of += PERLIN_ZWRAP; 69509 n2 = perlin[of & PERLIN_SIZE]; 69510 n2 += rxf * (perlin[of + 1 & PERLIN_SIZE] - n2); 69511 n3 = perlin[of + PERLIN_YWRAP & PERLIN_SIZE]; 69512 n3 += rxf * (perlin[of + PERLIN_YWRAP + 1 & PERLIN_SIZE] - n3); 69513 n2 += ryf * (n3 - n2); 69514 n1 += scaled_cosine(zf) * (n2 - n1); 69515 r += n1 * ampl; 69516 ampl *= perlin_amp_falloff; 69517 xi <<= 1; 69518 xf *= 2; 69519 yi <<= 1; 69520 yf *= 2; 69521 zi <<= 1; 69522 zf *= 2; 69523 69524 if (xf >= 1.0) { 69525 xi++; 69526 xf--; 69527 } 69528 69529 if (yf >= 1.0) { 69530 yi++; 69531 yf--; 69532 } 69533 69534 if (zf >= 1.0) { 69535 zi++; 69536 zf--; 69537 } 69538 } 69539 69540 return r; 69541 }; 69542 /** 69543 * 69544 * Adjusts the character and level of detail produced by the Perlin noise 69545 * function. Similar to harmonics in physics, noise is computed over 69546 * several octaves. Lower octaves contribute more to the output signal and 69547 * as such define the overall intensity of the noise, whereas higher octaves 69548 * create finer grained details in the noise sequence. 69549 * <br><br> 69550 * By default, noise is computed over 4 octaves with each octave contributing 69551 * exactly half than its predecessor, starting at 50% strength for the 1st 69552 * octave. This falloff amount can be changed by adding an additional function 69553 * parameter. Eg. a falloff factor of 0.75 means each octave will now have 69554 * 75% impact (25% less) of the previous lower octave. Any value between 69555 * 0.0 and 1.0 is valid, however note that values greater than 0.5 might 69556 * result in greater than 1.0 values returned by <b>noise()</b>. 69557 * <br><br> 69558 * By changing these parameters, the signal created by the <b>noise()</b> 69559 * function can be adapted to fit very specific needs and characteristics. 69560 * 69561 * @method noiseDetail 69562 * @param {Number} lod number of octaves to be used by the noise 69563 * @param {Number} falloff falloff factor for each octave 69564 * @example 69565 * <div> 69566 * <code> 69567 * let noiseVal; 69568 * let noiseScale = 0.02; 69569 * 69570 * function setup() { 69571 * createCanvas(100, 100); 69572 * } 69573 * 69574 * function draw() { 69575 * background(0); 69576 * for (let y = 0; y < height; y++) { 69577 * for (let x = 0; x < width / 2; x++) { 69578 * noiseDetail(2, 0.2); 69579 * noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); 69580 * stroke(noiseVal * 255); 69581 * point(x, y); 69582 * noiseDetail(8, 0.65); 69583 * noiseVal = noise( 69584 * (mouseX + x + width / 2) * noiseScale, 69585 * (mouseY + y) * noiseScale 69586 * ); 69587 * stroke(noiseVal * 255); 69588 * point(x + width / 2, y); 69589 * } 69590 * } 69591 * } 69592 * </code> 69593 * </div> 69594 * 69595 * @alt 69596 * 2 vertical grey smokey patterns affected my mouse x-position and noise. 69597 * 69598 */ 69599 69600 69601 p5.prototype.noiseDetail = function (lod, falloff) { 69602 if (lod > 0) { 69603 perlin_octaves = lod; 69604 } 69605 69606 if (falloff > 0) { 69607 perlin_amp_falloff = falloff; 69608 } 69609 }; 69610 /** 69611 * Sets the seed value for <b>noise()</b>. By default, <b>noise()</b> 69612 * produces different results each time the program is run. Set the 69613 * <b>value</b> parameter to a constant to return the same pseudo-random
69614 * numbers each time the software is run. 69615 * 69616 * @method noiseSeed 69617 * @param {Number} seed the seed value 69618 * @example 69619 * <div> 69620 * <code>let xoff = 0.0; 69621 * 69622 * function setup() { 69623 * noiseSeed(99); 69624 * stroke(0, 10); 69625 * } 69626 * 69627 * function draw() { 69628 * xoff = xoff + .01; 69629 * let n = noise(xoff) * width; 69630 * line(n, 0, n, height); 69631 * } 69632 * </code> 69633 * </div> 69634 * 69635 * @alt 69636 * vertical grey lines drawing in pattern affected by noise. 69637 * 69638 */ 69639 69640 69641 p5.prototype.noiseSeed = function (seed) { 69642 // Linear Congruential Generator 69643 // Variant of a Lehman Generator 69644 var lcg = function () { 69645 // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes 69646 // m is basically chosen to be large (as it is the max period) 69647 // and for its relationships to a and c 69648 var m = 4294967296; // a - 1 should be divisible by m's prime factors 69649 69650 var a = 1664525; // c and m should be co-prime 69651 69652 var c = 1013904223; 69653 var seed, z; 69654 return { 69655 setSeed: function (val) { 69656 // pick a random seed if val is undefined or null 69657 // the >>> 0 casts the seed to an unsigned 32-bit integer 69658 z = seed = (val == null ? Math.random() * m : val) >>> 0; 69659 }, 69660 getSeed: function () { 69661 return seed; 69662 }, 69663 rand: function () { 69664 // define the recurrence relationship 69665 z = (a * z + c) % m; // return a float in [0, 1) 69666 // if z = m then z / m = 0 therefore (z % m) / m < 1 always 69667 69668 return z / m; 69669 } 69670 }; 69671 }(); 69672 69673 lcg.setSeed(seed); 69674 perlin = new Array(PERLIN_SIZE + 1); 69675 69676 for (var i = 0; i < PERLIN_SIZE + 1; i++) { 69677 perlin[i] = lcg.rand(); 69678 } 69679 }; 69680 69681 module.exports = p5; 69682 }, {
69683 "../core/main": 24 69684 }], 69685 54: [function (_dereq_, module, exports) { 69686 /** 69687 * @module Math 69688 * @submodule Math 69689 * @requires constants 69690 */ 69691 'use strict'; 69692 69693 var p5 = _dereq_('../core/main'); 69694 69695 var constants = _dereq_('../core/constants'); 69696 /** 69697 * A class to describe a two or three dimensional vector, specifically 69698 * a Euclidean (also known as geometric) vector. A vector is an entity 69699 * that has both magnitude and direction. The datatype, however, stores 69700 * the components of the vector (x, y for 2D, and x, y, z for 3D). The magnitude 69701 * and direction can be accessed via the methods <a href="#/p5/mag">mag()</a> and <a href="#/p5/heading">heading()</a>. 69702 * <br><br> 69703 * In many of the p5.js examples, you will see <a href="#/p5.Vector">p5.Vector</a> used to describe a 69704 * position, velocity, or acceleration. For example, if you consider a rectangle 69705 * moving across the screen, at any given instant it has a position (a vector 69706 * that points from the origin to its location), a velocity (the rate at which 69707 * the object's position changes per time unit, expressed as a vector), and 69708 * acceleration (the rate at which the object's velocity changes per time 69709 * unit, expressed as a vector). 69710 * <br><br> 69711 * Since vectors represent groupings of values, we cannot simply use 69712 * traditional addition/multiplication/etc. Instead, we'll need to do some 69713 * "vector" math, which is made easy by the methods inside the <a href="#/p5.Vector">p5.Vector</a> class. 69714 * 69715 * @class p5.Vector 69716 * @param {Number} [x] x component of the vector 69717 * @param {Number} [y] y component of the vector 69718 * @param {Number} [z] z component of the vector 69719 * @example 69720 * <div> 69721 * <code> 69722 * let v1 = createVector(40, 50); 69723 * let v2 = createVector(40, 50); 69724 * 69725 * ellipse(v1.x, v1.y, 50, 50); 69726 * ellipse(v2.x, v2.y, 50, 50); 69727 * v1.add(v2); 69728 * ellipse(v1.x, v1.y, 50, 50); 69729 * </code> 69730 * </div> 69731 * 69732 * @alt 69733 * 2 white ellipses. One center-left the other bottom right and off canvas 69734 * 69735 */ 69736 69737 69738 p5.Vector = function Vector() { 69739 var x, y, z; // This is how it comes in with createVector() 69740 69741 if (arguments[0] instanceof p5) { 69742 // save reference to p5 if passed in 69743 this.p5 = arguments[0]; 69744 x = arguments[1][0] || 0; 69745 y = arguments[1][1] || 0; 69746 z = arguments[1][2] || 0; // This is what we'll get with new p5.Vector() 69747 } else { 69748 x = arguments[0] || 0; 69749 y = arguments[1] || 0; 69750 z = arguments[2] || 0; 69751 } 69752 /** 69753 * The x component of the vector 69754 * @property x {Number} 69755 */ 69756 69757 69758 this.x = x; 69759 /** 69760 * The y component of the vector 69761 * @property y {Number} 69762 */ 69763 69764 this.y = y; 69765 /** 69766 * The z component of the vector 69767 * @property z {Number} 69768 */ 69769 69770 this.z = z; 69771 }; 69772 /** 69773 * Returns a string representation of a vector v by calling String(v) 69774 * or v.toString(). This method is useful for logging vectors in the 69775 * console. 69776 * @method toString 69777 * @return {String} 69778 * @example 69779 * <div class = "norender"> 69780 * <code> 69781 * function setup() { 69782 * let v = createVector(20, 30); 69783 * print(String(v)); // prints "p5.Vector Object : [20, 30, 0]" 69784 * } 69785 * </code> 69786 * </div> 69787 * 69788 * <div> 69789 * <code> 69790 * function draw() { 69791 * background(240); 69792 * 69793 * let v0 = createVector(0, 0); 69794 * let v1 = createVector(mouseX, mouseY); 69795 * drawArrow(v0, v1, 'black'); 69796 * 69797 * noStroke(); 69798 * text(v1.toString(), 10, 25, 90, 75); 69799 * } 69800 * 69801 * // draw an arrow for a vector at a given base position 69802 * function drawArrow(base, vec, myColor) { 69803 * push(); 69804 * stroke(myColor); 69805 * strokeWeight(3); 69806 * fill(myColor); 69807 * translate(base.x, base.y); 69808 * line(0, 0, vec.x, vec.y); 69809 * rotate(vec.heading()); 69810 * let arrowSize = 7; 69811 * translate(vec.mag() - arrowSize, 0); 69812 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 69813 * pop(); 69814 * } 69815 * </code> 69816 * </div> 69817 */ 69818 69819 69820 p5.Vector.prototype.toString = function p5VectorToString() { 69821 return 'p5.Vector Object : [' + this.x + ', ' + this.y + ', ' + this.z + ']'; 69822 }; 69823 /** 69824 * Sets the x, y, and z component of the vector using two or three separate 69825 * variables, the data from a <a href="#/p5.Vector">p5.Vector</a>, or the values from a float array. 69826 * @method set 69827 * @param {Number} [x] the x component of the vector 69828 * @param {Number} [y] the y component of the vector 69829 * @param {Number} [z] the z component of the vector 69830 * @chainable 69831 * @example 69832 * <div class="norender"> 69833 * <code> 69834 * function setup() { 69835 * let v = createVector(1, 2, 3);
69836 * v.set(4, 5, 6); // Sets vector to [4, 5, 6] 69837 * 69838 * let v1 = createVector(0, 0, 0); 69839 * let arr = [1, 2, 3]; 69840 * v1.set(arr); // Sets vector to [1, 2, 3] 69841 * } 69842 * </code> 69843 * </div> 69844 * 69845 * <div> 69846 * <code> 69847 * let v0, v1; 69848 * function setup() { 69849 * createCanvas(100, 100); 69850 * 69851 * v0 = createVector(0, 0); 69852 * v1 = createVector(50, 50); 69853 * } 69854 * 69855 * function draw() { 69856 * background(240); 69857 * 69858 * drawArrow(v0, v1, 'black'); 69859 * v1.set(v1.x + random(-1, 1), v1.y + random(-1, 1)); 69860 * 69861 * noStroke(); 69862 * text('x: ' + round(v1.x) + ' y: ' + round(v1.y), 20, 90); 69863 * } 69864 * 69865 * // draw an arrow for a vector at a given base position 69866 * function drawArrow(base, vec, myColor) { 69867 * push(); 69868 * stroke(myColor); 69869 * strokeWeight(3); 69870 * fill(myColor); 69871 * translate(base.x, base.y); 69872 * line(0, 0, vec.x, vec.y); 69873 * rotate(vec.heading()); 69874 * let arrowSize = 7; 69875 * translate(vec.mag() - arrowSize, 0); 69876 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 69877 * pop(); 69878 * } 69879 * </code> 69880 * </div> 69881 */ 69882 69883 /** 69884 * @method set 69885 * @param {p5.Vector|Number[]} value the vector to set 69886 * @chainable 69887 */ 69888 69889 69890 p5.Vector.prototype.set = function set(x, y, z) { 69891 if (x instanceof p5.Vector) { 69892 this.x = x.x || 0; 69893 this.y = x.y || 0; 69894 this.z = x.z || 0; 69895 return this; 69896 } 69897 69898 if (x instanceof Array) { 69899 this.x = x[0] || 0; 69900 this.y = x[1] || 0; 69901 this.z = x[2] || 0; 69902 return this; 69903 } 69904 69905 this.x = x || 0; 69906 this.y = y || 0; 69907 this.z = z || 0; 69908 return this; 69909 }; 69910 /** 69911 * Gets a copy of the vector, returns a <a href="#/p5.Vector">p5.Vector</a> object. 69912 * 69913 * @method copy 69914 * @return {p5.Vector} the copy of the <a href="#/p5.Vector">p5.Vector</a> object 69915 * @example 69916 * <div class="norender"> 69917 * <code> 69918 * let v1 = createVector(1, 2, 3); 69919 * let v2 = v1.copy(); 69920 * print(v1.x === v2.x && v1.y === v2.y && v1.z === v2.z); 69921 * // Prints "true" 69922 * </code> 69923 * </div> 69924 */ 69925 69926 69927 p5.Vector.prototype.copy = function copy() { 69928 if (this.p5) { 69929 return new p5.Vector(this.p5, [this.x, this.y, this.z]); 69930 } else { 69931 return new p5.Vector(this.x, this.y, this.z); 69932 } 69933 }; 69934 /** 69935 * Adds x, y, and z components to a vector, adds one vector to another, or 69936 * adds two independent vectors together. The version of the method that adds 69937 * two vectors together is a static method and returns a <a href="#/p5.Vector">p5.Vector</a>, the others 69938 * acts directly on the vector. See the examples for more context. 69939 * 69940 * @method add 69941 * @param {Number} x the x component of the vector to be added 69942 * @param {Number} [y] the y component of the vector to be added 69943 * @param {Number} [z] the z component of the vector to be added 69944 * @chainable 69945 * @example 69946 * <div class="norender"> 69947 * <code> 69948 * let v = createVector(1, 2, 3); 69949 * v.add(4, 5, 6); 69950 * // v's components are set to [5, 7, 9] 69951 * </code> 69952 * </div> 69953 * 69954 * <div class="norender"> 69955 * <code> 69956 * // Static method 69957 * let v1 = createVector(1, 2, 3); 69958 * let v2 = createVector(2, 3, 4); 69959 * 69960 * let v3 = p5.Vector.add(v1, v2); 69961 * // v3 has components [3, 5, 7] 69962 * print(v3); 69963 * </code> 69964 * </div> 69965 * 69966 * <div> 69967 * <code> 69968 * // red vector + blue vector = purple vector 69969 * function draw() { 69970 * background(240); 69971 * 69972 * let v0 = createVector(0, 0); 69973 * let v1 = createVector(mouseX, mouseY); 69974 * drawArrow(v0, v1, 'red'); 69975 * 69976 * let v2 = createVector(-30, 20); 69977 * drawArrow(v1, v2, 'blue'); 69978 * 69979 * let v3 = p5.Vector.add(v1, v2); 69980 * drawArrow(v0, v3, 'purple'); 69981 * } 69982 * 69983 * // draw an arrow for a vector at a given base position 69984 * function drawArrow(base, vec, myColor) { 69985 * push(); 69986 * stroke(myColor); 69987 * strokeWeight(3); 69988 * fill(myColor); 69989 * translate(base.x, base.y); 69990 * line(0, 0, vec.x, vec.y); 69991 * rotate(vec.heading()); 69992 * let arrowSize = 7; 69993 * translate(vec.mag() - arrowSize, 0); 69994 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 69995 * pop(); 69996 * } 69997 * </code> 69998 * </div> 69999 */ 70000 70001 /** 70002 * @method add 70003 * @param {p5.Vector|Number[]} value the vector to add 70004 * @chainable 70005 */ 70006 70007 70008 p5.Vector.prototype.add = function add(x, y, z) { 70009 if (x instanceof p5.Vector) { 70010 this.x += x.x || 0; 70011 this.y += x.y || 0; 70012 this.z += x.z || 0; 70013 return this; 70014 } 70015 70016 if (x instanceof Array) { 70017 this.x += x[0] || 0; 70018 this.y += x[1] || 0; 70019 this.z += x[2] || 0; 70020 return this; 70021 } 70022 70023 this.x += x || 0; 70024 this.y += y || 0; 70025 this.z += z || 0; 70026 return this; 70027 }; 70028 /** 70029 * Subtracts x, y, and z components from a vector, subtracts one vector from 70030 * another, or subtracts two independent vectors. The version of the method 70031 * that subtracts two vectors is a static method and returns a <a href="#/p5.Vector">p5.Vector</a>, the 70032 * other acts directly on the vector. See the examples for more context. 70033 * 70034 * @method sub 70035 * @param {Number} x the x component of the vector to subtract 70036 * @param {Number} [y] the y component of the vector to subtract 70037 * @param {Number} [z] the z component of the vector to subtract 70038 * @chainable 70039 * @example 70040 * <div class="norender"> 70041 * <code>
70042 * let v = createVector(4, 5, 6); 70043 * v.sub(1, 1, 1); 70044 * // v's components are set to [3, 4, 5] 70045 * </code> 70046 * </div> 70047 * 70048 * <div class="norender"> 70049 * <code> 70050 * // Static method 70051 * let v1 = createVector(2, 3, 4); 70052 * let v2 = createVector(1, 2, 3); 70053 * 70054 * let v3 = p5.Vector.sub(v1, v2); 70055 * // v3 has components [1, 1, 1] 70056 * print(v3); 70057 * </code> 70058 * </div> 70059 * 70060 * <div> 70061 * <code> 70062 * // red vector - blue vector = purple vector 70063 * function draw() { 70064 * background(240); 70065 * 70066 * let v0 = createVector(0, 0); 70067 * let v1 = createVector(70, 50); 70068 * drawArrow(v0, v1, 'red'); 70069 * 70070 * let v2 = createVector(mouseX, mouseY); 70071 * drawArrow(v0, v2, 'blue'); 70072 * 70073 * let v3 = p5.Vector.sub(v1, v2); 70074 * drawArrow(v2, v3, 'purple'); 70075 * } 70076 * 70077 * // draw an arrow for a vector at a given base position 70078 * function drawArrow(base, vec, myColor) { 70079 * push(); 70080 * stroke(myColor); 70081 * strokeWeight(3); 70082 * fill(myColor); 70083 * translate(base.x, base.y); 70084 * line(0, 0, vec.x, vec.y); 70085 * rotate(vec.heading()); 70086 * let arrowSize = 7; 70087 * translate(vec.mag() - arrowSize, 0); 70088 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70089 * pop(); 70090 * } 70091 * </code> 70092 * </div> 70093 */ 70094 70095 /** 70096 * @method sub 70097 * @param {p5.Vector|Number[]} value the vector to subtract 70098 * @chainable 70099 */ 70100 70101 70102 p5.Vector.prototype.sub = function sub(x, y, z) { 70103 if (x instanceof p5.Vector) { 70104 this.x -= x.x || 0; 70105 this.y -= x.y || 0; 70106 this.z -= x.z || 0; 70107 return this; 70108 } 70109 70110 if (x instanceof Array) { 70111 this.x -= x[0] || 0; 70112 this.y -= x[1] || 0; 70113 this.z -= x[2] || 0; 70114 return this; 70115 } 70116 70117 this.x -= x || 0; 70118 this.y -= y || 0; 70119 this.z -= z || 0; 70120 return this; 70121 }; 70122 /** 70123 * Multiply the vector by a scalar. The static version of this method 70124 * creates a new <a href="#/p5.Vector">p5.Vector</a> while the non static version acts on the vector 70125 * directly. See the examples for more context. 70126 * 70127 * @method mult 70128 * @param {Number} n the number to multiply with the vector 70129 * @chainable 70130 * @example 70131 * <div class="norender"> 70132 * <code> 70133 * let v = createVector(1, 2, 3); 70134 * v.mult(2); 70135 * // v's components are set to [2, 4, 6] 70136 * </code> 70137 * </div> 70138 * 70139 * <div class="norender"> 70140 * <code> 70141 * // Static method 70142 * let v1 = createVector(1, 2, 3); 70143 * let v2 = p5.Vector.mult(v1, 2); 70144 * // v2 has components [2, 4, 6] 70145 * print(v2); 70146 * </code> 70147 * </div> 70148 * 70149 * <div> 70150 * <code> 70151 * function draw() { 70152 * background(240); 70153 * 70154 * let v0 = createVector(50, 50); 70155 * let v1 = createVector(25, -25); 70156 * drawArrow(v0, v1, 'red'); 70157 * 70158 * let num = map(mouseX, 0, width, -2, 2, true); 70159 * let v2 = p5.Vector.mult(v1, num); 70160 * drawArrow(v0, v2, 'blue'); 70161 * 70162 * noStroke(); 70163 * text('multiplied by ' + num.toFixed(2), 5, 90); 70164 * } 70165 * 70166 * // draw an arrow for a vector at a given base position 70167 * function drawArrow(base, vec, myColor) { 70168 * push(); 70169 * stroke(myColor); 70170 * strokeWeight(3); 70171 * fill(myColor); 70172 * translate(base.x, base.y); 70173 * line(0, 0, vec.x, vec.y); 70174 * rotate(vec.heading()); 70175 * let arrowSize = 7; 70176 * translate(vec.mag() - arrowSize, 0); 70177 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70178 * pop(); 70179 * } 70180 * </code> 70181 * </div> 70182 */ 70183 70184 70185 p5.Vector.prototype.mult = function mult(n) { 70186 if (!(typeof n === 'number' && isFinite(n))) { 70187 console.warn('p5.Vector.prototype.mult:', 'n is undefined or not a finite number'); 70188 return this; 70189 } 70190 70191 this.x *= n; 70192 this.y *= n; 70193 this.z *= n; 70194 return this; 70195 }; 70196 /** 70197 * Divide the vector by a scalar. The static version of this method creates a 70198 * new <a href="#/p5.Vector">p5.Vector</a> while the non static version acts on the vector directly. 70199 * See the examples for more context. 70200 * 70201 * @method div 70202 * @param {number} n the number to divide the vector by 70203 * @chainable 70204 * @example 70205 * <div class="norender"> 70206 * <code> 70207 * let v = createVector(6, 4, 2); 70208 * v.div(2); //v's components are set to [3, 2, 1] 70209 * </code> 70210 * </div> 70211 * 70212 * <div class="norender"> 70213 * <code> 70214 * // Static method 70215 * let v1 = createVector(6, 4, 2); 70216 * let v2 = p5.Vector.div(v1, 2); 70217 * // v2 has components [3, 2, 1] 70218 * print(v2); 70219 * </code> 70220 * </div> 70221 * 70222 * <div> 70223 * <code> 70224 * function draw() { 70225 * background(240); 70226 * 70227 * let v0 = createVector(0, 100); 70228 * let v1 = createVector(50, -50); 70229 * drawArrow(v0, v1, 'red'); 70230 * 70231 * let num = map(mouseX, 0, width, 10, 0.5, true); 70232 * let v2 = p5.Vector.div(v1, num); 70233 * drawArrow(v0, v2, 'blue'); 70234 * 70235 * noStroke(); 70236 * text('divided by ' + num.toFixed(2), 10, 90); 70237 * } 70238 * 70239 * // draw an arrow for a vector at a given base position 70240 * function drawArrow(base, vec, myColor) { 70241 * push(); 70242 * stroke(myColor); 70243 * strokeWeight(3); 70244 * fill(myColor); 70245 * translate(base.x, base.y); 70246 * line(0, 0, vec.x, vec.y); 70247 * rotate(vec.heading()); 70248 * let arrowSize = 7; 70249 * translate(vec.mag() - arrowSize, 0); 70250 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70251 * pop(); 70252 * } 70253 * </code> 70254 * </div> 70255 */ 70256 70257 70258 p5.Vector.prototype.div = function div(n) { 70259 if (!(typeof n === 'number' && isFinite(n))) { 70260 console.warn('p5.Vector.prototype.div:', 'n is undefined or not a finite number'); 70261 return this; 70262 } 70263 70264 if (n === 0) {
70265 console.warn('p5.Vector.prototype.div:', 'divide by 0'); 70266 return this; 70267 } 70268 70269 this.x /= n; 70270 this.y /= n; 70271 this.z /= n; 70272 return this; 70273 }; 70274 /** 70275 * Calculates the magnitude (length) of the vector and returns the result as 70276 * a float (this is simply the equation sqrt(x*x + y*y + z*z).) 70277 * 70278 * @method mag 70279 * @return {Number} magnitude of the vector 70280 * @example 70281 * <div> 70282 * <code> 70283 * function draw() { 70284 * background(240); 70285 * 70286 * let v0 = createVector(0, 0); 70287 * let v1 = createVector(mouseX, mouseY); 70288 * drawArrow(v0, v1, 'black'); 70289 * 70290 * noStroke(); 70291 * text('vector length: ' + v1.mag().toFixed(2), 10, 70, 90, 30); 70292 * } 70293 * 70294 * // draw an arrow for a vector at a given base position 70295 * function drawArrow(base, vec, myColor) { 70296 * push(); 70297 * stroke(myColor); 70298 * strokeWeight(3); 70299 * fill(myColor); 70300 * translate(base.x, base.y); 70301 * line(0, 0, vec.x, vec.y); 70302 * rotate(vec.heading()); 70303 * let arrowSize = 7; 70304 * translate(vec.mag() - arrowSize, 0); 70305 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70306 * pop(); 70307 * } 70308 * </code> 70309 * </div> 70310 * <div class="norender"> 70311 * <code> 70312 * let v = createVector(20.0, 30.0, 40.0); 70313 * let m = v.mag(); 70314 * print(m); // Prints "53.85164807134504" 70315 * </code> 70316 * </div> 70317 */ 70318 70319 70320 p5.Vector.prototype.mag = function mag() { 70321 return Math.sqrt(this.magSq()); 70322 }; 70323 /** 70324 * Calculates the squared magnitude of the vector and returns the result 70325 * as a float (this is simply the equation <em>(x*x + y*y + z*z)</em>.) 70326 * Faster if the real length is not required in the 70327 * case of comparing vectors, etc. 70328 * 70329 * @method magSq 70330 * @return {number} squared magnitude of the vector 70331 * @example 70332 * <div class="norender"> 70333 * <code> 70334 * // Static method 70335 * let v1 = createVector(6, 4, 2); 70336 * print(v1.magSq()); // Prints "56" 70337 * </code> 70338 * </div> 70339 * 70340 * <div> 70341 * <code> 70342 * function draw() { 70343 * background(240); 70344 * 70345 * let v0 = createVector(0, 0); 70346 * let v1 = createVector(mouseX, mouseY); 70347 * drawArrow(v0, v1, 'black'); 70348 * 70349 * noStroke(); 70350 * text('vector length squared: ' + v1.magSq().toFixed(2), 10, 45, 90, 55); 70351 * } 70352 * 70353 * // draw an arrow for a vector at a given base position 70354 * function drawArrow(base, vec, myColor) { 70355 * push(); 70356 * stroke(myColor); 70357 * strokeWeight(3); 70358 * fill(myColor); 70359 * translate(base.x, base.y); 70360 * line(0, 0, vec.x, vec.y); 70361 * rotate(vec.heading()); 70362 * let arrowSize = 7; 70363 * translate(vec.mag() - arrowSize, 0); 70364 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70365 * pop(); 70366 * } 70367 * </code> 70368 * </div> 70369 */ 70370 70371 70372 p5.Vector.prototype.magSq = function magSq() { 70373 var x = this.x; 70374 var y = this.y; 70375 var z = this.z; 70376 return x * x + y * y + z * z; 70377 }; 70378 /** 70379 * Calculates the dot product of two vectors. The version of the method 70380 * that computes the dot product of two independent vectors is a static 70381 * method. See the examples for more context. 70382 * 70383 * 70384 * @method dot 70385 * @param {Number} x x component of the vector 70386 * @param {Number} [y] y component of the vector 70387 * @param {Number} [z] z component of the vector 70388 * @return {Number} the dot product 70389 * 70390 * @example 70391 * <div class="norender"> 70392 * <code> 70393 * let v1 = createVector(1, 2, 3); 70394 * let v2 = createVector(2, 3, 4); 70395 * 70396 * print(v1.dot(v2)); // Prints "20" 70397 * </code> 70398 * </div> 70399 * 70400 * <div class="norender"> 70401 * <code> 70402 * //Static method 70403 * let v1 = createVector(1, 2, 3); 70404 * let v2 = createVector(3, 2, 1); 70405 * print(p5.Vector.dot(v1, v2)); // Prints "10" 70406 * </code> 70407 * </div> 70408 */ 70409 70410 /** 70411 * @method dot 70412 * @param {p5.Vector} value value component of the vector or a <a href="#/p5.Vector">p5.Vector</a> 70413 * @return {Number} 70414 */ 70415 70416 70417 p5.Vector.prototype.dot = function dot(x, y, z) { 70418 if (x instanceof p5.Vector) { 70419 return this.dot(x.x, x.y, x.z); 70420 } 70421 70422 return this.x * (x || 0) + this.y * (y || 0) + this.z * (z || 0); 70423 }; 70424 /** 70425 * Calculates and returns a vector composed of the cross product between 70426 * two vectors. Both the static and non static methods return a new <a href="#/p5.Vector">p5.Vector</a>. 70427 * See the examples for more context. 70428 * 70429 * @method cross 70430 * @param {p5.Vector} v <a href="#/p5.Vector">p5.Vector</a> to be crossed 70431 * @return {p5.Vector} <a href="#/p5.Vector">p5.Vector</a> composed of cross product 70432 * @example 70433 * <div class="norender"> 70434 * <code> 70435 * let v1 = createVector(1, 2, 3); 70436 * let v2 = createVector(1, 2, 3); 70437 * 70438 * v1.cross(v2); // v's components are [0, 0, 0] 70439 * </code> 70440 * </div> 70441 * 70442 * <div class="norender"> 70443 * <code> 70444 * // Static method 70445 * let v1 = createVector(1, 0, 0); 70446 * let v2 = createVector(0, 1, 0); 70447 *
70448 * let crossProduct = p5.Vector.cross(v1, v2); 70449 * // crossProduct has components [0, 0, 1] 70450 * print(crossProduct); 70451 * </code> 70452 * </div> 70453 */ 70454 70455 70456 p5.Vector.prototype.cross = function cross(v) { 70457 var x = this.y * v.z - this.z * v.y; 70458 var y = this.z * v.x - this.x * v.z; 70459 var z = this.x * v.y - this.y * v.x; 70460 70461 if (this.p5) { 70462 return new p5.Vector(this.p5, [x, y, z]); 70463 } else { 70464 return new p5.Vector(x, y, z); 70465 } 70466 }; 70467 /** 70468 * Calculates the Euclidean distance between two points (considering a 70469 * point as a vector object). 70470 * 70471 * @method dist 70472 * @param {p5.Vector} v the x, y, and z coordinates of a <a href="#/p5.Vector">p5.Vector</a> 70473 * @return {Number} the distance 70474 * @example 70475 * <div class="norender"> 70476 * <code> 70477 * let v1 = createVector(1, 0, 0); 70478 * let v2 = createVector(0, 1, 0); 70479 * 70480 * let distance = v1.dist(v2); // distance is 1.4142... 70481 * print(distance); 70482 * </code> 70483 * </div> 70484 * 70485 * <div class="norender"> 70486 * <code> 70487 * // Static method 70488 * let v1 = createVector(1, 0, 0); 70489 * let v2 = createVector(0, 1, 0); 70490 * 70491 * let distance = p5.Vector.dist(v1, v2); 70492 * // distance is 1.4142... 70493 * print(distance); 70494 * </code> 70495 * </div> 70496 * 70497 * <div> 70498 * <code> 70499 * function draw() { 70500 * background(240); 70501 * 70502 * let v0 = createVector(0, 0); 70503 * 70504 * let v1 = createVector(70, 50); 70505 * drawArrow(v0, v1, 'red'); 70506 * 70507 * let v2 = createVector(mouseX, mouseY); 70508 * drawArrow(v0, v2, 'blue'); 70509 * 70510 * noStroke(); 70511 * text('distance between vectors: ' + v2.dist(v1).toFixed(2), 5, 50, 95, 50); 70512 * } 70513 * 70514 * // draw an arrow for a vector at a given base position 70515 * function drawArrow(base, vec, myColor) { 70516 * push(); 70517 * stroke(myColor); 70518 * strokeWeight(3); 70519 * fill(myColor); 70520 * translate(base.x, base.y); 70521 * line(0, 0, vec.x, vec.y); 70522 * rotate(vec.heading()); 70523 * let arrowSize = 7; 70524 * translate(vec.mag() - arrowSize, 0); 70525 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70526 * pop(); 70527 * } 70528 * </code> 70529 * </div> 70530 */ 70531 70532 70533 p5.Vector.prototype.dist = function dist(v) { 70534 return v.copy().sub(this).mag(); 70535 }; 70536 /** 70537 * Normalize the vector to length 1 (make it a unit vector). 70538 * 70539 * @method normalize 70540 * @return {p5.Vector} normalized <a href="#/p5.Vector">p5.Vector</a> 70541 * @example 70542 * <div class="norender"> 70543 * <code> 70544 * let v = createVector(10, 20, 2); 70545 * // v has components [10.0, 20.0, 2.0] 70546 * v.normalize(); 70547 * // v's components are set to 70548 * // [0.4454354, 0.8908708, 0.089087084] 70549 * </code> 70550 * </div> 70551 * <div> 70552 * <code> 70553 * function draw() { 70554 * background(240); 70555 * 70556 * let v0 = createVector(50, 50); 70557 * let v1 = createVector(mouseX - 50, mouseY - 50); 70558 * 70559 * drawArrow(v0, v1, 'red'); 70560 * v1.normalize(); 70561 * drawArrow(v0, v1.mult(35), 'blue'); 70562 * 70563 * noFill(); 70564 * ellipse(50, 50, 35 * 2); 70565 * } 70566 * 70567 * // draw an arrow for a vector at a given base position 70568 * function drawArrow(base, vec, myColor) { 70569 * push(); 70570 * stroke(myColor); 70571 * strokeWeight(3); 70572 * fill(myColor); 70573 * translate(base.x, base.y); 70574 * line(0, 0, vec.x, vec.y); 70575 * rotate(vec.heading()); 70576 * let arrowSize = 7; 70577 * translate(vec.mag() - arrowSize, 0); 70578 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70579 * pop(); 70580 * } 70581 * </code> 70582 * </div> 70583 */ 70584 70585 70586 p5.Vector.prototype.normalize = function normalize() { 70587 var len = this.mag(); // here we multiply by the reciprocal instead of calling 'div()' 70588 // since div duplicates this zero check. 70589 70590 if (len !== 0) this.mult(1 / len); 70591 return this; 70592 }; 70593 /** 70594 * Limit the magnitude of this vector to the value used for the <b>max</b> 70595 * parameter. 70596 * 70597 * @method limit 70598 * @param {Number} max the maximum magnitude for the vector 70599 * @chainable 70600 * @example 70601 * <div class="norender"> 70602 * <code> 70603 * let v = createVector(10, 20, 2); 70604 * // v has components [10.0, 20.0, 2.0] 70605 * v.limit(5); 70606 * // v's components are set to 70607 * // [2.2271771, 4.4543543, 0.4454354] 70608 * </code> 70609 * </div> 70610 * <div> 70611 * <code> 70612 * function draw() { 70613 * background(240); 70614 * 70615 * let v0 = createVector(50, 50); 70616 * let v1 = createVector(mouseX - 50, mouseY - 50); 70617 * 70618 * drawArrow(v0, v1, 'red'); 70619 * drawArrow(v0, v1.limit(35), 'blue'); 70620 * 70621 * noFill(); 70622 * ellipse(50, 50, 35 * 2); 70623 * } 70624 * 70625 * // draw an arrow for a vector at a given base position 70626 * function drawArrow(base, vec, myColor) { 70627 * push(); 70628 * stroke(myColor); 70629 * strokeWeight(3); 70630 * fill(myColor); 70631 * translate(base.x, base.y); 70632 * line(0, 0, vec.x, vec.y); 70633 * rotate(vec.heading()); 70634 * let arrowSize = 7; 70635 * translate(vec.mag() - arrowSize, 0); 70636 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70637 * pop(); 70638 * } 70639 * </code> 70640 * </div> 70641 */ 70642 70643 70644 p5.Vector.prototype.limit = function limit(max) { 70645 var mSq = this.magSq(); 70646 70647 if (mSq > max * max) { 70648 this.div(Math.sqrt(mSq)) //normalize it 70649 .mult(max); 70650 } 70651 70652 return this; 70653 }; 70654 /** 70655 * Set the magnitude of this vector to the value used for the <b>len</b> 70656 * parameter. 70657 * 70658 * @method setMag 70659 * @param {number} len the new length for this vector 70660 * @chainable 70661 * @example 70662 * <div class="norender"> 70663 * <code> 70664 * let v = createVector(10, 20, 2); 70665 * // v has components [10.0, 20.0, 2.0] 70666 * v.setMag(10); 70667 * // v's components are set to [6.0, 8.0, 0.0] 70668 * </code> 70669 * </div> 70670 * 70671 * <div> 70672 * <code> 70673 * function draw() { 70674 * background(240); 70675 * 70676 * let v0 = createVector(0, 0); 70677 * let v1 = createVector(50, 50); 70678 * 70679 * drawArrow(v0, v1, 'red'); 70680 * 70681 * let length = map(mouseX, 0, width, 0, 141, true); 70682 * v1.setMag(length); 70683 * drawArrow(v0, v1, 'blue'); 70684 * 70685 * noStroke(); 70686 * text('magnitude set to: ' + length.toFixed(2), 10, 70, 90, 30); 70687 * } 70688 * 70689 * // draw an arrow for a vector at a given base position 70690 * function drawArrow(base, vec, myColor) { 70691 * push(); 70692 * stroke(myColor); 70693 * strokeWeight(3); 70694 * fill(myColor); 70695 * translate(base.x, base.y); 70696 * line(0, 0, vec.x, vec.y); 70697 * rotate(vec.heading()); 70698 * let arrowSize = 7; 70699 * translate(vec.mag() - arrowSize, 0); 70700 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70701 * pop(); 70702 * } 70703 * </code> 70704 * </div> 70705 */ 70706 70707 70708 p5.Vector.prototype.setMag = function setMag(n) { 70709 return this.normalize().mult(n); 70710 }; 70711 /** 70712 * Calculate the angle of rotation for this vector (only 2D vectors) 70713 * 70714 * @method heading 70715 * @return {Number} the angle of rotation 70716 * @example 70717 * <div class = "norender"> 70718 * <code> 70719 * function setup() { 70720 * let v1 = createVector(30, 50); 70721 * print(v1.heading()); // 1.0303768265243125 70722 * 70723 * v1 = createVector(40, 50); 70724 * print(v1.heading());
70724 // 0.8960553845713439 70725 * 70726 * v1 = createVector(30, 70); 70727 * print(v1.heading()); // 1.1659045405098132 70728 * } 70729 * </code> 70730 * </div> 70731 * 70732 * <div> 70733 * <code> 70734 * function draw() { 70735 * background(240); 70736 * 70737 * let v0 = createVector(50, 50); 70738 * let v1 = createVector(mouseX - 50, mouseY - 50); 70739 * 70740 * drawArrow(v0, v1, 'black'); 70741 * 70742 * let myHeading = v1.heading(); 70743 * noStroke(); 70744 * text( 70745 * 'vector heading: ' + 70746 * myHeading.toFixed(2) + 70747 * ' radians or ' + 70748 * degrees(myHeading).toFixed(2) + 70749 * ' degrees', 70750 * 10, 70751 * 50, 70752 * 90, 70753 * 50 70754 * ); 70755 * } 70756 * 70757 * // draw an arrow for a vector at a given base position 70758 * function drawArrow(base, vec, myColor) { 70759 * push(); 70760 * stroke(myColor); 70761 * strokeWeight(3); 70762 * fill(myColor); 70763 * translate(base.x, base.y); 70764 * line(0, 0, vec.x, vec.y); 70765 * rotate(vec.heading()); 70766 * let arrowSize = 7; 70767 * translate(vec.mag() - arrowSize, 0); 70768 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70769 * pop(); 70770 * } 70771 * </code> 70772 * </div> 70773 */ 70774 70775 70776 p5.Vector.prototype.heading = function heading() { 70777 var h = Math.atan2(this.y, this.x); 70778 if (this.p5) return this.p5._fromRadians(h); 70779 return h; 70780 }; 70781 /** 70782 * Rotate the vector by an angle (only 2D vectors), magnitude remains the 70783 * same 70784 * 70785 * @method rotate 70786 * @param {number} angle the angle of rotation 70787 * @chainable 70788 * @example 70789 * <div class="norender"> 70790 * <code> 70791 * let v = createVector(10.0, 20.0); 70792 * // v has components [10.0, 20.0, 0.0] 70793 * v.rotate(HALF_PI); 70794 * // v's components are set to [-20.0, 9.999999, 0.0] 70795 * </code> 70796 * </div> 70797 * 70798 * <div> 70799 * <code> 70800 * let angle = 0; 70801 * function draw() { 70802 * background(240); 70803 * 70804 * let v0 = createVector(50, 50); 70805 * let v1 = createVector(50, 0); 70806 * 70807 * drawArrow(v0, v1.rotate(angle), 'black'); 70808 * angle += 0.01; 70809 * } 70810 * 70811 * // draw an arrow for a vector at a given base position 70812 * function drawArrow(base, vec, myColor) { 70813 * push(); 70814 * stroke(myColor); 70815 * strokeWeight(3); 70816 * fill(myColor); 70817 * translate(base.x, base.y); 70818 * line(0, 0, vec.x, vec.y); 70819 * rotate(vec.heading()); 70820 * let arrowSize = 7; 70821 * translate(vec.mag() - arrowSize, 0); 70822 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70823 * pop(); 70824 * } 70825 * </code> 70826 * </div> 70827 */ 70828 70829 70830 p5.Vector.prototype.rotate = function rotate(a) { 70831 var newHeading = this.heading() + a; 70832 if (this.p5) newHeading = this.p5._toRadians(newHeading); 70833 var mag = this.mag(); 70834 this.x = Math.cos(newHeading) * mag; 70835 this.y = Math.sin(newHeading) * mag; 70836 return this; 70837 }; 70838 /** 70839 * Calculates and returns the angle (in radians) between two vectors. 70840 * @method angleBetween 70841 * @param {p5.Vector} the x, y, and z components of a <a href="#/p5.Vector">p5.Vector</a> 70842 * @return {Number} the angle between (in radians) 70843 * @example 70844 * <div class="norender"> 70845 * <code> 70846 * let v1 = createVector(1, 0, 0); 70847 * let v2 = createVector(0, 1, 0); 70848 * 70849 * let angle = v1.angleBetween(v2); 70850 * // angle is PI/2 70851 * print(angle); 70852 * </code> 70853 * </div> 70854 * 70855 * <div> 70856 * <code> 70857 * function draw() { 70858 * background(240); 70859 * let v0 = createVector(50, 50); 70860 * 70861 * let v1 = createVector(50, 0); 70862 * drawArrow(v0, v1, 'red'); 70863 * 70864 * let v2 = createVector(mouseX - 50, mouseY - 50); 70865 * drawArrow(v0, v2, 'blue'); 70866 * 70867 * let angleBetween = v1.angleBetween(v2); 70868 * noStroke(); 70869 * text( 70870 * 'angle between: ' + 70871 * angleBetween.toFixed(2) + 70872 * ' radians or ' + 70873 * degrees(angleBetween).toFixed(2) + 70874 * ' degrees', 70875 * 10, 70876 * 50, 70877 * 90, 70878 * 50 70879 * ); 70880 * } 70881 * 70882 * // draw an arrow for a vector at a given base position 70883 * function drawArrow(base, vec, myColor) { 70884 * push(); 70885 * stroke(myColor); 70886 * strokeWeight(3); 70887 * fill(myColor); 70888 * translate(base.x, base.y); 70889 * line(0, 0, vec.x, vec.y); 70890 * rotate(vec.heading()); 70891 * let arrowSize = 7; 70892 * translate(vec.mag() - arrowSize, 0); 70893 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70894 * pop(); 70895 * } 70896 * </code> 70897 * </div> 70898 */ 70899 70900 70901 p5.Vector.prototype.angleBetween = function angleBetween(v) { 70902 var dotmagmag = this.dot(v) / (this.mag() * v.mag()); // Mathematically speaking: the dotmagmag variable will be between -1 and 1 70903 // inclusive. Practically though it could be slightly outside this range due 70904 // to floating-point rounding issues. This can make Math.acos return NaN. 70905 // 70906 // Solution: we'll clamp the value to the -1,1 range 70907 70908 var angle = Math.acos(Math.min(1, Math.max(-1, dotmagmag))); 70909 if (this.p5) return this.p5._fromRadians(angle); 70910 return angle; 70911 }; 70912 /** 70913 * Linear interpolate the vector to another vector 70914 * 70915 * @method lerp 70916 * @param {Number} x the x component 70917 * @param {Number} y the y component 70918 * @param {Number} z the z component 70919 * @param {Number} amt the amount of interpolation; some value between 0.0 70920 * (old vector) and 1.0 (new vector). 0.9 is very near 70921 * the new vector. 0.5 is halfway in between. 70922 * @chainable 70923 * 70924 * @example 70925 * <div class="norender"> 70926 * <code> 70927 * let v = createVector(1, 1, 0); 70928 * 70929 * v.lerp(3, 3, 0, 0.5); // v now has components [2,2,0] 70930 * </code> 70931 * </div> 70932 * 70933 * <div class="norender"> 70934 * <code> 70935 * let v1 = createVector(0, 0, 0); 70936 * let v2 = createVector(100, 100, 0); 70937 * 70938 * let v3 = p5.Vector.lerp(v1, v2, 0.5); 70939 * // v3 has components [50,50,0] 70940 * print(v3); 70941 * </code> 70942 * </div> 70943 * 70944 * <div> 70945 * <code> 70946 * let step = 0.01; 70947 * let amount = 0; 70948 * 70949 * function draw() { 70950 * background(240); 70951 * let v0 = createVector(0, 0); 70952 * 70953 * let v1 = createVector(mouseX, mouseY); 70954 * drawArrow(v0, v1, 'red'); 70955 * 70956 * let v2 = createVector(90, 90); 70957 * drawArrow(v0, v2, 'blue'); 70958 * 70959 * if (amount > 1 || amount < 0) { 70960 * step *= -1; 70961 * } 70962 * amount += step; 70963 * let v3 = p5.Vector.lerp(v1, v2, amount); 70964 * 70965 * drawArrow(v0, v3, 'purple'); 70966 * } 70967 * 70968 * // draw an arrow for a vector at a given base position 70969 * function drawArrow(base, vec, myColor) { 70970 * push(); 70971 * stroke(myColor); 70972 * strokeWeight(3); 70973 * fill(myColor); 70974 * translate(base.x, base.y); 70975 * line(0, 0, vec.x, vec.y); 70976 * rotate(vec.heading()); 70977 * let arrowSize = 7; 70978 * translate(vec.mag() - arrowSize, 0); 70979 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 70980 * pop(); 70981 * } 70982 * </code> 70983 * </div> 70984 */ 70985 70986 /** 70987 * @method lerp 70988 * @param {p5.Vector} v the <a href="#/p5.Vector">p5.Vector</a> to lerp to 70989 * @param {Number} amt 70990 * @chainable 70991 */ 70992 70993 70994 p5.Vector.prototype.lerp = function lerp(x, y, z, amt) { 70995 if (x instanceof p5.Vector) { 70996 return this.lerp(x.x, x.y, x.z, y); 70997 } 70998 70999 this.x += (x - this.x) * amt || 0; 71000 this.y += (y - this.y) * amt || 0; 71001 this.z += (z - this.z) * amt || 0; 71002 return this; 71003 }; 71004 /** 71005 * Return a representation of this vector as a float array. This is only 71006 * for temporary use. If used in any other fashion, the contents should be 71007 * copied by using the <b>p5.Vector.<a href="#/p5.Vector/copy">copy()</a></b> method to copy into your own 71008 * array.
71009 * 71010 * @method array 71011 * @return {Number[]} an Array with the 3 values 71012 * @example 71013 * <div class = "norender"> 71014 * <code> 71015 * function setup() { 71016 * let v = createVector(20, 30); 71017 * print(v.array()); // Prints : Array [20, 30, 0] 71018 * } 71019 * </code> 71020 * </div> 71021 * 71022 * <div class="norender"> 71023 * <code> 71024 * let v = createVector(10.0, 20.0, 30.0); 71025 * let f = v.array(); 71026 * print(f[0]); // Prints "10.0" 71027 * print(f[1]); // Prints "20.0" 71028 * print(f[2]); // Prints "30.0" 71029 * </code> 71030 * </div> 71031 */ 71032 71033 71034 p5.Vector.prototype.array = function array() { 71035 return [this.x || 0, this.y || 0, this.z || 0]; 71036 }; 71037 /** 71038 * Equality check against a <a href="#/p5.Vector">p5.Vector</a> 71039 * 71040 * @method equals 71041 * @param {Number} [x] the x component of the vector 71042 * @param {Number} [y] the y component of the vector 71043 * @param {Number} [z] the z component of the vector 71044 * @return {Boolean} whether the vectors are equals 71045 * @example 71046 * <div class = "norender"> 71047 * <code> 71048 * let v1 = createVector(5, 10, 20); 71049 * let v2 = createVector(5, 10, 20); 71050 * let v3 = createVector(13, 10, 19); 71051 * 71052 * print(v1.equals(v2.x, v2.y, v2.z)); // true 71053 * print(v1.equals(v3.x, v3.y, v3.z)); // false 71054 * </code> 71055 * </div> 71056 * 71057 * <div class="norender"> 71058 * <code> 71059 * let v1 = createVector(10.0, 20.0, 30.0); 71060 * let v2 = createVector(10.0, 20.0, 30.0); 71061 * let v3 = createVector(0.0, 0.0, 0.0); 71062 * print(v1.equals(v2)); // true 71063 * print(v1.equals(v3)); // false 71064 * </code> 71065 * </div> 71066 */ 71067 71068 /** 71069 * @method equals 71070 * @param {p5.Vector|Array} value the vector to compare 71071 * @return {Boolean} 71072 */ 71073 71074 71075 p5.Vector.prototype.equals = function equals(x, y, z) { 71076 var a, b, c; 71077 71078 if (x instanceof p5.Vector) { 71079 a = x.x || 0; 71080 b = x.y || 0; 71081 c = x.z || 0; 71082 } else if (x instanceof Array) { 71083 a = x[0] || 0; 71084 b = x[1] || 0; 71085 c = x[2] || 0; 71086 } else { 71087 a = x || 0; 71088 b = y || 0; 71089 c = z || 0; 71090 } 71091 71092 return this.x === a && this.y === b && this.z === c; 71093 }; // Static Methods 71094 71095 /** 71096 * Make a new 2D vector from an angle 71097 * 71098 * @method fromAngle 71099 * @static 71100 * @param {Number} angle the desired angle, in radians 71101 * @param {Number} [length] the length of the new vector (defaults to 1) 71102 * @return {p5.Vector} the new <a href="#/p5.Vector">p5.Vector</a> object 71103 * @example 71104 * <div> 71105 * <code> 71106 * function draw() { 71107 * background(200); 71108 * 71109 * // Create a variable, proportional to the mouseX, 71110 * // varying from 0-360, to represent an angle in degrees. 71111 * angleMode(DEGREES); 71112 * let myDegrees = map(mouseX, 0, width, 0, 360); 71113 * 71114 * // Display that variable in an onscreen text. 71115 * // (Note the nfc() function to truncate additional decimal places, 71116 * // and the "\xB0" character for the degree symbol.) 71117 * let readout = 'angle = ' + nfc(myDegrees, 1) + '\xB0'; 71118 * noStroke(); 71119 * fill(0); 71120 * text(readout, 5, 15); 71121 * 71122 * // Create a p5.Vector using the fromAngle function, 71123 * // and extract its x and y components. 71124 * let v = p5.Vector.fromAngle(radians(myDegrees), 30); 71125 * let vx = v.x; 71126 * let vy = v.y; 71127 * 71128 * push(); 71129 * translate(width / 2, height / 2); 71130 * noFill(); 71131 * stroke(150); 71132 * line(0, 0, 30, 0); 71133 * stroke(0); 71134 * line(0, 0, vx, vy); 71135 * pop(); 71136 * } 71137 * </code> 71138 * </div> 71139 */ 71140 71141 71142 p5.Vector.fromAngle = function fromAngle(angle, length) { 71143 if (typeof length === 'undefined') { 71144 length = 1; 71145 } 71146 71147 return new p5.Vector(length * Math.cos(angle), length * Math.sin(angle), 0); 71148 }; 71149 /** 71150 * Make a new 3D vector from a pair of ISO spherical angles 71151 * 71152 * @method fromAngles 71153 * @static 71154 * @param {Number} theta the polar angle, in radians (zero is up) 71155 * @param {Number} phi the azimuthal angle, in radians 71156 * (zero is out of the screen) 71157 * @param {Number} [length] the length of the new vector (defaults to 1) 71158 * @return {p5.Vector} the new <a href="#/p5.Vector">p5.Vector</a> object 71159 * @example 71160 * <div modernizr='webgl'> 71161 * <code> 71162 * function setup() { 71163 * createCanvas(100, 100, WEBGL); 71164 * fill(255); 71165 * noStroke(); 71166 * } 71167 * function draw() { 71168 * background(255); 71169 * 71170 * let t = millis() / 1000; 71171 * 71172 * // add three point lights 71173 * pointLight(color('#f00'), p5.Vector.fromAngles(t * 1.0, t * 1.3, 100)); 71174 * pointLight(color('#0f0'), p5.Vector.fromAngles(t * 1.1, t * 1.2, 100)); 71175 * pointLight(color('#00f'), p5.Vector.fromAngles(t * 1.2, t * 1.1, 100)); 71176 * 71177 * sphere(35); 71178 * } 71179 * </code> 71180 * </div> 71181 */ 71182 71183 71184 p5.Vector.fromAngles = function (theta, phi, length) { 71185 if (typeof length === 'undefined') { 71186 length = 1; 71187 } 71188 71189 var cosPhi = Math.cos(phi);
71190 var sinPhi = Math.sin(phi); 71191 var cosTheta = Math.cos(theta); 71192 var sinTheta = Math.sin(theta); 71193 return new p5.Vector(length * sinTheta * sinPhi, -length * cosTheta, length * sinTheta * cosPhi); 71194 }; 71195 /** 71196 * Make a new 2D unit vector from a random angle 71197 * 71198 * @method random2D 71199 * @static 71200 * @return {p5.Vector} the new <a href="#/p5.Vector">p5.Vector</a> object 71201 * @example 71202 * <div class="norender"> 71203 * <code> 71204 * let v = p5.Vector.random2D(); 71205 * // May make v's attributes something like: 71206 * // [0.61554617, -0.51195765, 0.0] or 71207 * // [-0.4695841, -0.14366731, 0.0] or 71208 * // [0.6091097, -0.22805278, 0.0] 71209 * print(v); 71210 * </code> 71211 * </div> 71212 * 71213 * <div> 71214 * <code> 71215 * function setup() { 71216 * frameRate(1); 71217 * } 71218 * 71219 * function draw() { 71220 * background(240); 71221 * 71222 * let v0 = createVector(50, 50); 71223 * let v1 = p5.Vector.random2D(); 71224 * drawArrow(v0, v1.mult(50), 'black'); 71225 * } 71226 * 71227 * // draw an arrow for a vector at a given base position 71228 * function drawArrow(base, vec, myColor) { 71229 * push(); 71230 * stroke(myColor); 71231 * strokeWeight(3); 71232 * fill(myColor); 71233 * translate(base.x, base.y); 71234 * line(0, 0, vec.x, vec.y); 71235 * rotate(vec.heading()); 71236 * let arrowSize = 7; 71237 * translate(vec.mag() - arrowSize, 0); 71238 * triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0); 71239 * pop(); 71240 * } 71241 * </code> 71242 * </div> 71243 */ 71244 71245 71246 p5.Vector.random2D = function random2D() { 71247 return this.fromAngle(Math.random() * constants.TWO_PI); 71248 }; 71249 /** 71250 * Make a new random 3D unit vector. 71251 * 71252 * @method random3D 71253 * @static 71254 * @return {p5.Vector} the new <a href="#/p5.Vector">p5.Vector</a> object 71255 * @example 71256 * <div class="norender"> 71257 * <code> 71258 * let v = p5.Vector.random3D(); 71259 * // May make v's attributes something like: 71260 * // [0.61554617, -0.51195765, 0.599168] or 71261 * // [-0.4695841, -0.14366731, -0.8711202] or 71262 * // [0.6091097, -0.22805278, -0.7595902] 71263 * print(v); 71264 * </code> 71265 * </div> 71266 */ 71267 71268 71269 p5.Vector.random3D = function random3D() { 71270 var angle = Math.random() * constants.TWO_PI; 71271 var vz = Math.random() * 2 - 1; 71272 var vzBase = Math.sqrt(1 - vz * vz); 71273 var vx = vzBase * Math.cos(angle); 71274 var vy = vzBase * Math.sin(angle); 71275 return new p5.Vector(vx, vy, vz); 71276 }; // Adds two vectors together and returns a new one. 71277 71278 /** 71279 * @method add 71280 * @static 71281 * @param {p5.Vector} v1 a <a href="#/p5.Vector">p5.Vector</a> to add 71282 * @param {p5.Vector} v2 a <a href="#/p5.Vector">p5.Vector</a> to add 71283 * @param {p5.Vector} target the vector to receive the result 71284 */ 71285 71286 /** 71287 * @method add 71288 * @static 71289 * @param {p5.Vector} v1 71290 * @param {p5.Vector} v2 71291 * @return {p5.Vector} the resulting <a href="#/p5.Vector">p5.Vector</a> 71292 * 71293 */ 71294 71295 71296 p5.Vector.add = function add(v1, v2, target) { 71297 if (!target) { 71298 target = v1.copy(); 71299 } else { 71300 target.set(v1); 71301 } 71302 71303 target.add(v2); 71304 return target; 71305 }; 71306 /* 71307 * Subtracts one <a href="#/p5.Vector">p5.Vector</a> from another and returns a new one. The second 71308 * vector (v2) is subtracted from the first (v1), resulting in v1-v2. 71309 */ 71310 71311 /** 71312 * @method sub 71313 * @static 71314 * @param {p5.Vector} v1 a <a href="#/p5.Vector">p5.Vector</a> to subtract from 71315 * @param {p5.Vector} v2 a <a href="#/p5.Vector">p5.Vector</a> to subtract 71316 * @param {p5.Vector} target if undefined a new vector will be created 71317 */ 71318 71319 /** 71320 * @method sub 71321 * @static 71322 * @param {p5.Vector} v1 71323 * @param {p5.Vector} v2 71324 * @return {p5.Vector} the resulting <a href="#/p5.Vector">p5.Vector</a> 71325 */ 71326 71327 71328 p5.Vector.sub = function sub(v1, v2, target) { 71329 if (!target) { 71330 target = v1.copy(); 71331 } else { 71332 target.set(v1); 71333 } 71334 71335 target.sub(v2); 71336 return target; 71337 }; 71338 /** 71339 * Multiplies a vector by a scalar and returns a new vector. 71340 */ 71341 71342 /** 71343 * @method mult 71344 * @static 71345 * @param {p5.Vector} v the vector to multiply 71346 * @param {Number} n 71347 * @param {p5.Vector} target if undefined a new vector will be created 71348 */ 71349 71350 /** 71351 * @method mult 71352 * @static 71353 * @param {p5.Vector} v 71354 * @param {Number} n 71355 * @return {p5.Vector} the resulting new <a href="#/p5.Vector">p5.Vector</a> 71356 */ 71357 71358 71359 p5.Vector.mult = function mult(v, n, target) { 71360 if (!target) { 71361 target = v.copy(); 71362 } else { 71363 target.set(v); 71364 } 71365 71366 target.mult(n); 71367 return target; 71368 }; 71369 /** 71370 * Divides a vector by a scalar and returns a new vector. 71371 */ 71372 71373 /** 71374 * @method div 71375 * @static 71376 * @param {p5.Vector} v the vector to divide 71377 * @param {Number} n 71378 * @param {p5.Vector} target if undefined a new vector will be created 71379 */ 71380 71381 /** 71382 * @method div 71383 * @static 71384 * @param {p5.Vector} v 71385 * @param {Number} n 71386 * @return {p5.Vector} the resulting new <a href="#/p5.Vector">p5.Vector</a> 71387 */ 71388 71389 71390 p5.Vector.div = function div(v, n, target) { 71391 if (!target) { 71392 target = v.copy(); 71393 } else { 71394 target.set(v); 71395 } 71396 71397 target.div(n); 71398 return target; 71399 }; 71400 /** 71401 * Calculates the dot product of two vectors. 71402 */ 71403 71404 /** 71405 * @method dot 71406 * @static 71407 * @param {p5.Vector} v1 the first <a href="#/p5.Vector">p5.Vector</a> 71408 * @param {p5.Vector} v2 the second <a href="#/p5.Vector">p5.Vector</a> 71409 * @return {Number} the dot product 71410 */ 71411 71412 71413 p5.Vector.dot = function dot(v1, v2) { 71414 return v1.dot(v2); 71415 }; 71416 /** 71417 * Calculates the cross product of two vectors. 71418 */ 71419 71420 /** 71421 * @method cross 71422 * @static 71423 * @param {p5.Vector} v1 the first <a href="#/p5.Vector">p5.Vector</a> 71424 * @param {p5.Vector} v2 the second <a href="#/p5.Vector">p5.Vector</a> 71425 * @return {Number} the cross product 71426 */ 71427 71428 71429 p5.Vector.cross = function cross(v1, v2) { 71430 return v1.cross(v2); 71431 }; 71432 /** 71433 * Calculates the Euclidean distance between two points (considering a 71434 * point as a vector object). 71435 */ 71436 71437 /** 71438 * @method dist 71439 * @static 71440 * @param {p5.Vector} v1 the first <a href="#/p5.Vector">p5.Vector</a> 71441 * @param {p5.Vector} v2 the second <a href="#/p5.Vector">p5.Vector</a> 71442 * @return {Number} the distance 71443 */ 71444 71445 71446 p5.Vector.dist = function dist(v1, v2) { 71447 return v1.dist(v2); 71448 }; 71449 /** 71450 * Linear interpolate a vector to another vector and return the result as a 71451 * new vector. 71452 */ 71453 71454 /** 71455 * @method lerp 71456 * @static 71457 * @param {p5.Vector} v1 71458 * @param {p5.Vector} v2 71459 * @param {Number} amt 71460 * @param {p5.Vector} target if undefined a new vector will be created 71461 */ 71462 71463 /** 71464 * @method lerp 71465 * @static 71466 * @param {p5.Vector} v1 71467 * @param {p5.Vector} v2 71468 * @param {Number} amt 71469 * @return {Number} the lerped value 71470 */ 71471 71472 71473 p5.Vector.lerp = function lerp(v1, v2, amt, target) { 71474 if (!target) { 71475 target = v1.copy(); 71476 } else { 71477 target.set(v1); 71478 } 71479 71480 target.lerp(v2, amt); 71481 return target; 71482 }; 71483 /** 71484 * @method mag 71485 * @param {p5.Vector} vecT the vector to return the magnitude of 71486 * @return {Number} the magnitude of vecT 71487 * @static 71488 */ 71489 71490 71491 p5.Vector.mag = function mag(vecT) { 71492 var x = vecT.x, 71493 y = vecT.y, 71494 z = vecT.z; 71495 var magSq = x * x + y * y + z * z; 71496 return Math.sqrt(magSq); 71497 }; 71498 71499 module.exports = p5.Vector; 71500 }, {
71501 "../core/constants": 18, 71502 "../core/main": 24 71503 }], 71504 55: [function (_dereq_, module, exports) { 71505 /** 71506 * @module Math 71507 * @submodule Random 71508 * @for p5 71509 * @requires core 71510 */ 71511 'use strict'; 71512 71513 var p5 = _dereq_('../core/main'); 71514 71515 var seeded = false; 71516 var previous = false; 71517 var y2 = 0; // Linear Congruential Generator 71518 // Variant of a Lehman Generator 71519 71520 var lcg = function () { 71521 // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes 71522 // m is basically chosen to be large (as it is the max period) 71523 // and for its relationships to a and c 71524 var m = 4294967296, 71525 // a - 1 should be divisible by m's prime factors 71526 a = 1664525, 71527 // c and m should be co-prime 71528 c = 1013904223, 71529 seed, 71530 z; 71531 return { 71532 setSeed: function (val) { 71533 // pick a random seed if val is undefined or null 71534 // the >>> 0 casts the seed to an unsigned 32-bit integer 71535 z = seed = (val == null ? Math.random() * m : val) >>> 0; 71536 }, 71537 getSeed: function () { 71538 return seed; 71539 }, 71540 rand: function () { 71541 // define the recurrence relationship 71542 z = (a * z + c) % m; // return a float in [0, 1) 71543 // if z = m then z / m = 0 therefore (z % m) / m < 1 always 71544 71545 return z / m; 71546 } 71547 }; 71548 }(); 71549 /** 71550 * Sets the seed value for <a href="#/p5/random">random()</a>. 71551 * 71552 * By default, <a href="#/p5/random">random()</a> produces different results each time the program 71553 * is run. Set the seed parameter to a constant to return the same 71554 * pseudo-random numbers each time the software is run. 71555 * 71556 * @method randomSeed 71557 * @param {Number} seed the seed value 71558 * @example 71559 * <div> 71560 * <code> 71561 * randomSeed(99); 71562 * for (let i = 0; i < 100; i++) { 71563 * let r = random(0, 255); 71564 * stroke(r); 71565 * line(i, 0, i, 100); 71566 * } 71567 * </code> 71568 * </div> 71569 * 71570 * @alt 71571 * many vertical lines drawn in white, black or grey. 71572 * 71573 */ 71574 71575 71576 p5.prototype.randomSeed = function (seed) { 71577 lcg.setSeed(seed); 71578 seeded = true; 71579 previous = false; 71580 }; 71581 /** 71582 * Return a random floating-point number. 71583 * 71584 * Takes either 0, 1 or 2 arguments. 71585 * 71586 * If no argument is given, returns a random number from 0 71587 * up to (but not including) 1. 71588 * 71589 * If one argument is given and it is a number, returns a random number from 0 71590 * up to (but not including) the number. 71591 * 71592 * If one argument is given and it is an array, returns a random element from 71593 * that array. 71594 * 71595 * If two arguments are given, returns a random number from the 71596 * first argument up to (but not including) the second argument. 71597 * 71598 * @method random 71599 * @param {Number} [min] the lower bound (inclusive) 71600 * @param {Number} [max] the upper bound (exclusive) 71601 * @return {Number} the random number 71602 * @example 71603 * <div> 71604 * <code> 71605 * for (let i = 0; i < 100; i++) { 71606 * let r = random(50); 71607 * stroke(r * 5); 71608 * line(50, i, 50 + r, i); 71609 * } 71610 * </code> 71611 * </div> 71612 * <div> 71613 * <code> 71614 * for (let i = 0; i < 100; i++) { 71615 * let r = random(-50, 50); 71616 * line(50, i, 50 + r, i); 71617 * } 71618 * </code> 71619 * </div> 71620 * <div> 71621 * <code> 71622 * // Get a random element from an array using the random(Array) syntax 71623 * let words = ['apple', 'bear', 'cat', 'dog']; 71624 * let word = random(words); // select random word 71625 * text(word, 10, 50); // draw the word 71626 * </code> 71627 * </div> 71628 * 71629 * @alt 71630 * 100 horizontal lines from center canvas to right. size+fill change each time 71631 * 100 horizontal lines from center of canvas. height & side change each render 71632 * word displayed at random. Either apple, bear, cat, or dog 71633 * 71634 */ 71635 71636 /** 71637 * @method random 71638 * @param {Array} choices the array to choose from 71639 * @return {*} the random element from the array 71640 * @example 71641 */ 71642 71643 71644 p5.prototype.random = function (min, max) { 71645 var rand; 71646 71647 if (seeded) { 71648 rand = lcg.rand(); 71649 } else { 71650 rand = Math.random(); 71651 } 71652 71653 if (typeof min === 'undefined') { 71654 return rand; 71655 } else if (typeof max === 'undefined') { 71656 if (min instanceof Array) { 71657 return min[Math.floor(rand * min.length)]; 71658 } else { 71659 return rand * min; 71660 } 71661 } else { 71662 if (min > max) { 71663 var tmp = min; 71664 min = max; 71665 max = tmp; 71666 } 71667 71668 return rand * (max - min) + min; 71669 } 71670 }; 71671 /** 71672 * 71673 * Returns a random number fitting a Gaussian, or 71674 * normal, distribution. There is theoretically no minimum or maximum 71675 * value that <a href="#/p5/randomGaussian">randomGaussian()</a> might return. Rather, there is 71676 * just a very low probability that values far from the mean will be 71677 * returned; and a higher probability that numbers near the mean will 71678 * be returned. 71679 * <br><br> 71680 * Takes either 0, 1 or 2 arguments.<br> 71681 * If no args, returns a mean of 0 and standard deviation of 1.<br> 71682 * If one arg, that arg is the mean (standard deviation is 1).<br> 71683 * If two args, first is mean, second is standard deviation. 71684 * 71685 * @method randomGaussian 71686 * @param {Number} mean the mean 71687 * @param {Number} sd the standard deviation 71688 * @return {Number} the random number 71689 * @example 71690 * <div> 71691 * <code> 71692 * for (let y = 0; y < 100; y++) { 71693 * let x = randomGaussian(50, 15); 71694 * line(50, y, x, y); 71695 * } 71696 * </code> 71697 * </div> 71698 * <div> 71699 * <code> 71700 * let distribution = new Array(360); 71701 * 71702 * function setup() { 71703 * createCanvas(100, 100); 71704 * for (let i = 0; i < distribution.length; i++) { 71705 * distribution[i] = floor(randomGaussian(0, 15)); 71706 * } 71707 * } 71708 * 71709 * function draw() { 71710 * background(204); 71711 * 71712 * translate(width / 2, width / 2); 71713 * 71714 * for (let i = 0; i < distribution.length; i++) { 71715 * rotate(TWO_PI / distribution.length); 71716 * stroke(0); 71717 * let dist = abs(distribution[i]); 71718 * line(0, 0, dist, 0); 71719 * } 71720 * } 71721 * </code> 71722 * </div> 71723 * @alt 71724 * 100 horizontal lines from center of canvas. height & side change each render 71725 * black lines radiate from center of canvas. size determined each render 71726 */ 71727 71728 71729 p5.prototype.randomGaussian = function (mean, sd) { 71730 var y1, x1, x2, w; 71731 71732 if (previous) { 71733 y1 = y2; 71734 previous = false;
71735 } else { 71736 do { 71737 x1 = this.random(2) - 1; 71738 x2 = this.random(2) - 1; 71739 w = x1 * x1 + x2 * x2; 71740 } while (w >= 1); 71741 71742 w = Math.sqrt(-2 * Math.log(w) / w); 71743 y1 = x1 * w; 71744 y2 = x2 * w; 71745 previous = true; 71746 } 71747 71748 var m = mean || 0; 71749 var s = sd || 1; 71750 return y1 * s + m; 71751 }; 71752 71753 module.exports = p5; 71754 }, { 71755 "../core/main": 24 71756 }], 71757 56: [function (_dereq_, module, exports) { 71758 /** 71759 * @module Math 71760 * @submodule Trigonometry 71761 * @for p5 71762 * @requires core 71763 * @requires constants 71764 */ 71765 'use strict'; 71766 71767 var p5 = _dereq_('../core/main'); 71768 71769 var constants = _dereq_('../core/constants'); 71770 /* 71771 * all DEGREES/RADIANS conversion should be done in the p5 instance 71772 * if possible, using the p5._toRadians(), p5._fromRadians() methods. 71773 */ 71774 71775 71776 p5.prototype._angleMode = constants.RADIANS; 71777 /** 71778 * The inverse of <a href="#/p5/cos">cos()</a>, returns the arc cosine of a value. This function 71779 * expects the values in the range of -1 to 1 and values are returned in 71780 * the range 0 to PI (3.1415927). 71781 * 71782 * @method acos 71783 * @param {Number} value the value whose arc cosine is to be returned 71784 * @return {Number} the arc cosine of the given value 71785 * 71786 * @example 71787 * <div class= ânorender"> 71788 * <code> 71789 * let a = PI; 71790 * let c = cos(a); 71791 * let ac = acos(c); 71792 * // Prints: "3.1415927 : -1.0 : 3.1415927" 71793 * print(a + ' : ' + c + ' : ' + ac); 71794 * </code> 71795 * </div> 71796 * 71797 * <div class= ânorender"> 71798 * <code> 71799 * let a = PI + PI / 4.0; 71800 * let c = cos(a); 71801 * let ac = acos(c); 71802 * // Prints: "3.926991 : -0.70710665 : 2.3561943" 71803 * print(a + ' : ' + c + ' : ' + ac); 71804 * </code> 71805 * </div> 71806 */ 71807 71808 p5.prototype.acos = function (ratio) { 71809 return this._fromRadians(Math.acos(ratio)); 71810 }; 71811 /** 71812 * The inverse of <a href="#/p5/sin">sin()</a>, returns the arc sine of a value. This function 71813 * expects the values in the range of -1 to 1 and values are returned 71814 * in the range -PI/2 to PI/2. 71815 * 71816 * @method asin 71817 * @param {Number} value the value whose arc sine is to be returned 71818 * @return {Number} the arc sine of the given value 71819 * 71820 * @example 71821 * <div class= ânorender"> 71822 * <code> 71823 * let a = PI + PI / 3; 71824 * let s = sin(a); 71825 * let as = asin(s); 71826 * // Prints: "1.0471976 : 0.86602545 : 1.0471976" 71827 * print(a + ' : ' + s + ' : ' + as); 71828 * </code> 71829 * </div> 71830 * 71831 * <div class= ânorender"> 71832 * <code> 71833 * let a = PI + PI / 3.0; 71834 * let s = sin(a); 71835 * let as = asin(s); 71836 * // Prints: "4.1887903 : -0.86602545 : -1.0471976" 71837 * print(a + ' : ' + s + ' : ' + as); 71838 * </code> 71839 * </div> 71840 * 71841 */ 71842 71843 71844 p5.prototype.asin = function (ratio) { 71845 return this._fromRadians(Math.asin(ratio)); 71846 }; 71847 /** 71848 * The inverse of <a href="#/p5/tan">tan()</a>, returns the arc tangent of a value. This function 71849 * expects the values in the range of -Infinity to Infinity (exclusive) and 71850 * values are returned in the range -PI/2 to PI/2. 71851 * 71852 * @method atan 71853 * @param {Number} value the value whose arc tangent is to be returned 71854 * @return {Number} the arc tangent of the given value 71855 * 71856 * @example 71857 * <div class= ânorender"> 71858 * <code> 71859 * let a = PI + PI / 3; 71860 * let t = tan(a); 71861 * let at = atan(t); 71862 * // Prints: "1.0471976 : 1.7320509 : 1.0471976" 71863 * print(a + ' : ' + t + ' : ' + at); 71864 * </code> 71865 * </div> 71866 * 71867 * <div class= ânorender"> 71868 * <code> 71869 * let a = PI + PI / 3.0; 71870 * let t = tan(a); 71871 * let at = atan(t); 71872 * // Prints: "4.1887903 : 1.7320513 : 1.0471977" 71873 * print(a + ' : ' + t + ' : ' + at); 71874 * </code> 71875 * </div> 71876 * 71877 */ 71878 71879 71880 p5.prototype.atan = function (ratio) { 71881 return this._fromRadians(Math.atan(ratio)); 71882 }; 71883 /** 71884 * Calculates the angle (in radians) from a specified point to the coordinate 71885 * origin as measured from the positive x-axis. Values are returned as a 71886 * float in the range from PI to -PI. The atan2<a href="#/p5/">()</a> function is most often used 71887 * for orienting geometry to the position of the cursor. 71888 * <br><br> 71889 * Note: The y-coordinate of the point is the first parameter, and the 71890 * x-coordinate is the second parameter, due the the structure of calculating 71891 * the tangent. 71892 * 71893 * @method atan2 71894 * @param {Number} y y-coordinate of the point 71895 * @param {Number} x x-coordinate of the point 71896 * @return {Number} the arc tangent of the given point 71897 * 71898 * @example 71899 * <div> 71900 * <code> 71901 * function draw() { 71902 * background(204); 71903 * translate(width / 2, height / 2);
71904 * let a = atan2(mouseY - height / 2, mouseX - width / 2); 71905 * rotate(a); 71906 * rect(-30, -5, 60, 10); 71907 * } 71908 * </code> 71909 * </div> 71910 * 71911 * @alt 71912 * 60 by 10 rect at center of canvas rotates with mouse movements 71913 * 71914 */ 71915 71916 71917 p5.prototype.atan2 = function (y, x) { 71918 return this._fromRadians(Math.atan2(y, x)); 71919 }; 71920 /** 71921 * Calculates the cosine of an angle. This function takes into account the 71922 * current <a href="#/p5/angleMode">angleMode</a>. Values are returned in the range -1 to 1. 71923 * 71924 * @method cos 71925 * @param {Number} angle the angle 71926 * @return {Number} the cosine of the angle 71927 * 71928 * @example 71929 * <div> 71930 * <code> 71931 * let a = 0.0; 71932 * let inc = TWO_PI / 25.0; 71933 * for (let i = 0; i < 25; i++) { 71934 * line(i * 4, 50, i * 4, 50 + cos(a) * 40.0); 71935 * a = a + inc; 71936 * } 71937 * </code> 71938 * </div> 71939 * 71940 * @alt 71941 * vertical black lines form wave patterns, extend-down on left and right side 71942 * 71943 */ 71944 71945 71946 p5.prototype.cos = function (angle) { 71947 return Math.cos(this._toRadians(angle)); 71948 }; 71949 /** 71950 * Calculates the sine of an angle. This function takes into account the 71951 * current <a href="#/p5/angleMode">angleMode</a>. Values are returned in the range -1 to 1. 71952 * 71953 * @method sin 71954 * @param {Number} angle the angle 71955 * @return {Number} the sine of the angle 71956 * 71957 * @example 71958 * <div> 71959 * <code> 71960 * let a = 0.0; 71961 * let inc = TWO_PI / 25.0; 71962 * for (let i = 0; i < 25; i++) { 71963 * line(i * 4, 50, i * 4, 50 + sin(a) * 40.0); 71964 * a = a + inc; 71965 * } 71966 * </code> 71967 * </div> 71968 * 71969 * @alt 71970 * vertical black lines extend down and up from center to form wave pattern 71971 * 71972 */ 71973 71974 71975 p5.prototype.sin = function (angle) { 71976 return Math.sin(this._toRadians(angle)); 71977 }; 71978 /** 71979 * Calculates the tangent of an angle. This function takes into account 71980 * the current <a href="#/p5/angleMode">angleMode</a>. Values are returned in the range -1 to 1. 71981 * 71982 * @method tan 71983 * @param {Number} angle the angle 71984 * @return {Number} the tangent of the angle 71985 * 71986 * @example 71987 * <div> 71988 * <code> 71989 * let a = 0.0; 71990 * let inc = TWO_PI / 50.0; 71991 * for (let i = 0; i < 100; i = i + 2) { 71992 * line(i, 50, i, 50 + tan(a) * 2.0); 71993 * a = a + inc; 71994 * } 71995 * </code> 71996 * 71997 * 71998 * @alt 71999 * vertical black lines end down and up from center to form spike pattern 72000 * 72001 */ 72002 72003 72004 p5.prototype.tan = function (angle) { 72005 return Math.tan(this._toRadians(angle)); 72006 }; 72007 /** 72008 * Converts a radian measurement to its corresponding value in degrees. 72009 * Radians and degrees are two ways of measuring the same thing. There are 72010 * 360 degrees in a circle and 2*PI radians in a circle. For example, 72011 * 90° = PI/2 = 1.5707964. This function does not take into account the 72012 * current <a href="#/p5/angleMode">angleMode</a>. 72013 * 72014 * @method degrees 72015 * @param {Number} radians the radians value to convert to degrees 72016 * @return {Number} the converted angle 72017 * 72018 * 72019 * @example 72020 * <div class= ânorender"> 72021 * <code> 72022 * let rad = PI / 4; 72023 * let deg = degrees(rad); 72024 * print(rad + ' radians is ' + deg + ' degrees'); 72025 * // Prints: 0.7853981633974483 radians is 45 degrees 72026 * </code> 72027 * </div> 72028 * 72029 */ 72030 72031 72032 p5.prototype.degrees = function (angle) { 72033 return angle * constants.RAD_TO_DEG; 72034 }; 72035 /** 72036 * Converts a degree measurement to its corresponding value in radians. 72037 * Radians and degrees are two ways of measuring the same thing. There are 72038 * 360 degrees in a circle and 2*PI radians in a circle. For example, 72039 * 90° = PI/2 = 1.5707964. This function does not take into account the 72040 * current <a href="#/p5/angleMode">angleMode</a>. 72041 * 72042 * @method radians 72043 * @param {Number} degrees the degree value to convert to radians 72044 * @return {Number} the converted angle 72045 * 72046 * @example 72047 * <div class= ânorender"> 72048 * <code> 72049 * let deg = 45.0; 72050 * let rad = radians(deg); 72051 * print(deg + ' degrees is ' + rad + ' radians'); 72052 * // Prints: 45 degrees is 0.7853981633974483 radians 72053 * </code> 72054 * </div> 72055 */ 72056 72057 72058 p5.prototype.radians = function (angle) { 72059 return angle * constants.DEG_TO_RAD; 72060 }; 72061 /** 72062 * Sets the current mode of p5 to given mode. Default mode is RADIANS. 72063 * 72064 * @method angleMode 72065 * @param {Constant} mode either RADIANS or DEGREES 72066 * 72067 * @example 72068 * <div> 72069 * <code> 72070 * function draw() { 72071 * background(204); 72072 * angleMode(DEGREES); // Change the mode to DEGREES
72073 * let a = atan2(mouseY - height / 2, mouseX - width / 2); 72074 * translate(width / 2, height / 2); 72075 * push(); 72076 * rotate(a); 72077 * rect(-20, -5, 40, 10); // Larger rectangle is rotating in degrees 72078 * pop(); 72079 * angleMode(RADIANS); // Change the mode to RADIANS 72080 * rotate(a); // variable a stays the same 72081 * rect(-40, -5, 20, 10); // Smaller rectangle is rotating in radians 72082 * } 72083 * </code> 72084 * </div> 72085 * 72086 * @alt 72087 * 40 by 10 rect in center rotates with mouse moves. 20 by 10 rect moves faster. 72088 * 72089 * 72090 */ 72091 72092 72093 p5.prototype.angleMode = function (mode) { 72094 if (mode === constants.DEGREES || mode === constants.RADIANS) { 72095 this._angleMode = mode; 72096 } 72097 }; 72098 /** 72099 * converts angles from the current angleMode to RADIANS 72100 * 72101 * @method _toRadians 72102 * @private 72103 * @param {Number} angle 72104 * @returns {Number} 72105 */ 72106 72107 72108 p5.prototype._toRadians = function (angle) { 72109 if (this._angleMode === constants.DEGREES) { 72110 return angle * constants.DEG_TO_RAD; 72111 } 72112 72113 return angle; 72114 }; 72115 /** 72116 * converts angles from the current angleMode to DEGREES 72117 * 72118 * @method _toDegrees 72119 * @private 72120 * @param {Number} angle 72121 * @returns {Number} 72122 */ 72123 72124 72125 p5.prototype._toDegrees = function (angle) { 72126 if (this._angleMode === constants.RADIANS) { 72127 return angle * constants.RAD_TO_DEG; 72128 } 72129 72130 return angle; 72131 }; 72132 /** 72133 * converts angles from RADIANS into the current angleMode 72134 * 72135 * @method _fromRadians 72136 * @private 72137 * @param {Number} angle 72138 * @returns {Number} 72139 */ 72140 72141 72142 p5.prototype._fromRadians = function (angle) { 72143 if (this._angleMode === constants.DEGREES) { 72144 return angle * constants.RAD_TO_DEG; 72145 } 72146 72147 return angle; 72148 }; 72149 72150 module.exports = p5; 72151 }, {
72152 "../core/constants": 18, 72153 "../core/main": 24 72154 }], 72155 57: [function (_dereq_, module, exports) { 72156 /** 72157 * @module Typography 72158 * @submodule Attributes 72159 * @for p5 72160 * @requires core 72161 * @requires constants 72162 */ 72163 'use strict'; 72164 72165 var p5 = _dereq_('../core/main'); 72166 /** 72167 * Sets the current alignment for drawing text. Accepts two 72168 * arguments: horizAlign (LEFT, CENTER, or RIGHT) and 72169 * vertAlign (TOP, BOTTOM, CENTER, or BASELINE). 72170 * 72171 * The horizAlign parameter is in reference to the x value 72172 * of the <a href="#/p5/text">text()</a> function, while the vertAlign parameter is 72173 * in reference to the y value. 72174 * 72175 * So if you write textAlign(LEFT), you are aligning the left 72176 * edge of your text to the x value you give in <a href="#/p5/text">text()</a>. If you 72177 * write textAlign(RIGHT, TOP), you are aligning the right edge 72178 * of your text to the x value and the top of edge of the text 72179 * to the y value. 72180 * 72181 * @method textAlign 72182 * @param {Constant} horizAlign horizontal alignment, either LEFT, 72183 * CENTER, or RIGHT 72184 * @param {Constant} [vertAlign] vertical alignment, either TOP, 72185 * BOTTOM, CENTER, or BASELINE 72186 * @chainable 72187 * @example 72188 * <div> 72189 * <code> 72190 * textSize(16); 72191 * textAlign(RIGHT); 72192 * text('ABCD', 50, 30); 72193 * textAlign(CENTER); 72194 * text('EFGH', 50, 50); 72195 * textAlign(LEFT); 72196 * text('IJKL', 50, 70); 72197 * </code> 72198 * </div> 72199 * 72200 * <div> 72201 * <code> 72202 * textSize(16); 72203 * strokeWeight(0.5); 72204 * 72205 * line(0, 12, width, 12); 72206 * textAlign(CENTER, TOP); 72207 * text('TOP', 0, 12, width); 72208 * 72209 * line(0, 37, width, 37); 72210 * textAlign(CENTER, CENTER); 72211 * text('CENTER', 0, 37, width); 72212 * 72213 * line(0, 62, width, 62); 72214 * textAlign(CENTER, BASELINE); 72215 * text('BASELINE', 0, 62, width); 72216 * 72217 * line(0, 87, width, 87); 72218 * textAlign(CENTER, BOTTOM); 72219 * text('BOTTOM', 0, 87, width); 72220 * </code> 72221 * </div> 72222 * 72223 * @alt 72224 *Letters ABCD displayed at top right, EFGH at center and IJKL at bottom left. 72225 * The names of the four vertical alignments rendered each showing that alignment's placement relative to a horizontal line. 72226 * 72227 */ 72228 72229 /** 72230 * @method textAlign 72231 * @return {Object} 72232 */ 72233 72234 72235 p5.prototype.textAlign = function (horizAlign, vertAlign) { 72236 p5._validateParameters('textAlign', arguments); 72237 72238 return this._renderer.textAlign.apply(this._renderer, arguments); 72239 }; 72240 /** 72241 * Sets/gets the spacing, in pixels, between lines of text. This 72242 * setting will be used in all subsequent calls to the <a href="#/p5/text">text()</a> function. 72243 * 72244 * @method textLeading 72245 * @param {Number} leading the size in pixels for spacing between lines 72246 * @chainable 72247 * 72248 * @example 72249 * <div> 72250 * <code> 72251 * // Text to display. The "\n" is a "new line" character 72252 * let lines = 'L1\nL2\nL3'; 72253 * textSize(12); 72254 * 72255 * textLeading(10); // Set leading to 10 72256 * text(lines, 10, 25); 72257 * 72258 * textLeading(20); // Set leading to 20 72259 * text(lines, 40, 25); 72260 * 72261 * textLeading(30); // Set leading to 30 72262 * text(lines, 70, 25); 72263 * </code> 72264 * </div> 72265 * 72266 * @alt 72267 *set L1 L2 & L3 displayed vertically 3 times. spacing increases for each set 72268 */ 72269 72270 /** 72271 * @method textLeading 72272 * @return {Number} 72273 */ 72274 72275 72276 p5.prototype.textLeading = function (theLeading) { 72277 p5._validateParameters('textLeading', arguments); 72278 72279 return this._renderer.textLeading.apply(this._renderer, arguments); 72280 }; 72281 /** 72282 * Sets/gets the current font size. This size will be used in all subsequent 72283 * calls to the <a href="#/p5/text">text()</a> function. Font size is measured in pixels. 72284 * 72285 * @method textSize 72286 * @param {Number} theSize the size of the letters in units of pixels 72287 * @chainable 72288 * 72289 * @example 72290 * <div> 72291 * <code> 72292 * textSize(12); 72293 * text('Font Size 12', 10, 30); 72294 * textSize(14); 72295 * text('Font Size 14', 10, 60); 72296 * textSize(16); 72297 * text('Font Size 16', 10, 90); 72298 * </code> 72299 * </div> 72300 * 72301 * @alt 72302 *Font Size 12 displayed small, Font Size 14 medium & Font Size 16 large 72303 */ 72304 72305 /** 72306 * @method textSize 72307 * @return {Number} 72308 */ 72309 72310 72311 p5.prototype.textSize = function (theSize) { 72312 p5._validateParameters('textSize', arguments); 72313 72314 return this._renderer.textSize.apply(this._renderer, arguments); 72315 }; 72316 /** 72317 * Sets/gets the style of the text for system fonts to NORMAL, ITALIC, BOLD or BOLDITALIC. 72318 * Note: this may be is overridden by CSS styling. For non-system fonts 72319 * (opentype, truetype, etc.) please load styled fonts instead. 72320 * 72321 * @method textStyle 72322 * @param {Constant} theStyle styling for text, either NORMAL, 72323 * ITALIC, BOLD or BOLDITALIC 72324 * @chainable 72325 * @example 72326 * <div> 72327 * <code> 72328 * strokeWeight(0); 72329 * textSize(12); 72330 * textStyle(NORMAL); 72331 * text('Font Style Normal', 10, 15); 72332 * textStyle(ITALIC); 72333 * text('Font Style Italic', 10, 40); 72334 * textStyle(BOLD); 72335 * text('Font Style Bold', 10, 65); 72336 * textStyle(BOLDITALIC); 72337 * text('Font Style Bold Italic', 10, 90); 72338 * </code> 72339 * </div> 72340 * 72341 * @alt 72342 *words Font Style Normal displayed normally, Italic in italic, bold in bold and bold italic in bold italics. 72343 */ 72344 72345 /** 72346 * @method textStyle 72347 * @return {String} 72348 */ 72349 72350 72351 p5.prototype.textStyle = function (theStyle) { 72352 p5._validateParameters('textStyle', arguments); 72353 72354 return this._renderer.textStyle.apply(this._renderer, arguments); 72355 }; 72356 /** 72357 * Calculates and returns the width of any character or text str
72357ing. 72358 * 72359 * @method textWidth 72360 * @param {String} theText the String of characters to measure 72361 * @return {Number} 72362 * @example 72363 * <div> 72364 * <code> 72365 * textSize(28); 72366 * 72367 * let aChar = 'P'; 72368 * let cWidth = textWidth(aChar); 72369 * text(aChar, 0, 40); 72370 * line(cWidth, 0, cWidth, 50); 72371 * 72372 * let aString = 'p5.js'; 72373 * let sWidth = textWidth(aString); 72374 * text(aString, 0, 85); 72375 * line(sWidth, 50, sWidth, 100); 72376 * </code> 72377 * </div> 72378 * 72379 * @alt 72380 *Letter P and p5.js are displayed with vertical lines at end. P is wide 72381 * 72382 */ 72383 72384 72385 p5.prototype.textWidth = function (theText) { 72386 p5._validateParameters('textWidth', arguments); 72387 72388 if (theText.length === 0) { 72389 return 0; 72390 } 72391 72392 return this._renderer.textWidth.apply(this._renderer, arguments); 72393 }; 72394 /** 72395 * Returns the ascent of the current font at its current size. The ascent 72396 * represents the distance, in pixels, of the tallest character above 72397 * the baseline. 72398 * @method textAscent 72399 * @return {Number} 72400 * @example 72401 * <div> 72402 * <code> 72403 * let base = height * 0.75; 72404 * let scalar = 0.8; // Different for each font 72405 * 72406 * textSize(32); // Set initial text size 72407 * let asc = textAscent() * scalar; // Calc ascent 72408 * line(0, base - asc, width, base - asc); 72409 * text('dp', 0, base); // Draw text on baseline 72410 * 72411 * textSize(64); // Increase text size 72412 * asc = textAscent() * scalar; // Recalc ascent 72413 * line(40, base - asc, width, base - asc); 72414 * text('dp', 40, base); // Draw text on baseline 72415 * </code> 72416 * </div> 72417 */ 72418 72419 72420 p5.prototype.textAscent = function () { 72421 p5._validateParameters('textAscent', arguments); 72422 72423 return this._renderer.textAscent(); 72424 }; 72425 /** 72426 * Returns the descent of the current font at its current size. The descent 72427 * represents the distance, in pixels, of the character with the longest 72428 * descender below the baseline. 72429 * @method textDescent 72430 * @return {Number} 72431 * @example 72432 * <div> 72433 * <code> 72434 * let base = height * 0.75; 72435 * let scalar = 0.8; // Different for each font 72436 * 72437 * textSize(32); // Set initial text size 72438 * let desc = textDescent() * scalar; // Calc ascent 72439 * line(0, base + desc, width, base + desc); 72440 * text('dp', 0, base); // Draw text on baseline 72441 * 72442 * textSize(64); // Increase text size 72443 * desc = textDescent() * scalar; // Recalc ascent 72444 * line(40, base + desc, width, base + desc); 72445 * text('dp', 40, base); // Draw text on baseline 72446 * </code> 72447 * </div> 72448 */ 72449 72450 72451 p5.prototype.textDescent = function () { 72452 p5._validateParameters('textDescent', arguments); 72453 72454 return this._renderer.textDescent(); 72455 }; 72456 /** 72457 * Helper function to measure ascent and descent. 72458 */ 72459 72460 72461 p5.prototype._updateTextMetrics = function () { 72462 return this._renderer._updateTextMetrics(); 72463 }; 72464 72465 module.exports = p5; 72466 }, {
72467 "../core/main": 24 72468 }], 72469 58: [function (_dereq_, module, exports) { 72470 /** 72471 * @module Typography 72472 * @submodule Loading & Displaying 72473 * @for p5 72474 * @requires core 72475 */ 72476 'use strict'; 72477 72478 var p5 = _dereq_('../core/main'); 72479 72480 var constants = _dereq_('../core/constants'); 72481 72482 var opentype = _dereq_('opentype.js'); 72483 72484 _dereq_('../core/error_helpers'); 72485 /** 72486 * Loads an opentype font file (.otf, .ttf) from a file or a URL, 72487 * and returns a PFont Object. This method is asynchronous, 72488 * meaning it may not finish before the next line in your sketch 72489 * is executed. 72490 * <br><br> 72491 * The path to the font should be relative to the HTML file 72492 * that links in your sketch. Loading fonts from a URL or other 72493 * remote location may be blocked due to your browser's built-in 72494 * security. 72495 * 72496 * @method loadFont 72497 * @param {String} path name of the file or url to load 72498 * @param {Function} [callback] function to be executed after 72499 * <a href="#/p5/loadFont">loadFont()</a> completes 72500 * @param {Function} [onError] function to be executed if 72501 * an error occurs 72502 * @return {p5.Font} <a href="#/p5.Font">p5.Font</a> object 72503 * @example 72504 * 72505 * <p>Calling loadFont() inside <a href="#/p5/preload">preload()</a> guarantees that the load 72506 * operation will have completed before <a href="#/p5/setup">setup()</a> and <a href="#/p5/draw">draw()</a> are called.</p> 72507 * 72508 * <div><code> 72509 * let myFont; 72510 * function preload() { 72511 * myFont = loadFont('assets/AvenirNextLTPro-Demi.otf'); 72512 * } 72513 * 72514 * function setup() { 72515 * fill('#ED225D'); 72516 * textFont(myFont); 72517 * textSize(36); 72518 * text('p5*js', 10, 50); 72519 * } 72520 * </code></div> 72521 * 72522 * Outside of <a href="#/p5/preload">preload()</a>, you may supply a callback function to handle the 72523 * object: 72524 * 72525 * <div><code> 72526 * function setup() { 72527 * loadFont('assets/AvenirNextLTPro-Demi.otf', drawText); 72528 * } 72529 * 72530 * function drawText(font) { 72531 * fill('#ED225D'); 72532 * textFont(font, 36); 72533 * text('p5*js', 10, 50); 72534 * } 72535 * </code></div> 72536 * 72537 * <p>You can also use the font filename string (without the file extension) to style other HTML 72538 * elements.</p> 72539 * 72540 * <div><code> 72541 * function preload() { 72542 * loadFont('assets/Avenir.otf'); 72543 * } 72544 * 72545 * function setup() { 72546 * let myDiv = createDiv('hello there'); 72547 * myDiv.style('font-family', 'Avenir'); 72548 * } 72549 * </code></div> 72550 * 72551 * @alt 72552 * p5*js in p5's theme dark pink 72553 * p5*js in p5's theme dark pink 72554 * 72555 */ 72556 72557 72558 p5.prototype.loadFont = function (path, onSuccess, onError) { 72559 p5._validateParameters('loadFont', arguments); 72560 72561 var p5Font = new p5.Font(this); 72562 var self = this; 72563 opentype.load(path, function (err, font) { 72564 if (err) { 72565 p5._friendlyFileLoadError(4, path); 72566 72567 if (typeof onError !== 'undefined') { 72568 return onError(err); 72569 } 72570 72571 console.error(err, path); 72572 return; 72573 } 72574 72575 p5Font.font = font; 72576 72577 if (typeof onSuccess !== 'undefined') { 72578 onSuccess(p5Font); 72579 } 72580 72581 self._decrementPreload(); // check that we have an acceptable font type 72582 72583 72584 var validFontTypes = ['ttf', 'otf', 'woff', 'woff2'], 72585 fileNoPath = path.split('\\').pop().split('/').pop(), 72586 lastDotIdx = fileNoPath.lastIndexOf('.'), 72587 fontFamily, 72588 newStyle, 72589 fileExt = lastDotIdx < 1 ? null : fileNoPath.substr(lastDotIdx + 1); // if so, add it to the DOM (name-only) for use with p5.dom 72590 72591 if (validFontTypes.indexOf(fileExt) > -1) { 72592 fontFamily = fileNoPath.substr(0, lastDotIdx); 72593 newStyle = document.createElement('style'); 72594 newStyle.appendChild(document.createTextNode('\n@font-face {' + '\nfont-family: ' + fontFamily + ';\nsrc: url(' + path + ');\n}\n')); 72595 document.head.appendChild(newStyle); 72596 } 72597 }); 72598 return p5Font; 72599 }; 72600 /** 72601 * Draws text to the screen. Displays the information specified in the first 72602 * parameter on the screen in the position specified by the additional 72603 * parameters. A default font will be used unless a font is set with the 72604 * <a href="#/p5/textFont">textFont()</a> function and a default size will be used unless a font is set 72605 * with <a href="#/p5/textSize">textSize()</a>. Change the color of the text with the <a href="#/p5/fill">fill()</a> function. 72606 * Change the outline of the text with the <a href="#/p5/stroke">stroke()</a> and <a href="#/p5/strokeWeight">
72606strokeWeight()</a> 72607 * functions. 72608 * <br><br> 72609 * The text displays in relation to the <a href="#/p5/textAlign">textAlign()</a> function, which gives the 72610 * option to draw to the left, right, and center of the coordinates. 72611 * <br><br> 72612 * The x2 and y2 parameters define a rectangular area to display within and 72613 * may only be used with string data. When these parameters are specified, 72614 * they are interpreted based on the current <a href="#/p5/rectMode">rectMode()</a> setting. Text that 72615 * does not fit completely within the rectangle specified will not be drawn 72616 * to the screen. If x2 and y2 are not specified, the baseline alignment is the 72617 * default, which means that the text will be drawn upwards from x and y. 72618 * <br><br> 72619 * <b>WEBGL</b>: Only opentype/truetype fonts are supported. You must load a font using the 72620 * <a href="#/p5/loadFont">loadFont()</a> method (see the example above). 72621 * <a href="#/p5/stroke">stroke()</a> currently has no effect in webgl mode. 72622 * 72623 * @method text 72624 * @param {String|Object|Array|Number|Boolean} str the alphanumeric 72625 * symbols to be displayed 72626 * @param {Number} x x-coordinate of text 72627 * @param {Number} y y-coordinate of text 72628 * @param {Number} [x2] by default, the width of the text box, 72629 * see <a href="#/p5/rectMode">rectMode()</a> for more info 72630 * @param {Number} [y2] by default, the height of the text box, 72631 * see <a href="#/p5/rectMode">rectMode()</a> for more info 72632 * @chainable 72633 * @example 72634 * <div> 72635 * <code> 72636 * textSize(32); 72637 * text('word', 10, 30); 72638 * fill(0, 102, 153); 72639 * text('word', 10, 60); 72640 * fill(0, 102, 153, 51); 72641 * text('word', 10, 90); 72642 * </code> 72643 * </div> 72644 * <div> 72645 * <code> 72646 * let s = 'The quick brown fox jumped over the lazy dog.'; 72647 * fill(50); 72648 * text(s, 10, 10, 70, 80); // Text wraps within text box 72649 * </code> 72650 * </div> 72651 * 72652 * <div modernizr='webgl'> 72653 * <code> 72654 * let avenir; 72655 * function preload() { 72656 * avenir = loadFont('assets/Avenir.otf'); 72657 * } 72658 * function setup() { 72659 * createCanvas(100, 100, WEBGL); 72660 * textFont(avenir); 72661 * textSize(width / 3); 72662 * textAlign(CENTER, CENTER); 72663 * } 72664 * function draw() { 72665 * background(0); 72666 * let time = millis(); 72667 * rotateX(time / 1000); 72668 * rotateZ(time / 1234); 72669 * text('p5.js', 0, 0); 72670 * } 72671 * </code> 72672 * </div> 72673 * 72674 * @alt 72675 *'word' displayed 3 times going from black, blue to translucent blue 72676 * The quick brown fox jumped over the lazy dog. 72677 * the text 'p5.js' spinning in 3d 72678 * 72679 */ 72680 72681 72682 p5.prototype.text = function (str, x, y, maxWidth, maxHeight) { 72683 p5._validateParameters('text', arguments); 72684 72685 return !(this._renderer._doFill || this._renderer._doStroke) ? this : this._renderer.text.apply(this._renderer, arguments); 72686 }; 72687 /** 72688 * Sets the current font that will be drawn with the <a href="#/p5/text">text()</a> function. 72689 * <br><br> 72690 * <b>WEBGL</b>: Only fonts loaded via <a href="#/p5/loadFont">loadFont()</a> are supported. 72691 * 72692 * @method textFont 72693 * @return {Object} the current font 72694 * 72695 * @example 72696 * <div> 72697 * <code> 72698 * fill(0); 72699 * textSize(12); 72700 * textFont('Georgia'); 72701 * text('Georgia', 12, 30); 72702 * textFont('Helvetica'); 72703 * text('Helvetica', 12, 60); 72704 * </code> 72705 * </div> 72706 * <div> 72707 * <code> 72708 * let fontRegular, fontItalic, fontBold; 72709 * function preload() { 72710 * fontRegular = loadFont('assets/Regular.otf'); 72711 * fontItalic = loadFont('assets/Italic.ttf'); 72712 * fontBold = loadFont('assets/Bold.ttf'); 72713 * } 72714 * function setup() { 72715 * background(210); 72716 * fill(0) 72717 .strokeWeight(0) 72718 .textSize(10); 72719 * textFont(fontRegular); 72720 * text('Font Style Normal', 10, 30); 72721 * textFont(fontItalic); 72722 * text('Font Style Italic', 10, 50); 72723 * textFont(fontBold); 72724 * text('Font Style Bold', 10, 70); 72725 * } 72726 * </code> 72727 * </div> 72728 * 72729 * @alt 72730 *words Font Style Normal displayed normally, Italic in italic and bold in bold 72731 */ 72732 72733 /** 72734 * @method textFont 72735 * @param {Object|String} font a font loaded via <a href="#/p5/loadFont">loadFont()</a>, or a String 72736 * representing a <a href="https://mzl.la/2dOw8WD">web safe font</a> (a font 72737 * that is generally available across all systems) 72738 * @param {Number} [size] the font size to use 72739 * @chainable 72740 */ 72741 72742 72743 p5.prototype.textFont = function (theFont, theSize) { 72744 p5._validateParameters('textFont', arguments); 72745 72746 if (arguments.length) { 72747 if (!theFont) { 72748 throw new Error('null font passed to textFont'); 72749 } 72750 72751 this._renderer._setProperty('_textFont', theFont); 72752 72753 if (theSize) { 72754 this._renderer._setProperty('_textSize', theSize); 72755 72756 this._renderer._setProperty('_textLeading', theSize * constants._DEFAULT_LEADMULT); 72757 } 72758 72759 return this._renderer._applyTextProperties(); 72760 } 72761 72762 return this._renderer._textFont; 72763 }; 72764 72765 module.exports = p5; 72766 }, {
72767 "../core/constants": 18, 72768 "../core/error_helpers": 20, 72769 "../core/main": 24, 72770 "opentype.js": 10 72771 }], 72772 59: [function (_dereq_, module, exports) { 72773 /** 72774 * This module defines the <a href="#/p5.Font">p5.Font</a> class and functions for 72775 * drawing text to the display canvas. 72776 * @module Typography 72777 * @submodule Font 72778 * @requires core 72779 * @requires constants 72780 */ 72781 'use strict'; 72782 72783 var p5 = _dereq_('../core/main'); 72784 72785 var constants = _dereq_('../core/constants'); 72786 /** 72787 * Base class for font handling 72788 * @class p5.Font 72789 * @param {p5} [pInst] pointer to p5 instance 72790 */ 72791 72792 72793 p5.Font = function (p) { 72794 this.parent = p; 72795 this.cache = {}; 72796 /** 72797 * Underlying opentype font implementation 72798 * @property font 72799 */ 72800 72801 this.font = undefined; 72802 }; 72803 /** 72804 * Returns a tight bounding box for the given text string using this 72805 * font (currently only supports single lines) 72806 * 72807 * @method textBounds 72808 * @param {String} line a line of text 72809 * @param {Number} x x-position 72810 * @param {Number} y y-position 72811 * @param {Number} [fontSize] font size to use (optional) Default is 12. 72812 * @param {Object} [options] opentype options (optional) 72813 * opentype fonts contains alignment and baseline options. 72814 * Default is 'LEFT' and 'alphabetic' 72815 * 72816 * 72817 * @return {Object} a rectangle object with properties: x, y, w, h 72818 * 72819 * @example 72820 * <div> 72821 * <code> 72822 * let font; 72823 * let textString = 'Lorem ipsum dolor sit amet.'; 72824 * function preload() { 72825 * font = loadFont('./assets/Regular.otf'); 72826 * } 72827 * function setup() { 72828 * background(210); 72829 * 72830 * let bbox = font.textBounds(textString, 10, 30, 12); 72831 * fill(255); 72832 * stroke(0); 72833 * rect(bbox.x, bbox.y, bbox.w, bbox.h); 72834 * fill(0); 72835 * noStroke(); 72836 * 72837 * textFont(font); 72838 * textSize(12); 72839 * text(textString, 10, 30); 72840 * } 72841 * </code> 72842 * </div> 72843 * 72844 * @alt 72845 *words Lorem ipsum dol go off canvas and contained by white bounding box 72846 * 72847 */ 72848 72849 72850 p5.Font.prototype.textBounds = function (str, x, y, fontSize, opts) { 72851 x = x !== undefined ? x : 0; 72852 y = y !== undefined ? y : 0; // Check cache for existing bounds. Take into consideration the text alignment 72853 // settings. Default alignment should match opentype's origin: left-aligned & 72854 // alphabetic baseline. 72855 72856 var p = opts && opts.renderer && opts.renderer._pInst || this.parent, 72857 ctx = p._renderer.drawingContext, 72858 alignment = ctx.textAlign || constants.LEFT, 72859 baseline = ctx.textBaseline || constants.BASELINE, 72860 cacheResults = false, 72861 result, 72862 key; 72863 fontSize = fontSize || p._renderer._textSize; // NOTE: cache disabled for now pending further discussion of #3436 72864 72865 if (cacheResults) { 72866 key = cacheKey('textBounds', str, x, y, fontSize, alignment, baseline); 72867 result = this.cache[key]; 72868 } 72869 72870 if (!result) { 72871 var minX, 72872 minY, 72873 maxX, 72874 maxY, 72875 pos, 72876 xCoords = [], 72877 yCoords = [], 72878 scale = this._scale(fontSize); 72879 72880 this.font.forEachGlyph(str, x, y, fontSize, opts, function (glyph, gX, gY, gFontSize) { 72881 var gm = glyph.getMetrics(); 72882 xCoords.push(gX + gm.xMin * scale); 72883 xCoords.push(gX + gm.xMax * scale); 72884 yCoords.push(gY + -gm.yMin * scale); 72885 yCoords.push(gY + -gm.yMax * scale); 72886 }); 72887 minX = Math.min.apply(null, xCoords); 72888 minY = Math.min.apply(null, yCoords); 72889 maxX = Math.max.apply(null, xCoords); 72890 maxY = Math.max.apply(null, yCoords); 72891 result = { 72892 x: minX, 72893 y: minY, 72894 h: maxY - minY, 72895 w: maxX - minX, 72896 advance: minX - x 72897 }; // Bounds are now calculated, so shift the x & y to match alignment settings 72898 72899 pos = this._handleAlignment(p._renderer, str, result.x, result.y, result.w + result.advance); 72900 result.x = pos.x; 72901 result.y = pos.y; 72902 72903 if (cacheResults) { 72904 this.cache[key] = result; 72905 } 72906 } 72907 72908 return result; 72909 }; 72910 /** 72911 * Computes an array of points following the path for specified text 72912 * 72913 * @method textToPoints 72914 * @param {String} txt a line of text 72915 * @param {Number} x x-position 72916 * @param {Number} y y-position 72917 * @param {Number} fontSize font size to use (optional) 72918 * @param {Object} [options] an (optional) object that can contain: 72919 * 72920 * <br>sampleFactor - the ratio of path-length to number of samples 72921 * (default=.25); higher values yield more points and are therefore 72922 * more precise 72923 * 72924 * <br>simplifyThreshold - if set to a non-zero value, collinear points will be 72925 * be removed from the polygon; the value represents the threshold angle to use 72926 * when determining whether two edges are collinear 72927 * 72928 * @return {Array} an array of points, each with x, y, alpha (the path angle) 72929 * @example 72930 * <div> 72931 * <code> 72932 * let font; 72933 * function preload() { 72934 * font = loadFont('./assets/Avenir.otf'); 72935 * } 72936 * 72937 * let points; 72938 * let bounds; 72939 * function setup() { 72940 * createCanvas(100, 100); 72941 * stroke(0); 72942 * fill(255, 104, 204); 72943 * 72944 * points = font.textToPoints('p5', 0, 0, 10, { 72945 * sampleFactor: 5, 72946 * simplifyThreshold: 0 72947 * }); 72948 * bounds = font.textBounds(' p5 ', 0, 0, 10); 72949 * } 72950 * 72951 * function draw() { 72952 * background(255); 72953 * beginShape(); 72954 * translate(-bounds.x * width / bounds.w, -bounds.y * height / bounds.h); 72955 * for (let i = 0; i < points.length; i++) { 72956 * let p = points[i]; 72957 * vertex( 72958 * p.x * width / bounds.w +
72959 * sin(20 * p.y / bounds.h + millis() / 1000) * width / 30, 72960 * p.y * height / bounds.h 72961 * ); 72962 * } 72963 * endShape(CLOSE); 72964 * } 72965 * </code> 72966 * </div> 72967 * 72968 */ 72969 72970 72971 p5.Font.prototype.textToPoints = function (txt, x, y, fontSize, options) { 72972 var xoff = 0, 72973 result = [], 72974 glyphs = this._getGlyphs(txt); 72975 72976 function isSpace(i) { 72977 return glyphs[i].name && glyphs[i].name === 'space' || txt.length === glyphs.length && txt[i] === ' ' || glyphs[i].index && glyphs[i].index === 3; 72978 } 72979 72980 fontSize = fontSize || this.parent._renderer._textSize; 72981 72982 for (var i = 0; i < glyphs.length; i++) { 72983 if (!isSpace(i)) { 72984 // fix to #1817, #2069 72985 var gpath = glyphs[i].getPath(x, y, fontSize), 72986 paths = splitPaths(gpath.commands); 72987 72988 for (var j = 0; j < paths.length; j++) { 72989 var pts = pathToPoints(paths[j], options); 72990 72991 for (var k = 0; k < pts.length; k++) { 72992 pts[k].x += xoff; 72993 result.push(pts[k]); 72994 } 72995 } 72996 } 72997 72998 xoff += glyphs[i].advanceWidth * this._scale(fontSize); 72999 } 73000 73001 return result; 73002 }; // ----------------------------- End API ------------------------------ 73003 73004 /** 73005 * Returns the set of opentype glyphs for the supplied string. 73006 * 73007 * Note that there is not a strict one-to-one mapping between characters 73008 * and glyphs, so the list of returned glyphs can be larger or smaller 73009 * than the length of the given string. 73010 * 73011 * @private 73012 * @param {String} str the string to be converted 73013 * @return {Array} the opentype glyphs 73014 */ 73015 73016 73017 p5.Font.prototype._getGlyphs = function (str) { 73018 return this.font.stringToGlyphs(str); 73019 }; 73020 /** 73021 * Returns an opentype path for the supplied string and position. 73022 * 73023 * @private 73024 * @param {String} line a line of text 73025 * @param {Number} x x-position 73026 * @param {Number} y y-position 73027 * @param {Object} options opentype options (optional) 73028 * @return {Object} the opentype path 73029 */ 73030 73031 73032 p5.Font.prototype._getPath = function (line, x, y, options) { 73033 var p = options && options.renderer && options.renderer._pInst || this.parent, 73034 renderer = p._renderer, 73035 pos = this._handleAlignment(renderer, line, x, y); 73036 73037 return this.font.getPath(line, pos.x, pos.y, renderer._textSize, options); 73038 }; 73039 /* 73040 * Creates an SVG-formatted path-data string 73041 * (See http://www.w3.org/TR/SVG/paths.html#PathData) 73042 * from the given opentype path or string/position 73043 * 73044 * @param {Object} path an opentype path, OR the following: 73045 * 73046 * @param {String} line a line of text 73047 * @param {Number} x x-position 73048 * @param {Number} y y-position 73049 * @param {Object} options opentype options (optional), set options.decimals 73050 * to set the decimal precision of the path-data 73051 * 73052 * @return {Object} this p5.Font object 73053 */ 73054 73055 73056 p5.Font.prototype._getPathData = function (line, x, y, options) { 73057 var decimals = 3; // create path from string/position 73058 73059 if (typeof line === 'string' && arguments.length > 2) { 73060 line = this._getPath(line, x, y, options); 73061 } else if (typeof x === 'object') { 73062 // handle options specified in 2nd arg 73063 options = x; 73064 } // handle svg arguments 73065 73066 73067 if (options && typeof options.decimals === 'number') { 73068 decimals = options.decimals; 73069 } 73070 73071 return line.toPathData(decimals); 73072 }; 73073 /* 73074 * Creates an SVG <path> element, as a string, 73075 * from the given opentype path or string/position 73076 * 73077 * @param {Object} path an opentype path, OR the following: 73078 * 73079 * @param {String} line a line of text 73080 * @param {Number} x x-position 73081 * @param {Number} y y-position 73082 * @param {Object} options opentype options (optional), set options.decimals 73083 * to set the decimal precision of the path-data in the <path> element, 73084 * options.fill to set the fill color for the <path> element, 73085 * options.stroke to set the stroke color for the <path> element, 73086 * options.strokeWidth to set the strokeWidth for the <path> element. 73087 * 73088 * @return {Object} this p5.Font object 73089 */ 73090 73091 73092 p5.Font.prototype._getSVG = function (line, x, y, options) { 73093 var decimals = 3; // create path from string/position 73094 73095 if (typeof line === 'string' && arguments.length > 2) { 73096 line = this._getPath(line, x, y, options); 73097 } else if (typeof x === 'object') { 73098 // handle options specified in 2nd arg 73099 options = x; 73100 } // handle svg arguments 73101 73102 73103 if (options) { 73104 if (typeof options.decimals === 'number') { 73105 decimals = options.decimals; 73106 } 73107 73108 if (typeof options.strokeWidth === 'number') { 73109 line.strokeWidth = options.strokeWidth; 73110 } 73111 73112 if (typeof options.fill !== 'undefined') { 73113 line.fill = options.fill; 73114 } 73115 73116 if (typeof options.stroke !== 'undefined') { 73117 line.stroke = options.stroke; 73118 } 73119 } 73120 73121 return line.toSVG(decimals); 73122 }; 73123 /*
73124 * Renders an opentype path or string/position 73125 * to the current graphics context 73126 * 73127 * @param {Object} path an opentype path, OR the following: 73128 * 73129 * @param {String} line a line of text 73130 * @param {Number} x x-position 73131 * @param {Number} y y-position 73132 * @param {Object} options opentype options (optional) 73133 * 73134 * @return {p5.Font} this p5.Font object 73135 */ 73136 73137 73138 p5.Font.prototype._renderPath = function (line, x, y, options) { 73139 var pdata, 73140 pg = options && options.renderer || this.parent._renderer, 73141 ctx = pg.drawingContext; 73142 73143 if (typeof line === 'object' && line.commands) { 73144 pdata = line.commands; 73145 } else { 73146 //pos = handleAlignment(p, ctx, line, x, y); 73147 pdata = this._getPath(line, x, y, options).commands; 73148 } 73149 73150 ctx.beginPath(); 73151 73152 for (var i = 0; i < pdata.length; i += 1) { 73153 var cmd = pdata[i]; 73154 73155 if (cmd.type === 'M') { 73156 ctx.moveTo(cmd.x, cmd.y); 73157 } else if (cmd.type === 'L') { 73158 ctx.lineTo(cmd.x, cmd.y); 73159 } else if (cmd.type === 'C') { 73160 ctx.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y); 73161 } else if (cmd.type === 'Q') { 73162 ctx.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y); 73163 } else if (cmd.type === 'Z') { 73164 ctx.closePath(); 73165 } 73166 } // only draw stroke if manually set by user 73167 73168 73169 if (pg._doStroke && pg._strokeSet) { 73170 ctx.stroke(); 73171 } 73172 73173 if (pg._doFill) { 73174 // if fill hasn't been set by user, use default-text-fill 73175 if (!pg._fillSet) { 73176 pg._setFill(constants._DEFAULT_TEXT_FILL); 73177 } 73178 73179 ctx.fill(); 73180 } 73181 73182 return this; 73183 }; 73184 73185 p5.Font.prototype._textWidth = function (str, fontSize) { 73186 return this.font.getAdvanceWidth(str, fontSize); 73187 }; 73188 73189 p5.Font.prototype._textAscent = function (fontSize) { 73190 return this.font.ascender * this._scale(fontSize); 73191 }; 73192 73193 p5.Font.prototype._textDescent = function (fontSize) { 73194 return -this.font.descender * this._scale(fontSize); 73195 }; 73196 73197 p5.Font.prototype._scale = function (fontSize) { 73198 return 1 / this.font.unitsPerEm * (fontSize || this.parent._renderer._textSize); 73199 }; 73200 73201 p5.Font.prototype._handleAlignment = function (renderer, line, x, y, textWidth) { 73202 var fontSize = renderer._textSize; 73203 73204 if (typeof textWidth === 'undefined') { 73205 textWidth = this._textWidth(line, fontSize); 73206 } 73207 73208 switch (renderer._textAlign) { 73209 case constants.CENTER: 73210 x -= textWidth / 2; 73211 break; 73212 73213 case constants.RIGHT: 73214 x -= textWidth; 73215 break; 73216 } 73217 73218 switch (renderer._textBaseline) { 73219 case constants.TOP: 73220 y += this._textAscent(fontSize); 73221 break; 73222 73223 case constants.CENTER: 73224 y += this._textAscent(fontSize) / 2; 73225 break; 73226 73227 case constants.BOTTOM: 73228 y -= this._textDescent(fontSize); 73229 break; 73230 } 73231 73232 return { 73233 x: x, 73234 y: y 73235 }; 73236 }; // path-utils 73237 73238 73239 function pathToPoints(cmds, options) { 73240 var opts = parseOpts(options, { 73241 sampleFactor: 0.1, 73242 simplifyThreshold: 0 73243 }); 73244 var len = pointAtLength(cmds, 0, 1), 73245 // total-length 73246 t = len / (len * opts.sampleFactor), 73247 pts = []; 73248 73249 for (var i = 0; i < len; i += t) { 73250 pts.push(pointAtLength(cmds, i)); 73251 } 73252 73253 if (opts.simplifyThreshold) { 73254 simplify(pts, opts.simplifyThreshold); 73255 } 73256 73257 return pts; 73258 } 73259 73260 function simplify(pts, angle) { 73261 angle = typeof angle === 'undefined' ? 0 : angle; 73262 var num = 0; 73263 73264 for (var i = pts.length - 1; pts.length > 3 && i >= 0; --i) { 73265 if (collinear(at(pts, i - 1), at(pts, i), at(pts, i + 1), angle)) { 73266 // Remove the middle point 73267 pts.splice(i % pts.length, 1); 73268 num++; 73269 } 73270 } 73271 73272 return num; 73273 } 73274 73275 function splitPaths(cmds) { 73276 var paths = [], 73277 current; 73278 73279 for (var i = 0; i < cmds.length; i++) { 73280 if (cmds[i].type === 'M') { 73281 if (current) { 73282 paths.push(current); 73283 } 73284 73285 current = []; 73286 } 73287 73288 current.push(cmdToArr(cmds[i])); 73289 } 73290 73291 paths.push(current); 73292 return paths; 73293 } 73294 73295 function cmdToArr(cmd) { 73296 var arr = [cmd.type]; 73297 73298 if (cmd.type === 'M' || cmd.type === 'L') { 73299 // moveto or lineto 73300 arr.push(cmd.x, cmd.y); 73301 } else if (cmd.type === 'C') { 73302 arr.push(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y); 73303 } else if (cmd.type === 'Q') { 73304 arr.push(cmd.x1, cmd.y1, cmd.x, cmd.y); 73305 } // else if (cmd.type === 'Z') { /* no-op */ } 73306 73307 73308 return arr; 73309 } 73310 73311 function parseOpts(options, defaults) { 73312 if (typeof options !== 'object') { 73313 options = defaults; 73314 } else { 73315 for (var key in defaults) { 73316 if (typeof options[key] === 'undefined') { 73317 options[key] = defaults[key]; 73318 } 73319 } 73320 } 73321 73322 return options; 73323 } //////////////////////// Helpers //////////////////////////// 73324 73325 73326 function at(v, i) { 73327 var s = v.length; 73328 return v[i < 0 ? i % s + s : i % s]; 73329 } 73330 73331 function collinear(a, b, c, thresholdAngle) { 73332 if (!thresholdAngle) { 73333 return areaTriangle(a, b, c) === 0; 73334 } 73335 73336 if (typeof collinear.tmpPoint1 === 'undefined') { 73337 collinear.tmpPoint1 = []; 73338 collinear.tmpPoint2 = []; 73339 } 73340 73341 var ab = collinear.tmpPoint1, 73342 bc = collinear.tmpPoint2; 73343 ab.x = b.x - a.x; 73344 ab.y = b.y - a.y; 73345 bc.x = c.x - b.x; 73346 bc.y = c.y - b.y; 73347 var dot = ab.x * bc.x + ab.y * bc.y, 73348 magA = Math.sqrt(ab.x * ab.x + ab.y * ab.y), 73349 magB = Math.sqrt(bc.x * bc.x + bc.y * bc.y), 73350 angle = Math.acos(dot / (magA * magB)); 73351 return angle < thresholdAngle; 73352 } 73353 73354 function areaTriangle(a, b, c) { 73355 return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); 73356 } // Portions of below code copyright 2008 Dmitry Baranovskiy (via MIT license) 73357 73358 73359 function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { 73360 var t1 = 1 - t, 73361 t13 = Math.pow(t1, 3), 73362 t12 = Math.pow(t1, 2), 73363 t2 = t * t, 73364 t3 = t2 * t, 73365 x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, 73366 y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, 73367 mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), 73368 my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), 73369 nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), 73370 ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), 73371 ax = t1 * p1x + t * c1x, 73372 ay = t1 * p1y + t * c1y, 73373 cx = t1 * c2x + t * p2x, 73374 cy = t1 * c2y + t * p2y, 73375 alpha = 90 - Math.atan2(mx - nx, my - ny) * 180 / Math.PI; 73376 73377 if (mx > nx || my < ny) { 73378 alpha += 180; 73379 } 73380 73381 return { 73382 x: x, 73383 y: y, 73384 m: { 73385 x: mx, 73386 y: my 73387 }, 73388 n: { 73389 x: nx, 73390 y: ny 73391 }, 73392 start: { 73393 x: ax, 73394 y: ay 73395 }, 73396 end: { 73397 x: cx, 73398 y: cy 73399 }, 73400 alpha: alpha 73401 }; 73402 } 73403 73404 function getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { 73405 return length == null ? bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) : findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, getTatLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length)); 73406 } 73407 73408 function pointAtLength(path, length, istotal) { 73409 path = path2curve(path); 73410 var x, 73411 y, 73412 p, 73413 l, 73414 sp = '', 73415 subpaths = {}, 73416 point, 73417 len = 0; 73418 73419 for (var i = 0, ii = path.length; i < ii; i++) { 73420 p = path[i]; 73421 73422 if (p[0] === 'M') { 73423 x = +p[1]; 73424 y = +p[2]; 73425 } else { 73426 l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); 73427 73428 if (len + l > length) { 73429 if (!istotal) { 73430 point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); 73431 return { 73432 x: point.x, 73433 y: point.y, 73434 alpha: point.alpha 73435 }; 73436 } 73437 } 73438 73439 len += l; 73440 x = +p[5]; 73441 y = +p[6]; 73442 } 73443 73444 sp += p.shift() + p; 73445 } 73446 73447 subpaths.end = sp; 73448 point = istotal ? len : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); 73449 73450 if (point.alpha) { 73451 point = { 73452 x: point.x, 73453 y: point.y, 73454 alpha: point.alpha 73455 }; 73456 } 73457 73458 return point; 73459 } 73460 73461 function pathToAbsolute(pathArray) { 73462 var res = [], 73463 x = 0, 73464 y = 0, 73465 mx = 0, 73466 my = 0, 73467 start = 0; 73468 73469 if (!pathArray) { 73470 // console.warn("Unexpected state: undefined pathArray"); // shouldn't happen 73471 return res; 73472 } 73473 73474 if (pathArray[0][0] === 'M') { 73475 x = +pathArray[0][1]; 73476 y = +pathArray[0][2]; 73477 mx = x; 73478 my = y; 73479 start++; 73480 res[0] = ['M', x, y]; 73481 } 73482 73483 var dots, 73484 crz = pathArray.length === 3 && pathArray[0][0] === 'M' && pathArray[1][0].toUpperCase() === 'R' && pathArray[2][0].toUpperCase() === 'Z'; 73485 73486 for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { 73487 res.push(r = []); 73488 pa = pathArray[i]; 73489 73490 if (pa[0] !== String.prototype.toUpperCase.call(pa[0])) { 73491 r[0] = String.prototype.toUpperCase.call(pa[0]); 73492 73493 switch (r[0]) { 73494 case 'A': 73495 r[1] = pa[1]; 73496 r[2] = pa[2]; 73497 r[3] = pa[3]; 73498 r[4] = pa[4]; 73499 r[5] = pa[5]; 73500 r[6] = +(pa[6] + x); 73501 r[7] = +(pa[7] + y); 73502 break; 73503 73504 case 'V': 73505 r[1] = +pa[1] + y; 73506 break; 73507 73508 case 'H': 73509 r[1] = +pa[1] + x; 73510 break; 73511 73512 case 'R': 73513 dots = [x, y].concat(pa.slice(1)); 73514 73515 for (var j = 2, jj = dots.length; j < jj; j++) {
73516 dots[j] = +dots[j] + x; 73517 dots[++j] = +dots[j] + y; 73518 } 73519 73520 res.pop(); 73521 res = res.concat(catmullRom2bezier(dots, crz)); 73522 break; 73523 73524 case 'M': 73525 mx = +pa[1] + x; 73526 my = +pa[2] + y; 73527 break; 73528 73529 default: 73530 for (j = 1, jj = pa.length; j < jj; j++) { 73531 r[j] = +pa[j] + (j % 2 ? x : y); 73532 } 73533 73534 } 73535 } else if (pa[0] === 'R') { 73536 dots = [x, y].concat(pa.slice(1)); 73537 res.pop(); 73538 res = res.concat(catmullRom2bezier(dots, crz)); 73539 r = ['R'].concat(pa.slice(-2)); 73540 } else { 73541 for (var k = 0, kk = pa.length; k < kk; k++) { 73542 r[k] = pa[k]; 73543 } 73544 } 73545 73546 switch (r[0]) { 73547 case 'Z': 73548 x = mx; 73549 y = my; 73550 break; 73551 73552 case 'H': 73553 x = r[1]; 73554 break; 73555 73556 case 'V': 73557 y = r[1]; 73558 break; 73559 73560 case 'M': 73561 mx = r[r.length - 2]; 73562 my = r[r.length - 1]; 73563 break; 73564 73565 default: 73566 x = r[r.length - 2]; 73567 y = r[r.length - 1]; 73568 } 73569 } 73570 73571 return res; 73572 } 73573 73574 function path2curve(path, path2) { 73575 var p = pathToAbsolute(path), 73576 p2 = path2 && pathToAbsolute(path2); 73577 var attrs = { 73578 x: 0, 73579 y: 0, 73580 bx: 0, 73581 by: 0, 73582 X: 0, 73583 Y: 0, 73584 qx: null, 73585 qy: null 73586 }; 73587 var attrs2 = { 73588 x: 0, 73589 y: 0, 73590 bx: 0, 73591 by: 0, 73592 X: 0, 73593 Y: 0, 73594 qx: null, 73595 qy: null 73596 }; 73597 var pcoms1 = []; // path commands of original path p 73598 73599 var pcoms2 = []; // path commands of original path p2 73600 73601 var ii; 73602 73603 var processPath = function (path, d, pcom) { 73604 var nx, 73605 ny, 73606 tq = { 73607 T: 1, 73608 Q: 1 73609 }; 73610 73611 if (!path) { 73612 return ['C', d.x, d.y, d.x, d.y, d.x, d.y]; 73613 } 73614 73615 if (!(path[0] in tq)) { 73616 d.qx = d.qy = null; 73617 } 73618 73619 switch (path[0]) { 73620 case 'M': 73621 d.X = path[1]; 73622 d.Y = path[2]; 73623 break; 73624 73625 case 'A': 73626 path = ['C'].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1)))); 73627 break; 73628 73629 case 'S': 73630 if (pcom === 'C' || pcom === 'S') { 73631 nx = d.x * 2 - d.bx; 73632 ny = d.y * 2 - d.by; 73633 } else { 73634 nx = d.x; 73635 ny = d.y; 73636 } 73637 73638 path = ['C', nx, ny].concat(path.slice(1)); 73639 break; 73640 73641 case 'T': 73642 if (pcom === 'Q' || pcom === 'T') { 73643 d.qx = d.x * 2 - d.qx; 73644 d.qy = d.y * 2 - d.qy; 73645 } else { 73646 d.qx = d.x; 73647 d.qy = d.y; 73648 } 73649 73650 path = ['C'].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); 73651 break; 73652 73653 case 'Q': 73654 d.qx = path[1]; 73655 d.qy = path[2]; 73656 path = ['C'].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4])); 73657 break; 73658 73659 case 'L': 73660 path = ['C'].concat(l2c(d.x, d.y, path[1], path[2])); 73661 break; 73662 73663 case 'H': 73664 path = ['C'].concat(l2c(d.x, d.y, path[1], d.y)); 73665 break; 73666 73667 case 'V': 73668 path = ['C'].concat(l2c(d.x, d.y, d.x, path[1])); 73669 break; 73670 73671 case 'Z': 73672 path = ['C'].concat(l2c(d.x, d.y, d.X, d.Y)); 73673 break; 73674 } 73675 73676 return path; 73677 }, 73678 fixArc = function (pp, i) { 73679 if (pp[i].length > 7) { 73680 pp[i].shift(); 73681 var pi = pp[i]; 73682 73683 while (pi.length) { 73684 pcoms1[i] = 'A'; 73685 73686 if (p2) { 73687 pcoms2[i] = 'A'; 73688 } 73689 73690 pp.splice(i++, 0, ['C'].concat(pi.splice(0, 6))); 73691 } 73692 73693 pp.splice(i, 1); 73694 ii = Math.max(p.length, p2 && p2.length || 0); 73695 } 73696 }, 73697 fixM = function (path1, path2, a1, a2, i) { 73698 if (path1 && path2 && path1[i][0] === 'M' && path2[i][0] !== 'M') { 73699 path2.splice(i, 0, ['M', a2.x, a2.y]); 73700 a1.bx = 0; 73701 a1.by = 0; 73702 a1.x = path1[i][1]; 73703 a1.y = path1[i][2]; 73704 ii = Math.max(p.length, p2 && p2.length || 0); 73705 } 73706 }; 73707 73708 var pfirst = ''; // temporary holder for original path command 73709 73710 var pcom = ''; // holder for previous path command of original path 73711 73712 ii = Math.max(p.length, p2 && p2.length || 0); 73713 73714 for (var i = 0; i < ii; i++) { 73715 if (p[i]) { 73716 pfirst = p[i][0]; 73717 } // save current path command 73718 73719 73720 if (pfirst !== 'C') { 73721 pcoms1[i] = pfirst; // Save current path command 73722 73723 if (i) { 73724 pcom = pcoms1[i - 1]; 73725 } // Get previous path command pcom 73726 73727 } 73728 73729 p[i] = processPath(p[i], attrs, pcom); 73730 73731 if (pcoms1[i] !== 'A' && pfirst === 'C') { 73732 pcoms1[i] = 'C'; 73733 } 73734 73735 fixArc(p, i);
73735 // fixArc adds also the right amount of A:s to pcoms1 73736 73737 if (p2) { 73738 // the same procedures is done to p2 73739 if (p2[i]) { 73740 pfirst = p2[i][0]; 73741 } 73742 73743 if (pfirst !== 'C') { 73744 pcoms2[i] = pfirst; 73745 73746 if (i) { 73747 pcom = pcoms2[i - 1]; 73748 } 73749 } 73750 73751 p2[i] = processPath(p2[i], attrs2, pcom); 73752 73753 if (pcoms2[i] !== 'A' && pfirst === 'C') { 73754 pcoms2[i] = 'C'; 73755 } 73756 73757 fixArc(p2, i); 73758 } 73759 73760 fixM(p, p2, attrs, attrs2, i); 73761 fixM(p2, p, attrs2, attrs, i); 73762 var seg = p[i], 73763 seg2 = p2 && p2[i], 73764 seglen = seg.length, 73765 seg2len = p2 && seg2.length; 73766 attrs.x = seg[seglen - 2]; 73767 attrs.y = seg[seglen - 1]; 73768 attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x; 73769 attrs.by = parseFloat(seg[seglen - 3]) || attrs.y; 73770 attrs2.bx = p2 && (parseFloat(seg2[seg2len - 4]) || attrs2.x); 73771 attrs2.by = p2 && (parseFloat(seg2[seg2len - 3]) || attrs2.y); 73772 attrs2.x = p2 && seg2[seg2len - 2]; 73773 attrs2.y = p2 && seg2[seg2len - 1]; 73774 } 73775 73776 return p2 ? [p, p2] : p; 73777 } 73778 73779 function a2c(x1, y1, rx, ry, angle, lac, sweep_flag, x2, y2, recursive) { 73780 // for more information of where this Math came from visit: 73781 // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes 73782 var PI = Math.PI, 73783 _120 = PI * 120 / 180, 73784 f1, 73785 f2, 73786 cx, 73787 cy, 73788 rad = PI / 180 * (+angle || 0), 73789 res = [], 73790 xy, 73791 rotate = function (x, y, rad) { 73792 var X = x * Math.cos(rad) - y * Math.sin(rad), 73793 Y = x * Math.sin(rad) + y * Math.cos(rad); 73794 return { 73795 x: X, 73796 y: Y 73797 }; 73798 }; 73799 73800 if (!recursive) { 73801 xy = rotate(x1, y1, -rad); 73802 x1 = xy.x; 73803 y1 = xy.y; 73804 xy = rotate(x2, y2, -rad); 73805 x2 = xy.x; 73806 y2 = xy.y; 73807 var x = (x1 - x2) / 2, 73808 y = (y1 - y2) / 2, 73809 h = x * x / (rx * rx) + y * y / (ry * ry); 73810 73811 if (h > 1) { 73812 h = Math.sqrt(h); 73813 rx = h * rx; 73814 ry = h * ry; 73815 } 73816 73817 var rx2 = rx * rx, 73818 ry2 = ry * ry; 73819 var k = (lac === sweep_flag ? -1 : 1) * Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))); 73820 cx = k * rx * y / ry + (x1 + x2) / 2; 73821 cy = k * -ry * x / rx + (y1 + y2) / 2; 73822 f1 = Math.asin(((y1 - cy) / ry).toFixed(9)); 73823 f2 = Math.asin(((y2 - cy) / ry).toFixed(9)); 73824 f1 = x1 < cx ? PI - f1 : f1; 73825 f2 = x2 < cx ? PI - f2 : f2; 73826 73827 if (f1 < 0) { 73828 f1 = PI * 2 + f1; 73829 } 73830 73831 if (f2 < 0) { 73832 f2 = PI * 2 + f2; 73833 } 73834 73835 if (sweep_flag && f1 > f2) { 73836 f1 = f1 - PI * 2; 73837 } 73838 73839 if (!sweep_flag && f2 > f1) { 73840 f2 = f2 - PI * 2; 73841 } 73842 } else { 73843 f1 = recursive[0]; 73844 f2 = recursive[1]; 73845 cx = recursive[2]; 73846 cy = recursive[3]; 73847 } 73848 73849 var df = f2 - f1; 73850 73851 if (Math.abs(df) > _120) { 73852 var f2old = f2, 73853 x2old = x2, 73854 y2old = y2; 73855 f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); 73856 x2 = cx + rx * Math.cos(f2); 73857 y2 = cy + ry * Math.sin(f2); 73858 res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); 73859 } 73860 73861 df = f2 - f1; 73862 var c1 = Math.cos(f1), 73863 s1 = Math.sin(f1), 73864 c2 = Math.cos(f2), 73865 s2 = Math.sin(f2), 73866 t = Math.tan(df / 4), 73867 hx = 4 / 3 * rx * t, 73868 hy = 4 / 3 * ry * t, 73869 m1 = [x1, y1], 73870 m2 = [x1 + hx * s1, y1 - hy * c1], 73871 m3 = [x2 + hx * s2, y2 - hy * c2], 73872 m4 = [x2, y2]; 73873 m2[0] = 2 * m1[0] - m2[0]; 73874 m2[1] = 2 * m1[1] - m2[1]; 73875 73876 if (recursive) { 73877 return [m2, m3, m4].concat(res); 73878 } else { 73879 res = [m2, m3, m4].concat(res).join().split(','); 73880 var newres = []; 73881 73882 for (var i = 0, ii = res.length; i < ii; i++) { 73883 newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; 73884 } 73885 73886 return newres; 73887 } 73888 } // http://schepers.cc/getting-to-the-point 73889 73890 73891 function catmullRom2bezier(crp, z) { 73892 var d = []; 73893 73894 for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { 73895 var p = [{ 73896 x: +crp[i - 2], 73897 y: +crp[i - 1] 73898 }, { 73899 x: +crp[i], 73900 y: +crp[i + 1] 73901 }, { 73902 x: +crp[i + 2], 73903 y: +crp[i + 3] 73904 }, { 73905 x: +crp[i + 4], 73906 y: +crp[i + 5] 73907 }]; 73908 73909 if (z) { 73910 if (!i) { 73911 p[0] = { 73912 x: +crp[iLen - 2], 73913 y: +crp[iLen - 1] 73914 }; 73915 } else if (iLen - 4 === i) { 73916 p[3] = { 73917 x: +crp[0], 73918 y: +crp[1] 73919 }; 73920 } else if (iLen - 2 === i) { 73921 p[2] = { 73922 x: +crp[0], 73923 y: +crp[1] 73924 }; 73925 p[3] = { 73926 x: +crp[2], 73927 y: +crp[3] 73928 }; 73929 } 73930 } else { 73931 if (iLen - 4 === i) { 73932 p[3] = p[2]; 73933 } else if (!i) { 73934 p[0] = { 73935 x: +crp[i], 73936 y: +crp[i + 1] 73937 }; 73938 } 73939 } 73940 73941 d.push(['C', (-p[0].x + 6 * p[1].x + p[2].x) / 6, (-p[0].y + 6 * p[1].y + p[2].y) / 6, (p[1].x + 6 * p[2].x - p[3].x) / 6, (p[1].y + 6 * p[2].y - p[3].y) / 6, p[2].x, p[2].y]); 73942 } 73943 73944 return d; 73945 } 73946 73947 function l2c(x1, y1, x2, y2) { 73948 return [x1, y1, x2, y2, x2, y2]; 73949 } 73950 73951 function q2c(x1, y1, ax, ay, x2, y2) { 73952 var _13 = 1 / 3, 73953 _23 = 2 / 3; 73954 73955 return [_13 * x1 + _23 * ax, _13 * y1 + _23 * ay, _13 * x2 + _23 * ax, _13 * y2 + _23 * ay, x2, y2]; 73956 } 73957 73958 function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) { 73959 if (z == null) { 73960 z = 1; 73961 } 73962 73963 z = z > 1 ? 1 : z < 0 ? 0 : z; 73964 var z2 = z / 2; 73965 var n = 12; 73966 var Tvalues = [-0.1252, 0.1252, -0.3678, 0.3678, -0.5873, 0.5873, -0.7699, 0.7699, -0.9041, 0.9041, -0.9816, 0.9816]; 73967 var sum = 0; 73968 var Cvalues = [0.2491, 0.2491, 0.2335, 0.2335, 0.2032, 0.2032, 0.1601, 0.1601, 0.1069, 0.1069, 0.0472, 0.0472]; 73969 73970 for (var i = 0; i < n; i++) { 73971 var ct = z2 * Tvalues[i] + z2, 73972 xbase = base3(ct, x1, x2, x3, x4), 73973 ybase = base3(ct, y1, y2, y3, y4), 73974 comb = xbase * xbase + ybase * ybase; 73975 sum += Cvalues[i] * Math.sqrt(comb); 73976 } 73977 73978 return z2 * sum; 73979 } 73980 73981 function getTatLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) { 73982 if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) { 73983 return; 73984 } 73985 73986 var t = 1, 73987 step = t / 2, 73988 t2 = t - step, 73989 l, 73990 e = 0.01; 73991 l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); 73992 73993 while (Math.abs(l - ll) > e) { 73994 step /= 2; 73995 t2 += (l < ll ? 1 : -1) * step; 73996 l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); 73997 } 73998 73999 return t2; 74000 } 74001 74002 function base3(t, p1, p2, p3, p4) { 74003 var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4, 74004 t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3; 74005 return t * t2 - 3 * p1 + 3 * p2; 74006 } 74007 74008 function cacheKey() { 74009 var hash = ''; 74010 74011 for (var i = arguments.length - 1; i >= 0; --i) { 74012 hash += 'ï¼' + arguments[i]; 74013 } 74014 74015 return hash; 74016 } 74017 74018 module.exports = p5; 74019 }, {
74020 "../core/constants": 18, 74021 "../core/main": 24 74022 }], 74023 60: [function (_dereq_, module, exports) { 74024 /** 74025 * @module Data 74026 * @submodule Array Functions 74027 * @for p5 74028 * @requires core 74029 */ 74030 'use strict'; 74031 74032 var p5 = _dereq_('../core/main'); 74033 /** 74034 * Adds a value to the end of an array. Extends the length of 74035 * the array by one. Maps to Array.push(). 74036 * 74037 * @method append 74038 * @deprecated Use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push">array.push(value)</a> instead. 74039 * @param {Array} array Array to append 74040 * @param {any} value to be added to the Array 74041 * @return {Array} the array that was appended to 74042 * @example 74043 * <div class='norender'><code> 74044 * function setup() { 74045 * var myArray = ['Mango', 'Apple', 'Papaya']; 74046 * print(myArray); // ['Mango', 'Apple', 'Papaya'] 74047 * 74048 * append(myArray, 'Peach'); 74049 * print(myArray); // ['Mango', 'Apple', 'Papaya', 'Peach'] 74050 * } 74051 * </code></div> 74052 */ 74053 74054 74055 p5.prototype.append = function (array, value) { 74056 array.push(value); 74057 return array; 74058 }; 74059 /** 74060 * Copies an array (or part of an array) to another array. The src array is 74061 * copied to the dst array, beginning at the position specified by 74062 * srcPosition and into the position specified by dstPosition. The number of 74063 * elements to copy is determined by length. Note that copying values 74064 * overwrites existing values in the destination array. To append values 74065 * instead of overwriting them, use <a href="#/p5/concat">concat()</a>. 74066 * <br><br> 74067 * The simplified version with only two arguments, arrayCopy(src, dst), 74068 * copies an entire array to another of the same size. It is equivalent to 74069 * arrayCopy(src, 0, dst, 0, src.length). 74070 * <br><br> 74071 * Using this function is far more efficient for copying array data than 74072 * iterating through a for() loop and copying each element individually. 74073 * 74074 * @method arrayCopy 74075 * @deprecated 74076 * @param {Array} src the source Array 74077 * @param {Integer} srcPosition starting position in the source Array 74078 * @param {Array} dst the destination Array 74079 * @param {Integer} dstPosition starting position in the destination Array 74080 * @param {Integer} length number of Array elements to be copied 74081 * 74082 * @example 74083 * <div class='norender'><code> 74084 * var src = ['A', 'B', 'C']; 74085 * var dst = [1, 2, 3]; 74086 * var srcPosition = 1; 74087 * var dstPosition = 0; 74088 * var length = 2; 74089 * 74090 * print(src); // ['A', 'B', 'C'] 74091 * print(dst); // [ 1 , 2 , 3 ] 74092 * 74093 * arrayCopy(src, srcPosition, dst, dstPosition, length); 74094 * print(dst); // ['B', 'C', 3] 74095 * </code></div> 74096 */ 74097 74098 /** 74099 * @method arrayCopy 74100 * @deprecated Use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin">arr1.copyWithin(arr2)</a> instead. 74101 * @param {Array} src 74102 * @param {Array} dst 74103 * @param {Integer} [length] 74104 */ 74105 74106 74107 p5.prototype.arrayCopy = function (src, srcPosition, dst, dstPosition, length) { 74108 // the index to begin splicing from dst array 74109 var start; 74110 var end; 74111 74112 if (typeof length !== 'undefined') { 74113 end = Math.min(length, src.length); 74114 start = dstPosition; 74115 src = src.slice(srcPosition, end + srcPosition); 74116 } else { 74117 if (typeof dst !== 'undefined') { 74118 // src, dst, length 74119 // rename so we don't get confused 74120 end = dst; 74121 end = Math.min(end, src.length); 74122 } else { 74123 // src, dst 74124 end = src.length; 74125 } 74126 74127 start = 0; // rename so we don't get confused 74128 74129 dst = srcPosition; 74130 src = src.slice(0, end); 74131 } // Since we are not returning the array and JavaScript is pass by reference 74132 // we must modify the actual values of the array 74133 // instead of reassigning arrays 74134 74135 74136 Array.prototype.splice.apply(dst, [start, end].concat(src)); 74137 }; 74138 /** 74139 * Concatenates two arrays, maps to Array.concat(). Does not modify the 74140 * input arrays. 74141 * 74142 * @method concat 74143 * @deprecated Use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat">arr1.concat(arr2)</a> instead. 74144 * @param {Array} a first Array to concatenate 74145 * @param {Array} b second Array to concatenate 74146 * @return {Array} concatenated array 74147 * 74148 * @example 74149 * <div class = 'norender'><code> 74150 * function setup() { 74151 * var arr1 = ['A', 'B', 'C']; 74152 * var arr2 = [1, 2, 3]; 74153 * 74154 * print(arr1); // ['A','B','C'] 74155 * print(arr2); // [1,2,3] 74156 * 74157 * var arr3 = concat(arr1, arr2); 74158 * 74159 * print(arr1); // ['A','B','C'] 74160 * print(arr2); // [1, 2, 3] 74161 * print(arr3); // ['A','B','C', 1, 2, 3] 74162 * } 74163 * </code></div> 74164 */ 74165 74166 74167 p5.prototype.concat = function (list0, list1) { 74168 return list0.concat(list1); 74169 }; 74170 /** 74171 * Reverses the order of an array, maps to Array.reverse() 74172 * 74173 * @method reverse 74174 * @deprecated Use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse">array.reverse()</a> instead. 74175 * @param {Array} list Array to reverse 74176 * @return {Array} the reversed list 74177 * @example 74178 * <div class='norender'><code> 74179 * function setup() { 74180 * var myArray = ['A', 'B', 'C']; 74181 * print(myArray); // ['A','B','C'] 74182 * 74183 * reverse(myArray); 74184 * print(myArray); // ['C','B','A'] 74185 * } 74186 * </code></div> 74187 */ 74188 74189 74190 p5.prototype.reverse = function (list) { 74191 return list.reverse(); 74192 }; 74193 /** 74194 * Decreases an array by one element and returns the shortened array, 74195 * maps to Array.pop(). 74196 * 74197 * @method shorten 74198 * @deprecated Use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop">array.pop()</a> instead. 74199 * @param {Array} list Array to shorten 74200 * @return {Array} shortened Array 74201 * @example 74202 * <div class = 'norender'><code> 74203 * function setup() { 74204 * var myArray = ['A', 'B', 'C']; 74205 * print(myArray); // ['A', 'B', 'C'] 74206 * var newArray = shorten(myArray); 74207 * print(myArray); // ['A','B','C'] 74208 * print(newArray); // ['A','B'] 74209 * } 74210 * </code></div> 74211 */ 74212 74213 74214 p5.prototype.shorten = function (list) { 74215 list.pop(); 74216 return list; 74217 }; 74218 /** 74219 * Randomizes the order of the elements of an array. Implements 74220 * <a href='http://Bost.Ocks.org/mike/shuffle/' target=_blank>
74221 * Fisher-Yates Shuffle Algorithm</a>. 74222 * 74223 * @method shuffle 74224 * @param {Array} array Array to shuffle 74225 * @param {Boolean} [bool] modify passed array 74226 * @return {Array} shuffled Array 74227 * @example 74228 * <div><code> 74229 * function setup() { 74230 * var regularArr = ['ABC', 'def', createVector(), TAU, Math.E]; 74231 * print(regularArr); 74232 * shuffle(regularArr, true); // force modifications to passed array 74233 * print(regularArr); 74234 * 74235 * // By default shuffle() returns a shuffled cloned array: 74236 * var newArr = shuffle(regularArr); 74237 * print(regularArr); 74238 * print(newArr); 74239 * } 74240 * </code></div> 74241 */ 74242 74243 74244 p5.prototype.shuffle = function (arr, bool) { 74245 var isView = ArrayBuffer && ArrayBuffer.isView && ArrayBuffer.isView(arr); 74246 arr = bool || isView ? arr : arr.slice(); 74247 var rnd, 74248 tmp, 74249 idx = arr.length; 74250 74251 while (idx > 1) { 74252 rnd = Math.random() * idx | 0; 74253 tmp = arr[--idx]; 74254 arr[idx] = arr[rnd]; 74255 arr[rnd] = tmp; 74256 } 74257 74258 return arr; 74259 }; 74260 /** 74261 * Sorts an array of numbers from smallest to largest, or puts an array of 74262 * words in alphabetical order. The original array is not modified; a 74263 * re-ordered array is returned. The count parameter states the number of 74264 * elements to sort. For example, if there are 12 elements in an array and 74265 * count is set to 5, only the first 5 elements in the array will be sorted. 74266 * 74267 * @method sort 74268 * @deprecated Use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort">array.sort()</a> instead. 74269 * @param {Array} list Array to sort 74270 * @param {Integer} [count] number of elements to sort, starting from 0 74271 * @return {Array} the sorted list 74272 * 74273 * @example 74274 * <div class = 'norender'><code> 74275 * function setup() { 74276 * var words = ['banana', 'apple', 'pear', 'lime']; 74277 * print(words); // ['banana', 'apple', 'pear', 'lime'] 74278 * var count = 4; // length of array 74279 * 74280 * words = sort(words, count); 74281 * print(words); // ['apple', 'banana', 'lime', 'pear'] 74282 * } 74283 * </code></div> 74284 * <div class = 'norender'><code> 74285 * function setup() { 74286 * var numbers = [2, 6, 1, 5, 14, 9, 8, 12]; 74287 * print(numbers); // [2, 6, 1, 5, 14, 9, 8, 12] 74288 * var count = 5; // Less than the length of the array 74289 * 74290 * numbers = sort(numbers, count); 74291 * print(numbers); // [1,2,5,6,14,9,8,12] 74292 * } 74293 * </code></div> 74294 */ 74295 74296 74297 p5.prototype.sort = function (list, count) { 74298 var arr = count ? list.slice(0, Math.min(count, list.length)) : list; 74299 var rest = count ? list.slice(Math.min(count, list.length)) : []; 74300 74301 if (typeof arr[0] === 'string') { 74302 arr = arr.sort(); 74303 } else { 74304 arr = arr.sort(function (a, b) { 74305 return a - b; 74306 }); 74307 } 74308 74309 return arr.concat(rest); 74310 }; 74311 /** 74312 * Inserts a value or an array of values into an existing array. The first 74313 * parameter specifies the initial array to be modified, and the second 74314 * parameter defines the data to be inserted. The third parameter is an index 74315 * value which specifies the array position from which to insert data. 74316 * (Remember that array index numbering starts at zero, so the first position 74317 * is 0, the second position is 1, and so on.) 74318 * 74319 * @method splice 74320 * @deprecated Use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice">array.splice()</a> instead. 74321 * @param {Array} list Array to splice into 74322 * @param {any} value value to be spliced in 74323 * @param {Integer} position in the array from which to insert data 74324 * @return {Array} the list 74325 * 74326 * @example 74327 * <div class = 'norender'><code> 74328 * function setup() { 74329 * var myArray = [0, 1, 2, 3, 4]; 74330 * var insArray = ['A', 'B', 'C']; 74331 * print(myArray); // [0, 1, 2, 3, 4] 74332 * print(insArray); // ['A','B','C'] 74333 * 74334 * splice(myArray, insArray, 3); 74335 * print(myArray); // [0,1,2,'A','B','C',3,4] 74336 * } 74337 * </code></div> 74338 */ 74339 74340 74341 p5.prototype.splice = function (list, value, index) { 74342 // note that splice returns spliced elements and not an array 74343 Array.prototype.splice.apply(list, [index, 0].concat(value)); 74344 return list; 74345 }; 74346 /** 74347 * Extracts an array of elements from an existing array. The list parameter 74348 * defines the array from which the elements will be copied, and the start 74349 * and count parameters specify which elements to extract. If no count is 74350 * given, elements will be extracted from the start to the end of the array. 74351 * When specifying the start, remember that the first array element is 0. 74352 * This function does not change the source array. 74353 * 74354 * @method subset 74355 * @deprecated Use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice">array.slice()</a> instead. 74356 * @param {Array} list Array to extract from 74357 * @param {Integer} start position to begin 74358 * @param {Integer} [count] number of values to extract 74359 * @return {Array} Array of extracted elements 74360 * 74361 * @example 74362 * <div class = 'norender'><code> 74363 * function setup() { 74364 * var myArray = [1, 2, 3, 4, 5]; 74365 * print(myArray); // [1, 2, 3, 4, 5] 74366 * 74367 * var sub1 = subset(myArray, 0, 3); 74368 * var sub2 = subset(myArray, 2, 2); 74369 * print(sub1); // [1,2,3] 74370 * print(sub2); // [3,4] 74371 * } 74372 * </code></div> 74373 */ 74374 74375 74376 p5.prototype.subset = function (list, start, count) { 74377 if (typeof count !== 'undefined') { 74378 return list.slice(start, start + count); 74379 } else { 74380 return list.slice(start, list.length); 74381 } 74382 }; 74383 74384 module.exports = p5; 74385 }, {
74386 "../core/main": 24 74387 }], 74388 61: [function (_dereq_, module, exports) { 74389 /** 74390 * @module Data 74391 * @submodule Conversion 74392 * @for p5 74393 * @requires core 74394 */ 74395 'use strict'; 74396 74397 var p5 = _dereq_('../core/main'); 74398 /** 74399 * Converts a string to its floating point representation. The contents of a 74400 * string must resemble a number, or NaN (not a number) will be returned. 74401 * For example, float("1234.56") evaluates to 1234.56, but float("giraffe") 74402 * will return NaN. 74403 * 74404 * When an array of values is passed in, then an array of floats of the same 74405 * length is returned. 74406 * 74407 * @method float 74408 * @param {String} str float string to parse 74409 * @return {Number} floating point representation of string 74410 * @example 74411 * <div><code> 74412 * var str = '20'; 74413 * var diameter = float(str); 74414 * ellipse(width / 2, height / 2, diameter, diameter); 74415 * </code></div> 74416 * 74417 * @alt 74418 * 20 by 20 white ellipse in the center of the canvas 74419 * 74420 */ 74421 74422 74423 p5.prototype.float = function (str) { 74424 if (str instanceof Array) { 74425 return str.map(parseFloat); 74426 } 74427 74428 return parseFloat(str); 74429 }; 74430 /** 74431 * Converts a boolean, string, or float to its integer representation. 74432 * When an array of values is passed in, then an int array of the same length 74433 * is returned. 74434 * 74435 * @method int 74436 * @param {String|Boolean|Number} n value to parse 74437 * @param {Integer} [radix] the radix to convert to (default: 10) 74438 * @return {Number} integer representation of value 74439 * 74440 * @example 74441 * <div class='norender'><code> 74442 * print(int('10')); // 10 74443 * print(int(10.31)); // 10 74444 * print(int(-10)); // -10 74445 * print(int(true)); // 1 74446 * print(int(false)); // 0 74447 * print(int([false, true, '10.3', 9.8])); // [0, 1, 10, 9] 74448 * </code></div> 74449 */ 74450 74451 /** 74452 * @method int 74453 * @param {Array} ns values to parse 74454 * @return {Number[]} integer representation of values 74455 */ 74456 74457 74458 p5.prototype.int = function (n, radix) { 74459 radix = radix || 10; 74460 74461 if (typeof n === 'string') { 74462 return parseInt(n, radix); 74463 } else if (typeof n === 'number') { 74464 return n | 0; 74465 } else if (typeof n === 'boolean') { 74466 return n ? 1 : 0; 74467 } else if (n instanceof Array) { 74468 return n.map(function (n) { 74469 return p5.prototype.int(n, radix); 74470 }); 74471 } 74472 }; 74473 /** 74474 * Converts a boolean, string or number to its string representation. 74475 * When an array of values is passed in, then an array of strings of the same 74476 * length is returned. 74477 * 74478 * @method str 74479 * @param {String|Boolean|Number|Array} n value to parse 74480 * @return {String} string representation of value 74481 * @example 74482 * <div class='norender'><code> 74483 * print(str('10')); // "10" 74484 * print(str(10.31)); // "10.31" 74485 * print(str(-10)); // "-10" 74486 * print(str(true)); // "true" 74487 * print(str(false)); // "false" 74488 * print(str([true, '10.3', 9.8])); // [ "true", "10.3", "9.8" ] 74489 * </code></div> 74490 */ 74491 74492 74493 p5.prototype.str = function (n) { 74494 if (n instanceof Array) { 74495 return n.map(p5.prototype.str); 74496 } else { 74497 return String(n); 74498 } 74499 }; 74500 /** 74501 * Converts a number or string to its boolean representation. 74502 * For a number, any non-zero value (positive or negative) evaluates to true, 74503 * while zero evaluates to false. For a string, the value "true" evaluates to 74504 * true, while any other value evaluates to false. When an array of number or 74505 * string values is passed in, then a array of booleans of the same length is 74506 * returned. 74507 * 74508 * @method boolean 74509 * @param {String|Boolean|Number|Array} n value to parse 74510 * @return {Boolean} boolean representation of value 74511 * @example 74512 * <div class='norender'><code> 74513 * print(boolean(0)); // false 74514 * print(boolean(1)); // true 74515 * print(boolean('true')); // true 74516 * print(boolean('abcd')); // false 74517 * print(boolean([0, 12, 'true'])); // [false, true, false] 74518 * </code></div> 74519 */ 74520 74521 74522 p5.prototype.boolean = function (n) { 74523 if (typeof n === 'number') { 74524 return n !== 0; 74525 } else if (typeof n === 'string') { 74526 return n.toLowerCase() === 'true'; 74527 } else if (typeof n === 'boolean') { 74528 return n; 74529 } else if (n instanceof Array) { 74530 return n.map(p5.prototype.boolean); 74531 } 74532 }; 74533 /** 74534 * Converts a number, string representation of a number, or boolean to its byte
74535 * representation. A byte can be only a whole number between -128 and 127, so 74536 * when a value outside of this range is converted, it wraps around to the 74537 * corresponding byte representation. When an array of number, string or boolean 74538 * values is passed in, then an array of bytes the same length is returned. 74539 * 74540 * @method byte 74541 * @param {String|Boolean|Number} n value to parse 74542 * @return {Number} byte representation of value 74543 * 74544 * @example 74545 * <div class='norender'><code> 74546 * print(byte(127)); // 127 74547 * print(byte(128)); // -128 74548 * print(byte(23.4)); // 23 74549 * print(byte('23.4')); // 23 74550 * print(byte('hello')); // NaN 74551 * print(byte(true)); // 1 74552 * print(byte([0, 255, '100'])); // [0, -1, 100] 74553 * </code></div> 74554 */ 74555 74556 /** 74557 * @method byte 74558 * @param {Array} ns values to parse 74559 * @return {Number[]} array of byte representation of values 74560 */ 74561 74562 74563 p5.prototype.byte = function (n) { 74564 var nn = p5.prototype.int(n, 10); 74565 74566 if (typeof nn === 'number') { 74567 return (nn + 128) % 256 - 128; 74568 } else if (nn instanceof Array) { 74569 return nn.map(p5.prototype.byte); 74570 } 74571 }; 74572 /** 74573 * Converts a number or string to its corresponding single-character 74574 * string representation. If a string parameter is provided, it is first 74575 * parsed as an integer and then translated into a single-character string. 74576 * When an array of number or string values is passed in, then an array of 74577 * single-character strings of the same length is returned. 74578 * 74579 * @method char 74580 * @param {String|Number} n value to parse 74581 * @return {String} string representation of value 74582 * 74583 * @example 74584 * <div class='norender'><code> 74585 * print(char(65)); // "A" 74586 * print(char('65')); // "A" 74587 * print(char([65, 66, 67])); // [ "A", "B", "C" ] 74588 * print(join(char([65, 66, 67]), '')); // "ABC" 74589 * </code></div> 74590 */ 74591 74592 /** 74593 * @method char 74594 * @param {Array} ns values to parse 74595 * @return {String[]} array of string representation of values 74596 */ 74597 74598 74599 p5.prototype.char = function (n) { 74600 if (typeof n === 'number' && !isNaN(n)) { 74601 return String.fromCharCode(n); 74602 } else if (n instanceof Array) { 74603 return n.map(p5.prototype.char); 74604 } else if (typeof n === 'string') { 74605 return p5.prototype.char(parseInt(n, 10)); 74606 } 74607 }; 74608 /** 74609 * Converts a single-character string to its corresponding integer 74610 * representation. When an array of single-character string values is passed 74611 * in, then an array of integers of the same length is returned. 74612 * 74613 * @method unchar 74614 * @param {String} n value to parse 74615 * @return {Number} integer representation of value 74616 * 74617 * @example 74618 * <div class='norender'><code> 74619 * print(unchar('A')); // 65 74620 * print(unchar(['A', 'B', 'C'])); // [ 65, 66, 67 ] 74621 * print(unchar(split('ABC', ''))); // [ 65, 66, 67 ] 74622 * </code></div> 74623 */ 74624 74625 /** 74626 * @method unchar 74627 * @param {Array} ns values to parse 74628 * @return {Number[]} integer representation of values 74629 */ 74630 74631 74632 p5.prototype.unchar = function (n) { 74633 if (typeof n === 'string' && n.length === 1) { 74634 return n.charCodeAt(0); 74635 } else if (n instanceof Array) { 74636 return n.map(p5.prototype.unchar); 74637 } 74638 }; 74639 /** 74640 * Converts a number to a string in its equivalent hexadecimal notation. If a 74641 * second parameter is passed, it is used to set the number of characters to 74642 * generate in the hexadecimal notation. When an array is passed in, an 74643 * array of strings in hexadecimal notation of the same length is returned. 74644 * 74645 * @method hex 74646 * @param {Number} n value to parse 74647 * @param {Number} [digits] 74648 * @return {String} hexadecimal string representation of value 74649 * 74650 * @example 74651 * <div class='norender'><code> 74652 * print(hex(255)); // "000000FF" 74653 * print(hex(255, 6)); // "0000FF" 74654 * print(hex([0, 127, 255], 6)); // [ "000000", "00007F", "0000FF" ] 74655 * </code></div> 74656 */ 74657 74658 /** 74659 * @method hex 74660 * @param {Number[]} ns array of values to parse 74661 * @param {Number} [digits] 74662 * @return {String[]} hexadecimal string representation of values 74663 */ 74664 74665 74666 p5.prototype.hex = function (n, digits) { 74667 digits = digits === undefined || digits === null ? digits = 8 : digits; 74668 74669 if (n instanceof Array) { 74670 return n.map(function (n) { 74671 return p5.prototype.hex(n, digits); 74672 }); 74673 } else if (typeof n === 'number') { 74674 if (n < 0) { 74675 n = 0xffffffff + n + 1; 74676 } 74677 74678 var hex = Number(n).toString(16).toUpperCase(); 74679 74680 while (hex.length < digits) { 74681 hex = '0' + hex; 74682 } 74683 74684 if (hex.length >= digits) { 74685 hex = hex.substring(hex.length - digits, hex.length); 74686 } 74687 74688 return hex; 74689 } 74690 }; 74691 /** 74692 * Converts a string representation of a hexadecimal number to its equivalent
74693 * integer value. When an array of strings in hexadecimal notation is passed 74694 * in, an array of integers of the same length is returned. 74695 * 74696 * @method unhex 74697 * @param {String} n value to parse 74698 * @return {Number} integer representation of hexadecimal value 74699 * 74700 * @example 74701 * <div class='norender'><code> 74702 * print(unhex('A')); // 10 74703 * print(unhex('FF')); // 255 74704 * print(unhex(['FF', 'AA', '00'])); // [ 255, 170, 0 ] 74705 * </code></div> 74706 */ 74707 74708 /** 74709 * @method unhex 74710 * @param {Array} ns values to parse 74711 * @return {Number[]} integer representations of hexadecimal value 74712 */ 74713 74714 74715 p5.prototype.unhex = function (n) { 74716 if (n instanceof Array) { 74717 return n.map(p5.prototype.unhex); 74718 } else { 74719 return parseInt('0x' + n, 16); 74720 } 74721 }; 74722 74723 module.exports = p5; 74724 }, { 74725 "../core/main": 24 74726 }], 74727 62: [function (_dereq_, module, exports) { 74728 /** 74729 * @module Data 74730 * @submodule String Functions 74731 * @for p5 74732 * @requires core 74733 */ 74734 'use strict'; 74735 74736 var p5 = _dereq_('../core/main'); 74737 74738 _dereq_('../core/error_helpers'); //return p5; //LM is this a mistake? 74739 74740 /** 74741 * Combines an array of Strings into one String, each separated by the 74742 * character(s) used for the separator parameter. To join arrays of ints or 74743 * floats, it's necessary to first convert them to Strings using <a href="#/p5/nf">nf()</a> or 74744 * nfs(). 74745 * 74746 * @method join 74747 * @param {Array} list array of Strings to be joined 74748 * @param {String} separator String to be placed between each item 74749 * @return {String} joined String 74750 * @example 74751 * <div> 74752 * <code> 74753 * var array = ['Hello', 'world!']; 74754 * var separator = ' '; 74755 * var message = join(array, separator); 74756 * text(message, 5, 50); 74757 * </code> 74758 * </div> 74759 * 74760 * @alt 74761 * "hello world!" displayed middle left of canvas. 74762 * 74763 */ 74764 74765 74766 p5.prototype.join = function (list, separator) { 74767 p5._validateParameters('join', arguments); 74768 74769 return list.join(separator); 74770 }; 74771 /** 74772 * This function is used to apply a regular expression to a piece of text, 74773 * and return matching groups (elements found inside parentheses) as a 74774 * String array. If there are no matches, a null value will be returned. 74775 * If no groups are specified in the regular expression, but the sequence 74776 * matches, an array of length 1 (with the matched text as the first element 74777 * of the array) will be returned. 74778 * <br><br> 74779 * To use the function, first check to see if the result is null. If the 74780 * result is null, then the sequence did not match at all. If the sequence 74781 * did match, an array is returned. 74782 * <br><br> 74783 * If there are groups (specified by sets of parentheses) in the regular 74784 * expression, then the contents of each will be returned in the array. 74785 * Element [0] of a regular expression match returns the entire matching 74786 * string, and the match groups start at element [1] (the first group is [1], 74787 * the second [2], and so on). 74788 * 74789 * @method match 74790 * @param {String} str the String to be searched 74791 * @param {String} regexp the regexp to be used for matching 74792 * @return {String[]} Array of Strings found 74793 * @example 74794 * <div> 74795 * <code> 74796 * var string = 'Hello p5js*!'; 74797 * var regexp = 'p5js\\*'; 74798 * var m = match(string, regexp); 74799 * text(m, 5, 50); 74800 * </code> 74801 * </div> 74802 * 74803 * @alt 74804 * "p5js*" displayed middle left of canvas. 74805 * 74806 */ 74807 74808 74809 p5.prototype.match = function (str, reg) { 74810 p5._validateParameters('match', arguments); 74811 74812 return str.match(reg); 74813 }; 74814 /** 74815 * This function is used to apply a regular expression to a piece of text, 74816 * and return a list of matching groups (elements found inside parentheses)
74817 * as a two-dimensional String array. If there are no matches, a null value 74818 * will be returned. If no groups are specified in the regular expression, 74819 * but the sequence matches, a two dimensional array is still returned, but 74820 * the second dimension is only of length one. 74821 * <br><br> 74822 * To use the function, first check to see if the result is null. If the 74823 * result is null, then the sequence did not match at all. If the sequence 74824 * did match, a 2D array is returned. 74825 * <br><br> 74826 * If there are groups (specified by sets of parentheses) in the regular 74827 * expression, then the contents of each will be returned in the array. 74828 * Assuming a loop with counter variable i, element [i][0] of a regular 74829 * expression match returns the entire matching string, and the match groups 74830 * start at element [i][1] (the first group is [i][1], the second [i][2], 74831 * and so on). 74832 * 74833 * @method matchAll 74834 * @param {String} str the String to be searched 74835 * @param {String} regexp the regexp to be used for matching 74836 * @return {String[]} 2d Array of Strings found 74837 * @example 74838 * <div class="norender"> 74839 * <code> 74840 * var string = 'Hello p5js*! Hello world!'; 74841 * var regexp = 'Hello'; 74842 * matchAll(string, regexp); 74843 * </code> 74844 * </div> 74845 */ 74846 74847 74848 p5.prototype.matchAll = function (str, reg) { 74849 p5._validateParameters('matchAll', arguments); 74850 74851 var re = new RegExp(reg, 'g'); 74852 var match = re.exec(str); 74853 var matches = []; 74854 74855 while (match !== null) { 74856 matches.push(match); // matched text: match[0] 74857 // match start: match.index 74858 // capturing group n: match[n] 74859 74860 match = re.exec(str); 74861 } 74862 74863 return matches; 74864 }; 74865 /** 74866 * Utility function for formatting numbers into strings. There are two 74867 * versions: one for formatting floats, and one for formatting ints. 74868 * The values for the digits, left, and right parameters should always 74869 * be positive integers. 74870 * (NOTE): Be cautious when using left and right parameters as it prepends numbers of 0's if the parameter 74871 * if greater than the current length of the number. 74872 * For example if number is 123.2 and left parameter passed is 4 which is greater than length of 123 74873 * (integer part) i.e 3 than result will be 0123.2. Same case for right parameter i.e. if right is 3 than 74874 * the result will be 123.200. 74875 * 74876 * @method nf 74877 * @param {Number|String} num the Number to format 74878 * @param {Integer|String} [left] number of digits to the left of the 74879 * decimal point 74880 * @param {Integer|String} [right] number of digits to the right of the 74881 * decimal point 74882 * @return {String} formatted String 74883 * 74884 * @example 74885 * <div> 74886 * <code> 74887 * var myFont; 74888 * function preload() { 74889 * myFont = loadFont('assets/fonts/inconsolata.ttf'); 74890 * } 74891 * function setup() { 74892 * background(200); 74893 * var num1 = 321; 74894 * var num2 = -1321; 74895 * 74896 * noStroke(); 74897 * fill(0); 74898 * textFont(myFont); 74899 * textSize(22); 74900 * 74901 * text(nf(num1, 4, 2), 10, 30); 74902 * text(nf(num2, 4, 2), 10, 80); 74903 * // Draw dividing line 74904 * stroke(120); 74905 * line(0, 50, width, 50); 74906 * } 74907 * </code> 74908 * </div> 74909 * 74910 * @alt 74911 * "0321.00" middle top, -1321.00" middle bottom canvas 74912 */ 74913 74914 /** 74915 * @method nf 74916 * @param {Array} nums the Numbers to format 74917 * @param {Integer|String} [left] 74918 * @param {Integer|String} [right] 74919 * @return {String[]} formatted Strings 74920 */ 74921 74922 74923 p5.prototype.nf = function (nums, left, right) { 74924 p5._validateParameters('nf', arguments); 74925 74926 if (nums instanceof Array) { 74927 return nums.map(function (x) { 74928 return doNf(x, left, right); 74929 }); 74930 } else { 74931 var typeOfFirst = Object.prototype.toString.call(nums); 74932 74933 if (typeOfFirst === '[object Arguments]') { 74934 if (nums.length === 3) { 74935 return this.nf(nums[0], nums[1], nums[2]); 74936 } else if (nums.length === 2) { 74937 return this.nf(nums[0], nums[1]); 74938 } else { 74939 return this.nf(nums[0]); 74940 } 74941 } else { 74942 return doNf(nums, left, right); 74943 } 74944 } 74945 }; 74946 74947 function doNf(num, left, right) { 74948 var neg = num < 0; 74949 var n = neg ? num.toString().substring(1) : num.toString(); 74950 var decimalInd = n.indexOf('.'); 74951 var intPart = decimalInd !== -1 ? n.substring(0, decimalInd) : n; 74952 var decPart = decimalInd !== -1 ? n.substring(decimalInd + 1) : ''; 74953 var str = neg ? '-' : ''; 74954 74955 if (typeof right !== 'undefined') { 74956 var decimal = ''; 74957 74958 if (decimalInd !== -1 || right - decPart.length > 0) { 74959 decimal = '.'; 74960 } 74961 74962 if (decPart.length > right) { 74963 decPart = decPart.substring(0, right); 74964 } 74965 74966 for (var i = 0; i < left - intPart.length; i++) { 74967 str += '0'; 74968 } 74969 74970 str += intPart; 74971 str += decimal; 74972 str += decPart; 74973 74974 for (var j = 0; j < right - decPart.length; j++) { 74975 str += '0'; 74976 } 74977 74978 return str; 74979 } else { 74980 for (var k = 0; k < Math.max(left - intPart.length, 0); k++) { 74981 str += '0'; 74982 } 74983 74984 str += n; 74985 return str; 74986 } 74987 } 74988 /** 74989 * Utility function for formatting numbers into strings and placing 74990 * appropriate commas to mark units of 1000. There are two versions: one 74991 * for formatting ints, and one for formatting an array of ints. The value 74992 * for the right parameter should always be a positive integer. 74993 * 74994 * @method nfc 74995 * @param {Number|String} num the Number to format 74996 * @param {Integer|String} [right] number of digits to the right of the 74997 * decimal point 74998 * @return {String} formatted String 74999 * 75000 * @example 75001 * <div> 75002 * <code> 75003 * function setup() { 75004 * background(200); 75005 * var num = 11253106.115; 75006 * var numArr = [1, 1, 2]; 75007 * 75008 * noStroke(); 75009 * fill(0); 75010 * textSize(12); 75011 * 75012 * // Draw formatted numbers 75013 * text(nfc(num, 4), 10, 30); 75014 * text(nfc(numArr, 2), 10, 80); 75015 * 75016 * // Draw dividing line 75017 * stroke(120); 75018 * line(0, 50, width, 50); 75019 * } 75020 * </code> 75021 * </div> 75022 * 75023 * @alt 75024 * "11,253,106.115" top middle and "1.00,1.00,2.00" displayed bottom mid 75025 */ 75026 75027 /** 75028 * @method nfc 75029 * @param {Array} nums the Numbers to format 75030 * @param {Integer|String} [right] 75031 * @return {String[]} formatted Strings 75032 */ 75033 75034 75035 p5.prototype.nfc = function (num, right) { 75036 p5._validateParameters('nfc', arguments); 75037 75038 if (num instanceof Array) { 75039 return num.map(function (x) { 75040 return doNfc(x, right); 75041 }); 75042 } else { 75043 return doNfc(num, right); 75044 } 75045 }; 75046 75047 function doNfc(num, right) { 75048 num = num.toString(); 75049 var dec = num.indexOf('.'); 75050 var rem = dec !== -1 ? num.substring(dec) : ''; 75051 var n = dec !== -1 ? num.substring(0, dec) : num; 75052 n = n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); 75053 75054 if (right === 0) { 75055 rem = ''; 75056 } else if (typeof right !== 'undefined') { 75057 if (right > rem.length) { 75058 rem += dec === -1 ? '.' : ''; 75059 var len = right - rem.length + 1; 75060 75061 for (var i = 0; i < len; i++) { 75062 rem += '0'; 75063 } 75064 } else { 75065 rem = rem.substring(0, right + 1); 75066 } 75067 } 75068 75069 return n + rem; 75070 } 75071 /** 75072 * Utility function for formatting numbers into strings. Similar to <a href="#/p5/nf">nf()</a> but 75073 * puts a "+" in front of positive numbers and a "-" in front of negative 75074 * numbers. There are two versions: one for formatting floats, and one for 75075 * formatting ints. The values for left, and right parameters 75076 * should always be positive integers. 75077 * 75078 * @method nfp 75079 * @param {Number} num the Number to format 75080 * @param {Integer} [left] number of digits to the left of the decimal 75081 * point 75082 * @param {Integer} [right] number of digits to the right of the 75083 * decimal point 75084 * @return {String} formatted String 75085 * 75086 * @example 75087 * <div> 75088 * <code> 75089 * function setup() { 75090 * background(200); 75091 * var num1 = 11253106.115; 75092 * var num2 = -11253106.115; 75093 * 75094 * noStroke(); 75095 * fill(0); 75096 * textSize(12); 75097 * 75098 * // Draw formatted numbers 75099 * text(nfp(num1, 4, 2), 10, 30); 75100 * text(nfp(num2, 4, 2), 10, 80); 75101 * 75102 * // Draw dividing line 75103 * stroke(120); 75104 * line(0, 50, width, 50); 75105 * } 75106 * </code> 75107 * </div> 75108 * 75109 * @alt 75110 * "+11253106.11" top middle and "-11253106.11" displayed bottom middle 75111 */ 75112 75113 /** 75114 * @method nfp 75115 * @param {Number[]} nums the Numbers to format 75116 * @param {Integer} [left] 75117 * @param {Integer} [right] 75118 * @return {String[]} formatted Strings 75119 */ 75120 75121 75122 p5.prototype.nfp = function () { 75123 p5._validateParameters('nfp', arguments); 75124 75125 var nfRes = p5.prototype.nf.apply(this, arguments); 75126 75127 if (nfRes instanceof Array) { 75128 return nfRes.map(addNfp); 75129 } else { 75130 return addNfp(nfRes); 75131 } 75132 }; 75133 75134 function addNfp(num) { 75135 return parseFloat(num) > 0 ? '+' + num.toString() : num.toString(); 75136 } 75137 /** 75138 * Utility function for formatting numbers into strings. Similar to <a href="#/p5/nf">nf()</a> but 75139 * puts an additional "_" (space) in front of positive numbers just in case to align it with negative 75140 * numbers which includes "-" (minus) sign. 75141 * The main usecase of nfs() can be seen when one wants to align the digits (place values) of a positive 75142 * number with some negative number (See the example to get a clear picture). 75143 * There are two versions: one for formatting float, and one for formatting int. 75144 * The values for the digits, left, and right parameters should always be positive integers. 75145 * (IMP): The result on the canvas basically the expected alignment can vary based on the typeface you are using. 75146 * (NOTE): Be cautious when using left and right parameters as it prepends numbers of 0's if the parameter 75147 * if greater than the current length of the number. 75148 * For example if number is 123.2 and left parameter passed is 4 which is greater than length of 123 75149 * (integer part) i.e 3 than result will be 0123.2. Same case for right parameter i.e. if right is 3 than 75150 * the result will be 123.200. 75151 * 75152 * @method nfs 75153 * @param {Number} num the Number to format 75154 * @param {Integer} [left] number of digits to the left of the decimal 75155 * point 75156 * @param {Integer} [right] number of digits to the right of the 75157 * decimal point 75158 * @return {String} formatted String 75159 * 75160 * @example 75161 * <div> 75162 * <code> 75163 * var myFont; 75164 * function preload() { 75165 * myFont = loadFont('assets/fonts/inconsolata.ttf'); 75166 * } 75167 * function setup() { 75168 * background(200); 75169 * var num1 = 321; 75170 * var num2 = -1321; 75171 * 75172 * noStroke(); 75173 * fill(0); 75174 * textFont(myFont); 75175 * textSize(22); 75176 *
75177 * // nfs() aligns num1 (positive number) with num2 (negative number) by 75178 * // adding a blank space in front of the num1 (positive number) 75179 * // [left = 4] in num1 add one 0 in front, to align the digits with num2 75180 * // [right = 2] in num1 and num2 adds two 0's after both numbers 75181 * // To see the differences check the example of nf() too. 75182 * text(nfs(num1, 4, 2), 10, 30); 75183 * text(nfs(num2, 4, 2), 10, 80); 75184 * // Draw dividing line 75185 * stroke(120); 75186 * line(0, 50, width, 50); 75187 * } 75188 * </code> 75189 * </div> 75190 * 75191 * @alt 75192 * "0321.00" top middle and "-1321.00" displayed bottom middle 75193 */ 75194 75195 /** 75196 * @method nfs 75197 * @param {Array} nums the Numbers to format 75198 * @param {Integer} [left] 75199 * @param {Integer} [right] 75200 * @return {String[]} formatted Strings 75201 */ 75202 75203 75204 p5.prototype.nfs = function () { 75205 p5._validateParameters('nfs', arguments); 75206 75207 var nfRes = p5.prototype.nf.apply(this, arguments); 75208 75209 if (nfRes instanceof Array) { 75210 return nfRes.map(addNfs); 75211 } else { 75212 return addNfs(nfRes); 75213 } 75214 }; 75215 75216 function addNfs(num) { 75217 return parseFloat(num) > 0 ? ' ' + num.toString() : num.toString(); 75218 } 75219 /** 75220 * The <a href="#/p5/split">split()</a> function maps to String.split(), it breaks a String into 75221 * pieces using a character or string as the delimiter. The delim parameter 75222 * specifies the character or characters that mark the boundaries between 75223 * each piece. A String[] array is returned that contains each of the pieces. 75224 * 75225 * The <a href="#/p5/splitTokens">splitTokens()</a> function works in a similar fashion, except that it 75226 * splits using a range of characters instead of a specific character or 75227 * sequence. 75228 * 75229 * @method split 75230 * @param {String} value the String to be split 75231 * @param {String} delim the String used to separate the data 75232 * @return {String[]} Array of Strings 75233 * @example 75234 * <div> 75235 * <code> 75236 * var names = 'Pat,Xio,Alex'; 75237 * var splitString = split(names, ','); 75238 * text(splitString[0], 5, 30); 75239 * text(splitString[1], 5, 50); 75240 * text(splitString[2], 5, 70); 75241 * </code> 75242 * </div> 75243 * 75244 * @alt 75245 * "pat" top left, "Xio" mid left and "Alex" displayed bottom left 75246 * 75247 */ 75248 75249 75250 p5.prototype.split = function (str, delim) { 75251 p5._validateParameters('split', arguments); 75252 75253 return str.split(delim); 75254 }; 75255 /** 75256 * The <a href="#/p5/splitTokens">splitTokens()</a> function splits a String at one or many character 75257 * delimiters or "tokens." The delim parameter specifies the character or 75258 * characters to be used as a boundary. 75259 * <br><br> 75260 * If no delim characters are specified, any whitespace character is used to 75261 * split. Whitespace characters include tab (\t), line feed (\n), carriage 75262 * return (\r), form feed (\f), and space. 75263 * 75264 * @method splitTokens 75265 * @param {String} value the String to be split 75266 * @param {String} [delim] list of individual Strings that will be used as 75267 * separators 75268 * @return {String[]} Array of Strings 75269 * @example 75270 * <div class = "norender"> 75271 * <code> 75272 * function setup() { 75273 * var myStr = 'Mango, Banana, Lime'; 75274 * var myStrArr = splitTokens(myStr, ','); 75275 * 75276 * print(myStrArr); // prints : ["Mango"," Banana"," Lime"] 75277 * } 75278 * </code> 75279 * </div> 75280 */ 75281 75282 75283 p5.prototype.splitTokens = function (value, delims) { 75284 p5._validateParameters('splitTokens', arguments); 75285 75286 var d; 75287 75288 if (typeof delims !== 'undefined') { 75289 var str = delims; 75290 var sqc = /\]/g.exec(str); 75291 var sqo = /\[/g.exec(str); 75292 75293 if (sqo && sqc) { 75294 str = str.slice(0, sqc.index) + str.slice(sqc.index + 1); 75295 sqo = /\[/g.exec(str); 75296 str = str.slice(0, sqo.index) + str.slice(sqo.index + 1); 75297 d = new RegExp('[\\[' + str + '\\]]', 'g'); 75298 } else if (sqc) { 75299 str = str.slice(0, sqc.index) + str.slice(sqc.index + 1); 75300 d = new RegExp('[' + str + '\\]]', 'g'); 75301 } else if (sqo) { 75302 str = str.slice(0, sqo.index) + str.slice(sqo.index + 1); 75303 d = new RegExp('[' + str + '\\[]', 'g'); 75304 } else { 75305 d = new RegExp('[' + str + ']', 'g'); 75306 } 75307 } else { 75308 d = /\s/g; 75309 } 75310 75311 return value.split(d).filter(function (n) { 75312 return n; 75313 }); 75314 }; 75315 /** 75316 * Removes whitespace characters from the beginning and end of a String. In 75317 * addition to standard whitespace characters such as space, carriage return, 75318 * and tab, this function also removes the Unicode "nbsp" character. 75319 * 75320 * @method trim 75321 * @param {String} str a String to be trimmed 75322 * @return {String} a trimmed String 75323 * 75324 * @example 75325 * <div> 75326 * <code> 75327 * var string = trim(' No new lines\n '); 75328 * text(string + ' here', 2, 50); 75329 * </code> 75330 * </div> 75331 * 75332 * @alt 75333 * "No new lines here" displayed center canvas 75334 */ 75335 75336 /** 75337 * @method trim 75338 * @param {Array} strs an Array of Strings to be trimmed 75339 * @return {String[]} an Array of trimmed Strings 75340 */ 75341 75342 75343 p5.prototype.trim = function (str) { 75344 p5._validateParameters('trim', arguments); 75345 75346 if (str instanceof Array) { 75347 return str.map(this.trim); 75348 } else { 75349 return str.trim(); 75350 } 75351 }; 75352 75353 module.exports = p5; 75354 }, {
75355 "../core/error_helpers": 20, 75356 "../core/main": 24 75357 }], 75358 63: [function (_dereq_, module, exports) { 75359 /** 75360 * @module IO 75361 * @submodule Time & Date 75362 * @for p5 75363 * @requires core 75364 */ 75365 'use strict'; 75366 75367 var p5 = _dereq_('../core/main'); 75368 /** 75369 * p5.js communicates with the clock on your computer. The <a href="#/p5/day">day()</a> function 75370 * returns the current day as a value from 1 - 31. 75371 * 75372 * @method day 75373 * @return {Integer} the current day 75374 * @example 75375 * <div> 75376 * <code> 75377 * var d = day(); 75378 * text('Current day: \n' + d, 5, 50); 75379 * </code> 75380 * </div> 75381 * 75382 * @alt 75383 * Current day is displayed 75384 * 75385 */ 75386 75387 75388 p5.prototype.day = function () { 75389 return new Date().getDate(); 75390 }; 75391 /** 75392 * p5.js communicates with the clock on your computer. The <a href="#/p5/hour">hour()</a> function 75393 * returns the current hour as a value from 0 - 23. 75394 * 75395 * @method hour 75396 * @return {Integer} the current hour 75397 * @example 75398 * <div> 75399 * <code> 75400 * var h = hour(); 75401 * text('Current hour:\n' + h, 5, 50); 75402 * </code> 75403 * </div> 75404 * 75405 * @alt 75406 * Current hour is displayed 75407 * 75408 */ 75409 75410 75411 p5.prototype.hour = function () { 75412 return new Date().getHours(); 75413 }; 75414 /** 75415 * p5.js communicates with the clock on your computer. The <a href="#/p5/minute">minute()</a> function 75416 * returns the current minute as a value from 0 - 59. 75417 * 75418 * @method minute 75419 * @return {Integer} the current minute 75420 * @example 75421 * <div> 75422 * <code> 75423 * var m = minute(); 75424 * text('Current minute: \n' + m, 5, 50); 75425 * </code> 75426 * </div> 75427 * 75428 * @alt 75429 * Current minute is displayed 75430 * 75431 */ 75432 75433 75434 p5.prototype.minute = function () { 75435 return new Date().getMinutes(); 75436 }; 75437 /** 75438 * Returns the number of milliseconds (thousandths of a second) since 75439 * starting the program. This information is often used for timing events and 75440 * animation sequences. 75441 * 75442 * @method millis 75443 * @return {Number} the number of milliseconds since starting the program 75444 * @example 75445 * <div> 75446 * <code> 75447 * var millisecond = millis(); 75448 * text('Milliseconds \nrunning: \n' + millisecond, 5, 40); 75449 * </code> 75450 * </div> 75451 * 75452 * @alt 75453 * number of milliseconds since program has started displayed 75454 * 75455 */ 75456 75457 75458 p5.prototype.millis = function () { 75459 return window.performance.now(); 75460 }; 75461 /** 75462 * p5.js communicates with the clock on your computer. The <a href="#/p5/month">month()</a> function 75463 * returns the current month as a value from 1 - 12. 75464 * 75465 * @method month 75466 * @return {Integer} the current month 75467 * @example 75468 * <div> 75469 * <code> 75470 * var m = month(); 75471 * text('Current month: \n' + m, 5, 50); 75472 * </code> 75473 * </div> 75474 * 75475 * @alt 75476 * Current month is displayed 75477 * 75478 */ 75479 75480 75481 p5.prototype.month = function () { 75482 return new Date().getMonth() + 1; //January is 0! 75483 }; 75484 /** 75485 * p5.js communicates with the clock on your computer. The <a href="#/p5/second">second()</a> function 75486 * returns the current second as a value from 0 - 59. 75487 * 75488 * @method second 75489 * @return {Integer} the current second 75490 * @example 75491 * <div> 75492 * <code> 75493 * var s = second(); 75494 * text('Current second: \n' + s, 5, 50); 75495 * </code> 75496 * </div> 75497 * 75498 * @alt 75499 * Current second is displayed 75500 * 75501 */ 75502 75503 75504 p5.prototype.second = function () { 75505 return new Date().getSeconds(); 75506 }; 75507 /** 75508 * p5.js communicates with the clock on your computer. The <a href="#/p5/year">year()</a> function 75509 * returns the current year as an integer (2014, 2015, 2016, etc). 75510 * 75511 * @method year 75512 * @return {Integer} the current year 75513 * @example 75514 * <div> 75515 * <code> 75516 * var y = year(); 75517 * text('Current year: \n' + y, 5, 50); 75518 * </code> 75519 * </div> 75520 * 75521 * @alt 75522 * Current year is displayed 75523 * 75524 */ 75525 75526 75527 p5.prototype.year = function () { 75528 return new Date().getFullYear(); 75529 }; 75530 75531 module.exports = p5; 75532 }, {
75533 "../core/main": 24 75534 }], 75535 64: [function (_dereq_, module, exports) { 75536 /** 75537 * @module Shape 75538 * @submodule 3D Primitives 75539 * @for p5 75540 * @requires core 75541 * @requires p5.Geometry 75542 */ 75543 'use strict'; 75544 75545 var p5 = _dereq_('../core/main'); 75546 75547 _dereq_('./p5.Geometry'); 75548 75549 var constants = _dereq_('../core/constants'); 75550 /** 75551 * Draw a plane with given a width and height 75552 * @method plane 75553 * @param {Number} [width] width of the plane 75554 * @param {Number} [height] height of the plane 75555 * @param {Integer} [detailX] Optional number of triangle 75556 * subdivisions in x-dimension 75557 * @param {Integer} [detailY] Optional number of triangle 75558 * subdivisions in y-dimension 75559 * @chainable 75560 * @example 75561 * <div> 75562 * <code> 75563 * //draw a plane with width 50 and height 50 75564 * function setup() { 75565 * createCanvas(100, 100, WEBGL); 75566 * } 75567 * 75568 * function draw() { 75569 * background(200); 75570 * plane(50, 50); 75571 * } 75572 * </code> 75573 * </div> 75574 * 75575 * @alt 75576 * Nothing displayed on canvas 75577 * Rotating interior view of a box with sides that change color. 75578 * 3d red and green gradient. 75579 * Rotating interior view of a cylinder with sides that change color. 75580 * Rotating view of a cylinder with sides that change color. 75581 * 3d red and green gradient. 75582 * rotating view of a multi-colored cylinder with concave sides. 75583 */ 75584 75585 75586 p5.prototype.plane = function (width, height, detailX, detailY) { 75587 this._assert3d('plane'); 75588 75589 p5._validateParameters('plane', arguments); 75590 75591 if (typeof width === 'undefined') { 75592 width = 50; 75593 } 75594 75595 if (typeof height === 'undefined') { 75596 height = width; 75597 } 75598 75599 if (typeof detailX === 'undefined') { 75600 detailX = 1; 75601 } 75602 75603 if (typeof detailY === 'undefined') { 75604 detailY = 1; 75605 } 75606 75607 var gId = 'plane|' + detailX + '|' + detailY; 75608 75609 if (!this._renderer.geometryInHash(gId)) { 75610 var _plane = function () { 75611 var u, v, p; 75612 75613 for (var i = 0; i <= this.detailY; i++) { 75614 v = i / this.detailY; 75615 75616 for (var j = 0; j <= this.detailX; j++) { 75617 u = j / this.detailX; 75618 p = new p5.Vector(u - 0.5, v - 0.5, 0); 75619 this.vertices.push(p); 75620 this.uvs.push(u, v); 75621 } 75622 } 75623 }; 75624 75625 var planeGeom = new p5.Geometry(detailX, detailY, _plane); 75626 planeGeom.computeFaces().computeNormals(); 75627 75628 if (detailX <= 1 && detailY <= 1) { 75629 planeGeom._makeTriangleEdges()._edgesToVertices(); 75630 } else { 75631 console.log('Cannot draw stroke on plane objects with more' + ' than 1 detailX or 1 detailY'); 75632 } 75633 75634 this._renderer.createBuffers(gId, planeGeom); 75635 } 75636 75637 this._renderer.drawBuffersScaled(gId, width, height, 1); 75638 75639 return this; 75640 }; 75641 /** 75642 * Draw a box with given width, height and depth 75643 * @method box 75644 * @param {Number} [width] width of the box 75645 * @param {Number} [Height] height of the box 75646 * @param {Number} [depth] depth of the box 75647 * @param {Integer} [detailX] Optional number of triangle 75648 * subdivisions in x-dimension 75649 * @param {Integer} [detailY] Optional number of triangle 75650 * subdivisions in y-dimension 75651 * @chainable 75652 * @example 75653 * <div> 75654 * <code> 75655 * //draw a spinning box with width, height and depth 200 75656 * function setup() { 75657 * createCanvas(100, 100, WEBGL); 75658 * } 75659 * 75660 * function draw() { 75661 * background(200); 75662 * rotateX(frameCount * 0.01); 75663 * rotateY(frameCount * 0.01); 75664 * box(50); 75665 * } 75666 * </code> 75667 * </div> 75668 */ 75669 75670 75671 p5.prototype.box = function (width, height, depth, detailX, detailY) { 75672 this._assert3d('box'); 75673 75674 p5._validateParameters('box', arguments); 75675 75676 if (typeof width === 'undefined') { 75677 width = 50; 75678 } 75679 75680 if (typeof height === 'undefined') { 75681 height = width; 75682 } 75683 75684 if (typeof depth === 'undefined') { 75685 depth = height; 75686 } 75687 75688 var perPixelLighting = this._renderer.attributes && this._renderer.attributes.perPixelLighting; 75689 75690 if (typeof detailX === 'undefined') { 75691 detailX = perPixelLighting ? 1 : 4; 75692 } 75693 75694 if (typeof detailY === 'undefined') { 75695 detailY = perPixelLighting ? 1 : 4; 75696 } 75697 75698 var gId = 'box|' + detailX + '|' + detailY; 75699 75700 if (!this._renderer.geometryInHash(gId)) { 75701 var _box = function () { 75702 var cubeIndices = [[0, 4, 2, 6], // -1, 0, 0],// -x 75703 [1, 3, 5, 7], // +1, 0, 0],// +x 75704 [0, 1, 4, 5], // 0, -1, 0],// -y 75705 [2, 6, 3, 7], // 0, +1, 0],// +y 75706 [0, 2, 1, 3], // 0, 0, -1],// -z 75707 [4, 5, 6, 7] // 0, 0, +1] // +z 75708 ]; //using strokeIndices instead of faces for strokes 75709 //to avoid diagonal stroke lines across face of box 75710 75711 this.strokeIndices = [[0, 1], [1, 3], [3, 2], [6, 7], [8, 9], [9, 11], [14, 15], [16, 17], [17, 19], [18, 19], [20, 21], [22, 23]]; 75712 75713 for (var i = 0; i < cubeIndices.length; i++) { 75714 var cubeIndex = cubeIndices[i]; 75715 var v = i * 4; 75716 75717 for (var j = 0; j < 4; j++) { 75718 var d = cubeIndex[j]; //inspired by lightgl: 75719 //https://github.com/evanw/lightgl.js 75720 //octants:https://en.wikipedia.org/wiki/Octant_(solid_geometry) 75721 75722 var octant = new p5.Vector(((d & 1) * 2 - 1) / 2, ((d & 2) - 1) / 2, ((d & 4) / 2 - 1) / 2); 75723 this.vertices.push(octant); 75724 this.uvs.push(j & 1, (j & 2) / 2); 75725 } 75726 75727 this.faces.push([v, v + 1, v + 2]); 75728 this.faces.push([v + 2, v + 1, v + 3]); 75729 } 75730 }; 75731 75732 var boxGeom = new p5.Geometry(detailX, detailY, _box); 75733 boxGeom.computeNormals(); 75734 75735 if (detailX <= 4 && detailY <= 4) { 75736 boxGeom._makeTriangleEdges()._edgesToVertices(); 75737 } else { 75738 console.log('Cannot draw stroke on box objects with more' + ' than 4 detailX or 4 detailY'); 75739 } //initialize our geometry buffer with 75740 //the key val pair: 75741 //geometry Id, Geom object 75742 75743 75744 this._renderer.createBuffers(gId, boxGeom); 75745 } 75746 75747 this._renderer.drawBuffersScaled(gId, width, height, depth); 75748 75749 return this; 75750 }; 75751 /** 75752 * Draw a sphere with given radius 75753 * @method sphere 75754 * @param {Number} [radius] radius of circle 75755 * @param {Integer} [detailX] number of segments, 75756 * the more segments the smoother geometry 75757 * default is 24 75758 * @param {Integer} [detailY] number of segments, 75759 * the more segments the smoother geometry 75760 * default is 16 75761 * @chainable 75762 * @example 75763 * <div> 75764 * <code> 75765 * // draw a sphere with radius 200 75766 * function setup() { 75767 * createCanvas(100, 100, WEBGL); 75768 * } 75769 * 75770 * function draw() { 75771 * background(200); 75772 * sphere(40); 75773 * } 75774 * </code> 75775 * </div> 75776 */ 75777 75778 75779 p5.prototype.sphere = function (radius, detailX, detailY) { 75780 this._assert3d('sphere'); 75781 75782 p5._validateParameters('sphere', arguments); 75783 75784 if (typeof radius === 'undefined') { 75785 radius = 50; 75786 } 75787 75788 if (typeof detailX === 'undefined') { 75789 detailX = 24; 75790 } 75791 75792 if (typeof detailY === 'undefined') { 75793 detailY = 16; 75794 } 75795 75796 this.ellipsoid(radius, radius, radius, detailX, detailY); 75797 return this; 75798 }; 75799 /** 75800 * @private 75801 * Helper function for creating both cones and cyllinders 75802 * Will only generate well-defined geometry when bottomRadius, height > 0 75803 * and topRadius >= 0 75804 * If topRadius == 0, topCap should be false 75805 */ 75806 75807 75808 var _truncatedCone = function (bottomRadius, topRadius, height, detailX, detailY, bottomCap, topCap) { 75809 bottomRadius = bottomRadius <= 0 ? 1 : bottomRadius; 75810 topRadius = topRadius < 0 ? 0 : topRadius; 75811 height = height <= 0 ? bottomRadius : height; 75812 detailX = detailX < 3 ? 3 : detailX; 75813 detailY = detailY < 1 ? 1 : detailY; 75814 bottomCap = bottomCap === undefined ? true : bottomCap; 75815 topCap = topCap === undefined ? topRadius !== 0 : topCap; 75816 var start = bottomCap ? -2 : 0; 75817 var end = detailY + (topCap ? 2 : 0); 75818 var vertsOnLayer = {}; //ensure constant slant for interior vertex normals 75819 75820 var slant = Math.atan2(bottomRadius - topRadius, height); 75821 var yy, ii, jj, nextii, nextjj; 75822 75823 for (yy = start; yy <= end; ++yy) { 75824 var v = yy / detailY; 75825 var y = height * v; 75826 var ringRadius; 75827 75828 if (yy < 0) { 75829 //for the bottomCap edge 75830 y = 0; 75831 v = 0; 75832 ringRadius = bottomRadius; 75833 } else if (yy > detailY) { 75834 //for the topCap edge 75835 y = height; 75836 v = 1; 75837 ringRadius = topRadius; 75838 } else { 75839 //for the middle 75840 ringRadius = bottomRadius + (topRadius - bottomRadius) * v; 75841 } 75842 75843 if (yy === -2 || yy === detailY + 2) { 75844 //center of bottom or top caps 75845 ringRadius = 0; 75846 } 75847 75848 y -= height / 2; //shift coordiate origin to the center of object 75849 75850 vertsOnLayer[yy] = ringRadius === 0 ? 1 : detailX; 75851 75852 for (ii = 0; ii < vertsOnLayer[yy]; ++ii) { 75853 var u = ii / detailX; //VERTICES 75854 75855 this.vertices.push(new p5.Vector(Math.sin(u * 2 * Math.PI) * ringRadius, y, Math.cos(u * 2 * Math.PI) * ringRadius)); //VERTEX NORMALS 75856 75857 this.vertexNormals.push(new p5.Vector(yy < 0 || yy > detailY ? 0 : Math.sin(u * 2 * Math.PI) * Math.cos(slant), yy < 0 ? -1 : yy > detailY ? 1 : Math.sin(slant), yy < 0 || yy > detailY ? 0 : Math.cos(u * 2 * Math.PI) * Math.cos(slant))); //UVs 75858 75859 this.uvs.push(u, v); 75860 } 75861 } 75862 75863 var startIndex = 0; 75864 75865 if (bottomCap) { 75866 for (jj = 0; jj < vertsOnLayer[-1]; ++jj) { 75867 nextjj = (jj + 1) % vertsOnLayer[-1]; 75868 this.faces.push([startIndex, startIndex + 1 + nextjj, startIndex + 1 + jj]); 75869 } 75870 75871 startIndex += vertsOnLayer[-2] + vertsOnLayer[-1]; 75872 } 75873 75874 for (yy = 0; yy < detailY; ++yy) { 75875 for (ii = 0; ii < vertsOnLayer[yy]; ++ii) { 75876 if (vertsOnLayer[yy + 1] === 1) { 75877 //top layer 75878 nextii = (ii + 1) % vertsOnLayer[yy]; 75879 this.faces.push([startIndex + ii, startIndex + nextii, startIndex + vertsOnLayer[yy]]); 75880 } else { 75881 //other side faces 75882 //should have vertsOnLayer[yy] === vertsOnLayer[yy + 1] 75883 nextii = (ii + 1) % vertsOnLayer[yy]; 75884 this.faces.push([startIndex + ii, startIndex + nextii, startIndex + vertsOnLayer[yy] + nextii]); 75885 this.faces.push([startIndex + ii, startIndex + vertsOnLayer[yy] + nextii, startIndex + vertsOnLayer[yy] + ii]); 75886 } 75887 } 75888 75889 startIndex += vertsOnLayer[yy]; 75890 } 75891 75892 if (topCap) { 75893 startIndex += vertsOnLayer[detailY]; 75894 75895 for (ii = 0; ii < vertsOnLayer[detailY + 1]; ++ii) { 75896 nextii = (ii + 1) % vertsOnLayer[detailY + 1]; 75897 this.faces.push([startIndex + ii, startIndex + nextii, startIndex + vertsOnLayer[detailY + 1]]); 75898 } 75899 } 75900 }; 75901 /** 75902 * Draw a cylinder with given radius and height 75903 * @method cylinder 75904 * @param {Number} [radius] radius of the surface 75905 * @param {Number} [height] height of the cylinder 75906 * @param {Integer} [detailX] number of segments, 75907 * the more segments the smoother geometry 75908 * default is 24 75909 * @param {Integer} [detailY] number of segments in y-dimension, 75910 * the more segments the smoother geometry 75911 * default is 1 75912 * @param {Boolean} [bottomCap] whether to draw the bottom of the cylinder 75913 * @param {Boolean} [topCap] whether to draw the top of the cylinder 75914 * @chainable 75915 * @example 75916 * <div> 75917 * <code> 75918 * //draw a spinning cylinder with radius 20 and height 50 75919 * function setup() { 75920 * createCanvas(100, 100, WEBGL); 75921 * } 75922 * 75923 * function draw() { 75924 * background(200); 75925 * rotateX(frameCount * 0.01); 75926 * rotateZ(frameCount * 0.01); 75927 * cylinder(20, 50); 75928 * } 75929 * </code> 75930 * </div> 75931 */ 75932 75933 75934 p5.prototype.cylinder = function (radius, height, detailX, detailY, bottomCap, topCap) { 75935 this._assert3d('cylinder'); 75936 75937 p5._validateParameters('cylinder', arguments); 75938 75939 if (typeof radius === 'undefined') { 75940 radius = 50; 75941 } 75942 75943 if (typeof height === 'undefined') { 75944 height = radius; 75945 } 75946 75947 if (typeof detailX === 'undefined') { 75948 detailX = 24; 75949 } 75950 75951 if (typeof detailY === 'undefined') { 75952 detailY = 1; 75953 } 75954 75955 if (typeof topCap === 'undefined') { 75956 topCap = true; 75957 } 75958 75959 if (typeof bottomCap === 'undefined') { 75960 bottomCap = true; 75961 } 75962 75963 var gId = 'cylinder|' + detailX + '|' + detailY + '|' + bottomCap + '|' + topCap; 75964 75965 if (!this._renderer.geometryInHash(gId)) { 75966 var cylinderGeom = new p5.Geometry(detailX, detailY); 75967 75968 _truncatedCone.call(cylinderGeom, 1, 1, 1, detailX, detailY, bottomCap, topCap); 75969 75970 cylinderGeom.computeNormals(); 75971 75972 if (detailX <= 24 && detailY <= 16) { 75973 cylinderGeom._makeTriangleEdges()._edgesToVertices(); 75974 } else { 75975 console.log('Cannot draw stroke on cylinder objects with more' + ' than 24 detailX or 16 detailY'); 75976 } 75977 75978 this._renderer.createBuffers(gId, cylinderGeom); 75979 } 75980 75981 this._renderer.drawBuffersScaled(gId, radius, height, radius); 75982 75983 return this; 75984 }; 75985 /** 75986 * Draw a cone with given radius and height 75987 * @method cone 75988 * @param {Number} [radius] radius of the bottom surface 75989 * @param {Number} [height] height of the cone 75990 * @param {Integer} [detailX] number of segments, 75991 * the more segments the smoother geometry 75992 * default is 24 75993 * @param {Integer} [detailY] number of segments, 75994 * the more segments the smoother geometry 75995 * default is 1 75996 * @param {Boolean} [cap] whether to draw the base of the cone 75997 * @chainable 75998 * @example 75999 * <div> 76000 * <code> 76001 * //draw a spinning cone with radius 40 and height 70 76002 * function setup() { 76003 * createCanvas(100, 100, WEBGL); 76004 * } 76005 * 76006 * function draw() { 76007 * background(200); 76008 * rotateX(frameCount * 0.01); 76009 * rotateZ(frameCount * 0.01); 76010 * cone(40, 70); 76011 * } 76012 * </code> 76013 * </div> 76014 */ 76015 76016 76017 p5.prototype.cone = function (radius, height, detailX, detailY, cap) { 76018 this._assert3d('cone'); 76019 76020 p5._validateParameters('cone', arguments); 76021 76022 if (typeof radius === 'undefined') { 76023 radius = 50; 76024 } 76025 76026 if (typeof height === 'undefined') { 76027 height = radius; 76028 } 76029 76030 if (typeof detailX === 'undefined') { 76031 detailX = 24; 76032 } 76033 76034 if (typeof detailY === 'undefined') { 76035 detailY = 1; 76036 } 76037 76038 if (typeof cap === 'undefi
76038ned') { 76039 cap = true; 76040 } 76041 76042 var gId = 'cone|' + detailX + '|' + detailY + '|' + cap; 76043 76044 if (!this._renderer.geometryInHash(gId)) { 76045 var coneGeom = new p5.Geometry(detailX, detailY); 76046 76047 _truncatedCone.call(coneGeom, 1, 0, 1, detailX, detailY, cap, false); //for cones we need to average Normals 76048 76049 76050 coneGeom.computeNormals(); 76051 76052 if (detailX <= 24 && detailY <= 16) { 76053 coneGeom._makeTriangleEdges()._edgesToVertices(); 76054 } else { 76055 console.log('Cannot draw stroke on cone objects with more' + ' than 24 detailX or 16 detailY'); 76056 } 76057 76058 this._renderer.createBuffers(gId, coneGeom); 76059 } 76060 76061 this._renderer.drawBuffersScaled(gId, radius, height, radius); 76062 76063 return this; 76064 }; 76065 /** 76066 * Draw an ellipsoid with given radius 76067 * @method ellipsoid 76068 * @param {Number} [radiusx] xradius of circle 76069 * @param {Number} [radiusy] yradius of circle 76070 * @param {Number} [radiusz] zradius of circle 76071 * @param {Integer} [detailX] number of segments, 76072 * the more segments the smoother geometry 76073 * default is 24. Avoid detail number above 76074 * 150, it may crash the browser. 76075 * @param {Integer} [detailY] number of segments, 76076 * the more segments the smoother geometry 76077 * default is 16. Avoid detail number above 76078 * 150, it may crash the browser. 76079 * @chainable 76080 * @example 76081 * <div> 76082 * <code> 76083 * // draw an ellipsoid with radius 20, 30 and 40. 76084 * function setup() { 76085 * createCanvas(100, 100, WEBGL); 76086 * } 76087 * 76088 * function draw() { 76089 * background(200); 76090 * ellipsoid(20, 30, 40); 76091 * } 76092 * </code> 76093 * </div> 76094 */ 76095 76096 76097 p5.prototype.ellipsoid = function (radiusX, radiusY, radiusZ, detailX, detailY) { 76098 this._assert3d('ellipsoid'); 76099 76100 p5._validateParameters('ellipsoid', arguments); 76101 76102 if (typeof radiusX === 'undefined') { 76103 radiusX = 50; 76104 } 76105 76106 if (typeof radiusY === 'undefined') { 76107 radiusY = radiusX; 76108 } 76109 76110 if (typeof radiusZ === 'undefined') { 76111 radiusZ = radiusX; 76112 } 76113 76114 if (typeof detailX === 'undefined') { 76115 detailX = 24; 76116 } 76117 76118 if (typeof detailY === 'undefined') { 76119 detailY = 16; 76120 } 76121 76122 var gId = 'ellipsoid|' + detailX + '|' + detailY; 76123 76124 if (!this._renderer.geometryInHash(gId)) { 76125 var _ellipsoid = function () { 76126 for (var i = 0; i <= this.detailY; i++) { 76127 var v = i / this.detailY; 76128 var phi = Math.PI * v - Math.PI / 2; 76129 var cosPhi = Math.cos(phi); 76130 var sinPhi = Math.sin(phi); 76131 76132 for (var j = 0; j <= this.detailX; j++) { 76133 var u = j / this.detailX; 76134 var theta = 2 * Math.PI * u; 76135 var cosTheta = Math.cos(theta); 76136 var sinTheta = Math.sin(theta); 76137 var p = new p5.Vector(cosPhi * sinTheta, sinPhi, cosPhi * cosTheta); 76138 this.vertices.push(p); 76139 this.vertexNormals.push(p); 76140 this.uvs.push(u, v); 76141 } 76142 } 76143 }; 76144 76145 var ellipsoidGeom = new p5.Geometry(detailX, detailY, _ellipsoid); 76146 ellipsoidGeom.computeFaces(); 76147 76148 if (detailX <= 24 && detailY <= 24) { 76149 ellipsoidGeom._makeTriangleEdges()._edgesToVertices(); 76150 } else { 76151 console.log('Cannot draw stroke on ellipsoids with more' + ' than 24 detailX or 24 detailY'); 76152 } 76153 76154 this._renderer.createBuffers(gId, ellipsoidGeom); 76155 } 76156 76157 this._renderer.drawBuffersScaled(gId, radiusX, radiusY, radiusZ); 76158 76159 return this; 76160 }; 76161 /** 76162 * Draw a torus with given radius and tube radius 76163 * @method torus 76164 * @param {Number} [radius] radius of the whole ring 76165 * @param {Number} [tubeRadius] radius of the tube 76166 * @param {Integer} [detailX] number of segments in x-dimension, 76167 * the more segments the smoother geometry 76168 * default is 24 76169 * @param {Integer} [detailY] number of segments in y-dimension, 76170 * the more segments the smoother geometry 76171 * default is 16 76172 * @chainable 76173 * @example 76174 * <div> 76175 * <code> 76176 * //draw a spinning torus with radius 200 and tube radius 60 76177 * function setup() { 76178 * createCanvas(100, 100, WEBGL); 76179 * } 76180 * 76181 * function draw() { 76182 * background(200); 76183 * rotateX(frameCount * 0.01); 76184 * rotateY(frameCount * 0.01); 76185 * torus(50, 15); 76186 * } 76187 * </code> 76188 * </div> 76189 */ 76190 76191 76192 p5.prototype.torus = function (radius, tubeRadius, detailX, detailY) { 76193 this._assert3d('torus'); 76194 76195 p5._validateParameters('torus', arguments); 76196 76197 if (typeof radius === 'undefined') { 76198 radius = 50; 76199 } else if (!radius) { 76200 return; // nothing to draw 76201 } 76202 76203 if (typeof tubeRadius === 'undefined') { 76204 tubeRadius = 10; 76205 } else if (!tubeRadius) { 76206 return; // nothing to draw 76207 } 76208 76209 if (typeof detailX === 'undefined') { 76210 detailX = 24; 76211 } 76212 76213 if (typeof detailY === 'undefined') { 76214 detailY = 16; 76215 } 76216 76217 var tubeRatio = (tubeRadius / radius).toPrecision(4); 76218 var gId = 'torus|' + tubeRatio + '|' + detailX + '|' + detailY; 76219 76220 if (!this._renderer.geometryInHash(gId)) { 76221 var _torus = function () { 76222 for (var i = 0; i <= this.detailY; i++) { 76223 var v = i / this.detailY; 76224 var phi = 2 * Math.PI * v; 76225 var cosPhi = Math.cos(phi);
76226 var sinPhi = Math.sin(phi); 76227 var r = 1 + tubeRatio * cosPhi; 76228 76229 for (var j = 0; j <= this.detailX; j++) { 76230 var u = j / this.detailX; 76231 var theta = 2 * Math.PI * u; 76232 var cosTheta = Math.cos(theta); 76233 var sinTheta = Math.sin(theta); 76234 var p = new p5.Vector(r * cosTheta, r * sinTheta, tubeRatio * sinPhi); 76235 var n = new p5.Vector(cosPhi * cosTheta, cosPhi * sinTheta, sinPhi); 76236 this.vertices.push(p); 76237 this.vertexNormals.push(n); 76238 this.uvs.push(u, v); 76239 } 76240 } 76241 }; 76242 76243 var torusGeom = new p5.Geometry(detailX, detailY, _torus); 76244 torusGeom.computeFaces(); 76245 76246 if (detailX <= 24 && detailY <= 16) { 76247 torusGeom._makeTriangleEdges()._edgesToVertices(); 76248 } else { 76249 console.log('Cannot draw strokes on torus object with more' + ' than 24 detailX or 16 detailY'); 76250 } 76251 76252 this._renderer.createBuffers(gId, torusGeom); 76253 } 76254 76255 this._renderer.drawBuffersScaled(gId, radius, radius, radius); 76256 76257 return this; 76258 }; /////////////////////// 76259 /// 2D primitives 76260 ///////////////////////// 76261 76262 /** 76263 * Draws a point, a coordinate in space at the dimension of one pixel, 76264 * given x, y and z coordinates. The color of the point is determined 76265 * by the current stroke, while the point size is determined by current 76266 * stroke weight. 76267 * @private 76268 * @param {Number} x x-coordinate of point 76269 * @param {Number} y y-coordinate of point 76270 * @param {Number} z z-coordinate of point 76271 * @chainable 76272 * @example 76273 * <div> 76274 * <code> 76275 * function setup() { 76276 * createCanvas(100, 100, WEBGL); 76277 * } 76278 * 76279 * function draw() { 76280 * background(50); 76281 * stroke(255); 76282 * strokeWeight(4); 76283 * point(25, 0); 76284 * strokeWeight(3); 76285 * point(-25, 0); 76286 * strokeWeight(2); 76287 * point(0, 25); 76288 * strokeWeight(1); 76289 * point(0, -25); 76290 * } 76291 * </code> 76292 * </div> 76293 */ 76294 76295 76296 p5.RendererGL.prototype.point = function (x, y, z) { 76297 this._usePointShader(); 76298 76299 this.curPointShader.bindShader(); 76300 76301 if (typeof z === 'undefined') { 76302 z = 0; 76303 } 76304 76305 var _vertex = []; 76306 76307 _vertex.push(new p5.Vector(x, y, z)); 76308 76309 this._drawPoints(_vertex, this._pointVertexBuffer); 76310 76311 this.curPointShader.unbindShader(); 76312 return this; 76313 }; 76314 76315 p5.RendererGL.prototype.triangle = function (args) { 76316 var x1 = args[0], 76317 y1 = args[1]; 76318 var x2 = args[2], 76319 y2 = args[3]; 76320 var x3 = args[4], 76321 y3 = args[5]; 76322 var gId = 'tri'; 76323 76324 if (!this.geometryInHash(gId)) { 76325 var _triangle = function () { 76326 var vertices = []; 76327 vertices.push(new p5.Vector(0, 0, 0)); 76328 vertices.push(new p5.Vector(0, 1, 0)); 76329 vertices.push(new p5.Vector(1, 0, 0)); 76330 this.strokeIndices = [[0, 1], [1, 2], [2, 0]]; 76331 this.vertices = vertices; 76332 this.faces = [[0, 1, 2]]; 76333 this.uvs = [0, 0, 0, 1, 1, 1]; 76334 }; 76335 76336 var triGeom = new p5.Geometry(1, 1, _triangle); 76337 76338 triGeom._makeTriangleEdges()._edgesToVertices(); 76339 76340 triGeom.computeNormals(); 76341 this.createBuffers(gId, triGeom); 76342 } // only one triangle is cached, one point is at the origin, and the 76343 // two adjacent sides are tne unit vectors along the X & Y axes. 76344 // 76345 // this matrix multiplication transforms those two unit vectors 76346 // onto the required vector prior to rendering, and moves the 76347 // origin appropriately. 76348 76349 76350 var uMVMatrix = this.uMVMatrix.copy(); 76351 76352 try { 76353 // prettier-ignore 76354 var mult = new p5.Matrix([x2 - x1, y2 - y1, 0, 0, // the resulting unit X-axis 76355 x3 - x1, y3 - y1, 0, 0, // the resulting unit Y-axis 76356 0, 0, 1, 0, // the resulting unit Z-axis (unchanged) 76357 x1, y1, 0, 1 // the resulting origin 76358 ]).mult(this.uMVMatrix); 76359 this.uMVMatrix = mult; 76360 this.drawBuffers(gId); 76361 } finally { 76362 this.uMVMatrix = uMVMatrix; 76363 } 76364 76365 return this; 76366 }; 76367 76368 p5.RendererGL.prototype.ellipse = function (args) { 76369 this.arc(args[0], args[1], args[2], args[3], 0, constants.TWO_PI, constants.OPEN, args[4]); 76370 }; 76371 76372 p5.RendererGL.prototype.arc = function (args) { 76373 var x = arguments[0]; 76374 var y = arguments[1]; 76375 var width = arguments[2]; 76376 var height = arguments[3]; 76377 var start = arguments[4]; 76378 var stop = arguments[5]; 76379 var mode = arguments[6]; 76380 var detail = arguments[7] || 25; 76381 var shape; 76382 var gId; // check if it is an ellipse or an arc 76383 76384 if (Math.abs(stop - start) >= constants.TWO_PI) { 76385 shape = 'ellipse'; 76386 gId = shape + '|' + detail + '|'; 76387 } else { 76388 shape = 'arc'; 76389 gId = shape + '|' + start + '|' + stop + '|' + mode + '|' + detail + '|'; 76390 } 76391 76392 if (!this.geometryInHash(gId)) { 76393 var _arc = function () { 76394 this.strokeIndices = []; // if the start and stop angles are not the same, push vertices to the array 76395 76396 if (start.toFixed(10) !== stop.toFixed(10)) { 76397 // if the mode specified is PIE or null, push the mid point of the arc in vertices 76398 if (mode === constants.PIE || typeof mode === 'undefined') { 76399 this.vertices.push(new p5.Vector(0.5, 0.5, 0)); 76400 this.uvs.push([0.5, 0.5]); 76401 } // vertices for the perimeter of the circle 76402 76403 76404 for (var i = 0; i <= detail; i++) { 76405 var u = i / detail; 76406 var theta = (stop - start) * u + start; 76407
76408 var _x = 0.5 + Math.cos(theta) / 2; 76409 76410 var _y = 0.5 + Math.sin(theta) / 2; 76411 76412 this.vertices.push(new p5.Vector(_x, _y, 0)); 76413 this.uvs.push([_x, _y]); 76414 76415 if (i < detail - 1) { 76416 this.faces.push([0, i + 1, i + 2]); 76417 this.strokeIndices.push([i + 1, i + 2]); 76418 } 76419 } // check the mode specified in order to push vertices and faces, different for each mode 76420 76421 76422 switch (mode) { 76423 case constants.PIE: 76424 this.faces.push([0, this.vertices.length - 2, this.vertices.length - 1]); 76425 this.strokeIndices.push([0, 1]); 76426 this.strokeIndices.push([this.vertices.length - 2, this.vertices.length - 1]); 76427 this.strokeIndices.push([0, this.vertices.length - 1]); 76428 break; 76429 76430 case constants.CHORD: 76431 this.strokeIndices.push([0, 1]); 76432 this.strokeIndices.push([0, this.vertices.length - 1]); 76433 break; 76434 76435 case constants.OPEN: 76436 this.strokeIndices.push([0, 1]); 76437 break; 76438 76439 default: 76440 this.faces.push([0, this.vertices.length - 2, this.vertices.length - 1]); 76441 this.strokeIndices.push([this.vertices.length - 2, this.vertices.length - 1]); 76442 } 76443 } 76444 }; 76445 76446 var arcGeom = new p5.Geometry(detail, 1, _arc); 76447 arcGeom.computeNormals(); 76448 76449 if (detail <= 50) { 76450 arcGeom._makeTriangleEdges()._edgesToVertices(arcGeom); 76451 } else { 76452 console.log('Cannot stroke ' + shape + ' with more than 50 detail'); 76453 } 76454 76455 this.createBuffers(gId, arcGeom); 76456 } 76457 76458 var uMVMatrix = this.uMVMatrix.copy(); 76459 76460 try { 76461 this.uMVMatrix.translate([x, y, 0]); 76462 this.uMVMatrix.scale(width, height, 1); 76463 this.drawBuffers(gId); 76464 } finally { 76465 this.uMVMatrix = uMVMatrix; 76466 } 76467 76468 return this; 76469 }; 76470 76471 p5.RendererGL.prototype.rect = function (args) { 76472 var perPixelLighting = this.attributes.perPixelLighting; 76473 var x = args[0]; 76474 var y = args[1]; 76475 var width = args[2]; 76476 var height = args[3]; 76477 var detailX = args[4] || (perPixelLighting ? 1 : 24); 76478 var detailY = args[5] || (perPixelLighting ? 1 : 16); 76479 var gId = 'rect|' + detailX + '|' + detailY; 76480 76481 if (!this.geometryInHash(gId)) { 76482 var _rect = function () { 76483 for (var i = 0; i <= this.detailY; i++) { 76484 var v = i / this.detailY; 76485 76486 for (var j = 0; j <= this.detailX; j++) { 76487 var u = j / this.detailX; 76488 var p = new p5.Vector(u, v, 0); 76489 this.vertices.push(p); 76490 this.uvs.push(u, v); 76491 } 76492 } // using stroke indices to avoid stroke over face(s) of rectangle 76493 76494 76495 if (detailX > 0 && detailY > 0) { 76496 this.strokeIndices = [[0, detailX], [detailX, (detailX + 1) * (detailY + 1) - 1], [(detailX + 1) * (detailY + 1) - 1, (detailX + 1) * detailY], [(detailX + 1) * detailY, 0]]; 76497 } 76498 }; 76499 76500 var rectGeom = new p5.Geometry(detailX, detailY, _rect); 76501 76502 rectGeom.computeFaces().computeNormals()._makeTriangleEdges()._edgesToVertices(); 76503 76504 this.createBuffers(gId, rectGeom); 76505 } // only a single rectangle (of a given detail) is cached: a square with 76506 // opposite corners at (0,0) & (1,1). 76507 // 76508 // before rendering, this square is scaled & moved to the required location. 76509 76510 76511 var uMVMatrix = this.uMVMatrix.copy(); 76512 76513 try { 76514 this.uMVMatrix.translate([x, y, 0]); 76515 this.uMVMatrix.scale(width, height, 1); 76516 this.drawBuffers(gId); 76517 } finally { 76518 this.uMVMatrix = uMVMatrix; 76519 } 76520 76521 return this; 76522 }; 76523 76524 p5.RendererGL.prototype.quad = function (x1, y1, x2, y2, x3, y3, x4, y4) { 76525 var gId = 'quad|' + x1 + '|' + y1 + '|' + x2 + '|' + y2 + '|' + x3 + '|' + y3 + '|' + x4 + '|' + y4; 76526 76527 if (!this.geometryInHash(gId)) { 76528 var _quad = function () { 76529 this.vertices.push(new p5.Vector(x1, y1, 0)); 76530 this.vertices.push(new p5.Vector(x2, y2, 0)); 76531 this.vertices.push(new p5.Vector(x3, y3, 0)); 76532 this.vertices.push(new p5.Vector(x4, y4, 0)); 76533 this.uvs.push(0, 0, 1, 0, 1, 1, 0, 1); 76534 this.strokeIndices = [[0, 1], [1, 2], [2, 3], [3, 0]]; 76535 }; 76536 76537 var quadGeom = new p5.Geometry(2, 2, _quad); 76538 76539 quadGeom.computeNormals()._makeTriangleEdges()._edgesToVertices(); 76540 76541 quadGeom.faces = [[0, 1, 2], [2, 3, 0]]; 76542 this.createBuffers(gId, quadGeom); 76543 } 76544 76545 this.drawBuffers(gId); 76546 return this; 76547 }; //this implementation of bezier curve 76548 //is based on Bernstein polynomial 76549 // pretier-ignore 76550 76551 76552 p5.RendererGL.prototype.bezier = function (x1, y1, z1, // x2 76553 x2, // y2 76554 y2, // x3 76555 z2, // y3 76556 x3, // x4 76557 y3, // y4 76558 z3, x4, y4, z4) { 76559 if (arguments.length === 8) { 76560 x4 = x3; 76561 y4 = y3; 76562 x3 = y2; 76563 y3 = x2; 76564 x2 = z1; 76565 y2 = x2; 76566 z1 = z2 = z3 = z4 = 0; 76567 } 76568 76569 var bezierDetail = this._pInst._bezierDetail || 20; //value of Bezier detail 76570 76571 this.beginShape(); 76572 76573 for (var i = 0; i <= bezierDetail; i++) { 76574 var c1 = Math.pow(1 - i / bezierDetail, 3); 76575 var c2 = 3 * (i / bezierDetail) * Math.pow(1 - i / bezierDetail, 2); 76576 var c3 = 3 * Math.pow(i / bezierDetail, 2) * (1 - i / bezierDetail); 76577 var c4 = Math.pow(i / bezierDetail, 3); 76578 this.vertex(x1 * c1 + x2 * c2 + x3 * c3 + x4 * c4, y1 * c1 + y2 * c2 + y3 * c3 + y4 * c4, z1 * c1 + z2 * c2 + z3 * c3 + z4 * c4); 76579 } 76580 76581 this.endShape(); 76582 return this; 76583 }; // pretier-ignore 76584 76585 76586 p5.RendererGL.prototype.curve = function (x1, y1, z1, // x2 76587 x2, // y2 76588 y2, // x3 76589 z2, // y3 76590 x3, // x4 76591 y3, // y4 76592 z3, x4, y4, z4) { 76593 if (arguments.length === 8) { 76594 x4 = x3; 76595 y4 = y3; 76596 x3 = y2; 76597 y3 = x2; 76598 x2 = z1; 76599 y2 = x2; 76600 z1 = z2 = z3 = z4 = 0; 76601 } 76602 76603 var curveDetail = this._pInst._curveDetail; 76604 this.beginShape(); 76605 76606 for (var i = 0; i <= curveDetail; i++) { 76607 var c1 = Math.pow(i / curveDetail, 3) * 0.5; 76608 var c2 = Math.pow(i / curveDetail, 2) * 0.5; 76609 var c3 = i / curveDetail * 0.5; 76610 var c4 = 0.5; 76611 var vx = c1 * (-x1 + 3 * x2 - 3 * x3 + x4) + c2 * (2 * x1 - 5 * x2 + 4 * x3 - x4) + c3 * (-x1 + x3) + c4 * (2 * x2); 76612 var vy = c1 * (-y1 + 3 * y2 - 3 * y3 + y4) + c2 * (2 * y1 - 5 * y2 + 4 * y3 - y4) + c3 * (-y1 + y3) + c4 * (2 * y2); 76613 var vz = c1 * (-z1 + 3 * z2 - 3 * z3 + z4) + c2 * (2 * z1 - 5 * z2 + 4 * z3 - z4) + c3 * (-z1 + z3) + c4 * (2 * z2); 76614 this.vertex(vx, vy, vz); 76615 } 76616 76617 this.endShape(); 76618 return this; 76619 }; 76620 /** 76621 * Draw a line given two points 76622 * @private 76623 * @param {Number} x0 x-coordinate of first vertex 76624 * @param {Number} y0 y-coordinate of first vertex 76625 * @param {Number} z0 z-coordinate of first vertex 76626 * @param {Number} x1 x-coordinate of second vertex 76627 * @param {Number} y1 y-coordinate of second vertex 76628 * @param {Number} z1 z-coordinate of second vertex 76629 * @chainable 76630 * @example 76631 * <div> 76632 * <code> 76633 * //draw a line 76634 * function setup() { 76635 * createCanvas(100, 100, WEBGL); 76636 * } 76637 * 76638 * function draw() { 76639 * background(200); 76640 * rotateX(frameCount * 0.01); 76641 * rotateY(frameCount * 0.01); 76642 * // Use fill instead of stroke to change the color of shape. 76643 * fill(255, 0, 0); 76644 * line(10, 10, 0, 60, 60, 20); 76645 * } 76646 * </code> 76647 * </div> 76648 */ 76649 76650 76651 p5.RendererGL.prototype.line = function () { 76652 if (arguments.length === 6) { 76653 this.beginShape(); 76654 this.vertex(arguments[0], arguments[1], arguments[2]); 76655 this.vertex(arguments[3], arguments[4], arguments[5]); 76656 this.endShape(); 76657 } else if (arguments.length === 4) { 76658 this.beginShape(); 76659 this.vertex(arguments[0], arguments[1], 0); 76660 this.vertex(arguments[2], arguments[3], 0); 76661 this.endShape(); 76662 } 76663 76664 return this; 76665 }; 76666 76667 p5.RendererGL.prototype.bezierVertex = function () { 76668 if (this.immediateMode._bezierVertex.length === 0) { 76669 throw Error('vertex() must be used once before calling bezierVertex()'); 76670 } else { 76671 var w_x = [];
76672 var w_y = []; 76673 var w_z = []; 76674 76675 var t, _x, _y, _z, i; 76676 76677 var argLength = arguments.length; 76678 t = 0; 76679 76680 if (this._lookUpTableBezier.length === 0 || this._lutBezierDetail !== this._pInst._curveDetail) { 76681 this._lookUpTableBezier = []; 76682 this._lutBezierDetail = this._pInst._curveDetail; 76683 var step = 1 / this._lutBezierDetail; 76684 var start = 0; 76685 var end = 1; 76686 var j = 0; 76687 76688 while (start < 1) { 76689 t = parseFloat(start.toFixed(6)); 76690 this._lookUpTableBezier[j] = this._bezierCoefficients(t); 76691 76692 if (end.toFixed(6) === step.toFixed(6)) { 76693 t = parseFloat(end.toFixed(6)) + parseFloat(start.toFixed(6)); 76694 ++j; 76695 this._lookUpTableBezier[j] = this._bezierCoefficients(t); 76696 break; 76697 } 76698 76699 start += step; 76700 end -= step; 76701 ++j; 76702 } 76703 } 76704 76705 var LUTLength = this._lookUpTableBezier.length; 76706 76707 if (argLength === 6) { 76708 this.isBezier = true; 76709 w_x = [this.immediateMode._bezierVertex[0], arguments[0], arguments[2], arguments[4]]; 76710 w_y = [this.immediateMode._bezierVertex[1], arguments[1], arguments[3], arguments[5]]; 76711 76712 for (i = 0; i < LUTLength; i++) { 76713 _x = w_x[0] * this._lookUpTableBezier[i][0] + w_x[1] * this._lookUpTableBezier[i][1] + w_x[2] * this._lookUpTableBezier[i][2] + w_x[3] * this._lookUpTableBezier[i][3]; 76714 _y = w_y[0] * this._lookUpTableBezier[i][0] + w_y[1] * this._lookUpTableBezier[i][1] + w_y[2] * this._lookUpTableBezier[i][2] + w_y[3] * this._lookUpTableBezier[i][3]; 76715 this.vertex(_x, _y); 76716 } 76717 76718 this.immediateMode._bezierVertex[0] = arguments[4]; 76719 this.immediateMode._bezierVertex[1] = arguments[5]; 76720 } else if (argLength === 9) { 76721 this.isBezier = true; 76722 w_x = [this.immediateMode._bezierVertex[0], arguments[0], arguments[3], arguments[6]]; 76723 w_y = [this.immediateMode._bezierVertex[1], arguments[1], arguments[4], arguments[7]]; 76724 w_z = [this.immediateMode._bezierVertex[2], arguments[2], arguments[5], arguments[8]]; 76725 76726 for (i = 0; i < LUTLength; i++) { 76727 _x = w_x[0] * this._lookUpTableBezier[i][0] + w_x[1] * this._lookUpTableBezier[i][1] + w_x[2] * this._lookUpTableBezier[i][2] + w_x[3] * this._lookUpTableBezier[i][3]; 76728 _y = w_y[0] * this._lookUpTableBezier[i][0] + w_y[1] * this._lookUpTableBezier[i][1] + w_y[2] * this._lookUpTableBezier[i][2] + w_y[3] * this._lookUpTableBezier[i][3]; 76729 _z = w_z[0] * this._lookUpTableBezier[i][0] + w_z[1] * this._lookUpTableBezier[i][1] + w_z[2] * this._lookUpTableBezier[i][2] + w_z[3] * this._lookUpTableBezier[i][3]; 76730 this.vertex(_x, _y, _z); 76731 } 76732 76733 this.immediateMode._bezierVertex[0] = arguments[6]; 76734 this.immediateMode._bezierVertex[1] = arguments[7]; 76735 this.immediateMode._bezierVertex[2] = arguments[8]; 76736 } 76737 } 76738 }; 76739 76740 p5.RendererGL.prototype.quadraticVertex = function () { 76741 if (this.immediateMode._quadraticVertex.length === 0) { 76742 throw Error('vertex() must be used once before calling quadraticVertex()'); 76743 } else { 76744 var w_x = []; 76745 var w_y = []; 76746 var w_z = []; 76747 76748 var t, _x, _y, _z, i; 76749 76750 var argLength = arguments.length; 76751 t = 0; 76752 76753 if (this._lookUpTableQuadratic.length === 0 || this._lutQuadraticDetail !== this._pInst._curveDetail) { 76754 this._lookUpTableQuadratic = []; 76755 this._lutQuadraticDetail = this._pInst._curveDetail; 76756 var step = 1 / this._lutQuadraticDetail; 76757 var start = 0; 76758 var end = 1; 76759 var j = 0; 76760 76761 while (start < 1) { 76762 t = parseFloat(start.toFixed(6)); 76763 this._lookUpTableQuadratic[j] = this._quadraticCoefficients(t); 76764 76765 if (end.toFixed(6) === step.toFixed(6)) { 76766 t = parseFloat(end.toFixed(6)) + parseFloat(start.toFixed(6)); 76767 ++j; 76768 this._lookUpTableQuadratic[j] = this._quadraticCoefficients(t); 76769 break; 76770 } 76771 76772 start += step; 76773 end -= step; 76774 ++j; 76775 } 76776 } 76777 76778 var LUTLength = this._lookUpTableQuadratic.length; 76779 76780 if (argLength === 4) { 76781 this.isQuadratic = true; 76782 w_x = [this.immediateMode._quadraticVertex[0], arguments[0], arguments[2]]; 76783 w_y = [this.immediateMode._quadraticVertex[1], arguments[1], arguments[3]]; 76784 76785 for (i = 0; i < LUTLength; i++) { 76786 _x = w_x[0] * this._lookUpTableQuadratic[i][0] + w_x[1] * this._lookUpTableQuadratic[i][1] + w_x[2] * this._lookUpTableQuadratic[i][2]; 76787 _y = w_y[0] * this._lookUpTableQuadratic[i][0] + w_y[1] * this._lookUpTableQuadratic[i][1] + w_y[2] * this._lookUpTableQuadratic[i][2]; 76788 this.vertex(_x, _y); 76789 } 76790 76791 this.immediateMode._quadraticVertex[0] = arguments[2]; 76792 this.immediateMode._quadraticVertex[1] = arguments[3]; 76793 } else if (argLength === 6) { 76794 this.isQuadratic = true; 76795 w_x = [this.immediateMode._quadraticVertex[0], arguments[0], arguments[3]]; 76796 w_y = [this.immediateMode._quadraticVertex[1], arguments[1], arguments[4]]; 76797 w_z = [this.immediateMode._quadraticVertex[2], arguments[2], arguments[5]]; 76798 76799 for (i = 0; i < LUTLength; i++) { 76800 _x = w_x[0] * this._lookUpTableQuadratic[i][0] + w_x[1] * this._lookUpTableQuadratic[i][1] + w_x[2] * this._lookUpTableQuadratic[i][2]; 76801 _y = w_y[0] * this._lookUpTableQuadratic[i][0] + w_y[1] * this._lookUpTableQuadratic[i][1] + w_y[2] * this._lookUpTableQuadratic[i][2]; 76802 _z = w_z[0] * this._lookUpTableQuadratic[i][0] + w_z[1] * this._lookUpTableQuadratic[i][1] + w_z[2] * this._lookUpTableQuadratic[i][2]; 76803 this.vertex(_x, _y, _z); 76804 } 76805 76806 this.immediateMode._quadraticVertex[0] = arguments[3]; 76807 this.immediateMode._quadraticVertex[1] = arguments[4]; 76808 this.immediateMode._quadraticVertex[2] = arguments[5]; 76809 } 76810 } 76811 }; 76812 76813 p5.RendererGL.prototype.curveVertex = function () { 76814 var w_x = [];
76815 var w_y = []; 76816 var w_z = []; 76817 76818 var t, _x, _y, _z, i; 76819 76820 t = 0; 76821 var argLength = arguments.length; 76822 76823 if (this._lookUpTableBezier.length === 0 || this._lutBezierDetail !== this._pInst._curveDetail) { 76824 this._lookUpTableBezier = []; 76825 this._lutBezierDetail = this._pInst._curveDetail; 76826 var step = 1 / this._lutBezierDetail; 76827 var start = 0; 76828 var end = 1; 76829 var j = 0; 76830 76831 while (start < 1) { 76832 t = parseFloat(start.toFixed(6)); 76833 this._lookUpTableBezier[j] = this._bezierCoefficients(t); 76834 76835 if (end.toFixed(6) === step.toFixed(6)) { 76836 t = parseFloat(end.toFixed(6)) + parseFloat(start.toFixed(6)); 76837 ++j; 76838 this._lookUpTableBezier[j] = this._bezierCoefficients(t); 76839 break; 76840 } 76841 76842 start += step; 76843 end -= step; 76844 ++j; 76845 } 76846 } 76847 76848 var LUTLength = this._lookUpTableBezier.length; 76849 76850 if (argLength === 2) { 76851 this.immediateMode._curveVertex.push(arguments[0]); 76852 76853 this.immediateMode._curveVertex.push(arguments[1]); 76854 76855 if (this.immediateMode._curveVertex.length === 8) { 76856 this.isCurve = true; 76857 w_x = this._bezierToCatmull([this.immediateMode._curveVertex[0], this.immediateMode._curveVertex[2], this.immediateMode._curveVertex[4], this.immediateMode._curveVertex[6]]); 76858 w_y = this._bezierToCatmull([this.immediateMode._curveVertex[1], this.immediateMode._curveVertex[3], this.immediateMode._curveVertex[5], this.immediateMode._curveVertex[7]]); 76859 76860 for (i = 0; i < LUTLength; i++) { 76861 _x = w_x[0] * this._lookUpTableBezier[i][0] + w_x[1] * this._lookUpTableBezier[i][1] + w_x[2] * this._lookUpTableBezier[i][2] + w_x[3] * this._lookUpTableBezier[i][3]; 76862 _y = w_y[0] * this._lookUpTableBezier[i][0] + w_y[1] * this._lookUpTableBezier[i][1] + w_y[2] * this._lookUpTableBezier[i][2] + w_y[3] * this._lookUpTableBezier[i][3]; 76863 this.vertex(_x, _y); 76864 } 76865 76866 for (i = 0; i < argLength; i++) { 76867 this.immediateMode._curveVertex.shift(); 76868 } 76869 } 76870 } else if (argLength === 3) { 76871 this.immediateMode._curveVertex.push(arguments[0]); 76872 76873 this.immediateMode._curveVertex.push(arguments[1]); 76874 76875 this.immediateMode._curveVertex.push(arguments[2]); 76876 76877 if (this.immediateMode._curveVertex.length === 12) { 76878 this.isCurve = true; 76879 w_x = this._bezierToCatmull([this.immediateMode._curveVertex[0], this.immediateMode._curveVertex[3], this.immediateMode._curveVertex[6], this.immediateMode._curveVertex[9]]); 76880 w_y = this._bezierToCatmull([this.immediateMode._curveVertex[1], this.immediateMode._curveVertex[4], this.immediateMode._curveVertex[7], this.immediateMode._curveVertex[10]]); 76881 w_z = this._bezierToCatmull([this.immediateMode._curveVertex[2], this.immediateMode._curveVertex[5], this.immediateMode._curveVertex[8], this.immediateMode._curveVertex[11]]); 76882 76883 for (i = 0; i < LUTLength; i++) { 76884 _x = w_x[0] * this._lookUpTableBezier[i][0] + w_x[1] * this._lookUpTableBezier[i][1] + w_x[2] * this._lookUpTableBezier[i][2] + w_x[3] * this._lookUpTableBezier[i][3]; 76885 _y = w_y[0] * this._lookUpTableBezier[i][0] + w_y[1] * this._lookUpTableBezier[i][1] + w_y[2] * this._lookUpTableBezier[i][2] + w_y[3] * this._lookUpTableBezier[i][3]; 76886 _z = w_z[0] * this._lookUpTableBezier[i][0] + w_z[1] * this._lookUpTableBezier[i][1] + w_z[2] * this._lookUpTableBezier[i][2] + w_z[3] * this._lookUpTableBezier[i][3]; 76887 this.vertex(_x, _y, _z); 76888 } 76889 76890 for (i = 0; i < argLength; i++) { 76891 this.immediateMode._curveVertex.shift(); 76892 } 76893 } 76894 } 76895 }; 76896 76897 module.exports = p5; 76898 }, {
76899 "../core/constants": 18, 76900 "../core/main": 24, 76901 "./p5.Geometry": 70 76902 }], 76903 65: [function (_dereq_, module, exports) { 76904 /** 76905 * @module Lights, Camera 76906 * @submodule Interaction 76907 * @for p5 76908 * @requires core 76909 */ 76910 'use strict'; 76911 76912 var p5 = _dereq_('../core/main'); 76913 76914 var constants = _dereq_('../core/constants'); 76915 /** 76916 * Allows movement around a 3D sketch using a mouse or trackpad. Left-clicking 76917 * and dragging will rotate the camera position about the center of the sketch, 76918 * right-clicking and dragging will pan the camera position without rotation, 76919 * and using the mouse wheel (scrolling) will move the camera closer or further 76920 * from the center of the sketch. This function can be called with parameters 76921 * dictating sensitivity to mouse movement along the X and Y axes. Calling 76922 * this function without parameters is equivalent to calling orbitControl(1,1). 76923 * To reverse direction of movement in either axis, enter a negative number 76924 * for sensitivity. 76925 * @method orbitControl 76926 * @for p5 76927 * @param {Number} [sensitivityX] sensitivity to mouse movement along X axis 76928 * @param {Number} [sensitivityY] sensitivity to mouse movement along Y axis 76929 * @chainable 76930 * @example 76931 * <div> 76932 * <code> 76933 * function setup() { 76934 * createCanvas(100, 100, WEBGL); 76935 * normalMaterial(); 76936 * } 76937 * function draw() { 76938 * background(200); 76939 * orbitControl(); 76940 * rotateY(0.5); 76941 * box(30, 50); 76942 * } 76943 * </code> 76944 * </div> 76945 * 76946 * @alt 76947 * Camera orbits around a box when mouse is hold-clicked & then moved. 76948 */ 76949 // implementation based on three.js 'orbitControls': 76950 // https://github.com/mrdoob/three.js/blob/dev/examples/js/controls/OrbitControls.js 76951 76952 76953 p5.prototype.orbitControl = function (sensitivityX, sensitivityY) { 76954 this._assert3d('orbitControl'); 76955 76956 p5._validateParameters('orbitControl', arguments); // If the mouse is not in bounds of the canvas, disable all behaviors: 76957 76958 76959 var mouseInCanvas = this.mouseX < this.width && this.mouseX > 0 && this.mouseY < this.height && this.mouseY > 0; 76960 if (!mouseInCanvas) return; 76961 var cam = this._renderer._curCamera; 76962 76963 if (typeof sensitivityX === 'undefined') { 76964 sensitivityX = 1; 76965 } 76966 76967 if (typeof sensitivityY === 'undefined') { 76968 sensitivityY = sensitivityX; 76969 } // default right-mouse and mouse-wheel behaviors (context menu and scrolling, 76970 // respectively) are disabled here to allow use of those events for panning and 76971 // zooming 76972 // disable context menu for canvas element and add 'contextMenuDisabled' 76973 // flag to p5 instance 76974 76975 76976 if (this.contextMenuDisabled !== true) { 76977 this.canvas.oncontextmenu = function () { 76978 return false; 76979 }; 76980 76981 this._setProperty('contextMenuDisabled', true); 76982 } // disable default scrolling behavior on the canvas element and add 76983 // 'wheelDefaultDisabled' flag to p5 instance 76984 76985 76986 if (this.wheelDefaultDisabled !== true) { 76987 this.canvas.onwheel = function () { 76988 return false; 76989 }; 76990 76991 this._setProperty('wheelDefaultDisabled', true); 76992 } 76993 76994 var scaleFactor = this.height < this.width ? this.height : this.width; // ZOOM if there is a change in mouseWheelDelta 76995 76996 if (this._mouseWheelDeltaY !== this._pmouseWheelDeltaY) { 76997 // zoom according to direction of mouseWheelDeltaY rather than value 76998 if (this._mouseWheelDeltaY > 0) { 76999 this._renderer._curCamera._orbit(0, 0, 0.5 * scaleFactor); 77000 } else { 77001 this._renderer._curCamera._orbit(0, 0, -0.5 * scaleFactor); 77002 } 77003 } 77004 77005 if (this.mouseIsPressed) { 77006 // ORBIT BEHAVIOR 77007 if (this.mouseButton === this.LEFT) { 77008 var deltaTheta = -sensitivityX * (this.mouseX - this.pmouseX) / scaleFactor; 77009 var deltaPhi = sensitivityY * (this.mouseY - this.pmouseY) / scaleFactor; 77010 77011 this._renderer._curCamera._orbit(deltaTheta, deltaPhi, 0); 77012 } else if (this.mouseButton === this.RIGHT) { 77013 // PANNING BEHAVIOR along X/Z camera axes and restricted to X/Z plane 77014 // in world space 77015 var local = cam._getLocalAxes(); // normalize portions along X/Z axes 77016 77017 77018 var xmag = Math.sqrt(local.x[0] * local.x[0] + local.x[2] * local.x[2]); 77019 77020 if (xmag !== 0) { 77021 local.x[0] /= xmag; 77022 local.x[2] /= xmag; 77023 } // normalize portions along X/Z axes 77024 77025 77026 var ymag = Math.sqrt(local.y[0] * local.y[0] + local.y[2] * local.y[2]); 77027 77028 if (ymag !== 0) { 77029 local.y[0] /= ymag; 77030 local.y[2] /= ymag; 77031 } // move along those vectors by amount controlled by mouseX, pmouseY 77032 77033
77034 var dx = -1 * sensitivityX * (this.mouseX - this.pmouseX); 77035 var dz = -1 * sensitivityY * (this.mouseY - this.pmouseY); // restrict movement to XZ plane in world space 77036 77037 cam.setPosition(cam.eyeX + dx * local.x[0] + dz * local.z[0], cam.eyeY, cam.eyeZ + dx * local.x[2] + dz * local.z[2]); 77038 } 77039 } 77040 77041 return this; 77042 }; 77043 /** 77044 * debugMode() helps visualize 3D space by adding a grid to indicate where the 77045 * âgroundâ is in a sketch and an axes icon which indicates the +X, +Y, and +Z 77046 * directions. This function can be called without parameters to create a 77047 * default grid and axes icon, or it can be called according to the examples 77048 * above to customize the size and position of the grid and/or axes icon. The 77049 * grid is drawn using the most recently set stroke color and weight. To 77050 * specify these parameters, add a call to stroke() and strokeWeight() 77051 * just before the end of the draw() loop. 77052 * 77053 * By default, the grid will run through the origin (0,0,0) of the sketch 77054 * along the XZ plane 77055 * and the axes icon will be offset from the origin. Both the grid and axes 77056 * icon will be sized according to the current canvas size. Note that because the 77057 * grid runs parallel to the default camera view, it is often helpful to use 77058 * debugMode along with orbitControl to allow full view of the grid. 77059 * @method debugMode 77060 * @example 77061 * <div> 77062 * <code> 77063 * function setup() { 77064 * createCanvas(100, 100, WEBGL); 77065 * camera(0, -30, 100, 0, 0, 0, 0, 1, 0); 77066 * normalMaterial(); 77067 * debugMode(); 77068 * } 77069 * 77070 * function draw() { 77071 * background(200); 77072 * orbitControl(); 77073 * box(15, 30); 77074 * // Press the spacebar to turn debugMode off! 77075 * if (keyIsDown(32)) { 77076 * noDebugMode(); 77077 * } 77078 * } 77079 * </code> 77080 * </div> 77081 * @alt 77082 * a 3D box is centered on a grid in a 3D sketch. an icon 77083 * indicates the direction of each axis: a red line points +X, 77084 * a green line +Y, and a blue line +Z. the grid and icon disappear when the 77085 * spacebar is pressed. 77086 * 77087 * @example 77088 * <div> 77089 * <code> 77090 * function setup() { 77091 * createCanvas(100, 100, WEBGL); 77092 * camera(0, -30, 100, 0, 0, 0, 0, 1, 0); 77093 * normalMaterial(); 77094 * debugMode(GRID); 77095 * } 77096 * 77097 * function draw() { 77098 * background(200); 77099 * orbitControl(); 77100 * box(15, 30); 77101 * } 77102 * </code> 77103 * </div> 77104 * @alt 77105 * a 3D box is centered on a grid in a 3D sketch. 77106 * 77107 * @example 77108 * <div> 77109 * <code> 77110 * function setup() { 77111 * createCanvas(100, 100, WEBGL); 77112 * camera(0, -30, 100, 0, 0, 0, 0, 1, 0); 77113 * normalMaterial(); 77114 * debugMode(AXES); 77115 * } 77116 * 77117 * function draw() { 77118 * background(200); 77119 * orbitControl(); 77120 * box(15, 30); 77121 * } 77122 * </code> 77123 * </div> 77124 * @alt 77125 * a 3D box is centered in a 3D sketch. an icon 77126 * indicates the direction of each axis: a red line points +X, 77127 * a green line +Y, and a blue line +Z. 77128 * 77129 * @example 77130 * <div> 77131 * <code> 77132 * function setup() { 77133 * createCanvas(100, 100, WEBGL); 77134 * camera(0, -30, 100, 0, 0, 0, 0, 1, 0); 77135 * normalMaterial(); 77136 * debugMode(GRID, 100, 10, 0, 0, 0); 77137 * } 77138 * 77139 * function draw() { 77140 * background(200); 77141 * orbitControl(); 77142 * box(15, 30); 77143 * } 77144 * </code> 77145 * </div> 77146 * @alt 77147 * a 3D box is centered on a grid in a 3D sketch 77148 * 77149 * @example 77150 * <div> 77151 * <code> 77152 * function setup() { 77153 * createCanvas(100, 100, WEBGL); 77154 * camera(0, -30, 100, 0, 0, 0, 0, 1, 0); 77155 * normalMaterial(); 77156 * debugMode(100, 10, 0, 0, 0, 20, 0, -40, 0); 77157 * } 77158 * 77159 * function draw() { 77160 * noStroke(); 77161 * background(200); 77162 * orbitControl(); 77163 * box(15, 30); 77164 * // set the stroke color and weight for the grid! 77165 * stroke(255, 0, 150); 77166 * strokeWeight(0.8); 77167 * } 77168 * </code> 77169 * </div> 77170 * @alt 77171 * a 3D box is centered on a grid in a 3D sketch. an icon 77172 * indicates the direction of each axis: a red line points +X, 77173 * a green line +Y, and a blue line +Z. 77174 */ 77175 77176 /** 77177 * @method debugMode 77178 * @param {Constant} mode either GRID or AXES 77179 */ 77180 77181 /** 77182 * @method debugMode 77183 * @param {Constant} mode 77184 * @param {Number} [gridSize] size of one side of the grid 77185 * @param {Number} [gridDivisions] number of divisions in the grid 77186 * @param {Number} [xOff] X axis offset from origin (0,0,0) 77187 * @param {Number} [yOff] Y axis offset from origin (0,0,0) 77188 * @param {Number} [zOff] Z axis offset from origin (0,0,0) 77189 */ 77190 77191 /** 77192 * @method debugMode 77193 * @param {Constant} mode 77194 * @param {Number} [axesSize] size of axes icon 77195 * @param {Number} [xOff] 77196 * @param {Number} [yOff] 77197 * @param {Number} [zOff] 77198 */ 77199 77200 /** 77201 * @method debugMode 77202 * @param {Number} [gridSize] 77203 * @param {Number} [gridDivisions] 77204 * @param {Number} [gridXOff] 77205 * @param {Number} [gridYOff] 77206 * @param {Number} [gridZOff] 77207 * @param {Number} [axesSize] 77208 * @param {Number} [axesXOff] 77209 * @param {Number} [axesYOff] 77210 * @param {Number} [axesZOff] 77211 */ 77212 77213 77214 p5.prototype.debugMode = function () { 77215 this._assert3d('debugMode'); 77216 77217 p5._validateParameters('debugMode', arguments); // start by removing existing 'post' registered debug methods 77218 77219 77220 for (var i = this._registeredMethods.post.length - 1; i >= 0; i--) { 77221 // test for equality... 77222 if (this._registeredMethods.post[i].toString() === this._grid().toString() || this._registeredMethods.post[i].toString() === this._axesIcon().toString()) { 77223 this._registeredMethods.post.splice(i, 1); 77224 } 77225 } // then add new debugMode functions according to the argument list 77226 77227 77228 if (arguments[0] === constants.GRID) { 77229 this.registerMethod('post', this._grid.call(this, arguments[1], arguments[2], arguments[3], arguments[4], arguments[5])); 77230 } else if (arguments[0] === constants.AXES) { 77231 this.registerMethod('post', this._axesIcon.call(this, arguments[1], arguments[2], arguments[3], arguments[4])); 77232 } else { 77233 this.registerMethod('post', this._grid.call(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4])); 77234 this.registerMethod('post', this._axesIcon.call(this, arguments[5], arguments[6], arguments[7], arguments[8])); 77235 } 77236 }; 77237 /** 77238 * Turns off debugMode() in a 3D sketch. 77239 * @method noDebugMode 77240 * @example 77241 * <div> 77242 * <code> 77243 * function setup() { 77244 * createCanvas(100, 100, WEBGL); 77245 * camera(0, -30, 100, 0, 0, 0, 0, 1, 0); 77246 * normalMaterial(); 77247 * debugMode(); 77248 * } 77249 * 77250 * function draw() { 77251 * background(200); 77252 * orbitControl(); 77253 * box(15, 30); 77254 * // Press the spacebar to turn debugMode off! 77255 * if (keyIsDown(32)) { 77256 * noDebugMode(); 77257 * } 77258 * } 77259 * </code> 77260 * </div> 77261 * @alt 77262 * a 3D box is centered on a grid in a 3D sketch. an icon 77263 * indicates the direction of each axis: a red line points +X, 77264 * a green line +Y, and a blue line +Z. the grid and icon disappear when the 77265 * spacebar is pressed. 77266 */ 77267 77268 77269 p5.prototype.noDebugMode = function () { 77270 this._assert3d('noDebugMode'); // start by removing existing 'post' registered debug methods 77271 77272 77273 for (var i = this._registeredMethods.post.length - 1; i >= 0; i--) { 77274 // test for equality... 77275 if (this._registeredMethods.post[i].toString() === this._grid().toString() || this._registeredMethods.post[i].toString() === this._axesIcon().toString()) { 77276 this._registeredMethods.post.splice(i, 1); 77277 } 77278 } 77279 }; 77280 /** 77281 * For use with debugMode 77282 * @private 77283 * @method _grid 77284 * @param {Number}
77284 [size] size of grid sides 77285 * @param {Number} [div] number of grid divisions 77286 * @param {Number} [xOff] offset of grid center from origin in X axis 77287 * @param {Number} [yOff] offset of grid center from origin in Y axis 77288 * @param {Number} [zOff] offset of grid center from origin in Z axis 77289 */ 77290 77291 77292 p5.prototype._grid = function (size, numDivs, xOff, yOff, zOff) { 77293 if (typeof size === 'undefined') { 77294 size = this.width / 2; 77295 } 77296 77297 if (typeof numDivs === 'undefined') { 77298 // ensure at least 2 divisions 77299 numDivs = Math.round(size / 30) < 4 ? 4 : Math.round(size / 30); 77300 } 77301 77302 if (typeof xOff === 'undefined') { 77303 xOff = 0; 77304 } 77305 77306 if (typeof yOff === 'undefined') { 77307 yOff = 0; 77308 } 77309 77310 if (typeof zOff === 'undefined') { 77311 zOff = 0; 77312 } 77313 77314 var spacing = size / numDivs; 77315 var halfSize = size / 2; 77316 return function () { 77317 this.push(); 77318 this.stroke(this._renderer.curStrokeColor[0] * 255, this._renderer.curStrokeColor[1] * 255, this._renderer.curStrokeColor[2] * 255); 77319 77320 this._renderer.uMVMatrix.set(this._renderer._curCamera.cameraMatrix.mat4[0], this._renderer._curCamera.cameraMatrix.mat4[1], this._renderer._curCamera.cameraMatrix.mat4[2], this._renderer._curCamera.cameraMatrix.mat4[3], this._renderer._curCamera.cameraMatrix.mat4[4], this._renderer._curCamera.cameraMatrix.mat4[5], this._renderer._curCamera.cameraMatrix.mat4[6], this._renderer._curCamera.cameraMatrix.mat4[7], this._renderer._curCamera.cameraMatrix.mat4[8], this._renderer._curCamera.cameraMatrix.mat4[9], this._renderer._curCamera.cameraMatrix.mat4[10], this._renderer._curCamera.cameraMatrix.mat4[11], this._renderer._curCamera.cameraMatrix.mat4[12], this._renderer._curCamera.cameraMatrix.mat4[13], this._renderer._curCamera.cameraMatrix.mat4[14], this._renderer._curCamera.cameraMatrix.mat4[15]); // Lines along X axis 77321 77322 77323 for (var q = 0; q <= numDivs; q++) { 77324 this.beginShape(this.LINES); 77325 this.vertex(-halfSize + xOff, yOff, q * spacing - halfSize + zOff); 77326 this.vertex(+halfSize + xOff, yOff, q * spacing - halfSize + zOff); 77327 this.endShape(); 77328 } // Lines along Z axis 77329 77330 77331 for (var i = 0; i <= numDivs; i++) { 77332 this.beginShape(this.LINES); 77333 this.vertex(i * spacing - halfSize + xOff, yOff, -halfSize + zOff); 77334 this.vertex(i * spacing - halfSize + xOff, yOff, +halfSize + zOff); 77335 this.endShape(); 77336 } 77337 77338 this.pop(); 77339 }; 77340 }; 77341 /** 77342 * For use with debugMode 77343 * @private 77344 * @method _axesIcon 77345 * @param {Number} [size] size of axes icon lines 77346 * @param {Number} [xOff] offset of icon from origin in X axis 77347 * @param {Number} [yOff] offset of icon from origin in Y axis 77348 * @param {Number} [zOff] offset of icon from origin in Z axis 77349 */ 77350 77351 77352 p5.prototype._axesIcon = function (size, xOff, yOff, zOff) { 77353 if (typeof size === 'undefined') { 77354 size = this.width / 20 > 40 ? this.width / 20 : 40; 77355 } 77356 77357 if (typeof xOff === 'undefined') { 77358 xOff = -this.width / 4; 77359 } 77360 77361 if (typeof yOff === 'undefined') { 77362 yOff = xOff; 77363 } 77364 77365 if (typeof zOff === 'undefined') { 77366 zOff = xOff; 77367 } 77368 77369 return function () { 77370 this.push(); 77371 77372 this._renderer.uMVMatrix.set(this._renderer._curCamera.cameraMatrix.mat4[0], this._renderer._curCamera.cameraMatrix.mat4[1], this._renderer._curCamera.cameraMatrix.mat4[2], this._renderer._curCamera.cameraMatrix.mat4[3], this._renderer._curCamera.cameraMatrix.mat4[4], this._renderer._curCamera.cameraMatrix.mat4[5], this._renderer._curCamera.cameraMatrix.mat4[6], this._renderer._curCamera.cameraMatrix.mat4[7], this._renderer._curCamera.cameraMatrix.mat4[8], this._renderer._curCamera.cameraMatrix.mat4[9], this._renderer._curCamera.cameraMatrix.mat4[10], this._renderer._curCamera.cameraMatrix.mat4[11], this._renderer._curCamera.cameraMatrix.mat4[12], this._renderer._curCamera.cameraMatrix.mat4[13], this._renderer._curCamera.cameraMatrix.mat4[14], this._renderer._curCamera.cameraMatrix.mat4[15]); // X axis 77373 77374 77375 this.strokeWeight(2); 77376 this.stroke(255, 0, 0); 77377 this.beginShape(this.LINES); 77378 this.vertex(xOff, yOff, zOff); 77379 this.vertex(xOff + size, yOff, zOff); 77380 this.endShape(); // Y axis 77381 77382 this.stroke(0, 255, 0); 77383 this.beginShape(this.LINES); 77384 this.vertex(xOff, yOff, zOff); 77385 this.vertex(xOff, yOff + size, zOff); 77386 this.endShape(); // Z axis 77387 77388 this.stroke(0, 0, 255); 77389 this.beginShape(this.LINES); 77390 this.vertex(xOff, yOff, zOff); 77391 this.vertex(xOff, yOff, zOff + size); 77392 this.endShape(); 77393 this.pop(); 77394 }; 77395 }; 77396 77397 module.exports = p5; 77398 }, {
77399 "../core/constants": 18, 77400 "../core/main": 24 77401 }], 77402 66: [function (_dereq_, module, exports) { 77403 /** 77404 * @module Lights, Camera 77405 * @submodule Lights 77406 * @for p5 77407 * @requires core 77408 */ 77409 'use strict'; 77410 77411 var p5 = _dereq_('../core/main'); 77412 /** 77413 * Creates an ambient light with a color 77414 * 77415 * @method ambientLight 77416 * @param {Number} v1 red or hue value relative to 77417 * the current color range 77418 * @param {Number} v2 green or saturation value 77419 * relative to the current color range 77420 * @param {Number} v3 blue or brightness value 77421 * relative to the current color range 77422 * @param {Number} [alpha] the alpha value 77423 * @chainable 77424 * 77425 * @example 77426 * <div> 77427 * <code> 77428 * function setup() { 77429 * createCanvas(100, 100, WEBGL); 77430 * } 77431 * function draw() { 77432 * background(0); 77433 * ambientLight(150); 77434 * ambientMaterial(250); 77435 * noStroke(); 77436 * sphere(25); 77437 * } 77438 * </code> 77439 * </div> 77440 * 77441 * @alt 77442 * evenly distributed light across a sphere 77443 * 77444 */ 77445 77446 /** 77447 * @method ambientLight 77448 * @param {String} value a color string 77449 * @chainable 77450 */ 77451 77452 /** 77453 * @method ambientLight 77454 * @param {Number} gray a gray value 77455 * @param {Number} [alpha] 77456 * @chainable 77457 */ 77458 77459 /** 77460 * @method ambientLight 77461 * @param {Number[]} values an array containing the red,green,blue & 77462 * and alpha components of the color 77463 * @chainable 77464 */ 77465 77466 /** 77467 * @method ambientLight 77468 * @param {p5.Color} color the ambient light color 77469 * @chainable 77470 */ 77471 77472 77473 p5.prototype.ambientLight = function (v1, v2, v3, a) { 77474 this._assert3d('ambientLight'); 77475 77476 p5._validateParameters('ambientLight', arguments); 77477 77478 var color = this.color.apply(this, arguments); 77479 77480 var shader = this._renderer._useLightShader(); //@todo this is a bit icky. array uniforms have 77481 //to be multiples of the type 3(rgb) in this case. 77482 //a preallocated Float32Array(24) that we copy into 77483 //would be better 77484 77485 77486 shader.setUniform('uUseLighting', true); //in case there's no material color for the geometry 77487 77488 shader.setUniform('uMaterialColor', this._renderer.curFillColor); 77489 77490 this._renderer.ambientLightColors.push(color._array[0], color._array[1], color._array[2]); 77491 77492 shader.setUniform('uAmbientColor', this._renderer.ambientLightColors); 77493 shader.setUniform('uAmbientLightCount', this._renderer.ambientLightColors.length / 3); 77494 return this; 77495 }; 77496 /** 77497 * Creates a directional light with a color and a direction 77498 * @method directionalLight 77499 * @param {Number} v1 red or hue value (depending on the current 77500 * color mode), 77501 * @param {Number} v2 green or saturation value 77502 * @param {Number} v3 blue or brightness value 77503 * @param {p5.Vector} position the direction of the light 77504 * @chainable 77505 * @example 77506 * <div> 77507 * <code> 77508 * function setup() { 77509 * createCanvas(100, 100, WEBGL); 77510 * } 77511 * function draw() { 77512 * background(0); 77513 * //move your mouse to change light direction 77514 * let dirX = (mouseX / width - 0.5) * 2; 77515 * let dirY = (mouseY / height - 0.5) * 2; 77516 * directionalLight(250, 250, 250, -dirX, -dirY, 0.25); 77517 * ambientMaterial(250); 77518 * noStroke(); 77519 * sphere(25); 77520 * } 77521 * </code> 77522 * </div> 77523 * 77524 * @alt 77525 * light source on canvas changeable with mouse position 77526 * 77527 */ 77528 77529 /** 77530 * @method directionalLight 77531 * @param {Number[]|String|p5.Color} color color Array, CSS color string, 77532 * or <a href="#/p5.Color">p5.Color</a> value 77533 * @param {Number} x x axis direction 77534 * @param {Number} y y axis direction 77535 * @param {Number} z z axis direction 77536 * @chainable 77537 */ 77538 77539 /** 77540 * @method directionalLight 77541 * @param {Number[]|String|p5.Color} color 77542 * @param {p5.Vector} position 77543 * @chainable 77544 */ 77545 77546 /** 77547 * @method directionalLight 77548 * @param {Number} v1 77549 * @param {Number} v2 77550 * @param {Number} v3 77551 * @param {Number} x 77552 * @param {Number} y 77553 * @param {Number} z 77554 * @chainable 77555 */ 77556 77557 77558 p5.prototype.directionalLight = function (v1, v2, v3, x, y, z) { 77559 this._assert3d('directionalLight'); 77560 77561 p5._validateParameters('directionalLight', arguments); 77562 77563 var shader = this._renderer._useLightShader(); //@TODO: check parameters number 77564 77565 77566 var color; 77567 77568 if (v1 instanceof p5.Color) { 77569 color = v1; 77570 } else { 77571 color = this.color(v1, v2, v3); 77572 } 77573 77574 var _x, _y, _z; 77575 77576 var v = arguments[arguments.length - 1]; 77577 77578 if (typeof v === 'number') { 77579 _x = arguments[arguments.length - 3]; 77580 _y = arguments[arguments.length - 2]; 77581 _z = arguments[arguments.length - 1]; 77582 } else { 77583 _x = v.x; 77584 _y = v.y; 77585 _z = v.z; 77586 } 77587 77588 shader.setUniform('uUseLighting', true); //in case there's no material color for the geometry 77589 77590 shader.setUniform('uMaterialColor', this._renderer.curFillColor); // normalize direction 77591 77592 var l = Math.sqrt(_x * _x + _y * _y + _z * _z); 77593 77594 this._renderer.directionalLightDirections.push(_x / l, _y / l, _z / l); 77595 77596 shader.setUniform('uLightingDirection', this._renderer.directionalLightDirections); 77597 77598 this._renderer.directionalLightColors.push(color._array[0], color._array[1], color._array[2]); 77599 77600 shader.setUniform('uDirectionalColor', this._renderer.directionalLightColors); 77601 shader.setUniform('uDirectionalLightCount', this._renderer.directionalLightColors.length / 3); 77602 return this; 77603 }; 77604 /** 77605 * Creates a point light with a color and a light position 77606 * @method pointLight 77607 * @param {Number} v1 red or hue value (depending on the current 77608 * color mode), 77609 * @param {Number} v2 green or saturation value 77610 * @param {Number} v3 blue or brightness value 77611 * @param {Number} x x axis position 77612 * @param {Number} y y axis position 77613 * @param {Number} z z axis position 77614 * @chainable 77615 * @example 77616 * <div> 77617 * <code> 77618 * function setup() { 77619 * createCanvas(100, 100, WEBGL); 77620 * } 77621 * function draw() { 77622 * background(0); 77623 * //move your mouse to change light position 77624 * let locX = mouseX - width / 2;
77625 * let locY = mouseY - height / 2; 77626 * // to set the light position, 77627 * // think of the world's coordinate as: 77628 * // -width/2,-height/2 -------- width/2,-height/2 77629 * // | | 77630 * // | 0,0 | 77631 * // | | 77632 * // -width/2,height/2--------width/2,height/2 77633 * pointLight(250, 250, 250, locX, locY, 50); 77634 * ambientMaterial(250); 77635 * noStroke(); 77636 * sphere(25); 77637 * } 77638 * </code> 77639 * </div> 77640 * 77641 * @alt 77642 * spot light on canvas changes position with mouse 77643 * 77644 */ 77645 77646 /** 77647 * @method pointLight 77648 * @param {Number} v1 77649 * @param {Number} v2 77650 * @param {Number} v3 77651 * @param {p5.Vector} position the position of the light 77652 * @chainable 77653 */ 77654 77655 /** 77656 * @method pointLight 77657 * @param {Number[]|String|p5.Color} color color Array, CSS color string, 77658 * or <a href="#/p5.Color">p5.Color</a> value 77659 * @param {Number} x 77660 * @param {Number} y 77661 * @param {Number} z 77662 * @chainable 77663 */ 77664 77665 /** 77666 * @method pointLight 77667 * @param {Number[]|String|p5.Color} color 77668 * @param {p5.Vector} position 77669 * @chainable 77670 */ 77671 77672 77673 p5.prototype.pointLight = function (v1, v2, v3, x, y, z) { 77674 this._assert3d('pointLight'); 77675 77676 p5._validateParameters('pointLight', arguments); //@TODO: check parameters number 77677 77678 77679 var color; 77680 77681 if (v1 instanceof p5.Color) { 77682 color = v1; 77683 } else { 77684 color = this.color(v1, v2, v3); 77685 } 77686 77687 var _x, _y, _z; 77688 77689 var v = arguments[arguments.length - 1]; 77690 77691 if (typeof v === 'number') { 77692 _x = arguments[arguments.length - 3]; 77693 _y = arguments[arguments.length - 2]; 77694 _z = arguments[arguments.length - 1]; 77695 } else { 77696 _x = v.x; 77697 _y = v.y; 77698 _z = v.z; 77699 } 77700 77701 var shader = this._renderer._useLightShader(); 77702 77703 shader.setUniform('uUseLighting', true); //in case there's no material color for the geometry 77704 77705 shader.setUniform('uMaterialColor', this._renderer.curFillColor); 77706 77707 this._renderer.pointLightPositions.push(_x, _y, _z); 77708 77709 shader.setUniform('uPointLightLocation', this._renderer.pointLightPositions); 77710 77711 this._renderer.pointLightColors.push(color._array[0], color._array[1], color._array[2]); 77712 77713 shader.setUniform('uPointLightColor', this._renderer.pointLightColors); 77714 shader.setUniform('uPointLightCount', this._renderer.pointLightColors.length / 3); 77715 return this; 77716 }; 77717 77718 module.exports = p5; 77719 }, {
77720 "../core/main": 24 77721 }], 77722 67: [function (_dereq_, module, exports) { 77723 /** 77724 * @module Shape 77725 * @submodule 3D Models 77726 * @for p5 77727 * @requires core 77728 * @requires p5.Geometry 77729 */ 77730 'use strict'; 77731 77732 var p5 = _dereq_('../core/main'); 77733 77734 _dereq_('./p5.Geometry'); 77735 /** 77736 * Load a 3d model from an OBJ file. 77737 * <br><br> 77738 * One of the limitations of the OBJ format is that it doesn't have a built-in 77739 * sense of scale. This means that models exported from different programs might 77740 * be very different sizes. If your model isn't displaying, try calling 77741 * <a href="#/p5/loadModel">loadModel()</a> with the normalized parameter set to true. This will resize the 77742 * model to a scale appropriate for p5. You can also make additional changes to 77743 * the final size of your model with the <a href="#/p5/scale">scale()</a> function. 77744 * 77745 * @method loadModel 77746 * @param {String} path Path of the model to be loaded 77747 * @param {Boolean} normalize If true, scale the model to a 77748 * standardized size when loading 77749 * @param {function(p5.Geometry)} [successCallback] Function to be called 77750 * once the model is loaded. Will be passed 77751 * the 3D model object. 77752 * @param {function(Event)} [failureCallback] called with event error if 77753 * the image fails to load. 77754 * @return {p5.Geometry} the <a href="#/p5.Geometry">p5.Geometry</a> object 77755 * 77756 * @example 77757 * <div> 77758 * <code> 77759 * //draw a spinning octahedron 77760 * let octahedron; 77761 * 77762 * function preload() { 77763 * octahedron = loadModel('assets/octahedron.obj'); 77764 * } 77765 * 77766 * function setup() { 77767 * createCanvas(100, 100, WEBGL); 77768 * } 77769 * 77770 * function draw() { 77771 * background(200); 77772 * rotateX(frameCount * 0.01); 77773 * rotateY(frameCount * 0.01); 77774 * model(octahedron); 77775 * } 77776 * </code> 77777 * </div> 77778 * 77779 * @alt 77780 * Vertically rotating 3-d octahedron. 77781 * 77782 * @example 77783 * <div> 77784 * <code> 77785 * //draw a spinning teapot 77786 * let teapot; 77787 * 77788 * function preload() { 77789 * // Load model with normalise parameter set to true 77790 * teapot = loadModel('assets/teapot.obj', true); 77791 * } 77792 * 77793 * function setup() { 77794 * createCanvas(100, 100, WEBGL); 77795 * } 77796 * 77797 * function draw() { 77798 * background(200); 77799 * scale(0.4); // Scaled to make model fit into canvas 77800 * rotateX(frameCount * 0.01); 77801 * rotateY(frameCount * 0.01); 77802 * normalMaterial(); // For effect 77803 * model(teapot); 77804 * } 77805 * </code> 77806 * </div> 77807 * 77808 * @alt 77809 * Vertically rotating 3-d teapot with red, green and blue gradient. 77810 */ 77811 77812 /** 77813 * @method loadModel 77814 * @param {String} path 77815 * @param {function(p5.Geometry)} [successCallback] 77816 * @param {function(Event)} [failureCallback] 77817 * @return {p5.Geometry} the <a href="#/p5.Geometry">p5.Geometry</a> object 77818 */ 77819 77820 77821 p5.prototype.loadModel = function (path) { 77822 p5._validateParameters('loadModel', arguments); 77823 77824 var normalize; 77825 var successCallback; 77826 var failureCallback; 77827 77828 if (typeof arguments[1] === 'boolean') { 77829 normalize = arguments[1]; 77830 successCallback = arguments[2]; 77831 failureCallback = arguments[3]; 77832 } else { 77833 normalize = false; 77834 successCallback = arguments[1]; 77835 failureCallback = arguments[2]; 77836 } 77837 77838 var model = new p5.Geometry(); 77839 model.gid = path + '|' + normalize; 77840 var self = this; 77841 this.loadStrings(path, function (strings) { 77842 parseObj(model, strings); 77843 77844 if (normalize) { 77845 model.normalize(); 77846 } 77847 77848 self._decrementPreload(); 77849 77850 if (typeof successCallback === 'function') { 77851 successCallback(model); 77852 } 77853 }.bind(this), failureCallback); 77854 return model; 77855 }; 77856 /** 77857 * Parse OBJ lines into model. For reference, this is what a simple model of a 77858 * square might look like: 77859 * 77860 * v -0.5 -0.5 0.5 77861 * v -0.5 -0.5 -0.5 77862 * v -0.5 0.5 -0.5 77863 * v -0.5 0.5 0.5 77864 * 77865 * f 4 3 2 1 77866 */ 77867 77868 77869 function parseObj(model, lines) { 77870 // OBJ allows a face to specify an index for a vertex (in the above example), 77871 // but it also allows you to specify a custom combination of vertex, UV 77872 // coordinate, and vertex normal. So, "3/4/3" would mean, "use vertex 3 with 77873 // UV coordinate 4 and vertex normal 3". In WebGL, every vertex with different 77874 // parameters must be a different vertex, so loadedVerts is used to 77875 // temporarily store the parsed vertices, normals, etc., and indexedVerts is 77876 // used to map a specific combination (keyed on, for example, the string 77877 // "3/4/3"), to the actual index of the newly created vertex in the final 77878 // object. 77879 var loadedVerts = { 77880 v: [], 77881 vt: [], 77882 vn: [] 77883 }; 77884 var indexedVerts = {}; 77885 77886 for (var line = 0; line < lines.length; ++line) { 77887 // Each line is a separate object (vertex, face, vertex normal, etc) 77888 // For each line, split it into tokens on whitespace. The first token 77889 // describes the type. 77890 var tokens = lines[line].trim().split(/\b\s+/); 77891 77892 if (tokens.length > 0) { 77893 if (tokens[0] === 'v' || tokens[0] === 'vn') { 77894 // Check if this line describes a vertex or vertex normal. 77895 // It will have three numeric parameters. 77896 var vertex = new p5.Vector(parseFloat(tokens[1]), parseFloat(tokens[2]), parseFloat(tokens[3])); 77897 loadedVerts[tokens[0]].push(vertex); 77898 } else if (tokens[0] === 'vt') { 77899 // Check if this line describes a texture coordinate. 77900 // It will have two numeric parameters. 77901 var texVertex = [parseFloat(tokens[1]), parseFloat(tokens[2])]; 77902 loadedVerts[tokens[0]].push(texVertex); 77903 } else if (tokens[0] === 'f') { 77904 // Check if this line describes a face. 77905 // OBJ faces can have more than three points. Triangulate points. 77906 for (var tri = 3; tri < tokens.length; ++tri) { 77907 var face = []; 77908 var vertexTokens = [1, tri - 1, tri]; 77909 77910 for (var tokenInd = 0; tokenInd < vertexTokens.length; ++tokenInd) { 77911 // Now, convert the given token into an index 77912 var vertString = tokens[vertexTokens[tokenInd]]; 77913 var vertIndex = 0; // TODO: Faces can technically use negative numbers to refer to the 77914 // previous nth vertex. I haven't seen this used in practice, but 77915 // it might be good to implement this in the future. 77916 77917 if (indexedVerts[vertString] !== undefined) { 77918 vertIndex = indexedVerts[vertString]; 77919 } else { 77920 var vertParts = vertString.split('/'); 77921 77922 for (var i = 0; i < vertParts.length; i++) { 77923 vertParts[i] = parseInt(vertParts[i]) - 1; 77924 } 77925 77926 vertIndex = indexedVerts[vertString] = model.vertices.length; 77927 model.vertices.push(loadedVerts.v[vertParts[0]].copy()); 77928 77929 if (loadedVerts.vt[vertParts[1]]) { 77930 model.uvs.push(loadedVerts.vt[vertParts[1]].slice()); 77931 } else { 77932 model.uvs.push([0, 0]); 77933 } 77934 77935 if (loadedVerts.vn[vertParts[2]]) { 77936 model.vertexNormals.push(loadedVerts.vn[vertParts[2]].copy()); 77937 } 77938 } 77939 77940 face.push(vertIndex); 77941 } 77942 77943 if (face[0] !== face[1] && face[0] !== face[2] && face[1] !== face[2]) { 77944 model.faces.push(face); 77945 } 77946 } 77947 } 77948 } 77949 } // If the model doesn't have normals, compute the normals 77950 77951 77952 if (model.vertexNormals.length === 0) { 77953 model.computeNormals(); 77954 } 77955 77956 return model; 77957 } 77958 /**
77959 * Render a 3d model to the screen. 77960 * 77961 * @method model 77962 * @param {p5.Geometry} model Loaded 3d model to be rendered 77963 * @example 77964 * <div> 77965 * <code> 77966 * //draw a spinning octahedron 77967 * let octahedron; 77968 * 77969 * function preload() { 77970 * octahedron = loadModel('assets/octahedron.obj'); 77971 * } 77972 * 77973 * function setup() { 77974 * createCanvas(100, 100, WEBGL); 77975 * } 77976 * 77977 * function draw() { 77978 * background(200); 77979 * rotateX(frameCount * 0.01); 77980 * rotateY(frameCount * 0.01); 77981 * model(octahedron); 77982 * } 77983 * </code> 77984 * </div> 77985 * 77986 * @alt 77987 * Vertically rotating 3-d octahedron. 77988 * 77989 */ 77990 77991 77992 p5.prototype.model = function (model) { 77993 this._assert3d('model'); 77994 77995 p5._validateParameters('model', arguments); 77996 77997 if (model.vertices.length > 0) { 77998 if (!this._renderer.geometryInHash(model.gid)) { 77999 model._makeTriangleEdges()._edgesToVertices(); 78000 78001 this._renderer.createBuffers(model.gid, model); 78002 } 78003 78004 this._renderer.drawBuffers(model.gid); 78005 } 78006 }; 78007 78008 module.exports = p5; 78009 }, {
78010 "../core/main": 24, 78011 "./p5.Geometry": 70 78012 }], 78013 68: [function (_dereq_, module, exports) { 78014 /** 78015 * @module Lights, Camera 78016 * @submodule Material 78017 * @for p5 78018 * @requires core 78019 */ 78020 'use strict'; 78021 78022 var p5 = _dereq_('../core/main'); 78023 78024 var constants = _dereq_('../core/constants'); 78025 78026 _dereq_('./p5.Texture'); 78027 /** 78028 * Loads a custom shader from the provided vertex and fragment 78029 * shader paths. The shader files are loaded asynchronously in the 78030 * background, so this method should be used in <a href="#/p5/preload">preload()</a>. 78031 * 78032 * For now, there are three main types of shaders. p5 will automatically 78033 * supply appropriate vertices, normals, colors, and lighting attributes 78034 * if the parameters defined in the shader match the names. 78035 * 78036 * @method loadShader 78037 * @param {String} [vertFilename] path to file containing vertex shader 78038 * source code 78039 * @param {String} [fragFilename] path to file containing fragment shader 78040 * source code 78041 * @return {p5.Shader} a shader object created from the provided 78042 * vertex and fragment shader files. 78043 * 78044 * @example 78045 * <div modernizr='webgl'> 78046 * <code> 78047 * let mandel; 78048 * function preload() { 78049 * // load the shader definitions from files 78050 * mandel = loadShader('assets/shader.vert', 'assets/shader.frag'); 78051 * } 78052 * function setup() { 78053 * createCanvas(100, 100, WEBGL); 78054 * // use the shader 78055 * shader(mandel); 78056 * noStroke(); 78057 * mandel.setUniform('p', [-0.74364388703, 0.13182590421]); 78058 * } 78059 * 78060 * function draw() { 78061 * mandel.setUniform('r', 1.5 * exp(-6.5 * (1 + sin(millis() / 2000)))); 78062 * quad(-1, -1, 1, -1, 1, 1, -1, 1); 78063 * } 78064 * </code> 78065 * </div> 78066 * 78067 * @alt 78068 * zooming Mandelbrot set. a colorful, infinitely detailed fractal. 78069 */ 78070 78071 78072 p5.prototype.loadShader = function (vertFilename, fragFilename) { 78073 p5._validateParameters('loadShader', arguments); 78074 78075 var loadedShader = new p5.Shader(); 78076 var self = this; 78077 var loadedFrag = false; 78078 var loadedVert = false; 78079 this.loadStrings(fragFilename, function (result) { 78080 loadedShader._fragSrc = result.join('\n'); 78081 loadedFrag = true; 78082 78083 if (loadedVert) { 78084 self._decrementPreload(); 78085 } 78086 }); 78087 this.loadStrings(vertFilename, function (result) { 78088 loadedShader._vertSrc = result.join('\n'); 78089 loadedVert = true; 78090 78091 if (loadedFrag) { 78092 self._decrementPreload(); 78093 } 78094 }); 78095 return loadedShader; 78096 }; 78097 /** 78098 * @method createShader 78099 * @param {String} vertSrc source code for the vertex shader 78100 * @param {String} fragSrc source code for the fragment shader 78101 * @returns {p5.Shader} a shader object created from the provided 78102 * vertex and fragment shaders. 78103 * 78104 * @example 78105 * <div modernizr='webgl'> 78106 * <code> 78107 * // the 'varying's are shared between both vertex & fragment shaders 78108 * let varying = 'precision highp float; varying vec2 vPos;'; 78109 * 78110 * // the vertex shader is called for each vertex 78111 * let vs = 78112 * varying + 78113 * 'attribute vec3 aPosition;' + 78114 * 'void main() { vPos = (gl_Position = vec4(aPosition,1.0)).xy; }'; 78115 * 78116 * // the fragment shader is called for each pixel 78117 * let fs = 78118 * varying + 78119 * 'uniform vec2 p;' + 78120 * 'uniform float r;' + 78121 * 'const int I = 500;' + 78122 * 'void main() {' + 78123 * ' vec2 c = p + vPos * r, z = c;' + 78124 * ' float n = 0.0;' + 78125 * ' for (int i = I; i > 0; i --) {' + 78126 * ' if(z.x*z.x+z.y*z.y > 4.0) {' + 78127 * ' n = float(i)/float(I);' + 78128 * ' break;' + 78129 * ' }' + 78130 * ' z = vec2(z.x*z.x-z.y*z.y, 2.0*z.x*z.y) + c;' + 78131 * ' }' +
78132 * ' gl_FragColor = vec4(0.5-cos(n*17.0)/2.0,0.5-cos(n*13.0)/2.0,0.5-cos(n*23.0)/2.0,1.0);' + 78133 * '}'; 78134 * 78135 * let mandel; 78136 * function setup() { 78137 * createCanvas(100, 100, WEBGL); 78138 * 78139 * // create and initialize the shader 78140 * mandel = createShader(vs, fs); 78141 * shader(mandel); 78142 * noStroke(); 78143 * 78144 * // 'p' is the center point of the Mandelbrot image 78145 * mandel.setUniform('p', [-0.74364388703, 0.13182590421]); 78146 * } 78147 * 78148 * function draw() { 78149 * // 'r' is the size of the image in Mandelbrot-space 78150 * mandel.setUniform('r', 1.5 * exp(-6.5 * (1 + sin(millis() / 2000)))); 78151 * quad(-1, -1, 1, -1, 1, 1, -1, 1); 78152 * } 78153 * </code> 78154 * </div> 78155 * 78156 * @alt 78157 * zooming Mandelbrot set. a colorful, infinitely detailed fractal. 78158 */ 78159 78160 78161 p5.prototype.createShader = function (vertSrc, fragSrc) { 78162 this._assert3d('createShader'); 78163 78164 p5._validateParameters('createShader', arguments); 78165 78166 return new p5.Shader(this._renderer, vertSrc, fragSrc); 78167 }; 78168 /** 78169 * The <a href="#/p5/shader">shader()</a> function lets the user provide a custom shader 78170 * to fill in shapes in WEBGL mode. Users can create their 78171 * own shaders by loading vertex and fragment shaders with 78172 * <a href="#/p5/loadShader">loadShader()</a>. 78173 * 78174 * @method shader 78175 * @chainable 78176 * @param {p5.Shader} [s] the desired <a href="#/p5.Shader">p5.Shader</a> to use for rendering 78177 * shapes. 78178 */ 78179 78180 78181 p5.prototype.shader = function (s) { 78182 this._assert3d('shader'); 78183 78184 p5._validateParameters('shader', arguments); 78185 78186 if (s._renderer === undefined) { 78187 s._renderer = this._renderer; 78188 } 78189 78190 if (s.isStrokeShader()) { 78191 this._renderer.setStrokeShader(s); 78192 } else { 78193 this._renderer.setFillShader(s); 78194 } 78195 78196 return this; 78197 }; 78198 /** 78199 * Normal material for geometry. You can view all 78200 * possible materials in this 78201 * <a href="https://p5js.org/examples/3d-materials.html">example</a>. 78202 * @method normalMaterial 78203 * @chainable 78204 * @example 78205 * <div> 78206 * <code> 78207 * function setup() { 78208 * createCanvas(100, 100, WEBGL); 78209 * } 78210 * 78211 * function draw() { 78212 * background(200); 78213 * normalMaterial(); 78214 * sphere(50); 78215 * } 78216 * </code> 78217 * </div> 78218 * 78219 * @alt 78220 * Red, green and blue gradient. 78221 * 78222 */ 78223 78224 78225 p5.prototype.normalMaterial = function () { 78226 this._assert3d('normalMaterial'); 78227 78228 p5._validateParameters('normalMaterial', arguments); 78229 78230 this._renderer.drawMode = constants.FILL; 78231 78232 this._renderer.setFillShader(this._renderer._getNormalShader()); 78233 78234 this._renderer.curFillColor = [1, 1, 1, 1]; 78235 this.noStroke(); 78236 return this; 78237 }; 78238 /** 78239 * Texture for geometry. You can view other possible materials in this 78240 * <a href="https://p5js.org/examples/3d-materials.html">example</a>. 78241 * @method texture 78242 * @param {p5.Image|p5.MediaElement|p5.Graphics} tex 2-dimensional graphics 78243 * to render as texture 78244 * @chainable 78245 * @example 78246 * <div> 78247 * <code> 78248 * let img; 78249 * function preload() { 78250 * img = loadImage('assets/laDefense.jpg'); 78251 * } 78252 * 78253 * function setup() { 78254 * createCanvas(100, 100, WEBGL); 78255 * } 78256 * 78257 * function draw() { 78258 * background(0); 78259 * rotateZ(frameCount * 0.01); 78260 * rotateX(frameCount * 0.01); 78261 * rotateY(frameCount * 0.01); 78262 * //pass image as texture 78263 * texture(img); 78264 * box(200, 200, 200); 78265 * } 78266 * </code> 78267 * </div> 78268 * 78269 * <div> 78270 * <code> 78271 * let pg; 78272 * function setup() { 78273 * createCanvas(100, 100, WEBGL); 78274 * pg = createGraphics(200, 200); 78275 * pg.textSize(100); 78276 * } 78277 * 78278 * function draw() { 78279 * background(0); 78280 * pg.background(255); 78281 * pg.text('hello!', 0, 100); 78282 * //pass image as texture 78283 * texture(pg); 78284 * plane(200); 78285 * } 78286 * </code> 78287 * </div> 78288 * 78289 * <div> 78290 * <code> 78291 * let vid; 78292 * function preload() { 78293 * vid = createVideo('assets/fingers.mov'); 78294 * vid.hide(); 78295 * vid.loop(); 78296 * } 78297 * function setup() { 78298 * createCanvas(100, 100, WEBGL); 78299 * } 78300 * 78301 * function draw() { 78302 * background(0); 78303 * //pass video frame as texture 78304 * texture(vid); 78305 * plane(200); 78306 * } 78307 * </code> 78308 * </div> 78309 * 78310 * @alt 78311 * Rotating view of many images umbrella and grid roof on a 3d plane 78312 * black canvas 78313 * black canvas 78314 * 78315 */ 78316 78317 78318 p5.prototype.texture = function (tex) { 78319 this._assert3d('texture'); 78320 78321 p5._validateParameters('texture', arguments); 78322 78323 this._renderer.drawMode = constants.TEXTURE; 78324 this._renderer.textureImage = tex; 78325 78326 var shader = this._renderer._useLightShader(); 78327 78328 shader.setUniform('uSpecular', false); 78329 shader.setUniform('isTexture', true); 78330 shader.setUniform('uSampler', tex); 78331 this.noStroke(); 78332 return this; 78333 }; 78334 /** 78335 * Sets the coordinate space for texture mapping. The default mode is IMAGE 78336 * which refers to the actual coordinates of the image. 78337 * NORMAL refers to a normalized space of values ranging from 0 to 1. 78338 * This function only works in WEBGL mode. 78339 * 78340 * With IMAGE, if an image is 100 x 200 pixels, mapping the image onto the entire 78341 * size of a quad would require the points (0,0) (100, 0) (100,200) (0,200). 78342 * The same mapping in NORMAL is (0,0) (1,0) (1,1) (0,1). 78343 * @method textureMode 78344 * @param {Constant} mode either IMAGE or NORMAL 78345 * @example 78346 * <div> 78347 * <code> 78348 * let img; 78349 * 78350 * function preload() { 78351 * img = loadImage('assets/laDefense.jpg'); 78352 * } 78353 * 78354 * function setup() { 78355 * createCanvas(100, 100, WEBGL); 78356 * } 78357 * 78358 * function draw() { 78359 * texture(img); 78360 * textureMode(NORMAL); 78361 * beginShape(); 78362 * vertex(-50, -50, 0, 0); 78363 * vertex(50, -50, 1, 0); 78364 * vertex(50, 50, 1, 1); 78365 * vertex(-50, 50, 0, 1); 78366 * endShape(); 78367 * } 78368 * </code> 78369 * </div> 78370 * 78371 * @alt 78372 * the underside of a white umbrella and gridded ceiling above 78373 * 78374 * <div> 78375 * <code> 78376 * let img; 78377 * 78378 * function preload() { 78379 * img = loadImage('assets/laDefense.jpg'); 78380 * } 78381 * 78382 * function setup() { 78383 * createCanvas(100, 100, WEBGL); 78384 * } 78385 * 78386 * function draw() { 78387 * texture(img); 78388 * textureMode(NORMAL); 78389 * beginShape(); 78390 * vertex(-50, -50, 0, 0); 78391 * vertex(50, -50, img.width, 0); 78392 * vertex(50, 50, img.width, img.height); 78393 * vertex(-50, 50, 0, img.height); 78394 * endShape(); 78395 * } 78396 * </code> 78397 * </div> 78398 * 78399 * @alt 78400 * the underside of a white umbrella and gridded ceiling above 78401 * 78402 */ 78403 78404 78405 p5.prototype.textureMode = function (mode) { 78406 if (mode !== constants.IMAGE && mode !== constants.NORMAL) { 78407 console.warn('You tried to set ' + mode + ' textureMode only supports IMAGE & NORMAL '); 78408 } else { 78409 this._renderer.textureMode = mode; 78410 } 78411 }; 78412 /** 78413 * Ambient material for geometry with a given color. You can view all 78414 * possible materials in this 78415 * <a href="https://p5js.org/examples/3d-materials.html">example</a>. 78416 * @method ambientMaterial 78417 * @param {Number} v1 gray value, red or hue value 78418 * (depending on the current color mode), 78419 * @param {Number} [v2] green or saturation value 78420 * @param {Number} [v3] blue or brightness value 78421 * @param {Number} [a] opacity 78422 * @chainable 78423 * @example 78424 * <div> 78425 * <code> 78426 * function setup() { 78427 * createCanvas(100, 100, WEBGL); 78428 * } 78429 * function draw() { 78430 * background(0); 78431 * ambientLight(100); 78432 * pointLight(250, 250, 250, 100, 100, 0); 78433 * ambientMaterial(250); 78434 * sphere(50); 78435 * } 78436 * </code> 78437 * </div> 78438 * 78439 * @alt 78440 * radiating light source from top right of canvas 78441 * 78442 */ 78443 78444 /** 78445 * @method ambientMaterial 78446 * @param {Number[]|String|p5.Color} color color, color Array, or CSS color string 78447 * @chainable 78448 */ 78449 78450 78451 p5.prototype.ambientMaterial = function (v1, v2, v3, a) { 78452 this._assert3d('ambientMaterial'); 78453 78454 p5._validateParameters('ambientMaterial', arguments); 78455 78456 var color = p5.prototype.color.apply(this, arguments); 78457 this._renderer.curFillColor = color._array; 78458 78459 var shader = this._renderer._useLightShader(); 78460 78461 shader.setUniform('uMaterialColor', this._renderer.curFillColor); 78462 shader.setUniform('uSpecular', false); 78463 shader.setUniform('isTexture', false); 78464 return this; 78465 }; 78466 /** 78467 * Specular material for geometry with a given color. You can view all 78468 * possible materials in this 78469 * <a href="https://p5js.org/examples/3d-materials.html">example</a>. 78470 * @method specularMaterial 78471 * @param {Number} v1 gray value, red or hue value 78472 * (depending on the current color mode), 78473 * @param {Number} [v2] green or saturation value 78474 * @param {Number} [v3] blue or brightness value 78475 * @param {Number} [a] opacity 78476 * @chainable 78477 * @example 78478 * <div> 78479 * <code> 78480 * function setup() { 78481 * createCanvas(100, 100, WEBGL); 78482 * } 78483 * function draw() { 78484 * background(0); 78485 * ambientLight(100); 78486 * pointLight(250, 250, 250, 100, 100, 0); 78487 * specularMaterial(250); 78488 * sphere(50); 78489 * } 78490 * </code> 78491 * </div> 78492 * 78493 * @alt 78494 * diffused radiating light source from top right of canvas 78495 * 78496 */ 78497 78498 /** 78499 * @method specularMaterial 78500 * @param {Number[]|String|p5.Color} color color Array, or CSS color string 78501 * @chainable 78502 */ 78503 78504 78505 p5.prototype.specularMaterial = function (v1, v2, v3, a) { 78506 this._assert3d('specularMaterial'); 78507 78508 p5._validateParameters('specularMaterial', arguments); 78509 78510 var color = p5.prototype.color.apply(this, arguments); 78511 this._renderer.curFillColor = color._array; 78512 78513 var shader = this._renderer._useLightShader(); 78514 78515 shader.setUniform('uMaterialColor', this._renderer.curFillColor); 78516 shader.setUniform('uSpecular', true); 78517 shader.setUniform('isTexture', false); 78518 return this; 78519 }; 78520 /** 78521 * @private blends colors according to color components. 78522 * If alpha value is less than 1, we need to enable blending 78523 * on our gl context. Otherwise opaque objects need to a depthMask. 78524 * @param {Number[]} color [description] 78525 * @return {Number[]]} Normalized numbers array 78526 */ 78527 78528 78529 p5.RendererGL.prototype._applyColorBlend = function (colors) { 78530 var gl = this.GL; 78531 var isTexture = this.drawMode === constants.TEXTURE; 78532 78533 if (isTexture || colors[colors.length - 1] < 1.0) { 78534 gl.depthMask(isTexture); 78535 gl.enable(gl.BLEND); 78536 gl.blendEquation(gl.FUNC_ADD); 78537 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 78538 } else { 78539 gl.depthMask(true); 78540 gl.disable(gl.BLEND); 78541 } 78542 78543 return colors; 78544 }; 78545 78546 module.exports = p5; 78547 }, {
78548 "../core/constants": 18, 78549 "../core/main": 24, 78550 "./p5.Texture": 76 78551 }], 78552 69: [function (_dereq_, module, exports) { 78553 /** 78554 * @module Lights, Camera 78555 * @submodule Camera 78556 * @requires core 78557 */ 78558 'use strict'; 78559 78560 var p5 = _dereq_('../core/main'); //////////////////////////////////////////////////////////////////////////////// 78561 // p5.Prototype Methods 78562 //////////////////////////////////////////////////////////////////////////////// 78563 78564 /** 78565 * Sets the camera position for a 3D sketch. Parameters for this function define 78566 * the position for the camera, the center of the sketch (where the camera is 78567 * pointing), and an up direction (the orientation of the camera). 78568 * 78569 * When called with no arguments, this function creates a default camera 78570 * equivalent to 78571 * camera(0, 0, (height/2.0) / tan(PI*30.0 / 180.0), 0, 0, 0, 0, 1, 0); 78572 * @method camera 78573 * @for p5 78574 * @param {Number} [x] camera position value on x axis 78575 * @param {Number} [y] camera position value on y axis 78576 * @param {Number} [z] camera position value on z axis 78577 * @param {Number} [centerX] x coordinate representing center of the sketch 78578 * @param {Number} [centerY] y coordinate representing center of the sketch 78579 * @param {Number} [centerZ] z coordinate representing center of the sketch 78580 * @param {Number} [upX] x component of direction 'up' from camera 78581 * @param {Number} [upY] y component of direction 'up' from camera 78582 * @param {Number} [upZ] z component of direction 'up' from camera 78583 * @chainable 78584 * @example 78585 * <div> 78586 * <code> 78587 * function setup() { 78588 * createCanvas(100, 100, WEBGL); 78589 * } 78590 * function draw() { 78591 * background(204); 78592 * //move the camera away from the plane by a sin wave 78593 * camera(0, 0, 20 + sin(frameCount * 0.01) * 10, 0, 0, 0, 0, 1, 0); 78594 * plane(10, 10); 78595 * } 78596 * </code> 78597 * </div> 78598 * 78599 * @alt 78600 * White square repeatedly grows to fill canvas and then shrinks. 78601 * 78602 */ 78603 78604 78605 p5.prototype.camera = function () { 78606 this._assert3d('camera'); 78607 78608 p5._validateParameters('camera', arguments); 78609 78610 this._renderer._curCamera.camera.apply(this._renderer._curCamera, arguments); 78611 78612 return this; 78613 }; 78614 /** 78615 * Sets a perspective projection for the camera in a 3D sketch. This projection 78616 * represents depth through foreshortening: objects that are close to the camera 78617 * appear their actual size while those that are further away from the camera 78618 * appear smaller. The parameters to this function define the viewing frustum 78619 * (the truncated pyramid within which objects are seen by the camera) through 78620 * vertical field of view, aspect ratio (usually width/height), and near and far 78621 * clipping planes. 78622 * 78623 * When called with no arguments, the defaults 78624 * provided are equivalent to 78625 * perspective(PI/3.0, width/height, eyeZ/10.0, eyeZ*10.0), where eyeZ 78626 * is equal to ((height/2.0) / tan(PI*60.0/360.0)); 78627 * @method perspective 78628 * @for p5 78629 * @param {Number} [fovy] camera frustum vertical field of view, 78630 * from bottom to top of view, in <a href="#/p5/angleMode">angleMode</a> units 78631 * @param {Number} [aspect] camera frustum aspect ratio 78632 * @param {Number} [near] frustum near plane length 78633 * @param {Number} [far] frustum far plane length 78634 * @chainable 78635 * @example 78636 * <div> 78637 * <code> 78638 * //drag the mouse to look around! 78639 * //you will see there's a vanishing point 78640 * function setup() { 78641 * createCanvas(100, 100, WEBGL); 78642 * perspective(PI / 3.0, width / height, 0.1, 500); 78643 * } 78644 * function draw() { 78645 * background(200); 78646 * orbitControl(); 78647 * normalMaterial(); 78648 * 78649 * rotateX(-0.3); 78650 * rotateY(-0.2); 78651 * translate(0, 0, -50); 78652 * 78653 * push(); 78654 * translate(-15, 0, sin(frameCount / 30) * 95); 78655 * box(30); 78656 * pop(); 78657 * push(); 78658 * translate(15, 0, sin(frameCount / 30 + PI) * 95); 78659 * box(30); 78660 * pop(); 78661 * } 78662 * </code> 78663 * </div> 78664 * 78665 * @alt 78666 * two colored 3D boxes move back and forth, rotating as mouse is dragged. 78667 * 78668 */ 78669 78670 78671 p5.prototype.perspective = function () { 78672 this._assert3d('perspective'); 78673 78674 p5._validateParameters('perspective', arguments); 78675 78676 this._renderer._curCamera.perspective.apply(this._renderer._curCamera, arguments); 78677 78678 return this; 78679 }; 78680 /** 78681 * Sets an orthographic projection for the camera in a 3D sketch and defines a 78682 * box-shaped viewing frustum within which objects are seen. In this projection, 78683 * all objects with the same dimension appear the same size, regardless of 78684 * whether they are near or far from the camera. The parameters to this 78685 * function specify the viewing frustum where left and right are the minimum and 78686 * maximum x values, top and bottom are the minimum and maximum y values, and near 78687 * and far are the minimum and maximum z values. If no parameters are given, the 78688 * default is used: ortho(-width/2, width/2, -height/2, height/2). 78689 * @method ortho 78690 * @for p5 78691 * @param {Number} [left] camera frustum left plane 78692 * @param {Number} [right] camera frustum right plane 78693 * @param {Number} [bottom] camera frustum bottom plane 78694 * @param {Number} [top] camera frustum top plane 78695 * @param {Number} [near] camera frustum near plane 78696 * @param {Number} [far] camera frustum far plane 78697 * @chainable 78698 * @example 78699 * <div> 78700 * <code> 78701 * //drag the mouse to look around! 78702 * //there's no vanishing point 78703 * function setup() { 78704 * createCanvas(100, 100, WEBGL); 78705 * ortho(-width / 2, width / 2, height / 2, -height / 2, 0, 500); 78706 * } 78707 * function draw() { 78708 * background(200); 78709 * orbitControl(); 78710 * normalMaterial(); 78711 * 78712 * rotateX(0.2); 78713 * rotateY(-0.2); 78714 * push(); 78715 * translate(-15, 0, sin(frameCount / 30) * 65); 78716 * box(30); 78717 * pop(); 78718 * push(); 78719 * translate(15, 0, sin(frameCount / 30 + PI) * 65); 78720 * box(30); 78721 * pop(); 78722 * } 78723 * </code> 78724 * </div> 78725 * 78726 * @alt 78727 * two 3D boxes move back and forth along same plane, rotating as mouse is dragged. 78728 * 78729 */ 78730 78731 78732 p5.prototype.ortho = function () { 78733 this._assert3d('ortho'); 78734 78735 p5._validateParameters('ortho', arguments); 78736 78737 this._renderer._curCamera.ortho.apply(this._renderer._curCamera, arguments); 78738 78739 return this; 78740 }; //////////////////////////////////////////////////////////////////////////////// 78741 // p5.Camera
78742 //////////////////////////////////////////////////////////////////////////////// 78743 78744 /** 78745 * Creates a new <a href="#/p5.Camera">p5.Camera</a> object and tells the 78746 * renderer to use that camera. 78747 * Returns the p5.Camera object. 78748 * @method createCamera 78749 * @return {p5.Camera} The newly created camera object. 78750 * @for p5 78751 */ 78752 78753 78754 p5.prototype.createCamera = function () { 78755 this._assert3d('createCamera'); 78756 78757 var _cam = new p5.Camera(this._renderer); // compute default camera settings, then set a default camera 78758 78759 78760 _cam._computeCameraDefaultSettings(); 78761 78762 _cam._setDefaultCamera(); // set renderer current camera to the new camera 78763 78764 78765 this._renderer._curCamera = _cam; 78766 return _cam; 78767 }; 78768 /** 78769 * This class describes a camera for use in p5's 78770 * <a href="https://github.com/processing/p5.js/wiki/Getting-started-with-WebGL-in-p5"> 78771 * WebGL mode</a>. It contains camera position, orientation, and projection 78772 * information necessary for rendering a 3D scene. 78773 * 78774 * New p5.Camera objects can be made through the 78775 * <a href="#/p5/createCamera">createCamera()</a> function and controlled through 78776 * the methods described below. A camera created in this way will use a default 78777 * position in the scene and a default perspective projection until these 78778 * properties are changed through the various methods available. It is possible 78779 * to create multiple cameras, in which case the current camera 78780 * can be set through the <a href="#/p5/setCamera">setCamera()</a> method. 78781 * 78782 * 78783 * Note: 78784 * The methods below operate in two coordinate systems: the 'world' coordinate 78785 * system describe positions in terms of their relationship to the origin along 78786 * the X, Y and Z axes whereas the camera's 'local' coordinate system 78787 * describes positions from the camera's point of view: left-right, up-down, 78788 * and forward-backward. The <a href="#/p5.Camera/move">move()</a> method, 78789 * for instance, moves the camera along its own axes, whereas the 78790 * <a href="#/p5.Camera/setPosition">setPosition()</a> 78791 * method sets the camera's position in world-space. 78792 * 78793 * 78794 * @class p5.Camera 78795 * @param {rendererGL} rendererGL instance of WebGL renderer 78796 * @example 78797 * <div> 78798 * <code> 78799 * let cam; 78800 * let delta = 0.01; 78801 * 78802 * function setup() { 78803 * createCanvas(100, 100, WEBGL); 78804 * normalMaterial(); 78805 * cam = createCamera(); 78806 * // set initial pan angle 78807 * cam.pan(-0.8); 78808 * } 78809 * 78810 * function draw() { 78811 * background(200); 78812 * 78813 * // pan camera according to angle 'delta' 78814 * cam.pan(delta); 78815 * 78816 * // every 160 frames, switch direction 78817 * if (frameCount % 160 === 0) { 78818 * delta *= -1; 78819 * } 78820 * 78821 * rotateX(frameCount * 0.01); 78822 * translate(-100, 0, 0); 78823 * box(20); 78824 * translate(35, 0, 0); 78825 * box(20); 78826 * translate(35, 0, 0); 78827 * box(20); 78828 * translate(35, 0, 0); 78829 * box(20); 78830 * translate(35, 0, 0); 78831 * box(20); 78832 * translate(35, 0, 0); 78833 * box(20); 78834 * translate(35, 0, 0); 78835 * box(20); 78836 * } 78837 * </code> 78838 * </div> 78839 * 78840 * @alt 78841 * camera view pans left and right across a series of rotating 3D boxes. 78842 * 78843 */ 78844 78845 78846 p5.Camera = function (renderer) { 78847 this._renderer = renderer; 78848 this.cameraType = 'default'; 78849 this.cameraMatrix = new p5.Matrix(); 78850 this.projMatrix = new p5.Matrix(); 78851 }; //////////////////////////////////////////////////////////////////////////////// 78852 // Camera Projection Methods 78853 //////////////////////////////////////////////////////////////////////////////// 78854 78855 /** 78856 * Sets a perspective projection for a p5.Camera object and sets parameters 78857 * for that projection according to <a href="#/p5/perspective">perspective()</a> 78858 * syntax. 78859 * @method perspective 78860 * @for p5.Camera 78861 */ 78862 78863 78864 p5.Camera.prototype.perspective = function (fovy, aspect, near, far) { 78865 if (typeof fovy === 'undefined') { 78866 fovy = this.defaultCameraFOV; // this avoids issue where setting angleMode(DEGREES) before calling 78867 // perspective leads to a smaller than expected FOV (because 78868 // _computeCameraDefaultSettings computes in radians) 78869 78870 this.cameraFOV = fovy; 78871 } else { 78872 this.cameraFOV = this._renderer._pInst._toRadians(fovy); 78873 } 78874 78875 if (typeof aspect === 'undefined') { 78876 aspect = this.defaultAspectRatio; 78877 } 78878 78879 if (typeof near === 'undefined') { 78880 near = this.defaultCameraNear; 78881 } 78882 78883 if (typeof far === 'undefined') { 78884 far = this.defaultCameraFar; 78885 } 78886 78887 if (near <= 0.0001) { 78888 near = 0.01; 78889 console.log('Avoid perspective near plane values close to or below 0. ' + 'Setting value to 0.01.'); 78890 } 78891 78892 if (far < near) { 78893 console.log('Perspective far plane value is less than near plane value. ' + 'Nothing will be shown.'); 78894 } 78895 78896 this.aspectRatio = aspect; 78897 this.cameraNear = near; 78898 this.cameraFar = far; 78899 this.projMatrix = p5.Matrix.identity(); 78900 var f = 1.0 / Math.tan(this.cameraFOV / 2); 78901 var nf = 1.0 / (this.cameraNear - this.cameraFar); // prettier-ignore 78902 78903 this.projMatrix.set(f / aspect, 0, 0, 0, 0, -f, 0, 0, 0, 0, (far + near) * nf, -1, 0, 0, 2 * far * near * nf, 0); 78904 78905 if (this._isActive()) { 78906 this._renderer.uPMatrix.set(this.projMatrix.mat4[0], this.projMatrix.mat4[1], this.projMatrix.mat4[2], this.projMatrix.mat4[3], this.projMatrix.mat4[4], this.projMatrix.mat4[5], this.projMatrix.mat4[6], this.projMatrix.mat4[7], this.projMatrix.mat4[8], this.projMatrix.mat4[9], this.projMatrix.mat4[10], this.projMatrix.mat4[11], this.projMatrix.mat4[12], this.projMatrix.mat4[13], this.projMatrix.mat4[14], this.projMatrix.mat4[15]); 78907 } 78908 78909 this.cameraType = 'custom'; 78910 }; 78911 /** 78912 * Sets an orthographic projection for a p5.Camera object and sets parameters 78913 * for that projection according to <a href="#/p5/ortho">ortho()</a> syntax. 78914 * @method ortho 78915 * @for p5.Camera 78916 */ 78917 78918 78919 p5.Camera.prototype.ortho = function (left, right, bottom, top, near, far) { 78920 if (left === undefined) left = -this._renderer.width / 2; 78921 if (right === undefined) right = +this._renderer.width / 2; 78922 if (bottom === undefined) bottom = -this._renderer.height / 2; 78923 if (top === undefined) top = +this._renderer.height / 2; 78924 if (near === undefined) near = 0; 78925 if (far === undefined) far = Math.max(this._renderer.width, this._renderer.height); 78926 var w = right - left; 78927 var h = top - bottom; 78928 var d = far - near; 78929 var x = +2.0 / w; 78930 var y = +2.0 / h; 78931 var z = -2.0 / d; 78932 var tx = -(right + left) / w; 78933 var ty = -(top + bottom) / h; 78934 var tz = -(far + near) / d; 78935 this.projMatrix = p5.Matrix.identity(); // prettier-ignore 78936
78937 this.projMatrix.set(x, 0, 0, 0, 0, -y, 0, 0, 0, 0, z, 0, tx, ty, tz, 1); 78938 78939 if (this._isActive()) { 78940 this._renderer.uPMatrix.set(this.projMatrix.mat4[0], this.projMatrix.mat4[1], this.projMatrix.mat4[2], this.projMatrix.mat4[3], this.projMatrix.mat4[4], this.projMatrix.mat4[5], this.projMatrix.mat4[6], this.projMatrix.mat4[7], this.projMatrix.mat4[8], this.projMatrix.mat4[9], this.projMatrix.mat4[10], this.projMatrix.mat4[11], this.projMatrix.mat4[12], this.projMatrix.mat4[13], this.projMatrix.mat4[14], this.projMatrix.mat4[15]); 78941 } 78942 78943 this.cameraType = 'custom'; 78944 }; //////////////////////////////////////////////////////////////////////////////// 78945 // Camera Orientation Methods 78946 //////////////////////////////////////////////////////////////////////////////// 78947 78948 /** 78949 * Rotate camera view about arbitrary axis defined by x,y,z 78950 * based on http://learnwebgl.brown37.net/07_cameras/camera_rotating_motion.html 78951 * @method _rotateView 78952 * @private 78953 */ 78954 78955 78956 p5.Camera.prototype._rotateView = function (a, x, y, z) { 78957 var centerX = this.centerX; 78958 var centerY = this.centerY; 78959 var centerZ = this.centerZ; // move center by eye position such that rotation happens around eye position 78960 78961 centerX -= this.eyeX; 78962 centerY -= this.eyeY; 78963 centerZ -= this.eyeZ; 78964 var rotation = p5.Matrix.identity(this._renderer._pInst); 78965 rotation.rotate(a, x, y, z); // prettier-ignore 78966 78967 var rotatedCenter = [centerX * rotation.mat4[0] + centerY * rotation.mat4[4] + centerZ * rotation.mat4[8], centerX * rotation.mat4[1] + centerY * rotation.mat4[5] + centerZ * rotation.mat4[9], centerX * rotation.mat4[2] + centerY * rotation.mat4[6] + centerZ * rotation.mat4[10]]; // add eye position back into center 78968 78969 rotatedCenter[0] += this.eyeX; 78970 rotatedCenter[1] += this.eyeY; 78971 rotatedCenter[2] += this.eyeZ; 78972 this.camera(this.eyeX, this.eyeY, this.eyeZ, rotatedCenter[0], rotatedCenter[1], rotatedCenter[2], this.upX, this.upY, this.upZ); 78973 }; 78974 /** 78975 * Panning rotates the camera view to the left and right. 78976 * @method pan 78977 * @param {Number} angle amount to rotate camera in current 78978 * <a href="#/p5/angleMode">angleMode</a> units. 78979 * Greater than 0 values rotate counterclockwise (to the left). 78980 * @example 78981 * <div> 78982 * <code> 78983 * let cam; 78984 * let delta = 0.01; 78985 * 78986 * function setup() { 78987 * createCanvas(100, 100, WEBGL); 78988 * normalMaterial(); 78989 * cam = createCamera(); 78990 * // set initial pan angle 78991 * cam.pan(-0.8); 78992 * } 78993 * 78994 * function draw() { 78995 * background(200); 78996 * 78997 * // pan camera according to angle 'delta' 78998 * cam.pan(delta); 78999 * 79000 * // every 160 frames, switch direction 79001 * if (frameCount % 160 === 0) { 79002 * delta *= -1; 79003 * } 79004 * 79005 * rotateX(frameCount * 0.01); 79006 * translate(-100, 0, 0); 79007 * box(20); 79008 * translate(35, 0, 0); 79009 * box(20); 79010 * translate(35, 0, 0); 79011 * box(20); 79012 * translate(35, 0, 0); 79013 * box(20); 79014 * translate(35, 0, 0); 79015 * box(20); 79016 * translate(35, 0, 0); 79017 * box(20); 79018 * translate(35, 0, 0); 79019 * box(20); 79020 * } 79021 * </code> 79022 * </div> 79023 * 79024 * @alt 79025 * camera view pans left and right across a series of rotating 3D boxes. 79026 * 79027 */ 79028 79029 79030 p5.Camera.prototype.pan = function (amount) { 79031 var local = this._getLocalAxes(); 79032 79033 this._rotateView(amount, local.y[0], local.y[1], local.y[2]); 79034 }; 79035 /** 79036 * Tilting rotates the camera view up and down. 79037 * @method tilt 79038 * @param {Number} angle amount to rotate camera in current 79039 * <a href="#/p5/angleMode">angleMode</a> units. 79040 * Greater than 0 values rotate counterclockwise (to the left). 79041 * @example 79042 * <div> 79043 * <code> 79044 * let cam; 79045 * let delta = 0.01; 79046 * 79047 * function setup() { 79048 * createCanvas(100, 100, WEBGL); 79049 * normalMaterial(); 79050 * cam = createCamera(); 79051 * // set initial tilt 79052 * cam.tilt(-0.8); 79053 * } 79054 * 79055 * function draw() { 79056 * background(200); 79057 * 79058 * // pan camera according to angle 'delta' 79059 * cam.tilt(delta); 79060 * 79061 * // every 160 frames, switch direction 79062 * if (frameCount % 160 === 0) { 79063 * delta *= -1; 79064 * } 79065 * 79066 * rotateY(frameCount * 0.01); 79067 * translate(0, -100, 0); 79068 * box(20); 79069 * translate(0, 35, 0); 79070 * box(20); 79071 * translate(0, 35, 0); 79072 * box(20); 79073 * translate(0, 35, 0); 79074 * box(20); 79075 * translate(0, 35, 0); 79076 * box(20); 79077 * translate(0, 35, 0); 79078 * box(20); 79079 * translate(0, 35, 0); 79080 * box(20); 79081 * } 79082 * </code> 79083 * </div> 79084 * 79085 * @alt 79086 * camera view tilts up and down across a series of rotating 3D boxes. 79087 */ 79088 79089 79090 p5.Camera.prototype.tilt = function (amount) { 79091 var local = this._getLocalAxes(); 79092 79093 this._rotateView(amount, local.x[0], local.x[1], local.x[2]); 79094 }; 79095 /** 79096 * Reorients the camera to look at a position in world space. 79097 * @method lookAt 79098 * @for p5.Camera 79099 * @param {Number} x x position of a point in world space 79100 * @param {Number} y y position of a point in world space 79101 * @param {Number} z z position of a point in world space 79102 * @example 79103 * <div> 79104 * <code> 79105 * let cam; 79106 * 79107 * function setup() { 79108 * createCanvas(100, 100, WEBGL); 79109 * normalMaterial(); 79110 * cam = createCamera(); 79111 * } 79112 * 79113 * function draw() { 79114 * background(200); 79115 * 79116 * // look at a new random point every 60 frames 79117 * if (frameCount % 60 === 0) { 79118 * cam.lookAt(random(-100, 100), random(-50, 50), 0); 79119 * } 79120 * 79121 * rotateX(frameCount * 0.01); 79122 * translate(-100, 0, 0); 79123 * box(20); 79124 * translate(35, 0, 0); 79125 * box(20); 79126 * translate(35, 0, 0); 79127 * box(20); 79128 * translate(35, 0, 0); 79129 * box(20); 79130 * translate(35, 0, 0); 79131 * box(20); 79132 * translate(35, 0, 0); 79133 * box(20); 79134 * translate(35, 0, 0); 79135 * box(20); 79136 * } 79137 * </code> 79138 * </div> 79139 * 79140 * @alt 79141 * camera view of rotating 3D cubes changes to look at a new random 79142 * point every second . 79143 */ 79144 79145 79146 p5.Camera.prototype.lookAt = function (x, y, z) { 79147 this.camera(this.eyeX, this.eyeY, this.eyeZ, x, y, z, this.upX, this.upY, this.upZ); 79148 }; //////////////////////////////////////////////////////////////////////////////// 79149 // Camera Position Methods
79150 //////////////////////////////////////////////////////////////////////////////// 79151 79152 /** 79153 * Sets a camera's position and orientation. This is equivalent to calling 79154 * <a href="#/p5/camera">camera()</a> on a p5.Camera object. 79155 * @method camera 79156 * @for p5.Camera 79157 */ 79158 79159 79160 p5.Camera.prototype.camera = function (eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) { 79161 if (typeof eyeX === 'undefined') { 79162 eyeX = this.defaultEyeX; 79163 eyeY = this.defaultEyeY; 79164 eyeZ = this.defaultEyeZ; 79165 centerX = eyeX; 79166 centerY = eyeY; 79167 centerZ = 0; 79168 upX = 0; 79169 upY = 1; 79170 upZ = 0; 79171 } 79172 79173 this.eyeX = eyeX; 79174 this.eyeY = eyeY; 79175 this.eyeZ = eyeZ; 79176 this.centerX = centerX; 79177 this.centerY = centerY; 79178 this.centerZ = centerZ; 79179 this.upX = upX; 79180 this.upY = upY; 79181 this.upZ = upZ; 79182 79183 var local = this._getLocalAxes(); // the camera affects the model view matrix, insofar as it 79184 // inverse translates the world to the eye position of the camera 79185 // and rotates it. 79186 // prettier-ignore 79187 79188 79189 this.cameraMatrix.set(local.x[0], local.y[0], local.z[0], 0, local.x[1], local.y[1], local.z[1], 0, local.x[2], local.y[2], local.z[2], 0, 0, 0, 0, 1); 79190 var tx = -eyeX; 79191 var ty = -eyeY; 79192 var tz = -eyeZ; 79193 this.cameraMatrix.translate([tx, ty, tz]); 79194 79195 if (this._isActive()) { 79196 this._renderer.uMVMatrix.set(this.cameraMatrix.mat4[0], this.cameraMatrix.mat4[1], this.cameraMatrix.mat4[2], this.cameraMatrix.mat4[3], this.cameraMatrix.mat4[4], this.cameraMatrix.mat4[5], this.cameraMatrix.mat4[6], this.cameraMatrix.mat4[7], this.cameraMatrix.mat4[8], this.cameraMatrix.mat4[9], this.cameraMatrix.mat4[10], this.cameraMatrix.mat4[11], this.cameraMatrix.mat4[12], this.cameraMatrix.mat4[13], this.cameraMatrix.mat4[14], this.cameraMatrix.mat4[15]); 79197 } 79198 79199 return this; 79200 }; 79201 /** 79202 * Move camera along its local axes while maintaining current camera orientation. 79203 * @method move 79204 * @param {Number} x amount to move along camera's left-right axis 79205 * @param {Number} y amount to move along camera's up-down axis 79206 * @param {Number} z amount to move along camera's forward-backward axis 79207 * @example 79208 * <div> 79209 * <code> 79210 * // see the camera move along its own axes while maintaining its orientation 79211 * let cam; 79212 * let delta = 0.5; 79213 * 79214 * function setup() { 79215 * createCanvas(100, 100, WEBGL); 79216 * normalMaterial(); 79217 * cam = createCamera(); 79218 * } 79219 * 79220 * function draw() { 79221 * background(200); 79222 * 79223 * // move the camera along its local axes 79224 * cam.move(delta, delta, 0); 79225 * 79226 * // every 100 frames, switch direction 79227 * if (frameCount % 150 === 0) { 79228 * delta *= -1; 79229 * } 79230 * 79231 * translate(-10, -10, 0); 79232 * box(50, 8, 50); 79233 * translate(15, 15, 0); 79234 * box(50, 8, 50); 79235 * translate(15, 15, 0); 79236 * box(50, 8, 50); 79237 * translate(15, 15, 0); 79238 * box(50, 8, 50); 79239 * translate(15, 15, 0); 79240 * box(50, 8, 50); 79241 * translate(15, 15, 0); 79242 * box(50, 8, 50); 79243 * } 79244 * </code> 79245 * </div> 79246 * 79247 * @alt 79248 * camera view moves along a series of 3D boxes, maintaining the same 79249 * orientation throughout the move 79250 */ 79251 79252 79253 p5.Camera.prototype.move = function (x, y, z) { 79254 var local = this._getLocalAxes(); // scale local axes by movement amounts 79255 // based on http://learnwebgl.brown37.net/07_cameras/camera_linear_motion.html 79256 79257 79258 var dx = [local.x[0] * x, local.x[1] * x, local.x[2] * x]; 79259 var dy = [local.y[0] * y, local.y[1] * y, local.y[2] * y]; 79260 var dz = [local.z[0] * z, local.z[1] * z, local.z[2] * z]; 79261 this.camera(this.eyeX + dx[0] + dy[0] + dz[0], this.eyeY + dx[1] + dy[1] + dz[1], this.eyeZ + dx[2] + dy[2] + dz[2], this.centerX + dx[0] + dy[0] + dz[0], this.centerY + dx[1] + dy[1] + dz[1], this.centerZ + dx[2] + dy[2] + dz[2], 0, 1, 0); 79262 }; 79263 /** 79264 * Set camera position in world-space while maintaining current camera 79265 * orientation. 79266 * @method setPosition 79267 * @param {Number} x x position of a point in world space 79268 * @param {Number} y y position of a point in world space 79269 * @param {Number} z z position of a point in world space 79270 * @example 79271 * <div> 79272 * <code> 79273 * // press '1' '2' or '3' keys to set camera position 79274 * 79275 * let cam; 79276 * 79277 * function setup() { 79278 * createCanvas(100, 100, WEBGL); 79279 * normalMaterial(); 79280 * cam = createCamera(); 79281 * } 79282 * 79283 * function draw() { 79284 * background(200); 79285 * 79286 * // '1' key 79287 * if (keyIsDown(49)) { 79288 * cam.setPosition(30, 0, 80); 79289 * } 79290 * // '2' key 79291 * if (keyIsDown(50)) { 79292 * cam.setPosition(0, 0, 80); 79293 * } 79294 * // '3' key 79295 * if (keyIsDown(51)) { 79296 * cam.setPosition(-30, 0, 80); 79297 * } 79298 * 79299 * box(20); 79300 * } 79301 * </code> 79302 * </div> 79303 * 79304 * @alt 79305 * camera position changes as the user presses keys, altering view of a 3D box 79306 */ 79307 79308 79309 p5.Camera.prototype.setPosition = function (x, y, z) { 79310 var diffX = x - this.eyeX; 79311 var diffY = y - this.eyeY; 79312 var diffZ = z - this.eyeZ; 79313 this.camera(x, y, z, this.centerX + diffX, this.centerY + diffY, this.centerZ + diffZ, 0, 1, 0); 79314 }; //////////////////////////////////////////////////////////////////////////////// 79315 // Camera Helper Methods
79316 //////////////////////////////////////////////////////////////////////////////// 79317 // @TODO: combine this function with _setDefaultCamera to compute these values 79318 // as-needed 79319 79320 79321 p5.Camera.prototype._computeCameraDefaultSettings = function () { 79322 this.defaultCameraFOV = 60 / 180 * Math.PI; 79323 this.defaultAspectRatio = this._renderer.width / this._renderer.height; 79324 this.defaultEyeX = 0; 79325 this.defaultEyeY = 0; 79326 this.defaultEyeZ = this._renderer.height / 2.0 / Math.tan(this.defaultCameraFOV / 2.0); 79327 this.defaultCenterX = 0; 79328 this.defaultCenterY = 0; 79329 this.defaultCenterZ = 0; 79330 this.defaultCameraNear = this.defaultEyeZ * 0.1; 79331 this.defaultCameraFar = this.defaultEyeZ * 10; 79332 }; //detect if user didn't set the camera 79333 //then call this function below 79334 79335 79336 p5.Camera.prototype._setDefaultCamera = function () { 79337 this.cameraFOV = this.defaultCameraFOV; 79338 this.aspectRatio = this.defaultAspectRatio; 79339 this.eyeX = this.defaultEyeX; 79340 this.eyeY = this.defaultEyeY; 79341 this.eyeZ = this.defaultEyeZ; 79342 this.centerX = this.defaultCenterX; 79343 this.centerY = this.defaultCenterY; 79344 this.centerZ = this.defaultCenterZ; 79345 this.upX = 0; 79346 this.upY = 1; 79347 this.upZ = 0; 79348 this.cameraNear = this.defaultCameraNear; 79349 this.cameraFar = this.defaultCameraFar; 79350 this.perspective(); 79351 this.camera(); 79352 this.cameraType = 'default'; 79353 }; 79354 79355 p5.Camera.prototype._resize = function () { 79356 // If we're using the default camera, update the aspect ratio 79357 if (this.cameraType === 'default') { 79358 this._computeCameraDefaultSettings(); 79359 79360 this._setDefaultCamera(); 79361 } else { 79362 this.perspective(this.cameraFOV, this._renderer.width / this._renderer.height); 79363 } 79364 }; 79365 /** 79366 * Returns a copy of a camera. 79367 * @method copy 79368 * @private 79369 */ 79370 79371 79372 p5.Camera.prototype.copy = function () { 79373 var _cam = new p5.Camera(this._renderer); 79374 79375 _cam.cameraFOV = this.cameraFOV; 79376 _cam.aspectRatio = this.aspectRatio; 79377 _cam.eyeX = this.eyeX; 79378 _cam.eyeY = this.eyeY; 79379 _cam.eyeZ = this.eyeZ; 79380 _cam.centerX = this.centerX; 79381 _cam.centerY = this.centerY; 79382 _cam.centerZ = this.centerZ; 79383 _cam.cameraNear = this.cameraNear; 79384 _cam.cameraFar = this.cameraFar; 79385 _cam.cameraType = this.cameraType; 79386 _cam.cameraMatrix = this.cameraMatrix.copy(); 79387 _cam.projMatrix = this.projMatrix.copy(); 79388 return _cam; 79389 }; 79390 /** 79391 * Returns a camera's local axes: left-right, up-down, and forward-backward, 79392 * as defined by vectors in world-space. 79393 * @method _getLocalAxes 79394 * @private 79395 */ 79396 79397 79398 p5.Camera.prototype._getLocalAxes = function () { 79399 // calculate camera local Z vector 79400 var z0 = this.eyeX - this.centerX; 79401 var z1 = this.eyeY - this.centerY; 79402 var z2 = this.eyeZ - this.centerZ; // normalize camera local Z vector 79403 79404 var eyeDist = Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); 79405 79406 if (eyeDist !== 0) { 79407 z0 /= eyeDist; 79408 z1 /= eyeDist; 79409 z2 /= eyeDist; 79410 } // calculate camera Y vector 79411 79412 79413 var y0 = this.upX; 79414 var y1 = this.upY; 79415 var y2 = this.upZ; // compute camera local X vector as up vector (local Y) cross local Z 79416 79417 var x0 = y1 * z2 - y2 * z1; 79418 var x1 = -y0 * z2 + y2 * z0; 79419 var x2 = y0 * z1 - y1 * z0; // recompute y = z cross x 79420 79421 y0 = z1 * x2 - z2 * x1; 79422 y1 = -z0 * x2 + z2 * x0; 79423 y2 = z0 * x1 - z1 * x0; // cross product gives area of parallelogram, which is < 1.0 for 79424 // non-perpendicular unit-length vectors; so normalize x, y here: 79425 79426 var xmag = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); 79427 79428 if (xmag !== 0) { 79429 x0 /= xmag; 79430 x1 /= xmag; 79431 x2 /= xmag; 79432 } 79433 79434 var ymag = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); 79435 79436 if (ymag !== 0) { 79437 y0 /= ymag; 79438 y1 /= ymag; 79439 y2 /= ymag; 79440 } 79441 79442 return { 79443 x: [x0, x1, x2], 79444 y: [y0, y1, y2], 79445 z: [z0, z1, z2] 79446 }; 79447 }; 79448 /** 79449 * Orbits the camera about center point. For use with orbitControl(). 79450 * @method _orbit 79451 * @private 79452 * @param {Number} dTheta change in spherical coordinate theta 79453 * @param {Number} dPhi change in spherical coordinate phi 79454 * @param {Number} dRadius change in radius 79455 */ 79456 79457 79458 p5.Camera.prototype._orbit = function (dTheta, dPhi, dRadius) { 79459 var diffX = this.eyeX - this.centerX; 79460 var diffY = this.eyeY - this.centerY; 79461 var diffZ = this.eyeZ - this.centerZ; // get spherical coorinates for current camera position about origin 79462 79463 var camRadius = Math.sqrt(diffX * diffX + diffY * diffY + diffZ * diffZ); // from https://github.com/mrdoob/three.js/blob/dev/src/math/Spherical.js#L72-L73 79464 79465 var camTheta = Math.atan2(diffX, diffZ); // equatorial angle 79466 79467 var camPhi = Math.acos(Math.max(-1, Math.min(1, diffY / camRadius))); // polar angle 79468 // add change 79469 79470 camTheta += dTheta; 79471 camPhi += dPhi; 79472 camRadius += dRadius; // prevent zooming through the center: 79473 79474 if (camRadius < 0) { 79475 camRadius = 0.1; 79476 } // prevent rotation over the zenith / under bottom 79477 79478 79479 if (camPhi > Math.PI) { 79480 camPhi = Math.PI; 79481 } else if (camPhi <= 0) { 79482 camPhi = 0.001; 79483 } // from https://github.com/mrdoob/three.js/blob/dev/src/math/Vector3.js#L628-L632 79484 79485 79486 var _x = Math.sin(camPhi) * camRadius * Math.sin(camTheta); 79487 79488 var _y = Math.cos(camPhi) * camRadius; 79489 79490 var _z = Math.sin(camPhi) * camRadius * Math.cos(camTheta); 79491 79492 this.camera(_x + this.centerX, _y + this.centerY, _z + this.centerZ, this.centerX, this.centerY, this.centerZ, 0, 1, 0); 79493 }; 79494 /** 79495 * Returns true if camera is currently attached to renderer. 79496 * @method _isActive 79497 * @private 79498 */ 79499 79500 79501 p5.Camera.prototype._isActive = function () { 79502 return this === this._renderer._curCamera; 79503 }; 79504 /** 79505 * Sets rendererGL's current camera to a p5.Camera object. Allows switching 79506 * between multiple cameras. 79507 * @method setCamera 79508 * @param {p5.Camera} cam p5.Camera object 79509 * @for p5 79510 * @example 79511 * <div> 79512 * <code> 79513 * let cam1, cam2; 79514 * let currentCamera; 79515 * 79516 * function setup() { 79517 * createCanvas(100, 100, WEBGL); 79518 * normalMaterial(); 79519 * 79520 * cam1 = createCamera(); 79521 * cam2 = createCamera(); 79522 * cam2.setPosition(30, 0, 50); 79523 * cam2.lookAt(0, 0, 0); 79524 * cam2.ortho(); 79525 * 79526 * // set variable for previously active camera: 79527 * currentCamera = 1; 79528 * } 79529 * 79530 * function draw() { 79531 * background(200); 79532 * 79533 * // camera 1: 79534 * cam1.lookAt(0, 0, 0); 79535 * cam1.setPosition(sin(frameCount / 60) * 200, 0, 100); 79536 * 79537 * // every 100 frames, switch between the two cameras 79538 * if (frameCount % 100 === 0) { 79539 * if (currentCamera === 1) { 79540 * setCamera(cam1); 79541 * currentCamera = 0; 79542 * } else { 79543 * setCamera(cam2); 79544 * currentCamera = 1; 79545 * } 79546 * } 79547 * 79548 * drawBoxes(); 79549 * } 79550 * 79551 * function drawBoxes() { 79552 * rotateX(frameCount * 0.01); 79553 * translate(-100, 0, 0); 79554 * box(20); 79555 * translate(35, 0, 0); 79556 * box(20); 79557 * translate(35, 0, 0); 79558 * box(20); 79559 * translate(35, 0, 0); 79560 * box(20); 79561 * translate(35, 0, 0); 79562 * box(20); 79563 * translate(35, 0, 0); 79564 * box(20); 79565 * translate(35, 0, 0); 79566 * box(20); 79567 * } 79568 * </code> 79569 * </div> 79570 * 79571 * @alt 79572 * Canvas switches between two camera views, each showing a series of spinning 79573 * 3D boxes. 79574 */ 79575 79576 79577 p5.prototype.setCamera = function (cam) { 79578 this._renderer._curCamera = cam; // set the projection matrix (which is not normally updated each frame) 79579
79580 this._renderer.uPMatrix.set(cam.projMatrix.mat4[0], cam.projMatrix.mat4[1], cam.projMatrix.mat4[2], cam.projMatrix.mat4[3], cam.projMatrix.mat4[4], cam.projMatrix.mat4[5], cam.projMatrix.mat4[6], cam.projMatrix.mat4[7], cam.projMatrix.mat4[8], cam.projMatrix.mat4[9], cam.projMatrix.mat4[10], cam.projMatrix.mat4[11], cam.projMatrix.mat4[12], cam.projMatrix.mat4[13], cam.projMatrix.mat4[14], cam.projMatrix.mat4[15]); 79581 }; 79582 79583 module.exports = p5.Camera; 79584 }, { 79585 "../core/main": 24 79586 }], 79587 70: [function (_dereq_, module, exports) { 79588 //some of the functions are adjusted from Three.js(http://threejs.org) 79589 'use strict'; 79590 79591 var p5 = _dereq_('../core/main'); 79592 /** 79593 * p5 Geometry class 79594 * @class p5.Geometry 79595 * @constructor 79596 * @param {Integer} [detailX] number of vertices on horizontal surface 79597 * @param {Integer} [detailY] number of vertices on horizontal surface 79598 * @param {function} [callback] function to call upon object instantiation. 79599 * 79600 */ 79601 79602 79603 p5.Geometry = function (detailX, detailY, callback) { 79604 //an array containing every vertex 79605 //@type [p5.Vector] 79606 this.vertices = []; //an array containing every vertex for stroke drawing 79607 79608 this.lineVertices = []; //an array 1 normal per lineVertex with 79609 //final position representing which direction to 79610 //displace for strokeWeight 79611 //[[0,0,-1,1], [0,1,0,-1] ...]; 79612 79613 this.lineNormals = []; //an array containing 1 normal per vertex 79614 //@type [p5.Vector] 79615 //[p5.Vector, p5.Vector, p5.Vector,p5.Vector, p5.Vector, p5.Vector,...] 79616 79617 this.vertexNormals = []; //an array containing each three vertex indices that form a face 79618 //[[0, 1, 2], [2, 1, 3], ...] 79619 79620 this.faces = []; //a 2D array containing uvs for every vertex 79621 //[[0.0,0.0],[1.0,0.0], ...] 79622 79623 this.uvs = []; // a 2D array containing edge connectivity pattern for create line vertices 79624 //based on faces for most objects; 79625 79626 this.edges = []; 79627 this.detailX = detailX !== undefined ? detailX : 1; 79628 this.detailY = detailY !== undefined ? detailY : 1; 79629 79630 if (callback instanceof Function) { 79631 callback.call(this); 79632 } 79633 79634 return this; // TODO: is this a constructor? 79635 }; 79636 /** 79637 * @method computeFaces 79638 * @chainable 79639 */ 79640 79641 79642 p5.Geometry.prototype.computeFaces = function () { 79643 this.faces.length = 0; 79644 var sliceCount = this.detailX + 1; 79645 var a, b, c, d; 79646 79647 for (var i = 0; i < this.detailY; i++) { 79648 for (var j = 0; j < this.detailX; j++) { 79649 a = i * sliceCount + j; // + offset; 79650 79651 b = i * sliceCount + j + 1; // + offset; 79652 79653 c = (i + 1) * sliceCount + j + 1; // + offset; 79654 79655 d = (i + 1) * sliceCount + j; // + offset; 79656 79657 this.faces.push([a, b, d]); 79658 this.faces.push([d, b, c]); 79659 } 79660 } 79661 79662 return this; 79663 }; 79664 79665 p5.Geometry.prototype._getFaceNormal = function (faceId) { 79666 //This assumes that vA->vB->vC is a counter-clockwise ordering 79667 var face = this.faces[faceId]; 79668 var vA = this.vertices[face[0]]; 79669 var vB = this.vertices[face[1]]; 79670 var vC = this.vertices[face[2]]; 79671 var ab = p5.Vector.sub(vB, vA); 79672 var ac = p5.Vector.sub(vC, vA); 79673 var n = p5.Vector.cross(ab, ac); 79674 var ln = p5.Vector.mag(n); 79675 var sinAlpha = ln / (p5.Vector.mag(ab) * p5.Vector.mag(ac)); 79676 79677 if (sinAlpha === 0 || isNaN(sinAlpha)) { 79678 console.warn('p5.Geometry.prototype._getFaceNormal:', 'face has colinear sides or a repeated vertex'); 79679 return n; 79680 } 79681 79682 if (sinAlpha > 1) sinAlpha = 1; // handle float rounding error 79683 79684 return n.mult(Math.asin(sinAlpha) / ln); 79685 }; 79686 /** 79687 * computes smooth normals per vertex as an average of each 79688 * face. 79689 * @method computeNormals 79690 * @chainable 79691 */ 79692 79693 79694 p5.Geometry.prototype.computeNormals = function () { 79695 var vertexNormals = this.vertexNormals; 79696 var vertices = this.vertices; 79697 var faces = this.faces; 79698 var iv; // initialize the vertexNormals array with empty vectors 79699 79700 vertexNormals.length = 0; 79701 79702 for (iv = 0; iv < vertices.length; ++iv) { 79703 vertexNormals.push(new p5.Vector()); 79704 } // loop through all the faces adding its normal to the normal 79705 // of each of its vertices 79706 79707 79708 for (var f = 0; f < faces.length; ++f) { 79709 var face = faces[f]; 79710
79711 var faceNormal = this._getFaceNormal(f); // all three vertices get the normal added 79712 79713 79714 for (var fv = 0; fv < 3; ++fv) { 79715 var vertexIndex = face[fv]; 79716 vertexNormals[vertexIndex].add(faceNormal); 79717 } 79718 } // normalize the normals 79719 79720 79721 for (iv = 0; iv < vertices.length; ++iv) { 79722 vertexNormals[iv].normalize(); 79723 } 79724 79725 return this; 79726 }; 79727 /** 79728 * Averages the vertex normals. Used in curved 79729 * surfaces 79730 * @method averageNormals 79731 * @chainable 79732 */ 79733 79734 79735 p5.Geometry.prototype.averageNormals = function () { 79736 for (var i = 0; i <= this.detailY; i++) { 79737 var offset = this.detailX + 1; 79738 var temp = p5.Vector.add(this.vertexNormals[i * offset], this.vertexNormals[i * offset + this.detailX]); 79739 temp = p5.Vector.div(temp, 2); 79740 this.vertexNormals[i * offset] = temp; 79741 this.vertexNormals[i * offset + this.detailX] = temp; 79742 } 79743 79744 return this; 79745 }; 79746 /** 79747 * Averages pole normals. Used in spherical primitives 79748 * @method averagePoleNormals 79749 * @chainable 79750 */ 79751 79752 79753 p5.Geometry.prototype.averagePoleNormals = function () { 79754 //average the north pole 79755 var sum = new p5.Vector(0, 0, 0); 79756 79757 for (var i = 0; i < this.detailX; i++) { 79758 sum.add(this.vertexNormals[i]); 79759 } 79760 79761 sum = p5.Vector.div(sum, this.detailX); 79762 79763 for (i = 0; i < this.detailX; i++) { 79764 this.vertexNormals[i] = sum; 79765 } //average the south pole 79766 79767 79768 sum = new p5.Vector(0, 0, 0); 79769 79770 for (i = this.vertices.length - 1; i > this.vertices.length - 1 - this.detailX; i--) { 79771 sum.add(this.vertexNormals[i]); 79772 } 79773 79774 sum = p5.Vector.div(sum, this.detailX); 79775 79776 for (i = this.vertices.length - 1; i > this.vertices.length - 1 - this.detailX; i--) { 79777 this.vertexNormals[i] = sum; 79778 } 79779 79780 return this; 79781 }; 79782 /** 79783 * Create a 2D array for establishing stroke connections 79784 * @private 79785 * @chainable 79786 */ 79787 79788 79789 p5.Geometry.prototype._makeTriangleEdges = function () { 79790 this.edges.length = 0; 79791 79792 if (Array.isArray(this.strokeIndices)) { 79793 for (var i = 0, max = this.strokeIndices.length; i < max; i++) { 79794 this.edges.push(this.strokeIndices[i]); 79795 } 79796 } else { 79797 for (var j = 0; j < this.faces.length; j++) { 79798 this.edges.push([this.faces[j][0], this.faces[j][1]]); 79799 this.edges.push([this.faces[j][1], this.faces[j][2]]); 79800 this.edges.push([this.faces[j][2], this.faces[j][0]]); 79801 } 79802 } 79803 79804 return this; 79805 }; 79806 /** 79807 * Create 4 vertices for each stroke line, two at the beginning position 79808 * and two at the end position. These vertices are displaced relative to 79809 * that line's normal on the GPU 79810 * @private 79811 * @chainable 79812 */ 79813 79814 79815 p5.Geometry.prototype._edgesToVertices = function () { 79816 this.lineVertices.length = 0; 79817 this.lineNormals.length = 0; 79818 79819 for (var i = 0; i < this.edges.length; i++) { 79820 var begin = this.vertices[this.edges[i][0]]; 79821 var end = this.vertices[this.edges[i][1]]; 79822 var dir = end.copy().sub(begin).normalize(); 79823 var a = begin.array(); 79824 var b = begin.array(); 79825 var c = end.array(); 79826 var d = end.array(); 79827 var dirAdd = dir.array(); 79828 var dirSub = dir.array(); // below is used to displace the pair of vertices at beginning and end 79829 // in opposite directions 79830 79831 dirAdd.push(1); 79832 dirSub.push(-1); 79833 this.lineNormals.push(dirAdd, dirSub, dirAdd, dirAdd, dirSub, dirSub); 79834 this.lineVertices.push(a, b, c, c, b, d); 79835 } 79836 79837 return this; 79838 }; 79839 /** 79840 * Modifies all vertices to be centered within the range -100 to 100. 79841 * @method normalize 79842 * @chainable 79843 */ 79844 79845 79846 p5.Geometry.prototype.normalize = function () { 79847 if (this.vertices.length > 0) { 79848 // Find the corners of our bounding box 79849 var maxPosition = this.vertices[0].copy(); 79850 var minPosition = this.vertices[0].copy(); 79851 79852 for (var i = 0; i < this.vertices.length; i++) { 79853 maxPosition.x = Math.max(maxPosition.x, this.vertices[i].x); 79854 minPosition.x = Math.min(minPosition.x, this.vertices[i].x); 79855 maxPosition.y = Math.max(maxPosition.y, this.vertices[i].y); 79856 minPosition.y = Math.min(minPosition.y, this.vertices[i].y); 79857 maxPosition.z = Math.max(maxPosition.z, this.vertices[i].z); 79858 minPosition.z = Math.min(minPosition.z, this.vertices[i].z); 79859 } 79860 79861 var center = p5.Vector.lerp(maxPosition, minPosition, 0.5); 79862 var dist = p5.Vector.sub(maxPosition, minPosition); 79863 var longestDist = Math.max(Math.max(dist.x, dist.y), dist.z); 79864 var scale = 200 / longestDist; 79865 79866 for (i = 0; i < this.vertices.length; i++) { 79867 this.vertices[i].sub(center); 79868 this.vertices[i].mult(scale); 79869 } 79870 } 79871 79872 return this; 79873 }; 79874 79875 module.exports = p5.Geometry; 79876 }, {
79877 "../core/main": 24 79878 }], 79879 71: [function (_dereq_, module, exports) { 79880 /** 79881 * @requires constants 79882 * @todo see methods below needing further implementation. 79883 * future consideration: implement SIMD optimizations 79884 * when browser compatibility becomes available 79885 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/ 79886 * Reference/Global_Objects/SIMD 79887 */ 79888 'use strict'; 79889 79890 var p5 = _dereq_('../core/main'); 79891 79892 var GLMAT_ARRAY_TYPE = Array; 79893 79894 var isMatrixArray = function (x) { 79895 return x instanceof Array; 79896 }; 79897 79898 if (typeof Float32Array !== 'undefined') { 79899 GLMAT_ARRAY_TYPE = Float32Array; 79900 79901 isMatrixArray = function (x) { 79902 return x instanceof Array || x instanceof Float32Array; 79903 }; 79904 } 79905 /** 79906 * A class to describe a 4x4 matrix 79907 * for model and view matrix manipulation in the p5js webgl renderer. 79908 * @class p5.Matrix 79909 * @private 79910 * @constructor 79911 * @param {Array} [mat4] array literal of our 4x4 matrix 79912 */ 79913 79914 79915 p5.Matrix = function () { 79916 var args = new Array(arguments.length); 79917 79918 for (var i = 0; i < args.length; ++i) { 79919 args[i] = arguments[i]; 79920 } // This is default behavior when object 79921 // instantiated using createMatrix() 79922 // @todo implement createMatrix() in core/math.js 79923 79924 79925 if (args.length && args[args.length - 1] instanceof p5) { 79926 this.p5 = args[args.length - 1]; 79927 } 79928 79929 if (args[0] === 'mat3') { 79930 this.mat3 = Array.isArray(args[1]) ? args[1] : new GLMAT_ARRAY_TYPE([1, 0, 0, 0, 1, 0, 0, 0, 1]); 79931 } else { 79932 this.mat4 = Array.isArray(args[0]) ? args[0] : new GLMAT_ARRAY_TYPE([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); 79933 } 79934 79935 return this; 79936 }; 79937 /** 79938 * Sets the x, y, and z component of the vector using two or three separate 79939 * variables, the data from a p5.Matrix, or the values from a float array. 79940 * 79941 * @method set 79942 * @param {p5.Matrix|Float32Array|Number[]} [inMatrix] the input p5.Matrix or 79943 * an Array of length 16 79944 * @chainable 79945 */ 79946 79947 /** 79948 * @method set 79949 * @param {Number[]} elements 16 numbers passed by value to avoid 79950 * array copying. 79951 * @chainable 79952 */ 79953 79954 79955 p5.Matrix.prototype.set = function (inMatrix) { 79956 if (inMatrix instanceof p5.Matrix) { 79957 this.mat4 = inMatrix.mat4; 79958 return this; 79959 } else if (isMatrixArray(inMatrix)) { 79960 this.mat4 = inMatrix; 79961 return this; 79962 } else if (arguments.length === 16) { 79963 this.mat4[0] = arguments[0]; 79964 this.mat4[1] = arguments[1]; 79965 this.mat4[2] = arguments[2]; 79966 this.mat4[3] = arguments[3]; 79967 this.mat4[4] = arguments[4]; 79968 this.mat4[5] = arguments[5]; 79969 this.mat4[6] = arguments[6]; 79970 this.mat4[7] = arguments[7]; 79971 this.mat4[8] = arguments[8]; 79972 this.mat4[9] = arguments[9]; 79973 this.mat4[10] = arguments[10]; 79974 this.mat4[11] = arguments[11]; 79975 this.mat4[12] = arguments[12]; 79976 this.mat4[13] = arguments[13]; 79977 this.mat4[14] = arguments[14]; 79978 this.mat4[15] = arguments[15]; 79979 } 79980 79981 return this; 79982 }; 79983 /** 79984 * Gets a copy of the vector, returns a p5.Matrix object. 79985 * 79986 * @method get 79987 * @return {p5.Matrix} the copy of the p5.Matrix object 79988 */ 79989 79990 79991 p5.Matrix.prototype.get = function () { 79992 return new p5.Matrix(this.mat4, this.p5); 79993 }; 79994 /** 79995 * return a copy of a matrix 79996 * @method copy 79997 * @return {p5.Matrix} the result matrix 79998 */ 79999 80000 80001 p5.Matrix.prototype.copy = function () { 80002 var copied = new p5.Matrix(this.p5); 80003 copied.mat4[0] = this.mat4[0]; 80004 copied.mat4[1] = this.mat4[1]; 80005 copied.mat4[2] = this.mat4[2]; 80006 copied.mat4[3] = this.mat4[3]; 80007 copied.mat4[4] = this.mat4[4]; 80008 copied.mat4[5] = this.mat4[5]; 80009 copied.mat4[6] = this.mat4[6]; 80010 copied.mat4[7] = this.mat4[7]; 80011 copied.mat4[8] = this.mat4[8]; 80012 copied.mat4[9] = this.mat4[9]; 80013 copied.mat4[10] = this.mat4[10]; 80014 copied.mat4[11] = this.mat4[11]; 80015 copied.mat4[12] = this.mat4[12]; 80016 copied.mat4[13] = this.mat4[13]; 80017 copied.mat4[14] = this.mat4[14]; 80018 copied.mat4[15] = this.mat4[15]; 80019 return copied; 80020 }; 80021 /** 80022 * return an identity matrix 80023 * @method identity 80024 * @return {p5.Matrix} the result matrix 80025 */ 80026 80027 80028 p5.Matrix.identity = function (pInst) { 80029 return new p5.Matrix(pInst); 80030 }; 80031 /** 80032 * transpose according to a given matrix 80033 * @method transpose 80034 * @param {p5.Matrix|Float32Array|Number[]} a the matrix to be 80035 * based on to transpose 80036 * @chainable 80037 */ 80038 80039 80040 p5.Matrix.prototype.transpose = function (a) { 80041 var a01, a02, a03, a12, a13, a23; 80042 80043 if (a instanceof p5.Matrix) { 80044 a01 = a.mat4[1]; 80045 a02 = a.mat4[2]; 80046 a03 = a.mat4[3]; 80047 a12 = a.mat4[6]; 80048 a13 = a.mat4[7]; 80049 a23 = a.mat4[11]; 80050 this.mat4[0] = a.mat4[0]; 80051 this.mat4[1] = a.mat4[4]; 80052 this.mat4[2] = a.mat4[8]; 80053 this.mat4[3] = a.mat4[12]; 80054 this.mat4[4] = a01; 80055 this.mat4[5] = a.mat4[5]; 80056 this.mat4[6] = a.mat4[9]; 80057 this.mat4[7] = a.mat4[13]; 80058 this.mat4[8] = a02; 80059 this.mat4[9] = a12; 80060 this.mat4[10] = a.mat4[10]; 80061 this.mat4[11] = a.mat4[14]; 80062 this.mat4[12] = a03; 80063 this.mat4[13] = a13; 80064 this.mat4[14] = a23; 80065 this.mat4[15] = a.mat4[15]; 80066 } else if (isMatrixArray(a)) { 80067 a01 = a[1]; 80068 a02 = a[2]; 80069 a03 = a[3]; 80070 a12 = a[6]; 80071 a13 = a[7]; 80072 a23 = a[11]; 80073 this.mat4[0] = a[0]; 80074 this.mat4[1] = a[4]; 80075 this.mat4[2] = a[8]; 80076 this.mat4[3] = a[12]; 80077 this.mat4[4] = a01; 80078 this.mat4[5] = a[5]; 80079 this.mat4[6] = a[9]; 80080 this.mat4[7] = a[13]; 80081 this.mat4[8] = a02; 80082 this.mat4[9] = a12; 80083 this.mat4[10] = a[10]; 80084 this.mat4[11] = a[14]; 80085 this.mat4[12] = a03; 80086 this.mat4[13] = a13; 80087 this.mat4[14] = a23; 80088 this.mat4[15] = a[15]; 80089 } 80090 80091 return this; 80092 }; 80093 /** 80094 * invert matrix according to a give matrix 80095 * @method invert 80096 * @param {p5.Matrix|Float32Array|Number[]} a the matrix to be 80097 * based on to invert 80098 * @chainable 80099 */ 80100 80101 80102 p5.Matrix.prototype.invert = function (a) { 80103 var a00, a01, a02, a03, a10, a11, a12, a13; 80104 var a20, a21, a22, a23, a30, a31, a32, a33; 80105 80106 if (a instanceof p5.Matrix) { 80107 a00 = a.mat4[0]; 80108 a01 = a.mat4[1]; 80109 a02 = a.mat4[2]; 80110 a03 = a.mat4[3]; 80111 a10 = a.mat4[4]; 80112 a11 = a.mat4[5]; 80113 a12 = a.mat4[6]; 80114 a13 = a.mat4[7]; 80115 a20 = a.mat4[8]; 80116 a21 = a.mat4[9]; 80117 a22 = a.mat4[10]; 80118 a23 = a.mat4[11]; 80119 a30 = a.mat4[12]; 80120 a31 = a.mat4[13]; 80121 a32 = a.mat4[14]; 80122 a33 = a.mat4[15]; 80123 } else if (isMatrixArray(a)) { 80124 a00 = a[0]; 80125 a01 = a[1]; 80126 a02 = a[2]; 80127 a03 = a[3]; 80128 a10 = a[4]; 80129 a11 = a[5]; 80130 a12 = a[6]; 80131 a13 = a[7]; 80132 a20 = a[8]; 80133 a21 = a[9]; 80134 a22 = a[10]; 80135 a23 = a[11]; 80136 a30 = a[12]; 80137 a31 = a[13]; 80138 a32 = a[14]; 80139 a33 = a[15]; 80140 } 80141 80142 var b00 = a00 * a11 - a01 * a10; 80143 var b01 = a00 * a12 - a02 * a10; 80144 var b02 = a00 * a13 - a03 * a10; 80145 var b03 = a01 * a12 - a02 * a11; 80146 var b04 = a01 * a13 - a03 * a11; 80147 var b05 = a02 * a13 - a03 * a12; 80148 var b06 = a20 * a31 - a21 * a30; 80149 var b07 = a20 * a32 - a22 * a30; 80150 var b08 = a20 * a33 - a23 * a30; 80151 var b09 = a21 * a32 - a22 * a31; 80152 var b10 = a21 * a33 - a23 * a31; 80153 var b11 = a22 * a33 - a23 * a32; // Calculate the determinant 80154 80155 var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; 80156 80157 if (!det) { 80158 return null; 80159 } 80160 80161 det = 1.0 / det; 80162 this.mat4[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; 80163 this.mat4[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; 80164 this.mat4[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; 80165 this.mat4[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; 80166 this.mat4[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; 80167 this.mat4[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; 80168 this.mat4[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; 80169 this.mat4[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; 80170 this.mat4[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; 80171 this.mat4[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; 80172 this.mat4[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; 80173 this.mat4[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; 80174 this.mat4[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; 80175 this.mat4[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; 80176 this.mat4[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; 80177 this.mat4[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; 80178 return this; 80179 }; 80180 /** 80181 * Inverts a 3x3 matrix 80182 * @method invert3x3 80183 * @chainable 80184 */ 80185 80186 80187 p5.Matrix.prototype.invert3x3 = function () { 80188 var a00 = this.mat3[0]; 80189 var a01 = this.mat3[1]; 80190 var a02 = this.mat3[2]; 80191 var a10 = this.mat3[3]; 80192 var a11 = this.mat3[4]; 80193 var a12 = this.mat3[5]; 80194 var a20 = this.mat3[6]; 80195 var a21 = this.mat3[7]; 80196 var a22 = this.mat3[8]; 80197 var b01 = a22 * a11 - a12 * a21; 80198 var b11 = -a22 * a10 + a12 * a20; 80199 var b21 = a21 * a10 - a11 * a20; // Calculate the determinant 80200 80201 var det = a00 * b01 + a01 * b11 + a02 * b21; 80202 80203 if (!det) { 80204 return null; 80205 } 80206 80207 det = 1.0 / det; 80208 this.mat3[0] = b01 * det; 80209 this.mat3[1] = (-a22 * a01 + a02 * a21) * det; 80210 this.mat3[2] = (a12 * a01 - a02 * a11) * det; 80211 this.mat3[3] = b11 * det; 80212 this.mat3[4] = (a22 * a00 - a02 * a20) * det; 80213 this.mat3[5] = (-a12 * a00 + a02 * a10) * det; 80214 this.mat3[6] = b21 * det; 80215 this.mat3[7] = (-a21 * a00 + a01 * a20) * det; 80216 this.mat3[8] = (a11 * a00 - a01 * a10) * det; 80217 return this; 80218 }; 80219 /** 80220 * transposes a 3x3 p5.Matrix by a mat3 80221 * @method transpose3x3 80222 * @param {Number[]} mat3 1-dimensional array 80223 * @chainable 80224 */ 80225 80226 80227 p5.Matrix.prototype.transpose3x3 = function (mat3) { 80228 var a01 = mat3[1], 80229 a02 = mat3[2], 80230 a12 = mat3[5]; 80231 this.mat3[1] = mat3[3]; 80232 this.mat3[2] = mat3[6]; 80233 this.mat3[3] = a01; 80234 this.mat3[5] = mat3[7]; 80235 this.mat3[6] = a02; 80236 this.mat3[7] = a12; 80237 return this; 80238 }; 80239 /** 80240 * converts a 4x4 matrix to its 3x3 inverse tranform 80241 * commonly used in MVMatrix to NMatrix conversions. 80242 * @method invertTranspose 80243 * @param {p5.Matrix} mat4 the matrix to be based on to invert 80244 * @chainable 80245 * @todo finish implementation 80246 */ 80247 80248 80249 p5.Matrix.prototype.inverseTranspose = function (matrix) { 80250 if (this.mat3 === undefined) { 80251 console.error('sorry, this function only works with mat3'); 80252 } else { 80253 //convert mat4 -> mat3 80254 this.mat3[0] = matrix.mat4[0]; 80255 this.mat3[1] = matrix.mat4[1]; 80256 this.mat3[2] = matrix.mat4[2]; 80257 this.mat3[3] = matrix.mat4[4]; 80258 this.mat3[4] = matrix.mat4[5]; 80259 this.mat3[5] = matrix.mat4[6]; 80260 this.mat3[6] = matrix.mat4[8]; 80261 this.mat3[7] = matrix.mat4[9]; 80262 this.mat3[8] = matrix.mat4[10]; 80263 } 80264 80265 var inverse = this.invert3x3(); // check inverse succeded 80266 80267 if (inverse) { 80268 inverse.transpose3x3(this.mat3); 80269 } else { 80270 // in case of singularity, just zero the matrix 80271 for (var i = 0; i < 9; i++) { 80272 this.mat3[i] = 0; 80273 } 80274 } 80275 80276 return this; 80277 }; 80278 /** 80279 * inspired by Toji's mat4 determinant 80280 * @method determinant 80281 * @return {Number} Determinant of our 4x4 matrix 80282 */ 80283 80284 80285 p5.Matrix.prototype.determinant = function () { 80286 var d00 = this.mat4[0] * this.mat4[5] - this.mat4[1] * this.mat4[4], 80287 d01 = this.mat4[0] * this.mat4[6] - this.mat4[2] * this.mat4[4],
80288 d02 = this.mat4[0] * this.mat4[7] - this.mat4[3] * this.mat4[4], 80289 d03 = this.mat4[1] * this.mat4[6] - this.mat4[2] * this.mat4[5], 80290 d04 = this.mat4[1] * this.mat4[7] - this.mat4[3] * this.mat4[5], 80291 d05 = this.mat4[2] * this.mat4[7] - this.mat4[3] * this.mat4[6], 80292 d06 = this.mat4[8] * this.mat4[13] - this.mat4[9] * this.mat4[12], 80293 d07 = this.mat4[8] * this.mat4[14] - this.mat4[10] * this.mat4[12], 80294 d08 = this.mat4[8] * this.mat4[15] - this.mat4[11] * this.mat4[12], 80295 d09 = this.mat4[9] * this.mat4[14] - this.mat4[10] * this.mat4[13], 80296 d10 = this.mat4[9] * this.mat4[15] - this.mat4[11] * this.mat4[13], 80297 d11 = this.mat4[10] * this.mat4[15] - this.mat4[11] * this.mat4[14]; // Calculate the determinant 80298 80299 return d00 * d11 - d01 * d10 + d02 * d09 + d03 * d08 - d04 * d07 + d05 * d06; 80300 }; 80301 /** 80302 * multiply two mat4s 80303 * @method mult 80304 * @param {p5.Matrix|Float32Array|Number[]} multMatrix The matrix 80305 * we want to multiply by 80306 * @chainable 80307 */ 80308 80309 80310 p5.Matrix.prototype.mult = function (multMatrix) { 80311 var _src; 80312 80313 if (multMatrix === this || multMatrix === this.mat4) { 80314 _src = this.copy().mat4; // only need to allocate in this rare case 80315 } else if (multMatrix instanceof p5.Matrix) { 80316 _src = multMatrix.mat4; 80317 } else if (isMatrixArray(multMatrix)) { 80318 _src = multMatrix; 80319 } else { 80320 return; // nothing to do. 80321 } // each row is used for the multiplier 80322 80323 80324 var b0 = this.mat4[0], 80325 b1 = this.mat4[1], 80326 b2 = this.mat4[2], 80327 b3 = this.mat4[3]; 80328 this.mat4[0] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12]; 80329 this.mat4[1] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13]; 80330 this.mat4[2] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14]; 80331 this.mat4[3] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15]; 80332 b0 = this.mat4[4]; 80333 b1 = this.mat4[5]; 80334 b2 = this.mat4[6]; 80335 b3 = this.mat4[7]; 80336 this.mat4[4] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12]; 80337 this.mat4[5] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13]; 80338 this.mat4[6] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14]; 80339 this.mat4[7] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15]; 80340 b0 = this.mat4[8]; 80341 b1 = this.mat4[9]; 80342 b2 = this.mat4[10]; 80343 b3 = this.mat4[11]; 80344 this.mat4[8] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12]; 80345 this.mat4[9] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13]; 80346 this.mat4[10] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14]; 80347 this.mat4[11] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15]; 80348 b0 = this.mat4[12]; 80349 b1 = this.mat4[13]; 80350 b2 = this.mat4[14]; 80351 b3 = this.mat4[15]; 80352 this.mat4[12] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12]; 80353 this.mat4[13] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13]; 80354 this.mat4[14] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14]; 80355 this.mat4[15] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15]; 80356 return this; 80357 }; 80358 /** 80359 * scales a p5.Matrix by scalars or a vector 80360 * @method scale 80361 * @param {p5.Vector|Float32Array|Number[]} s vector to scale by 80362 * @chainable 80363 */ 80364 80365 80366 p5.Matrix.prototype.scale = function (x, y, z) { 80367 if (x instanceof p5.Vector) { 80368 // x is a vector, extract the components from it. 80369 y = x.y; 80370 z = x.z; 80371 x = x.x; // must be last 80372 } else if (x instanceof Array) { 80373 // x is an array, extract the components from it. 80374 y = x[1]; 80375 z = x[2]; 80376 x = x[0]; // must be last 80377 } 80378 80379 this.mat4[0] *= x; 80380 this.mat4[1] *= x; 80381 this.mat4[2] *= x; 80382 this.mat4[3] *= x; 80383 this.mat4[4] *= y; 80384 this.mat4[5] *= y; 80385 this.mat4[6] *= y; 80386 this.mat4[7] *= y; 80387 this.mat4[8] *= z; 80388 this.mat4[9] *= z; 80389 this.mat4[10] *= z; 80390 this.mat4[11] *= z; 80391 return this; 80392 }; 80393 /** 80394 * rotate our Matrix around an axis by the given angle. 80395 * @method rotate 80396 * @param {Number} a The angle of rotation in radians 80397 * @param {p5.Vector|Number[]} axis the axis(es) to rotate around 80398 * @chainable 80399 * inspired by Toji's gl-matrix lib, mat4 rotation 80400 */ 80401 80402 80403 p5.Matrix.prototype.rotate = function (a, x, y, z) { 80404 if (x instanceof p5.Vector) { 80405 // x is a vector, extract the components from it. 80406 y = x.y; 80407 z = x.z; 80408 x = x.x; //must be last 80409 } else if (x instanceof Array) { 80410 // x is an array, extract the components from it. 80411 y = x[1]; 80412 z = x[2]; 80413 x = x[0]; //must be last 80414 } 80415 80416 var len = Math.sqrt(x * x + y * y + z * z); 80417 x *= 1 / len; 80418 y *= 1 / len; 80419 z *= 1 / len; 80420 var a00 = this.mat4[0]; 80421 var a01 = this.mat4[1]; 80422 var a02 = this.mat4[2]; 80423 var a03 = this.mat4[3]; 80424 var a10 = this.mat4[4]; 80425 var a11 = this.mat4[5]; 80426 var a12 = this.mat4[6]; 80427 var a13 = this.mat4[7]; 80428 var a20 = this.mat4[8]; 80429 var a21 = this.mat4[9]; 80430 var a22 = this.mat4[10]; 80431 var a23 = this.mat4[11]; //sin,cos, and tan of respective angle 80432 80433 var sA = Math.sin(a);
80434 var cA = Math.cos(a); 80435 var tA = 1 - cA; // Construct the elements of the rotation matrix 80436 80437 var b00 = x * x * tA + cA; 80438 var b01 = y * x * tA + z * sA; 80439 var b02 = z * x * tA - y * sA; 80440 var b10 = x * y * tA - z * sA; 80441 var b11 = y * y * tA + cA; 80442 var b12 = z * y * tA + x * sA; 80443 var b20 = x * z * tA + y * sA; 80444 var b21 = y * z * tA - x * sA; 80445 var b22 = z * z * tA + cA; // rotation-specific matrix multiplication 80446 80447 this.mat4[0] = a00 * b00 + a10 * b01 + a20 * b02; 80448 this.mat4[1] = a01 * b00 + a11 * b01 + a21 * b02; 80449 this.mat4[2] = a02 * b00 + a12 * b01 + a22 * b02; 80450 this.mat4[3] = a03 * b00 + a13 * b01 + a23 * b02; 80451 this.mat4[4] = a00 * b10 + a10 * b11 + a20 * b12; 80452 this.mat4[5] = a01 * b10 + a11 * b11 + a21 * b12; 80453 this.mat4[6] = a02 * b10 + a12 * b11 + a22 * b12; 80454 this.mat4[7] = a03 * b10 + a13 * b11 + a23 * b12; 80455 this.mat4[8] = a00 * b20 + a10 * b21 + a20 * b22; 80456 this.mat4[9] = a01 * b20 + a11 * b21 + a21 * b22; 80457 this.mat4[10] = a02 * b20 + a12 * b21 + a22 * b22; 80458 this.mat4[11] = a03 * b20 + a13 * b21 + a23 * b22; 80459 return this; 80460 }; 80461 /** 80462 * @todo finish implementing this method! 80463 * translates 80464 * @method translate 80465 * @param {Number[]} v vector to translate by 80466 * @chainable 80467 */ 80468 80469 80470 p5.Matrix.prototype.translate = function (v) { 80471 var x = v[0], 80472 y = v[1], 80473 z = v[2] || 0; 80474 this.mat4[12] += this.mat4[0] * x + this.mat4[4] * y + this.mat4[8] * z; 80475 this.mat4[13] += this.mat4[1] * x + this.mat4[5] * y + this.mat4[9] * z; 80476 this.mat4[14] += this.mat4[2] * x + this.mat4[6] * y + this.mat4[10] * z; 80477 this.mat4[15] += this.mat4[3] * x + this.mat4[7] * y + this.mat4[11] * z; 80478 }; 80479 80480 p5.Matrix.prototype.rotateX = function (a) { 80481 this.rotate(a, 1, 0, 0); 80482 }; 80483 80484 p5.Matrix.prototype.rotateY = function (a) { 80485 this.rotate(a, 0, 1, 0); 80486 }; 80487 80488 p5.Matrix.prototype.rotateZ = function (a) { 80489 this.rotate(a, 0, 0, 1); 80490 }; 80491 /** 80492 * sets the perspective matrix 80493 * @method perspective 80494 * @param {Number} fovy [description] 80495 * @param {Number} aspect [description] 80496 * @param {Number} near near clipping plane 80497 * @param {Number} far far clipping plane 80498 * @chainable 80499 */ 80500 80501 80502 p5.Matrix.prototype.perspective = function (fovy, aspect, near, far) { 80503 var f = 1.0 / Math.tan(fovy / 2), 80504 nf = 1 / (near - far); 80505 this.mat4[0] = f / aspect; 80506 this.mat4[1] = 0; 80507 this.mat4[2] = 0; 80508 this.mat4[3] = 0; 80509 this.mat4[4] = 0; 80510 this.mat4[5] = f; 80511 this.mat4[6] = 0; 80512 this.mat4[7] = 0; 80513 this.mat4[8] = 0; 80514 this.mat4[9] = 0; 80515 this.mat4[10] = (far + near) * nf; 80516 this.mat4[11] = -1; 80517 this.mat4[12] = 0; 80518 this.mat4[13] = 0; 80519 this.mat4[14] = 2 * far * near * nf; 80520 this.mat4[15] = 0; 80521 return this; 80522 }; 80523 /** 80524 * sets the ortho matrix 80525 * @method ortho 80526 * @param {Number} left [description] 80527 * @param {Number} right [description] 80528 * @param {Number} bottom [description] 80529 * @param {Number} top [description] 80530 * @param {Number} near near clipping plane 80531 * @param {Number} far far clipping plane 80532 * @chainable 80533 */ 80534 80535 80536 p5.Matrix.prototype.ortho = function (left, right, bottom, top, near, far) { 80537 var lr = 1 / (left - right), 80538 bt = 1 / (bottom - top), 80539 nf = 1 / (near - far); 80540 this.mat4[0] = -2 * lr; 80541 this.mat4[1] = 0; 80542 this.mat4[2] = 0; 80543 this.mat4[3] = 0; 80544 this.mat4[4] = 0; 80545 this.mat4[5] = -2 * bt; 80546 this.mat4[6] = 0; 80547 this.mat4[7] = 0; 80548 this.mat4[8] = 0; 80549 this.mat4[9] = 0; 80550 this.mat4[10] = 2 * nf; 80551 this.mat4[11] = 0; 80552 this.mat4[12] = (left + right) * lr; 80553 this.mat4[13] = (top + bottom) * bt; 80554 this.mat4[14] = (far + near) * nf; 80555 this.mat4[15] = 1; 80556 return this; 80557 }; 80558 /** 80559 * PRIVATE 80560 */ 80561 // matrix methods adapted from: 80562 // https://developer.mozilla.org/en-US/docs/Web/WebGL/ 80563 // gluPerspective 80564 // 80565 // function _makePerspective(fovy, aspect, znear, zfar){ 80566 // var ymax = znear * Math.tan(fovy * Math.PI / 360.0); 80567 // var ymin = -ymax; 80568 // var xmin = ymin * aspect; 80569 // var xmax = ymax * aspect; 80570 // return _makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); 80571 // } 80572 //// 80573 //// glFrustum 80574 //// 80575 //function _makeFrustum(left, right, bottom, top, znear, zfar){ 80576 // var X = 2*znear/(right-left); 80577 // var Y = 2*znear/(top-bottom); 80578 // var A = (right+left)/(right-left); 80579 // var B = (top+bottom)/(top-bottom); 80580 // var C = -(zfar+znear)/(zfar-znear); 80581 // var D = -2*zfar*znear/(zfar-znear); 80582 // var frustrumMatrix =[ 80583 // X, 0, A, 0, 80584 // 0, Y, B, 0, 80585 // 0, 0, C, D, 80586 // 0, 0, -1, 0 80587 //]; 80588 //return frustrumMatrix; 80589 // } 80590 // function _setMVPMatrices(){ 80591 ////an identity matrix 80592 ////@TODO use the p5.Matrix class to abstract away our MV matrices and 80593 ///other math 80594 //var _mvMatrix = 80595 //[ 80596 // 1.0,0.0,0.0,0.0, 80597 // 0.0,1.0,0.0,0.0, 80598 // 0.0,0.0,1.0,0.0, 80599 // 0.0,0.0,0.0,1.0 80600 //]; 80601 80602 80603 module.exports = p5.Matrix; 80604 }, {
80605 "../core/main": 24 80606 }], 80607 72: [function (_dereq_, module, exports) { 80608 /** 80609 * Welcome to RendererGL Immediate Mode. 80610 * Immediate mode is used for drawing custom shapes 80611 * from a set of vertices. Immediate Mode is activated 80612 * when you call <a href="#/p5/beginShape">beginShape()</a> & de-activated when you call <a href="#/p5/endShape">endShape()</a>. 80613 * Immediate mode is a style of programming borrowed 80614 * from OpenGL's (now-deprecated) immediate mode. 80615 * It differs from p5.js' default, Retained Mode, which caches 80616 * geometries and buffers on the CPU to reduce the number of webgl 80617 * draw calls. Retained mode is more efficient & performative, 80618 * however, Immediate Mode is useful for sketching quick 80619 * geometric ideas. 80620 */ 80621 'use strict'; 80622 80623 var p5 = _dereq_('../core/main'); 80624 80625 var constants = _dereq_('../core/constants'); 80626 /** 80627 * Begin shape drawing. This is a helpful way of generating 80628 * custom shapes quickly. However in WEBGL mode, application 80629 * performance will likely drop as a result of too many calls to 80630 * <a href="#/p5/beginShape">beginShape()</a> / <a href="#/p5/endShape">endShape()</a>. As a high performance alternative, 80631 * please use p5.js geometry primitives. 80632 * @private 80633 * @method beginShape 80634 * @param {Number} mode webgl primitives mode. beginShape supports the 80635 * following modes: 80636 * POINTS,LINES,LINE_STRIP,LINE_LOOP,TRIANGLES, 80637 * TRIANGLE_STRIP,and TRIANGLE_FAN. 80638 * @chainable 80639 */ 80640 80641 80642 p5.RendererGL.prototype.beginShape = function (mode) { 80643 //default shape mode is line_strip 80644 this.immediateMode.shapeMode = mode !== undefined ? mode : constants.LINE_STRIP; //if we haven't yet initialized our 80645 //immediateMode vertices & buffers, create them now! 80646 80647 if (this.immediateMode.vertices === undefined) { 80648 this.immediateMode.vertices = []; 80649 this.immediateMode.edges = []; 80650 this.immediateMode.lineVertices = []; 80651 this.immediateMode.vertexColors = []; 80652 this.immediateMode.lineNormals = []; 80653 this.immediateMode.uvCoords = []; 80654 this.immediateMode.vertexBuffer = this.GL.createBuffer(); 80655 this.immediateMode.colorBuffer = this.GL.createBuffer(); 80656 this.immediateMode.uvBuffer = this.GL.createBuffer(); 80657 this.immediateMode.lineVertexBuffer = this.GL.createBuffer(); 80658 this.immediateMode.lineNormalBuffer = this.GL.createBuffer(); 80659 this.immediateMode.pointVertexBuffer = this.GL.createBuffer(); 80660 this.immediateMode._bezierVertex = []; 80661 this.immediateMode._quadraticVertex = []; 80662 this.immediateMode._curveVertex = []; 80663 } else { 80664 this.immediateMode.vertices.length = 0; 80665 this.immediateMode.edges.length = 0; 80666 this.immediateMode.lineVertices.length = 0; 80667 this.immediateMode.lineNormals.length = 0; 80668 this.immediateMode.vertexColors.length = 0; 80669 this.immediateMode.uvCoords.length = 0; 80670 } 80671 80672 this.isImmediateDrawing = true; 80673 return this; 80674 }; 80675 /** 80676 * adds a vertex to be drawn in a custom Shape. 80677 * @private 80678 * @method vertex 80679 * @param {Number} x x-coordinate of vertex 80680 * @param {Number} y y-coordinate of vertex 80681 * @param {Number} z z-coordinate of vertex 80682 * @chainable 80683 * @TODO implement handling of <a href="#/p5.Vector">p5.Vector</a> args 80684 */ 80685 80686 80687 p5.RendererGL.prototype.vertex = function (x, y) { 80688 var z, u, v; // default to (x, y) mode: all other arugments assumed to be 0. 80689 80690 z = u = v = 0; 80691 80692 if (arguments.length === 3) { 80693 // (x, y, z) mode: (u, v) assumed to be 0. 80694 z = arguments[2]; 80695 } else if (arguments.length === 4) { 80696 // (x, y, u, v) mode: z assumed to be 0. 80697 u = arguments[2]; 80698 v = arguments[3]; 80699 } else if (arguments.length === 5) { 80700 // (x, y, z, u, v) mode 80701 z = arguments[2]; 80702 u = arguments[3]; 80703 v = arguments[4]; 80704 } 80705 80706 var vert = new p5.Vector(x, y, z); 80707 this.immediateMode.vertices.push(vert); 80708 var vertexColor = this.curFillColor || [0.5, 0.5, 0.5, 1.0]; 80709 this.immediateMode.vertexColors.push(vertexColor[0], vertexColor[1], vertexColor[2], vertexColor[3]); 80710 80711 if (this.textureMode === constants.IMAGE) { 80712 if (this.textureImage !== undefined) {
80713 if (this.textureImage.width > 0 && this.textureImage.height > 0) { 80714 u /= this.textureImage.width; 80715 v /= this.textureImage.height; 80716 } 80717 } else { 80718 console.warn('You must first call texture() before using' + ' vertex() with image based u and v coordinates'); 80719 } 80720 } 80721 80722 this.immediateMode.uvCoords.push(u, v); 80723 this.immediateMode._bezierVertex[0] = x; 80724 this.immediateMode._bezierVertex[1] = y; 80725 this.immediateMode._bezierVertex[2] = z; 80726 this.immediateMode._quadraticVertex[0] = x; 80727 this.immediateMode._quadraticVertex[1] = y; 80728 this.immediateMode._quadraticVertex[2] = z; 80729 return this; 80730 }; 80731 /** 80732 * End shape drawing and render vertices to screen. 80733 * @chainable 80734 */ 80735 80736 80737 p5.RendererGL.prototype.endShape = function (mode, isCurve, isBezier, isQuadratic, isContour, shapeKind) { 80738 if (this.immediateMode.shapeMode === constants.POINTS) { 80739 this._usePointShader(); 80740 80741 this.curPointShader.bindShader(); 80742 80743 this._drawPoints(this.immediateMode.vertices, this.immediateMode.pointVertexBuffer); 80744 80745 this.curPointShader.unbindShader(); 80746 } else if (this.immediateMode.vertices.length > 1) { 80747 this._useImmediateModeShader(); 80748 80749 if (this._doStroke && this.drawMode !== constants.TEXTURE) { 80750 if (this.immediateMode.shapeMode === constants.TRIANGLE_STRIP) { 80751 var i; 80752 80753 for (i = 0; i < this.immediateMode.vertices.length - 2; i++) { 80754 this.immediateMode.edges.push([i, i + 1]); 80755 this.immediateMode.edges.push([i, i + 2]); 80756 } 80757 80758 this.immediateMode.edges.push([i, i + 1]); 80759 } else if (this.immediateMode.shapeMode === constants.TRIANGLES) { 80760 for (i = 0; i < this.immediateMode.vertices.length - 2; i = i + 3) { 80761 this.immediateMode.edges.push([i, i + 1]); 80762 this.immediateMode.edges.push([i + 1, i + 2]); 80763 this.immediateMode.edges.push([i + 2, i]); 80764 } 80765 } else { 80766 for (i = 0; i < this.immediateMode.vertices.length - 1; i++) { 80767 this.immediateMode.edges.push([i, i + 1]); 80768 } 80769 } 80770 80771 if (mode === constants.CLOSE) { 80772 this.immediateMode.edges.push([this.immediateMode.vertices.length - 1, 0]); 80773 } 80774 80775 p5.Geometry.prototype._edgesToVertices.call(this.immediateMode); 80776 80777 this._drawStrokeImmediateMode(); 80778 } 80779 80780 if (this._doFill) { 80781 if (this.isBezier || this.isQuadratic || this.isCurve) { 80782 var contours = [new Float32Array(this._vToNArray(this.immediateMode.vertices))]; 80783 80784 var polyTriangles = this._triangulate(contours); 80785 80786 this.immediateMode.vertices = []; 80787 80788 for (var j = 0, polyTriLength = polyTriangles.length; j < polyTriLength; j = j + 3) { 80789 this.vertex(polyTriangles[j], polyTriangles[j + 1], polyTriangles[j + 2]); 80790 } 80791 } 80792 80793 this._drawFillImmediateMode(mode, isCurve, isBezier, isQuadratic, isContour, shapeKind); 80794 } 80795 } //clear out our vertexPositions & colors arrays 80796 //after rendering 80797 80798 80799 this.immediateMode.vertices.length = 0; 80800 this.immediateMode.vertexColors.length = 0; 80801 this.immediateMode.uvCoords.length = 0; 80802 this.isImmediateDrawing = false; 80803 this.isBezier = false;
80804 this.isQuadratic = false; 80805 this.isCurve = false; 80806 this.immediateMode._bezierVertex.length = 0; 80807 this.immediateMode._quadraticVertex.length = 0; 80808 this.immediateMode._curveVertex.length = 0; 80809 return this; 80810 }; 80811 80812 p5.RendererGL.prototype._drawFillImmediateMode = function (mode, isCurve, isBezier, isQuadratic, isContour, shapeKind) { 80813 var gl = this.GL; 80814 this.curFillShader.bindShader(); // initialize the fill shader's 'aPosition' buffer 80815 80816 if (this.curFillShader.attributes.aPosition) { 80817 //vertex position Attribute 80818 this._bindBuffer(this.immediateMode.vertexBuffer, gl.ARRAY_BUFFER, this._vToNArray(this.immediateMode.vertices), Float32Array, gl.DYNAMIC_DRAW); 80819 80820 this.curFillShader.enableAttrib(this.curFillShader.attributes.aPosition.location, 3, gl.FLOAT, false, 0, 0); 80821 } // initialize the fill shader's 'aVertexColor' buffer 80822 80823 80824 if (this.drawMode === constants.FILL && this.curFillShader.attributes.aVertexColor) { 80825 this._bindBuffer(this.immediateMode.colorBuffer, gl.ARRAY_BUFFER, this.immediateMode.vertexColors, Float32Array, gl.DYNAMIC_DRAW); 80826 80827 this.curFillShader.enableAttrib(this.curFillShader.attributes.aVertexColor.location, 4, gl.FLOAT, false, 0, 0); 80828 } // initialize the fill shader's 'aTexCoord' buffer 80829 80830 80831 if (this.drawMode === constants.TEXTURE && this.curFillShader.attributes.aTexCoord) { 80832 //texture coordinate Attribute 80833 this._bindBuffer(this.immediateMode.uvBuffer, gl.ARRAY_BUFFER, this.immediateMode.uvCoords, Float32Array, gl.DYNAMIC_DRAW); 80834 80835 this.curFillShader.enableAttrib(this.curFillShader.attributes.aTexCoord.location, 2, gl.FLOAT, false, 0, 0); 80836 } //if (true || mode) { 80837 80838 80839 if (this.drawMode === constants.FILL || this.drawMode === constants.TEXTURE) { 80840 switch (this.immediateMode.shapeMode) { 80841 case constants.LINE_STRIP: 80842 case constants.LINES: 80843 case constants.TRIANGLES: 80844 this.immediateMode.shapeMode = this.isBezier || this.isQuadratic || this.isCurve || this.immediateMode.shapeMode === constants.TRIANGLES ? constants.TRIANGLES : constants.TRIANGLE_FAN; 80845 break; 80846 } 80847 } else { 80848 switch (this.immediateMode.shapeMode) { 80849 case constants.LINE_STRIP: 80850 case constants.LINES: 80851 this.immediateMode.shapeMode = constants.LINE_LOOP; 80852 break; 80853 } 80854 } //} 80855 //QUADS & QUAD_STRIP are not supported primitives modes 80856 //in webgl. 80857 80858 80859 if (this.immediateMode.shapeMode === constants.QUADS || this.immediateMode.shapeMode === constants.QUAD_STRIP) { 80860 throw new Error('sorry, ' + this.immediateMode.shapeMode + ' not yet implemented in webgl mode.'); 80861 } else { 80862 this._applyColorBlend(this.curFillColor); 80863 80864 gl.enable(gl.BLEND); 80865 gl.drawArrays(this.immediateMode.shapeMode, 0, this.immediateMode.vertices.length); 80866 this._pInst._pixelsDirty = true; 80867 } // todo / optimizations? leave bound until another shader is set? 80868 80869 80870 this.curFillShader.unbindShader(); 80871 }; 80872 80873 p5.RendererGL.prototype._drawStrokeImmediateMode = function () { 80874 var gl = this.GL; 80875 this.curStrokeShader.bindShader(); // initialize the stroke shader's 'aPosition' buffer 80876 80877 if (this.curStrokeShader.attributes.aPosition) { 80878 this._bindBuffer(this.immediateMode.lineVertexBuffer, gl.ARRAY_BUFFER, this._flatten(this.immediateMode.lineVertices), Float32Array, gl.STATIC_DRAW); 80879 80880 this.curStrokeShader.enableAttrib(this.curStrokeShader.attributes.aPosition.location, 3, gl.FLOAT, false, 0, 0); 80881 } // initialize the stroke shader's 'aDirection' buffer 80882 80883 80884 if (this.curStrokeShader.attributes.aDirection) { 80885 this._bindBuffer(this.immediateMode.lineNormalBuffer, gl.ARRAY_BUFFER, this._flatten(this.immediateMode.lineNormals), Float32Array, gl.STATIC_DRAW); 80886 80887 this.curStrokeShader.enableAttrib(this.curStrokeShader.attributes.aDirection.location, 4, gl.FLOAT, false, 0, 0); 80888 } 80889 80890 this._applyColorBlend(this.curStrokeColor); 80891 80892 gl.drawArrays(gl.TRIANGLES, 0, this.immediateMode.lineVertices.length); // todo / optimizations? leave bound until another shader is set? 80893 80894 this.curStrokeShader.unbindShader(); 80895 this._pInst._pixelsDirty = true; 80896 }; 80897 80898 module.exports = p5.RendererGL; 80899 }, {
80900 "../core/constants": 18, 80901 "../core/main": 24 80902 }], 80903 73: [function (_dereq_, module, exports) { 80904 //Retained Mode. The default mode for rendering 3D primitives 80905 //in WEBGL. 80906 'use strict'; 80907 80908 var p5 = _dereq_('../core/main'); 80909 80910 var hashCount = 0; 80911 /** 80912 * _initBufferDefaults 80913 * @private 80914 * @description initializes buffer defaults. runs each time a new geometry is 80915 * registered 80916 * @param {String} gId key of the geometry object 80917 */ 80918 80919 p5.RendererGL.prototype._initBufferDefaults = function (gId) { 80920 this._freeBuffers(gId); //@TODO remove this limit on hashes in gHash 80921 80922 80923 hashCount++; 80924 80925 if (hashCount > 1000) { 80926 var key = Object.keys(this.gHash)[0]; 80927 delete this.gHash[key]; 80928 hashCount--; 80929 } //create a new entry in our gHash 80930 80931 80932 this.gHash[gId] = {}; 80933 }; 80934 80935 p5.RendererGL.prototype._freeBuffers = function (gId) { 80936 var geometry = this.gHash[gId]; 80937 80938 if (!geometry) { 80939 return; 80940 } 80941 80942 delete this.gHash[gId]; 80943 hashCount--; 80944 var gl = this.GL; 80945 geometry.vertexBuffer && gl.deleteBuffer(geometry.vertexBuffer); 80946 geometry.normalBuffer && gl.deleteBuffer(geometry.normalBuffer); 80947 geometry.lineNormalBuffer && gl.deleteBuffer(geometry.lineNormalBuffer); 80948 geometry.uvBuffer && gl.deleteBuffer(geometry.uvBuffer); 80949 geometry.indexBuffer && gl.deleteBuffer(geometry.indexBuffer); 80950 geometry.lineVertexBuffer && gl.deleteBuffer(geometry.lineVertexBuffer); 80951 }; 80952 /** 80953 * createBuffers description 80954 * @private 80955 * @param {String} gId key of the geometry object 80956 * @param {p5.Geometry} obj contains geometry data 80957 */ 80958 80959 80960 p5.RendererGL.prototype.createBuffers = function (gId, obj) { 80961 var gl = this.GL; //initialize the gl buffers for our geom groups 80962 80963 this._initBufferDefaults(gId); 80964 80965 var geometry = this.gHash[gId]; 80966 geometry.numberOfItems = obj.faces.length * 3; 80967 geometry.lineVertexCount = obj.lineVertices.length; 80968 80969 this._useColorShader(); // initialize the stroke shader's 'aPosition' buffer, if used 80970 80971 80972 if (this.curStrokeShader.attributes.aPosition) { 80973 geometry.lineVertexBuffer = gl.createBuffer(); 80974 80975 this._bindBuffer(geometry.lineVertexBuffer, gl.ARRAY_BUFFER, this._flatten(obj.lineVertices), Float32Array, gl.STATIC_DRAW); 80976 80977 this.curStrokeShader.enableAttrib(this.curStrokeShader.attributes.aPosition.location, 3, gl.FLOAT, false, 0, 0); 80978 } // initialize the stroke shader's 'aDirection' buffer, if used 80979 80980 80981 if (this.curStrokeShader.attributes.aDirection) { 80982 geometry.lineNormalBuffer = gl.createBuffer(); 80983 80984 this._bindBuffer(geometry.lineNormalBuffer, gl.ARRAY_BUFFER, this._flatten(obj.lineNormals), Float32Array, gl.STATIC_DRAW); 80985 80986 this.curStrokeShader.enableAttrib(this.curStrokeShader.attributes.aDirection.location, 4, gl.FLOAT, false, 0, 0); 80987 } // initialize the fill shader's 'aPosition' buffer, if used 80988 80989 80990 if (this.curFillShader.attributes.aPosition) { 80991 geometry.vertexBuffer = gl.createBuffer(); // allocate space for vertex positions 80992 80993 this._bindBuffer(geometry.vertexBuffer, gl.ARRAY_BUFFER, this._vToNArray(obj.vertices), Float32Array, gl.STATIC_DRAW); 80994 80995 this.curFillShader.enableAttrib(this.curFillShader.attributes.aPosition.location, 3, gl.FLOAT, false, 0, 0); 80996 } // allocate space for faces 80997 80998 80999 geometry.indexBuffer = gl.createBuffer(); 81000 81001 this._bindBuffer(geometry.indexBuffer, gl.ELEMENT_ARRAY_BUFFER, this._flatten(obj.faces), Uint16Array, gl.STATIC_DRAW); // initialize the fill shader's 'aNormal' buffer, if used 81002 81003 81004 if (this.curFillShader.attributes.aNormal) { 81005 geometry.normalBuffer = gl.createBuffer(); // allocate space for normals 81006 81007 this._bindBuffer(geometry.normalBuffer, gl.ARRAY_BUFFER, this._vToNArray(obj.vertexNormals), Float32Array, gl.STATIC_DRAW); 81008 81009 this.curFillShader.enableAttrib(this.curFillShader.attributes.aNormal.location, 3, gl.FLOAT, false, 0, 0); 81010 } // initialize the fill shader's 'aTexCoord' buffer, if used 81011 81012 81013 if (this.curFillShader.attributes.aTexCoord) { 81014 geometry.uvBuffer = gl.createBuffer(); // tex coords 81015 81016 this._bindBuffer(geometry.uvBuffer, gl.ARRAY_BUFFER, this._flatten(obj.uvs), Float32Array, gl.STATIC_DRAW); 81017 81018 this.curFillShader.enableAttrib(this.curFillShader.attributes.aTexCoord.location, 2, gl.FLOAT, false, 0, 0); 81019 } //} 81020 81021 81022 return geometry; 81023 }; 81024 /** 81025 * Draws buffers given a geometry key ID 81026 * @private 81027 * @param {String} gId ID in our geom hash 81028 * @chainable 81029 */ 81030 81031 81032 p5.RendererGL.prototype.drawBuffers = function (gId) { 81033 var gl = this.GL; 81034 81035 this._useColorShader(); 81036 81037 var geometry = this.gHash[gId]; 81038 81039 if (this._doStroke && geometry.lineVertexCount > 0) { 81040 this.curStrokeShader.bindShader(); // bind the stroke shader's 'aPosition' buffer 81041 81042 if (geometry.lineVertexBuffer) { 81043 this._bindBuffer(geometry.lineVertexBuffer, gl.ARRAY_BUFFER); 81044 81045 this.curStrokeShader.enableAttrib(this.curStrokeShader.attributes.aPosition.location, 3, gl.FLOAT, false, 0, 0); 81046 } // bind the stroke shader's 'aDirection' buffer 81047 81048 81049 if (geometry.lineNormalBuffer) { 81050 this._bindBuffer(geometry.lineNormalBuffer, gl.ARRAY_BUFFER); 81051 81052 this.curStrokeShader.enableAttrib(this.curStrokeShader.attributes.aDirection.location, 4, gl.FLOAT, false, 0, 0); 81053 } 81054 81055 this._applyColorBlend(this.curStrokeColor); 81056 81057 this._drawArrays(gl.TRIANGLES, gId); 81058 81059 this.curStrokeShader.unbindShader(); 81060 } 81061 81062 if (this._doFill !== false) { 81063 this.curFillShader.bindShader(); // bind the fill shader's 'aPosition' buffer 81064 81065 if (geometry.vertexBuffer) { 81066 //vertex position buffer 81067 this._bindBuffer(geometry.vertexBuffer, gl.ARRAY_BUFFER); 81068 81069 this.curFillShader.enableAttrib(this.curFillShader.attributes.aPosition.location, 3, gl.FLOAT, false, 0, 0); 81070 } 81071 81072 if (geometry.indexBuffer) { 81073 //vertex index buffer 81074 this._bindBuffer(geometry.indexBuffer, gl.ELEMENT_ARRAY_BUFFER); 81075 } // bind the fill shader's 'aNormal' buffer 81076 81077 81078 if (geometry.normalBuffer) { 81079 this._bindBuffer(geometry.normalBuffer, gl.ARRAY_BUFFER); 81080 81081 this.curFillShader.enableAttrib(this.curFillShader.attributes.aNormal.location, 3, gl.FLOAT, false, 0, 0); 81082 } // bind the fill shader's 'aTexCoord' buffer 81083 81084 81085 if (geometry.uvBuffer) { 81086 // uv buffer 81087 this._bindBuffer(geometry.uvBuffer, gl.ARRAY_BUFFER); 81088 81089 this.curFillShader.enableAttrib(this.curFillShader.attributes.aTexCoord.location, 2, gl.FLOAT, false, 0, 0); 81090 } 81091 81092 this._applyColorBlend(this.curFillColor); 81093 81094 this._drawElements(gl.TRIANGLES, gId); 81095 81096 this.curFillShader.unbindShader(); 81097 } 81098 81099 return this; 81100 }; 81101 /** 81102 * Calls drawBuffers() with a scaled model/view matrix. 81103 * 81104 * This is used by various 3d primitive methods (in primitives.js, eg. plane, 81105 * box, torus, etc...) to allow caching of un-scaled geometries. Those 81106 * geometries are generally created with unit-length dimensions, cached as 81107 * such, and then scaled appropriately in this method prior to rendering. 81108 * 81109 * @private 81110 * @method drawBuffersScaled 81111 * @param {String} gId ID in our geom hash 81112 * @param {Number} scaleX the amount to scale in the X direction 81113 * @param {Number} scaleY the amount to scale in the Y direction 81114 * @param {Number} scaleZ the amount to scale in the Z direction 81115 */ 81116 81117 81118 p5.RendererGL.prototype.drawBuffersScaled = function (gId, scaleX, scaleY, scaleZ) { 81119 var uMVMatrix = this.uMVMatrix.copy(); 81120 81121 try { 81122 this.uMVMatrix.scale(scaleX, scaleY, scaleZ); 81123 this.drawBuffers(gId); 81124 } finally { 81125 this.uMVMatrix = uMVMatrix; 81126 } 81127 }; 81128 81129 p5.RendererGL.prototype._drawArrays = function (drawMode, gId) { 81130 this.GL.drawArrays(drawMode, 0, this.gHash[gId].lineVertexCount); 81131 this._pInst._pixelsDirty = true; 81132 return this; 81133 }; 81134 81135 p5.RendererGL.prototype._drawElements = function (drawMode, gId) { 81136 this.GL.drawElements(drawMode, this.gHash[gId].numberOfItems, this.GL.UNSIGNED_SHORT, 0); 81137 this._pInst._pixelsDirty = true; 81138 }; 81139 81140 p5.RendererGL.prototype._drawPoints = function (vertices, vertexBuffer) { 81141 var gl = this.GL; 81142 81143 this._bindBuffer(vertexBuffer, gl.ARRAY_BUFFER, this._vToNArray(vertices), Float32Array, gl.STATIC_DRAW); 81144 81145 this.curPointShader.enableAttrib(this.curPointShader.attributes.aPosition.location, 3, gl.FLOAT, false, 0, 0); 81146 gl.drawArrays(gl.Points, 0, vertices.length); 81147 }; 81148 81149 module.exports = p5.RendererGL; 81150 }, {
81151 "../core/main": 24 81152 }], 81153 74: [function (_dereq_, module, exports) { 81154 'use strict'; 81155 81156 var p5 = _dereq_('../core/main'); 81157 81158 var constants = _dereq_('../core/constants'); 81159 81160 var libtess = _dereq_('libtess'); 81161 81162 _dereq_('./p5.Shader'); 81163 81164 _dereq_('./p5.Camera'); 81165 81166 _dereq_('../core/p5.Renderer'); 81167 81168 _dereq_('./p5.Matrix'); 81169 81170 var defaultShaders = { 81171 immediateVert: "attribute vec3 aPosition;\nattribute vec4 aVertexColor;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform float uResolution;\nuniform float uPointSize;\n\nvarying vec4 vColor;\nvoid main(void) {\n vec4 positionVec4 = vec4(aPosition, 1.0);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n vColor = aVertexColor;\n gl_PointSize = uPointSize;\n}\n", 81172 vertexColorVert: "attribute vec3 aPosition;\nattribute vec4 aVertexColor;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\n\nvarying vec4 vColor;\n\nvoid main(void) {\n vec4 positionVec4 = vec4(aPosition, 1.0
81172);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n vColor = aVertexColor;\n}\n", 81173 vertexColorFrag: "precision mediump float;\nvarying vec4 vColor;\nvoid main(void) {\n gl_FragColor = vColor;\n}", 81174 normalVert: "attribute vec3 aPosition;\nattribute vec3 aNormal;\nattribute vec2 aTexCoord;\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform mat3 uNormalMatrix;\n\nvarying vec3 vVertexNormal;\nvarying highp vec2 vVertTexCoord;\n\nvoid main(void) {\n vec4 positionVec4 = vec4(aPosition, 1.0);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n vVertexNormal = normalize(vec3( uNormalMatrix * aNormal ));\n vVertTexCoord = aTexCoord;\n}\n", 81175 normalFrag: "precision mediump float;\nvarying vec3 vVertexNormal;\nvoid main(void) {\n gl_FragColor = vec4(vVertexNormal, 1.0);\n}", 81176 basicFrag: "precision mediump float;\nvarying vec3 vVertexNormal;\nuniform vec4 uMaterialColor;\nvoid main(void) {\n gl_FragColor = uMaterialColor;\n}", 81177 lightVert: "attribute vec3 aPosition;\nattribute vec3 aNormal;\nattribute vec2 aTexCoord;\n\nuniform mat4 uViewMatrix;\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform mat3 uNormalMatrix;\nuniform int uAmbientLightCount;\nuniform int uDirectionalLightCount;\nuniform int uPointLightCount;\n\nuniform vec3 uAmbientColor[8];\nuniform vec3 uLightingDirection[8];\nuniform vec3 uDirectionalColor[8];\nuniform vec3 uPointLightLocation[8];\nuniform vec3 uPointLightColor[8];\nuniform bool uSpecular;\n\nvarying vec3 vVertexNormal;\nvarying vec2 vVertTexCoord;\nvarying vec3 vLightWeighting;\n\nvoid main(void){\n\n vec4 positionVec4 = vec4(aPosition, 1.0
81177);\n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n\n vec3 vertexNormal = normalize(vec3( uNormalMatrix * aNormal ));\n vVertexNormal = vertexNormal;\n vVertTexCoord = aTexCoord;\n\n vec4 mvPosition = uModelViewMatrix * vec4(aPosition, 1.0);\n vec3 eyeDirection = normalize(-mvPosition.xyz);\n\n float shininess = 32.0;\n float specularFactor = 2.0;\n float diffuseFactor = 0.3;\n\n vec3 ambientLightFactor = vec3(0.0);\n\n for (int i = 0; i < 8; i++) {\n if (uAmbientLightCount == i) break;\n ambientLightFactor += uAmbientColor[i];\n }\n\n\n vec3 directionalLightFactor = vec3(0.0);\n\n for (int j = 0; j < 8; j++) {\n if (uDirectionalLightCount == j) break;\n vec3 dir = uLightingDirection[j];\n float directionalLightWeighting = max(dot(vertexNormal, -dir), 0.0);\n directionalLightFactor += uDirectionalColor[j] * directionalLightWeighting;\n }\n\n\n vec3 pointLightFactor = vec3(0.0);\n\n for (int k = 0; k < 8; k++) {\n if (uPointLightCount == k) break;\n vec3 loc = (uViewMatrix * vec4(uPointLightLocation[k], 1.0)).xyz;\n vec3 lightDirection = normalize(loc - mvPosition.xyz);\n\n float directionalLightWeighting = max(dot(vertexNormal, lightDirection), 0.0);\n\n float specularLightWeighting = 0.0;\n if (uSpecular ){\n vec3 reflectionDirection = reflect(-lightDirection, vertexNormal);\n specularLightWeighting = pow(max(dot(reflectionDirection, eyeDirection), 0.0), shininess);\n }\n\n pointLightFactor += uPointLightColor[k] * (specularFactor * specularLightWeighting\n + directionalLightWeighting * diffuseFactor);\n }\n\n vLightWeighting = ambientLightFactor + directionalLightFactor + pointLightFactor;\n}\n", 81178 lightTextureFrag: "precision mediump float;\n\nuniform vec4 uMaterialColor;\nuniform sampler2D uSampler;\nuniform bool isTexture;\nuniform bool uUseLighting;\n\nvarying vec3 vLightWeighting;\nvarying highp vec2 vVertTexCoord;\n\nvoid main(void) {\n gl_FragColor = isTexture ? texture2D(uSampler, vVertTexCoord) : uMaterialColor;\n if (uUseLighting)\n gl_FragColor.rgb *= vLightWeighting;\n}", 81179 phongVert: "precision mediump float;\n\nattribute vec3 aPosition;\nattribute vec3 aNormal;\nattribute vec2 aTexCoord;\n\nuniform vec3 uAmbientColor[8];\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform mat3 uNormalMatrix;\nuniform int uAmbientLightCount;\n\nvarying vec3 vNormal;\nvarying vec2 vTexCoord;\nvarying vec3 vViewPosition;\nvarying vec3 vAmbientColor;\n\nvoid main(void){\n\n vec4 viewModelPosition = uModelViewMatrix * vec4(aPosition, 1.0
81179);\n\n // Pass varyings to fragment shader\n vViewPosition = viewModelPosition.xyz;\n gl_Position = uProjectionMatrix * viewModelPosition; \n\n vNormal = normalize(uNormalMatrix * normalize(aNormal));\n vTexCoord = aTexCoord;\n\n vAmbientColor = vec3(0.0);\n for (int i = 0; i < 8; i++) {\n if (uAmbientLightCount == i) break;\n vAmbientColor += uAmbientColor[i];\n }\n}\n", 81180 phongFrag: "precision mediump float;\n\n//uniform mat4 uModelViewMatrix;\nuniform mat4 uViewMatrix;\n\nuniform vec4 uMaterialColor;\nuniform sampler2D uSampler;\nuniform bool isTexture;\nuniform bool uUseLighting;\n\nuniform vec3 uLightingDirection[8];\nuniform vec3 uDirectionalColor[8];\nuniform vec3 uPointLightLocation[8];\nuniform vec3 uPointLightColor[8];\nuniform bool uSpecular;\n\nuniform int uDirectionalLightCount;\nuniform int uPointLightCount;\n\nvarying vec3 vNormal;\nvarying vec2 vTexCoord;\nvarying vec3 vViewPosition;\nvarying vec3 vAmbientColor;\n\nvec3 V;\nvec3 N;\n\nconst float shininess = 32.0;\nconst float specularFactor = 2.0;\nconst float diffuseFactor = 0.73;\n\nstruct LightResult {\n\tfloat specular;\n\tfloat diffuse;\n};\n\nfloat phongSpecular(\n vec3 lightDirection,\n vec3 viewDirection,\n vec3 surfaceNormal,\n float shininess) {\n\n vec3 R = normalize(reflect(-lightDirection, surfaceNormal)); \n return pow(max(0.0, dot(R, viewDirection)), shininess);\n}\n\nfloat lambertDiffuse(\n vec3 lightDirection,\n vec3 surfaceNormal) {\n return max(0.0, dot(-lightDirection, surfaceNormal));\n}\n\nLightResult light(vec3 lightVector) {\n\n vec3 L = normalize(lightVector);\n\n //compute our diffuse & specular terms\n LightResult lr;\n if (uSpecular)\n lr.specular = phongSpecular(L, V, N, shininess);\n lr.diffuse = lambertDiffuse(L, N);\n return lr;\n}\n\nvoid main(void) {\n\n V = normalize(vViewPosition);\n N = vNormal;\n\n vec3 diffuse = vec3(0.0);\n float specular = 0.0;\n\n for (int j = 0; j < 8; j++) {\n if (uDirectionalLightCount == j) break;\n\n LightResult result = light(uLightingDirection[j]);\n diffuse += result.diffuse * uDirectionalColor[j];\n specular += result.specular;\n }\n\n for (int k = 0; k < 8; k++) {\n if (uPointLightCount == k) break;\n\n vec3 lightPosition = (uViewMatrix * vec4(uPointLightLocation[k], 1.0)).xyz;\n vec3 lightVector = vViewPosition - lightPosition;\n\t\n //calculate attenuation\n float lightDistance = length(lightVector);\n float falloff = 500.0 / (lightDistance + 500.0);\n\n LightResult result = light(lightVector);\n diffuse += result.diffuse * falloff * uPointLightColor[k];\n specular += result.specular * falloff;\n }\n\n gl_FragColor = isTexture ? texture2D(uSampler, vTexCoord) : uMaterialColor;\n gl_FragColor.rgb = gl_FragColor.rgb * (diffuse * diffuseFactor + vAmbientColor) + specular * specularFactor;\n}", 81181 fontVert: "precision mediump float;\n\nattribute vec3 aPosition;\nattribute vec2 aTexCoord;\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\n\nuniform vec4 uGlyphRect;\nuniform float uGlyphOffset;\n\nvarying vec2 vTexCoord;\nvarying float w;
81181\n\nvoid main() {\n vec4 positionVec4 = vec4(aPosition, 1.0);\n\n // scale by the size of the glyph's rectangle\n positionVec4.xy *= uGlyphRect.zw - uGlyphRect.xy;\n\n // move to the corner of the glyph\n positionVec4.xy += uGlyphRect.xy;\n\n // move to the letter's line offset\n positionVec4.x += uGlyphOffset;\n \n gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n vTexCoord = aTexCoord;\n w = gl_Position.w;\n}\n", 81182 fontFrag: "#extension GL_OES_standard_derivatives : enable\nprecision mediump float;\n\n#if 0\n // simulate integer math using floats\n\t#define int float\n\t#define ivec2 vec2\n\t#define INT(x) float(x)\n\n\tint ifloor(float v) { return floor(v); }\n\tivec2 ifloor(vec2 v) { return floor(v); }\n\n#else\n // use native integer math\n\tprecision mediump int;\n\t#define INT(x) x\n\n\tint ifloor(float v) { return int(v); }\n\tint ifloor(int v) { return v; }\n\tivec2 ifloor(vec2 v) { return ivec2(v); }\n\n#endif\n\nuniform sampler2D uSamplerStrokes;\nuniform sampler2D uSamplerRowStrokes;\nuniform sampler2D uSamplerRows;\nuniform sampler2D uSamplerColStrokes;\nuniform sampler2D uSamplerCols;\n\nuniform ivec2 uStrokeImageSize;\nuniform ivec2 uCellsImageSize;\nuniform ivec2 uGridImageSize;\n\nuniform ivec2 uGridOffset;\nuniform ivec2 uGridSize;\nuniform vec4 uMaterialColor;\n\nvarying vec2 vTexCoord;\n\n// some helper functions\nint round(float v) { return ifloor(v + 0.5); }\nivec2 round(vec2 v) { return ifloor(v + 0.5); }\nfloat saturate(float v) { return clamp(v, 0.0, 1.0); }\nvec2 saturate(vec2 v) { return clamp(v, 0.0, 1.0); }\n\nint mul(float v1, int v2) {\n return ifloor(v1 * float(v2));\n}\n\nivec2 mul(vec2 v1, ivec2 v2) {\n return ifloor(v1 * vec2(v2) + 0.5);\n}\n\n// unpack a 16-bit integer from a float vec2\nint getInt16(vec2 v) {\n ivec2 iv = round(v * 255.0);\n return iv.x * INT(128) + iv.y;\n}\n\nvec2 pixelScale;\nvec2 coverage = vec2(0.0);\nvec2 weight = vec2(0.5);\nconst float minDistance = 1.0/8192.0;\nconst float hardness = 1.05; // amount of antialias\n\n// the maximum number of curves in a glyph\nconst int N = INT(250);\n\n// retrieves an indexed pixel from a sampler\nvec4 getTexel(sampler2D sampler, int pos, ivec2 size) {\n int width = size.x;\n int y = ifloor(pos / width);\n int x = pos - y * width; // pos % width\n\n return texture2D(sampler, (vec2(x, y) + 0.5) / vec2(size));\n}\n\nvoid calulateCrossings(vec2 p0, vec2 p1, vec2 p2, out vec2 C1, out vec2 C2) {\n\n // get the coefficients of the quadratic in t\n vec2 a = p0 - p1 * 2.0 + p2;\n vec2 b = p0 - p1;\n vec2 c = p0 - vTexCoord;\n\n // found out which values of 't' it crosses the axes\n vec2 surd = sqrt(max(vec2(0.0), b * b - a * c));\n vec2 t1 = ((b - surd) / a).yx;\n vec2 t2 = ((b + surd) / a).yx;\n\n // approximate straight lines to avoid rounding errors\n if (abs(a.y) < 0.001)\n t1.x = t2.x = c.y / (2.0 * b.y);\n\n if (abs(a.x) < 0.001)\n t1.y = t2.y = c.x / (2.0 * b.x);\n\n // plug into quadratic formula to find the corrdinates of the crossings\n C1 = ((a * t1 - b * 2.0) * t1 + c) * pixelScale;\n C2 = ((a * t2 - b * 2.0) * t2 + c) * pixelScale;\n}\n\nvoid coverageX(vec2 p0, vec2 p1, vec2 p2) {\n\n vec2 C1, C2;\n calulateCrossings(p0, p1, p2, C1, C2);\n\n // determine on which side of the x-axis the points lie\n bool y0 = p0.y > vTexCoord.y;\n bool y1 = p1.y > vTexCoord.y;\n bool y2 = p2.y > vTexCoord.y;\n\n // could web be under the curve (after t1)?\n if (y1 ? !y2 : y0) {\n // add the coverage for t1\n coverage.x += saturate(C1.x + 0.5);\n // calculate the anti-aliasing for t1\n weight.x = min(weight.x, abs(C1.x));\n }\n\n // are we outside the curve (after t2)?\n if (y1 ? !y0 : y2) {\n // subtract the coverage for t2\n coverage.x -= saturate(C2.x + 0.5);\n // calculate the anti-aliasing for t2\n weight.x = min(weight.x, abs(C2.x));\n }\n}\n\n// this is essentially the same as coverageX, but with the axes swapped\nvoid coverageY(vec2 p0, vec2 p1, vec2 p2) {\n\n vec2 C1, C2;\n calulateCrossings(p0, p1, p2, C1, C2);\n\n bool x0 = p0.x > vTexCoord.x;\n bool x1 = p1.x > vTexCoord.x;\n bool x2 = p2.x > vTexCoord.x;
81182\n\n if (x1 ? !x2 : x0) {\n coverage.y -= saturate(C1.y + 0.5);\n weight.y = min(weight.y, abs(C1.y));\n }\n\n if (x1 ? !x0 : x2) {\n coverage.y += saturate(C2.y + 0.5);\n weight.y = min(weight.y, abs(C2.y));\n }\n}\n\nvoid main() {\n\n // calculate the pixel scale based on screen-coordinates\n pixelScale = hardness / fwidth(vTexCoord);\n\n // which grid cell is this pixel in?\n ivec2 gridCoord = ifloor(vTexCoord * vec2(uGridSize));\n\n // intersect curves in this row\n {\n // the index into the row info bitmap\n int rowIndex = gridCoord.y + uGridOffset.y;\n // fetch the info texel\n vec4 rowInfo = getTexel(uSamplerRows, rowIndex, uGridImageSize);\n // unpack the rowInfo\n int rowStrokeIndex = getInt16(rowInfo.xy);\n int rowStrokeCount = getInt16(rowInfo.zw);\n\n for (int iRowStroke = INT(0); iRowStroke < N; iRowStroke++) {\n if (iRowStroke >= rowStrokeCount)\n break;\n\n // each stroke is made up of 3 points: the start and control point\n // and the start of the next curve.\n // fetch the indices of this pair of strokes:\n vec4 strokeIndices = getTexel(uSamplerRowStrokes, rowStrokeIndex++, uCellsImageSize);\n\n // unpack the stroke index\n int strokePos = getInt16(strokeIndices.xy);\n\n // fetch the two strokes\n vec4 stroke0 = getTexel(uSamplerStrokes, strokePos + INT(0), uStrokeImageSize);\n vec4 stroke1 = getTexel(uSamplerStrokes, strokePos + INT(1), uStrokeImageSize);\n\n // calculate the coverage\n coverageX(stroke0.xy, stroke0.zw, stroke1.xy);\n }\n }\n\n // intersect curves in this column\n {\n int colIndex = gridCoord.x + uGridOffset.x;\n vec4 colInfo = getTexel(uSamplerCols, colIndex, uGridImageSize);\n int colStrokeIndex = getInt16(colInfo.xy);\n int colStrokeCount = getInt16(colInfo.zw);\n \n for (int iColStroke = INT(0); iColStroke < N; iColStroke++) {\n if (iColStroke >= colStrokeCount)\n break;\n\n vec4 strokeIndices = getTexel(uSamplerColStrokes, colStrokeIndex++, uCellsImageSize);\n\n int strokePos = getInt16(strokeIndices.xy);\n vec4 stroke0 = getTexel(uSamplerStrokes, strokePos + INT(0), uStrokeImageSize);\n vec4 stroke1 = getTexel(uSamplerStrokes, strokePos + INT(1), uStrokeImageSize);\n coverageY(stroke0.xy, stroke0.zw, stroke1.xy);\n }\n }\n\n weight = saturate(1.0 - weight * 2.0);\n float distance = max(weight.x + weight.y, minDistance); // manhattan approx.\n float antialias = abs(dot(coverage, weight) / distance);\n float cover = min(abs(coverage.x), abs(coverage.y));\n gl_FragColor = uMaterialColor;\n gl_FragColor.a *= saturate(max(antialias, cover));\n}", 81183 lineVert: "/*\n Part of the Processing project - http://processing.org\n Copyright (c) 2012-15 The Processing Foundation\n Copyright (c) 2004-12 Ben Fry and Casey Reas\n Copyright (c) 2001-04 Massachusetts Institute of Technology\n This library is free software; you can redistribute it and/or\n modify it under the terms of the GNU Lesser General Public\n License as published by the Free Software Foundation, version 2.1.\n This library is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n Lesser General Public License for more details.\n You should have received a copy of the GNU Lesser General\n Public License along with this library; if not, write to the\n Free Software Foundation, Inc., 59 Temple Place, Suite 330,\n Boston, MA 02111-1307 USA\n*/\n\n#define PROCESSING_LINE_SHADER\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform float uStrokeWeight;\n\nuniform vec4 uViewport;\n\n// using a scale <1 moves the lines towards the camera\n// in order to prevent popping effects due to half of\n// the line disappearing behind the geometry faces.\nvec3 scale = vec3(0.9995);\n\nattribute vec4 aPosition;\nattribute vec4 aDirection;\n \nvoid main() {\n vec4 posp = uModelViewMatrix * aPosition;\n vec4 posq = uModelViewMatrix * (aPosition + vec4(aDirection.xyz, 0));\n\n // Moving vertices slightly toward the camera\n // to avoid depth-fighting with the fill triangles.\n // Discussed here:\n // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=252848 \n posp.xyz = posp.xyz * scale;\n posq.xyz = posq.xyz * scale;\n\n vec4 p = uProjectionMatrix * posp;\n vec4 q = uProjectionMatrix * posq;\n\n // formula to convert from clip space (range -1..1) to screen space (range 0..[width or height])\n // screen_p = (p.xy/p.w + <1,1>) * 0.5 * uViewport.zw\n\n // prevent division by W by transforming the tangent formula (div by 0 causes\n // the line to disappear, see https://github.com/processing/processing/issues/5183)\n // t = screen_q - screen_p\n //\n // tangent is normalized and we don't care which aDirection it points to (+-)\n // t = +- normalize( screen_q - screen_p )\n // t = +- normalize( (q.xy/q.w+<1,1>)*0.5*uViewport.zw - (p.xy/p.w+<1,1>)*0.5*uViewport.zw )\n //\n // extract common factor, <1,1> - <1,1> cancels out\n // t = +- normalize( (q.xy/q.w - p.xy/p.w) * 0.5 * uViewport.zw )\n //\n // convert to common divisor\n // t = +- normalize( ((q.xy*p.w - p.xy*q.w) / (p.w*q.w)) * 0.5 * uViewport.zw )\n //\n // remove the common scalar divisor/factor, not needed due to normalize and +-\n // (keep uViewport - can't remove because it has different c
81183omponents for x and y\n // and corrects for aspect ratio, see https://github.com/processing/processing/issues/5181)\n // t = +- normalize( (q.xy*p.w - p.xy*q.w) * uViewport.zw )\n\n vec2 tangent = normalize((q.xy*p.w - p.xy*q.w) * uViewport.zw);\n\n // flip tangent to normal (it's already normalized)\n vec2 normal = vec2(-tangent.y, tangent.x);\n\n float thickness = aDirection.w * uStrokeWeight;\n vec2 offset = normal * thickness / 2.0;\n\n // Perspective ---\n // convert from world to clip by multiplying with projection scaling factor\n // to get the right thickness (see https://github.com/processing/processing/issues/5182)\n // invert Y, projections in Processing invert Y\n vec2 perspScale = (uProjectionMatrix * vec4(1, -1, 0, 0)).xy;\n\n // No Perspective ---\n // multiply by W (to cancel out division by W later in the pipeline) and\n // convert from screen to clip (derived from clip to screen above)\n vec2 noPerspScale = p.w / (0.5 * uViewport.zw);\n\n //gl_Position.xy = p.xy + offset.xy * mix(noPerspScale, perspScale, float(perspective > 0));\n gl_Position.xy = p.xy + offset.xy * perspScale;\n gl_Position.zw = p.zw;\n}\n", 81184 lineFrag: "precision mediump float;\nprecision mediump int;\n\nuniform vec4 uMaterialColor;\n\nvoid main() {\n gl_FragColor = uMaterialColor;\n}", 81185 pointVert: "attribute vec3 aPosition;\nuniform float uPointSize;\nvarying float vStrokeWeight;\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;
81185\nvoid main() {\n\tvec4 positionVec4 = vec4(aPosition, 1.0);\n\tgl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n\tgl_PointSize = uPointSize;\n\tvStrokeWeight = uPointSize;\n}", 81186 pointFrag: "precision mediump float;\nprecision mediump int;\nuniform vec4 uMaterialColor;\nvarying float vStrokeWeight;\n\nvoid main(){\n\tfloat mask = 0.0;\n\n\t// make a circular mask using the gl_PointCoord (goes from 0 - 1 on a point)\n // might be able to get a nicer edge on big strokeweights with smoothstep but slightly less performant\n\n\tmask = step(0.98, length(gl_PointCoord * 2.0 - 1.0));\n\n\t// if strokeWeight is 1 or less lets just draw a square\n\t// this prevents weird artifacting from carving circles when our points are really small\n\t// if strokeWeight is larger than 1, we just use it as is\n\n\tmask = mix(0.0, mask, clamp(floor(vStrokeWeight - 0.5),0.0,1.0));\n\n\t// throw away the borders of the mask\n // otherwise we get weird alpha blending issues\n\n\tif(mask > 0.98){\n discard;\n \t}\n\n \tgl_FragColor = vec4(uMaterialColor.rgb * (1.0 - mask), uMaterialColor.a) ;\n}" 81187 }; 81188 /** 81189 * 3D graphics class 81190 * @private 81191 * @class p5.RendererGL 81192 * @constructor 81193 * @extends p5.Renderer 81194 * @todo extend class to include public method for offscreen 81195 * rendering (FBO). 81196 * 81197 */ 81198 81199 p5.RendererGL = function (elt, pInst, isMainCanvas, attr) { 81200 p5.Renderer.call(this, elt, pInst, isMainCanvas); 81201 this.attributes = {}; 81202 attr = attr || {}; 81203 this.attributes.alpha = attr.alpha === undefined ? true : attr.alpha; 81204 this.attributes.depth = attr.depth === undefined ? true : attr.depth; 81205 this.attributes.stencil = attr.stencil === undefined ? true : attr.stencil; 81206 this.attributes.antialias = attr.antialias === undefined ? false : attr.antialias; 81207 this.attributes.premultipliedAlpha = attr.premultipliedAlpha === undefined ? false : attr.premultipliedAlpha; 81208 this.attributes.preserveDrawingBuffer = attr.preserveDrawingBuffer === undefined ? true : attr.preserveDrawingBuffer; 81209 this.attributes.perPixelLighting = attr.perPixelLighting === undefined ? false : attr.perPixelLighting; 81210 81211 this._initContext(); 81212 81213 this.isP3D = true; //lets us know we're in 3d mode 81214 81215 this.GL = this.drawingContext; // lights 81216 81217 this.ambientLightColors = []; 81218 this.directionalLightDirections = []; 81219 this.directionalLightColors = []; 81220 this.pointLightPositions = []; 81221 this.pointLightColors = []; 81222 /** 81223 * model view, projection, & normal 81224 * matrices 81225 */ 81226 81227 this.uMVMatrix = new p5.Matrix(); 81228 this.uPMatrix = new p5.Matrix(); 81229 this.uNMatrix = new p5.Matrix('mat3'); // Camera 81230 81231 this._curCamera = new p5.Camera(this); 81232 81233 this._curCamera._computeCameraDefaultSettings(); 81234 81235 this._curCamera._setDefaultCamera(); //Geometry & Material hashes 81236 81237 81238 this.gHash = {}; 81239 this._defaultLightShader = undefined; 81240 this._defaultImmediateModeShader = undefined; 81241 this._defaultNormalShader = undefined; 81242 this._defaultColorShader = undefined; 81243 this._defaultPointShader = undefined; 81244 this.curFillShader = undefined; 81245 this.curStrokeShader = undefined; 81246 this.curPointShader = undefined; 81247 81248 this._useColorShader(); 81249 81250 this.setStrokeShader(this._getLineShader()); 81251 81252 this._usePointShader(); 81253 81254 this._pointVertexBuffer = this.GL.createBuffer(); //Imediate Mode 81255 //default drawing is done in Retained Mode 81256 81257 this.isImmediateDrawing = false; 81258 this.immediateMode = {}; // note: must call fill() and stroke () AFTER 81259 // default shader has been set. 81260 81261 this.fill(255, 255, 255, 255); //this.stroke(0, 0, 0, 255); 81262 81263 this.pointSize = 5.0; //default point size 81264 81265 this.strokeWeight(1); 81266 this.stroke(0, 0, 0); // array of textures created in this gl context via this.getTexture(src) 81267 81268 this.textures = []; 81269 this.textureImage = undefined; 81270 this.textureMode = constants.IMAGE; 81271 this._curveTightness = 6; // lookUpTable for coefficients needed to be calculated for bezierVertex, same are used for curveVertex 81272 81273 this._lookUpTableBezier = []; // lookUpTable for coefficients needed to be calculated for quadraticVertex 81274 81275 this._lookUpTableQuadratic = []; // current curveDetail in the Bezier lookUpTable 81276 81277 this._lutBezierDetail = 0; // current curveDetail in the Quadratic lookUpTable 81278 81279 this._lutQuadraticDetail = 0; 81280 this._tessy = this._initTessy(); 81281 this.fontInfos = {}; 81282 return this; 81283 }; 81284 81285 p5.RendererGL.prototype = Object.create(p5.Renderer.prototype); ////////////////////////////////////////////// 81286 // Setting
81287 ////////////////////////////////////////////// 81288 81289 p5.RendererGL.prototype._initContext = function () { 81290 try { 81291 this.drawingContext = this.canvas.getContext('webgl', this.attributes) || this.canvas.getContext('experimental-webgl', this.attributes); 81292 81293 if (this.drawingContext === null) { 81294 throw new Error('Error creating webgl context'); 81295 } else { 81296 console.log('p5.RendererGL: enabled webgl context'); 81297 var gl = this.drawingContext; 81298 gl.enable(gl.DEPTH_TEST); 81299 gl.depthFunc(gl.LEQUAL); 81300 gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); 81301 this._viewport = this.drawingContext.getParameter(this.drawingContext.VIEWPORT); 81302 } 81303 } catch (er) { 81304 throw er; 81305 } 81306 }; //This is helper function to reset the context anytime the attributes 81307 //are changed with setAttributes() 81308 81309 81310 p5.RendererGL.prototype._resetContext = function (attr, options, callback) { 81311 var w = this.width; 81312 var h = this.height; 81313 var defaultId = this.canvas.id; 81314 var c = this.canvas; 81315 81316 if (c) { 81317 c.parentNode.removeChild(c); 81318 } 81319 81320 c = document.createElement('canvas'); 81321 c.id = defaultId; 81322 81323 if (this._pInst._userNode) { 81324 this._pInst._userNode.appendChild(c); 81325 } else { 81326 document.body.appendChild(c); 81327 } 81328 81329 this._pInst.canvas = c; 81330 var renderer = new p5.RendererGL(this._pInst.canvas, this._pInst, true, attr); 81331 81332 this._pInst._setProperty('_renderer', renderer); 81333 81334 renderer.resize(w, h); 81335 81336 renderer._applyDefaults(); 81337 81338 this._pInst._elements.push(renderer); 81339 81340 if (typeof callback === 'function') { 81341 //setTimeout with 0 forces the task to the back of the queue, this ensures that 81342 //we finish switching out the renderer 81343 setTimeout(function () { 81344 callback.apply(window._renderer, options); 81345 }, 0); 81346 } 81347 }; 81348 /** 81349 * @module Rendering 81350 * @submodule Rendering 81351 * @for p5 81352 */ 81353 81354 /** 81355 * Set attributes for the WebGL Drawing context. 81356 * This is a way of adjusting ways that the WebGL 81357 * renderer works to fine-tune the display and performance. 81358 * This should be put in setup(). 81359 * The available attributes are: 81360 * <br> 81361 * alpha - indicates if the canvas contains an alpha buffer 81362 * default is true 81363 * <br><br> 81364 * depth - indicates whether the drawing buffer has a depth buffer 81365 * of at least 16 bits - default is true 81366 * <br><br> 81367 * stencil - indicates whether the drawing buffer has a stencil buffer 81368 * of at least 8 bits 81369 * <br><br> 81370 * antialias - indicates whether or not to perform anti-aliasing 81371 * default is false 81372 * <br><br> 81373 * premultipliedAlpha - indicates that the page compositor will assume 81374 * the drawing buffer contains colors with pre-multiplied alpha 81375 * default is false 81376 * <br><br> 81377 * preserveDrawingBuffer - if true the buffers will not be cleared and 81378 * and will preserve their values until cleared or overwritten by author 81379 * (note that p5 clears automatically on draw loop) 81380 * default is true 81381 * <br><br> 81382 * perPixelLighting - if true, per-pixel lighting will be used in the 81383 * lighting shader. 81384 * default is false 81385 * <br><br> 81386 * @method setAttributes 81387 * @for p5 81388 * @param {String} key Name of attribute 81389 * @param {Boolean} value New value of named attribute 81390 * @example 81391 * <div> 81392 * <code> 81393 * function setup() { 81394 * createCanvas(100, 100, WEBGL); 81395 * } 81396 * 81397 * function draw() { 81398 * background(255); 81399 * push(); 81400 * rotateZ(frameCount * 0.02); 81401 * rotateX(frameCount * 0.02); 81402 * rotateY(frameCount * 0.02); 81403 * fill(0, 0, 0); 81404 * box(50); 81405 * pop(); 81406 * } 81407 * </code> 81408 * </div> 81409 * <br> 81410 * Now with the antialias attribute set to true. 81411 * <br> 81412 * <div> 81413 * <code> 81414 * function setup() { 81415 * createCanvas(100, 100, WEBGL); 81416 * setAttributes('antialias', true); 81417 * } 81418 * 81419 * function draw() { 81420 * background(255); 81421 * push(); 81422 * rotateZ(frameCount * 0.02); 81423 * rotateX(frameCount * 0.02); 81424 * rotateY(frameCount * 0.02); 81425 * fill(0, 0, 0); 81426 * box(50); 81427 * pop(); 81428 * } 81429 * </code> 81430 * </div> 81431 * 81432 * <div> 81433 * <code> 81434 * // press the mouse button to enable perPixelLighting 81435 * function setup() { 81436 * createCanvas(100, 100, WEBGL); 81437 * noStroke(); 81438 * fill(255); 81439 * } 81440 * 81441 * var lights = [ 81442 * { c: '#f00', t: 1.12, p: 1.91, r: 0.2 }, 81443 * { c: '#0f0', t: 1.21, p: 1.31, r: 0.2 }, 81444 * { c: '#00f', t: 1.37, p: 1.57, r: 0.2 }, 81445 * { c: '#ff0', t: 1.12, p: 1.91, r: 0.7 }, 81446 * { c: '#0ff', t: 1.21, p: 1.31, r: 0.7 }, 81447 * { c: '#f0f', t: 1.37, p: 1.57, r: 0.7 } 81448 * ]; 81449 * 81450 * function draw() { 81451 * var t = millis() / 1000 + 1000; 81452 * background(0); 81453 * directionalLight(color('#222'), 1, 1, 1); 81454 * 81455 * for (var i = 0; i < lights.length; i++) { 81456 * var light = lights[i]; 81457 * pointLight( 81458 * color(light.c), 81459 * p5.Vector.fromAngles(t * light.t, t * light.p, width * light.r) 81460 * ); 81461 * } 81462 * 81463 * specularMaterial(255); 81464 * sphere(width * 0.1); 81465 * 81466 * rotateX(t * 0.77); 81467 * rotateY(t * 0.83); 81468 * rotateZ(t * 0.91); 81469 * torus(width * 0.3, width * 0.07, 24, 10); 81470 * } 81471 * 81472 * function mousePressed() { 81473 * setAttributes('perPixelLighting', true); 81474 * noStroke(); 81475 * fill(255); 81476 * } 81477 * function mouseReleased() { 81478 * setAttributes('perPixelLighting', false); 81479 * noStroke(); 81480 * fill(255); 81481 * } 81482 * </code> 81483 * </div> 81484 * 81485 * @alt a rotating cube with smoother edges 81486 */ 81487 81488 /** 81489 * @method setAttributes 81490 * @for p5 81491 * @param {Object} obj object with key-value pairs 81492 */ 81493 81494 81495 p5.prototype.setAttributes = function (key, value) { 81496 this._assert3d('setAttributes'); //@todo_FES 81497 81498 81499 var attr; 81500 81501 if (typeof value !== 'undefined') { 81502 attr = {}; 81503 attr[key] = value; 81504 } else if (key instanceof Object) { 81505 attr = key; 81506 } 81507 81508 this.push(); 81509 81510 this._renderer._resetContext(attr); 81511 81512 this.pop(); 81513 }; 81514 /** 81515 * @class p5.RendererGL 81516 */ 81517 81518 81519 p5.RendererGL.prototype._update = function () { 81520 // reset model view and apply initial camera transform 81521 // (containing only look at info; no projection). 81522 this.uMVMatrix.set(this._curCamera.cameraMatrix.mat4[0], this._curCamera.cameraMatrix.mat4[1], this._curCamera.cameraMatrix.mat4[2], this._curCamera.cameraMatrix.mat4[3], this._curCamera.cameraMatrix.mat4[4], this._curCamera.cameraMatrix.mat4[5], this._curCamera.cameraMatrix.mat4[6], this._curCamera.cameraMatrix.mat4[7], this._curCamera.cameraMatrix.mat4[8], this._curCamera.cameraMatrix.mat4[9], this._curCamera.cameraMatrix.mat4[10], this._curCamera.cameraMatrix.mat4[11], this._curCamera.cameraMatrix.mat4[12], this._curCamera.cameraMatrix.mat4[13], this._curCamera.cameraMatrix.mat4[14], this._curCamera.cameraMatrix.mat4[15]); // reset light data for new frame. 81523 81524 this.ambientLightColors.length = 0; 81525 this.directionalLightDirections.length = 0; 81526 this.directionalLightColors.length = 0; 81527 this.pointLightPositions.length = 0; 81528 this.pointLightColors.length = 0; 81529 }; 81530 /** 81531 * [background description] 81532 */ 81533 81534 81535 p5.RendererGL.prototype.background = function () { 81536 var _col = this._pInst.color.apply(this._pInst, arguments); 81537 81538 var _r = _col.levels[0] / 255; 81539 81540 var _g = _col.levels[1] / 255; 81541 81542 var _b = _col.levels[2] / 255; 81543 81544 var _a = _col.levels[3] / 255; 81545 81546 this.GL.clearColor(_r, _g, _b, _a); 81547 this.GL.depthMask(true); 81548 this.GL.clear(this.GL.COLOR_BUFFER_BIT | this.GL.DEPTH_BUFFER_BIT); 81549 }; //@TODO implement this 81550 // p5.RendererGL.prototype.clear = function() { 81551 //@TODO 81552 // };
81553 ////////////////////////////////////////////// 81554 // COLOR 81555 ////////////////////////////////////////////// 81556 81557 /** 81558 * Basic fill material for geometry with a given color 81559 * @method fill 81560 * @class p5.RendererGL 81561 * @param {Number|Number[]|String|p5.Color} v1 gray value, 81562 * red or hue value (depending on the current color mode), 81563 * or color Array, or CSS color string 81564 * @param {Number} [v2] green or saturation value 81565 * @param {Number} [v3] blue or brightness value 81566 * @param {Number} [a] opacity 81567 * @chainable 81568 * @example 81569 * <div> 81570 * <code> 81571 * function setup() { 81572 * createCanvas(200, 200, WEBGL); 81573 * } 81574 * 81575 * function draw() { 81576 * background(0); 81577 * noStroke(); 81578 * fill(100, 100, 240); 81579 * rotateX(frameCount * 0.01); 81580 * rotateY(frameCount * 0.01); 81581 * box(75, 75, 75); 81582 * } 81583 * </code> 81584 * </div> 81585 * 81586 * @alt 81587 * black canvas with purple cube spinning 81588 * 81589 */ 81590 81591 81592 p5.RendererGL.prototype.fill = function (v1, v2, v3, a) { 81593 //see material.js for more info on color blending in webgl 81594 var color = p5.prototype.color.apply(this._pInst, arguments); 81595 this.curFillColor = color._array; 81596 81597 if (this.isImmediateDrawing) { 81598 this.setFillShader(this._getImmediateModeShader()); 81599 } else { 81600 this.setFillShader(this._getColorShader()); 81601 } 81602 81603 this.drawMode = constants.FILL; 81604 this.curFillShader.setUniform('uMaterialColor', this.curFillColor); 81605 }; 81606 /** 81607 * Basic stroke material for geometry with a given color 81608 * @method stroke 81609 * @param {Number|Number[]|String|p5.Color} v1 gray value, 81610 * red or hue value (depending on the current color mode), 81611 * or color Array, or CSS color string 81612 * @param {Number} [v2] green or saturation value 81613 * @param {Number} [v3] blue or brightness value 81614 * @param {Number} [a] opacity 81615 * @example 81616 * <div> 81617 * <code> 81618 * function setup() { 81619 * createCanvas(200, 200, WEBGL); 81620 * } 81621 * 81622 * function draw() { 81623 * background(0); 81624 * stroke(240, 150, 150); 81625 * fill(100, 100, 240); 81626 * rotateX(frameCount * 0.01); 81627 * rotateY(frameCount * 0.01); 81628 * box(75, 75, 75); 81629 * } 81630 * </code> 81631 * </div> 81632 * 81633 * @alt 81634 * black canvas with purple cube with pink outline spinning 81635 * 81636 */ 81637 81638 81639 p5.RendererGL.prototype.stroke = function (r, g, b, a) { 81640 //@todo allow transparency in stroking currently doesn't have 81641 //any impact and causes problems with specularMaterial 81642 arguments[3] = 255; 81643 var color = p5.prototype.color.apply(this._pInst, arguments); 81644 this.curStrokeColor = color._array; 81645 this.curStrokeShader.setUniform('uMaterialColor', this.curStrokeColor); 81646 this.curPointShader.setUniform('uMaterialColor', color._array); 81647 }; 81648 /** 81649 * Change weight of stroke 81650 * @method strokeWeight 81651 * @param {Number} stroke weight to be used for drawing 81652 * @example 81653 * <div> 81654 * <code> 81655 * function setup() { 81656 * createCanvas(200, 400, WEBGL); 81657 * setAttributes('antialias', true); 81658 * } 81659 * 81660 * function draw() { 81661 * background(0); 81662 * noStroke(); 81663 * translate(0, -100, 0); 81664 * stroke(240, 150, 150); 81665 * fill(100, 100, 240); 81666 * push(); 81667 * strokeWeight(8); 81668 * rotateX(frameCount * 0.01); 81669 * rotateY(frameCount * 0.01); 81670 * sphere(75); 81671 * pop(); 81672 * push(); 81673 * translate(0, 200, 0); 81674 * strokeWeight(1); 81675 * rotateX(frameCount * 0.01); 81676 * rotateY(frameCount * 0.01); 81677 * sphere(75); 81678 * pop(); 81679 * } 81680 * </code> 81681 * </div> 81682 * 81683 * @alt 81684 * black canvas with two purple rotating spheres with pink 81685 * outlines the sphere on top has much heavier outlines, 81686 * 81687 */ 81688 81689 81690 p5.RendererGL.prototype.strokeWeight = function (w) { 81691 if (this.curStrokeWeight !== w) { 81692 this.pointSize = w; 81693 this.curStrokeWeight = w; 81694 this.curStrokeShader.setUniform('uStrokeWeight', w); 81695 this.curPointShader.setUniform('uPointSize', w); 81696 } 81697 }; 81698 /** 81699 * Returns an array of [R,G,B,A] values for any pixel or grabs a section of 81700 * an image. If no parameters are specified, the entire image is returned. 81701 * Use the x and y parameters to get the value of one pixel. Get a section of 81702 * the display window by specifying additional w and h parameters. When 81703 * getting an image, the x and y parameters define the coordinates for the 81704 * upper-left corner of the image, regardless of the current imageMode(). 81705 * <br><br> 81706 * If the pixel requested is outside of the image window, [0,0,0,255] is 81707 * returned. 81708 * <br><br> 81709 * Getting the color of a single pixel with get(x, y) is easy, but not as fast 81710 * as grabbing the data directly from pixels[]. The equivalent statement to 81711 * get(x, y) is using pixels[] with pixel density d 81712 * 81713 * @private 81714 * @method get 81715 * @param {Number} [x] x-coordinate of the pixel 81716 * @param {Number} [y] y-coordinate of the pixel 81717 * @param {Number} [w] width 81718 * @param {Number} [h] height 81719 * @return {Number[]|Color|p5.Image} color of pixel at x,y in array format 81720 * [R, G, B, A] or <a href="#/p5.Image">p5.Image</a> 81721 */ 81722 81723 81724 p5.RendererGL.prototype.get = function (x, y, w, h) { 81725 var ctx = this._pInst || this; 81726 var pd = ctx._pixelDensity; 81727 var sx = x * pd; 81728 var sy = y * pd; 81729 81730 if (w === 1 && h === 1) { 81731 var pixels = new Uint8Array(4); 81732 this.drawingContext.readPixels(sx, sy, 1, 1, this.drawingContext.RGBA, this.drawingContext.UNSIGNED_BYTE, pixels); 81733 return [pixels[0], pixels[1], pixels[2], pixels[3]]; 81734 } else { 81735 //auto constrain the width and height to 81736 //dimensions of the source image 81737 var dw = Math.min(w, ctx.width); 81738 var dh = Math.min(h, ctx.height); 81739 var sw = dw * pd; 81740 var sh = dh * pd; 81741 var region = new p5.Image(dw, dh); 81742 region.canvas.getContext('2d') // not sure this is correct 81743 .drawImage(this.canvas, sx, sy, sw, sh, 0, 0, dw, dh); 81744 return region; 81745 } 81746 }; 81747 /** 81748 * Loads the pixels data for this canvas into the pixels[] attribute. 81749 * Note that updatePixels() and set() do not work. 81750 * Any pixel manipulation must be done directly to the pixels[] array.
81751 * 81752 * @private 81753 * @method loadPixels 81754 * 81755 */ 81756 81757 81758 p5.RendererGL.prototype.loadPixels = function () { 81759 //@todo_FES 81760 if (this.attributes.preserveDrawingBuffer !== true) { 81761 console.log('loadPixels only works in WebGL when preserveDrawingBuffer ' + 'is true.'); 81762 return; 81763 } 81764 81765 var pd = this._pInst._pixelDensity; 81766 var x = 0; 81767 var y = 0; 81768 var w = this.width; 81769 var h = this.height; 81770 w *= pd; 81771 h *= pd; //if there isn't a renderer-level temporary pixels buffer 81772 //make a new one 81773 81774 if (typeof this.pixels === 'undefined') { 81775 this.pixels = new Uint8Array(this.GL.drawingBufferWidth * this.GL.drawingBufferHeight * 4); 81776 } 81777 81778 this.GL.readPixels(x, y, w, h, this.GL.RGBA, this.GL.UNSIGNED_BYTE, this.pixels); 81779 81780 this._pInst._setProperty('pixels', this.pixels); 81781 }; ////////////////////////////////////////////// 81782 // HASH | for geometry 81783 ////////////////////////////////////////////// 81784 81785 81786 p5.RendererGL.prototype.geometryInHash = function (gId) { 81787 return this.gHash[gId] !== undefined; 81788 }; 81789 /** 81790 * [resize description] 81791 * @private 81792 * @param {Number} w [description] 81793 * @param {Number} h [description] 81794 */ 81795 81796 81797 p5.RendererGL.prototype.resize = function (w, h) { 81798 p5.Renderer.prototype.resize.call(this, w, h); 81799 this.GL.viewport(0, 0, this.GL.drawingBufferWidth, this.GL.drawingBufferHeight); 81800 this._viewport = this.GL.getParameter(this.GL.VIEWPORT); 81801 81802 this._curCamera._resize(); //resize pixels buffer 81803 81804 81805 if (typeof this.pixels !== 'undefined') { 81806 this.pixels = new Uint8Array(this.GL.drawingBufferWidth * this.GL.drawingBufferHeight * 4); 81807 } 81808 }; 81809 /** 81810 * clears color and depth buffers 81811 * with r,g,b,a 81812 * @private 81813 * @param {Number} r normalized red val. 81814 * @param {Number} g normalized green val. 81815 * @param {Number} b normalized blue val. 81816 * @param {Number} a normalized alpha val. 81817 */ 81818 81819 81820 p5.RendererGL.prototype.clear = function () { 81821 var _r = arguments[0] || 0; 81822 81823 var _g = arguments[1] || 0; 81824 81825 var _b = arguments[2] || 0; 81826 81827 var _a = arguments[3] || 0; 81828 81829 this.GL.clearColor(_r, _g, _b, _a); 81830 this.GL.clear(this.GL.COLOR_BUFFER_BIT | this.GL.DEPTH_BUFFER_BIT); 81831 }; 81832 /** 81833 * [translate description] 81834 * @private 81835 * @param {Number} x [description] 81836 * @param {Number} y [description] 81837 * @param {Number} z [description] 81838 * @chainable 81839 * @todo implement handle for components or vector as args 81840 */ 81841 81842 81843 p5.RendererGL.prototype.translate = function (x, y, z) { 81844 if (x instanceof p5.Vector) { 81845 z = x.z; 81846 y = x.y; 81847 x = x.x; 81848 } 81849 81850 this.uMVMatrix.translate([x, y, z]); 81851 return this; 81852 }; 81853 /** 81854 * Scales the Model View Matrix by a vector 81855 * @private 81856 * @param {Number | p5.Vector | Array} x [description] 81857 * @param {Number} [y] y-axis scalar 81858 * @param {Number} [z] z-axis scalar 81859 * @chainable 81860 */ 81861 81862 81863 p5.RendererGL.prototype.scale = function (x, y, z) { 81864 this.uMVMatrix.scale(x, y, z); 81865 return this; 81866 }; 81867 81868 p5.RendererGL.prototype.rotate = function (rad, axis) { 81869 if (typeof axis === 'undefined') { 81870 return this.rotateZ(rad); 81871 } 81872 81873 arguments[0] = this._pInst._fromRadians(rad); 81874 p5.Matrix.prototype.rotate.apply(this.uMVMatrix, arguments); 81875 return this; 81876 }; 81877 81878 p5.RendererGL.prototype.rotateX = function (rad) { 81879 this.rotate(rad, 1, 0, 0); 81880 return this; 81881 }; 81882 81883 p5.RendererGL.prototype.rotateY = function (rad) { 81884 this.rotate(rad, 0, 1, 0); 81885 return this; 81886 }; 81887 81888 p5.RendererGL.prototype.rotateZ = function (rad) { 81889 this.rotate(rad, 0, 0, 1); 81890 return this; 81891 }; 81892 81893 p5.RendererGL.prototype.push = function () { 81894 // get the base renderer style 81895 var style = p5.Renderer.prototype.push.apply(this); // add webgl-specific style properties 81896 81897 var properties = style.properties; 81898 properties.uMVMatrix = this.uMVMatrix.copy(); 81899 properties.uPMatrix = this.uPMatrix.copy(); 81900 properties._curCamera = this._curCamera; // make a copy of the current camera for the push state 81901 // this preserves any references stored using 'createCamera' 81902 81903 this._curCamera = this._curCamera.copy(); 81904 return style; 81905 }; 81906 81907 p5.RendererGL.prototype.resetMatrix = function () { 81908 this.uMVMatrix = p5.Matrix.identity(this._pInst); 81909 return this; 81910 }; ////////////////////////////////////////////// 81911 // SHADER
81912 ////////////////////////////////////////////// 81913 81914 /* 81915 * Initializes and uses the specified shader, then returns 81916 * that shader. Note: initialization and resetting the program 81917 * is only used if needed (say, if a new value is provided) 81918 * so it is safe to call this method with the same shader multiple 81919 * times without a signficant performance hit). 81920 * 81921 * @method setFillShader 81922 * @param {p5.Shader} [s] a p5.Shader object 81923 * @return {p5.Shader} the current, updated fill shader 81924 */ 81925 81926 81927 p5.RendererGL.prototype.setFillShader = function (s) { 81928 if (this.curFillShader !== s) { 81929 // only do setup etc. if shader is actually new. 81930 this.curFillShader = s; // safe to do this multiple times; 81931 // init() will bail early if has already been run. 81932 81933 this.curFillShader.init(); //this.curFillShader.useProgram(); 81934 } // always return this.curFillShader, even if no change was made. 81935 81936 81937 return this.curFillShader; 81938 }; 81939 81940 p5.RendererGL.prototype.setPointShader = function (s) { 81941 if (this.curPointShader !== s) { 81942 // only do setup etc. if shader is actually new. 81943 this.curPointShader = s; // safe to do this multiple times; 81944 // init() will bail early if has already been run. 81945 81946 this.curPointShader.init(); 81947 } 81948 81949 return this.curPointShader; 81950 }; 81951 /* 81952 * @method setStrokeShader 81953 * @param {p5.Shader} [s] a p5.Shader object 81954 * @return {p5.Shader} the current, updated stroke shader 81955 */ 81956 81957 81958 p5.RendererGL.prototype.setStrokeShader = function (s) { 81959 if (this.curStrokeShader !== s) { 81960 // only do setup etc. if shader is actually new. 81961 this.curStrokeShader = s; // safe to do this multiple times; 81962 // init() will bail early if has already been run. 81963 81964 this.curStrokeShader.init(); //this.curStrokeShader.useProgram(); 81965 } // always return this.curLineShader, even if no change was made. 81966 81967 81968 return this.curStrokeShader; 81969 }; 81970 /* 81971 * shaders are created and cached on a per-renderer basis, 81972 * on the grounds that each renderer will have its own gl context 81973 * and the shader must be valid in that context. 81974 * 81975 * 81976 */ 81977 81978 81979 p5.RendererGL.prototype._useLightShader = function () { 81980 if (!this.curFillShader || !this.curFillShader.isLightShader()) { 81981 this.setFillShader(this._getLightShader()); 81982 } 81983 81984 return this.curFillShader; 81985 }; 81986 81987 p5.RendererGL.prototype._useColorShader = function () { 81988 // looking at the code within the glsl files, I'm not really 81989 // sure why these are two different shaders. but, they are, 81990 // and if we're drawing in retain mode but the shader is the 81991 // immediate mode one, we need to switch. 81992 // TODO: what if curFillShader is _any_ other shader? 81993 if (!this.curFillShader || this.curFillShader === this._defaultImmediateModeShader) { 81994 // there are different immediate mode and retain mode color shaders. 81995 // if we're using the immediate mode one, we need to switch to 81996 // one that works for retain mode. 81997 this.setFillShader(this._getColorShader()); 81998 } 81999 82000 return this.curFillShader; 82001 }; 82002 82003 p5.RendererGL.prototype._usePointShader = function () { 82004 if (!this.curPointShader) { 82005 this.setPointShader(this._getPointShader()); 82006 } 82007 82008 return this.curPointShader; 82009 }; 82010 82011 p5.RendererGL.prototype._useImmediateModeShader = function () { 82012 // TODO: what if curFillShader is _any_ other shader? 82013 if (!this.curFillShader || this.curFillShader === this._defaultColorShader) { 82014 // this is the fill/stroke shader for retain mode. 82015 // must switch to immediate mode shader before drawing! 82016 this.setFillShader(this._getImmediateModeShader()); // note that if we're using the texture shader... 82017 // this shouldn't change. :) 82018 } 82019 82020 return this.curFillShader; 82021 }; 82022 82023 p5.RendererGL.prototype._getLightShader = function () { 82024 if (!this._defaultLightShader) { 82025 if (this.attributes.perPixelLighting) { 82026 this._defaultLightShader = new p5.Shader(this, defaultShaders.phongVert, defaultShaders.phongFrag); 82027 } else { 82028 this._defaultLightShader = new p5.Shader(this, defaultShaders.lightVert, defaultShaders.lightTextureFrag); 82029 } 82030 } //this.drawMode = constants.FILL; 82031 82032 82033 return this._defaultLightShader; 82034 }; 82035 82036 p5.RendererGL.prototype._getImmediateModeShader = function () { 82037 if (!this._defaultImmediateModeShader) { 82038 this._defaultImmediateModeShader = new p5.Shader(this, defaultShaders.immediateVert, defaultShaders.vertexColorFrag); 82039 } //this.drawMode = constants.FILL; 82040 82041 82042 return this._defaultImmediateModeShader; 82043 }; 82044 82045 p5.RendererGL.prototype._getNormalShader = function () { 82046 if (!this._defaultNormalShader) { 82047 this._defaultNormalShader = new p5.Shader(this, defaultShaders.normalVert, defaultShaders.normalFrag); 82048 } //this.drawMode = constants.FILL; 82049 82050 82051 return this._defaultNormalShader; 82052 }; 82053 82054 p5.RendererGL.prototype._getColorShader = function () { 82055 if (!this._defaultColorShader) { 82056 this._defaultColorShader = new p5.Shader(this, defaultShaders.normalVert, defaultShaders.basicFrag); 82057 } //this.drawMode = constants.FILL; 82058 82059 82060 return this._defaultColorShader; 82061 }; 82062 82063 p5.RendererGL.prototype._getPointShader = function () { 82064 if (!this._defaultPointShader) { 82065 this._defaultPointShader = new p5.Shader(this, defaultShaders.pointVert, defaultShaders.pointFrag); 82066 } 82067 82068 return this._defaultPointShader; 82069 }; 82070 82071 p5.RendererGL.prototype._getLineShader = function () { 82072 if (!this._defaultLineShader) { 82073 this._defaultLineShader = new p5.Shader(this, defaultShaders.lineVert, defaultShaders.lineFrag); 82074 } //this.drawMode = constants.STROKE; 82075 82076 82077 return this._defaultLineShader; 82078 }; 82079 82080 p5.RendererGL.prototype._getFontShader = function () { 82081 if (!this._defaultFontShader) { 82082 this.GL.getExtension('OES_standard_derivatives'); 82083 this._defaultFontShader = new p5.Shader(this, defaultShaders.fontVert, defaultShaders.fontFrag); 82084 } 82085 82086 return this._defaultFontShader; 82087 }; 82088 82089 p5.RendererGL.prototype._getEmptyTexture = function () { 82090 if (!this._emptyTexture) { 82091 // a plain white texture RGBA, full alpha, single pixel. 82092 var im = new p5.Image(1, 1); 82093 im.set(0, 0, 255); 82094 this._emptyTexture = new p5.Texture(this, im); 82095 } 82096 82097 return this._emptyTexture; 82098 }; 82099 82100 p5.RendererGL.prototype.getTexture = function (img) { 82101 var textures = this.textures; 82102 82103 for (var it = 0; it < textures.length; ++it) { 82104 var texture = textures[it]; 82105 if (texture.src === img) return texture; 82106 } 82107 82108 var tex = new p5.Texture(this, img); 82109 this.textures.push(tex); 82110 return tex; 82111 }; //Binds a buffer to the drawing context 82112 //when passed more than two arguments it also updates or initializes 82113 //the data associated with the buffer 82114 82115 82116 p5.RendererGL.prototype._bindBuffer = function (buffer, target, values, type, usage) { 82117 this.GL.bindBuffer(target, buffer); 82118 82119 if (values !== undefined) { 82120 var data = new type(values); 82121 this.GL.bufferData(target, data, usage); 82122 } 82123 }; ////////////////////////// 82124 //// SMOOTHING
82125 ///////////////////////// 82126 82127 82128 p5.RendererGL.prototype.smooth = function () { 82129 if (this.attributes.antialias === false) { 82130 this._pInst.setAttributes('antialias', true); 82131 } 82132 }; 82133 82134 p5.RendererGL.prototype.noSmooth = function () { 82135 if (this.attributes.antialias === true) { 82136 this._pInst.setAttributes('antialias', false); 82137 } 82138 }; /////////////////////////////// 82139 //// UTILITY FUNCTIONS 82140 ////////////////////////////// 82141 82142 /** 82143 * turn a two dimensional array into one dimensional array 82144 * @private 82145 * @param {Array} arr 2-dimensional array 82146 * @return {Array} 1-dimensional array 82147 * [[1, 2, 3],[4, 5, 6]] -> [1, 2, 3, 4, 5, 6] 82148 */ 82149 82150 82151 p5.RendererGL.prototype._flatten = function (arr) { 82152 //when empty, return empty 82153 if (arr.length === 0) { 82154 return []; 82155 } else if (arr.length > 20000) { 82156 //big models , load slower to avoid stack overflow 82157 //faster non-recursive flatten via axelduch 82158 //stackoverflow.com/questions/27266550/how-to-flatten-nested-array-in-javascript 82159 var toString = Object.prototype.toString; 82160 var arrayTypeStr = '[object Array]'; 82161 var result = []; 82162 var nodes = arr.slice(); 82163 var node; 82164 node = nodes.pop(); 82165 82166 do { 82167 if (toString.call(node) === arrayTypeStr) { 82168 nodes.push.apply(nodes, node); 82169 } else { 82170 result.push(node); 82171 } 82172 } while (nodes.length && (node = nodes.pop()) !== undefined); 82173 82174 result.reverse(); // we reverse result to restore the original order 82175 82176 return result; 82177 } else { 82178 //otherwise if model within limits for browser 82179 //use faster recursive loading 82180 return [].concat.apply([], arr); 82181 } 82182 }; 82183 /** 82184 * turn a p5.Vector Array into a one dimensional number array 82185 * @private 82186 * @param {p5.Vector[]} arr an array of p5.Vector 82187 * @return {Number[]} a one dimensional array of numbers 82188 * [p5.Vector(1, 2, 3), p5.Vector(4, 5, 6)] -> 82189 * [1, 2, 3, 4, 5, 6] 82190 */ 82191 82192 82193 p5.RendererGL.prototype._vToNArray = function (arr) { 82194 return this._flatten(arr.map(function (item) { 82195 return [item.x, item.y, item.z]; 82196 })); 82197 }; 82198 /** 82199 * ensures that p5 is using a 3d renderer. throws an error if not. 82200 */ 82201 82202 82203 p5.prototype._assert3d = function (name) { 82204 if (!this._renderer.isP3D) throw new Error(name + "() is only supported in WEBGL mode. If you'd like to use 3D graphics" + ' and WebGL, see https://p5js.org/examples/form-3d-primitives.html' + ' for more information.'); 82205 }; // function to initialize GLU Tesselator 82206 82207 82208 p5.RendererGL.prototype._initTessy = function initTesselator() { 82209 // function called for each vertex of tesselator output 82210 function vertexCallback(data, polyVertArray) { 82211 polyVertArray[polyVertArray.length] = data[0]; 82212 polyVertArray[polyVertArray.length] = data[1]; 82213 polyVertArray[polyVertArray.length] = data[2]; 82214 } 82215 82216 function begincallback(type) { 82217 if (type !== libtess.primitiveType.GL_TRIANGLES) { 82218 console.log('expected TRIANGLES but got type: ' + type); 82219 } 82220 } 82221 82222 function errorcallback(errno) { 82223 console.log('error callback'); 82224 console.log('error number: ' + errno); 82225 } // callback for when segments intersect and must be split 82226 82227 82228 function combinecallback(coords, data, weight) { 82229 return [coords[0], coords[1], coords[2]]; 82230 } 82231 82232 function edgeCallback(flag) {// don't really care about the flag, but need no-strip/no-fan behavior 82233 } 82234 82235 var tessy = new libtess.GluTesselator(); 82236 tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_VERTEX_DATA, vertexCallback); 82237 tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_BEGIN, begincallback); 82238 tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_ERROR, errorcallback); 82239 tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_COMBINE, combinecallback); 82240 tessy.gluTessCallback(libtess.gluEnum.GLU_TESS_EDGE_FLAG, edgeCallback); 82241 return tessy; 82242 }; 82243 82244 p5.RendererGL.prototype._triangulate = function (contours) { 82245 // libtess will take 3d verts and flatten to a plane for tesselation 82246 // since only doing 2d tesselation here, provide z=1 normal to skip 82247 // iterating over verts only to get the same answer. 82248 // comment out to test normal-generation code 82249 this._tessy.gluTessNormal(0, 0, 1); 82250 82251 var triangleVerts = []; 82252 82253 this._tessy.gluTessBeginPolygon(triangleVerts); 82254 82255 for (var i = 0; i < contours.length; i++) { 82256 this._tessy.gluTessBeginContour(); 82257 82258 var contour = contours[i]; 82259 82260 for (var j = 0; j < contour.length; j += 3) { 82261 var coords = [contour[j], contour[j + 1], contour[j + 2]]; 82262 82263 this._tessy.gluTessVertex(coords, coords); 82264 } 82265 82266 this._tessy.gluTessEndContour(); 82267 } // finish polygon 82268 82269 82270 this._tessy.gluTessEndPolygon(); 82271 82272 return triangleVerts; 82273 }; // function to calculate BezierVertex Coefficients 82274 82275 82276 p5.RendererGL.prototype._bezierCoefficients = function (t) { 82277 var t2 = t * t; 82278 var t3 = t2 * t; 82279 var mt = 1 - t; 82280 var mt2 = mt * mt; 82281 var mt3 = mt2 * mt; 82282 return [mt3, 3 * mt2 * t, 3 * mt * t2, t3]; 82283 }; // function to calculate QuadraticVertex Coefficients 82284 82285 82286 p5.RendererGL.prototype._quadraticCoefficients = function (t) { 82287 var t2 = t * t; 82288 var mt = 1 - t; 82289 var mt2 = mt * mt; 82290 return [mt2, 2 * mt * t, t2]; 82291 }; // function to convert Bezier coordinates to Catmull Rom Splines 82292 82293 82294 p5.RendererGL.prototype._bezierToCatmull = function (w) { 82295 var p1 = w[1]; 82296 var p2 = w[1] + (w[2] - w[0]) / this._curveTightness; 82297 var p3 = w[2] - (w[3] - w[1]) / this._curveTightness; 82298 var p4 = w[2]; 82299 var p = [p1, p2, p3, p4]; 82300 return p; 82301 }; 82302 82303 module.exports = p5.RendererGL; 82304 }, {
82305 "../core/constants": 18, 82306 "../core/main": 24, 82307 "../core/p5.Renderer": 27, 82308 "./p5.Camera": 69, 82309 "./p5.Matrix": 71, 82310 "./p5.Shader": 75, 82311 "libtess": 9 82312 }], 82313 75: [function (_dereq_, module, exports) { 82314 /** 82315 * This module defines the p5.Shader class 82316 * @module Lights, Camera 82317 * @submodule Shaders 82318 * @for p5 82319 * @requires core 82320 */ 82321 'use strict'; 82322 82323 var p5 = _dereq_('../core/main'); 82324 /** 82325 * Shader class for WEBGL Mode 82326 * @class p5.Shader 82327 * @param {p5.RendererGL} renderer an instance of p5.RendererGL that 82328 * will provide the GL context for this new p5.Shader 82329 * @param {String} vertSrc source code for the vertex shader (as a string) 82330 * @param {String} fragSrc source code for the fragment shader (as a string) 82331 */ 82332 82333 82334 p5.Shader = function (renderer, vertSrc, fragSrc) { 82335 // TODO: adapt this to not take ids, but rather, 82336 // to take the source for a vertex and fragment shader 82337 // to enable custom shaders at some later date 82338 this._renderer = renderer; 82339 this._vertSrc = vertSrc; 82340 this._fragSrc = fragSrc; 82341 this._vertShader = -1; 82342 this._fragShader = -1; 82343 this._glProgram = 0; 82344 this._loadedAttributes = false; 82345 this.attributes = {}; 82346 this._loadedUniforms = false; 82347 this.uniforms = {}; 82348 this._bound = false; 82349 this.samplers = []; 82350 }; 82351 /** 82352 * Creates, compiles, and links the shader based on its 82353 * sources for the vertex and fragment shaders (provided 82354 * to the constructor). Populates known attributes and 82355 * uniforms from the shader. 82356 * @method init 82357 * @chainable 82358 * @private 82359 */ 82360 82361 82362 p5.Shader.prototype.init = function () { 82363 if (this._glProgram === 0 82364 /* or context is stale? */ 82365 ) { 82366 var gl = this._renderer.GL; // @todo: once custom shading is allowed, 82367 // friendly error messages should be used here to share 82368 // compiler and linker errors. 82369 //set up the shader by 82370 // 1. creating and getting a gl id for the shader program, 82371 // 2. compliling its vertex & fragment sources, 82372 // 3. linking the vertex and fragment shaders 82373 82374 this._vertShader = gl.createShader(gl.VERTEX_SHADER); //load in our default vertex shader 82375 82376 gl.shaderSource(this._vertShader, this._vertSrc); 82377 gl.compileShader(this._vertShader); // if our vertex shader failed compilation? 82378 82379 if (!gl.getShaderParameter(this._vertShader, gl.COMPILE_STATUS)) { 82380 console.error('Yikes! An error occurred compiling the vertex shader:' + gl.getShaderInfoLog(this._vertShader)); 82381 return null; 82382 } 82383 82384 this._fragShader = gl.createShader(gl.FRAGMENT_SHADER); //load in our material frag shader 82385 82386 gl.shaderSource(this._fragShader, this._fragSrc); 82387 gl.compileShader(this._fragShader); // if our frag shader failed compilation? 82388 82389 if (!gl.getShaderParameter(this._fragShader, gl.COMPILE_STATUS)) { 82390 console.error('Darn! An error occurred compiling the fragment shader:' + gl.getShaderInfoLog(this._fragShader)); 82391 return null; 82392 } 82393 82394 this._glProgram = gl.createProgram(); 82395 gl.attachShader(this._glProgram, this._vertShader); 82396 gl.attachShader(this._glProgram, this._fragShader); 82397 gl.linkProgram(this._glProgram); 82398 82399 if (!gl.getProgramParameter(this._glProgram, gl.LINK_STATUS)) { 82400 console.error('Snap! Error linking shader program: ' + gl.getProgramInfoLog(this._glProgram)); 82401 } 82402 82403 this._loadAttributes(); 82404 82405 this._loadUniforms(); 82406 } 82407 82408 return this; 82409 }; 82410 /** 82411 * Queries the active attributes for this shader and loads 82412 * their names and locations into the attributes array. 82413 * @method _loadAttributes 82414 * @private 82415 */ 82416 82417 82418 p5.Shader.prototype._loadAttributes = function () { 82419 if (this._loadedAttributes) { 82420 return; 82421 } 82422 82423 this.attributes = {}; 82424 var gl = this._renderer.GL; 82425 var numAttributes = gl.getProgramParameter(this._glProgram, gl.ACTIVE_ATTRIBUTES); 82426 82427 for (var i = 0; i < numAttributes; ++i) { 82428 var attributeInfo = gl.getActiveAttrib(this._glProgram, i); 82429 var name = attributeInfo.name; 82430 var location = gl.getAttribLocation(this._glProgram, name); 82431 var attribute = {}; 82432 attribute.name = name; 82433 attribute.location = location; 82434 attribute.type = attributeInfo.type; 82435 attribute.size = attributeInfo.size; 82436 this.attributes[name] = attribute; 82437 } 82438 82439 this._loadedAttributes = true; 82440 }; 82441 /** 82442 * Queries the active uniforms for this shader and loads 82443 * their names and locations into the uniforms array. 82444 * @method _loadUniforms 82445 * @private 82446 */ 82447 82448 82449 p5.Shader.prototype._loadUniforms = function () { 82450 if (this._loadedUniforms) { 82451 return; 82452 } 82453 82454 var gl = this._renderer.GL; // Inspect shader and cache uniform info 82455 82456 var numUniforms = gl.getProgramParameter(this._glProgram, gl.ACTIVE_UNIFORMS); 82457 var samplerIndex = 0; 82458 82459 for (var i = 0; i < numUniforms; ++i) { 82460 var uniformInfo = gl.getActiveUniform(this._glProgram, i); 82461 var uniform = {}; 82462 uniform.location = gl.getUniformLocation(this._glProgram, uniformInfo.name); 82463 uniform.size = uniformInfo.size; 82464 var uniformName = uniformInfo.name; //uniforms thats are arrays have their name returned as 82465 //someUniform[0] which is a bit silly so we trim it 82466 //off here. The size property tells us that its an array 82467 //so we dont lose any information by doing this 82468 82469 if (uniformInfo.size > 1) { 82470 uniformName = uniformName.substring(0, uniformName.indexOf('[0]')); 82471 } 82472 82473 uniform.name = uniformName; 82474 uniform.type = uniformInfo.type; 82475 82476 if (uniform.type === gl.SAMPLER_2D) { 82477 uniform.samplerIndex = samplerIndex; 82478 samplerIndex++; 82479 this.samplers.push(uniform); 82480 } 82481 82482 this.uniforms[uniformName] = uniform; 82483 } 82484 82485 this._loadedUniforms = true; 82486 }; 82487 82488 p5.Shader.prototype.compile = function () {// TODO 82489 }; 82490 /** 82491 * initializes (if needed) and binds the shader program. 82492 * @method bindShader 82493 * @private 82494 */ 82495 82496 82497 p5.Shader.prototype.bindShader = function () { 82498 this.init(); 82499 82500 if (!this._bound) { 82501 this.useProgram(); 82502 this._bound = true; 82503 this.bindTextures(); 82504 82505 this._setMatrixUniforms(); 82506 82507 if (this === this._renderer.curStrokeShader) {
82508 this._setViewportUniform(); 82509 } 82510 } 82511 }; 82512 /** 82513 * @method unbindShader 82514 * @chainable 82515 * @private 82516 */ 82517 82518 82519 p5.Shader.prototype.unbindShader = function () { 82520 if (this._bound) { 82521 this.unbindTextures(); //this._renderer.GL.useProgram(0); ?? 82522 82523 this._bound = false; 82524 } 82525 82526 return this; 82527 }; 82528 82529 p5.Shader.prototype.bindTextures = function () { 82530 var gl = this._renderer.GL; 82531 82532 for (var i = 0; i < this.samplers.length; i++) { 82533 var uniform = this.samplers[i]; 82534 var tex = uniform.texture; 82535 82536 if (tex === undefined) { 82537 // user hasn't yet supplied a texture for this slot. 82538 // (or there may not be one--maybe just lighting), 82539 // so we supply a default texture instead. 82540 tex = this._renderer._getEmptyTexture(); 82541 } 82542 82543 gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex); 82544 tex.bindTexture(); 82545 tex.update(); 82546 gl.uniform1i(uniform.location, uniform.samplerIndex); 82547 } 82548 }; 82549 82550 p5.Shader.prototype.updateTextures = function () { 82551 for (var i = 0; i < this.samplers.length; i++) { 82552 var uniform = this.samplers[i]; 82553 var tex = uniform.texture; 82554 82555 if (tex) { 82556 tex.update(); 82557 } 82558 } 82559 }; 82560 82561 p5.Shader.prototype.unbindTextures = function () {// TODO: migrate stuff from material.js here 82562 // - OR - have material.js define this function 82563 }; 82564 82565 p5.Shader.prototype._setMatrixUniforms = function () { 82566 this.setUniform('uProjectionMatrix', this._renderer.uPMatrix.mat4); 82567 this.setUniform('uModelViewMatrix', this._renderer.uMVMatrix.mat4); 82568 this.setUniform('uViewMatrix', this._renderer._curCamera.cameraMatrix.mat4); 82569 82570 if (this === this._renderer.curFillShader) { 82571 this._renderer.uNMatrix.inverseTranspose(this._renderer.uMVMatrix); 82572 82573 this.setUniform('uNormalMatrix', this._renderer.uNMatrix.mat3); 82574 } 82575 }; 82576 82577 p5.Shader.prototype._setViewportUniform = function () { 82578 this.setUniform('uViewport', this._renderer._viewport); 82579 }; 82580 /** 82581 * @method useProgram 82582 * @chainable 82583 * @private 82584 */ 82585 82586 82587 p5.Shader.prototype.useProgram = function () { 82588 var gl = this._renderer.GL; 82589 gl.useProgram(this._glProgram); 82590 return this; 82591 }; 82592 /** 82593 * Wrapper around gl.uniform functions. 82594 * As we store uniform info in the shader we can use that 82595 * to do type checking on the supplied data and call 82596 * the appropriate function. 82597 * @method setUniform 82598 * @chainable 82599 * @param {String} uniformName the name of the uniform in the 82600 * shader program 82601 * @param {Object|Number|Boolean|Number[]} data the data to be associated 82602 * with that uniform; type varies (could be a single numerical value, array, 82603 * matrix, or texture / sampler reference) 82604 */ 82605 82606 82607 p5.Shader.prototype.setUniform = function (uniformName, data) { 82608 //@todo update all current gl.uniformXX calls 82609 var uniform = this.uniforms[uniformName]; 82610 82611 if (!uniform) { 82612 //@todo warning? 82613 return; 82614 } 82615 82616 var location = uniform.location; 82617 var gl = this._renderer.GL; // todo: is this safe to do here? 82618 // todo: store the values another way? 82619 82620 this.useProgram(); // TODO BIND? 82621 82622 switch (uniform.type) { 82623 case gl.BOOL: 82624 if (data === true) { 82625 gl.uniform1i(location, 1); 82626 } else { 82627 gl.uniform1i(location, 0); 82628 } 82629 82630 break; 82631 82632 case gl.INT: 82633 if (uniform.size > 1) { 82634 data.length && gl.uniform1iv(location, data); 82635 } else { 82636 gl.uniform1i(location, data); 82637 } 82638 82639 break; 82640 82641 case gl.FLOAT: 82642 if (uniform.size > 1) { 82643 data.length && gl.uniform1fv(location, data); 82644 } else { 82645 gl.uniform1f(location, data); 82646 } 82647 82648 break; 82649 82650 case gl.FLOAT_MAT3: 82651 gl.uniformMatrix3fv(location, false, data); 82652 break; 82653 82654 case gl.FLOAT_MAT4: 82655 gl.uniformMatrix4fv(location, false, data); 82656 break; 82657 82658 case gl.FLOAT_VEC2: 82659 if (uniform.size > 1) { 82660 data.length && gl.uniform2fv(location, data); 82661 } else { 82662 gl.uniform2f(location, data[0], data[1]); 82663 } 82664 82665 break; 82666 82667 case gl.FLOAT_VEC3: 82668 if (uniform.size > 1) { 82669 data.length && gl.uniform3fv(location, data); 82670 } else { 82671 gl.uniform3f(location, data[0], data[1], data[2]); 82672 } 82673 82674 break; 82675 82676 case gl.FLOAT_VEC4: 82677 if (uniform.size > 1) { 82678 data.length && gl.uniform4fv(location, data); 82679 } else { 82680 gl.uniform4f(location, data[0], data[1], data[2], data[3]); 82681 } 82682 82683 break; 82684 82685 case gl.INT_VEC2: 82686 if (uniform.size > 1) { 82687 data.length && gl.uniform2iv(location, data); 82688 } else { 82689 gl.uniform2i(location, data[0], data[1]); 82690 } 82691 82692 break; 82693 82694 case gl.INT_VEC3: 82695 if (uniform.size > 1) { 82696 data.length && gl.uniform3iv(location, data); 82697 } else { 82698 gl.uniform3i(location, data[0], data[1], data[2]); 82699 } 82700 82701 break; 82702 82703 case gl.INT_VEC4: 82704 if (uniform.size > 1) { 82705 data.length && gl.uniform4iv(location, data); 82706 } else { 82707 gl.uniform4i(location, data[0], data[1], data[2], data[3]); 82708 } 82709 82710 break; 82711 82712 case gl.SAMPLER_2D: 82713 gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex); 82714 uniform.texture = this._renderer.getTexture(data); 82715 gl.uniform1i(uniform.location, uniform.samplerIndex); 82716 break; 82717 //@todo complete all types 82718 } 82719 82720 return this; 82721 }; 82722 /* NONE OF THIS IS FAST OR EFFICIENT BUT BEAR WITH ME 82723 * 82724 * these shader "type" query methods are used by various 82725 * facilities of the renderer to determine if changing
82726 * the shader type for the required action (for example, 82727 * do we need to load the default lighting shader if the 82728 * current shader cannot handle lighting?) 82729 * 82730 **/ 82731 82732 82733 p5.Shader.prototype.isLightShader = function () { 82734 return this.uniforms.uUseLighting !== undefined || this.uniforms.uAmbientLightCount !== undefined || this.uniforms.uDirectionalLightCount !== undefined || this.uniforms.uPointLightCount !== undefined || this.uniforms.uAmbientColor !== undefined || this.uniforms.uDirectionalColor !== undefined || this.uniforms.uPointLightLocation !== undefined || this.uniforms.uPointLightColor !== undefined || this.uniforms.uLightingDirection !== undefined || this.uniforms.uSpecular !== undefined; 82735 }; 82736 82737 p5.Shader.prototype.isTextureShader = function () { 82738 return this.samplerIndex > 0; 82739 }; 82740 82741 p5.Shader.prototype.isColorShader = function () { 82742 return this.attributes.aVertexColor !== undefined || this.uniforms.uMaterialColor !== undefined; 82743 }; 82744 82745 p5.Shader.prototype.isTexLightShader = function () { 82746 return this.isLightShader() && this.isTextureShader(); 82747 }; 82748 82749 p5.Shader.prototype.isStrokeShader = function () { 82750 return this.uniforms.uStrokeWeight !== undefined; 82751 }; 82752 /** 82753 * @method enableAttrib 82754 * @chainable 82755 * @private 82756 */ 82757 82758 82759 p5.Shader.prototype.enableAttrib = function (loc, size, type, normalized, stride, offset) { 82760 var gl = this._renderer.GL; 82761 82762 if (loc !== -1) { 82763 gl.enableVertexAttribArray(loc); 82764 gl.vertexAttribPointer(loc, size, type, normalized, stride, offset); 82765 } 82766 82767 return this; 82768 }; 82769 82770 module.exports = p5.Shader; 82771 }, { 82772 "../core/main": 24 82773 }], 82774 76: [function (_dereq_, module, exports) { 82775 /** 82776 * This module defines the p5.Texture class 82777 * @module Lights, Camera 82778 * @submodule Material 82779 * @for p5 82780 * @requires core 82781 */ 82782 'use strict'; 82783 82784 var p5 = _dereq_('../core/main'); 82785 82786 var constants = _dereq_('../core/constants'); 82787 /** 82788 * Texture class for WEBGL Mode 82789 * @private 82790 * @class p5.Texture 82791 * @param {p5.RendererGL} renderer an instance of p5.RendererGL that 82792 * will provide the GL context for this new p5.Texture 82793 * @param {p5.Image|p5.Graphics|p5.Element|p5.MediaElement|ImageData} [obj] the 82794 * object containing the image data to store in the texture. 82795 */ 82796 82797 82798 p5.Texture = function (renderer, obj) { 82799 this._renderer = renderer; 82800 var gl = this._renderer.GL; 82801 this.src = obj; 82802 this.glTex = undefined; 82803 this.glTarget = gl.TEXTURE_2D; 82804 this.glFormat = gl.RGBA; 82805 this.mipmaps = false; 82806 this.glMinFilter = gl.LINEAR; 82807 this.glMagFilter = gl.LINEAR; 82808 this.glWrapS = gl.CLAMP_TO_EDGE; 82809 this.glWrapT = gl.CLAMP_TO_EDGE; // used to determine if this texture might need constant updating 82810 // because it is a video or gif. 82811 82812 this.isSrcMediaElement = typeof p5.MediaElement !== 'undefined' && obj instanceof p5.MediaElement; 82813 this._videoPrevUpdateTime = 0; 82814 this.isSrcHTMLElement = typeof p5.Element !== 'undefined' && obj instanceof p5.Element && !(obj instanceof p5.Graphics); 82815 this.isSrcP5Image = obj instanceof p5.Image; 82816 this.isSrcP5Graphics = obj instanceof p5.Graphics; 82817 this.isImageData = typeof ImageData !== 'undefined' && obj instanceof ImageData; 82818 82819 var textureData = this._getTextureDataFromSource(); 82820 82821 this.width = textureData.width; 82822 this.height = textureData.height; 82823 this.init(textureData); 82824 return this; 82825 }; 82826 82827 p5.Texture.prototype._getTextureDataFromSource = function () { 82828 var textureData; 82829 82830 if (this.isSrcP5Image) { 82831 // param is a p5.Image 82832 textureData = this.src.canvas; 82833 } else if (this.isSrcMediaElement || this.isSrcP5Graphics || this.isSrcHTMLElement) { 82834 // if param is a video HTML element 82835 textureData = this.src.elt; 82836 } else if (this.isImageData) { 82837 textureData = this.src; 82838 } 82839 82840 return textureData; 82841 }; 82842 /** 82843 * Initializes common texture parameters, creates a gl texture, 82844 * tries to upload the texture for the first time if data is 82845 * already available. 82846 * @private 82847 * @method init 82848 */ 82849 82850 82851 p5.Texture.prototype.init = function (data) { 82852 var gl = this._renderer.GL; 82853 this.glTex = gl.createTexture(); 82854 this.bindTexture(); //gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); 82855 82856 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.glMagFilter); 82857 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.glMinFilter); 82858 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.glWrapS); 82859 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.glWrapT); 82860 82861 if (this.width === 0 || this.height === 0 || this.isSrcMediaElement && !this.src.loadedmetadata) { 82862 // assign a 1x1 empty texture initially, because data is not yet ready, 82863 // so that no errors occur in gl console! 82864 var tmpdata = new Uint8Array([1, 1, 1, 1]); 82865 gl.texImage2D(this.glTarget, 0, gl.RGBA, 1, 1, 0, this.glFormat, gl.UNSIGNED_BYTE, tmpdata); 82866 } else { 82867 // data is ready: just push the texture! 82868 gl.texImage2D(this.glTarget, 0, this.glFormat, this.glFormat, gl.UNSIGNED_BYTE, data); 82869 } 82870 }; 82871 /** 82872 * Checks if the source data for this texture has changed (if it's 82873 * easy to do so) and reuploads the texture if necessary. If it's not 82874 * possible or to expensive to do a calculation to determine wheter or 82875 * not the data has occurred, this method simply re-uploads the texture. 82876 * @method update 82877 */ 82878 82879 82880 p5.Texture.prototype.update = function () { 82881 var data = this.src; 82882 82883 if (data.width === 0 || data.height === 0) { 82884 return false; // nothing to do! 82885 } 82886 82887 var textureData = this._getTextureDataFromSource(); 82888 82889 var updated = false;
82890 var gl = this._renderer.GL; // pull texture from data, make sure width & height are appropriate 82891 82892 if (textureData.width !== this.width || textureData.height !== this.height) { 82893 updated = true; // make sure that if the width and height of this.src have changed 82894 // for some reason, we update our metadata and upload the texture again 82895 82896 this.width = textureData.width; 82897 this.height = textureData.height; 82898 82899 if (this.isSrcP5Image) { 82900 data.setModified(false); 82901 } else if (this.isSrcMediaElement || this.isSrcHTMLElement) { 82902 // on the first frame the metadata comes in, the size will be changed 82903 // from 0 to actual size, but pixels may not be available. 82904 // flag for update in a future frame. 82905 // if we don't do this, a paused video, for example, may not 82906 // send the first frame to texture memory. 82907 data.setModified(true); 82908 } 82909 } else if (this.isSrcP5Image) { 82910 // for an image, we only update if the modified field has been set, 82911 // for example, by a call to p5.Image.set 82912 if (data.isModified()) { 82913 updated = true; 82914 data.setModified(false); 82915 } 82916 } else if (this.isSrcMediaElement) { 82917 // for a media element (video), we'll check if the current time in 82918 // the video frame matches the last time. if it doesn't match, the 82919 // video has advanced or otherwise been taken to a new frame, 82920 // and we need to upload it. 82921 if (data.isModified()) { 82922 // p5.MediaElement may have also had set/updatePixels, etc. called 82923 // on it and should be updated, or may have been set for the first 82924 // time! 82925 updated = true; 82926 data.setModified(false); 82927 } else if (data.loadedmetadata) { 82928 // if the meta data has been loaded, we can ask the video 82929 // what it's current position (in time) is. 82930 if (this._videoPrevUpdateTime !== data.time()) { 82931 // update the texture in gpu mem only if the current 82932 // video timestamp does not match the timestamp of the last 82933 // time we uploaded this texture (and update the time we 82934 // last uploaded, too) 82935 this._videoPrevUpdateTime = data.time(); 82936 updated = true; 82937 } 82938 } 82939 } else if (this.isImageData) { 82940 if (data._dirty) { 82941 data._dirty = false; 82942 updated = true; 82943 } 82944 } else { 82945 /* data instanceof p5.Graphics, probably */ 82946 // there is not enough information to tell if the texture can be 82947 // conditionally updated; so to be safe, we just go ahead and upload it. 82948 updated = true; 82949 } 82950 82951 if (updated) { 82952 this.bindTexture(); 82953 gl.texImage2D(this.glTarget, 0, this.glFormat, this.glFormat, gl.UNSIGNED_BYTE, textureData); 82954 } 82955 82956 return updated; 82957 }; 82958 /** 82959 * Binds the texture to the appropriate GL target. 82960 * @method bindTexture 82961 */ 82962 82963 82964 p5.Texture.prototype.bindTexture = function () { 82965 // bind texture using gl context + glTarget and 82966 // generated gl texture object 82967 var gl = this._renderer.GL; 82968 gl.bindTexture(this.glTarget, this.glTex); 82969 return this; 82970 }; 82971 /** 82972 * Unbinds the texture from the appropriate GL target. 82973 * @method unbindTexture 82974 */ 82975 82976 82977 p5.Texture.prototype.unbindTexture = function () { 82978 // unbind per above, disable texturing on glTarget 82979 var gl = this._renderer.GL; 82980 gl.bindTexture(this.glTarget, null); 82981 }; 82982 /**
82983 * Sets how a texture is be interpolated when upscaled or downscaled. 82984 * Nearest filtering uses nearest neighbor scaling when interpolating 82985 * Linear filtering uses WebGL's linear scaling when interpolating 82986 * @method setInterpolation 82987 * @param {String} downScale Specifies the texture filtering when 82988 * textures are shrunk. Options are LINEAR or NEAREST 82989 * @param {String} upScale Specifies the texture filtering when 82990 * textures are magnified. Options are LINEAR or NEAREST 82991 * @todo implement mipmapping filters 82992 */ 82993 82994 82995 p5.Texture.prototype.setInterpolation = function (downScale, upScale) { 82996 var gl = this._renderer.GL; 82997 82998 if (downScale === constants.NEAREST) { 82999 this.glMinFilter = gl.NEAREST; 83000 } else { 83001 this.glMinFilter = gl.LINEAR; 83002 } 83003 83004 if (upScale === constants.NEAREST) { 83005 this.glMagFilter = gl.NEAREST; 83006 } else { 83007 this.glMagFilter = gl.LINEAR; 83008 } 83009 83010 this.bindTexture(); 83011 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.glMinFilter); 83012 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.glMagFilter); 83013 this.unbindTexture(); 83014 }; 83015 /** 83016 * Sets the texture wrapping mode. This controls how textures behave 83017 * when their uv's go outside of the 0 - 1 range. There are three options: 83018 * CLAMP, REPEAT, and MIRROR. REPEAT & MIRROR are only available if the texture 83019 * is a power of two size (128, 256, 512, 1024, etc.). 83020 * @method setWrapMode 83021 * @param {String} wrapX Controls the horizontal texture wrapping behavior 83022 * @param {String} wrapY Controls the vertical texture wrapping behavior 83023 */ 83024 83025 83026 p5.Texture.prototype.setWrapMode = function (wrapX, wrapY) { 83027 var gl = this._renderer.GL; // for webgl 1 we need to check if the texture is power of two 83028 // if it isn't we will set the wrap mode to CLAMP 83029 // webgl2 will support npot REPEAT and MIRROR but we don't check for it yet 83030 83031 var isPowerOfTwo = function (x) { 83032 return (x & x - 1) === 0; 83033 }; 83034 83035 var widthPowerOfTwo = isPowerOfTwo(this.width); 83036 var heightPowerOfTwo = isPowerOfTwo(this.width); 83037 83038 if (wrapX === constants.REPEAT) { 83039 if (widthPowerOfTwo && heightPowerOfTwo) { 83040 this.glWrapS = gl.REPEAT; 83041 } else { 83042 console.warn('You tried to set the wrap mode to REPEAT but the texture size is not a power of two. Setting to CLAMP instead'); 83043 this.glWrapS = gl.CLAMP_TO_EDGE; 83044 } 83045 } else if (wrapX === constants.MIRROR) { 83046 if (widthPowerOfTwo && heightPowerOfTwo) { 83047 this.glWrapS = gl.MIRRORED_REPEAT; 83048 } else { 83049 console.warn('You tried to set the wrap mode to MIRROR but the texture size is not a power of two. Setting to CLAMP instead'); 83050 this.glWrapS = gl.CLAMP_TO_EDGE; 83051 } 83052 } else { 83053 // falling back to default if didn't get a proper mode 83054 this.glWrapS = gl.CLAMP_TO_EDGE; 83055 } 83056 83057 if (wrapY === constants.REPEAT) { 83058 if (widthPowerOfTwo && heightPowerOfTwo) { 83059 this.glWrapT = gl.REPEAT; 83060 } else { 83061 console.warn('You tried to set the wrap mode to REPEAT but the texture size is not a power of two. Setting to CLAMP instead'); 83062 this.glWrapT = gl.CLAMP_TO_EDGE; 83063 } 83064 } else if (wrapY === constants.MIRROR) { 83065 if (widthPowerOfTwo && heightPowerOfTwo) { 83066 this.glWrapT = gl.MIRRORED_REPEAT; 83067 } else { 83068 console.warn('You tried to set the wrap mode to MIRROR but the texture size is not a power of two. Setting to CLAMP instead'); 83069 this.glWrapT = gl.CLAMP_TO_EDGE; 83070 } 83071 } else { 83072 // falling back to default if didn't get a proper mode 83073 this.glWrapT = gl.CLAMP_TO_EDGE; 83074 } 83075 83076 this.bindTexture(); 83077 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.glWrapS); 83078 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.glWrapT); 83079 this.unbindTexture(); 83080 }; 83081 83082 module.exports = p5.Texture; 83083 }, {
83084 "../core/constants": 18, 83085 "../core/main": 24 83086 }], 83087 77: [function (_dereq_, module, exports) { 83088 'use strict'; 83089 83090 var p5 = _dereq_('../core/main'); 83091 83092 var constants = _dereq_('../core/constants'); 83093 83094 _dereq_('./p5.Shader'); 83095 83096 _dereq_('./p5.RendererGL'); // Text/Typography 83097 // @TODO: 83098 83099 83100 p5.RendererGL.prototype._applyTextProperties = function () {//@TODO finish implementation 83101 //console.error('text commands not yet implemented in webgl'); 83102 }; 83103 83104 p5.RendererGL.prototype.textWidth = function (s) { 83105 if (this._isOpenType()) { 83106 return this._textFont._textWidth(s, this._textSize); 83107 } 83108 83109 return 0; // TODO: error 83110 }; // rendering constants 83111 // the number of rows/columns dividing each glyph 83112 83113 83114 var charGridWidth = 9; 83115 var charGridHeight = charGridWidth; // size of the image holding the bezier stroke info 83116 83117 var strokeImageWidth = 64; 83118 var strokeImageHeight = 64; // size of the image holding the stroke indices for each row/col 83119 83120 var gridImageWidth = 64; 83121 var gridImageHeight = 64; // size of the image holding the offset/length of each row/col stripe 83122 83123 var cellImageWidth = 64; 83124 var cellImageHeight = 64; 83125 /** 83126 * @private 83127 * @class ImageInfos 83128 * @param {Integer} width 83129 * @param {Integer} height 83130 * 83131 * the ImageInfos class holds a list of ImageDatas of a given size. 83132 */ 83133 83134 function ImageInfos(width, height) { 83135 this.width = width; 83136 this.height = height; 83137 this.infos = []; // the list of images 83138 83139 /** 83140 * 83141 * @method findImage 83142 * @param {Integer} space 83143 * @return {Object} contains the ImageData, and pixel index into that 83144 * ImageData where the free space was allocated. 83145 * 83146 * finds free space of a given size in the ImageData list 83147 */ 83148 83149 this.findImage = function (space) { 83150 var imageSize = this.width * this.height; 83151 if (space > imageSize) throw new Error('font is too complex to render in 3D'); // search through the list of images, looking for one with 83152 // anough unused space. 83153 83154 var imageInfo, imageData; 83155 83156 for (var ii = this.infos.length - 1; ii >= 0; --ii) { 83157 var imageInfoTest = this.infos[ii]; 83158 83159 if (imageInfoTest.index + space < imageSize) { 83160 // found one 83161 imageInfo = imageInfoTest; 83162 imageData = imageInfoTest.imageData; 83163 break; 83164 } 83165 } 83166 83167 if (!imageInfo) { 83168 try { 83169 // create a new image 83170 imageData = new ImageData(this.width, this.height); 83171 } catch (err) { 83172 // for browsers that don't support ImageData constructors (ie IE11) 83173 // create an ImageData using the old method 83174 var canvas = document.getElementsByTagName('canvas')[0]; 83175 var created = !canvas; 83176 83177 if (!canvas) { 83178 // create a temporary canvas 83179 canvas = document.createElement('canvas'); 83180 canvas.style.display = 'none'; 83181 document.body.appendChild(canvas); 83182 } 83183 83184 var ctx = canvas.getContext('2d'); 83185 83186 if (ctx) { 83187 imageData = ctx.createImageData(this.width, this.height); 83188 } 83189 83190 if (created) { 83191 // distroy the temporary canvas, if necessary 83192 document.body.removeChild(canvas); 83193 } 83194 } // construct & dd the new image info 83195 83196 83197 imageInfo = { 83198 index: 0, 83199 imageData: imageData 83200 }; 83201 this.infos.push(imageInfo); 83202 } 83203 83204 var index = imageInfo.index; 83205 imageInfo.index += space; // move to the start of the next image 83206 83207 imageData._dirty = true; 83208 return { 83209 imageData: imageData, 83210 index: index 83211 }; 83212 }; 83213 } 83214 /** 83215 * @function setPixel 83216 * @param {Object} imageInfo 83217 * @param {Number} r 83218 * @param {Number} g 83219 * @param {Number} b 83220 * @param {Number} a 83221 * 83222 * writes the next pixel into an indexed ImageData 83223 */ 83224 83225 83226 function setPixel(imageInfo, r, g, b, a) { 83227 var imageData = imageInfo.imageData; 83228 var pixels = imageData.data; 83229 var index = imageInfo.index++ * 4; 83230 pixels[index++] = r; 83231 pixels[index++] = g; 83232 pixels[index++] = b; 83233 pixels[index++] = a; 83234 } 83235 83236 var SQRT3 = Math.sqrt(3); 83237 /** 83238 * @private 83239 * @class FontInfo 83240 * @param {Object} font an opentype.js font object 83241 * 83242 * contains cached images and glyph information for an opentype font 83243 */ 83244 83245 var FontInfo = function (font) { 83246 this.font = font; // the bezier curve coordinates 83247 83248 this.strokeImageInfos = new ImageInfos(strokeImageWidth, strokeImageHeight); // lists of curve indices for each row/column slice 83249 83250 this.colDimImageInfos = new ImageInfos(gridImageWidth, gridImageHeight); 83251 this.rowDimImageInfos = new ImageInfos(gridImageWidth, gridImageHeight); // the offset & length of each row/col slice in the glyph 83252 83253 this.colCellImageInfos = new ImageInfos(cellImageWidth, cellImageHeight); 83254 this.rowCellImageInfos = new ImageInfos(cellImageWidth, cellImageHeight); // the cached information for each glyph 83255 83256 this.glyphInfos = {}; 83257 /** 83258 * @method getGlyphInfo 83259 * @param {Glyph} glyph the x positions of points in the curve 83260 * @returns {Object} the glyphInfo for that glyph 83261 * 83262 * calculates rendering info for a glyph, including the curve information, 83263 * row & column stripes compiled into textures. 83264 */ 83265 83266 this.getGlyphInfo = function (glyph) { 83267 // check the cache 83268 var gi = this.glyphInfos[glyph.index]; 83269 if (gi) return gi; // get the bounding box of the glyph from opentype.js 83270 83271 var bb = glyph.getBoundingBox(); 83272 var xMin = bb.x1; 83273 var yMin = bb.y1; 83274 var gWidth = bb.x2 - xMin; 83275 var gHeight = bb.y2 - yMin; 83276 var cmds = glyph.path.commands; // don't bother rendering invisible glyphs 83277 83278 if (gWidth === 0 || gHeight === 0 || !cmds.length) { 83279 return this.glyphInfos[glyph.index] = {}; 83280 } 83281 83282 var i; 83283 var strokes = []; // the strokes in this glyph 83284 83285 var rows = []; // the indices of strokes in each row 83286 83287 var cols = []; // the indices of strokes in each column 83288 83289 for (i = charGridWidth - 1; i >= 0; --i) cols.push([]); 83290 83291 for (i = charGridHeight - 1; i >= 0; --i) rows.push([]); 83292 /** 83293 * @function push 83294 * @param {Number[]} xs the x positions of points in the curve 83295 * @param {Number[]} ys the y positions of points in the curve 83296 * @param {Object} v the curve information 83297 * 83298 * adds a curve to the rows & columns that it intersects with 83299 */ 83300 83301 83302 function push(xs, ys, v) { 83303 var index = strokes.length; // the index of this stroke 83304 83305 strokes.push(v);
83305 // add this stroke to the list 83306 83307 /** 83308 * @function minMax 83309 * @param {Number[]} rg the list of values to compare 83310 * @param {Number} min the initial minimum value 83311 * @param {Number} max the initial maximum value 83312 * 83313 * find the minimum & maximum value in a list of values 83314 */ 83315 83316 function minMax(rg, min, max) { 83317 for (var i = rg.length; i-- > 0;) { 83318 var v = rg[i]; 83319 if (min > v) min = v; 83320 if (max < v) max = v; 83321 } 83322 83323 return { 83324 min: min, 83325 max: max 83326 }; 83327 } // loop through the rows & columns that the curve intersects 83328 // adding the curve to those slices 83329 83330 83331 var mmX = minMax(xs, 1, 0); 83332 var ixMin = Math.max(Math.floor(mmX.min * charGridWidth), 0); 83333 var ixMax = Math.min(Math.ceil(mmX.max * charGridWidth), charGridWidth); 83334 83335 for (var iCol = ixMin; iCol < ixMax; ++iCol) cols[iCol].push(index); 83336 83337 var mmY = minMax(ys, 1, 0); 83338 var iyMin = Math.max(Math.floor(mmY.min * charGridHeight), 0); 83339 var iyMax = Math.min(Math.ceil(mmY.max * charGridHeight), charGridHeight); 83340 83341 for (var iRow = iyMin; iRow < iyMax; ++iRow) rows[iRow].push(index); 83342 } 83343 /** 83344 * @function clamp 83345 * @param {Number} v the value to clamp 83346 * @param {Number} min the minimum value 83347 * @param {Number} max the maxmimum value 83348 * 83349 * clamps a value between a minimum & maximum value 83350 */ 83351 83352 83353 function clamp(v, min, max) { 83354 if (v < min) return min; 83355 if (v > max) return max; 83356 return v; 83357 } 83358 /** 83359 * @function byte 83360 * @param {Number} v the value to scale 83361 * 83362 * converts a floating-point number in the range 0-1 to a byte 0-255 83363 */ 83364 83365 83366 function byte(v) { 83367 return clamp(255 * v, 0, 255); 83368 } 83369 /** 83370 * @private 83371 * @class Cubic 83372 * @param {Number} p0 the start point of the curve 83373 * @param {Number} c0 the first control point 83374 * @param {Number} c1 the second control point 83375 * @param {Number} p1 the end point 83376 * 83377 * a cubic curve 83378 */ 83379 83380 83381 function Cubic(p0, c0, c1, p1) { 83382 this.p0 = p0; 83383 this.c0 = c0; 83384 this.c1 = c1; 83385 this.p1 = p1; 83386 /** 83387 * @method toQuadratic 83388 * @return {Object} the quadratic approximation 83389 * 83390 * converts the cubic to a quadtratic approximation by 83391 * picking an appropriate quadratic control point 83392 */ 83393 83394 this.toQuadratic = function () { 83395 return { 83396 x: this.p0.x, 83397 y: this.p0.y, 83398 x1: this.p1.x, 83399 y1: this.p1.y, 83400 cx: ((this.c0.x + this.c1.x) * 3 - (this.p0.x + this.p1.x)) / 4, 83401 cy: ((this.c0.y + this.c1.y) * 3 - (this.p0.y + this.p1.y)) / 4 83402 }; 83403 }; 83404 /** 83405 * @method quadError 83406 * @return {Number} the error 83407 * 83408 * calculates the magnitude of error of this curve's 83409 * quadratic approximation. 83410 */ 83411 83412 83413 this.quadError = function () { 83414 return p5.Vector.sub(p5.Vector.sub(this.p1, this.p0), p5.Vector.mult(p5.Vector.sub(this.c1, this.c0), 3)).mag() / 2; 83415 }; 83416 /** 83417 * @method split 83418 * @param {Number} t the value (0-1) at which to split 83419 * @return {Cubic} the second part of the curve 83420 * 83421 * splits the cubic into two parts at a point 't' along the curve. 83422 * this cubic keeps its start point and its end point becomes the 83423 * point at 't'. the 'end half is returned. 83424 */ 83425 83426 83427 this.split = function (t) { 83428 var m1 = p5.Vector.lerp(this.p0, this.c0, t); 83429 var m2 = p5.Vector.lerp(this.c0, this.c1, t); 83430 var mm1 = p5.Vector.lerp(m1, m2, t);
83431 this.c1 = p5.Vector.lerp(this.c1, this.p1, t); 83432 this.c0 = p5.Vector.lerp(m2, this.c1, t); 83433 var pt = p5.Vector.lerp(mm1, this.c0, t); 83434 var part1 = new Cubic(this.p0, m1, mm1, pt); 83435 this.p0 = pt; 83436 return part1; 83437 }; 83438 /** 83439 * @method splitInflections 83440 * @return {Cubic[]} the non-inflecting pieces of this cubic 83441 * 83442 * returns an array containing 0, 1 or 2 cubics split resulting 83443 * from splitting this cubic at its inflection points. 83444 * this cubic is (potentially) altered and returned in the list. 83445 */ 83446 83447 83448 this.splitInflections = function () { 83449 var a = p5.Vector.sub(this.c0, this.p0); 83450 var b = p5.Vector.sub(p5.Vector.sub(this.c1, this.c0), a); 83451 var c = p5.Vector.sub(p5.Vector.sub(p5.Vector.sub(this.p1, this.c1), a), p5.Vector.mult(b, 2)); 83452 var cubics = []; // find the derivative coefficients 83453 83454 var A = b.x * c.y - b.y * c.x; 83455 83456 if (A !== 0) { 83457 var B = a.x * c.y - a.y * c.x; 83458 var C = a.x * b.y - a.y * b.x; 83459 var disc = B * B - 4 * A * C; 83460 83461 if (disc >= 0) { 83462 if (A < 0) { 83463 A = -A; 83464 B = -B; 83465 C = -C; 83466 } 83467 83468 var Q = Math.sqrt(disc); 83469 var t0 = (-B - Q) / (2 * A); // the first inflection point 83470 83471 var t1 = (-B + Q) / (2 * A); // the second inflection point 83472 // test if the first inflection point lies on the curve 83473 83474 if (t0 > 0 && t0 < 1) { 83475 // split at the first inflection point 83476 cubics.push(this.split(t0)); // scale t2 into the second part 83477 83478 t1 = 1 - (1 - t1) / (1 - t0); 83479 } // test if the second inflection point lies on the curve 83480 83481 83482 if (t1 > 0 && t1 < 1) { 83483 // split at the second inflection point 83484 cubics.push(this.split(t1)); 83485 } 83486 } 83487 } 83488 83489 cubics.push(this); 83490 return cubics; 83491 }; 83492 } 83493 /** 83494 * @function cubicToQuadratics 83495 * @param {Number} x0 83496 * @param {Number} y0 83497 * @param {Number} cx0 83498 * @param {Number} cy0 83499 * @param {Number} cx1 83500 * @param {Number} cy1 83501 * @param {Number} x1 83502 * @param {Number} y1 83503 * @returns {Cubic[]} an array of cubics whose quadratic approximations 83504 * closely match the civen cubic. 83505 * 83506 * converts a cubic curve to a list of quadratics. 83507 */ 83508 83509 83510 function cubicToQuadratics(x0, y0, cx0, cy0, cx1, cy1, x1, y1) { 83511 // create the Cubic object and split it at its inflections 83512 var cubics = new Cubic(new p5.Vector(x0, y0), new p5.Vector(cx0, cy0), new p5.Vector(cx1, cy1), new p5.Vector(x1, y1)).splitInflections(); 83513 var qs = []; // the final list of quadratics 83514 83515 var precision = 30 / SQRT3; // for each of the non-inflected pieces of the original cubic 83516 83517 for (var i = 0; i < cubics.length; i++) { 83518 var cubic = cubics[i]; // the cubic is iteratively split in 3 pieces: 83519 // the first piece is accumulated in 'qs', the result. 83520 // the last piece is accumulated in 'tail', temporarily. 83521 // the middle piece is repeatedly split again, while necessary. 83522 83523 var tail = []; 83524 var t3; 83525 83526 for (;;) { 83527 // calculate this cubic's precision 83528 t3 = precision / cubic.quadError(); 83529 83530 if (t3 >= 0.5 * 0.5 * 0.5) { 83531 break; // not too bad, we're done 83532 } // find a split point based on the error 83533 83534 83535 var t = Math.pow(t3, 1.0 / 3.0); // split the cubic in 3 83536 83537 var start = cubic.split(t); 83538 var middle = cubic.split(1 - t / (1 - t)); 83539 qs.push(start); // the first part 83540 83541 tail.push(cubic); // the last part 83542
83543 cubic = middle; // iterate on the middle piece 83544 } 83545 83546 if (t3 < 1) { 83547 // a little excess error, split the middle in two 83548 qs.push(cubic.split(0.5)); 83549 } // add the middle piece to the result 83550 83551 83552 qs.push(cubic); // finally add the tail, reversed, onto the result 83553 83554 Array.prototype.push.apply(qs, tail.reverse()); 83555 } 83556 83557 return qs; 83558 } 83559 /** 83560 * @function pushLine 83561 * @param {Number} x0 83562 * @param {Number} y0 83563 * @param {Number} x1 83564 * @param {Number} y1 83565 * 83566 * add a straight line to the row/col grid of a glyph 83567 */ 83568 83569 83570 function pushLine(x0, y0, x1, y1) { 83571 var mx = (x0 + x1) / 2; 83572 var my = (y0 + y1) / 2; 83573 push([x0, x1], [y0, y1], { 83574 x: x0, 83575 y: y0, 83576 cx: mx, 83577 cy: my 83578 }); 83579 } 83580 /** 83581 * @function samePoint 83582 * @param {Number} x0 83583 * @param {Number} y0 83584 * @param {Number} x1 83585 * @param {Number} y1 83586 * @return {Boolean} true if the two points are sufficiently close 83587 * 83588 * tests if two points are close enough to be considered the same 83589 */ 83590 83591 83592 function samePoint(x0, y0, x1, y1) { 83593 return Math.abs(x1 - x0) < 0.00001 && Math.abs(y1 - y0) < 0.00001; 83594 } 83595 83596 var x0, y0, xs, ys; 83597 83598 for (var iCmd = 0; iCmd < cmds.length; ++iCmd) { 83599 var cmd = cmds[iCmd]; // scale the coordinates to the range 0-1 83600 83601 var x1 = (cmd.x - xMin) / gWidth; 83602 var y1 = (cmd.y - yMin) / gHeight; // don't bother if this point is the same as the last 83603 83604 if (samePoint(x0, y0, x1, y1)) continue; 83605 83606 switch (cmd.type) { 83607 case 'M': 83608 // move 83609 xs = x1; 83610 ys = y1; 83611 break; 83612 83613 case 'L': 83614 // line 83615 pushLine(x0, y0, x1, y1); 83616 break; 83617 83618 case 'Q': 83619 // quadratic 83620 var cx = (cmd.x1 - xMin) / gWidth; 83621 var cy = (cmd.y1 - yMin) / gHeight; 83622 push([x0, x1, cx], [y0, y1, cy], { 83623 x: x0, 83624 y: y0, 83625 cx: cx, 83626 cy: cy 83627 }); 83628 break; 83629 83630 case 'Z': 83631 // end 83632 if (!samePoint(x0, y0, xs, ys)) { 83633 // add an extra line closing the loop, if necessary 83634 pushLine(x0, y0, xs, ys); 83635 strokes.push({ 83636 x: xs, 83637 y: ys 83638 }); 83639 } else { 83640 strokes.push({ 83641 x: x0, 83642 y: y0 83643 }); 83644 } 83645 83646 break; 83647 83648 case 'C': 83649 // cubic 83650 var cx1 = (cmd.x1 - xMin) / gWidth; 83651 var cy1 = (cmd.y1 - yMin) / gHeight; 83652 var cx2 = (cmd.x2 - xMin) / gWidth; 83653 var cy2 = (cmd.y2 - yMin) / gHeight; 83654 var qs = cubicToQuadratics(x0, y0, cx1, cy1, cx2, cy2, x1, y1); 83655 83656 for (var iq = 0; iq < qs.length; iq++) { 83657 var q = qs[iq].toQuadratic(); 83658 push([q.x, q.x1, q.cx], [q.y, q.y1, q.cy], q); 83659 } 83660 83661 break; 83662 83663 default: 83664 throw new Error('unknown command type: ' + cmd.type); 83665 } 83666 83667 x0 = x1; 83668 y0 = y1; 83669 } // allocate space for the strokes 83670 83671 83672 var strokeCount = strokes.length; 83673 var strokeImageInfo = this.strokeImageInfos.findImage(strokeCount); 83674 var strokeOffset = strokeImageInfo.index; // fill the stroke image 83675 83676 for (var il = 0; il < strokeCount; ++il) { 83677 var s = strokes[il]; 83678 setPixel(strokeImageInfo, byte(s.x), byte(s.y), byte(s.cx), byte(s.cy)); 83679 } 83680 /** 83681 * @function layout 83682 * @param {Number[][]} dim 83683 * @param {ImageInfo[]} dimImageInfos 83684 * @param {ImageInfo[]} cellImageInfos 83685 * @return {Object} 83686 * 83687 * lays out the curves in a dimension (row or col) into two 83688 * images, one for the indices of the curves themselves, and 83689 * one containing the offset and length of those index spans. 83690 */ 83691 83692 83693 function layout(dim, dimImageInfos, cellImageInfos) { 83694 var dimLength = dim.length; // the number of slices in this dimension 83695 83696 var dimImageInfo = dimImageInfos.findImage(dimLength); 83697 var dimOffset = dimImageInfo.index; // calculate the total number of stroke indices in this dimension 83698 83699 var totalStrokes = 0; 83700 83701 for (var id = 0; id < dimLength; ++id) { 83702 totalStrokes += dim[id].length; 83703 } // allocate space for the stroke indices 83704 83705 83706 var cellImageInfo = cellImageInfos.findImage(totalStrokes); // for each slice in the glyph 83707 83708 for (var i = 0; i < dimLength; ++i) { 83709 var strokeIndices = dim[i]; 83710 var strokeCount = strokeIndices.length; 83711 var cellLineIndex = cellImageInfo.index; // write the offset and count into the glyph slice image 83712 83713 setPixel(dimImageInfo, cellLineIndex >> 7, cellLineIndex & 0x7f, strokeCount >> 7, strokeCount & 0x7f); // for each stroke index in that slice 83714 83715 for (var iil = 0; iil < strokeCount; ++iil) { 83716 // write the stroke index into the slice's image 83717 var strokeIndex = strokeIndices[iil] + strokeOffset; 83718 setPixel(cellImageInfo, strokeIndex >> 7, strokeIndex & 0x7f, 0, 0); 83719 } 83720 } 83721 83722 return { 83723 cellImageInfo: cellImageInfo, 83724 dimOffset: dimOffset, 83725 dimImageInfo: dimImageInfo 83726 }; 83727 } // initialize the info for this glyph 83728 83729 83730 gi = this.glyphInfos[glyph.index] = { 83731 glyph: glyph, 83732 uGlyphRect: [bb.x1, -bb.y1, bb.x2, -bb.y2], 83733 strokeImageInfo: strokeImageInfo, 83734 strokes: strokes, 83735 colInfo: layout(cols, this.colDimImageInfos, this.colCellImageInfos), 83736 rowInfo: layout(rows, this.rowDimImageInfos, this.rowCellImageInfos) 83737 }; 83738 gi.uGridOffset = [gi.colInfo.dimOffset, gi.rowInfo.dimOffset]; 83739 return gi; 83740 }; 83741 }; 83742 83743 p5.RendererGL.prototype._renderText = function (p, line, x, y, maxY) { 83744 if (y >= maxY || !this._doFill) { 83745 return; // don't render lines beyond our maxY position 83746 } 83747 83748 if (!this._isOpenType()) { 83749 console.log('WEBGL: only opentype fonts are supported'); 83750 return p; 83751 } 83752 83753 p.push(); // fix to #803 83754 // remember this state, so it can be restored later 83755 83756 var curFillShader = this.curFillShader; 83757 var doStroke = this._doStroke; 83758 var drawMode = this.drawMode; 83759 this.curFillShader = null; 83760 this._doStroke = false;
83761 this.drawMode = constants.TEXTURE; // get the cached FontInfo object 83762 83763 var font = this._textFont.font; 83764 var fontInfo = this._textFont._fontInfo; 83765 83766 if (!fontInfo) { 83767 fontInfo = this._textFont._fontInfo = new FontInfo(font); 83768 } // calculate the alignment and move/scale the view accordingly 83769 83770 83771 var pos = this._textFont._handleAlignment(this, line, x, y); 83772 83773 var fontSize = this._textSize; 83774 var scale = fontSize / font.unitsPerEm; 83775 this.translate(pos.x, pos.y, 0); 83776 this.scale(scale, scale, 1); // initialize the font shader 83777 83778 var gl = this.GL; 83779 var initializeShader = !this._defaultFontShader; 83780 var sh = this.setFillShader(this._getFontShader()); 83781 83782 if (initializeShader) { 83783 // these are constants, really. just initialize them one-time. 83784 sh.setUniform('uGridImageSize', [gridImageWidth, gridImageHeight]); 83785 sh.setUniform('uCellsImageSize', [cellImageWidth, cellImageHeight]); 83786 sh.setUniform('uStrokeImageSize', [strokeImageWidth, strokeImageHeight]); 83787 sh.setUniform('uGridSize', [charGridWidth, charGridHeight]); 83788 } 83789 83790 this._applyColorBlend(this.curFillColor); 83791 83792 var g = this.gHash['glyph']; 83793 83794 if (!g) { 83795 // create the geometry for rendering a quad 83796 var geom = this._textGeom = new p5.Geometry(1, 1, function () { 83797 for (var i = 0; i <= 1; i++) { 83798 for (var j = 0; j <= 1; j++) { 83799 this.vertices.push(new p5.Vector(j, i, 0)); 83800 this.uvs.push(j, i); 83801 } 83802 } 83803 }); 83804 geom.computeFaces().computeNormals(); 83805 g = this.createBuffers('glyph', geom); 83806 } // bind the shader buffers 83807 83808 83809 this._bindBuffer(g.vertexBuffer, gl.ARRAY_BUFFER); 83810 83811 sh.enableAttrib(sh.attributes.aPosition.location, 3, gl.FLOAT, false, 0, 0); 83812 83813 this._bindBuffer(g.indexBuffer, gl.ELEMENT_ARRAY_BUFFER); 83814 83815 this._bindBuffer(g.uvBuffer, gl.ARRAY_BUFFER); 83816 83817 sh.enableAttrib(sh.attributes.aTexCoord.location, 2, gl.FLOAT, false, 0, 0); // this will have to do for now... 83818 83819 sh.setUniform('uMaterialColor', this.curFillColor); 83820 83821 try { 83822 var dx = 0; // the x position in the line 83823 83824 var glyphPrev = null; // the previous glyph, used for kerning 83825 83826 var shaderBound = false; // fetch the glyphs in the line of text 83827 83828 var glyphs = font.stringToGlyphs(line); 83829 83830 for (var ig = 0; ig < glyphs.length; ++ig) { 83831 var glyph = glyphs[ig]; // kern 83832 83833 if (glyphPrev) dx += font.getKerningValue(glyphPrev, glyph); 83834 var gi = fontInfo.getGlyphInfo(glyph); 83835 83836 if (gi.uGlyphRect) { 83837 var rowInfo = gi.rowInfo; 83838 var colInfo = gi.colInfo; 83839 sh.setUniform('uSamplerStrokes', gi.strokeImageInfo.imageData); 83840 sh.setUniform('uSamplerRowStrokes', rowInfo.cellImageInfo.imageData); 83841 sh.setUniform('uSamplerRows', rowInfo.dimImageInfo.imageData); 83842 sh.setUniform('uSamplerColStrokes', colInfo.cellImageInfo.imageData); 83843 sh.setUniform('uSamplerCols', colInfo.dimImageInfo.imageData); 83844 sh.setUniform('uGridOffset', gi.uGridOffset); 83845 sh.setUniform('uGlyphRect', gi.uGlyphRect); 83846 sh.setUniform('uGlyphOffset', dx); 83847 83848 if (!shaderBound) { 83849 shaderBound = true; 83850 sh.bindShader(); // first time around, bind the shader fully 83851 } else { 83852 sh.bindTextures(); // afterwards, only textures need updating 83853 } // draw it 83854 83855 83856 gl.drawElements(gl.TRIANGLES, 6, this.GL.UNSIGNED_SHORT, 0); 83857 } 83858 83859 dx += glyph.advanceWidth; 83860 glyphPrev = glyph; 83861 } 83862 } finally { 83863 // clean up 83864 sh.unbindShader(); 83865 this.curFillShader = curFillShader; 83866 this._doStroke = doStroke; 83867 this.drawMode = drawMode; 83868 p.pop(); 83869 } 83870 83871 this._pInst._pixelsDirty = true; 83872 return p; 83873 }; 83874 }, {
83875 "../core/constants": 18, 83876 "../core/main": 24, 83877 "./p5.RendererGL": 74, 83878 "./p5.Shader": 75 83879 }] 83880 }, {}, [13])(13); 83881}); 83882},{"buffer":"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/buffer/index.js","process":"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/node_modules/process/browser.js"}],"../node_modules/p5/lib/addons/p5.sound.js":[function(require,module,exports) { 83883var define; 83884/*! p5.sound.js v0.3.10 2019-01-10 */ 83885/** 83886 * p5.sound extends p5 with <a href="http://caniuse.com/audio-api" 83887 * target="_blank">Web Audio</a> functionality including audio input, 83888 * playback, analysis and synthesis. 83889 * <br/><br/> 83890 * <a href="#/p5.SoundFile"><b>p5.SoundFile</b></a>: Load and play sound files.<br/> 83891 * <a href="#/p5.Amplitude"><b>p5.Amplitude</b></a>: Get the current volume of a sound.<br/> 83892 * <a href="#/p5.AudioIn"><b>p5.AudioIn</b></a>: Get sound from an input source, typically 83893 * a computer microphone.<br/> 83894 * <a href="#/p5.FFT"><b>p5.FFT</b></a>: Analyze the frequency of sound. Returns 83895 * results from the frequency spectrum or time domain (waveform).<br/> 83896 * <a href="#/p5.Oscillator"><b>p5.Oscillator</b></a>: Generate Sine, 83897 * Triangle, Square and Sawtooth waveforms. Base class of 83898 * <a href="#/p5.Noise">p5.Noise</a> and <a href="#/p5.Pulse">p5.Pulse</a>. 83899 * <br/> 83900 * <a href="#/p5.Envelope"><b>p5.Envelope</b></a>: An Envelope is a series 83901 * of fades over time. Often used to control an object's 83902 * output gain level as an "ADSR Envelope" (Attack, Decay, 83903 * Sustain, Release). Can also modulate other parameters.<br/> 83904 * <a href="#/p5.Delay"><b>p5.Delay</b></a>: A delay effect with 83905 * parameters for feedback, delayTime, and lowpass filter.<br/> 83906 * <a href="#/p5.Filter"><b>p5.Filter</b></a>: Filter the frequency range of a 83907 * sound. 83908 * <br/> 83909 * <a href="#/p5.Reverb"><b>p5.Reverb</b></a>: Add reverb to a sound by specifying 83910 * duration and decay. <br/> 83911 * <b><a href="#/p5.Convolver">p5.Convolver</a>:</b> Extends 83912 * <a href="#/p5.Reverb">p5.Reverb</a> to simulate the sound of real 83913 * physical spaces through convolution.<br/> 83914 * <b><a href="#/p5.SoundRecorder">p5.SoundRecorder</a></b>: Record sound for playback 83915 * / save the .wav file. 83916 * <b><a href="#/p5.Phrase">p5.Phrase</a></b>, <b><a href="#/p5.Part">p5.Part</a></b> and 83917 * <b><a href="#/p5.Score">p5.Score</a></b>: Compose musical sequences. 83918 * <br/><br/> 83919 * p5.sound is on <a href="https://github.com/therewasaguy/p5.sound/">GitHub</a>. 83920 * Download the latest version 83921 * <a href="https://github.com/therewasaguy/p5.sound/blob/master/lib/p5.sound.js">here</a>. 83922 * 83923 * @module p5.sound 83924 * @submodule p5.sound 83925 * @for p5.sound 83926 * @main 83927 */ 83928 83929/** 83930 * p5.sound 83931 * https://p5js.org/reference/#/libraries/p5.sound 83932 * 83933 * From the Processing Foundation and contributors 83934 * https://github.com/processing/p5.js-sound/graphs/contributors 83935 * 83936 * MIT License (MIT) 83937 * https://github.com/processing/p5.js-sound/blob/master/LICENSE 83938 * 83939 * Some of the many audio libraries & resources that inspire p5.sound: 83940 * - TONE.js (c) Yotam Mann. Licensed under The MIT License (MIT). https://github.com/TONEnoTONE/Tone.js 83941 * - buzz.js (c) Jay Salvat. Licensed under The MIT License (MIT). http://buzz.jaysalvat.com/ 83942 * - Boris Smus Web Audio API book, 2013. Licensed under the Apache License http://www.apache.org/licenses/LICENSE-2.0 83943 * - wavesurfer.js https://github.com/katspaugh/wavesurfer.js 83944 * - Web Audio Components by Jordan Santell https://github.com/web-audio-components 83945 * - Wilm Thoben's Sound library for Processing https://github.com/processing/processing/tree/master/java/libraries/sound 83946 * 83947 * Web Audio API: http://w3.org/TR/webaudio/ 83948 */ 83949 83950(function (root, factory) { 83951 if (typeof define === 'function' && define.amd) 83952 define('p5.sound', ['p5'], function (p5) { (factory(p5));}); 83953 else if (typeof exports === 'object') 83954 factory(require('../p5')); 83955 else 83956 factory(root['p5']); 83957}(this, function (p5) { 83958 83959var shims; 83960'use strict'; /** 83961 * This module has shims 83962 */ 83963shims = function () { 83964 /* AudioContext Monkeypatch 83965 Copyright 2013 Chris Wilson 83966 Licensed under the Apache License, Version 2.0 (the "License");
83967 you may not use this file except in compliance with the License. 83968 You may obtain a copy of the License at 83969 http://www.apache.org/licenses/LICENSE-2.0 83970 Unless required by applicable law or agreed to in writing, software 83971 distributed under the License is distributed on an "AS IS" BASIS, 83972 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 83973 See the License for the specific language governing permissions and 83974 limitations under the License. 83975 */ 83976 (function () { 83977 function fixSetTarget(param) { 83978 if (!param) 83979 // if NYI, just return 83980 return; 83981 if (!param.setTargetAtTime) 83982 param.setTargetAtTime = param.setTargetValueAtTime; 83983 } 83984 if (window.hasOwnProperty('webkitAudioContext') && !window.hasOwnProperty('AudioContext')) { 83985 window.AudioContext = window.webkitAudioContext; 83986 if (typeof AudioContext.prototype.createGain !== 'function') 83987 AudioContext.prototype.createGain = AudioContext.prototype.createGainNode; 83988 if (typeof AudioContext.prototype.createDelay !== 'function') 83989 AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode; 83990 if (typeof AudioContext.prototype.createScriptProcessor !== 'function') 83991 AudioContext.prototype.createScriptProcessor = AudioContext.prototype.createJavaScriptNode; 83992 if (typeof AudioContext.prototype.createPeriodicWave !== 'function') 83993 AudioContext.prototype.createPeriodicWave = AudioContext.prototype.createWaveTable; 83994 AudioContext.prototype.internal_createGain = AudioContext.prototype.createGain; 83995 AudioContext.prototype.createGain = function () { 83996 var node = this.internal_createGain(); 83997 fixSetTarget(node.gain); 83998 return node; 83999 }; 84000 AudioContext.prototype.internal_createDelay = AudioContext.prototype.createDelay; 84001 AudioContext.prototype.createDelay = function (maxDelayTime) { 84002 var node = maxDelayTime ? this.internal_createDelay(maxDelayTime) : this.internal_createDelay(); 84003 fixSetTarget(node.delayTime); 84004 return node; 84005 }; 84006 AudioContext.prototype.internal_createBufferSource = AudioContext.prototype.createBufferSource; 84007 AudioContext.prototype.createBufferSource = function () { 84008 var node = this.internal_createBufferSource(); 84009 if (!node.start) { 84010 node.start = function (when, offset, duration) { 84011 if (offset || duration) 84012 this.noteGrainOn(when || 0, offset, duration); 84013 else 84014 this.noteOn(when || 0); 84015 }; 84016 } else { 84017 node.internal_start = node.start; 84018 node.start = function (when, offset, duration) { 84019 if (typeof duration !== 'undefined') 84020 node.internal_start(when || 0, offset, duration); 84021 else 84022 node.internal_start(when || 0, offset || 0); 84023 }; 84024 } 84025 if (!node.stop) { 84026 node.stop = function (when) { 84027 this.noteOff(when || 0); 84028 }; 84029 } else { 84030 node.internal_stop = node.stop; 84031 node.stop = function (when) { 84032 node.internal_stop(when || 0); 84033 }; 84034 } 84035 fixSetTarget(node.playbackRate); 84036 return node; 84037 }; 84038 AudioContext.prototype.internal_createDynamicsCompressor = AudioContext.prototype.createDynamicsCompressor; 84039 AudioContext.prototype.createDynamicsCompressor = function () { 84040 var node = this.internal_createDynamicsCompressor(); 84041 fixSetTarget(node.threshold); 84042 fixSetTarget(node.knee); 84043 fixSetTarget(node.ratio); 84044 fixSetTarget(node.reduction); 84045 fixSetTarget(node.attack); 84046 fixSetTarget(node.release); 84047 return node; 84048 }; 84049 AudioContext.prototype.internal_createBiquadFilter = AudioContext.prototype.createBiquadFilter; 84050 AudioContext.prototype.createBiquadFilter = function () { 84051 var node = this.internal_createBiquadFilter(); 84052 fixSetTarget(node.frequency); 84053 fixSetTarget(node.detune); 84054 fixSetTarget(node.Q); 84055 fixSetTarget(node.gain); 84056 return node; 84057 }; 84058 if (typeof AudioContext.prototype.createOscillator !== 'function') { 84059 AudioContext.prototype.internal_createOscillator = AudioContext.prototype.createOscillator; 84060 AudioContext.prototype.createOscillator = function () { 84061 var node = this.internal_createOscillator(); 84062 if (!node.start) { 84063 node.start = function (when) { 84064 this.noteOn(when || 0); 84065 }; 84066 } else { 84067 node.internal_start = node.start; 84068 node.start = function (when) { 84069 node.internal_start(when || 0); 84070 }; 84071 } 84072 if (!node.stop) { 84073 node.stop = function (when) { 84074 this.noteOff(when || 0); 84075 }; 84076 } else { 84077 node.internal_stop = node.stop; 84078 node.stop = function (when) { 84079 node.internal_stop(when || 0); 84080 }; 84081 } 84082 if (!node.setPeriodicWave) 84083 node.setPeriodicWave = node.setWaveTable; 84084 fixSetTarget(node.frequency); 84085 fixSetTarget(node.detune); 84086 return node; 84087 }; 84088 } 84089 } 84090 if (window.hasOwnProperty('webkitOfflineAudioContext') && !window.hasOwnProperty('OfflineAudioContext')) { 84091 window.OfflineAudioContext = window.webkitOfflineAudioContext; 84092 } 84093 }(window)); 84094 // <-- end MonkeyPatch. 84095 // Polyfill for AudioIn, also handled by p5.dom createCapture 84096 navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; 84097 /** 84098 * Determine which filetypes are supported (inspired by buzz.js) 84099 * The audio element (el) will only be used to test browser support for various audio formats 84100 */ 84101 var el = document.createElement('audio'); 84102 p5.prototype.isSupported = function () { 84103 return !!el.canPlayType; 84104 }; 84105 var isOGGSupported = function () { 84106 return !!el.canPlayType && el.canPlayType('audio/ogg; codecs="vorbis"'); 84107 }; 84108 var isMP3Supported = function () { 84109 return !!el.canPlayType && el.canPlayType('audio/mpeg;'); 84110 }; 84111 var isWAVSupported = function () { 84112 return !!el.canPlayType && el.canPlayType('audio/wav; codecs="1"'); 84113 }; 84114 var isAACSupported = function () { 84115 return !!el.canPlayType && (el.canPlayType('audio/x-m4a;') || el.canPlayType('audio/aac;')); 84116 }; 84117 var isAIFSupported = function () { 84118 return !!el.canPlayType && el.canPlayType('audio/x-aiff;'); 84119 }; 84120 p5.prototype.isFileSupported = function (extension) { 84121 switch (extension.toLowerCase()) { 84122 case 'mp3': 84123 return isMP3Supported(); 84124 case 'wav': 84125 return isWAVSupported(); 84126 case 'ogg': 84127 return isOGGSupported(); 84128 case 'aac': 84129 case 'm4a': 84130 case 'mp4': 84131 return isAACSupported(); 84132 case 'aif': 84133 case 'aiff': 84134 return isAIFSupported(); 84135 default: 84136 return false;
84137 } 84138 }; 84139}(); 84140var StartAudioContext; 84141(function (root, factory) { 84142 if (true) { 84143 StartAudioContext = function () { 84144 return factory(); 84145 }(); 84146 } else if (typeof module === 'object' && module.exports) { 84147 module.exports = factory(); 84148 } else { 84149 root.StartAudioContext = factory(); 84150 } 84151}(this, function () { 84152 var TapListener = function (element, context) { 84153 this._dragged = false; 84154 this._element = element; 84155 this._bindedMove = this._moved.bind(this); 84156 this._bindedEnd = this._ended.bind(this, context); 84157 }; 84158 TapListener.prototype._moved = function (e) { 84159 this._dragged = true; 84160 }; 84161 TapListener.prototype._ended = function (context) { 84162 if (!this._dragged) { 84163 startContext(context); 84164 } 84165 this._dragged = false; 84166 }; 84167 TapListener.prototype.dispose = function () { 84168 this._element.removeEventListener('touchstart', this._bindedEnd); 84169 this._element.removeEventListener('touchmove', this._bindedMove); 84170 this._element.removeEventListener('touchend', this._bindedEnd); 84171 this._element.removeEventListener('mouseup', this._bindedEnd); 84172 this._bindedMove = null; 84173 this._bindedEnd = null; 84174 this._element = null; 84175 }; 84176 function startContext(context) { 84177 var buffer = context.createBuffer(1, 1, context.sampleRate); 84178 var source = context.createBufferSource(); 84179 source.buffer = buffer; 84180 source.connect(context.destination); 84181 source.start(0); 84182 if (context.resume) { 84183 context.resume(); 84184 } 84185 } 84186 function isStarted(context) { 84187 return context.state === 'running'; 84188 } 84189 function onStarted(context, callback) { 84190 function checkLoop() { 84191 if (isStarted(context)) { 84192 callback(); 84193 } else { 84194 requestAnimationFrame(checkLoop); 84195 if (context.resume) { 84196 context.resume(); 84197 } 84198 } 84199 } 84200 if (isStarted(context)) { 84201 callback(); 84202 } else { 84203 checkLoop(); 84204 } 84205 } 84206 function bindTapListener(element, tapListeners, context) { 84207 if (Array.isArray(element) || NodeList && element instanceof NodeList) { 84208 for (var i = 0; i < element.length; i++) { 84209 bindTapListener(element[i], tapListeners, context); 84210 } 84211 } else if (typeof element === 'string') { 84212 bindTapListener(document.querySelectorAll(element), tapListeners, context); 84213 } else if (element.jquery && typeof element.toArray === 'function') { 84214 bindTapListener(element.toArray(), tapListeners, context); 84215 } else if (Element && element instanceof Element) { 84216 var tap = new TapListener(element, context); 84217 tapListeners.push(tap); 84218 } 84219 } 84220 function StartAudioContext(context, elements, callback) { 84221 var promise = new Promise(function (success) { 84222 onStarted(context, success); 84223 }); 84224 var tapListeners = []; 84225 if (!elements) { 84226 elements = document.body; 84227 } 84228 bindTapListener(elements, tapListeners, context); 84229 promise.then(function () { 84230 for (var i = 0; i < tapListeners.length; i++) { 84231 tapListeners[i].dispose(); 84232 } 84233 tapListeners = null; 84234 if (callback) { 84235 callback(); 84236 } 84237 }); 84238 return promise; 84239 } 84240 return StartAudioContext; 84241})); 84242var audiocontext; 84243'use strict'; 84244audiocontext = function (StartAudioContext) { 84245 // Create the Audio Context 84246 var audiocontext = new window.AudioContext(); 84247 /** 84248 * <p>Returns the Audio Context for this sketch. Useful for users 84249 * who would like to dig deeper into the <a target='_blank' href= 84250 * 'http://webaudio.github.io/web-audio-api/'>Web Audio API 84251 * </a>.</p> 84252 * 84253 * <p>Some browsers require users to startAudioContext 84254 * with a user gesture, such as touchStarted in the example below.</p> 84255 * 84256 * @method getAudioContext 84257 * @return {Object} AudioContext for this sketch 84258 * @example 84259 * <div><code> 84260 * function draw() { 84261 * background(255); 84262 * textAlign(CENTER); 84263 * 84264 * if (getAudioContext().state !== 'running') { 84265 * text('click to start audio', width/2, height/2); 84266 * } else { 84267 * text('audio is enabled', width/2, height/2); 84268 * } 84269 * } 84270 * 84271 * function touchStarted() { 84272 * if (getAudioContext().state !== 'running') { 84273 * getAudioContext().resume(); 84274 * } 84275 * var synth = new p5.MonoSynth(); 84276 * synth.play('A4', 0.5, 0, 0.2); 84277 * } 84278 * 84279 * </div></code> 84280 */ 84281 p5.prototype.getAudioContext = function () { 84282 return audiocontext; 84283 }; 84284 /** 84285 * <p>It is a good practice to give users control over starting audio playback. 84286 * This practice is enforced by Google Chrome's autoplay policy as of r70 84287 * (<a href="https://goo.gl/7K7WLu">info</a>), iOS Safari, and other browsers. 84288 * </p> 84289 * 84290 * <p> 84291 * userStartAudio() starts the <a href="https://developer.mozilla.org/en-US/docs/Web/API/AudioContext" 84292 * target="_blank" title="Audio Context @ MDN">Audio Context</a> on a user gesture. It utilizes 84293 * the <a href="https://github.com/tambien/StartAudioContext">StartAudioContext</a> library by 84294 * Yotam Mann (MIT Licence, 2016). Read more at https://github.com/tambien/StartAudioContext. 84295 * </p> 84296 * 84297 * <p>Starting the audio context on a user gesture can be as simple as <code>userStartAudio()</code>. 84298 * Optional parameters let you decide on a specific element that will start the audio context, 84299 * and/or call a function once the audio context is started.</p> 84300 * @param {Element|Array} [element(s)] This argument can be an Element, 84301 * Selector String, NodeList, p5.Element, 84302 * jQuery Element, or an Array of any of those. 84303 * @param {Function} [callback] Callback to invoke when the AudioContext has started 84304 * @return {Promise} Returns a Promise which is resolved when 84305 * the AudioContext state is 'running' 84306 * @method userStartAudio 84307 * @example 84308 * <div><code> 84309 * function setup() { 84310 * var myDiv = createDiv('click to start audio'); 84311 * myDiv.position(0, 0); 84312 * 84313 * var mySynth = new p5.MonoSynth(); 84314 * 84315 * // This won't play until the context has started 84316 * mySynth.play('A6'); 84317 * 84318 * // Start the audio context on a click/touch event 84319 * userStartAudio().then(function() { 84320 * myDiv.remove(); 84321 * }); 84322 * } 84323 * </code></div> 84324 */ 84325 p5.prototype.userStartAudio = function (elements, callback) { 84326 var elt = elements; 84327 if (elements instanceof p5.Element) { 84328 elt = elements.elt;
84329 } else if (elements instanceof Array && elements[0] instanceof p5.Element) { 84330 elt = elements.map(function (e) { 84331 return e.elt; 84332 }); 84333 } 84334 return StartAudioContext(audiocontext, elt, callback); 84335 }; 84336 return audiocontext; 84337}(StartAudioContext); 84338var master; 84339'use strict'; 84340master = function () { 84341 /** 84342 * Master contains AudioContext and the master sound output. 84343 */ 84344 var Master = function () { 84345 var audiocontext = p5.prototype.getAudioContext(); 84346 this.input = audiocontext.createGain(); 84347 this.output = audiocontext.createGain(); 84348 //put a hard limiter on the output 84349 this.limiter = audiocontext.createDynamicsCompressor(); 84350 this.limiter.threshold.value = -3; 84351 this.limiter.ratio.value = 20; 84352 this.limiter.knee.value = 1; 84353 this.audiocontext = audiocontext; 84354 this.output.disconnect(); 84355 // connect input to limiter 84356 this.input.connect(this.limiter); 84357 // connect limiter to output 84358 this.limiter.connect(this.output); 84359 // meter is just for global Amplitude / FFT analysis 84360 this.meter = audiocontext.createGain(); 84361 this.fftMeter = audiocontext.createGain(); 84362 this.output.connect(this.meter); 84363 this.output.connect(this.fftMeter); 84364 // connect output to destination 84365 this.output.connect(this.audiocontext.destination); 84366 // an array of all sounds in the sketch 84367 this.soundArray = []; 84368 // an array of all musical parts in the sketch 84369 this.parts = []; 84370 // file extensions to search for 84371 this.extensions = []; 84372 }; 84373 // create a single instance of the p5Sound / master output for use within this sketch 84374 var p5sound = new Master(); 84375 /** 84376 * Returns a number representing the master amplitude (volume) for sound 84377 * in this sketch. 84378 * 84379 * @method getMasterVolume 84380 * @return {Number} Master amplitude (volume) for sound in this sketch. 84381 * Should be between 0.0 (silence) and 1.0. 84382 */ 84383 p5.prototype.getMasterVolume = function () { 84384 return p5sound.output.gain.value; 84385 }; 84386 /** 84387 * <p>Scale the output of all sound in this sketch</p> 84388 * Scaled between 0.0 (silence) and 1.0 (full volume). 84389 * 1.0 is the maximum amplitude of a digital sound, so multiplying 84390 * by greater than 1.0 may cause digital distortion. To 84391 * fade, provide a <code>rampTime</code> parameter. For more 84392 * complex fades, see the Envelope class. 84393 * 84394 * Alternately, you can pass in a signal source such as an 84395 * oscillator to modulate the amplitude with an audio signal. 84396 * 84397 * <p><b>How This Works</b>: When you load the p5.sound module, it 84398 * creates a single instance of p5sound. All sound objects in this 84399 * module output to p5sound before reaching your computer's output. 84400 * So if you change the amplitude of p5sound, it impacts all of the 84401 * sound in this module.</p> 84402 * 84403 * <p>If no value is provided, returns a Web Audio API Gain Node</p> 84404 * 84405 * @method masterVolume 84406 * @param {Number|Object} volume Volume (amplitude) between 0.0 84407 * and 1.0 or modulating signal/oscillator 84408 * @param {Number} [rampTime] Fade for t seconds 84409 * @param {Number} [timeFromNow] Schedule this event to happen at 84410 * t seconds in the future 84411 */ 84412 p5.prototype.masterVolume = function (vol, rampTime, tFromNow) { 84413 if (typeof vol === 'number') { 84414 var rampTime = rampTime || 0; 84415 var tFromNow = tFromNow || 0; 84416 var now = p5sound.audiocontext.currentTime; 84417 var currentVol = p5sound.output.gain.value; 84418 p5sound.output.gain.cancelScheduledValues(now + tFromNow); 84419 p5sound.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow); 84420 p5sound.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime); 84421 } else if (vol) { 84422 vol.connect(p5sound.output.gain); 84423 } else { 84424 // return the Gain Node 84425 return p5sound.output.gain; 84426 } 84427 }; 84428 /** 84429 * `p5.soundOut` is the p5.sound master output. It sends output to 84430 * the destination of this window's web audio context. It contains 84431 * Web Audio API nodes including a dyanmicsCompressor (<code>.limiter</code>), 84432 * and Gain Nodes for <code>.input</code> and <code>.output</code>. 84433 * 84434 * @property {Object} soundOut 84435 */ 84436 p5.prototype.soundOut = p5.soundOut = p5sound; 84437 /**
84438 * a silent connection to the DesinationNode 84439 * which will ensure that anything connected to it 84440 * will not be garbage collected 84441 * 84442 * @private 84443 */ 84444 p5.soundOut._silentNode = p5sound.audiocontext.createGain(); 84445 p5.soundOut._silentNode.gain.value = 0; 84446 p5.soundOut._silentNode.connect(p5sound.audiocontext.destination); 84447 return p5sound; 84448}(); 84449var helpers; 84450'use strict'; 84451helpers = function () { 84452 var p5sound = master; 84453 /** 84454 * @for p5 84455 */ 84456 /** 84457 * Returns a number representing the sample rate, in samples per second, 84458 * of all sound objects in this audio context. It is determined by the 84459 * sampling rate of your operating system's sound card, and it is not 84460 * currently possile to change. 84461 * It is often 44100, or twice the range of human hearing. 84462 * 84463 * @method sampleRate 84464 * @return {Number} samplerate samples per second 84465 */ 84466 p5.prototype.sampleRate = function () { 84467 return p5sound.audiocontext.sampleRate; 84468 }; 84469 /** 84470 * Returns the closest MIDI note value for 84471 * a given frequency. 84472 * 84473 * @method freqToMidi 84474 * @param {Number} frequency A freqeuncy, for example, the "A" 84475 * above Middle C is 440Hz 84476 * @return {Number} MIDI note value 84477 */ 84478 p5.prototype.freqToMidi = function (f) { 84479 var mathlog2 = Math.log(f / 440) / Math.log(2); 84480 var m = Math.round(12 * mathlog2) + 69; 84481 return m; 84482 }; 84483 /** 84484 * Returns the frequency value of a MIDI note value. 84485 * General MIDI treats notes as integers where middle C 84486 * is 60, C# is 61, D is 62 etc. Useful for generating 84487 * musical frequencies with oscillators. 84488 * 84489 * @method midiToFreq 84490 * @param {Number} midiNote The number of a MIDI note 84491 * @return {Number} Frequency value of the given MIDI note 84492 * @example 84493 * <div><code> 84494 * var notes = [60, 64, 67, 72]; 84495 * var i = 0; 84496 * 84497 * function setup() { 84498 * osc = new p5.Oscillator('Triangle'); 84499 * osc.start(); 84500 * frameRate(1); 84501 * } 84502 * 84503 * function draw() { 84504 * var freq = midiToFreq(notes[i]); 84505 * osc.freq(freq); 84506 * i++; 84507 * if (i >= notes.length){ 84508 * i = 0; 84509 * } 84510 * } 84511 * </code></div> 84512 */ 84513 var midiToFreq = p5.prototype.midiToFreq = function (m) { 84514 return 440 * Math.pow(2, (m - 69) / 12); 84515 }; 84516 // This method converts ANSI notes specified as a string "C4", "Eb3" to a frequency 84517 var noteToFreq = function (note) { 84518 if (typeof note !== 'string') { 84519 return note; 84520 } 84521 var wholeNotes = { 84522 A: 21, 84523 B: 23, 84524 C: 24, 84525 D: 26, 84526 E: 28, 84527 F: 29, 84528 G: 31 84529 }; 84530 var value = wholeNotes[note[0].toUpperCase()]; 84531 var octave = ~~note.slice(-1); 84532 value += 12 * (octave - 1); 84533 switch (note[1]) { 84534 case '#': 84535 value += 1; 84536 break; 84537 case 'b': 84538 value -= 1; 84539 break; 84540 default: 84541 break; 84542 } 84543 return midiToFreq(value); 84544 }; 84545 /** 84546 * List the SoundFile formats that you will include. LoadSound 84547 * will search your directory for these extensions, and will pick 84548 * a format that is compatable with the client's web browser. 84549 * <a href="http://media.io/">Here</a> is a free online file 84550 * converter. 84551 * 84552 * @method soundFormats 84553 * @param {String} [...formats] i.e. 'mp3', 'wav', 'ogg' 84554 * @example 84555 * <div><code> 84556 * function preload() { 84557 * // set the global sound formats 84558 * soundFormats('mp3', 'ogg'); 84559 * 84560 * // load either beatbox.mp3, or .ogg, depending on browser 84561 * mySound = loadSound('assets/beatbox.mp3'); 84562 * } 84563 * 84564 * function setup() { 84565 * mySound.play(); 84566 * } 84567 * </code></div> 84568 */ 84569 p5.prototype.soundFormats = function () { 84570 // reset extensions array 84571 p5sound.extensions = []; 84572 // add extensions 84573 for (var i = 0; i < arguments.length; i++) { 84574 arguments[i] = arguments[i].toLowerCase(); 84575 if ([ 84576 'mp3', 84577 'wav', 84578 'ogg', 84579 'm4a', 84580 'aac' 84581 ].indexOf(arguments[i]) > -1) { 84582 p5sound.extensions.push(arguments[i]); 84583 } else { 84584 throw arguments[i] + ' is not a valid sound format!'; 84585 } 84586 } 84587 }; 84588 p5.prototype.disposeSound = function () { 84589 for (var i = 0; i < p5sound.soundArray.length; i++) { 84590 p5sound.soundArray[i].dispose(); 84591 } 84592 }; 84593 // register removeSound to dispose of p5sound SoundFiles, Convolvers, 84594 // Oscillators etc when sketch ends 84595 p5.prototype.registerMethod('remove', p5.prototype.disposeSound); 84596 p5.prototype._checkFileFormats = function (paths) { 84597 var path;
84598 // if path is a single string, check to see if extension is provided 84599 if (typeof paths === 'string') { 84600 path = paths; 84601 // see if extension is provided 84602 var extTest = path.split('.').pop(); 84603 // if an extension is provided... 84604 if ([ 84605 'mp3', 84606 'wav', 84607 'ogg', 84608 'm4a', 84609 'aac' 84610 ].indexOf(extTest) > -1) { 84611 if (p5.prototype.isFileSupported(extTest)) { 84612 path = path; 84613 } else { 84614 var pathSplit = path.split('.'); 84615 var pathCore = pathSplit[pathSplit.length - 1]; 84616 for (var i = 0; i < p5sound.extensions.length; i++) { 84617 var extension = p5sound.extensions[i]; 84618 var supported = p5.prototype.isFileSupported(extension); 84619 if (supported) { 84620 pathCore = ''; 84621 if (pathSplit.length === 2) { 84622 pathCore += pathSplit[0]; 84623 } 84624 for (var i = 1; i <= pathSplit.length - 2; i++) { 84625 var p = pathSplit[i]; 84626 pathCore += '.' + p; 84627 } 84628 path = pathCore += '.'; 84629 path = path += extension; 84630 break; 84631 } 84632 } 84633 } 84634 } else { 84635 for (var i = 0; i < p5sound.extensions.length; i++) { 84636 var extension = p5sound.extensions[i]; 84637 var supported = p5.prototype.isFileSupported(extension); 84638 if (supported) { 84639 path = path + '.' + extension; 84640 break; 84641 } 84642 } 84643 } 84644 } else if (typeof paths === 'object') { 84645 for (var i = 0; i < paths.length; i++) { 84646 var extension = paths[i].split('.').pop(); 84647 var supported = p5.prototype.isFileSupported(extension); 84648 if (supported) { 84649 // console.log('.'+extension + ' is ' + supported + 84650 // ' supported by your browser.'); 84651 path = paths[i]; 84652 break; 84653 } 84654 } 84655 } 84656 return path; 84657 }; 84658 /** 84659 * Used by Osc and Envelope to chain signal math 84660 */ 84661 p5.prototype._mathChain = function (o, math, thisChain, nextChain, type) { 84662 // if this type of math already exists in the chain, replace it 84663 for (var i in o.mathOps) { 84664 if (o.mathOps[i] instanceof type) { 84665 o.mathOps[i].dispose(); 84666 thisChain = i; 84667 if (thisChain < o.mathOps.length - 1) { 84668 nextChain = o.mathOps[i + 1]; 84669 } 84670 } 84671 } 84672 o.mathOps[thisChain - 1].disconnect(); 84673 o.mathOps[thisChain - 1].connect(math); 84674 math.connect(nextChain); 84675 o.mathOps[thisChain] = math; 84676 return o; 84677 }; 84678 // helper methods to convert audio file as .wav format, 84679 // will use as saving .wav file and saving blob object 84680 // Thank you to Matt Diamond's RecorderJS (MIT License) 84681 // https://github.com/mattdiamond/Recorderjs 84682 function convertToWav(audioBuffer) { 84683 var leftChannel, rightChannel; 84684 leftChannel = audioBuffer.getChannelData(0); 84685 // handle mono files 84686 if (audioBuffer.numberOfChannels > 1) { 84687 rightChannel = audioBuffer.getChannelData(1); 84688 } else { 84689 rightChannel = leftChannel; 84690 } 84691 var interleaved = interleave(leftChannel, rightChannel); 84692 // create the buffer and view to create the .WAV file 84693 var buffer = new window.ArrayBuffer(44 + interleaved.length * 2); 84694 var view = new window.DataView(buffer); 84695 // write the WAV container, 84696 // check spec at: https://web.archive.org/web/20171215131933/http://tiny.systems/software/soundProgrammer/WavFormatDocs.pdf 84697 // RIFF chunk descriptor 84698 writeUTFBytes(view, 0, 'RIFF'); 84699 view.setUint32(4, 36 + interleaved.length * 2, true); 84700 writeUTFBytes(view, 8, 'WAVE'); 84701 // FMT sub-chunk 84702 writeUTFBytes(view, 12, 'fmt '); 84703 view.setUint32(16, 16, true); 84704 view.setUint16(20, 1, true); 84705 // stereo (2 channels) 84706 view.setUint16(22, 2, true); 84707 view.setUint32(24, 44100, true); 84708 view.setUint32(28, 44100 * 4, true); 84709 view.setUint16(32, 4, true); 84710 view.setUint16(34, 16, true); 84711 // data sub-chunk 84712 writeUTFBytes(view, 36, 'data'); 84713 view.setUint32(40, interleaved.length * 2, true); 84714 // write the PCM samples 84715 var lng = interleaved.length; 84716 var index = 44; 84717 var volume = 1; 84718 for (var i = 0; i < lng; i++) { 84719 view.setInt16(index, interleaved[i] * (32767 * volume), true); 84720 index += 2; 84721 } 84722 return view; 84723 } 84724 // helper methods to save waves
84725 function interleave(leftChannel, rightChannel) { 84726 var length = leftChannel.length + rightChannel.length; 84727 var result = new Float32Array(length); 84728 var inputIndex = 0; 84729 for (var index = 0; index < length;) { 84730 result[index++] = leftChannel[inputIndex]; 84731 result[index++] = rightChannel[inputIndex]; 84732 inputIndex++; 84733 } 84734 return result; 84735 } 84736 function writeUTFBytes(view, offset, string) { 84737 var lng = string.length; 84738 for (var i = 0; i < lng; i++) { 84739 view.setUint8(offset + i, string.charCodeAt(i)); 84740 } 84741 } 84742 return { 84743 convertToWav: convertToWav, 84744 midiToFreq: midiToFreq, 84745 noteToFreq: noteToFreq 84746 }; 84747}(master); 84748var errorHandler; 84749'use strict'; 84750errorHandler = function () { 84751 /* 84752 Helper function to generate an error 84753 with a custom stack trace that points to the sketch 84754 and removes other parts of the stack trace. 84755 84756 @private 84757 @class customError 84758 @constructor 84759 @param {String} name custom error name 84760 @param {String} errorTrace custom error trace 84761 @param {String} failedPath path to the file that failed to load 84762 @property {String} name custom error name 84763 @property {String} message custom error message 84764 @property {String} stack trace the error back to a line in the user's sketch. 84765 Note: this edits out stack trace within p5.js and p5.sound. 84766 @property {String} originalStack unedited, original stack trace 84767 @property {String} failedPath path to the file that failed to load 84768 @return {Error} returns a custom Error object 84769 */ 84770 var CustomError = function (name, errorTrace, failedPath) { 84771 var err = new Error(); 84772 var tempStack, splitStack; 84773 err.name = name; 84774 err.originalStack = err.stack + errorTrace; 84775 tempStack = err.stack + errorTrace; 84776 err.failedPath = failedPath; 84777 // only print the part of the stack trace that refers to the user code: 84778 var splitStack = tempStack.split('\n'); 84779 splitStack = splitStack.filter(function (ln) { 84780 return !ln.match(/(p5.|native code|globalInit)/g); 84781 }); 84782 err.stack = splitStack.join('\n'); 84783 return err; 84784 }; 84785 return CustomError; 84786}(); 84787var panner; 84788'use strict'; 84789panner = function () { 84790 var p5sound = master; 84791 var ac = p5sound.audiocontext; 84792 // Stereo panner 84793 // if there is a stereo panner node use it 84794 if (typeof ac.createStereoPanner !== 'undefined') { 84795 p5.Panner = function (input, output) { 84796 this.stereoPanner = this.input = ac.createStereoPanner(); 84797 input.connect(this.stereoPanner); 84798 this.stereoPanner.connect(output); 84799 }; 84800 p5.Panner.prototype.pan = function (val, tFromNow) { 84801 var time = tFromNow || 0; 84802 var t = ac.currentTime + time; 84803 this.stereoPanner.pan.linearRampToValueAtTime(val, t); 84804 }; 84805 //not implemented because stereopanner 84806 //node does not require this and will automatically 84807 //convert single channel or multichannel to stereo. 84808 //tested with single and stereo, not with (>2) multichannel 84809 p5.Panner.prototype.inputChannels = function () { 84810 }; 84811 p5.Panner.prototype.connect = function (obj) { 84812 this.stereoPanner.connect(obj); 84813 }; 84814 p5.Panner.prototype.disconnect = function () { 84815 if (this.stereoPanner) { 84816 this.stereoPanner.disconnect(); 84817 } 84818 }; 84819 } else { 84820 // if there is no createStereoPanner object 84821 // such as in safari 7.1.7 at the time of writing this 84822 // use this method to create the effect 84823 p5.Panner = function (input, output, numInputChannels) { 84824 this.input = ac.createGain(); 84825 input.connect(this.input); 84826 this.left = ac.createGain(); 84827 this.right = ac.createGain(); 84828 this.left.channelInterpretation = 'discrete'; 84829 this.right.channelInterpretation = 'discrete'; 84830 // if input is stereo 84831 if (numInputChannels > 1) { 84832 this.splitter = ac.createChannelSplitter(2); 84833 this.input.connect(this.splitter); 84834 this.splitter.connect(this.left, 1); 84835 this.splitter.connect(this.right, 0); 84836 } else { 84837 this.input.connect(this.left); 84838 this.input.connect(this.right); 84839 } 84840 this.output = ac.createChannelMerger(2); 84841 this.left.connect(this.output, 0, 1); 84842 this.right.connect(this.output, 0, 0); 84843 this.output.connect(output); 84844 }; 84845 // -1 is left, +1 is right 84846 p5.Panner.prototype.pan = function (val, tFromNow) { 84847 var time = tFromNow || 0; 84848 var t = ac.currentTime + time; 84849 var v = (val + 1) / 2;
84850 var rightVal = Math.cos(v * Math.PI / 2); 84851 var leftVal = Math.sin(v * Math.PI / 2); 84852 this.left.gain.linearRampToValueAtTime(leftVal, t); 84853 this.right.gain.linearRampToValueAtTime(rightVal, t); 84854 }; 84855 p5.Panner.prototype.inputChannels = function (numChannels) { 84856 if (numChannels === 1) { 84857 this.input.disconnect(); 84858 this.input.connect(this.left); 84859 this.input.connect(this.right); 84860 } else if (numChannels === 2) { 84861 if (typeof (this.splitter === 'undefined')) { 84862 this.splitter = ac.createChannelSplitter(2); 84863 } 84864 this.input.disconnect(); 84865 this.input.connect(this.splitter); 84866 this.splitter.connect(this.left, 1); 84867 this.splitter.connect(this.right, 0); 84868 } 84869 }; 84870 p5.Panner.prototype.connect = function (obj) { 84871 this.output.connect(obj); 84872 }; 84873 p5.Panner.prototype.disconnect = function () { 84874 if (this.output) { 84875 this.output.disconnect(); 84876 } 84877 }; 84878 } 84879}(master); 84880var soundfile; 84881'use strict'; 84882soundfile = function () { 84883 var CustomError = errorHandler; 84884 var p5sound = master; 84885 var ac = p5sound.audiocontext; 84886 var midiToFreq = helpers.midiToFreq; 84887 var convertToWav = helpers.convertToWav; 84888 /** 84889 * <p>SoundFile object with a path to a file.</p> 84890 * 84891 * <p>The p5.SoundFile may not be available immediately because 84892 * it loads the file information asynchronously.</p> 84893 * 84894 * <p>To do something with the sound as soon as it loads 84895 * pass the name of a function as the second parameter.</p> 84896 * 84897 * <p>Only one file path is required. However, audio file formats 84898 * (i.e. mp3, ogg, wav and m4a/aac) are not supported by all 84899 * web browsers. If you want to ensure compatability, instead of a single 84900 * file path, you may include an Array of filepaths, and the browser will 84901 * choose a format that works.</p> 84902 * 84903 * @class p5.SoundFile 84904 * @constructor 84905 * @param {String|Array} path path to a sound file (String). Optionally, 84906 * you may include multiple file formats in 84907 * an array. Alternately, accepts an object 84908 * from the HTML5 File API, or a p5.File. 84909 * @param {Function} [successCallback] Name of a function to call once file loads 84910 * @param {Function} [errorCallback] Name of a function to call if file fails to 84911 * load. This function will receive an error or 84912 * XMLHttpRequest object with information 84913 * about what went wrong. 84914 * @param {Function} [whileLoadingCallback] Name of a function to call while file 84915 * is loading. That function will 84916 * receive progress of the request to 84917 * load the sound file 84918 * (between 0 and 1) as its first 84919 * parameter. This progress 84920 * does not account for the additional 84921 * time needed to decode the audio data. 84922 * 84923 * @example 84924 * <div><code> 84925 * 84926 * function preload() { 84927 * soundFormats('mp3', 'ogg'); 84928 * mySound = loadSound('assets/doorbell.mp3'); 84929 * } 84930 * 84931 * function setup() { 84932 * mySound.setVolume(0.1); 84933 * mySound.play(); 84934 * } 84935 * 84936 * </code></div> 84937 */ 84938 p5.SoundFile = function (paths, onload, onerror, whileLoading) { 84939 if (typeof paths !== 'undefined') { 84940 if (typeof paths === 'string' || typeof paths[0] === 'string') { 84941 var path = p5.prototype._checkFileFormats(paths); 84942 this.url = path; 84943 } else if (typeof paths === 'object') { 84944 if (!(window.File && window.FileReader && window.FileList && window.Blob)) { 84945 // The File API isn't supported in this browser 84946 throw 'Unable to load file because the File API is not supported'; 84947 } 84948 } 84949 // if type is a p5.File...get the actual file 84950 if (paths.file) { 84951 paths = paths.file; 84952 } 84953 this.file = paths; 84954 } 84955 // private _onended callback, set by the method: onended(callback) 84956 this._onended = function () { 84957 }; 84958 this._looping = false;
84959 this._playing = false; 84960 this._paused = false; 84961 this._pauseTime = 0; 84962 // cues for scheduling events with addCue() removeCue() 84963 this._cues = []; 84964 this._cueIDCounter = 0; 84965 // position of the most recently played sample 84966 this._lastPos = 0; 84967 this._counterNode = null; 84968 this._scopeNode = null; 84969 // array of sources so that they can all be stopped! 84970 this.bufferSourceNodes = []; 84971 // current source 84972 this.bufferSourceNode = null; 84973 this.buffer = null; 84974 this.playbackRate = 1; 84975 this.input = p5sound.audiocontext.createGain(); 84976 this.output = p5sound.audiocontext.createGain(); 84977 this.reversed = false; 84978 // start and end of playback / loop 84979 this.startTime = 0; 84980 this.endTime = null; 84981 this.pauseTime = 0; 84982 // "restart" would stop playback before retriggering 84983 this.mode = 'sustain'; 84984 // time that playback was started, in millis 84985 this.startMillis = null; 84986 // stereo panning 84987 this.panPosition = 0; 84988 this.panner = new p5.Panner(this.output, p5sound.input, 2); 84989 // it is possible to instantiate a soundfile with no path 84990 if (this.url || this.file) { 84991 this.load(onload, onerror); 84992 } 84993 // add this p5.SoundFile to the soundArray 84994 p5sound.soundArray.push(this); 84995 if (typeof whileLoading === 'function') { 84996 this._whileLoading = whileLoading; 84997 } else { 84998 this._whileLoading = function () { 84999 }; 85000 } 85001 }; 85002 // register preload handling of loadSound 85003 p5.prototype.registerPreloadMethod('loadSound', p5.prototype); 85004 /** 85005 * loadSound() returns a new p5.SoundFile from a specified 85006 * path. If called during preload(), the p5.SoundFile will be ready 85007 * to play in time for setup() and draw(). If called outside of 85008 * preload, the p5.SoundFile will not be ready immediately, so 85009 * loadSound accepts a callback as the second parameter. Using a 85010 * <a href="https://github.com/processing/p5.js/wiki/Local-server"> 85011 * local server</a> is recommended when loading external files. 85012 * 85013 * @method loadSound 85014 * @param {String|Array} path Path to the sound file, or an array with 85015 * paths to soundfiles in multiple formats 85016 * i.e. ['sound.ogg', 'sound.mp3']. 85017 * Alternately, accepts an object: either 85018 * from the HTML5 File API, or a p5.File. 85019 * @param {Function} [successCallback] Name of a function to call once file loads 85020 * @param {Function} [errorCallback] Name of a function to call if there is 85021 * an error loading the file. 85022 * @param {Function} [whileLoading] Name of a function to call while file is loading. 85023 * This function will receive the percentage loaded 85024 * so far, from 0.0 to 1.0. 85025 * @return {SoundFile} Returns a p5.SoundFile 85026 * @example 85027 * <div><code> 85028 * function preload() { 85029 * mySound = loadSound('assets/doorbell.mp3'); 85030 * } 85031 * 85032 * function setup() { 85033 * mySound.setVolume(0.1); 85034 * mySound.play(); 85035 * } 85036 * </code></div> 85037 */ 85038 p5.prototype.loadSound = function (path, callback, onerror, whileLoading) { 85039 // if loading locally without a server 85040 if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') { 85041 window.alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS'); 85042 } 85043 var self = this; 85044 var s = new p5.SoundFile(path, function () { 85045 if (typeof callback === 'function') { 85046 callback.apply(self, arguments); 85047 } 85048 if (typeof self._decrementPreload === 'function') { 85049 self._decrementPreload(); 85050 } 85051 }, onerror, whileLoading); 85052 return s; 85053 }; 85054 /** 85055 * This is a helper function that the p5.SoundFile calls to load 85056 * itself. Accepts a callback (the name of another function) 85057 * as an optional parameter. 85058 * 85059 * @private 85060 * @param {Function} [successCallback] Name of a function to call once file loads 85061 * @param {Function} [errorCallback] Name of a function to call if there is an error 85062 */ 85063 p5.SoundFile.prototype.load = function (callback, errorCallback) { 85064 var self = this; 85065 var errorTrace = new Error().stack; 85066 if (this.url !== undefined && this.url !== '') { 85067 var request = new XMLHttpRequest(); 85068 request.addEventListener('progress', function (evt) { 85069 self._updateProgress(evt); 85070 }, false); 85071 request.open('GET', this.url, true); 85072 request.responseType = 'arraybuffer'; 85073 request.onload = function () { 85074 if (request.status === 200) { 85075 // on sucess loading file: 85076 if (!self.panner) 85077 return; 85078 ac.decodeAudioData(request.response, // success decoding buffer: 85079 function (buff) { 85080 if (!self.panner) 85081 return; 85082 self.buffer = buff; 85083 self.panner.inputChannels(buff.numberOfChannels); 85084 if (callback) { 85085 callback(self); 85086 } 85087 }, // error decoding buffer. "e" is undefined in Chrome 11/22/2015 85088 function () { 85089 if (!self.panner) 85090 return; 85091 var err = new CustomError('decodeAudioData', errorTrace, self.url); 85092 var msg = 'AudioContext error at decodeAudioData for ' + self.url; 85093 if (errorCallback) { 85094 err.msg = msg; 85095 errorCallback(err); 85096 } else { 85097 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 85098 } 85099 }); 85100 } else { 85101 if (!self.panner) 85102 return; 85103 var err = new CustomError('loadSound', errorTrace, self.url); 85104 var msg = 'Unable to load ' + self.url + '. The request status was: ' + request.status + ' (' + request.statusText + ')'; 85105 if (errorCallback) { 85106 err.message = msg; 85107 errorCallback(err); 85108 } else { 85109 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 85110 } 85111 } 85112 }; 85113 // if there is another error, aside from 404... 85114 request.onerror = function () { 85115 var err = new CustomError('loadSound', errorTrace, self.url); 85116 var msg = 'There was no response from the server at ' + self.url + '. Check the url and internet connectivity.';
85117 if (errorCallback) { 85118 err.message = msg; 85119 errorCallback(err); 85120 } else { 85121 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 85122 } 85123 }; 85124 request.send(); 85125 } else if (this.file !== undefined) { 85126 var reader = new FileReader(); 85127 reader.onload = function () { 85128 if (!self.panner) 85129 return; 85130 ac.decodeAudioData(reader.result, function (buff) { 85131 if (!self.panner) 85132 return; 85133 self.buffer = buff; 85134 self.panner.inputChannels(buff.numberOfChannels); 85135 if (callback) { 85136 callback(self); 85137 } 85138 }); 85139 }; 85140 reader.onerror = function (e) { 85141 if (!self.panner) 85142 return; 85143 if (onerror) { 85144 onerror(e); 85145 } 85146 }; 85147 reader.readAsArrayBuffer(this.file); 85148 } 85149 }; 85150 // TO DO: use this method to create a loading bar that shows progress during file upload/decode. 85151 p5.SoundFile.prototype._updateProgress = function (evt) { 85152 if (evt.lengthComputable) { 85153 var percentComplete = evt.loaded / evt.total * 0.99; 85154 this._whileLoading(percentComplete, evt); 85155 } else { 85156 // Unable to compute progress information since the total size is unknown 85157 this._whileLoading('size unknown'); 85158 } 85159 }; 85160 /** 85161 * Returns true if the sound file finished loading successfully. 85162 * 85163 * @method isLoaded 85164 * @return {Boolean} 85165 */ 85166 p5.SoundFile.prototype.isLoaded = function () { 85167 if (this.buffer) { 85168 return true; 85169 } else { 85170 return false; 85171 } 85172 }; 85173 /** 85174 * Play the p5.SoundFile 85175 * 85176 * @method play 85177 * @param {Number} [startTime] (optional) schedule playback to start (in seconds from now). 85178 * @param {Number} [rate] (optional) playback rate 85179 * @param {Number} [amp] (optional) amplitude (volume) 85180 * of playback 85181 * @param {Number} [cueStart] (optional) cue start time in seconds 85182 * @param {Number} [duration] (optional) duration of playback in seconds 85183 */ 85184 p5.SoundFile.prototype.play = function (startTime, rate, amp, _cueStart, duration) { 85185 if (!this.output) { 85186 console.warn('SoundFile.play() called after dispose'); 85187 return; 85188 } 85189 var self = this; 85190 var now = p5sound.audiocontext.currentTime; 85191 var cueStart, cueEnd; 85192 var time = startTime || 0; 85193 if (time < 0) { 85194 time = 0; 85195 } 85196 time = time + now; 85197 if (typeof rate !== 'undefined') { 85198 this.rate(rate); 85199 } 85200 if (typeof amp !== 'undefined') { 85201 this.setVolume(amp); 85202 } 85203 // TO DO: if already playing, create array of buffers for easy stop() 85204 if (this.buffer) { 85205 // reset the pause time (if it was paused) 85206 this._pauseTime = 0; 85207 // handle restart playmode 85208 if (this.mode === 'restart' && this.buffer && this.bufferSourceNode) { 85209 this.bufferSourceNode.stop(time); 85210 this._counterNode.stop(time); 85211 } 85212 //dont create another instance if already playing 85213 if (this.mode === 'untildone' && this.isPlaying()) { 85214 return; 85215 } 85216 // make a new source and counter. They are automatically assigned playbackRate and buffer 85217 this.bufferSourceNode = this._initSourceNode(); 85218 // garbage collect counterNode and create a new one 85219 delete this._counterNode; 85220 this._counterNode = this._initCounterNode(); 85221 if (_cueStart) { 85222 if (_cueStart >= 0 && _cueStart < this.buffer.duration) { 85223 // this.startTime = cueStart; 85224 cueStart = _cueStart; 85225 } else { 85226 throw 'start time out of range'; 85227 } 85228 } else { 85229 cueStart = 0; 85230 } 85231 if (duration) { 85232 // if duration is greater than buffer.duration, just play entire file anyway rather than throw an error 85233 duration = duration <= this.buffer.duration - cueStart ? duration : this.buffer.duration; 85234 } 85235 // if it was paused, play at the pause position 85236 if (this._paused) { 85237 this.bufferSourceNode.start(time, this.pauseTime, duration); 85238 this._counterNode.start(time, this.pauseTime, duration); 85239 } else { 85240 this.bufferSourceNode.start(time, cueStart, duration); 85241 this._counterNode.start(time, cueStart, duration); 85242 } 85243 this._playing = true; 85244 this._paused = false;
85245 // add source to sources array, which is used in stopAll() 85246 this.bufferSourceNodes.push(this.bufferSourceNode); 85247 this.bufferSourceNode._arrayIndex = this.bufferSourceNodes.length - 1; 85248 // delete this.bufferSourceNode from the sources array when it is done playing: 85249 var clearOnEnd = function () { 85250 this._playing = false; 85251 this.removeEventListener('ended', clearOnEnd, false); 85252 // call the onended callback 85253 self._onended(self); 85254 self.bufferSourceNodes.forEach(function (n, i) { 85255 if (n._playing === false) { 85256 self.bufferSourceNodes.splice(i); 85257 } 85258 }); 85259 if (self.bufferSourceNodes.length === 0) { 85260 self._playing = false; 85261 } 85262 }; 85263 this.bufferSourceNode.onended = clearOnEnd; 85264 } else { 85265 throw 'not ready to play file, buffer has yet to load. Try preload()'; 85266 } 85267 // if looping, will restart at original time 85268 this.bufferSourceNode.loop = this._looping; 85269 this._counterNode.loop = this._looping; 85270 if (this._looping === true) { 85271 cueEnd = duration ? duration : cueStart - 1e-15; 85272 this.bufferSourceNode.loopStart = cueStart; 85273 this.bufferSourceNode.loopEnd = cueEnd; 85274 this._counterNode.loopStart = cueStart; 85275 this._counterNode.loopEnd = cueEnd; 85276 } 85277 }; 85278 /** 85279 * p5.SoundFile has two play modes: <code>restart</code> and 85280 * <code>sustain</code>. Play Mode determines what happens to a 85281 * p5.SoundFile if it is triggered while in the middle of playback. 85282 * In sustain mode, playback will continue simultaneous to the 85283 * new playback. In restart mode, play() will stop playback 85284 * and start over. With untilDone, a sound will play only if it's 85285 * not already playing. Sustain is the default mode. 85286 * 85287 * @method playMode 85288 * @param {String} str 'restart' or 'sustain' or 'untilDone' 85289 * @example 85290 * <div><code> 85291 * var mySound; 85292 * function preload(){ 85293 * mySound = loadSound('assets/Damscray_DancingTiger.mp3'); 85294 * } 85295 * function mouseClicked() { 85296 * mySound.playMode('sustain'); 85297 * mySound.play(); 85298 * } 85299 * function keyPressed() { 85300 * mySound.playMode('restart'); 85301 * mySound.play(); 85302 * } 85303 * 85304 * </code></div> 85305 */ 85306 p5.SoundFile.prototype.playMode = function (str) { 85307 var s = str.toLowerCase(); 85308 // if restart, stop all other sounds from playing 85309 if (s === 'restart' && this.buffer && this.bufferSourceNode) { 85310 for (var i = 0; i < this.bufferSourceNodes.length - 1; i++) { 85311 var now = p5sound.audiocontext.currentTime; 85312 this.bufferSourceNodes[i].stop(now); 85313 } 85314 } 85315 // set play mode to effect future playback 85316 if (s === 'restart' || s === 'sustain' || s === 'untildone') { 85317 this.mode = s; 85318 } else { 85319 throw 'Invalid play mode. Must be either "restart" or "sustain"'; 85320 } 85321 }; 85322 /** 85323 * Pauses a file that is currently playing. If the file is not 85324 * playing, then nothing will happen. 85325 * 85326 * After pausing, .play() will resume from the paused 85327 * position. 85328 * If p5.SoundFile had been set to loop before it was paused, 85329 * it will continue to loop after it is unpaused with .play(). 85330 * 85331 * @method pause 85332 * @param {Number} [startTime] (optional) schedule event to occur 85333 * seconds from now 85334 * @example 85335 * <div><code> 85336 * var soundFile; 85337 * 85338 * function preload() { 85339 * soundFormats('ogg', 'mp3'); 85340 * soundFile = loadSound('assets/Damscray_-_Dancing_Tiger_02.mp3'); 85341 * } 85342 * function setup() { 85343 * background(0, 255, 0); 85344 * soundFile.setVolume(0.1); 85345 * soundFile.loop(); 85346 * } 85347 * function keyTyped() { 85348 * if (key == 'p') { 85349 * soundFile.pause(); 85350 * background(255, 0, 0); 85351 * } 85352 * } 85353 * 85354 * function keyReleased() { 85355 * if (key == 'p') { 85356 * soundFile.play(); 85357 * background(0, 255, 0); 85358 * } 85359 * } 85360 * </code> 85361 * </div> 85362 */ 85363 p5.SoundFile.prototype.pause = function (startTime) { 85364 var now = p5sound.audiocontext.currentTime; 85365 var time = startTime || 0; 85366 var pTime = time + now; 85367 if (this.isPlaying() && this.buffer && this.bufferSourceNode) { 85368 this.pauseTime = this.currentTime(); 85369 this.bufferSourceNode.stop(pTime); 85370 this._counterNode.stop(pTime); 85371 this._paused = true; 85372 this._playing = false;
85373 this._pauseTime = this.currentTime(); 85374 } else { 85375 this._pauseTime = 0; 85376 } 85377 }; 85378 /** 85379 * Loop the p5.SoundFile. Accepts optional parameters to set the 85380 * playback rate, playback volume, loopStart, loopEnd. 85381 * 85382 * @method loop 85383 * @param {Number} [startTime] (optional) schedule event to occur 85384 * seconds from now 85385 * @param {Number} [rate] (optional) playback rate 85386 * @param {Number} [amp] (optional) playback volume 85387 * @param {Number} [cueLoopStart] (optional) startTime in seconds 85388 * @param {Number} [duration] (optional) loop duration in seconds 85389 */ 85390 p5.SoundFile.prototype.loop = function (startTime, rate, amp, loopStart, duration) { 85391 this._looping = true; 85392 this.play(startTime, rate, amp, loopStart, duration); 85393 }; 85394 /** 85395 * Set a p5.SoundFile's looping flag to true or false. If the sound 85396 * is currently playing, this change will take effect when it 85397 * reaches the end of the current playback. 85398 * 85399 * @method setLoop 85400 * @param {Boolean} Boolean set looping to true or false 85401 */ 85402 p5.SoundFile.prototype.setLoop = function (bool) { 85403 if (bool === true) { 85404 this._looping = true; 85405 } else if (bool === false) { 85406 this._looping = false; 85407 } else { 85408 throw 'Error: setLoop accepts either true or false'; 85409 } 85410 if (this.bufferSourceNode) { 85411 this.bufferSourceNode.loop = this._looping; 85412 this._counterNode.loop = this._looping; 85413 } 85414 }; 85415 /** 85416 * Returns 'true' if a p5.SoundFile is currently looping and playing, 'false' if not. 85417 * 85418 * @method isLooping 85419 * @return {Boolean} 85420 */ 85421 p5.SoundFile.prototype.isLooping = function () { 85422 if (!this.bufferSourceNode) { 85423 return false; 85424 } 85425 if (this._looping === true && this.isPlaying() === true) { 85426 return true; 85427 } 85428 return false; 85429 }; 85430 /** 85431 * Returns true if a p5.SoundFile is playing, false if not (i.e. 85432 * paused or stopped). 85433 * 85434 * @method isPlaying 85435 * @return {Boolean} 85436 */ 85437 p5.SoundFile.prototype.isPlaying = function () { 85438 return this._playing; 85439 }; 85440 /** 85441 * Returns true if a p5.SoundFile is paused, false if not (i.e. 85442 * playing or stopped). 85443 * 85444 * @method isPaused 85445 * @return {Boolean} 85446 */ 85447 p5.SoundFile.prototype.isPaused = function () { 85448 return this._paused; 85449 }; 85450 /** 85451 * Stop soundfile playback. 85452 * 85453 * @method stop 85454 * @param {Number} [startTime] (optional) schedule event to occur 85455 * in seconds from now 85456 */ 85457 p5.SoundFile.prototype.stop = function (timeFromNow) { 85458 var time = timeFromNow || 0; 85459 if (this.mode === 'sustain' || this.mode === 'untildone') { 85460 this.stopAll(time); 85461 this._playing = false; 85462 this.pauseTime = 0; 85463 this._paused = false; 85464 } else if (this.buffer && this.bufferSourceNode) { 85465 var now = p5sound.audiocontext.currentTime; 85466 var t = time || 0; 85467 this.pauseTime = 0; 85468 this.bufferSourceNode.stop(now + t); 85469 this._counterNode.stop(now + t); 85470 this._playing = false; 85471 this._paused = false; 85472 } 85473 }; 85474 /** 85475 * Stop playback on all of this soundfile's sources. 85476 * @private 85477 */ 85478 p5.SoundFile.prototype.stopAll = function (_time) { 85479 var now = p5sound.audiocontext.currentTime; 85480 var time = _time || 0; 85481 if (this.buffer && this.bufferSourceNode) { 85482 for (var i = 0; i < this.bufferSourceNodes.length; i++) { 85483 if (typeof this.bufferSourceNodes[i] !== undefined) { 85484 try { 85485 this.bufferSourceNodes[i].onended = function () { 85486 }; 85487 this.bufferSourceNodes[i].stop(now + time); 85488 } catch (e) { 85489 } 85490 } 85491 } 85492 this._counterNode.stop(now + time); 85493 this._onended(this); 85494 } 85495 }; 85496 /** 85497 * Multiply the output volume (amplitude) of a sound file 85498 * between 0.0 (silence) and 1.0 (full volume). 85499 * 1.0 is the maximum amplitude of a digital sound, so multiplying 85500 * by greater than 1.0 may cause digital distortion. To 85501 * fade, provide a <code>rampTime</code> parameter. For more 85502 * complex fades, see the Envelope class. 85503 * 85504 * Alternately, you can pass in a signal source such as an 85505 * oscillator to modulate the amplitude with an audio signal. 85506 * 85507 * @method setVolume 85508 * @param {Number|Object} volume Volume (amplitude) between 0.0 85509 * and 1.0 or modulating signal/oscillator 85510 * @param {Number} [rampTime] Fade for t seconds 85511 * @param {Number} [timeFromNow] Schedule this event to happen at
85512 * t seconds in the future 85513 */ 85514 p5.SoundFile.prototype.setVolume = function (vol, _rampTime, _tFromNow) { 85515 if (typeof vol === 'number') { 85516 var rampTime = _rampTime || 0; 85517 var tFromNow = _tFromNow || 0; 85518 var now = p5sound.audiocontext.currentTime; 85519 var currentVol = this.output.gain.value; 85520 this.output.gain.cancelScheduledValues(now + tFromNow); 85521 this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow); 85522 this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime); 85523 } else if (vol) { 85524 vol.connect(this.output.gain); 85525 } else { 85526 // return the Gain Node 85527 return this.output.gain; 85528 } 85529 }; 85530 // same as setVolume, to match Processing Sound 85531 p5.SoundFile.prototype.amp = p5.SoundFile.prototype.setVolume; 85532 // these are the same thing 85533 p5.SoundFile.prototype.fade = p5.SoundFile.prototype.setVolume; 85534 p5.SoundFile.prototype.getVolume = function () { 85535 return this.output.gain.value; 85536 }; 85537 /** 85538 * Set the stereo panning of a p5.sound object to 85539 * a floating point number between -1.0 (left) and 1.0 (right). 85540 * Default is 0.0 (center). 85541 * 85542 * @method pan 85543 * @param {Number} [panValue] Set the stereo panner 85544 * @param {Number} [timeFromNow] schedule this event to happen 85545 * seconds from now 85546 * @example 85547 * <div><code> 85548 * 85549 * var ball = {}; 85550 * var soundFile; 85551 * 85552 * function preload() { 85553 * soundFormats('ogg', 'mp3'); 85554 * soundFile = loadSound('assets/beatbox.mp3'); 85555 * } 85556 * 85557 * function draw() { 85558 * background(0); 85559 * ball.x = constrain(mouseX, 0, width); 85560 * ellipse(ball.x, height/2, 20, 20) 85561 * } 85562 * 85563 * function mousePressed(){ 85564 * // map the ball's x location to a panning degree 85565 * // between -1.0 (left) and 1.0 (right) 85566 * var panning = map(ball.x, 0., width,-1.0, 1.0); 85567 * soundFile.pan(panning); 85568 * soundFile.play(); 85569 * } 85570 * </div></code> 85571 */ 85572 p5.SoundFile.prototype.pan = function (pval, tFromNow) { 85573 this.panPosition = pval; 85574 this.panner.pan(pval, tFromNow); 85575 }; 85576 /** 85577 * Returns the current stereo pan position (-1.0 to 1.0) 85578 * 85579 * @method getPan 85580 * @return {Number} Returns the stereo pan setting of the Oscillator 85581 * as a number between -1.0 (left) and 1.0 (right). 85582 * 0.0 is center and default. 85583 */ 85584 p5.SoundFile.prototype.getPan = function () { 85585 return this.panPosition; 85586 }; 85587 /** 85588 * Set the playback rate of a sound file. Will change the speed and the pitch. 85589 * Values less than zero will reverse the audio buffer. 85590 * 85591 * @method rate 85592 * @param {Number} [playbackRate] Set the playback rate. 1.0 is normal, 85593 * .5 is half-speed, 2.0 is twice as fast. 85594 * Values less than zero play backwards. 85595 * @example 85596 * <div><code> 85597 * var song; 85598 * 85599 * function preload() { 85600 * song = loadSound('assets/Damscray_DancingTiger.mp3'); 85601 * } 85602 * 85603 * function setup() { 85604 * song.loop(); 85605 * } 85606 * 85607 * function draw() { 85608 * background(200); 85609 * 85610 * // Set the rate to a range between 0.1 and 4 85611 * // Changing the rate also alters the pitch 85612 * var speed = map(mouseY, 0.1, height, 0, 2); 85613 * speed = constrain(speed, 0.01, 4); 85614 * song.rate(speed); 85615 * 85616 * // Draw a circle to show what is going on 85617 * stroke(0); 85618 * fill(51, 100); 85619 * ellipse(mouseX, 100, 48, 48); 85620 * } 85621 * 85622 * </code> 85623 * </div> 85624 * 85625 */ 85626 p5.SoundFile.prototype.rate = function (playbackRate) { 85627 var reverse = false; 85628 if (typeof playbackRate === 'undefined') { 85629 return this.playbackRate; 85630 } 85631 this.playbackRate = playbackRate; 85632 if (playbackRate === 0) { 85633 playbackRate = 1e-13; 85634 } else if (playbackRate < 0 && !this.reversed) { 85635 playbackRate = Math.abs(playbackRate); 85636 reverse = true; 85637 } else if (playbackRate > 0 && this.reversed) { 85638 reverse = true; 85639 } 85640 if (this.bufferSourceNode) { 85641 var now = p5sound.audiocontext.currentTime; 85642 this.bufferSourceNode.playbackRate.cancelScheduledValues(now); 85643 this.bufferSourceNode.playbackRate.linearRampToValueAtTime(Math.abs(playbackRate), now); 85644 this._counterNode.playbackRate.cancelScheduledValues(now); 85645 this._counterNode.playbackRate.linearRampToValueAtTime(Math.abs(playbackRate), now); 85646 } 85647 if (reverse) { 85648 this.reverseBuffer(); 85649 } 85650 return this.playbackRate; 85651 }; 85652 // TO DO: document this 85653 p5.SoundFile.prototype.setPitch = function (num) { 85654 var newPlaybackRate = midiToFreq(num) / midiToFreq(60); 85655 this.rate(newPlaybackRate); 85656 }; 85657 p5.SoundFile.prototype.getPlaybackRate = function () { 85658 return this.playbackRate; 85659 }; 85660 /** 85661 * Returns the duration of a sound file in seconds. 85662 * 85663 * @method duration 85664 * @return {Number} The duration of the soundFile in seconds. 85665 */ 85666 p5.SoundFile.prototype.duration = function () { 85667 // Return Duration 85668 if (this.buffer) { 85669 return this.buffer.duration; 85670 } else { 85671 return 0; 85672 } 85673 }; 85674 /** 85675 * Return the current position of the p5.SoundFile playhead, in seconds. 85676 * Time is relative to the normal buffer direction, so if `reverseBuffer` 85677 * has been called, currentTime will count backwards. 85678 * 85679 * @method currentTime 85680 * @return {Number} currentTime of the soundFile in seconds. 85681 */ 85682 p5.SoundFile.prototype.currentTime = function () { 85683 return this.reversed ? Math.abs(this._lastPos - this.buffer.length) / ac.sampleRate : this._lastPos / ac.sampleRate; 85684 }; 85685 /** 85686 * Move the playhead of the song to a position, in seconds. Start timing 85687 * and playback duration. If none are given, will reset the file to play 85688 * entire duration from start to finish. 85689 * 85690 * @method jump 85691 * @param {Number} cueTime cueTime of the soundFile in seconds. 85692 * @param {Number} duration duration in seconds. 85693 */ 85694 p5.SoundFile.prototype.jump = function (cueTime, duration) { 85695 if (cueTime < 0 || cueTime > this.buffer.duration) { 85696 throw 'jump time out of range'; 85697 } 85698 if (duration > this.buffer.duration - cueTime) { 85699 throw 'end time out of range'; 85700 } 85701 var cTime = cueTime || 0; 85702 var dur = duration || undefined; 85703 if (this.isPlaying()) { 85704 this.stop(0); 85705 } 85706 this.play(0, this.playbackRate, this.output.gain.value, cTime, dur); 85707 }; 85708 /** 85709 * Return the number of channels in a sound file. 85710 * For example, Mono = 1, Stereo = 2. 85711 * 85712 * @method channels 85713 * @return {Number} [channels] 85714 */ 85715 p5.SoundFile.prototype.channels = function () { 85716 return this.buffer.numberOfChannels; 85717 }; 85718 /** 85719 * Return the sample rate of the sound file. 85720 * 85721 * @method sampleRate 85722 * @return {Number} [sampleRate] 85723 */ 85724 p5.SoundFile.prototype.sampleRate = function () { 85725 return this.buffer.sampleRate; 85726 }; 85727 /** 85728 * Return the number of samples in a sound file. 85729 * Equal to sampleRate * duration. 85730 * 85731 * @method frames 85732 * @return {Number}
85732 [sampleCount] 85733 */ 85734 p5.SoundFile.prototype.frames = function () { 85735 return this.buffer.length; 85736 }; 85737 /** 85738 * Returns an array of amplitude peaks in a p5.SoundFile that can be 85739 * used to draw a static waveform. Scans through the p5.SoundFile's 85740 * audio buffer to find the greatest amplitudes. Accepts one 85741 * parameter, 'length', which determines size of the array. 85742 * Larger arrays result in more precise waveform visualizations. 85743 * 85744 * Inspired by Wavesurfer.js. 85745 * 85746 * @method getPeaks 85747 * @params {Number} [length] length is the size of the returned array. 85748 * Larger length results in more precision. 85749 * Defaults to 5*width of the browser window. 85750 * @returns {Float32Array} Array of peaks. 85751 */ 85752 p5.SoundFile.prototype.getPeaks = function (length) { 85753 if (this.buffer) { 85754 // set length to window's width if no length is provided 85755 if (!length) { 85756 length = window.width * 5; 85757 } 85758 if (this.buffer) { 85759 var buffer = this.buffer; 85760 var sampleSize = buffer.length / length; 85761 var sampleStep = ~~(sampleSize / 10) || 1; 85762 var channels = buffer.numberOfChannels; 85763 var peaks = new Float32Array(Math.round(length)); 85764 for (var c = 0; c < channels; c++) { 85765 var chan = buffer.getChannelData(c); 85766 for (var i = 0; i < length; i++) { 85767 var start = ~~(i * sampleSize); 85768 var end = ~~(start + sampleSize); 85769 var max = 0; 85770 for (var j = start; j < end; j += sampleStep) { 85771 var value = chan[j]; 85772 if (value > max) { 85773 max = value; 85774 } else if (-value > max) { 85775 max = value; 85776 } 85777 } 85778 if (c === 0 || Math.abs(max) > peaks[i]) { 85779 peaks[i] = max; 85780 } 85781 } 85782 } 85783 return peaks; 85784 } 85785 } else { 85786 throw 'Cannot load peaks yet, buffer is not loaded'; 85787 } 85788 }; 85789 /** 85790 * Reverses the p5.SoundFile's buffer source. 85791 * Playback must be handled separately (see example). 85792 * 85793 * @method reverseBuffer 85794 * @example 85795 * <div><code> 85796 * var drum; 85797 * 85798 * function preload() { 85799 * drum = loadSound('assets/drum.mp3'); 85800 * } 85801 * 85802 * function setup() { 85803 * drum.reverseBuffer(); 85804 * drum.play(); 85805 * } 85806 * 85807 * </code> 85808 * </div> 85809 */ 85810 p5.SoundFile.prototype.reverseBuffer = function () { 85811 if (this.buffer) { 85812 var currentPos = this._lastPos / ac.sampleRate; 85813 var curVol = this.getVolume(); 85814 this.setVolume(0, 0.001); 85815 const numChannels = this.buffer.numberOfChannels; 85816 for (var i = 0; i < numChannels; i++) { 85817 this.buffer.getChannelData(i).reverse(); 85818 } 85819 // set reversed flag 85820 this.reversed = !this.reversed; 85821 if (currentPos) { 85822 this.jump(this.duration() - currentPos); 85823 } 85824 this.setVolume(curVol, 0.001); 85825 } else { 85826 throw 'SoundFile is not done loading'; 85827 } 85828 }; 85829 /** 85830 * Schedule an event to be called when the soundfile 85831 * reaches the end of a buffer. If the soundfile is 85832 * playing through once, this will be called when it 85833 * ends. If it is looping, it will be called when 85834 * stop is called. 85835 * 85836 * @method onended 85837 * @param {Function} callback function to call when the 85838 * soundfile has ended. 85839 */ 85840 p5.SoundFile.prototype.onended = function (callback) { 85841 this._onended = callback; 85842 return this; 85843 }; 85844 p5.SoundFile.prototype.add = function () { 85845 }; 85846 p5.SoundFile.prototype.dispose = function () { 85847 var now = p5sound.audiocontext.currentTime; 85848 // remove reference to soundfile 85849 var index = p5sound.soundArray.indexOf(this); 85850 p5sound.soundArray.splice(index, 1); 85851 this.stop(now); 85852 if (this.buffer && this.bufferSourceNode) { 85853 for (var i = 0; i < this.bufferSourceNodes.length - 1; i++) { 85854 if (this.bufferSourceNodes[i] !== null) { 85855 this.bufferSourceNodes[i].disconnect(); 85856 try { 85857 this.bufferSourceNodes[i].stop(now); 85858 } catch (e) { 85859 console.warning('no buffer source node to dispose'); 85860 } 85861 this.bufferSourceNodes[i] = null; 85862 } 85863 } 85864 if (this.isPlaying()) { 85865 try { 85866 this._counterNode.stop(now); 85867 } catch (e) { 85868 console.log(e); 85869 } 85870 this._counterNode = null; 85871 } 85872 } 85873 if (this.output) { 85874 this.output.disconnect(); 85875 this.output = null; 85876 } 85877 if (this.panner) { 85878 this.panner.disconnect(); 85879 this.panner = null; 85880 } 85881 }; 85882 /** 85883 * Connects the output of a p5sound object to input of another 85884 * p5.sound object. For example, you may connect a p5.SoundFile to an 85885 * FFT or an Effect. If no parameter is given, it will connect to 85886 * the master output. Most p5sound objects connect to the master 85887 * output when they are created. 85888 * 85889 * @method connect 85890 * @param {Object} [object] Audio object that accepts an input 85891 */ 85892 p5.SoundFile.prototype.connect = function (unit) { 85893 if (!unit) { 85894 this.panner.connect(p5sound.input); 85895 } else { 85896 if (unit.hasOwnProperty('input')) {
85897 this.panner.connect(unit.input); 85898 } else { 85899 this.panner.connect(unit); 85900 } 85901 } 85902 }; 85903 /** 85904 * Disconnects the output of this p5sound object. 85905 * 85906 * @method disconnect 85907 */ 85908 p5.SoundFile.prototype.disconnect = function () { 85909 if (this.panner) { 85910 this.panner.disconnect(); 85911 } 85912 }; 85913 /** 85914 */ 85915 p5.SoundFile.prototype.getLevel = function () { 85916 console.warn('p5.SoundFile.getLevel has been removed from the library. Use p5.Amplitude instead'); 85917 }; 85918 /** 85919 * Reset the source for this SoundFile to a 85920 * new path (URL). 85921 * 85922 * @method setPath 85923 * @param {String} path path to audio file 85924 * @param {Function} callback Callback 85925 */ 85926 p5.SoundFile.prototype.setPath = function (p, callback) { 85927 var path = p5.prototype._checkFileFormats(p); 85928 this.url = path; 85929 this.load(callback); 85930 }; 85931 /** 85932 * Replace the current Audio Buffer with a new Buffer. 85933 * 85934 * @method setBuffer 85935 * @param {Array} buf Array of Float32 Array(s). 2 Float32 Arrays 85936 * will create a stereo source. 1 will create 85937 * a mono source. 85938 */ 85939 p5.SoundFile.prototype.setBuffer = function (buf) { 85940 var numChannels = buf.length; 85941 var size = buf[0].length; 85942 var newBuffer = ac.createBuffer(numChannels, size, ac.sampleRate); 85943 if (!(buf[0] instanceof Float32Array)) { 85944 buf[0] = new Float32Array(buf[0]); 85945 } 85946 for (var channelNum = 0; channelNum < numChannels; channelNum++) { 85947 var channel = newBuffer.getChannelData(channelNum); 85948 channel.set(buf[channelNum]); 85949 } 85950 this.buffer = newBuffer; 85951 // set numbers of channels on input to the panner 85952 this.panner.inputChannels(numChannels); 85953 }; 85954 ////////////////////////////////////////////////// 85955 // script processor node with an empty buffer to help 85956 // keep a sample-accurate position in playback buffer. 85957 // Inspired by Chinmay Pendharkar's technique for Sonoport --> http://bit.ly/1HwdCsV 85958 // Copyright [2015] [Sonoport (Asia) Pte. Ltd.], 85959 // Licensed under the Apache License http://apache.org/licenses/LICENSE-2.0 85960 //////////////////////////////////////////////////////////////////////////////////// 85961 var _createCounterBuffer = function (buffer) { 85962 const len = buffer.length; 85963 const audioBuf = ac.createBuffer(1, buffer.length, ac.sampleRate); 85964 const arrayBuffer = audioBuf.getChannelData(0); 85965 for (var index = 0; index < len; index++) { 85966 arrayBuffer[index] = index; 85967 } 85968 return audioBuf; 85969 }; 85970 // initialize counterNode, set its initial buffer and playbackRate 85971 p5.SoundFile.prototype._initCounterNode = function () { 85972 var self = this; 85973 var now = ac.currentTime; 85974 var cNode = ac.createBufferSource(); 85975 // dispose of scope node if it already exists 85976 if (self._scopeNode) { 85977 self._scopeNode.disconnect(); 85978 delete self._scopeNode.onaudioprocess; 85979 delete self._scopeNode; 85980 } 85981 self._scopeNode = ac.createScriptProcessor(256, 1, 1); 85982 // create counter buffer of the same length as self.buffer 85983 cNode.buffer = _createCounterBuffer(self.buffer); 85984 cNode.playbackRate.setValueAtTime(self.playbackRate, now); 85985 cNode.connect(self._scopeNode); 85986 self._scopeNode.connect(p5.soundOut._silentNode); 85987 self._scopeNode.onaudioprocess = function (processEvent) { 85988 var inputBuffer = processEvent.inputBuffer.getChannelData(0); 85989 self._lastPos = inputBuffer[inputBuffer.length - 1] || 0; 85990 // do any callbacks that have been scheduled 85991 self._onTimeUpdate(self._lastPos); 85992 }; 85993 return cNode; 85994 }; 85995 // initialize sourceNode, set its initial buffer and playbackRate 85996 p5.SoundFile.prototype._initSourceNode = function () { 85997 var bufferSourceNode = ac.createBufferSource(); 85998 bufferSourceNode.buffer = this.buffer; 85999 bufferSourceNode.playbackRate.value = this.playbackRate; 86000 bufferSourceNode.connect(this.output); 86001 return bufferSourceNode; 86002 }; 86003 /** 86004 * processPeaks returns an array of timestamps where it thinks there is a beat. 86005 * 86006 * This is an asynchronous function that processes the soundfile in an offline audio context, 86007 * and sends the results to your callback function. 86008 * 86009 * The process involves running the soundfile through a lowpass filter, and finding all of the 86010 * peaks above the initial threshold. If the total number of peaks are below the minimum number of peaks, 86011 * it decreases the threshold and re-runs the analysis until either minPeaks or minThreshold are reached. 86012 * 86013 * @method processPeaks 86014 * @param {Function} callback a function to call once this data is returned 86015 * @param {Number} [initThreshold] initial threshold defaults to 0.9 86016 * @param {Number} [minThreshold] minimum threshold defaults to 0.22 86017 * @param {Number} [minPeaks] minimum number of peaks defaults to 200 86018 * @return {Array} Array of timestamped peaks 86019 */ 86020 p5.SoundFile.prototype.processPeaks = function (callback, _initThreshold, _minThreshold, _minPeaks) { 86021 var bufLen = this.buffer.length; 86022 var sampleRate = this.buffer.sampleRate; 86023 var buffer = this.buffer; 86024 var allPeaks = []; 86025 var initialThreshold = _initThreshold || 0.9, threshold = initialThreshold, minThreshold = _minThreshold || 0.22, minPeaks = _minPeaks || 200; 86026 // Create offline context 86027 var offlineContext = new window.OfflineAudioContext(1, bufLen, sampleRate); 86028 // create buffer source 86029 var source = offlineContext.createBufferSource(); 86030 source.buffer = buffer; 86031 // Create filter. TO DO: allow custom setting of filter 86032 var filter = offlineContext.createBiquadFilter(); 86033 filter.type = 'lowpass'; 86034 source.connect(filter); 86035 filter.connect(offlineContext.destination); 86036 // start playing at time:0 86037 source.start(0); 86038 offlineContext.startRendering(); 86039 // Render the song 86040 // act on the result 86041 offlineContext.oncomplete = function (e) { 86042 if (!self.panner) 86043 return; 86044 var filteredBuffer = e.renderedBuffer; 86045 var bufferData = filteredBuffer.getChannelData(0); 86046 // step 1: 86047 // create Peak instances, add them to array, with strength and sampleIndex 86048 do { 86049 allPeaks = getPeaksAtThreshold(bufferData, threshold); 86050 threshold -= 0.005; 86051 } while (Object.keys(allPeaks).length < minPeaks && threshold >= minThreshold); 86052 // step 2: 86053 // find intervals for each peak in the sampleIndex, add tempos array 86054 var intervalCounts = countIntervalsBetweenNearbyPeaks(allPeaks); 86055 // step 3: find top tempos 86056 var groups = groupNeighborsByTempo(intervalCounts, filteredBuffer.sampleRate); 86057 // sort top intervals 86058 var topTempos = groups.sort(function (intA, intB) { 86059 return intB.count - intA.count; 86060 }).splice(0, 5); 86061 // set this SoundFile's tempo to the top tempo ?? 86062 this.tempo = topTempos[0].tempo; 86063 // step 4: 86064 // new array of peaks at top tempo within a bpmVariance 86065 var bpmVariance = 5; 86066 var tempoPeaks = getPeaksAtTopTempo(allPeaks, topTempos[0].tempo, filteredBuffer.sampleRate, bpmVariance); 86067 callback(tempoPeaks); 86068 }; 86069 }; 86070 // process peaks 86071 var Peak = function (amp, i) { 86072 this.sampleIndex = i; 86073 this.amplitude = amp; 86074 this.tempos = []; 86075 this.intervals = []; 86076 };
86077 // 1. for processPeaks() Function to identify peaks above a threshold 86078 // returns an array of peak indexes as frames (samples) of the original soundfile 86079 function getPeaksAtThreshold(data, threshold) { 86080 var peaksObj = {}; 86081 var length = data.length; 86082 for (var i = 0; i < length; i++) { 86083 if (data[i] > threshold) { 86084 var amp = data[i]; 86085 var peak = new Peak(amp, i); 86086 peaksObj[i] = peak; 86087 // Skip forward ~ 1/8s to get past this peak. 86088 i += 6000; 86089 } 86090 i++; 86091 } 86092 return peaksObj; 86093 } 86094 // 2. for processPeaks() 86095 function countIntervalsBetweenNearbyPeaks(peaksObj) { 86096 var intervalCounts = []; 86097 var peaksArray = Object.keys(peaksObj).sort(); 86098 for (var index = 0; index < peaksArray.length; index++) { 86099 // find intervals in comparison to nearby peaks 86100 for (var i = 0; i < 10; i++) { 86101 var startPeak = peaksObj[peaksArray[index]]; 86102 var endPeak = peaksObj[peaksArray[index + i]]; 86103 if (startPeak && endPeak) { 86104 var startPos = startPeak.sampleIndex; 86105 var endPos = endPeak.sampleIndex; 86106 var interval = endPos - startPos; 86107 // add a sample interval to the startPeak in the allPeaks array 86108 if (interval > 0) { 86109 startPeak.intervals.push(interval); 86110 } 86111 // tally the intervals and return interval counts 86112 var foundInterval = intervalCounts.some(function (intervalCount) { 86113 if (intervalCount.interval === interval) { 86114 intervalCount.count++; 86115 return intervalCount; 86116 } 86117 }); 86118 // store with JSON like formatting 86119 if (!foundInterval) { 86120 intervalCounts.push({ 86121 interval: interval, 86122 count: 1 86123 }); 86124 } 86125 } 86126 } 86127 } 86128 return intervalCounts; 86129 } 86130 // 3. for processPeaks --> find tempo 86131 function groupNeighborsByTempo(intervalCounts, sampleRate) { 86132 var tempoCounts = []; 86133 intervalCounts.forEach(function (intervalCount) { 86134 try { 86135 // Convert an interval to tempo 86136 var theoreticalTempo = Math.abs(60 / (intervalCount.interval / sampleRate)); 86137 theoreticalTempo = mapTempo(theoreticalTempo); 86138 var foundTempo = tempoCounts.some(function (tempoCount) { 86139 if (tempoCount.tempo === theoreticalTempo) 86140 return tempoCount.count += intervalCount.count; 86141 }); 86142 if (!foundTempo) { 86143 if (isNaN(theoreticalTempo)) { 86144 return; 86145 } 86146 tempoCounts.push({ 86147 tempo: Math.round(theoreticalTempo), 86148 count: intervalCount.count 86149 }); 86150 } 86151 } catch (e) { 86152 throw e; 86153 } 86154 }); 86155 return tempoCounts; 86156 } 86157 // 4. for processPeaks - get peaks at top tempo 86158 function getPeaksAtTopTempo(peaksObj, tempo, sampleRate, bpmVariance) { 86159 var peaksAtTopTempo = []; 86160 var peaksArray = Object.keys(peaksObj).sort(); 86161 // TO DO: filter out peaks that have the tempo and return 86162 for (var i = 0; i < peaksArray.length; i++) { 86163 var key = peaksArray[i]; 86164 var peak = peaksObj[key]; 86165 for (var j = 0; j < peak.intervals.length; j++) { 86166 var intervalBPM = Math.round(Math.abs(60 / (peak.intervals[j] / sampleRate))); 86167 intervalBPM = mapTempo(intervalBPM); 86168 if (Math.abs(intervalBPM - tempo) < bpmVariance) { 86169 // convert sampleIndex to seconds 86170 peaksAtTopTempo.push(peak.sampleIndex / sampleRate); 86171 } 86172 } 86173 } 86174 // filter out peaks that are very close to each other 86175 peaksAtTopTempo = peaksAtTopTempo.filter(function (peakTime, index, arr) { 86176 var dif = arr[index + 1] - peakTime; 86177 if (dif > 0.01) { 86178 return true; 86179 } 86180 }); 86181 return peaksAtTopTempo; 86182 } 86183 // helper function for processPeaks 86184 function mapTempo(theoreticalTempo) { 86185 // these scenarios create infinite while loop 86186 if (!isFinite(theoreticalTempo) || theoreticalTempo === 0) { 86187 return; 86188 } 86189 // Adjust the tempo to fit within the 90-180 BPM range 86190 while (theoreticalTempo < 90) 86191 theoreticalTempo *= 2; 86192 while (theoreticalTempo > 180 && theoreticalTempo > 90) 86193 theoreticalTempo /= 2; 86194 return theoreticalTempo; 86195 } 86196 /*** SCHEDULE EVENTS ***/ 86197 // Cue inspired by JavaScript setTimeout, and the 86198 // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org 86199 var Cue = function (callback, time, id, val) { 86200 this.callback = callback; 86201 this.time = time; 86202 this.id = id; 86203 this.val = val; 86204 }; 86205 /** 86206 * Schedule events to trigger every time a MediaElement 86207 * (audio/video) reaches a playback cue point. 86208 * 86209 * Accepts a callback function, a time (in seconds) at which to trigger 86210 * the callback, and an optional parameter for the callback. 86211 * 86212 * Time will be passed as the first parameter to the callback function, 86213 * and param will be the second parameter. 86214 * 86215 * 86216 * @method addCue 86217 * @param {Number} time Time in seconds, relative to this media 86218 * element's playback. For example, to trigger 86219 * an event every time playback reaches two 86220 * seconds, pass in the number 2. This will be 86221 * passed as the first parameter to 86222 * the callback function. 86223 * @param {Function} callback Name of a function that will be 86224 * called at the given time. The callback will 86225 * receive time and (optionally) param as its 86226 * two parameters. 86227 * @param {Object} [value] An object to be passed as the 86228 * second parameter to the 86229 * callback function. 86230 * @return {Number} id ID of this cue, 86231 * useful for removeCue(id) 86232 * @example 86233 * <div><code> 86234 * var mySound; 86235 * function preload() { 86236 * mySound = loadSound('assets/beat.mp3'); 86237 * } 86238 * 86239 * function setup() { 86240 * background(0); 86241 * noStroke(); 86242 * fill(255); 86243 * textAlign(CENTER); 86244 * text('click to play', width/2, height/2); 86245 * 86246 * // schedule calls to changeText 86247 * mySound.addCue(0.50, changeText, "hello" ); 86248 * mySound.addCue(1.00, changeText, "p5" ); 86249 * mySound.addCue(1.50, changeText, "what" ); 86250 * mySound.addCue(2.00, changeText, "do" ); 86251 * mySound.addCue(2.50, changeText, "you" ); 86252 * mySound.addCue(3.00, changeText, "want" ); 86253 * mySound.addCue(4.00, changeText, "to" ); 86254 * mySound.addCue(5.00, changeText, "make" );
86255 * mySound.addCue(6.00, changeText, "?" ); 86256 * } 86257 * 86258 * function changeText(val) { 86259 * background(0); 86260 * text(val, width/2, height/2); 86261 * } 86262 * 86263 * function mouseClicked() { 86264 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 86265 * if (mySound.isPlaying() ) { 86266 * mySound.stop(); 86267 * } else { 86268 * mySound.play(); 86269 * } 86270 * } 86271 * } 86272 * </code></div> 86273 */ 86274 p5.SoundFile.prototype.addCue = function (time, callback, val) { 86275 var id = this._cueIDCounter++; 86276 var cue = new Cue(callback, time, id, val); 86277 this._cues.push(cue); 86278 // if (!this.elt.ontimeupdate) { 86279 // this.elt.ontimeupdate = this._onTimeUpdate.bind(this); 86280 // } 86281 return id; 86282 }; 86283 /** 86284 * Remove a callback based on its ID. The ID is returned by the 86285 * addCue method. 86286 * 86287 * @method removeCue 86288 * @param {Number} id ID of the cue, as returned by addCue 86289 */ 86290 p5.SoundFile.prototype.removeCue = function (id) { 86291 var cueLength = this._cues.length; 86292 for (var i = 0; i < cueLength; i++) { 86293 var cue = this._cues[i]; 86294 if (cue.id === id) { 86295 this._cues.splice(i, 1); 86296 break; 86297 } 86298 } 86299 if (this._cues.length === 0) { 86300 } 86301 }; 86302 /** 86303 * Remove all of the callbacks that had originally been scheduled 86304 * via the addCue method. 86305 * 86306 * @method clearCues 86307 */ 86308 p5.SoundFile.prototype.clearCues = function () { 86309 this._cues = []; 86310 }; 86311 // private method that checks for cues to be fired if events 86312 // have been scheduled using addCue(callback, time).
86313 p5.SoundFile.prototype._onTimeUpdate = function (position) { 86314 var playbackTime = position / this.buffer.sampleRate; 86315 var cueLength = this._cues.length; 86316 for (var i = 0; i < cueLength; i++) { 86317 var cue = this._cues[i]; 86318 var callbackTime = cue.time; 86319 var val = cue.val; 86320 if (this._prevTime < callbackTime && callbackTime <= playbackTime) { 86321 // pass the scheduled callbackTime as parameter to the callback 86322 cue.callback(val); 86323 } 86324 } 86325 this._prevTime = playbackTime; 86326 }; 86327 /** 86328 * Save a p5.SoundFile as a .wav file. The browser will prompt the user 86329 * to download the file to their device. To upload a file to a server, see 86330 * <a href="/docs/reference/#/p5.SoundFile/getBlob">getBlob</a> 86331 * 86332 * @method save 86333 * @param {String} [fileName] name of the resulting .wav file. 86334 * @example 86335 * <div><code> 86336 * var inp, button, mySound; 86337 * var fileName = 'cool'; 86338 * function preload() { 86339 * mySound = loadSound('assets/doorbell.mp3'); 86340 * } 86341 * function setup() { 86342 * btn = createButton('click to save file'); 86343 * btn.position(0, 0); 86344 * btn.mouseClicked(handleMouseClick); 86345 * } 86346 * 86347 * function handleMouseClick() { 86348 * mySound.save(fileName); 86349 * } 86350 * </code></div> 86351 */ 86352 p5.SoundFile.prototype.save = function (fileName) { 86353 const dataView = convertToWav(this.buffer); 86354 p5.prototype.saveSound([dataView], fileName, 'wav'); 86355 }; 86356 /** 86357 * This method is useful for sending a SoundFile to a server. It returns the 86358 * .wav-encoded audio data as a "<a target="_blank" title="Blob reference at 86359 * MDN" href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>". 86360 * A Blob is a file-like data object that can be uploaded to a server 86361 * with an <a href="/docs/reference/#/p5/httpDo">http</a> request. We'll 86362 * use the `httpDo` options object to send a POST request with some 86363 * specific options: we encode the request as `multipart/form-data`, 86364 * and attach the blob as one of the form values using `FormData`. 86365 * 86366 * 86367 * @method getBlob 86368 * @returns {Blob} A file-like data object 86369 * @example 86370 * <div><code> 86371 * 86372 * function preload() { 86373 * mySound = loadSound('assets/doorbell.mp3'); 86374 * } 86375 * 86376 * function setup() { 86377 * noCanvas(); 86378 * var soundBlob = mySound.getBlob(); 86379 * 86380 * // Now we can send the blob to a server... 86381 * var serverUrl = 'https://jsonplaceholder.typicode.com/posts'; 86382 * var httpRequestOptions = { 86383 * method: 'POST', 86384 * body: new FormData().append('soundBlob', soundBlob), 86385 * headers: new Headers({ 86386 * 'Content-Type': 'multipart/form-data' 86387 * }) 86388 * }; 86389 * httpDo(serverUrl, httpRequestOptions); 86390 * 86391 * // We can also create an `ObjectURL` pointing to the Blob 86392 * var blobUrl = URL.createObjectURL(soundBlob); 86393 * 86394 * // The `<Audio>` Element accepts Object URL's 86395 * var htmlAudioElt = createAudio(blobUrl).showControls(); 86396 * 86397 * createDiv(); 86398 * 86399 * // The ObjectURL exists as long as this tab is open 86400 * var input = createInput(blobUrl); 86401 * input.attribute('readonly', true); 86402 * input.mouseClicked(function() { input.elt.select() }); 86403 * } 86404 * 86405 * </code></div> 86406 */ 86407 p5.SoundFile.prototype.getBlob = function () { 86408 const dataView = convertToWav(this.buffer); 86409 return new Blob([dataView], { type: 'audio/wav' }); 86410 }; 86411}(errorHandler, master, helpers, helpers); 86412var amplitude; 86413'use strict'; 86414amplitude = function () { 86415 var p5sound = master; 86416 /** 86417 * Amplitude measures volume between 0.0 and 1.0. 86418 * Listens to all p5sound by default, or use setInput() 86419 * to listen to a specific sound source. Accepts an optional 86420 * smoothing value, which defaults to 0. 86421 * 86422 * @class p5.Amplitude 86423 * @constructor 86424 * @param {Number} [smoothing] between 0.0 and .999 to smooth 86425 * amplitude readings (defaults to 0) 86426 * @example 86427 * <div><code> 86428 * var sound, amplitude, cnv; 86429 * 86430 * function preload(){ 86431 * sound = loadSound('assets/beat.mp3'); 86432 * } 86433 * function setup() { 86434 * cnv = createCanvas(100,100); 86435 * amplitude = new p5.Amplitude(); 86436 * 86437 * // start / stop the sound when canvas is clicked 86438 * cnv.mouseClicked(function() { 86439 * if (sound.isPlaying() ){ 86440 * sound.stop(); 86441 * } else { 86442 * sound.play(); 86443 * } 86444 * }); 86445 * } 86446 * function draw() { 86447 * background(0); 86448 * fill(255); 86449 * var level = amplitude.getLevel(); 86450 * var size = map(level, 0, 1, 0, 200); 86451 * ellipse(width/2, height/2, size, size); 86452 * } 86453 * 86454 * </code></div> 86455 */ 86456 p5.Amplitude = function (smoothing) { 86457 // Set to 2048 for now. In future iterations, this should be inherited or parsed from p5sound's default 86458 this.bufferSize = 2048; 86459 // set audio context 86460 this.audiocontext = p5sound.audiocontext; 86461 this.processor = this.audiocontext.createScriptProcessor(this.bufferSize, 2, 1); 86462 // for connections 86463 this.input = this.processor; 86464 this.output = this.audiocontext.createGain(); 86465 // smoothing defaults to 0 86466 this.smoothing = smoothing || 0; 86467 // the variables to return 86468 this.volume = 0; 86469 this.average = 0; 86470 this.stereoVol = [ 86471 0, 86472 0 86473 ]; 86474 this.stereoAvg = [ 86475 0, 86476 0 86477 ]; 86478 this.stereoVolNorm = [ 86479 0, 86480 0 86481 ]; 86482 this.volMax = 0.001; 86483 this.normalize = false;
86484 this.processor.onaudioprocess = this._audioProcess.bind(this); 86485 this.processor.connect(this.output); 86486 this.output.gain.value = 0; 86487 // this may only be necessary because of a Chrome bug 86488 this.output.connect(this.audiocontext.destination); 86489 // connect to p5sound master output by default, unless set by input() 86490 p5sound.meter.connect(this.processor); 86491 // add this p5.SoundFile to the soundArray 86492 p5sound.soundArray.push(this); 86493 }; 86494 /** 86495 * Connects to the p5sound instance (master output) by default. 86496 * Optionally, you can pass in a specific source (i.e. a soundfile). 86497 * 86498 * @method setInput 86499 * @param {soundObject|undefined} [snd] set the sound source 86500 * (optional, defaults to 86501 * master output) 86502 * @param {Number|undefined} [smoothing] a range between 0.0 and 1.0 86503 * to smooth amplitude readings 86504 * @example 86505 * <div><code> 86506 * function preload(){ 86507 * sound1 = loadSound('assets/beat.mp3'); 86508 * sound2 = loadSound('assets/drum.mp3'); 86509 * } 86510 * function setup(){ 86511 * amplitude = new p5.Amplitude(); 86512 * sound1.play(); 86513 * sound2.play(); 86514 * amplitude.setInput(sound2); 86515 * } 86516 * function draw() { 86517 * background(0); 86518 * fill(255); 86519 * var level = amplitude.getLevel(); 86520 * var size = map(level, 0, 1, 0, 200); 86521 * ellipse(width/2, height/2, size, size); 86522 * } 86523 * function mouseClicked(){ 86524 * sound1.stop(); 86525 * sound2.stop(); 86526 * } 86527 * </code></div> 86528 */ 86529 p5.Amplitude.prototype.setInput = function (source, smoothing) { 86530 p5sound.meter.disconnect(); 86531 if (smoothing) { 86532 this.smoothing = smoothing; 86533 } 86534 // connect to the master out of p5s instance if no snd is provided 86535 if (source == null) { 86536 console.log('Amplitude input source is not ready! Connecting to master output instead'); 86537 p5sound.meter.connect(this.processor); 86538 } else if (source instanceof p5.Signal) { 86539 source.output.connect(this.processor); 86540 } else if (source) { 86541 source.connect(this.processor); 86542 this.processor.disconnect(); 86543 this.processor.connect(this.output); 86544 } else { 86545 p5sound.meter.connect(this.processor); 86546 } 86547 }; 86548 p5.Amplitude.prototype.connect = function (unit) { 86549 if (unit) { 86550 if (unit.hasOwnProperty('input')) { 86551 this.output.connect(unit.input); 86552 } else { 86553 this.output.connect(unit); 86554 } 86555 } else { 86556 this.output.connect(this.panner.connect(p5sound.input)); 86557 } 86558 }; 86559 p5.Amplitude.prototype.disconnect = function () { 86560 if (this.output) { 86561 this.output.disconnect(); 86562 } 86563 }; 86564 // TO DO make this stereo / dependent on # of audio channels 86565 p5.Amplitude.prototype._audioProcess = function (event) { 86566 for (var channel = 0; channel < event.inputBuffer.numberOfChannels; channel++) { 86567 var inputBuffer = event.inputBuffer.getChannelData(channel); 86568 var bufLength = inputBuffer.length; 86569 var total = 0; 86570 var sum = 0; 86571 var x; 86572 for (var i = 0; i < bufLength; i++) { 86573 x = inputBuffer[i]; 86574 if (this.normalize) { 86575 total += Math.max(Math.min(x / this.volMax, 1), -1); 86576 sum += Math.max(Math.min(x / this.volMax, 1), -1) * Math.max(Math.min(x / this.volMax, 1), -1); 86577 } else { 86578 total += x; 86579 sum += x * x; 86580 } 86581 } 86582 var average = total / bufLength; 86583 // ... then take the square root of the sum. 86584 var rms = Math.sqrt(sum / bufLength); 86585 this.stereoVol[channel] = Math.max(rms, this.stereoVol[channel] * this.smoothing); 86586 this.stereoAvg[channel] = Math.max(average, this.stereoVol[channel] * this.smoothing); 86587 this.volMax = Math.max(this.stereoVol[channel], this.volMax); 86588 } 86589 // add volume from all channels together 86590 var self = this; 86591 var volSum = this.stereoVol.reduce(function (previousValue, currentValue, index) { 86592 self.stereoVolNorm[index - 1] = Math.max(Math.min(self.stereoVol[index - 1] / self.volMax, 1), 0); 86593 self.stereoVolNorm[index] = Math.max(Math.min(self.stereoVol[index] / self.volMax, 1), 0); 86594 return previousValue + currentValue; 86595 }); 86596 // volume is average of channels 86597 this.volume = volSum / this.stereoVol.length; 86598 // normalized value 86599 this.volNorm = Math.max(Math.min(this.volume / this.volMax, 1), 0); 86600 }; 86601 /** 86602 * Returns a single Amplitude reading at the moment it is called. 86603 * For continuous readings, run in the draw loop. 86604 * 86605 * @method getLevel 86606 * @param {Number} [channel] Optionally return only channel 0 (left) or 1 (right) 86607 * @return {Number} Amplitude as a number between 0.0 and 1.0 86608 * @example 86609 * <div><code> 86610 * function preload(){ 86611 * sound = loadSound('assets/beat.mp3'); 86612 * } 86613 * function setup() { 86614 * amplitude = new p5.Amplitude(); 86615 * sound.play(); 86616 * } 86617 * function draw() { 86618 * background(0); 86619 * fill(255); 86620 * var level = amplitude.getLevel(); 86621 * var size = map(level, 0, 1, 0, 200); 86622 * ellipse(width/2, height/2, size, size); 86623 * } 86624 * function mouseClicked(){ 86625 * sound.stop(); 86626 * } 86627 * </code></div> 86628 */ 86629 p5.Amplitude.prototype.getLevel = function (channel) { 86630 if (typeof channel !== 'undefined') { 86631 if (this.normalize) { 86632 return this.stereoVolNorm[channel]; 86633 } else { 86634 return this.stereoVol[channel]; 86635 } 86636 } else if (this.normalize) { 86637 return this.volNorm; 86638 } else { 86639 return this.volume; 86640 } 86641 }; 86642 /** 86643 * Determines whether the results of Amplitude.process() will be 86644 * Normalized. To normalize, Amplitude finds the difference the 86645 * loudest reading it has processed and the maximum amplitude of 86646 * 1.0. Amplitude adds this difference to all values to produce 86647 * results that will reliably map between 0.0 and 1.0. However, 86648 * if a louder moment occurs, the amount that Normalize adds to 86649 * all the values will change. Accepts an optional boolean parameter 86650 * (true or false). Normalizing is off by default. 86651 * 86652 * @method toggleNormalize 86653 * @param {boolean} [boolean] set normalize to true (1) or false (0) 86654 */ 86655 p5.Amplitude.prototype.toggleNormalize = function (bool) { 86656 if (typeof bool === 'boolean') { 86657 this.normalize = bool; 86658 } else { 86659 this.normalize = !this.normalize; 86660 } 86661 }; 86662 /** 86663 * Smooth Amplitude analysis by averaging with the last analysis 86664 * frame. Off by default. 86665 * 86666 * @method smooth 86667 * @param {Number} set smoothing from 0.0 <= 1 86668 */ 86669 p5.Amplitude.prototype.smooth = function (s) { 86670 if (s >= 0 && s < 1) { 86671 this.smoothing = s; 86672 } else { 86673 console.log('Error: smoothing must be between 0 and 1'); 86674 } 86675 }; 86676 p5.Amplitude.prototype.dispose = function () { 86677 // remove reference from soundArray 86678 var index = p5sound.soundArray.indexOf(this); 86679 p5sound.soundArray.splice(index, 1); 86680 if (this.input) { 86681 this.input.disconnect(); 86682 delete this.input; 86683 } 86684 if (this.output) { 86685 this.output.disconnect(); 86686 delete this.output; 86687 } 86688 delete this.processor; 86689 }; 86690}(master); 86691var fft; 86692'use strict'; 86693fft = function () { 86694 var p5sound = master; 86695 /** 86696 * <p>
86696FFT (Fast Fourier Transform) is an analysis algorithm that 86697 * isolates individual 86698 * <a href="https://en.wikipedia.org/wiki/Audio_frequency"> 86699 * audio frequencies</a> within a waveform.</p> 86700 * 86701 * <p>Once instantiated, a p5.FFT object can return an array based on 86702 * two types of analyses: <br> ⢠<code>FFT.waveform()</code> computes 86703 * amplitude values along the time domain. The array indices correspond 86704 * to samples across a brief moment in time. Each value represents 86705 * amplitude of the waveform at that sample of time.<br> 86706 * ⢠<code>FFT.analyze() </code> computes amplitude values along the 86707 * frequency domain. The array indices correspond to frequencies (i.e. 86708 * pitches), from the lowest to the highest that humans can hear. Each 86709 * value represents amplitude at that slice of the frequency spectrum. 86710 * Use with <code>getEnergy()</code> to measure amplitude at specific 86711 * frequencies, or within a range of frequencies. </p> 86712 * 86713 * <p>FFT analyzes a very short snapshot of sound called a sample 86714 * buffer. It returns an array of amplitude measurements, referred 86715 * to as <code>bins</code>. The array is 1024 bins long by default. 86716 * You can change the bin array length, but it must be a power of 2 86717 * between 16 and 1024 in order for the FFT algorithm to function 86718 * correctly. The actual size of the FFT buffer is twice the 86719 * number of bins, so given a standard sample rate, the buffer is 86720 * 2048/44100 seconds long.</p> 86721 * 86722 * 86723 * @class p5.FFT 86724 * @constructor 86725 * @param {Number} [smoothing] Smooth results of Freq Spectrum. 86726 * 0.0 < smoothing < 1.0. 86727 * Defaults to 0.8. 86728 * @param {Number} [bins] Length of resulting array. 86729 * Must be a power of two between 86730 * 16 and 1024. Defaults to 1024. 86731 * @example 86732 * <div><code> 86733 * function preload(){ 86734 * sound = loadSound('assets/Damscray_DancingTiger.mp3'); 86735 * } 86736 * 86737 * function setup(){ 86738 * var cnv = createCanvas(100,100); 86739 * cnv.mouseClicked(togglePlay); 86740 * fft = new p5.FFT(); 86741 * sound.amp(0.2); 86742 * } 86743 * 86744 * function draw(){ 86745 * background(0); 86746 * 86747 * var spectrum = fft.analyze(); 86748 * noStroke(); 86749 * fill(0,255,0); // spectrum is green 86750 * for (var i = 0; i< spectrum.length; i++){ 86751 * var x = map(i, 0, spectrum.length, 0, width); 86752 * var h = -height + map(spectrum[i], 0, 255, height, 0); 86753 * rect(x, height, width / spectrum.length, h ) 86754 * } 86755 * 86756 * var waveform = fft.waveform(); 86757 * noFill(); 86758 * beginShape(); 86759 * stroke(255,0,0); // waveform is red 86760 * strokeWeight(1); 86761 * for (var i = 0; i< waveform.length; i++){ 86762 * var x = map(i, 0, waveform.length, 0, width); 86763 * var y = map( waveform[i], -1, 1, 0, height); 86764 * vertex(x,y); 86765 * } 86766 * endShape(); 86767 * 86768 * text('click to play/pause', 4, 10); 86769 * } 86770 * 86771 * // fade sound if mouse is over canvas 86772 * function togglePlay() { 86773 * if (sound.isPlaying()) { 86774 * sound.pause(); 86775 * } else { 86776 * sound.loop(); 86777 * } 86778 * } 86779 * </code></div> 86780 */ 86781 p5.FFT = function (smoothing, bins) { 86782 this.input = this.analyser = p5sound.audiocontext.createAnalyser();
86783 Object.defineProperties(this, { 86784 bins: { 86785 get: function () { 86786 return this.analyser.fftSize / 2; 86787 }, 86788 set: function (b) { 86789 this.analyser.fftSize = b * 2; 86790 }, 86791 configurable: true, 86792 enumerable: true 86793 }, 86794 smoothing: { 86795 get: function () { 86796 return this.analyser.smoothingTimeConstant; 86797 }, 86798 set: function (s) { 86799 this.analyser.smoothingTimeConstant = s; 86800 }, 86801 configurable: true, 86802 enumerable: true 86803 } 86804 }); 86805 // set default smoothing and bins 86806 this.smooth(smoothing); 86807 this.bins = bins || 1024; 86808 // default connections to p5sound fftMeter 86809 p5sound.fftMeter.connect(this.analyser); 86810 this.freqDomain = new Uint8Array(this.analyser.frequencyBinCount); 86811 this.timeDomain = new Uint8Array(this.analyser.frequencyBinCount); 86812 // predefined frequency ranges, these will be tweakable 86813 this.bass = [ 86814 20, 86815 140 86816 ]; 86817 this.lowMid = [ 86818 140, 86819 400 86820 ]; 86821 this.mid = [ 86822 400, 86823 2600 86824 ]; 86825 this.highMid = [ 86826 2600, 86827 5200 86828 ]; 86829 this.treble = [ 86830 5200, 86831 14000 86832 ]; 86833 // add this p5.SoundFile to the soundArray 86834 p5sound.soundArray.push(this); 86835 }; 86836 /** 86837 * Set the input source for the FFT analysis. If no source is 86838 * provided, FFT will analyze all sound in the sketch. 86839 * 86840 * @method setInput 86841 * @param {Object} [source] p5.sound object (or web audio API source node) 86842 */ 86843 p5.FFT.prototype.setInput = function (source) { 86844 if (!source) { 86845 p5sound.fftMeter.connect(this.analyser); 86846 } else { 86847 if (source.output) { 86848 source.output.connect(this.analyser); 86849 } else if (source.connect) { 86850 source.connect(this.analyser); 86851 } 86852 p5sound.fftMeter.disconnect(); 86853 } 86854 }; 86855 /** 86856 * Returns an array of amplitude values (between -1.0 and +1.0) that represent 86857 * a snapshot of amplitude readings in a single buffer. Length will be 86858 * equal to bins (defaults to 1024). Can be used to draw the waveform 86859 * of a sound. 86860 * 86861 * @method waveform 86862 * @param {Number} [bins] Must be a power of two between 86863 * 16 and 1024. Defaults to 1024. 86864 * @param {String} [precision] If any value is provided, will return results 86865 * in a Float32 Array which is more precise 86866 * than a regular array. 86867 * @return {Array} Array Array of amplitude values (-1 to 1) 86868 * over time. Array length = bins. 86869 * 86870 */ 86871 p5.FFT.prototype.waveform = function () { 86872 var bins, mode, normalArray; 86873 for (var i = 0; i < arguments.length; i++) { 86874 if (typeof arguments[i] === 'number') { 86875 bins = arguments[i]; 86876 this.analyser.fftSize = bins * 2; 86877 } 86878 if (typeof arguments[i] === 'string') { 86879 mode = arguments[i]; 86880 } 86881 } 86882 // getFloatFrequencyData doesnt work in Safari as of 5/2015 86883 if (mode && !p5.prototype._isSafari()) { 86884 timeToFloat(this, this.timeDomain); 86885 this.analyser.getFloatTimeDomainData(this.timeDomain); 86886 return this.timeDomain; 86887 } else { 86888 timeToInt(this, this.timeDomain); 86889 this.analyser.getByteTimeDomainData(this.timeDomain); 86890 var normalArray = new Array(); 86891 for (var j = 0; j < this.timeDomain.length; j++) { 86892 var scaled = p5.prototype.map(this.timeDomain[j], 0, 255, -1, 1); 86893 normalArray.push(scaled); 86894 } 86895 return normalArray; 86896 } 86897 }; 86898 /** 86899 * Returns an array of amplitude values (between 0 and 255) 86900 * across the frequency spectrum. Length is equal to FFT bins 86901 * (1024 by default). The array indices correspond to frequencies 86902 * (i.e. pitches), from the lowest to the highest that humans can 86903 * hear. Each value represents amplitude at that slice of the 86904 * frequency spectrum. Must be called prior to using 86905 * <code>getEnergy()</code>. 86906 * 86907 * @method analyze 86908 * @param {Number} [bins] Must be a power of two between 86909 * 16 and 1024. Defaults to 1024. 86910 * @param {Number} [scale] If "dB," returns decibel 86911 * float measurements between
86912 * -140 and 0 (max). 86913 * Otherwise returns integers from 0-255. 86914 * @return {Array} spectrum Array of energy (amplitude/volume) 86915 * values across the frequency spectrum. 86916 * Lowest energy (silence) = 0, highest 86917 * possible is 255. 86918 * @example 86919 * <div><code> 86920 * var osc; 86921 * var fft; 86922 * 86923 * function setup(){ 86924 * createCanvas(100,100); 86925 * osc = new p5.Oscillator(); 86926 * osc.amp(0); 86927 * osc.start(); 86928 * fft = new p5.FFT(); 86929 * } 86930 * 86931 * function draw(){ 86932 * background(0); 86933 * 86934 * var freq = map(mouseX, 0, 800, 20, 15000); 86935 * freq = constrain(freq, 1, 20000); 86936 * osc.freq(freq); 86937 * 86938 * var spectrum = fft.analyze(); 86939 * noStroke(); 86940 * fill(0,255,0); // spectrum is green 86941 * for (var i = 0; i< spectrum.length; i++){ 86942 * var x = map(i, 0, spectrum.length, 0, width); 86943 * var h = -height + map(spectrum[i], 0, 255, height, 0); 86944 * rect(x, height, width / spectrum.length, h ); 86945 * } 86946 * 86947 * stroke(255); 86948 * text('Freq: ' + round(freq)+'Hz', 10, 10); 86949 * 86950 * isMouseOverCanvas(); 86951 * } 86952 * 86953 * // only play sound when mouse is over canvas 86954 * function isMouseOverCanvas() { 86955 * var mX = mouseX, mY = mouseY; 86956 * if (mX > 0 && mX < width && mY < height && mY > 0) { 86957 * osc.amp(0.5, 0.2); 86958 * } else { 86959 * osc.amp(0, 0.2); 86960 * } 86961 * } 86962 * </code></div> 86963 * 86964 * 86965 */ 86966 p5.FFT.prototype.analyze = function () { 86967 var mode; 86968 for (var i = 0; i < arguments.length; i++) { 86969 if (typeof arguments[i] === 'number') { 86970 this.bins = arguments[i]; 86971 this.analyser.fftSize = this.bins * 2; 86972 } 86973 if (typeof arguments[i] === 'string') { 86974 mode = arguments[i]; 86975 } 86976 } 86977 if (mode && mode.toLowerCase() === 'db') { 86978 freqToFloat(this); 86979 this.analyser.getFloatFrequencyData(this.freqDomain); 86980 return this.freqDomain; 86981 } else { 86982 freqToInt(this, this.freqDomain); 86983 this.analyser.getByteFrequencyData(this.freqDomain); 86984 var normalArray = Array.apply([], this.freqDomain); 86985 normalArray.length === this.analyser.fftSize; 86986 normalArray.constructor === Array; 86987 return normalArray; 86988 } 86989 }; 86990 /** 86991 * Returns the amount of energy (volume) at a specific 86992 * <a href="https://en.wikipedia.org/wiki/Audio_frequency" target="_blank"> 86993 * frequency</a>, or the average amount of energy between two 86994 * frequencies. Accepts Number(s) corresponding 86995 * to frequency (in Hz), or a String corresponding to predefined 86996 * frequency ranges ("bass", "lowMid", "mid", "highMid", "treble"). 86997 * Returns a range between 0 (no energy/volume at that frequency) and 86998 * 255 (maximum energy). 86999 * <em>NOTE: analyze() must be called prior to getEnergy(). Analyze() 87000 * tells the FFT to analyze frequency data, and getEnergy() uses 87001 * the results determine the value at a specific frequency or 87002 * range of frequencies.</em></p> 87003 * 87004 * @method getEnergy 87005 * @param {Number|String} frequency1 Will return a value representing 87006 * energy at this frequency. Alternately, 87007 * the strings "bass", "lowMid" "mid", 87008 * "highMid", and "treble" will return 87009 * predefined frequency ranges. 87010 * @param {Number} [frequency2] If a second frequency is given, 87011 * will return average amount of 87012 * energy that exists between the 87013 * two frequencies. 87014 * @return {Number} Energy Energy (volume/amplitude) from 87015 * 0 and 255. 87016 * 87017 */ 87018 p5.FFT.prototype.getEnergy = function (frequency1, frequency2) { 87019 var nyquist = p5sound.audiocontext.sampleRate / 2; 87020 if (frequency1 === 'bass') { 87021 frequency1 = this.bass[0]; 87022 frequency2 = this.bass[1]; 87023 } else if (frequency1 === 'lowMid') { 87024 frequency1 = this.lowMid[0]; 87025 frequency2 = this.lowMid[1]; 87026 } else if (frequency1 === 'mid') { 87027 frequency1 = this.mid[0]; 87028 frequency2 = this.mid[1]; 87029 } else if (frequency1 === 'highMid') { 87030 frequency1 = this.highMid[0]; 87031 frequency2 = this.highMid[1]; 87032 } else if (frequency1 === 'treble') { 87033 frequency1 = this.treble[0]; 87034 frequency2 = this.treble[1]; 87035 } 87036 if (typeof frequency1 !== 'number') {
87037 throw 'invalid input for getEnergy()'; 87038 } else if (!frequency2) { 87039 // if only one parameter: 87040 var index = Math.round(frequency1 / nyquist * this.freqDomain.length); 87041 return this.freqDomain[index]; 87042 } else if (frequency1 && frequency2) { 87043 // if two parameters: 87044 // if second is higher than first 87045 if (frequency1 > frequency2) { 87046 var swap = frequency2; 87047 frequency2 = frequency1; 87048 frequency1 = swap; 87049 } 87050 var lowIndex = Math.round(frequency1 / nyquist * this.freqDomain.length); 87051 var highIndex = Math.round(frequency2 / nyquist * this.freqDomain.length); 87052 var total = 0; 87053 var numFrequencies = 0; 87054 // add up all of the values for the frequencies 87055 for (var i = lowIndex; i <= highIndex; i++) { 87056 total += this.freqDomain[i]; 87057 numFrequencies += 1; 87058 } 87059 // divide by total number of frequencies 87060 var toReturn = total / numFrequencies; 87061 return toReturn; 87062 } else { 87063 throw 'invalid input for getEnergy()'; 87064 } 87065 }; 87066 // compatability with v.012, changed to getEnergy in v.0121. Will be deprecated... 87067 p5.FFT.prototype.getFreq = function (freq1, freq2) { 87068 console.log('getFreq() is deprecated. Please use getEnergy() instead.'); 87069 var x = this.getEnergy(freq1, freq2); 87070 return x; 87071 }; 87072 /** 87073 * Returns the 87074 * <a href="http://en.wikipedia.org/wiki/Spectral_centroid" target="_blank"> 87075 * spectral centroid</a> of the input signal. 87076 * <em>NOTE: analyze() must be called prior to getCentroid(). Analyze() 87077 * tells the FFT to analyze frequency data, and getCentroid() uses 87078 * the results determine the spectral centroid.</em></p> 87079 * 87080 * @method getCentroid 87081 * @return {Number} Spectral Centroid Frequency Frequency of the spectral centroid in Hz. 87082 * 87083 * 87084 * @example 87085 * <div><code> 87086 * 87087 * 87088 *function setup(){ 87089 * cnv = createCanvas(100,100); 87090 * sound = new p5.AudioIn(); 87091 * sound.start(); 87092 * fft = new p5.FFT(); 87093 * sound.connect(fft); 87094 *} 87095 * 87096 * 87097 *function draw(){ 87098 * 87099 * var centroidplot = 0.0; 87100 * var spectralCentroid = 0; 87101 * 87102 * 87103 * background(0); 87104 * stroke(0,255,0); 87105 * var spectrum = fft.analyze(); 87106 * fill(0,255,0); // spectrum is green 87107 * 87108 * //draw the spectrum 87109 * for (var i = 0; i< spectrum.length; i++){ 87110 * var x = map(log(i), 0, log(spectrum.length), 0, width); 87111 * var h = map(spectrum[i], 0, 255, 0, height); 87112 * var rectangle_width = (log(i+1)-log(i))*(width/log(spectrum.length)); 87113 * rect(x, height, rectangle_width, -h ) 87114 * } 87115 87116 * var nyquist = 22050; 87117 * 87118 * // get the centroid 87119 * spectralCentroid = fft.getCentroid(); 87120 * 87121 * // the mean_freq_index calculation is for the display. 87122 * var mean_freq_index = spectralCentroid/(nyquist/spectrum.length); 87123 * 87124 * centroidplot = map(log(mean_freq_index), 0, log(spectrum.length), 0, width); 87125 * 87126 * 87127 * stroke(255,0,0); // the line showing where the centroid is will be red 87128 * 87129 * rect(centroidplot, 0, width / spectrum.length, height) 87130 * noStroke(); 87131 * fill(255,255,255); // text is white 87132 * text("centroid: ", 10, 20); 87133 * text(round(spectralCentroid)+" Hz", 10, 40); 87134 *} 87135 * </code></div> 87136 */ 87137 p5.FFT.prototype.getCentroid = function () { 87138 var nyquist = p5sound.audiocontext.sampleRate / 2; 87139 var cumulative_sum = 0; 87140 var centroid_normalization = 0; 87141 for (var i = 0; i < this.freqDomain.length; i++) { 87142 cumulative_sum += i * this.freqDomain[i]; 87143 centroid_normalization += this.freqDomain[i]; 87144 } 87145 var mean_freq_index = 0; 87146 if (centroid_normalization !== 0) { 87147 mean_freq_index = cumulative_sum / centroid_normalization; 87148 } 87149 var spec_centroid_freq = mean_freq_index * (nyquist / this.freqDomain.length); 87150 return spec_centroid_freq; 87151 }; 87152 /** 87153 * Smooth FFT analysis by averaging with the last analysis frame. 87154 * 87155 * @method smooth 87156 * @param {Number} smoothing 0.0 < smoothing < 1.0. 87157 * Defaults to 0.8. 87158 */ 87159 p5.FFT.prototype.smooth = function (s) { 87160 if (typeof s !== 'undefined') { 87161 this.smoothing = s; 87162 } 87163 return this.smoothing; 87164 }; 87165 p5.FFT.prototype.dispose = function () { 87166 // remove reference from soundArray 87167 var index = p5sound.soundArray.indexOf(this); 87168 p5sound.soundArray.splice(index, 1); 87169 if (this.analyser) { 87170 this.analyser.disconnect(); 87171 delete this.analyser; 87172 } 87173 }; 87174 /** 87175 * Returns an array of average amplitude values for a given number 87176 * of frequency bands split equally. N defaults to 16. 87177 * <em>NOTE: analyze() must be called prior to linAverages(). Analyze() 87178 * tells the FFT to analyze frequency data, and linAverages() uses 87179 * the results to group them into a smaller set of averages.</em></p> 87180 * 87181 * @method linAverages 87182 * @param {Number} N Number of returned frequency groups 87183 * @return {Array} linearAverages Array of average amplitude values for each group 87184 */ 87185 p5.FFT.prototype.linAverages = function (N) { 87186 var N = N || 16; 87187 // This prevents undefined, null or 0 values of N 87188 var spectrum = this.freqDomain; 87189 var spectrumLength = spectrum.length; 87190 var spectrumStep = Math.floor(spectrumLength / N); 87191 var linearAverages = new Array(N); 87192 // Keep a second index for the current average group and place the values accordingly 87193 // with only one loop in the spectrum data 87194 var groupIndex = 0; 87195 for (var specIndex = 0; specIndex < spectrumLength; specIndex++) { 87196 linearAverages[groupIndex] = linearAverages[groupIndex] !== undefined ? (linearAverages[groupIndex] + spectrum[specIndex]) / 2 : spectrum[specIndex]; 87197 // Increase the group index when the last element of the group is processed 87198 if (specIndex % spectrumStep === spectrumStep - 1) { 87199 groupIndex++; 87200 } 87201 } 87202 return linearAverages; 87203 }; 87204 /** 87205 * Returns an array of average amplitude values of the spectrum, for a given 87206 * set of <a href="https://en.wikipedia.org/wiki/Octave_band" target="_blank"> 87207 * Octave Bands</a> 87208 * <em>NOTE: analyze() must be called prior to logAverages(). Analyze() 87209 * tells the FFT to analyze frequency data, and logAverages() uses 87210 * the results to group them into a smaller set of averages.</em></p> 87211 * 87212 * @method logAverages 87213 * @param {Array} octaveBands Array of Octave Bands objects for grouping 87214 * @return {Array} logAverages Array of average amplitude values for each group 87215 */ 87216 p5.FFT.prototype.logAverages = function (octaveBands) { 87217 var nyquist = p5sound.audiocontext.sampleRate / 2; 87218 var spectrum = this.freqDomain; 87219 var spectrumLength = spectrum.length; 87220 var logAverages = new Array(octaveBands.length); 87221 // Keep a second index for the current average group and place the values accordingly 87222 // With only one loop in the spectrum data 87223 var octaveIndex = 0; 87224 for (var specIndex = 0; specIndex < spectrumLength; specIndex++) { 87225 var specIndexFrequency = Math.round(specIndex * nyquist / this.freqDomain.length); 87226 // Increase the group index if the current frequency exceeds the limits of the band 87227 if (specIndexFrequency > octaveBands[octaveIndex].hi) { 87228 octaveIndex++; 87229 } 87230 logAverages[octaveIndex] = logAverages[octaveIndex] !== undefined ? (logAverages[octaveIndex] + spectrum[specIndex]) / 2 : spectrum[specIndex]; 87231 } 87232 return logAverages; 87233 }; 87234 /** 87235 * Calculates and Returns the 1/N 87236 * <a href="https://en.wikipedia.org/wiki/Octave_band" target="_blank">Octave Bands</a> 87237 * N defaults to 3 and minimum central frequency to 15.625Hz. 87238 * (1/3 Octave Bands ~= 31 Frequency Bands) 87239 * Setting fCtr0 to a central value of a higher octave will ignore the lower bands 87240 * and produce less frequency groups. 87241 * 87242 * @method getOctaveBands 87243 * @param {Number} N Specifies the 1/N type of generated octave bands 87244 * @param {Number} fCtr0 Minimum central frequency for the lowest band 87245 * @return {Array} octaveBands Array of octave band objects with their bounds 87246 */ 87247 p5.FFT.prototype.getOctaveBands = function (N, fCtr0) { 87248 var N = N || 3; 87249 // Default to 1/3 Octave Bands 87250 var fCtr0 = fCtr0 || 15.625; 87251 // Minimum central frequency, defaults to 15.625Hz 87252 var octaveBands = []; 87253 var lastFrequencyBand = { 87254 lo: fCtr0 / Math.pow(2, 1 / (2 * N)), 87255 ctr: fCtr0, 87256 hi: fCtr0 * Math.pow(2, 1 / (2 * N)) 87257 }; 87258 octaveBands.push(lastFrequencyBand); 87259 var nyquist = p5sound.audiocontext.sampleRate / 2; 87260 while (lastFrequencyBand.hi < nyquist) { 87261 var newFrequencyBand = {}; 87262 newFrequencyBand.lo = lastFrequencyBand.hi; 87263 newFrequencyBand.ctr = lastFrequencyBand.ctr * Math.pow(2, 1 / N); 87264 newFrequencyBand.hi = newFrequencyBand.ctr * Math.pow(2, 1 / (2 * N)); 87265 octaveBands.push(newFrequencyBand); 87266 lastFrequencyBand = newFrequencyBand; 87267 } 87268 return octaveBands; 87269 }; 87270 // helper methods to convert type from float (dB) to int (0-255) 87271 var freqToFloat = function (fft) { 87272 if (fft.freqDomain instanceof Float32Array === false) { 87273 fft.freqDomain = new Float32Array(fft.analyser.frequencyBinCount); 87274 } 87275 }; 87276 var freqToInt = function (fft) { 87277 if (fft.freqDomain instanceof Uint8Array === false) { 87278 fft.freqDomain = new Uint8Array(fft.analyser.frequencyBinCount); 87279 } 87280 }; 87281 var timeToFloat = function (fft) { 87282 if (fft.timeDomain instanceof Float32Array === false) { 87283 fft.timeDomain = new Float32Array(fft.analyser.frequencyBinCount); 87284 } 87285 }; 87286 var timeToInt = function (fft) { 87287 if (fft.timeDomain instanceof Uint8Array === false) { 87288 fft.timeDomain = new Uint8Array(fft.analyser.frequencyBinCount); 87289 } 87290 }; 87291}(master); 87292/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 87293var Tone_core_Tone; 87294Tone_core_Tone = function () { 87295 'use strict'; 87296 var Tone = function (inputs, outputs) { 87297 if (this.isUndef(inputs) || inputs === 1) { 87298 this.input = this.context.createGain(); 87299 } else if (inputs > 1) { 87300 this.input = new Array(inputs); 87301 } 87302 if (this.isUndef(outputs) || outputs === 1) { 87303 this.output = this.context.createGain(); 87304 } else if (outputs > 1) { 87305 this.output = new Array(inputs); 87306 } 87307 }; 87308 Tone.prototype.set = function (params, value, rampTime) { 87309 if (this.isObject(params)) { 87310 rampTime = value; 87311 } else if (this.isString(params)) { 87312 var tmpObj = {}; 87313 tmpObj[params] = value; 87314 params = tmpObj; 87315 } 87316 paramLoop: 87317 for (var attr in params) { 87318 value = params[attr]; 87319 var parent = this; 87320 if (attr.indexOf('.') !== -1) { 87321 var attrSplit = attr.split('.'); 87322 for (var i = 0; i < attrSplit.length - 1; i++) { 87323 parent = parent[attrSplit[i]]; 87324 if (parent instanceof Tone) { 87325 attrSplit.splice(0, i + 1); 87326 var innerParam = attrSplit.join('.'); 87327 parent.set(innerParam, value); 87328 continue paramLoop; 87329 } 87330 } 87331 attr = attrSplit[attrSplit.length - 1]; 87332 } 87333 var param = parent[attr]; 87334 if (this.isUndef(param)) { 87335 continue; 87336 } 87337 if (Tone.Signal && param instanceof Tone.Signal || Tone.Param && param instanceof Tone.Param) { 87338 if (param.value !== value) { 87339 if (this.isUndef(rampTime)) { 87340 param.value = value; 87341 } else { 87342 param.rampTo(value, rampTime); 87343 } 87344 } 87345 } else if (param instanceof AudioParam) { 87346 if (param.value !== value) { 87347 param.value = value; 87348 } 87349 } else if (param instanceof Tone) { 87350 param.set(value); 87351 } else if (param !== value) { 87352 parent[attr] = value; 87353 } 87354 } 87355 return this; 87356 }; 87357 Tone.prototype.get = function (params) { 87358 if (this.isUndef(params)) { 87359 params = this._collectDefaults(this.constructor); 87360 } else if (this.isString(params)) { 87361 params = [params]; 87362 } 87363 var ret = {}; 87364 for (var i = 0; i < params.length; i++) { 87365 var attr = params[i]; 87366 var parent = this; 87367 var subRet = ret; 87368 if (attr.indexOf('.') !== -1) { 87369 var attrSplit = attr.split('.'); 87370 for (var j = 0; j < attrSplit.length - 1; j++) { 87371 var subAttr = attrSplit[j]; 87372 subRet[subAttr] = subRet[subAttr] || {}; 87373 subRet = subRet[subAttr]; 87374 parent = parent[subAttr]; 87375 } 87376 attr = attrSplit[attrSplit.length - 1]; 87377 } 87378 var param = parent[attr]; 87379 if (this.isObject(params[attr])) { 87380 subRet[attr] = param.get(); 87381 } else if (Tone.Signal && param instanceof Tone.Signal) { 87382 subRet[attr] = param.value; 87383 } else if (Tone.Param && param instanceof Tone.Param) { 87384 subRet[attr] = param.value; 87385 } else if (param instanceof AudioParam) { 87386 subRet[attr] = param.value; 87387 } else if (param instanceof Tone) { 87388 subRet[attr] = param.get(); 87389 } else if (!this.isFunction(param) && !this.isUndef(param)) { 87390 subRet[attr] = param; 87391 } 87392 } 87393 return ret; 87394 }; 87395 Tone.prototype._collectDefaults = function (constr) { 87396 var ret = []; 87397 if (!this.isUndef(constr.defaults)) { 87398 ret = Object.keys(constr.defaults); 87399 } 87400 if (!this.isUndef(constr._super)) { 87401 var superDefs = this._collectDefaults(constr._super); 87402 for (var i = 0; i < superDefs.length; i++) { 87403 if (ret.indexOf(superDefs[i]) === -1) {
87404 ret.push(superDefs[i]); 87405 } 87406 } 87407 } 87408 return ret; 87409 }; 87410 Tone.prototype.toString = function () { 87411 for (var className in Tone) { 87412 var isLetter = className[0].match(/^[A-Z]$/); 87413 var sameConstructor = Tone[className] === this.constructor; 87414 if (this.isFunction(Tone[className]) && isLetter && sameConstructor) { 87415 return className; 87416 } 87417 } 87418 return 'Tone'; 87419 }; 87420 Object.defineProperty(Tone.prototype, 'numberOfInputs', { 87421 get: function () { 87422 if (this.input) { 87423 if (this.isArray(this.input)) { 87424 return this.input.length; 87425 } else { 87426 return 1; 87427 } 87428 } else { 87429 return 0; 87430 } 87431 } 87432 }); 87433 Object.defineProperty(Tone.prototype, 'numberOfOutputs', { 87434 get: function () { 87435 if (this.output) { 87436 if (this.isArray(this.output)) { 87437 return this.output.length; 87438 } else { 87439 return 1; 87440 } 87441 } else { 87442 return 0; 87443 } 87444 } 87445 }); 87446 Tone.prototype.dispose = function () { 87447 if (!this.isUndef(this.input)) { 87448 if (this.input instanceof AudioNode) { 87449 this.input.disconnect(); 87450 } 87451 this.input = null; 87452 } 87453 if (!this.isUndef(this.output)) { 87454 if (this.output instanceof AudioNode) { 87455 this.output.disconnect(); 87456 } 87457 this.output = null; 87458 } 87459 return this; 87460 }; 87461 Tone.prototype.connect = function (unit, outputNum, inputNum) { 87462 if (Array.isArray(this.output)) { 87463 outputNum = this.defaultArg(outputNum, 0); 87464 this.output[outputNum].connect(unit, 0, inputNum); 87465 } else { 87466 this.output.connect(unit, outputNum, inputNum); 87467 } 87468 return this; 87469 }; 87470 Tone.prototype.disconnect = function (destination, outputNum, inputNum) { 87471 if (this.isArray(this.output)) { 87472 if (this.isNumber(destination)) { 87473 this.output[destination].disconnect(); 87474 } else { 87475 outputNum = this.defaultArg(outputNum, 0); 87476 this.output[outputNum].disconnect(destination, 0, inputNum); 87477 } 87478 } else { 87479 this.output.disconnect.apply(this.output, arguments); 87480 } 87481 }; 87482 Tone.prototype.connectSeries = function () { 87483 if (arguments.length > 1) { 87484 var currentUnit = arguments[0]; 87485 for (var i = 1; i < arguments.length; i++) { 87486 var toUnit = arguments[i]; 87487 currentUnit.connect(toUnit); 87488 currentUnit = toUnit; 87489 } 87490 } 87491 return this; 87492 }; 87493 Tone.prototype.chain = function () { 87494 if (arguments.length > 0) { 87495 var currentUnit = this; 87496 for (var i = 0; i < arguments.length; i++) { 87497 var toUnit = arguments[i]; 87498 currentUnit.connect(toUnit); 87499 currentUnit = toUnit; 87500 } 87501 } 87502 return this; 87503 }; 87504 Tone.prototype.fan = function () { 87505 if (arguments.length > 0) { 87506 for (var i = 0; i < arguments.length; i++) { 87507 this.connect(arguments[i]); 87508 } 87509 } 87510 return this; 87511 }; 87512 AudioNode.prototype.chain = Tone.prototype.chain; 87513 AudioNode.prototype.fan = Tone.prototype.fan; 87514 Tone.prototype.defaultArg = function (given, fallback) { 87515 if (this.isObject(given) && this.isObject(fallback)) { 87516 var ret = {}; 87517 for (var givenProp in given) { 87518 ret[givenProp] = this.defaultArg(fallback[givenProp], given[givenProp]); 87519 } 87520 for (var fallbackProp in fallback) { 87521 ret[fallbackProp] = this.defaultArg(given[fallbackProp], fallback[fallbackProp]); 87522 } 87523 return ret; 87524 } else { 87525 return this.isUndef(given) ? fallback : given; 87526 } 87527 }; 87528 Tone.prototype.optionsObject = function (values, keys, defaults) { 87529 var options = {}; 87530 if (values.length === 1 && this.isObject(values[0])) { 87531 options = values[0]; 87532 } else { 87533 for (var i = 0; i < keys.length; i++) { 87534 options[keys[i]] = values[i]; 87535 } 87536 } 87537 if (!this.isUndef(defaults)) { 87538 return this.defaultArg(options, defaults); 87539 } else { 87540 return options; 87541 } 87542 }; 87543 Tone.prototype.isUndef = function (val) { 87544 return typeof val === 'undefined'; 87545 }; 87546 Tone.prototype.isFunction = function (val) { 87547 return typeof val === 'function'; 87548 }; 87549 Tone.prototype.isNumber = function (arg) { 87550 return typeof arg === 'number'; 87551 }; 87552 Tone.prototype.isObject = function (arg) { 87553 return Object.prototype.toString.call(arg) === '[object Object]' && arg.constructor === Object; 87554 }; 87555 Tone.prototype.isBoolean = function (arg) { 87556 return typeof arg === 'boolean'; 87557 }; 87558 Tone.prototype.isArray = function (arg) { 87559 return Array.isArray(arg); 87560 }; 87561 Tone.prototype.isString = function (arg) { 87562 return typeof arg === 'string'; 87563 }; 87564 Tone.noOp = function () { 87565 }; 87566 Tone.prototype._readOnly = function (property) { 87567 if (Array.isArray(property)) { 87568 for (var i = 0; i < property.length; i++) { 87569 this._readOnly(property[i]); 87570 } 87571 } else { 87572 Object.defineProperty(this, property, { 87573 writable: false, 87574 enumerable: true 87575 }); 87576 } 87577 }; 87578 Tone.prototype._writable = function (property) { 87579 if (Array.isArray(property)) { 87580 for (var i = 0; i < property.length; i++) { 87581 this._writable(property[i]); 87582 } 87583 } else { 87584 Object.defineProperty(this, property, { writable: true }); 87585 } 87586 }; 87587 Tone.State = { 87588 Started: 'started', 87589 Stopped: 'stopped', 87590 Paused: 'paused' 87591 }; 87592 Tone.prototype.equalPowerScale = function (percent) { 87593 var piFactor = 0.5 * Math.PI; 87594 return Math.sin(percent * piFactor); 87595 }; 87596 Tone.prototype.dbToGain = function (db) { 87597 return Math.pow(2, db / 6); 87598 }; 87599 Tone.prototype.gainToDb = function (gain) { 87600 return 20 * (Math.log(gain) / Math.LN10); 87601 }; 87602 Tone.prototype.intervalToFrequencyRatio = function (interval) { 87603 return Math.pow(2, interval / 12); 87604 }; 87605 Tone.prototype.now = function () { 87606 return Tone.context.now(); 87607 }; 87608 Tone.now = function () { 87609 return Tone.context.now(); 87610 }; 87611 Tone.extend = function (child, parent) { 87612 if (Tone.prototype.isUndef(parent)) { 87613 parent = Tone; 87614 } 87615 function TempConstructor() { 87616 } 87617 TempConstructor.prototype = parent.prototype; 87618 child.prototype = new TempConstructor(); 87619 child.prototype.constructor = child; 87620 child._super = parent; 87621 }; 87622 var audioContext; 87623 Object.defineProperty(Tone, 'context', { 87624 get: function () { 87625 return audioContext; 87626 }, 87627 set: function (context) { 87628 if (Tone.Context && context instanceof Tone.Context) { 87629 audioContext = context; 87630 } else { 87631 audioContext = new Tone.Context(context); 87632 } 87633 if (Tone.Context) { 87634 Tone.Context.emit('init', audioContext); 87635 } 87636 } 87637 }); 87638 Object.defineProperty(Tone.prototype, 'context', { 87639 get: function () { 87640 return Tone.context; 87641 } 87642 }); 87643 Tone.setContext = function (ctx) { 87644 Tone.context = ctx; 87645 }; 87646 Object.defineProperty(Tone.prototype, 'blockTime', { 87647 get: function () { 87648 return 128 / this.context.sampleRate; 87649 } 87650 }); 87651 Object.defineProperty(Tone.prototype, 'sampleTime', { 87652 get: function () { 87653 return 1 / this.context.sampleRate; 87654 } 87655 }); 87656 Object.defineProperty(Tone, 'supported', { 87657 get: function () { 87658 var hasAudioContext = window.hasOwnProperty('AudioContext') || window.hasOwnProperty('webkitAudioContext'); 87659 var hasPromises = window.hasOwnProperty('Promise'); 87660 var hasWorkers = window.hasOwnProperty('Worker'); 87661 return hasAudioContext && hasPromises && hasWorkers; 87662 } 87663 }); 87664 Tone.version = 'r10'; 87665 if (!window.TONE_SILENCE_VERSION_LOGGING) { 87666 } 87667 return Tone; 87668}(); 87669/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 87670var Tone_signal_SignalBase; 87671Tone_signal_SignalBase = function (Tone) { 87672 'use strict'; 87673 Tone.SignalBase = function () { 87674 }; 87675 Tone.extend(Tone.SignalBase); 87676 Tone.SignalBase.prototype.connect = function (node, outputNumber, inputNumber) { 87677 if (Tone.Signal && Tone.Signal === node.constructor || Tone.Param && Tone.Param === node.constructor || Tone.TimelineSignal && Tone.TimelineSignal === node.constructor) { 87678 node._param.cancelScheduledValues(0); 87679 node._param.value = 0; 87680 node.overridden = true; 87681 } else if (node instanceof AudioParam) { 87682 node.cancelScheduledValues(0); 87683 node.value = 0; 87684 } 87685 Tone.prototype.connect.call(this, node, outputNumber, inputNumber); 87686 return this; 87687 }; 87688 return Tone.SignalBase; 87689}(Tone_core_Tone); 87690/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 87691var Tone_signal_WaveShaper; 87692Tone_signal_WaveShaper = function (Tone) { 87693 'use strict'; 87694 Tone.WaveShaper = function (mapping, bufferLen) { 87695 this._shaper = this.input = this.output = this.context.createWaveShaper(); 87696 this._curve = null; 87697 if (Array.isArray(mapping)) { 87698 this.curve = mapping; 87699 } else if (isFinite(mapping) || this.isUndef(mapping)) { 87700 this._curve = new Float32Array(this.defaultArg(mapping, 1024)); 87701 } else if (this.isFunction(mapping)) { 87702 this._curve = new Float32Array(this.defaultArg(bufferLen, 1024));
87703 this.setMap(mapping); 87704 } 87705 }; 87706 Tone.extend(Tone.WaveShaper, Tone.SignalBase); 87707 Tone.WaveShaper.prototype.setMap = function (mapping) { 87708 for (var i = 0, len = this._curve.length; i < len; i++) { 87709 var normalized = i / (len - 1) * 2 - 1; 87710 this._curve[i] = mapping(normalized, i); 87711 } 87712 this._shaper.curve = this._curve; 87713 return this; 87714 }; 87715 Object.defineProperty(Tone.WaveShaper.prototype, 'curve', { 87716 get: function () { 87717 return this._shaper.curve; 87718 }, 87719 set: function (mapping) { 87720 this._curve = new Float32Array(mapping); 87721 this._shaper.curve = this._curve; 87722 } 87723 }); 87724 Object.defineProperty(Tone.WaveShaper.prototype, 'oversample', { 87725 get: function () { 87726 return this._shaper.oversample; 87727 }, 87728 set: function (oversampling) { 87729 if ([ 87730 'none', 87731 '2x', 87732 '4x' 87733 ].indexOf(oversampling) !== -1) { 87734 this._shaper.oversample = oversampling; 87735 } else { 87736 throw new RangeError('Tone.WaveShaper: oversampling must be either \'none\', \'2x\', or \'4x\''); 87737 } 87738 } 87739 }); 87740 Tone.WaveShaper.prototype.dispose = function () { 87741 Tone.prototype.dispose.call(this); 87742 this._shaper.disconnect(); 87743 this._shaper = null; 87744 this._curve = null; 87745 return this; 87746 }; 87747 return Tone.WaveShaper; 87748}(Tone_core_Tone); 87749/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 87750var Tone_type_TimeBase; 87751Tone_type_TimeBase = function (Tone) { 87752 Tone.TimeBase = function (val, units) { 87753 if (this instanceof Tone.TimeBase) { 87754 this._expr = this._noOp; 87755 if (val instanceof Tone.TimeBase) { 87756 this.copy(val); 87757 } else if (!this.isUndef(units) || this.isNumber(val)) { 87758 units = this.defaultArg(units, this._defaultUnits); 87759 var method = this._primaryExpressions[units].method; 87760 this._expr = method.bind(this, val); 87761 } else if (this.isString(val)) { 87762 this.set(val); 87763 } else if (this.isUndef(val)) { 87764 this._expr = this._defaultExpr(); 87765 } 87766 } else { 87767 return new Tone.TimeBase(val, units); 87768 } 87769 }; 87770 Tone.extend(Tone.TimeBase); 87771 Tone.TimeBase.prototype.set = function (exprString) { 87772 this._expr = this._parseExprString(exprString); 87773 return this; 87774 }; 87775 Tone.TimeBase.prototype.clone = function () { 87776 var instance = new this.constructor(); 87777 instance.copy(this); 87778 return instance; 87779 }; 87780 Tone.TimeBase.prototype.copy = function (time) { 87781 var val = time._expr(); 87782 return this.set(val); 87783 }; 87784 Tone.TimeBase.prototype._primaryExpressions = { 87785 'n': { 87786 regexp: /^(\d+)n/i, 87787 method: function (value) { 87788 value = parseInt(value); 87789 if (value === 1) { 87790 return this._beatsToUnits(this._timeSignature()); 87791 } else { 87792 return this._beatsToUnits(4 / value); 87793 } 87794 } 87795 }, 87796 't': { 87797 regexp: /^(\d+)t/i, 87798 method: function (value) { 87799 value = parseInt(value); 87800 return this._beatsToUnits(8 / (parseInt(value) * 3)); 87801 } 87802 }, 87803 'm': { 87804 regexp: /^(\d+)m/i, 87805 method: function (value) { 87806 return this._beatsToUnits(parseInt(value) * this._timeSignature()); 87807 } 87808 }, 87809 'i': { 87810 regexp: /^(\d+)i/i, 87811 method: function (value) { 87812 return this._ticksToUnits(parseInt(value)); 87813 } 87814 }, 87815 'hz': { 87816 regexp: /^(\d+(?:\.\d+)?)hz/i, 87817 method: function (value) { 87818 return this._frequencyToUnits(parseFloat(value)); 87819 } 87820 }, 87821 'tr': { 87822 regexp: /^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/, 87823 method: function (m, q, s) { 87824 var total = 0; 87825 if (m && m !== '0') { 87826 total += this._beatsToUnits(this._timeSignature() * parseFloat(m)); 87827 } 87828 if (q && q !== '0') { 87829 total += this._beatsToUnits(parseFloat(q)); 87830 } 87831 if (s && s !== '0') { 87832 total += this._beatsToUnits(parseFloat(s) / 4); 87833 } 87834 return total; 87835 } 87836 }, 87837 's': { 87838 regexp: /^(\d+(?:\.\d+)?s)/, 87839 method: function (value) { 87840 return this._secondsToUnits(parseFloat(value)); 87841 } 87842 }, 87843 'samples': { 87844 regexp: /^(\d+)samples/, 87845 method: function (value) { 87846 return parseInt(value) / this.context.sampleRate; 87847 } 87848 }, 87849 'default': { 87850 regexp: /^(\d+(?:\.\d+)?)/, 87851 method: function (value) { 87852 return this._primaryExpressions[this._defaultUnits].method.call(this, value); 87853 } 87854 } 87855 }; 87856 Tone.TimeBase.prototype._binaryExpressions = { 87857 '+': { 87858 regexp: /^\+/, 87859 precedence: 2, 87860 method: function (lh, rh) { 87861 return lh() + rh(); 87862 } 87863 }, 87864 '-': { 87865 regexp: /^\-/, 87866 precedence: 2, 87867 method: function (lh, rh) { 87868 return lh() - rh(); 87869 } 87870 }, 87871 '*': { 87872 regexp: /^\*/, 87873 precedence: 1, 87874 method: function (lh, rh) { 87875 return lh() * rh(); 87876 } 87877 }, 87878 '/': { 87879 regexp: /^\//, 87880 precedence: 1, 87881 method: function (lh, rh) { 87882 return lh() / rh(); 87883 } 87884 } 87885 }; 87886 Tone.TimeBase.prototype._unaryExpressions = { 87887 'neg': { 87888 regexp: /^\-/, 87889 method: function (lh) { 87890 return -lh(); 87891 } 87892 } 87893 }; 87894 Tone.TimeBase.prototype._syntaxGlue = { 87895 '(': { regexp: /^\(/ }, 87896 ')': { regexp: /^\)/ } 87897 }; 87898 Tone.TimeBase.prototype._tokenize = function (expr) { 87899 var position = -1; 87900 var tokens = []; 87901 while (expr.length > 0) { 87902 expr = expr.trim(); 87903 var token = getNextToken(expr, this); 87904 tokens.push(token); 87905 expr = expr.substr(token.value.length); 87906 } 87907 function getNextToken(expr, context) { 87908 var expressions = [ 87909 '_binaryExpressions', 87910 '_unaryExpressions', 87911 '_primaryExpressions', 87912 '_syntaxGlue' 87913 ]; 87914 for (var i = 0; i < expressions.length; i++) { 87915 var group = context[expressions[i]]; 87916 for (var opName in group) { 87917 var op = group[opName]; 87918 var reg = op.regexp; 87919 var match = expr.match(reg); 87920 if (match !== null) { 87921 return { 87922 method: op.method, 87923 precedence: op.precedence, 87924 regexp: op.regexp, 87925 value: match[0] 87926 }; 87927 } 87928 } 87929 } 87930 throw new SyntaxError('Tone.TimeBase: Unexpected token ' + expr); 87931 } 87932 return { 87933 next: function () { 87934 return tokens[++position]; 87935 }, 87936 peek: function () { 87937 return tokens[position + 1]; 87938 } 87939 }; 87940 }; 87941 Tone.TimeBase.prototype._matchGroup = function (token, group, prec) { 87942 var ret = false;
87943 if (!this.isUndef(token)) { 87944 for (var opName in group) { 87945 var op = group[opName]; 87946 if (op.regexp.test(token.value)) { 87947 if (!this.isUndef(prec)) { 87948 if (op.precedence === prec) { 87949 return op; 87950 } 87951 } else { 87952 return op; 87953 } 87954 } 87955 } 87956 } 87957 return ret; 87958 }; 87959 Tone.TimeBase.prototype._parseBinary = function (lexer, precedence) { 87960 if (this.isUndef(precedence)) { 87961 precedence = 2; 87962 } 87963 var expr; 87964 if (precedence < 0) { 87965 expr = this._parseUnary(lexer); 87966 } else { 87967 expr = this._parseBinary(lexer, precedence - 1); 87968 } 87969 var token = lexer.peek(); 87970 while (token && this._matchGroup(token, this._binaryExpressions, precedence)) { 87971 token = lexer.next(); 87972 expr = token.method.bind(this, expr, this._parseBinary(lexer, precedence - 1)); 87973 token = lexer.peek(); 87974 } 87975 return expr; 87976 }; 87977 Tone.TimeBase.prototype._parseUnary = function (lexer) { 87978 var token, expr; 87979 token = lexer.peek(); 87980 var op = this._matchGroup(token, this._unaryExpressions); 87981 if (op) { 87982 token = lexer.next(); 87983 expr = this._parseUnary(lexer); 87984 return op.method.bind(this, expr); 87985 } 87986 return this._parsePrimary(lexer); 87987 }; 87988 Tone.TimeBase.prototype._parsePrimary = function (lexer) { 87989 var token, expr; 87990 token = lexer.peek(); 87991 if (this.isUndef(token)) { 87992 throw new SyntaxError('Tone.TimeBase: Unexpected end of expression'); 87993 } 87994 if (this._matchGroup(token, this._primaryExpressions)) { 87995 token = lexer.next(); 87996 var matching = token.value.match(token.regexp); 87997 return token.method.bind(this, matching[1], matching[2], matching[3]); 87998 } 87999 if (token && token.value === '(') { 88000 lexer.next(); 88001 expr = this._parseBinary(lexer); 88002 token = lexer.next(); 88003 if (!(token && token.value === ')')) { 88004 throw new SyntaxError('Expected )'); 88005 } 88006 return expr; 88007 } 88008 throw new SyntaxError('Tone.TimeBase: Cannot process token ' + token.value); 88009 }; 88010 Tone.TimeBase.prototype._parseExprString = function (exprString) { 88011 if (!this.isString(exprString)) { 88012 exprString = exprString.toString(); 88013 } 88014 var lexer = this._tokenize(exprString); 88015 var tree = this._parseBinary(lexer); 88016 return tree; 88017 }; 88018 Tone.TimeBase.prototype._noOp = function () { 88019 return 0; 88020 }; 88021 Tone.TimeBase.prototype._defaultExpr = function () { 88022 return this._noOp; 88023 }; 88024 Tone.TimeBase.prototype._defaultUnits = 's'; 88025 Tone.TimeBase.prototype._frequencyToUnits = function (freq) { 88026 return 1 / freq; 88027 }; 88028 Tone.TimeBase.prototype._beatsToUnits = function (beats) { 88029 return 60 / Tone.Transport.bpm.value * beats; 88030 }; 88031 Tone.TimeBase.prototype._secondsToUnits = function (seconds) { 88032 return seconds; 88033 }; 88034 Tone.TimeBase.prototype._ticksToUnits = function (ticks) { 88035 return ticks * (this._beatsToUnits(1) / Tone.Transport.PPQ); 88036 }; 88037 Tone.TimeBase.prototype._timeSignature = function () { 88038 return Tone.Transport.timeSignature; 88039 }; 88040 Tone.TimeBase.prototype._pushExpr = function (val, name, units) { 88041 if (!(val instanceof Tone.TimeBase)) { 88042 val = new this.constructor(val, units); 88043 } 88044 this._expr = this._binaryExpressions[name].method.bind(this, this._expr, val._expr); 88045 return this; 88046 }; 88047 Tone.TimeBase.prototype.add = function (val, units) { 88048 return this._pushExpr(val, '+', units); 88049 }; 88050 Tone.TimeBase.prototype.sub = function (val, units) { 88051 return this._pushExpr(val, '-', units); 88052 }; 88053 Tone.TimeBase.prototype.mult = function (val, units) { 88054 return this._pushExpr(val, '*', units); 88055 }; 88056 Tone.TimeBase.prototype.div = function (val, units) { 88057 return this._pushExpr(val, '/', units); 88058 }; 88059 Tone.TimeBase.prototype.valueOf = function () { 88060 return this._expr(); 88061 }; 88062 Tone.TimeBase.prototype.dispose = function () { 88063 this._expr = null; 88064 }; 88065 return Tone.TimeBase; 88066}(Tone_core_Tone); 88067/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 88068var Tone_type_Time; 88069Tone_type_Time = function (Tone) { 88070 Tone.Time = function (val, units) { 88071 if (this instanceof Tone.Time) { 88072 this._plusNow = false;
88073 Tone.TimeBase.call(this, val, units); 88074 } else { 88075 return new Tone.Time(val, units); 88076 } 88077 }; 88078 Tone.extend(Tone.Time, Tone.TimeBase); 88079 Tone.Time.prototype._unaryExpressions = Object.create(Tone.TimeBase.prototype._unaryExpressions); 88080 Tone.Time.prototype._unaryExpressions.quantize = { 88081 regexp: /^@/, 88082 method: function (rh) { 88083 return Tone.Transport.nextSubdivision(rh()); 88084 } 88085 }; 88086 Tone.Time.prototype._unaryExpressions.now = { 88087 regexp: /^\+/, 88088 method: function (lh) { 88089 this._plusNow = true; 88090 return lh(); 88091 } 88092 }; 88093 Tone.Time.prototype.quantize = function (subdiv, percent) { 88094 percent = this.defaultArg(percent, 1); 88095 this._expr = function (expr, subdivision, percent) { 88096 expr = expr(); 88097 subdivision = subdivision.toSeconds(); 88098 var multiple = Math.round(expr / subdivision); 88099 var ideal = multiple * subdivision; 88100 var diff = ideal - expr; 88101 return expr + diff * percent; 88102 }.bind(this, this._expr, new this.constructor(subdiv), percent); 88103 return this; 88104 }; 88105 Tone.Time.prototype.addNow = function () { 88106 this._plusNow = true; 88107 return this; 88108 }; 88109 Tone.Time.prototype._defaultExpr = function () { 88110 this._plusNow = true; 88111 return this._noOp; 88112 }; 88113 Tone.Time.prototype.copy = function (time) { 88114 Tone.TimeBase.prototype.copy.call(this, time); 88115 this._plusNow = time._plusNow; 88116 return this; 88117 }; 88118 Tone.Time.prototype.toNotation = function () { 88119 var time = this.toSeconds(); 88120 var testNotations = [ 88121 '1m', 88122 '2n', 88123 '4n', 88124 '8n', 88125 '16n', 88126 '32n', 88127 '64n', 88128 '128n' 88129 ]; 88130 var retNotation = this._toNotationHelper(time, testNotations); 88131 var testTripletNotations = [ 88132 '1m', 88133 '2n', 88134 '2t', 88135 '4n', 88136 '4t', 88137 '8n', 88138 '8t', 88139 '16n', 88140 '16t', 88141 '32n', 88142 '32t', 88143 '64n', 88144 '64t', 88145 '128n' 88146 ]; 88147 var retTripletNotation = this._toNotationHelper(time, testTripletNotations); 88148 if (retTripletNotation.split('+').length < retNotation.split('+').length) { 88149 return retTripletNotation; 88150 } else { 88151 return retNotation; 88152 } 88153 }; 88154 Tone.Time.prototype._toNotationHelper = function (units, testNotations) { 88155 var threshold = this._notationToUnits(testNotations[testNotations.length - 1]); 88156 var retNotation = ''; 88157 for (var i = 0; i < testNotations.length; i++) { 88158 var notationTime = this._notationToUnits(testNotations[i]); 88159 var multiple = units / notationTime; 88160 var floatingPointError = 0.000001; 88161 if (1 - multiple % 1 < floatingPointError) { 88162 multiple += floatingPointError; 88163 } 88164 multiple = Math.floor(multiple); 88165 if (multiple > 0) { 88166 if (multiple === 1) { 88167 retNotation += testNotations[i]; 88168 } else { 88169 retNotation += multiple.toString() + '*' + testNotations[i]; 88170 } 88171 units -= multiple * notationTime; 88172 if (units < threshold) { 88173 break; 88174 } else { 88175 retNotation += ' + '; 88176 } 88177 } 88178 } 88179 if (retNotation === '') { 88180 retNotation = '0'; 88181 } 88182 return retNotation; 88183 }; 88184 Tone.Time.prototype._notationToUnits = function (notation) { 88185 var primaryExprs = this._primaryExpressions; 88186 var notationExprs = [ 88187 primaryExprs.n, 88188 primaryExprs.t, 88189 primaryExprs.m 88190 ]; 88191 for (var i = 0; i < notationExprs.length; i++) { 88192 var expr = notationExprs[i]; 88193 var match = notation.match(expr.regexp); 88194 if (match) { 88195 return expr.method.call(this, match[1]); 88196 } 88197 } 88198 }; 88199 Tone.Time.prototype.toBarsBeatsSixteenths = function () { 88200 var quarterTime = this._beatsToUnits(1); 88201 var quarters = this.toSeconds() / quarterTime; 88202 var measures = Math.floor(quarters / this._timeSignature()); 88203 var sixteenths = quarters % 1 * 4; 88204 quarters = Math.floor(quarters) % this._timeSignature(); 88205 sixteenths = sixteenths.toString(); 88206 if (sixteenths.length > 3) { 88207 sixteenths = parseFloat(sixteenths).toFixed(3); 88208 } 88209 var progress = [ 88210 measures, 88211 quarters, 88212 sixteenths 88213 ]; 88214 return progress.join(':'); 88215 }; 88216 Tone.Time.prototype.toTicks = function () { 88217 var quarterTime = this._beatsToUnits(1); 88218 var quarters = this.valueOf() / quarterTime; 88219 return Math.floor(quarters * Tone.Transport.PPQ); 88220 }; 88221 Tone.Time.prototype.toSamples = function () { 88222 return this.toSeconds() * this.context.sampleRate; 88223 }; 88224 Tone.Time.prototype.toFrequency = function () { 88225 return 1 / this.toSeconds(); 88226 }; 88227 Tone.Time.prototype.toSeconds = function () { 88228 return this.valueOf(); 88229 }; 88230 Tone.Time.prototype.toMilliseconds = function () { 88231 return this.toSeconds() * 1000; 88232 }; 88233 Tone.Time.prototype.valueOf = function () { 88234 var val = this._expr(); 88235 return val + (this._plusNow ? this.now() : 0); 88236 }; 88237 return Tone.Time; 88238}(Tone_core_Tone); 88239/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 88240var Tone_type_Frequency; 88241Tone_type_Frequency = function (Tone) { 88242 Tone.Frequency = function (val, units) { 88243 if (this instanceof Tone.Frequency) { 88244 Tone.TimeBase.call(this, val, units); 88245 } else { 88246 return new Tone.Frequency(val, units); 88247 } 88248 }; 88249 Tone.extend(Tone.Frequency, Tone.TimeBase); 88250 Tone.Frequency.prototype._primaryExpressions = Object.create(Tone.TimeBase.prototype._primaryExpressions); 88251 Tone.Frequency.prototype._primaryExpressions.midi = { 88252 regexp: /^(\d+(?:\.\d+)?midi)/, 88253 method: function (value) { 88254 return this.midiToFrequency(value); 88255 } 88256 }; 88257 Tone.Frequency.prototype._primaryExpressions.note = { 88258 regexp: /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i, 88259 method: function (pitch, octave) { 88260 var index = noteToScaleIndex[pitch.toLowerCase()]; 88261 var noteNumber = index + (parseInt(octave) + 1) * 12; 88262 return this.midiToFrequency(noteNumber); 88263 } 88264 }; 88265 Tone.Frequency.prototype._primaryExpressions.tr = { 88266 regexp: /^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/, 88267 method: function (m, q, s) { 88268 var total = 1; 88269 if (m && m !== '0') { 88270 total *= this._beatsToUnits(this._timeSignature() * parseFloat(m)); 88271 } 88272 if (q && q !== '0') { 88273 total *= this._beatsToUnits(parseFloat(q)); 88274 } 88275 if (s && s !== '0') { 88276 total *= this._beatsToUnits(parseFloat(s) / 4); 88277 } 88278 return total; 88279 } 88280 }; 88281 Tone.Frequency.prototype.transpose = function (interval) { 88282 this._expr = function (expr, interval) { 88283 var val = expr(); 88284 return val * this.intervalToFrequencyRatio(interval); 88285 }.bind(this, this._expr, interval); 88286 return this; 88287 }; 88288 Tone.Frequency.prototype.harmonize = function (intervals) { 88289 this._expr = function (expr, intervals) { 88290 var val = expr(); 88291 var ret = []; 88292 for (var i = 0; i < intervals.length; i++) { 88293 ret[i] = val * this.intervalToFrequencyRatio(intervals[i]); 88294 } 88295 return ret; 88296 }.bind(this, this._expr, intervals); 88297 return this; 88298 }; 88299 Tone.Frequency.prototype.toMidi = function () { 88300 return this.frequencyToMidi(this.valueOf()); 88301 }; 88302 Tone.Frequency.prototype.toNote = function () { 88303 var freq = this.valueOf(); 88304 var log = Math.log(freq / Tone.Frequency.A4) / Math.LN2; 88305 var noteNumber = Math.round(12 * log) + 57; 88306 var octave = Math.floor(noteNumber / 12); 88307 if (octave < 0) { 88308 noteNumber += -12 * octave; 88309 } 88310 var noteName = scaleIndexToNote[noteNumber % 12]; 88311 return noteName + octave.toString(); 88312 }; 88313 Tone.Frequency.prototype.toSeconds = function () { 88314 return 1 / this.valueOf(); 88315 }; 88316 Tone.Frequency.prototype.toFrequency = function () { 88317 return this.valueOf(); 88318 }; 88319 Tone.Frequency.prototype.toTicks = function () { 88320 var quarterTime = this._beatsToUnits(1); 88321 var quarters = this.valueOf() / quarterTime; 88322 return Math.floor(quarters * Tone.Transport.PPQ); 88323 }; 88324 Tone.Frequency.prototype._frequencyToUnits = function (freq) { 88325 return freq; 88326 }; 88327 Tone.Frequency.prototype._ticksToUnits = function (ticks) { 88328 return 1 / (ticks * 60 / (Tone.Transport.bpm.value * Tone.Transport.PPQ)); 88329 }; 88330 Tone.Frequency.prototype._beatsToUnits = function (beats) { 88331 return 1 / Tone.TimeBase.prototype._beatsToUnits.call(this, beats); 88332 }; 88333 Tone.Frequency.prototype._secondsToUnits = function (seconds) { 88334 return 1 / seconds; 88335 }; 88336 Tone.Frequency.prototype._defaultUnits = 'hz'; 88337 var noteToScaleIndex = { 88338 'cbb': -2, 88339 'cb': -1, 88340 'c': 0, 88341 'c#': 1, 88342 'cx': 2, 88343 'dbb': 0, 88344 'db': 1, 88345 'd': 2, 88346 'd#': 3, 88347 'dx': 4, 88348 'ebb': 2, 88349 'eb': 3, 88350 'e': 4, 88351 'e#': 5, 88352 'ex': 6, 88353 'fbb': 3, 88354 'fb': 4, 88355 'f': 5, 88356 'f#': 6, 88357 'fx': 7, 88358 'gbb': 5, 88359 'gb': 6, 88360 'g': 7, 88361 'g#': 8, 88362 'gx': 9, 88363 'abb': 7, 88364 'ab': 8, 88365 'a': 9, 88366 'a#': 10, 88367 'ax': 11, 88368 'bbb': 9, 88369 'bb': 10, 88370 'b': 11, 88371 'b#': 12, 88372 'bx': 13 88373 }; 88374 var scaleIndexToNote = [ 88375 'C', 88376 'C#', 88377 'D', 88378 'D#', 88379 'E', 88380 'F', 88381 'F#', 88382 'G', 88383 'G#', 88384 'A', 88385 'A#', 88386 'B' 88387 ]; 88388 Tone.Frequency.A4 = 440; 88389 Tone.Frequency.prototype.midiToFrequency = function (midi) { 88390 return Tone.Frequency.A4 * Math.pow(2, (midi - 69) / 12); 88391 }; 88392 Tone.Frequency.prototype.frequencyToMidi = function (frequency) { 88393 return 69 + 12 * Math.log(frequency / Tone.Frequency.A4) / Math.LN2; 88394 }; 88395 return Tone.Frequency; 88396}(Tone_core_Tone); 88397/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/
88398var Tone_type_TransportTime; 88399Tone_type_TransportTime = function (Tone) { 88400 Tone.TransportTime = function (val, units) { 88401 if (this instanceof Tone.TransportTime) { 88402 Tone.Time.call(this, val, units); 88403 } else { 88404 return new Tone.TransportTime(val, units); 88405 } 88406 }; 88407 Tone.extend(Tone.TransportTime, Tone.Time); 88408 Tone.TransportTime.prototype._unaryExpressions = Object.create(Tone.Time.prototype._unaryExpressions); 88409 Tone.TransportTime.prototype._unaryExpressions.quantize = { 88410 regexp: /^@/, 88411 method: function (rh) { 88412 var subdivision = this._secondsToTicks(rh()); 88413 var multiple = Math.ceil(Tone.Transport.ticks / subdivision); 88414 return this._ticksToUnits(multiple * subdivision); 88415 } 88416 }; 88417 Tone.TransportTime.prototype._secondsToTicks = function (seconds) { 88418 var quarterTime = this._beatsToUnits(1); 88419 var quarters = seconds / quarterTime; 88420 return Math.round(quarters * Tone.Transport.PPQ); 88421 }; 88422 Tone.TransportTime.prototype.valueOf = function () { 88423 var val = this._secondsToTicks(this._expr()); 88424 return val + (this._plusNow ? Tone.Transport.ticks : 0); 88425 }; 88426 Tone.TransportTime.prototype.toTicks = function () { 88427 return this.valueOf(); 88428 }; 88429 Tone.TransportTime.prototype.toSeconds = function () { 88430 var val = this._expr(); 88431 return val + (this._plusNow ? Tone.Transport.seconds : 0); 88432 }; 88433 Tone.TransportTime.prototype.toFrequency = function () { 88434 return 1 / this.toSeconds(); 88435 }; 88436 return Tone.TransportTime; 88437}(Tone_core_Tone); 88438/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 88439var Tone_core_Emitter; 88440Tone_core_Emitter = function (Tone) { 88441 'use strict'; 88442 Tone.Emitter = function () { 88443 this._events = {}; 88444 }; 88445 Tone.extend(Tone.Emitter); 88446 Tone.Emitter.prototype.on = function (event, callback) { 88447 var events = event.split(/\W+/); 88448 for (var i = 0; i < events.length; i++) { 88449 var eventName = events[i]; 88450 if (!this._events.hasOwnProperty(eventName)) { 88451 this._events[eventName] = []; 88452 } 88453 this._events[eventName].push(callback); 88454 } 88455 return this; 88456 }; 88457 Tone.Emitter.prototype.off = function (event, callback) { 88458 var events = event.split(/\W+/); 88459 for (var ev = 0; ev < events.length; ev++) { 88460 event = events[ev]; 88461 if (this._events.hasOwnProperty(event)) { 88462 if (Tone.prototype.isUndef(callback)) { 88463 this._events[event] = []; 88464 } else { 88465 var eventList = this._events[event]; 88466 for (var i = 0; i < eventList.length; i++) { 88467 if (eventList[i] === callback) { 88468 eventList.splice(i, 1); 88469 } 88470 } 88471 } 88472 } 88473 } 88474 return this; 88475 }; 88476 Tone.Emitter.prototype.emit = function (event) { 88477 if (this._events) { 88478 var args = Array.apply(null, arguments).slice(1); 88479 if (this._events.hasOwnProperty(event)) { 88480 var eventList = this._events[event]; 88481 for (var i = 0, len = eventList.length; i < len; i++) { 88482 eventList[i].apply(this, args); 88483 } 88484 } 88485 } 88486 return this; 88487 }; 88488 Tone.Emitter.mixin = function (object) { 88489 var functions = [ 88490 'on', 88491 'off', 88492 'emit' 88493 ]; 88494 object._events = {}; 88495 for (var i = 0; i < functions.length; i++) { 88496 var func = functions[i]; 88497 var emitterFunc = Tone.Emitter.prototype[func]; 88498 object[func] = emitterFunc; 88499 } 88500 }; 88501 Tone.Emitter.prototype.dispose = function () { 88502 Tone.prototype.dispose.call(this); 88503 this._events = null; 88504 return this; 88505 }; 88506 return Tone.Emitter; 88507}(Tone_core_Tone); 88508/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 88509var Tone_core_Context; 88510Tone_core_Context = function (Tone) { 88511 if (!window.hasOwnProperty('AudioContext') && window.hasOwnProperty('webkitAudioContext')) { 88512 window.AudioContext = window.webkitAudioContext; 88513 } 88514 Tone.Context = function (context) { 88515 Tone.Emitter.call(this); 88516 if (!context) { 88517 context = new window.AudioContext(); 88518 } 88519 this._context = context; 88520 for (var prop in this._context) { 88521 this._defineProperty(this._context, prop); 88522 } 88523 this._latencyHint = 'interactive'; 88524 this._lookAhead = 0.1; 88525 this._updateInterval = this._lookAhead / 3; 88526 this._computedUpdateInterval = 0; 88527 this._worker = this._createWorker(); 88528 this._constants = {}; 88529 }; 88530 Tone.extend(Tone.Context, Tone.Emitter); 88531 Tone.Emitter.mixin(Tone.Context); 88532 Tone.Context.prototype._defineProperty = function (context, prop) { 88533 if (this.isUndef(this[prop])) { 88534 Object.defineProperty(this, prop, { 88535 get: function () { 88536 if (typeof context[prop] === 'function') { 88537 return context[prop].bind(context); 88538 } else { 88539 return context[prop]; 88540 } 88541 }, 88542 set: function (val) { 88543 context[prop] = val; 88544 } 88545 }); 88546 } 88547 }; 88548 Tone.Context.prototype.now = function () { 88549 return this._context.currentTime; 88550 }; 88551 Tone.Context.prototype._createWorker = function () { 88552 window.URL = window.URL || window.webkitURL; 88553 var blob = new Blob(['var timeoutTime = ' + (this._updateInterval * 1000).toFixed(1) + ';' + 'self.onmessage = function(msg){' + '\ttimeoutTime = parseInt(msg.data);' + '};' + 'function tick(){' + '\tsetTimeout(tick, timeoutTime);' + '\tself.postMessage(\'tick\');' + '}' + 'tick();']); 88554 var blobUrl = URL.createObjectURL(blob); 88555 var worker = new Worker(blobUrl); 88556 worker.addEventListener('message', function () {
88557 this.emit('tick'); 88558 }.bind(this)); 88559 worker.addEventListener('message', function () { 88560 var now = this.now(); 88561 if (this.isNumber(this._lastUpdate)) { 88562 var diff = now - this._lastUpdate; 88563 this._computedUpdateInterval = Math.max(diff, this._computedUpdateInterval * 0.97); 88564 } 88565 this._lastUpdate = now; 88566 }.bind(this)); 88567 return worker; 88568 }; 88569 Tone.Context.prototype.getConstant = function (val) { 88570 if (this._constants[val]) { 88571 return this._constants[val]; 88572 } else { 88573 var buffer = this._context.createBuffer(1, 128, this._context.sampleRate); 88574 var arr = buffer.getChannelData(0); 88575 for (var i = 0; i < arr.length; i++) { 88576 arr[i] = val; 88577 } 88578 var constant = this._context.createBufferSource(); 88579 constant.channelCount = 1; 88580 constant.channelCountMode = 'explicit'; 88581 constant.buffer = buffer; 88582 constant.loop = true; 88583 constant.start(0); 88584 this._constants[val] = constant; 88585 return constant; 88586 } 88587 }; 88588 Object.defineProperty(Tone.Context.prototype, 'lag', { 88589 get: function () { 88590 var diff = this._computedUpdateInterval - this._updateInterval; 88591 diff = Math.max(diff, 0); 88592 return diff; 88593 } 88594 }); 88595 Object.defineProperty(Tone.Context.prototype, 'lookAhead', { 88596 get: function () { 88597 return this._lookAhead; 88598 }, 88599 set: function (lA) { 88600 this._lookAhead = lA; 88601 } 88602 }); 88603 Object.defineProperty(Tone.Context.prototype, 'updateInterval', { 88604 get: function () { 88605 return this._updateInterval; 88606 }, 88607 set: function (interval) { 88608 this._updateInterval = Math.max(interval, Tone.prototype.blockTime); 88609 this._worker.postMessage(Math.max(interval * 1000, 1)); 88610 } 88611 }); 88612 Object.defineProperty(Tone.Context.prototype, 'latencyHint', { 88613 get: function () { 88614 return this._latencyHint; 88615 }, 88616 set: function (hint) { 88617 var lookAhead = hint; 88618 this._latencyHint = hint; 88619 if (this.isString(hint)) { 88620 switch (hint) { 88621 case 'interactive': 88622 lookAhead = 0.1; 88623 this._context.latencyHint = hint; 88624 break; 88625 case 'playback': 88626 lookAhead = 0.8; 88627 this._context.latencyHint = hint; 88628 break; 88629 case 'balanced': 88630 lookAhead = 0.25; 88631 this._context.latencyHint = hint; 88632 break; 88633 case 'fastest': 88634 lookAhead = 0.01; 88635 break; 88636 } 88637 } 88638 this.lookAhead = lookAhead; 88639 this.updateInterval = lookAhead / 3; 88640 } 88641 }); 88642 function shimConnect() { 88643 var nativeConnect = AudioNode.prototype.connect; 88644 var nativeDisconnect = AudioNode.prototype.disconnect; 88645 function toneConnect(B, outNum, inNum) { 88646 if (B.input) { 88647 if (Array.isArray(B.input)) { 88648 if (Tone.prototype.isUndef(inNum)) { 88649 inNum = 0; 88650 } 88651 this.connect(B.input[inNum]); 88652 } else { 88653 this.connect(B.input, outNum, inNum); 88654 } 88655 } else { 88656 try { 88657 if (B instanceof AudioNode) { 88658 nativeConnect.call(this, B, outNum, inNum); 88659 } else { 88660 nativeConnect.call(this, B, outNum); 88661 } 88662 } catch (e) { 88663 throw new Error('error connecting to node: ' + B + '\n' + e); 88664 } 88665 } 88666 } 88667 function toneDisconnect(B, outNum, inNum) { 88668 if (B && B.input && Array.isArray(B.input)) { 88669 if (Tone.prototype.isUndef(inNum)) { 88670 inNum = 0; 88671 } 88672 this.disconnect(B.input[inNum], outNum, inNum); 88673 } else if (B && B.input) { 88674 this.disconnect(B.input, outNum, inNum); 88675 } else { 88676 try { 88677 nativeDisconnect.apply(this, arguments); 88678 } catch (e) { 88679 throw new Error('error disconnecting node: ' + B + '\n' + e); 88680 } 88681 } 88682 } 88683 if (AudioNode.prototype.connect !== toneConnect) { 88684 AudioNode.prototype.connect = toneConnect; 88685 AudioNode.prototype.disconnect = toneDisconnect; 88686 } 88687 } 88688 if (Tone.supported) { 88689 shimConnect(); 88690 Tone.context = new Tone.Context(); 88691 } else { 88692 console.warn('This browser does not support Tone.js'); 88693 } 88694 return Tone.Context; 88695}(Tone_core_Tone); 88696/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 88697var Tone_type_Type; 88698Tone_type_Type = function (Tone) { 88699 Tone.Type = { 88700 Default: 'number', 88701 Time: 'time', 88702 Frequency: 'frequency', 88703 TransportTime: 'transportTime',
88704 Ticks: 'ticks', 88705 NormalRange: 'normalRange', 88706 AudioRange: 'audioRange', 88707 Decibels: 'db', 88708 Interval: 'interval', 88709 BPM: 'bpm', 88710 Positive: 'positive', 88711 Cents: 'cents', 88712 Degrees: 'degrees', 88713 MIDI: 'midi', 88714 BarsBeatsSixteenths: 'barsBeatsSixteenths', 88715 Samples: 'samples', 88716 Hertz: 'hertz', 88717 Note: 'note', 88718 Milliseconds: 'milliseconds', 88719 Seconds: 'seconds', 88720 Notation: 'notation' 88721 }; 88722 Tone.prototype.toSeconds = function (time) { 88723 if (this.isNumber(time)) { 88724 return time; 88725 } else if (this.isUndef(time)) { 88726 return this.now(); 88727 } else if (this.isString(time)) { 88728 return new Tone.Time(time).toSeconds(); 88729 } else if (time instanceof Tone.TimeBase) { 88730 return time.toSeconds(); 88731 } 88732 }; 88733 Tone.prototype.toFrequency = function (freq) { 88734 if (this.isNumber(freq)) { 88735 return freq; 88736 } else if (this.isString(freq) || this.isUndef(freq)) { 88737 return new Tone.Frequency(freq).valueOf(); 88738 } else if (freq instanceof Tone.TimeBase) { 88739 return freq.toFrequency(); 88740 } 88741 }; 88742 Tone.prototype.toTicks = function (time) { 88743 if (this.isNumber(time) || this.isString(time)) { 88744 return new Tone.TransportTime(time).toTicks(); 88745 } else if (this.isUndef(time)) { 88746 return Tone.Transport.ticks; 88747 } else if (time instanceof Tone.TimeBase) { 88748 return time.toTicks(); 88749 } 88750 }; 88751 return Tone; 88752}(Tone_core_Tone, Tone_type_Time, Tone_type_Frequency, Tone_type_TransportTime); 88753/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 88754var Tone_core_Param; 88755Tone_core_Param = function (Tone) { 88756 'use strict'; 88757 Tone.Param = function () { 88758 var options = this.optionsObject(arguments, [ 88759 'param', 88760 'units', 88761 'convert' 88762 ], Tone.Param.defaults); 88763 this._param = this.input = options.param; 88764 this.units = options.units; 88765 this.convert = options.convert; 88766 this.overridden = false; 88767 this._lfo = null; 88768 if (this.isObject(options.lfo)) { 88769 this.value = options.lfo; 88770 } else if (!this.isUndef(options.value)) { 88771 this.value = options.value; 88772 } 88773 }; 88774 Tone.extend(Tone.Param); 88775 Tone.Param.defaults = { 88776 'units': Tone.Type.Default, 88777 'convert': true, 88778 'param': undefined 88779 }; 88780 Object.defineProperty(Tone.Param.prototype, 'value', { 88781 get: function () { 88782 return this._toUnits(this._param.value); 88783 }, 88784 set: function (value) { 88785 if (this.isObject(value)) { 88786 if (this.isUndef(Tone.LFO)) { 88787 throw new Error('Include \'Tone.LFO\' to use an LFO as a Param value.'); 88788 } 88789 if (this._lfo) { 88790 this._lfo.dispose(); 88791 } 88792 this._lfo = new Tone.LFO(value).start(); 88793 this._lfo.connect(this.input); 88794 } else { 88795 var convertedVal = this._fromUnits(value); 88796 this._param.cancelScheduledValues(0); 88797 this._param.value = convertedVal; 88798 } 88799 } 88800 }); 88801 Tone.Param.prototype._fromUnits = function (val) { 88802 if (this.convert || this.isUndef(this.convert)) { 88803 switch (this.units) { 88804 case Tone.Type.Time: 88805 return this.toSeconds(val); 88806 case Tone.Type.Frequency: 88807 return this.toFrequency(val); 88808 case Tone.Type.Decibels: 88809 return this.dbToGain(val); 88810 case Tone.Type.NormalRange: 88811 return Math.min(Math.max(val, 0), 1); 88812 case Tone.Type.AudioRange: 88813 return Math.min(Math.max(val, -1), 1); 88814 case Tone.Type.Positive: 88815 return Math.max(val, 0); 88816 default: 88817 return val; 88818 } 88819 } else { 88820 return val; 88821 } 88822 }; 88823 Tone.Param.prototype._toUnits = function (val) { 88824 if (this.convert || this.isUndef(this.convert)) { 88825 switch (this.units) { 88826 case Tone.Type.Decibels: 88827 return this.gainToDb(val); 88828 default: 88829 return val; 88830 } 88831 } else { 88832 return val; 88833 } 88834 }; 88835 Tone.Param.prototype._minOutput = 0.00001; 88836 Tone.Param.prototype.setValueAtTime = function (value, time) { 88837 value = this._fromUnits(value); 88838 time = this.toSeconds(time); 88839 if (time <= this.now() + this.blockTime) { 88840 this._param.value = value; 88841 } else { 88842 this._param.setValueAtTime(value, time); 88843 } 88844 return this; 88845 }; 88846 Tone.Param.prototype.setRampPoint = function (now) { 88847 now = this.defaultArg(now, this.now()); 88848 var currentVal = this._param.value; 88849 if (currentVal === 0) { 88850 currentVal = this._minOutput; 88851 } 88852 this._param.setValueAtTime(currentVal, now); 88853 return this; 88854 }; 88855 Tone.Param.prototype.linearRampToValueAtTime = function (value, endTime) { 88856 value = this._fromUnits(value); 88857 this._param.linearRampToValueAtTime(value, this.toSeconds(endTime)); 88858 return this; 88859 };
88860 Tone.Param.prototype.exponentialRampToValueAtTime = function (value, endTime) { 88861 value = this._fromUnits(value); 88862 value = Math.max(this._minOutput, value); 88863 this._param.exponentialRampToValueAtTime(value, this.toSeconds(endTime)); 88864 return this; 88865 }; 88866 Tone.Param.prototype.exponentialRampToValue = function (value, rampTime, startTime) { 88867 startTime = this.toSeconds(startTime); 88868 this.setRampPoint(startTime); 88869 this.exponentialRampToValueAtTime(value, startTime + this.toSeconds(rampTime)); 88870 return this; 88871 }; 88872 Tone.Param.prototype.linearRampToValue = function (value, rampTime, startTime) { 88873 startTime = this.toSeconds(startTime); 88874 this.setRampPoint(startTime); 88875 this.linearRampToValueAtTime(value, startTime + this.toSeconds(rampTime)); 88876 return this; 88877 }; 88878 Tone.Param.prototype.setTargetAtTime = function (value, startTime, timeConstant) { 88879 value = this._fromUnits(value); 88880 value = Math.max(this._minOutput, value); 88881 timeConstant = Math.max(this._minOutput, timeConstant); 88882 this._param.setTargetAtTime(value, this.toSeconds(startTime), timeConstant); 88883 return this; 88884 }; 88885 Tone.Param.prototype.setValueCurveAtTime = function (values, startTime, duration) { 88886 for (var i = 0; i < values.length; i++) { 88887 values[i] = this._fromUnits(values[i]); 88888 } 88889 this._param.setValueCurveAtTime(values, this.toSeconds(startTime), this.toSeconds(duration)); 88890 return this; 88891 }; 88892 Tone.Param.prototype.cancelScheduledValues = function (startTime) { 88893 this._param.cancelScheduledValues(this.toSeconds(startTime)); 88894 return this; 88895 }; 88896 Tone.Param.prototype.rampTo = function (value, rampTime, startTime) { 88897 rampTime = this.defaultArg(rampTime, 0); 88898 if (this.units === Tone.Type.Frequency || this.units === Tone.Type.BPM || this.units === Tone.Type.Decibels) { 88899 this.exponentialRampToValue(value, rampTime, startTime); 88900 } else { 88901 this.linearRampToValue(value, rampTime, startTime); 88902 } 88903 return this; 88904 }; 88905 Object.defineProperty(Tone.Param.prototype, 'lfo', { 88906 get: function () { 88907 return this._lfo; 88908 } 88909 }); 88910 Tone.Param.prototype.dispose = function () { 88911 Tone.prototype.dispose.call(this); 88912 this._param = null; 88913 if (this._lfo) { 88914 this._lfo.dispose(); 88915 this._lfo = null; 88916 } 88917 return this; 88918 }; 88919 return Tone.Param; 88920}(Tone_core_Tone); 88921/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 88922var Tone_core_Gain; 88923Tone_core_Gain = function (Tone) { 88924 'use strict'; 88925 if (window.GainNode && !AudioContext.prototype.createGain) { 88926 AudioContext.prototype.createGain = AudioContext.prototype.createGainNode; 88927 } 88928 Tone.Gain = function () { 88929 var options = this.optionsObject(arguments, [ 88930 'gain', 88931 'units' 88932 ], Tone.Gain.defaults); 88933 this.input = this.output = this._gainNode = this.context.createGain(); 88934 this.gain = new Tone.Param({ 88935 'param': this._gainNode.gain, 88936 'units': options.units, 88937 'value': options.gain, 88938 'convert': options.convert 88939 }); 88940 this._readOnly('gain'); 88941 }; 88942 Tone.extend(Tone.Gain); 88943 Tone.Gain.defaults = { 88944 'gain': 1, 88945 'convert': true 88946 }; 88947 Tone.Gain.prototype.dispose = function () { 88948 Tone.Param.prototype.dispose.call(this); 88949 this._gainNode.disconnect(); 88950 this._gainNode = null; 88951 this._writable('gain'); 88952 this.gain.dispose(); 88953 this.gain = null; 88954 }; 88955 Tone.prototype.createInsOuts = function (inputs, outputs) { 88956 if (inputs === 1) { 88957 this.input = new Tone.Gain(); 88958 } else if (inputs > 1) { 88959 this.input = new Array(inputs); 88960 } 88961 if (outputs === 1) { 88962 this.output = new Tone.Gain(); 88963 } else if (outputs > 1) { 88964 this.output = new Array(inputs); 88965 } 88966 }; 88967 return Tone.Gain; 88968}(Tone_core_Tone, Tone_core_Param); 88969/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 88970var Tone_signal_Signal; 88971Tone_signal_Signal = function (Tone) { 88972 'use strict'; 88973 Tone.Signal = function () { 88974 var options = this.optionsObject(arguments, [ 88975 'value', 88976 'units' 88977 ], Tone.Signal.defaults); 88978 this.output = this._gain = this.context.createGain(); 88979 options.param = this._gain.gain; 88980 Tone.Param.call(this, options); 88981 this.input = this._param = this._gain.gain; 88982 this.context.getConstant(1).chain(this._gain); 88983 }; 88984 Tone.extend(Tone.Signal, Tone.Param); 88985 Tone.Signal.defaults = { 88986 'value': 0, 88987 'units': Tone.Type.Default, 88988 'convert': true 88989 }; 88990 Tone.Signal.prototype.connect = Tone.SignalBase.prototype.connect; 88991 Tone.Signal.prototype.dispose = function () { 88992 Tone.Param.prototype.dispose.call(this); 88993 this._param = null; 88994 this._gain.disconnect(); 88995 this._gain = null; 88996 return this; 88997 }; 88998 return Tone.Signal; 88999}(Tone_core_Tone, Tone_signal_WaveShaper, Tone_type_Type, Tone_core_Param); 89000/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 89001var Tone_signal_Add; 89002Tone_signal_Add = function (Tone) { 89003 'use strict'; 89004 Tone.Add = function (value) { 89005 this.createInsOuts(2, 0); 89006 this._sum = this.input[0] = this.input[1] = this.output = new Tone.Gain(); 89007 this._param = this.input[1] = new Tone.Signal(value); 89008 this._param.connect(this._sum); 89009 }; 89010 Tone.extend(Tone.Add, Tone.Signal); 89011 Tone.Add.prototype.dispose = function () { 89012 Tone.prototype.dispose.call(this); 89013 this._sum.dispose(); 89014 this._sum = null; 89015 this._param.dispose(); 89016 this._param = null; 89017 return this; 89018 }; 89019 return Tone.Add; 89020}(Tone_core_Tone, Tone_signal_Signal); 89021/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 89022var Tone_signal_Multiply; 89023Tone_signal_Multiply = function (Tone) { 89024 'use strict'; 89025 Tone.Multiply = function (value) { 89026 this.createInsOuts(2, 0); 89027 this._mult = this.input[0] = this.output = new Tone.Gain(); 89028 this._param = this.input[1] = this.output.gain; 89029 this._param.value = this.defaultArg(value, 0); 89030 }; 89031 Tone.extend(Tone.Multiply, Tone.Signal); 89032 Tone.Multiply.prototype.dispose = function () { 89033 Tone.prototype.dispose.call(this); 89034 this._mult.dispose(); 89035 this._mult = null; 89036 this._param = null; 89037 return this; 89038 }; 89039 return Tone.Multiply; 89040}(Tone_core_Tone, Tone_signal_Signal); 89041/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 89042var Tone_signal_Scale; 89043Tone_signal_Scale = function (Tone) { 89044 'use strict'; 89045 Tone.Scale = function (outputMin, outputMax) { 89046 this._outputMin = this.defaultArg(outputMin, 0); 89047 this._outputMax = this.defaultArg(outputMax, 1); 89048 this._scale = this.input = new Tone.Multiply(1); 89049 this._add = this.output = new Tone.Add(0); 89050 this._scale.connect(this._add); 89051 this._setRange(); 89052 }; 89053 Tone.extend(Tone.Scale, Tone.SignalBase); 89054 Object.defineProperty(Tone.Scale.prototype, 'min', { 89055 get: function () { 89056 return this._outputMin; 89057 }, 89058 set: function (min) { 89059 this._outputMin = min; 89060 this._setRange(); 89061 } 89062 }); 89063 Object.defineProperty(Tone.Scale.prototype, 'max', { 89064 get: function () { 89065 return this._outputMax; 89066 }, 89067 set: function (max) { 89068 this._outputMax = max; 89069 this._setRange(); 89070 } 89071 }); 89072 Tone.Scale.prototype._setRange = function () { 89073 this._add.value = this._outputMin; 89074 this._scale.value = this._outputMax - this._outputMin; 89075 }; 89076 Tone.Scale.prototype.dispose = function () { 89077 Tone.prototype.dispose.call(this); 89078 this._add.dispose(); 89079 this._add = null; 89080 this._scale.dispose(); 89081 this._scale = null; 89082 return this; 89083 }; 89084 return Tone.Scale; 89085}(Tone_core_Tone, Tone_signal_Add, Tone_signal_Multiply); 89086var signal; 89087'use strict'; 89088signal = function () { 89089 // Signal is built with the Tone.js signal by Yotam Mann 89090 // https://github.com/TONEnoTONE/Tone.js/ 89091 var Signal = Tone_signal_Signal; 89092 var Add = Tone_signal_Add; 89093 var Mult = Tone_signal_Multiply; 89094 var Scale = Tone_signal_Scale; 89095 var Tone = Tone_core_Tone; 89096 var p5sound = master; 89097 Tone.setContext(p5sound.audiocontext); 89098 /** 89099 * <p>p5.Signal is a constant audio-rate signal used by p5.Oscillator 89100 * and p5.Envelope for modulation math.</p> 89101 * 89102 * <p>This is necessary because Web Audio is processed on a seprate clock. 89103 * For example, the p5 draw loop runs about 60 times per second. But 89104 * the audio clock must process samples 44100 times per second. If we 89105 * want to add a value to each of those samples, we can't do it in the 89106 * draw loop, but we can do it by adding a constant-rate audio signal.</p. 89107 * 89108 * <p>This class mostly functions behind the scenes in p5.sound, and returns 89109 * a Tone.Signal from the Tone.js library by Yotam Mann. 89110 * If you want to work directly with audio signals for modular 89111 * synthesis, check out 89112 * <a href='http://bit.ly/1oIoEng' target=_'blank'>tone.js.</a></p> 89113 * 89114 * @class p5.Signal 89115 * @constructor 89116 * @return {Tone.Signal} A Signal object from the Tone.js library 89117 * @example 89118 * <div><code> 89119 * function setup() { 89120 * carrier = new p5.Oscillator('sine'); 89121 * carrier.amp(1); // set amplitude 89122 * carrier.freq(220); // set frequency 89123 * carrier.start(); // start oscillating 89124 * 89125 * modulator = new p5.Oscillator('sawtooth'); 89126 * modulator.disconnect(); 89127 * modulator.amp(1); 89128 * modulator.freq(4); 89129 * modulator.start(); 89130 * 89131 * // Modulator's default amplitude range is -1 to 1. 89132 * // Multiply it by -200, so the range is -200 to 200
89133 * // then add 220 so the range is 20 to 420 89134 * carrier.freq( modulator.mult(-200).add(220) ); 89135 * } 89136 * </code></div> 89137 */ 89138 p5.Signal = function (value) { 89139 var s = new Signal(value); 89140 // p5sound.soundArray.push(s); 89141 return s; 89142 }; 89143 /** 89144 * Fade to value, for smooth transitions 89145 * 89146 * @method fade 89147 * @param {Number} value Value to set this signal 89148 * @param {Number} [secondsFromNow] Length of fade, in seconds from now 89149 */ 89150 Signal.prototype.fade = Signal.prototype.linearRampToValueAtTime; 89151 Mult.prototype.fade = Signal.prototype.fade; 89152 Add.prototype.fade = Signal.prototype.fade; 89153 Scale.prototype.fade = Signal.prototype.fade; 89154 /** 89155 * Connect a p5.sound object or Web Audio node to this 89156 * p5.Signal so that its amplitude values can be scaled. 89157 * 89158 * @method setInput 89159 * @param {Object} input 89160 */ 89161 Signal.prototype.setInput = function (_input) { 89162 _input.connect(this); 89163 }; 89164 Mult.prototype.setInput = Signal.prototype.setInput; 89165 Add.prototype.setInput = Signal.prototype.setInput; 89166 Scale.prototype.setInput = Signal.prototype.setInput; 89167 // signals can add / mult / scale themselves 89168 /** 89169 * Add a constant value to this audio signal, 89170 * and return the resulting audio signal. Does 89171 * not change the value of the original signal, 89172 * instead it returns a new p5.SignalAdd. 89173 * 89174 * @method add 89175 * @param {Number} number 89176 * @return {p5.Signal} object 89177 */ 89178 Signal.prototype.add = function (num) { 89179 var add = new Add(num); 89180 // add.setInput(this); 89181 this.connect(add); 89182 return add; 89183 }; 89184 Mult.prototype.add = Signal.prototype.add; 89185 Add.prototype.add = Signal.prototype.add; 89186 Scale.prototype.add = Signal.prototype.add; 89187 /** 89188 * Multiply this signal by a constant value, 89189 * and return the resulting audio signal. Does 89190 * not change the value of the original signal, 89191 * instead it returns a new p5.SignalMult. 89192 * 89193 * @method mult 89194 * @param {Number} number to multiply 89195 * @return {p5.Signal} object 89196 */ 89197 Signal.prototype.mult = function (num) { 89198 var mult = new Mult(num); 89199 // mult.setInput(this); 89200 this.connect(mult); 89201 return mult; 89202 }; 89203 Mult.prototype.mult = Signal.prototype.mult; 89204 Add.prototype.mult = Signal.prototype.mult; 89205 Scale.prototype.mult = Signal.prototype.mult; 89206 /** 89207 * Scale this signal value to a given range, 89208 * and return the result as an audio signal. Does 89209 * not change the value of the original signal, 89210 * instead it returns a new p5.SignalScale. 89211 * 89212 * @method scale 89213 * @param {Number} number to multiply 89214 * @param {Number} inMin input range minumum 89215 * @param {Number} inMax input range maximum 89216 * @param {Number} outMin input range minumum 89217 * @param {Number} outMax input range maximum 89218 * @return {p5.Signal} object 89219 */ 89220 Signal.prototype.scale = function (inMin, inMax, outMin, outMax) { 89221 var mapOutMin, mapOutMax; 89222 if (arguments.length === 4) { 89223 mapOutMin = p5.prototype.map(outMin, inMin, inMax, 0, 1) - 0.5; 89224 mapOutMax = p5.prototype.map(outMax, inMin, inMax, 0, 1) - 0.5; 89225 } else { 89226 mapOutMin = arguments[0]; 89227 mapOutMax = arguments[1]; 89228 } 89229 var scale = new Scale(mapOutMin, mapOutMax); 89230 this.connect(scale); 89231 return scale; 89232 }; 89233 Mult.prototype.scale = Signal.prototype.scale; 89234 Add.prototype.scale = Signal.prototype.scale; 89235 Scale.prototype.scale = Signal.prototype.scale; 89236}(Tone_signal_Signal, Tone_signal_Add, Tone_signal_Multiply, Tone_signal_Scale, Tone_core_Tone, master); 89237var oscillator; 89238'use strict'; 89239oscillator = function () { 89240 var p5sound = master; 89241 var Add = Tone_signal_Add; 89242 var Mult = Tone_signal_Multiply; 89243 var Scale = Tone_signal_Scale; 89244 /** 89245 * <p>Creates a signal that oscillates between -1.0 and 1.0. 89246 * By default, the oscillation takes the form of a sinusoidal 89247 * shape ('sine'). Additional types include 'triangle', 89248 * 'sawtooth' and 'square'. The frequency defaults to 89249 * 440 oscillations per second (440Hz, equal to the pitch of an 89250 * 'A' note).</p> 89251 * 89252 * <p>Set the type of oscillation with setType(), or by instantiating a 89253 * specific oscillator: <a href="/reference/#/p5.SinOsc">p5.SinOsc</a>, <a 89254 * href="/reference/#/p5.TriOsc">p5.TriOsc</a>, <a 89255 * href="/reference/#/p5.SqrOsc">p5.SqrOsc</a>, or <a 89256 * href="/reference/#/p5.SawOsc">p5.SawOsc</a>. 89257 * </p> 89258 * 89259 * @class p5.Oscillator 89260 * @constructor 89261 * @param {Number} [freq] frequency defaults to 440Hz 89262 * @param {String} [type] type of oscillator. Options: 89263 * 'sine' (default), 'triangle',
89264 * 'sawtooth', 'square' 89265 * @example 89266 * <div><code> 89267 * var osc; 89268 * var playing = false; 89269 * 89270 * function setup() { 89271 * backgroundColor = color(255,0,255); 89272 * textAlign(CENTER); 89273 * 89274 * osc = new p5.Oscillator(); 89275 * osc.setType('sine'); 89276 * osc.freq(240); 89277 * osc.amp(0); 89278 * osc.start(); 89279 * } 89280 * 89281 * function draw() { 89282 * background(backgroundColor) 89283 * text('click to play', width/2, height/2); 89284 * } 89285 * 89286 * function mouseClicked() { 89287 * if (mouseX > 0 && mouseX < width && mouseY < height && mouseY > 0) { 89288 * if (!playing) { 89289 * // ramp amplitude to 0.5 over 0.05 seconds 89290 * osc.amp(0.5, 0.05); 89291 * playing = true; 89292 * backgroundColor = color(0,255,255); 89293 * } else { 89294 * // ramp amplitude to 0 over 0.5 seconds 89295 * osc.amp(0, 0.5); 89296 * playing = false; 89297 * backgroundColor = color(255,0,255); 89298 * } 89299 * } 89300 * } 89301 * </code> </div> 89302 */ 89303 p5.Oscillator = function (freq, type) { 89304 if (typeof freq === 'string') { 89305 var f = type; 89306 type = freq; 89307 freq = f; 89308 } 89309 if (typeof type === 'number') { 89310 var f = type; 89311 type = freq; 89312 freq = f; 89313 } 89314 this.started = false; 89315 // components 89316 this.phaseAmount = undefined; 89317 this.oscillator = p5sound.audiocontext.createOscillator(); 89318 this.f = freq || 440; 89319 // frequency 89320 this.oscillator.type = type || 'sine'; 89321 this.oscillator.frequency.setValueAtTime(this.f, p5sound.audiocontext.currentTime); 89322 // connections 89323 this.output = p5sound.audiocontext.createGain(); 89324 this._freqMods = []; 89325 // modulators connected to this oscillator's frequency 89326 // set default output gain to 0.5 89327 this.output.gain.value = 0.5; 89328 this.output.gain.setValueAtTime(0.5, p5sound.audiocontext.currentTime); 89329 this.oscillator.connect(this.output); 89330 // stereo panning 89331 this.panPosition = 0; 89332 this.connection = p5sound.input; 89333 // connect to p5sound by default 89334 this.panner = new p5.Panner(this.output, this.connection, 1); 89335 //array of math operation signal chaining 89336 this.mathOps = [this.output]; 89337 // add to the soundArray so we can dispose of the osc later 89338 p5sound.soundArray.push(this); 89339 }; 89340 /** 89341 * Start an oscillator. Accepts an optional parameter to 89342 * determine how long (in seconds from now) until the 89343 * oscillator starts. 89344 * 89345 * @method start 89346 * @param {Number} [time] startTime in seconds from now. 89347 * @param {Number} [frequency] frequency in Hz. 89348 */ 89349 p5.Oscillator.prototype.start = function (time, f) { 89350 if (this.started) { 89351 var now = p5sound.audiocontext.currentTime; 89352 this.stop(now); 89353 } 89354 if (!this.started) { 89355 var freq = f || this.f; 89356 var type = this.oscillator.type; 89357 // set old osc free to be garbage collected (memory) 89358 if (this.oscillator) { 89359 this.oscillator.disconnect(); 89360 delete this.oscillator; 89361 } 89362 // var detune = this.oscillator.frequency.value; 89363 this.oscillator = p5sound.audiocontext.createOscillator(); 89364 this.oscillator.frequency.value = Math.abs(freq); 89365 this.oscillator.type = type; 89366 // this.oscillator.detune.value = detune; 89367 this.oscillator.connect(this.output); 89368 time = time || 0; 89369 this.oscillator.start(time + p5sound.audiocontext.currentTime); 89370 this.freqNode = this.oscillator.frequency; 89371 // if other oscillators are already connected to this osc's freq 89372 for (var i in this._freqMods) { 89373 if (typeof this._freqMods[i].connect !== 'undefined') { 89374 this._freqMods[i].connect(this.oscillator.frequency); 89375 } 89376 } 89377 this.started = true; 89378 } 89379 }; 89380 /** 89381 * Stop an oscillator. Accepts an optional parameter 89382 * to determine how long (in seconds from now) until the 89383 * oscillator stops. 89384 * 89385 * @method stop 89386 * @param {Number} secondsFromNow Time, in seconds from now. 89387 */ 89388 p5.Oscillator.prototype.stop = function (time) { 89389 if (this.started) { 89390 var t = time || 0; 89391 var now = p5sound.audiocontext.currentTime; 89392 this.oscillator.stop(t + now); 89393 this.started = false;
89394 } 89395 }; 89396 /** 89397 * Set the amplitude between 0 and 1.0. Or, pass in an object 89398 * such as an oscillator to modulate amplitude with an audio signal. 89399 * 89400 * @method amp 89401 * @param {Number|Object} vol between 0 and 1.0 89402 * or a modulating signal/oscillator 89403 * @param {Number} [rampTime] create a fade that lasts rampTime 89404 * @param {Number} [timeFromNow] schedule this event to happen 89405 * seconds from now 89406 * @return {AudioParam} gain If no value is provided, 89407 * returns the Web Audio API 89408 * AudioParam that controls 89409 * this oscillator's 89410 * gain/amplitude/volume) 89411 */ 89412 p5.Oscillator.prototype.amp = function (vol, rampTime, tFromNow) { 89413 var self = this; 89414 if (typeof vol === 'number') { 89415 var rampTime = rampTime || 0; 89416 var tFromNow = tFromNow || 0; 89417 var now = p5sound.audiocontext.currentTime; 89418 this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime); 89419 } else if (vol) { 89420 vol.connect(self.output.gain); 89421 } else { 89422 // return the Gain Node 89423 return this.output.gain; 89424 } 89425 }; 89426 // these are now the same thing 89427 p5.Oscillator.prototype.fade = p5.Oscillator.prototype.amp; 89428 p5.Oscillator.prototype.getAmp = function () { 89429 return this.output.gain.value; 89430 }; 89431 /** 89432 * Set frequency of an oscillator to a value. Or, pass in an object 89433 * such as an oscillator to modulate the frequency with an audio signal. 89434 * 89435 * @method freq 89436 * @param {Number|Object} Frequency Frequency in Hz 89437 * or modulating signal/oscillator 89438 * @param {Number} [rampTime] Ramp time (in seconds) 89439 * @param {Number} [timeFromNow] Schedule this event to happen 89440 * at x seconds from now 89441 * @return {AudioParam} Frequency If no value is provided, 89442 * returns the Web Audio API 89443 * AudioParam that controls 89444 * this oscillator's frequency 89445 * @example 89446 * <div><code> 89447 * var osc = new p5.Oscillator(300); 89448 * osc.start(); 89449 * osc.freq(40, 10); 89450 * </code></div> 89451 */ 89452 p5.Oscillator.prototype.freq = function (val, rampTime, tFromNow) { 89453 if (typeof val === 'number' && !isNaN(val)) { 89454 this.f = val; 89455 var now = p5sound.audiocontext.currentTime; 89456 var rampTime = rampTime || 0; 89457 var tFromNow = tFromNow || 0; 89458 var t = now + tFromNow + rampTime; 89459 // var currentFreq = this.oscillator.frequency.value; 89460 // this.oscillator.frequency.cancelScheduledValues(now); 89461 if (rampTime === 0) { 89462 this.oscillator.frequency.setValueAtTime(val, tFromNow + now); 89463 } else { 89464 if (val > 0) { 89465 this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); 89466 } else { 89467 this.oscillator.frequency.linearRampToValueAtTime(val, tFromNow + rampTime + now); 89468 } 89469 } 89470 // reset phase if oscillator has a phase 89471 if (this.phaseAmount) { 89472 this.phase(this.phaseAmount); 89473 } 89474 } else if (val) { 89475 if (val.output) { 89476 val = val.output; 89477 } 89478 val.connect(this.oscillator.frequency); 89479 // keep track of what is modulating this param 89480 // so it can be re-connected if 89481 this._freqMods.push(val); 89482 } else { 89483 // return the Frequency Node 89484 return this.oscillator.frequency; 89485 } 89486 }; 89487 p5.Oscillator.prototype.getFreq = function () { 89488 return this.oscillator.frequency.value; 89489 }; 89490 /** 89491 * Set type to 'sine', 'triangle', 'sawtooth' or 'square'. 89492 * 89493 * @method setType 89494 * @param {String} type 'sine', 'triangle', 'sawtooth' or 'square'. 89495 */ 89496 p5.Oscillator.prototype.setType = function (type) { 89497 this.oscillator.type = type; 89498 }; 89499 p5.Oscillator.prototype.getType = function () { 89500 return this.oscillator.type; 89501 }; 89502 /** 89503 * Connect to a p5.sound / Web Audio object. 89504 * 89505 * @method connect 89506 * @param {Object} unit A p5.sound or Web Audio object 89507 */ 89508 p5.Oscillator.prototype.connect = function (unit) { 89509 if (!unit) { 89510 this.panner.connect(p5sound.input); 89511 } else if (unit.hasOwnProperty('input')) {
89512 this.panner.connect(unit.input); 89513 this.connection = unit.input; 89514 } else { 89515 this.panner.connect(unit); 89516 this.connection = unit; 89517 } 89518 }; 89519 /** 89520 * Disconnect all outputs 89521 * 89522 * @method disconnect 89523 */ 89524 p5.Oscillator.prototype.disconnect = function () { 89525 if (this.output) { 89526 this.output.disconnect(); 89527 } 89528 if (this.panner) { 89529 this.panner.disconnect(); 89530 if (this.output) { 89531 this.output.connect(this.panner); 89532 } 89533 } 89534 this.oscMods = []; 89535 }; 89536 /** 89537 * Pan between Left (-1) and Right (1) 89538 * 89539 * @method pan 89540 * @param {Number} panning Number between -1 and 1 89541 * @param {Number} timeFromNow schedule this event to happen 89542 * seconds from now 89543 */ 89544 p5.Oscillator.prototype.pan = function (pval, tFromNow) { 89545 this.panPosition = pval; 89546 this.panner.pan(pval, tFromNow); 89547 }; 89548 p5.Oscillator.prototype.getPan = function () { 89549 return this.panPosition; 89550 }; 89551 // get rid of the oscillator 89552 p5.Oscillator.prototype.dispose = function () { 89553 // remove reference from soundArray 89554 var index = p5sound.soundArray.indexOf(this); 89555 p5sound.soundArray.splice(index, 1); 89556 if (this.oscillator) { 89557 var now = p5sound.audiocontext.currentTime; 89558 this.stop(now); 89559 this.disconnect(); 89560 this.panner = null; 89561 this.oscillator = null; 89562 } 89563 // if it is a Pulse 89564 if (this.osc2) { 89565 this.osc2.dispose(); 89566 } 89567 }; 89568 /** 89569 * Set the phase of an oscillator between 0.0 and 1.0. 89570 * In this implementation, phase is a delay time 89571 * based on the oscillator's current frequency. 89572 * 89573 * @method phase 89574 * @param {Number} phase float between 0.0 and 1.0 89575 */ 89576 p5.Oscillator.prototype.phase = function (p) { 89577 var delayAmt = p5.prototype.map(p, 0, 1, 0, 1 / this.f); 89578 var now = p5sound.audiocontext.currentTime; 89579 this.phaseAmount = p; 89580 if (!this.dNode) { 89581 // create a delay node 89582 this.dNode = p5sound.audiocontext.createDelay(); 89583 // put the delay node in between output and panner 89584 this.oscillator.disconnect(); 89585 this.oscillator.connect(this.dNode); 89586 this.dNode.connect(this.output); 89587 } 89588 // set delay time to match phase: 89589 this.dNode.delayTime.setValueAtTime(delayAmt, now); 89590 }; 89591 // ========================== // 89592 // SIGNAL MATH FOR MODULATION // 89593 // ========================== // 89594 // return sigChain(this, scale, thisChain, nextChain, Scale); 89595 var sigChain = function (o, mathObj, thisChain, nextChain, type) { 89596 var chainSource = o.oscillator; 89597 // if this type of math already exists in the chain, replace it 89598 for (var i in o.mathOps) { 89599 if (o.mathOps[i] instanceof type) { 89600 chainSource.disconnect(); 89601 o.mathOps[i].dispose(); 89602 thisChain = i; 89603 // assume nextChain is output gain node unless... 89604 if (thisChain < o.mathOps.length - 2) { 89605 nextChain = o.mathOps[i + 1]; 89606 } 89607 } 89608 } 89609 if (thisChain === o.mathOps.length - 1) { 89610 o.mathOps.push(nextChain); 89611 } 89612 // assume source is the oscillator unless i > 0 89613 if (i > 0) { 89614 chainSource = o.mathOps[i - 1]; 89615 } 89616 chainSource.disconnect(); 89617 chainSource.connect(mathObj); 89618 mathObj.connect(nextChain); 89619 o.mathOps[thisChain] = mathObj; 89620 return o; 89621 }; 89622 /** 89623 * Add a value to the p5.Oscillator's output amplitude, 89624 * and return the oscillator. Calling this method again 89625 * will override the initial add() with a new value. 89626 * 89627 * @method add 89628 * @param {Number} number Constant number to add 89629 * @return {p5.Oscillator} Oscillator Returns this oscillator 89630 * with scaled output 89631 * 89632 */ 89633 p5.Oscillator.prototype.add = function (num) { 89634 var add = new Add(num); 89635 var thisChain = this.mathOps.length - 1; 89636 var nextChain = this.output; 89637 return sigChain(this, add, thisChain, nextChain, Add); 89638 }; 89639 /** 89640 * Multiply the p5.Oscillator's output amplitude 89641 * by a fixed value (i.e. turn it up!). Calling this method 89642 * again will override the initial mult() with a new value. 89643 * 89644 * @method mult 89645 * @param {Number}
89645 number Constant number to multiply 89646 * @return {p5.Oscillator} Oscillator Returns this oscillator 89647 * with multiplied output 89648 */ 89649 p5.Oscillator.prototype.mult = function (num) { 89650 var mult = new Mult(num); 89651 var thisChain = this.mathOps.length - 1; 89652 var nextChain = this.output; 89653 return sigChain(this, mult, thisChain, nextChain, Mult); 89654 }; 89655 /** 89656 * Scale this oscillator's amplitude values to a given 89657 * range, and return the oscillator. Calling this method 89658 * again will override the initial scale() with new values. 89659 * 89660 * @method scale 89661 * @param {Number} inMin input range minumum 89662 * @param {Number} inMax input range maximum 89663 * @param {Number} outMin input range minumum 89664 * @param {Number} outMax input range maximum 89665 * @return {p5.Oscillator} Oscillator Returns this oscillator 89666 * with scaled output 89667 */ 89668 p5.Oscillator.prototype.scale = function (inMin, inMax, outMin, outMax) { 89669 var mapOutMin, mapOutMax; 89670 if (arguments.length === 4) { 89671 mapOutMin = p5.prototype.map(outMin, inMin, inMax, 0, 1) - 0.5; 89672 mapOutMax = p5.prototype.map(outMax, inMin, inMax, 0, 1) - 0.5; 89673 } else { 89674 mapOutMin = arguments[0]; 89675 mapOutMax = arguments[1]; 89676 } 89677 var scale = new Scale(mapOutMin, mapOutMax); 89678 var thisChain = this.mathOps.length - 1; 89679 var nextChain = this.output; 89680 return sigChain(this, scale, thisChain, nextChain, Scale); 89681 }; 89682 // ============================== // 89683 // SinOsc, TriOsc, SqrOsc, SawOsc // 89684 // ============================== // 89685 /** 89686 * Constructor: <code>new p5.SinOsc()</code>. 89687 * This creates a Sine Wave Oscillator and is 89688 * equivalent to <code> new p5.Oscillator('sine') 89689 * </code> or creating a p5.Oscillator and then calling 89690 * its method <code>setType('sine')</code>. 89691 * See p5.Oscillator for methods. 89692 * 89693 * @class p5.SinOsc 89694 * @constructor 89695 * @extends p5.Oscillator 89696 * @param {Number} [freq] Set the frequency 89697 */ 89698 p5.SinOsc = function (freq) { 89699 p5.Oscillator.call(this, freq, 'sine'); 89700 }; 89701 p5.SinOsc.prototype = Object.create(p5.Oscillator.prototype); 89702 /** 89703 * Constructor: <code>new p5.TriOsc()</code>. 89704 * This creates a Triangle Wave Oscillator and is 89705 * equivalent to <code>new p5.Oscillator('triangle') 89706 * </code> or creating a p5.Oscillator and then calling 89707 * its method <code>setType('triangle')</code>. 89708 * See p5.Oscillator for methods. 89709 * 89710 * @class p5.TriOsc 89711 * @constructor 89712 * @extends p5.Oscillator 89713 * @param {Number} [freq] Set the frequency 89714 */ 89715 p5.TriOsc = function (freq) { 89716 p5.Oscillator.call(this, freq, 'triangle'); 89717 }; 89718 p5.TriOsc.prototype = Object.create(p5.Oscillator.prototype); 89719 /** 89720 * Constructor: <code>new p5.SawOsc()</code>. 89721 * This creates a SawTooth Wave Oscillator and is 89722 * equivalent to <code> new p5.Oscillator('sawtooth') 89723 * </code> or creating a p5.Oscillator and then calling 89724 * its method <code>setType('sawtooth')</code>. 89725 * See p5.Oscillator for methods. 89726 * 89727 * @class p5.SawOsc 89728 * @constructor 89729 * @extends p5.Oscillator 89730 * @param {Number} [freq] Set the frequency 89731 */ 89732 p5.SawOsc = function (freq) { 89733 p5.Oscillator.call(this, freq, 'sawtooth'); 89734 }; 89735 p5.SawOsc.prototype = Object.create(p5.Oscillator.prototype); 89736 /** 89737 * Constructor: <code>new p5.SqrOsc()</code>. 89738 * This creates a Square Wave Oscillator and is 89739 * equivalent to <code> new p5.Oscillator('square') 89740 * </code> or creating a p5.Oscillator and then calling 89741 * its method <code>setType('square')</code>. 89742 * See p5.Oscillator for methods. 89743 * 89744 * @class p5.SqrOsc 89745 * @constructor 89746 * @extends p5.Oscillator 89747 * @param {Number} [freq] Set the frequency 89748 */ 89749 p5.SqrOsc = function (freq) { 89750 p5.Oscillator.call(this, freq, 'square'); 89751 }; 89752 p5.SqrOsc.prototype = Object.create(p5.Oscillator.prototype); 89753}(master, Tone_signal_Add, Tone_signal_Multiply, Tone_signal_Scale); 89754/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 89755var Tone_core_Timeline; 89756Tone_core_Timeline = function (Tone) { 89757 'use strict'; 89758 Tone.Timeline = function () { 89759 var options = this.optionsObject(arguments, ['memory'], Tone.Timeline.defaults); 89760 this._timeline = []; 89761 this._toRemove = []; 89762 this._iterating = false;
89763 this.memory = options.memory; 89764 }; 89765 Tone.extend(Tone.Timeline); 89766 Tone.Timeline.defaults = { 'memory': Infinity }; 89767 Object.defineProperty(Tone.Timeline.prototype, 'length', { 89768 get: function () { 89769 return this._timeline.length; 89770 } 89771 }); 89772 Tone.Timeline.prototype.add = function (event) { 89773 if (this.isUndef(event.time)) { 89774 throw new Error('Tone.Timeline: events must have a time attribute'); 89775 } 89776 if (this._timeline.length) { 89777 var index = this._search(event.time); 89778 this._timeline.splice(index + 1, 0, event); 89779 } else { 89780 this._timeline.push(event); 89781 } 89782 if (this.length > this.memory) { 89783 var diff = this.length - this.memory; 89784 this._timeline.splice(0, diff); 89785 } 89786 return this; 89787 }; 89788 Tone.Timeline.prototype.remove = function (event) { 89789 if (this._iterating) { 89790 this._toRemove.push(event); 89791 } else { 89792 var index = this._timeline.indexOf(event); 89793 if (index !== -1) { 89794 this._timeline.splice(index, 1); 89795 } 89796 } 89797 return this; 89798 }; 89799 Tone.Timeline.prototype.get = function (time) { 89800 var index = this._search(time); 89801 if (index !== -1) { 89802 return this._timeline[index]; 89803 } else { 89804 return null; 89805 } 89806 }; 89807 Tone.Timeline.prototype.peek = function () { 89808 return this._timeline[0]; 89809 }; 89810 Tone.Timeline.prototype.shift = function () { 89811 return this._timeline.shift(); 89812 }; 89813 Tone.Timeline.prototype.getAfter = function (time) { 89814 var index = this._search(time); 89815 if (index + 1 < this._timeline.length) { 89816 return this._timeline[index + 1]; 89817 } else { 89818 return null; 89819 } 89820 }; 89821 Tone.Timeline.prototype.getBefore = function (time) { 89822 var len = this._timeline.length; 89823 if (len > 0 && this._timeline[len - 1].time < time) { 89824 return this._timeline[len - 1]; 89825 } 89826 var index = this._search(time); 89827 if (index - 1 >= 0) { 89828 return this._timeline[index - 1]; 89829 } else { 89830 return null; 89831 } 89832 }; 89833 Tone.Timeline.prototype.cancel = function (after) { 89834 if (this._timeline.length > 1) { 89835 var index = this._search(after); 89836 if (index >= 0) { 89837 if (this._timeline[index].time === after) { 89838 for (var i = index; i >= 0; i--) { 89839 if (this._timeline[i].time === after) { 89840 index = i; 89841 } else { 89842 break; 89843 } 89844 } 89845 this._timeline = this._timeline.slice(0, index); 89846 } else { 89847 this._timeline = this._timeline.slice(0, index + 1); 89848 } 89849 } else { 89850 this._timeline = []; 89851 } 89852 } else if (this._timeline.length === 1) { 89853 if (this._timeline[0].time >= after) { 89854 this._timeline = []; 89855 } 89856 } 89857 return this; 89858 }; 89859 Tone.Timeline.prototype.cancelBefore = function (time) { 89860 if (this._timeline.length) { 89861 var index = this._search(time); 89862 if (index >= 0) { 89863 this._timeline = this._timeline.slice(index + 1); 89864 } 89865 } 89866 return this; 89867 }; 89868 Tone.Timeline.prototype._search = function (time) { 89869 var beginning = 0; 89870 var len = this._timeline.length; 89871 var end = len; 89872 if (len > 0 && this._timeline[len - 1].time <= time) { 89873 return len - 1; 89874 } 89875 while (beginning < end) { 89876 var midPoint = Math.floor(beginning + (end - beginning) / 2); 89877 var event = this._timeline[midPoint]; 89878 var nextEvent = this._timeline[midPoint + 1]; 89879 if (event.time === time) { 89880 for (var i = midPoint; i < this._timeline.length; i++) { 89881 var testEvent = this._timeline[i]; 89882 if (testEvent.time === time) { 89883 midPoint = i; 89884 } 89885 } 89886 return midPoint; 89887 } else if (event.time < time && nextEvent.time > time) { 89888 return midPoint; 89889 } else if (event.time > time) { 89890 end = midPoint; 89891 } else if (event.time < time) { 89892 beginning = midPoint + 1; 89893 } 89894 } 89895 return -1; 89896 }; 89897 Tone.Timeline.prototype._iterate = function (callback, lowerBound, upperBound) { 89898 this._iterating = true; 89899 lowerBound = this.defaultArg(lowerBound, 0); 89900 upperBound = this.defaultArg(upperBound, this._timeline.length - 1); 89901 for (var i = lowerBound; i <= upperBound; i++) { 89902 callback(this._timeline[i]); 89903 } 89904 this._iterating = false;
89905 if (this._toRemove.length > 0) { 89906 for (var j = 0; j < this._toRemove.length; j++) { 89907 var index = this._timeline.indexOf(this._toRemove[j]); 89908 if (index !== -1) { 89909 this._timeline.splice(index, 1); 89910 } 89911 } 89912 this._toRemove = []; 89913 } 89914 }; 89915 Tone.Timeline.prototype.forEach = function (callback) { 89916 this._iterate(callback); 89917 return this; 89918 }; 89919 Tone.Timeline.prototype.forEachBefore = function (time, callback) { 89920 var upperBound = this._search(time); 89921 if (upperBound !== -1) { 89922 this._iterate(callback, 0, upperBound); 89923 } 89924 return this; 89925 }; 89926 Tone.Timeline.prototype.forEachAfter = function (time, callback) { 89927 var lowerBound = this._search(time); 89928 this._iterate(callback, lowerBound + 1); 89929 return this; 89930 }; 89931 Tone.Timeline.prototype.forEachFrom = function (time, callback) { 89932 var lowerBound = this._search(time); 89933 while (lowerBound >= 0 && this._timeline[lowerBound].time >= time) { 89934 lowerBound--; 89935 } 89936 this._iterate(callback, lowerBound + 1); 89937 return this; 89938 }; 89939 Tone.Timeline.prototype.forEachAtTime = function (time, callback) { 89940 var upperBound = this._search(time); 89941 if (upperBound !== -1) { 89942 this._iterate(function (event) { 89943 if (event.time === time) { 89944 callback(event); 89945 } 89946 }, 0, upperBound); 89947 } 89948 return this; 89949 }; 89950 Tone.Timeline.prototype.dispose = function () { 89951 Tone.prototype.dispose.call(this); 89952 this._timeline = null; 89953 this._toRemove = null; 89954 }; 89955 return Tone.Timeline; 89956}(Tone_core_Tone); 89957/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 89958var Tone_signal_TimelineSignal; 89959Tone_signal_TimelineSignal = function (Tone) { 89960 'use strict'; 89961 Tone.TimelineSignal = function () { 89962 var options = this.optionsObject(arguments, [ 89963 'value', 89964 'units' 89965 ], Tone.Signal.defaults); 89966 this._events = new Tone.Timeline(10); 89967 Tone.Signal.apply(this, options); 89968 options.param = this._param; 89969 Tone.Param.call(this, options); 89970 this._initial = this._fromUnits(this._param.value); 89971 }; 89972 Tone.extend(Tone.TimelineSignal, Tone.Param); 89973 Tone.TimelineSignal.Type = { 89974 Linear: 'linear', 89975 Exponential: 'exponential', 89976 Target: 'target', 89977 Curve: 'curve', 89978 Set: 'set' 89979 }; 89980 Object.defineProperty(Tone.TimelineSignal.prototype, 'value', { 89981 get: function () { 89982 var now = this.now(); 89983 var val = this.getValueAtTime(now); 89984 return this._toUnits(val); 89985 }, 89986 set: function (value) { 89987 var convertedVal = this._fromUnits(value); 89988 this._initial = convertedVal; 89989 this.cancelScheduledValues(); 89990 this._param.value = convertedVal; 89991 } 89992 }); 89993 Tone.TimelineSignal.prototype.setValueAtTime = function (value, startTime) { 89994 value = this._fromUnits(value); 89995 startTime = this.toSeconds(startTime); 89996 this._events.add({ 89997 'type': Tone.TimelineSignal.Type.Set, 89998 'value': value, 89999 'time': startTime 90000 }); 90001 this._param.setValueAtTime(value, startTime); 90002 return this; 90003 }; 90004 Tone.TimelineSignal.prototype.linearRampToValueAtTime = function (value, endTime) { 90005 value = this._fromUnits(value); 90006 endTime = this.toSeconds(endTime); 90007 this._events.add({ 90008 'type': Tone.TimelineSignal.Type.Linear, 90009 'value': value, 90010 'time': endTime 90011 }); 90012 this._param.linearRampToValueAtTime(value, endTime); 90013 return this; 90014 }; 90015 Tone.TimelineSignal.prototype.exponentialRampToValueAtTime = function (value, endTime) { 90016 endTime = this.toSeconds(endTime); 90017 var beforeEvent = this._searchBefore(endTime); 90018 if (beforeEvent && beforeEvent.value === 0) { 90019 this.setValueAtTime(this._minOutput, beforeEvent.time); 90020 } 90021 value = this._fromUnits(value); 90022 var setValue = Math.max(value, this._minOutput); 90023 this._events.add({ 90024 'type': Tone.TimelineSignal.Type.Exponential, 90025 'value': setValue, 90026 'time': endTime 90027 }); 90028 if (value < this._minOutput) { 90029 this._param.exponentialRampToValueAtTime(this._minOutput, endTime - this.sampleTime); 90030 this.setValueAtTime(0, endTime); 90031 } else { 90032 this._param.exponentialRampToValueAtTime(value, endTime); 90033 } 90034 return this; 90035 }; 90036 Tone.TimelineSignal.prototype.setTargetAtTime = function (value, startTime, timeConstant) { 90037 value = this._fromUnits(value); 90038 value = Math.max(this._minOutput, value); 90039 timeConstant = Math.max(this._minOutput, timeConstant); 90040 startTime = this.toSeconds(startTime); 90041 this._events.add({ 90042 'type': Tone.TimelineSignal.Type.Target, 90043 'value': value, 90044 'time': startTime, 90045 'constant': timeConstant 90046 }); 90047 this._param.setTargetAtTime(value, startTime, timeConstant); 90048 return this; 90049 }; 90050 Tone.TimelineSignal.prototype.setValueCurveAtTime = function (values, startTime, duration, scaling) { 90051 scaling = this.defaultArg(scaling, 1); 90052 var floats = new Array(values.length); 90053 for (var i = 0; i < floats.length; i++) { 90054 floats[i] = this._fromUnits(values[i]) * scaling; 90055 } 90056 startTime = this.toSeconds(startTime); 90057 duration = this.toSeconds(duration); 90058 this._events.add({ 90059 'type': Tone.TimelineSignal.Type.Curve, 90060 'value': floats, 90061 'time': startTime, 90062 'duration': duration 90063 }); 90064 this._param.setValueAtTime(floats[0], startTime); 90065 for (var j = 1; j < floats.length; j++) { 90066 var segmentTime = startTime + j / (floats.length - 1) * duration; 90067 this._param.linearRampToValueAtTime(floats[j], segmentTime); 90068 } 90069 return this; 90070 }; 90071 Tone.TimelineSignal.prototype.cancelScheduledValues = function (after) { 90072 after = this.toSeconds(after); 90073 this._events.cancel(after); 90074 this._param.cancelScheduledValues(after); 90075 return this; 90076 }; 90077 Tone.TimelineSignal.prototype.setRampPoint = function (time) { 90078 time = this.toSeconds(time); 90079 var val = this._toUnits(this.getValueAtTime(time)); 90080 var before = this._searchBefore(time); 90081 if (before && before.time === time) { 90082 this.cancelScheduledValues(time + this.sampleTime); 90083 } else if (before && before.type === Tone.TimelineSignal.Type.Curve && before.time + before.duration > time) { 90084 this.cancelScheduledValues(time); 90085 this.linearRampToValueAtTime(val, time); 90086 } else { 90087 var after = this._searchAfter(time); 90088 if (after) { 90089 this.cancelScheduledValues(time); 90090 if (after.type === Tone.TimelineSignal.Type.Linear) { 90091 this.linearRampToValueAtTime(val, time); 90092 } else if (after.type === Tone.TimelineSignal.Type.Exponential) { 90093 this.exponentialRampToValueAtTime(val, time); 90094 } 90095 } 90096 this.setValueAtTime(val, time); 90097 } 90098 return this; 90099 }; 90100 Tone.TimelineSignal.prototype.linearRampToValueBetween = function (value, start, finish) { 90101 this.setRampPoint(start); 90102 this.linearRampToValueAtTime(value, finish); 90103 return this; 90104 };
90105 Tone.TimelineSignal.prototype.exponentialRampToValueBetween = function (value, start, finish) { 90106 this.setRampPoint(start); 90107 this.exponentialRampToValueAtTime(value, finish); 90108 return this; 90109 }; 90110 Tone.TimelineSignal.prototype._searchBefore = function (time) { 90111 return this._events.get(time); 90112 }; 90113 Tone.TimelineSignal.prototype._searchAfter = function (time) { 90114 return this._events.getAfter(time); 90115 }; 90116 Tone.TimelineSignal.prototype.getValueAtTime = function (time) { 90117 time = this.toSeconds(time); 90118 var after = this._searchAfter(time); 90119 var before = this._searchBefore(time); 90120 var value = this._initial; 90121 if (before === null) { 90122 value = this._initial; 90123 } else if (before.type === Tone.TimelineSignal.Type.Target) { 90124 var previous = this._events.getBefore(before.time); 90125 var previouVal; 90126 if (previous === null) { 90127 previouVal = this._initial; 90128 } else { 90129 previouVal = previous.value; 90130 } 90131 value = this._exponentialApproach(before.time, previouVal, before.value, before.constant, time); 90132 } else if (before.type === Tone.TimelineSignal.Type.Curve) { 90133 value = this._curveInterpolate(before.time, before.value, before.duration, time); 90134 } else if (after === null) { 90135 value = before.value; 90136 } else if (after.type === Tone.TimelineSignal.Type.Linear) { 90137 value = this._linearInterpolate(before.time, before.value, after.time, after.value, time); 90138 } else if (after.type === Tone.TimelineSignal.Type.Exponential) { 90139 value = this._exponentialInterpolate(before.time, before.value, after.time, after.value, time); 90140 } else { 90141 value = before.value; 90142 } 90143 return value; 90144 }; 90145 Tone.TimelineSignal.prototype.connect = Tone.SignalBase.prototype.connect; 90146 Tone.TimelineSignal.prototype._exponentialApproach = function (t0, v0, v1, timeConstant, t) { 90147 return v1 + (v0 - v1) * Math.exp(-(t - t0) / timeConstant); 90148 }; 90149 Tone.TimelineSignal.prototype._linearInterpolate = function (t0, v0, t1, v1, t) { 90150 return v0 + (v1 - v0) * ((t - t0) / (t1 - t0)); 90151 }; 90152 Tone.TimelineSignal.prototype._exponentialInterpolate = function (t0, v0, t1, v1, t) { 90153 v0 = Math.max(this._minOutput, v0); 90154 return v0 * Math.pow(v1 / v0, (t - t0) / (t1 - t0)); 90155 }; 90156 Tone.TimelineSignal.prototype._curveInterpolate = function (start, curve, duration, time) { 90157 var len = curve.length; 90158 if (time >= start + duration) { 90159 return curve[len - 1]; 90160 } else if (time <= start) { 90161 return curve[0]; 90162 } else { 90163 var progress = (time - start) / duration; 90164 var lowerIndex = Math.floor((len - 1) * progress); 90165 var upperIndex = Math.ceil((len - 1) * progress); 90166 var lowerVal = curve[lowerIndex]; 90167 var upperVal = curve[upperIndex]; 90168 if (upperIndex === lowerIndex) { 90169 return lowerVal; 90170 } else { 90171 return this._linearInterpolate(lowerIndex, lowerVal, upperIndex, upperVal, progress * (len - 1)); 90172 } 90173 } 90174 }; 90175 Tone.TimelineSignal.prototype.dispose = function () { 90176 Tone.Signal.prototype.dispose.call(this); 90177 Tone.Param.prototype.dispose.call(this); 90178 this._events.dispose(); 90179 this._events = null; 90180 }; 90181 return Tone.TimelineSignal; 90182}(Tone_core_Tone, Tone_signal_Signal); 90183var envelope; 90184'use strict'; 90185envelope = function () { 90186 var p5sound = master; 90187 var Add = Tone_signal_Add; 90188 var Mult = Tone_signal_Multiply; 90189 var Scale = Tone_signal_Scale; 90190 var TimelineSignal = Tone_signal_TimelineSignal; 90191 var Tone = Tone_core_Tone; 90192 Tone.setContext(p5sound.audiocontext); 90193 /** 90194 * <p>Envelopes are pre-defined amplitude distribution over time. 90195 * Typically, envelopes are used to control the output volume 90196 * of an object, a series of fades referred to as Attack, Decay, 90197 * Sustain and Release ( 90198 * <a href="https://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg">ADSR</a> 90199 * ). Envelopes can also control other Web Audio Parametersâfor example, a p5.Envelope can 90200 * control an Oscillator's frequency like this: <code>osc.freq(env)</code>.</p> 90201 * <p>Use <code><a href="#/p5.Envelope/setRange">setRange</a></code> to change the attack/release level. 90202 * Use <code><a href="#/p5.Envelope/setADSR">setADSR</a></code> to change attackTime, decayTime, sustainPercent and releaseTime.</p> 90203 * <p>Use the <code><a href="#/p5.Envelope/play">play</a></code> method to play the entire envelope, 90204 * the <code><a href="#/p5.Envelope/ramp">ramp</a></code> method for a pingable trigger, 90205 * or <code><a href="#/p5.Envelope/triggerAttack">triggerAttack</a></code>/ 90206 * <code><a href="#/p5.Envelope/triggerRelease">triggerRelease</a></code> to trigger noteOn/noteOff.</p> 90207 * 90208 * @class p5.Envelope 90209 * @constructor 90210 * @example 90211 * <div><code> 90212 * var attackLevel = 1.0; 90213 * var releaseLevel = 0; 90214 * 90215 * var attackTime = 0.001; 90216 * var decayTime = 0.2; 90217 * var susPercent = 0.2; 90218 * var releaseTime = 0.5; 90219 * 90220 * var env, triOsc; 90221 * 90222 * function setup() { 90223 * var cnv = createCanvas(100, 100); 90224 * 90225 * textAlign(CENTER); 90226 * text('click to play', width/2, height/2); 90227 * 90228 * env = new p5.Envelope(); 90229 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 90230 * env.setRange(attackLevel, releaseLevel); 90231 * 90232 * triOsc = new p5.Oscillator('triangle'); 90233 * triOsc.amp(env); 90234 * triOsc.start(); 90235 * triOsc.freq(220); 90236 * 90237 * cnv.mousePressed(playEnv); 90238 * } 90239 * 90240 * function playEnv() { 90241 * env.play(); 90242 * } 90243 * </code></div> 90244 */ 90245 p5.Envelope = function (t1, l1, t2, l2, t3, l3) { 90246 /** 90247 * Time until envelope reaches attackLevel 90248 * @property attackTime 90249 */ 90250 this.aTime = t1 || 0.1; 90251 /** 90252 * Level once attack is complete. 90253 * @property attackLevel 90254 */ 90255 this.aLevel = l1 || 1; 90256 /** 90257 * Time until envelope reaches decayLevel. 90258 * @property decayTime 90259 */ 90260 this.dTime = t2 || 0.5; 90261 /** 90262 * Level after decay. The envelope will sustain here until it is released. 90263 * @property decayLevel 90264 */ 90265 this.dLevel = l2 || 0; 90266 /** 90267 * Duration of the release portion of the envelope. 90268 * @property releaseTime 90269 */ 90270 this.rTime = t3 || 0; 90271 /** 90272 * Level at the end of the release. 90273 * @property releaseLevel 90274 */ 90275 this.rLevel = l3 || 0; 90276 this._rampHighPercentage = 0.98; 90277 this._rampLowPercentage = 0.02; 90278 this.output = p5sound.audiocontext.createGain(); 90279 this.control = new TimelineSignal(); 90280 this._init(); 90281 // this makes sure the envelope starts at zero 90282 this.control.connect(this.output); 90283 // connect to the output 90284 this.connection = null; 90285 // store connection 90286 //array of math operation signal chaining 90287 this.mathOps = [this.control]; 90288 //whether envelope should be linear or exponential curve 90289 this.isExponential = false;
90290 // oscillator or buffer source to clear on env complete 90291 // to save resources if/when it is retriggered 90292 this.sourceToClear = null; 90293 // set to true if attack is set, then false on release 90294 this.wasTriggered = false; 90295 // add to the soundArray so we can dispose of the env later 90296 p5sound.soundArray.push(this); 90297 }; 90298 // this init function just smooths the starting value to zero and gives a start point for the timeline 90299 // - it was necessary to remove glitches at the beginning. 90300 p5.Envelope.prototype._init = function () { 90301 var now = p5sound.audiocontext.currentTime; 90302 var t = now; 90303 this.control.setTargetAtTime(0.00001, t, 0.001); 90304 //also, compute the correct time constants 90305 this._setRampAD(this.aTime, this.dTime); 90306 }; 90307 /** 90308 * Reset the envelope with a series of time/value pairs. 90309 * 90310 * @method set 90311 * @param {Number} attackTime Time (in seconds) before level 90312 * reaches attackLevel 90313 * @param {Number} attackLevel Typically an amplitude between 90314 * 0.0 and 1.0 90315 * @param {Number} decayTime Time 90316 * @param {Number} decayLevel Amplitude (In a standard ADSR envelope, 90317 * decayLevel = sustainLevel) 90318 * @param {Number} releaseTime Release Time (in seconds) 90319 * @param {Number} releaseLevel Amplitude 90320 * @example 90321 * <div><code> 90322 * var t1 = 0.1;
90322 // attack time in seconds 90323 * var l1 = 0.7; // attack level 0.0 to 1.0 90324 * var t2 = 0.3; // decay time in seconds 90325 * var l2 = 0.1; // decay level 0.0 to 1.0 90326 * var t3 = 0.2; // sustain time in seconds 90327 * var l3 = 0.5; // sustain level 0.0 to 1.0 90328 * // release level defaults to zero 90329 * 90330 * var env; 90331 * var triOsc; 90332 * 90333 * function setup() { 90334 * background(0); 90335 * noStroke(); 90336 * fill(255); 90337 * textAlign(CENTER); 90338 * text('click to play', width/2, height/2); 90339 * 90340 * env = new p5.Envelope(t1, l1, t2, l2, t3, l3); 90341 * triOsc = new p5.Oscillator('triangle'); 90342 * triOsc.amp(env); // give the env control of the triOsc's amp 90343 * triOsc.start(); 90344 * } 90345 * 90346 * // mouseClick triggers envelope if over canvas 90347 * function mouseClicked() { 90348 * // is mouse over canvas? 90349 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 90350 * env.play(triOsc); 90351 * } 90352 * } 90353 * </code></div> 90354 * 90355 */ 90356 p5.Envelope.prototype.set = function (t1, l1, t2, l2, t3, l3) { 90357 this.aTime = t1; 90358 this.aLevel = l1; 90359 this.dTime = t2 || 0; 90360 this.dLevel = l2 || 0; 90361 this.rTime = t3 || 0; 90362 this.rLevel = l3 || 0; 90363 // set time constants for ramp 90364 this._setRampAD(t1, t2); 90365 }; 90366 /** 90367 * Set values like a traditional 90368 * <a href="https://en.wikipedia.org/wiki/Synthesizer#/media/File:ADSR_parameter.svg"> 90369 * ADSR envelope 90370 * </a>. 90371 * 90372 * @method setADSR 90373 * @param {Number} attackTime Time (in seconds before envelope 90374 * reaches Attack Level 90375 * @param {Number} [decayTime] Time (in seconds) before envelope 90376 * reaches Decay/Sustain Level 90377 * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, 90378 * where 1.0 = attackLevel, 0.0 = releaseLevel. 90379 * The susRatio determines the decayLevel and the level at which the 90380 * sustain portion of the envelope will sustain. 90381 * For example, if attackLevel is 0.4, releaseLevel is 0, 90382 * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is 90383 * increased to 1.0 (using <code>setRange</code>), 90384 * then decayLevel would increase proportionally, to become 0.5. 90385 * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) 90386 * @example 90387 * <div><code> 90388 * var attackLevel = 1.0; 90389 * var releaseLevel = 0; 90390 * 90391 * var attackTime = 0.001; 90392 * var decayTime = 0.2; 90393 * var susPercent = 0.2; 90394 * var releaseTime = 0.5; 90395 * 90396 * var env, triOsc; 90397 * 90398 * function setup() { 90399 * var cnv = createCanvas(100, 100); 90400 * 90401 * textAlign(CENTER); 90402 * text('click to play', width/2, height/2); 90403 * 90404 * env = new p5.Envelope(); 90405 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 90406 * env.setRange(attackLevel, releaseLevel); 90407 * 90408 * triOsc = new p5.Oscillator('triangle'); 90409 * triOsc.amp(env); 90410 * triOsc.start(); 90411 * triOsc.freq(220); 90412 * 90413 * cnv.mousePressed(playEnv); 90414 * } 90415 * 90416 * function playEnv() { 90417 * env.play(); 90418 * } 90419 * </code></div> 90420 */ 90421 p5.Envelope.prototype.setADSR = function (aTime, dTime, sPercent, rTime) { 90422 this.aTime = aTime; 90423 this.dTime = dTime || 0; 90424 // lerp 90425 this.sPercent = sPercent || 0; 90426 this.dLevel = typeof sPercent !== 'undefined' ? sPercent * (this.aLevel - this.rLevel) + this.rLevel : 0; 90427 this.rTime = rTime || 0; 90428 // also set time constants for ramp 90429 this._setRampAD(aTime, dTime); 90430 }; 90431 /** 90432 * Set max (attackLevel) and min (releaseLevel) of envelope. 90433 * 90434 * @method setRange 90435 * @param {Number} aLevel attack level (defaults to 1) 90436 * @param {Number} rLevel release level (defaults to 0) 90437 * @example 90438 * <div><code> 90439 * var attackLevel = 1.0; 90440 * var releaseLevel = 0; 90441 * 90442 * var attackTime = 0.001; 90443 * var decayTime = 0.2; 90444 * var susPercent = 0.2; 90445 * var releaseTime = 0.5; 90446 * 90447 * var env, triOsc; 90448 * 90449 * function setup() { 90450 * var cnv = createCanvas(100, 100); 90451 * 90452 * textAlign(CENTER); 90453 * text('click to play', width/2, height/2); 90454 * 90455 * env = new p5.Envelope(); 90456 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 90457 * env.setRange(attackLevel, releaseLevel); 90458 * 90459 * triOsc = new p5.Oscillator('triangle'); 90460 * triOsc.amp(env); 90461 * triOsc.start(); 90462 * triOsc.freq(220); 90463 * 90464 * cnv.mousePressed(playEnv); 90465 * } 90466 * 90467 * function playEnv() { 90468 * env.play(); 90469 * } 90470 * </code></div> 90471 */ 90472 p5.Envelope.prototype.setRange = function (aLevel, rLevel) { 90473 this.aLevel = aLevel || 1; 90474 this.rLevel = rLevel || 0; 90475 }; 90476 // private (undocumented) method called when ADSR is set to set time constants for ramp 90477 // 90478 // Set the <a href="https://en.wikipedia.org/wiki/RC_time_constant"> 90479 // time constants</a> for simple exponential ramps. 90480 // The larger the time constant value, the slower the 90481 // transition will be. 90482 // 90483 // method _setRampAD 90484 // param {Number}
90484 attackTimeConstant attack time constant 90485 // param {Number} decayTimeConstant decay time constant 90486 // 90487 p5.Envelope.prototype._setRampAD = function (t1, t2) { 90488 this._rampAttackTime = this.checkExpInput(t1); 90489 this._rampDecayTime = this.checkExpInput(t2); 90490 var TCDenominator = 1; 90491 /// Aatish Bhatia's calculation for time constant for rise(to adjust 1/1-e calculation to any percentage) 90492 TCDenominator = Math.log(1 / this.checkExpInput(1 - this._rampHighPercentage)); 90493 this._rampAttackTC = t1 / this.checkExpInput(TCDenominator); 90494 TCDenominator = Math.log(1 / this._rampLowPercentage); 90495 this._rampDecayTC = t2 / this.checkExpInput(TCDenominator); 90496 }; 90497 // private method 90498 p5.Envelope.prototype.setRampPercentages = function (p1, p2) { 90499 //set the percentages that the simple exponential ramps go to 90500 this._rampHighPercentage = this.checkExpInput(p1); 90501 this._rampLowPercentage = this.checkExpInput(p2); 90502 var TCDenominator = 1; 90503 //now re-compute the time constants based on those percentages 90504 /// Aatish Bhatia's calculation for time constant for rise(to adjust 1/1-e calculation to any percentage) 90505 TCDenominator = Math.log(1 / this.checkExpInput(1 - this._rampHighPercentage)); 90506 this._rampAttackTC = this._rampAttackTime / this.checkExpInput(TCDenominator); 90507 TCDenominator = Math.log(1 / this._rampLowPercentage); 90508 this._rampDecayTC = this._rampDecayTime / this.checkExpInput(TCDenominator); 90509 }; 90510 /** 90511 * Assign a parameter to be controlled by this envelope. 90512 * If a p5.Sound object is given, then the p5.Envelope will control its 90513 * output gain. If multiple inputs are provided, the env will 90514 * control all of them. 90515 * 90516 * @method setInput 90517 * @param {Object} [...inputs] A p5.sound object or 90518 * Web Audio Param. 90519 */ 90520 p5.Envelope.prototype.setInput = function () { 90521 for (var i = 0; i < arguments.length; i++) { 90522 this.connect(arguments[i]); 90523 } 90524 }; 90525 /** 90526 * Set whether the envelope ramp is linear (default) or exponential. 90527 * Exponential ramps can be useful because we perceive amplitude 90528 * and frequency logarithmically. 90529 * 90530 * @method setExp 90531 * @param {Boolean} isExp true is exponential, false is linear 90532 */ 90533 p5.Envelope.prototype.setExp = function (isExp) { 90534 this.isExponential = isExp; 90535 }; 90536 //helper method to protect against zero values being sent to exponential functions 90537 p5.Envelope.prototype.checkExpInput = function (value) { 90538 if (value <= 0) { 90539 value = 1e-8; 90540 } 90541 return value; 90542 }; 90543 /** 90544 * Play tells the envelope to start acting on a given input. 90545 * If the input is a p5.sound object (i.e. AudioIn, Oscillator, 90546 * SoundFile), then Envelope will control its output volume. 90547 * Envelopes can also be used to control any <a href=" 90548 * http://docs.webplatform.org/wiki/apis/webaudio/AudioParam"> 90549 * Web Audio Audio Param.</a> 90550 * 90551 * @method play 90552 * @param {Object} unit A p5.sound object or 90553 * Web Audio Param. 90554 * @param {Number} [startTime] time from now (in seconds) at which to play 90555 * @param {Number} [sustainTime] time to sustain before releasing the envelope 90556 * @example 90557 * <div><code> 90558 * var attackLevel = 1.0; 90559 * var releaseLevel = 0; 90560 * 90561 * var attackTime = 0.001; 90562 * var decayTime = 0.2; 90563 * var susPercent = 0.2; 90564 * var releaseTime = 0.5; 90565 * 90566 * var env, triOsc; 90567 * 90568 * function setup() { 90569 * var cnv = createCanvas(100, 100); 90570 * 90571 * textAlign(CENTER); 90572 * text('click to play', width/2, height/2); 90573 * 90574 * env = new p5.Envelope(); 90575 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 90576 * env.setRange(attackLevel, releaseLevel); 90577 * 90578 * triOsc = new p5.Oscillator('triangle'); 90579 * triOsc.amp(env); 90580 * triOsc.start(); 90581 * triOsc.freq(220); 90582 * 90583 * cnv.mousePressed(playEnv); 90584 * } 90585 * 90586 * function playEnv() { 90587 * // trigger env on triOsc, 0 seconds from now 90588 * // After decay, sustain for 0.2 seconds before release 90589 * env.play(triOsc, 0, 0.2); 90590 * } 90591 * </code></div> 90592 */ 90593 p5.Envelope.prototype.play = function (unit, secondsFromNow, susTime) { 90594 var tFromNow = secondsFromNow || 0; 90595 var susTime = susTime || 0; 90596 if (unit) { 90597 if (this.connection !== unit) { 90598 this.connect(unit); 90599 } 90600 } 90601 this.triggerAttack(unit, tFromNow); 90602 this.triggerRelease(unit, tFromNow + this.aTime + this.dTime + susTime); 90603 }; 90604 /** 90605 * Trigger the Attack, and Decay portion of the Envelope. 90606 * Similar to holding down a key on a piano, but it will 90607 * hold the sustain level until you let go. Input can be 90608 * any p5.sound object, or a <a href=" 90609 * http://docs.webplatform.org/wiki/apis/webaudio/AudioParam"> 90610 * Web Audio Param</a>. 90611 * 90612 * @method triggerAttack 90613 * @param {Object} unit p5.sound Object or Web Audio Param 90614 * @param {Number} secondsFromNow time from now (in seconds) 90615 * @example 90616 * <div><code> 90617 * 90618 * var attackLevel = 1.0; 90619 * var releaseLevel = 0; 90620 * 90621 * var attackTime = 0.001; 90622 * var decayTime = 0.3; 90623 * var susPercent = 0.4; 90624 * var releaseTime = 0.5; 90625 * 90626 * var env, triOsc; 90627 * 90628 * function setup() { 90629 * var cnv = createCanvas(100, 100); 90630 * background(200); 90631 * textAlign(CENTER); 90632 * text('click to play', width/2, height/2); 90633 * 90634 * env = new p5.Envelope(); 90635 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 90636 * env.setRange(attackLevel, releaseLevel); 90637 * 90638 * triOsc = new p5.Oscillator('triangle'); 90639 * triOsc.amp(env); 90640 * triOsc.start(); 90641 * triOsc.freq(220); 90642 * 90643 * cnv.mousePressed(envAttack); 90644 * } 90645 * 90646 * function envAttack() { 90647 * console.log('trigger attack'); 90648 * env.triggerAttack(); 90649 * 90650 * background(0,255,0); 90651 * text('attack!', width/2, height/2); 90652 * } 90653 * 90654 * function mouseReleased() { 90655 * env.triggerRelease(); 90656 * 90657 * background(200); 90658 * text('click to play', width/2, height/2); 90659 * } 90660 * </code></div> 90661 */ 90662 p5.Envelope.prototype.triggerAttack = function (unit, secondsFromNow) { 90663 var now = p5sound.audiocontext.currentTime; 90664 var tFromNow = secondsFromNow || 0; 90665 var t = now + tFromNow; 90666 this.lastAttack = t; 90667 this.wasTriggered = true; 90668 if (unit) { 90669 if (this.connection !== unit) { 90670 this.connect(unit); 90671 } 90672 } 90673 // get and set value (with linear ramp) to anchor automation 90674 var valToSet = this.control.getValueAtTime(t); 90675 if (this.isExponential === true) { 90676 this.control.exponentialRampToValueAtTime(this.checkExpInput(valToSet), t); 90677 } else { 90678 this.control.linearRampToValueAtTime(valToSet, t); 90679 } 90680 // after each ramp completes, cancel scheduled values 90681 // (so they can be overridden in case env has been re-triggered) 90682 // then, set current value (with linearRamp to avoid click) 90683 // then, schedule the next automation... 90684 // attack 90685 t += this.aTime; 90686 if (this.isExponential === true) { 90687 this.control.exponentialRampToValueAtTime(this.checkExpInput(this.aLevel), t); 90688 valToSet = this.checkExpInput(this.control.getValueAtTime(t)); 90689 this.control.cancelScheduledValues(t); 90690 this.control.exponentialRampToValueAtTime(valToSet, t); 90691 } else { 90692 this.control.linearRampToValueAtTime(this.aLevel, t); 90693 valToSet = this.control.getValueAtTime(t); 90694 this.control.cancelScheduledValues(t); 90695 this.control.linearRampToValueAtTime(valToSet, t); 90696 } 90697 // decay to decay level (if using ADSR, then decay level == sustain level) 90698 t += this.dTime; 90699 if (this.isExponential === true) { 90700 this.control.exponentialRampToValueAtTime(this.checkExpInput(this.dLevel), t); 90701 valToSet = this.checkExpInput(this.control.getValueAtTime(t)); 90702 this.control.cancelScheduledValues(t); 90703 this.control.exponentialRampToValueAtTime(valToSet, t); 90704 } else { 90705 this.control.linearRampToValueAtTime(this.dLevel, t); 90706 valToSet = this.control.getValueAtTime(t); 90707 this.control.cancelScheduledValues(t); 90708 this.control.linearRampToValueAtTime(valToSet, t); 90709 } 90710 }; 90711 /** 90712 * Trigger the Release of the Envelope. This is similar to releasing 90713 * the key on a piano and letting the sound fade according to the 90714 * release level and release time. 90715 * 90716 * @method triggerRelease 90717 * @param {Object} unit p5.sound Object or Web Audio Param 90718 * @param {Number} secondsFromNow time to trigger the release 90719 * @example 90720 * <div><code> 90721 * 90722 * var attackLevel = 1.0; 90723 * var releaseLevel = 0; 90724 * 90725 * var attackTime = 0.001; 90726 * var decayTime = 0.3; 90727 * var susPercent = 0.4; 90728 * var releaseTime = 0.5; 90729 * 90730 * var env, triOsc; 90731 * 90732 * function setup() { 90733 * var cnv = createCanvas(100, 100); 90734 * background(200); 90735 * textAlign(CENTER); 90736 * text('click to play', width/2, height/2); 90737 * 90738 * env = new p5.Envelope(); 90739 * env.setADSR(attackTime, decayTime, susPercent, releaseTime); 90740 * env.setRange(attackLevel, releaseLevel); 90741 * 90742 * triOsc = new p5.Oscillator('triangle'); 90743 * triOsc.amp(env); 90744 * triOsc.start(); 90745 * triOsc.freq(220); 90746 * 90747 * cnv.mousePressed(envAttack); 90748 * } 90749 * 90750 * function envAttack() { 90751 * console.log('trigger attack'); 90752 * env.triggerAttack(); 90753 * 90754 * background(0,255,0); 90755 * text('attack!', width/2, height/2); 90756 * } 90757 * 90758 * function mouseReleased() { 90759 * env.triggerRelease(); 90760 * 90761 * background(200); 90762 * text('click to play', width/2, height/2); 90763 * } 90764 * </code></div> 90765 */ 90766 p5.Envelope.prototype.triggerRelease = function (unit, secondsFromNow) { 90767 // only trigger a release if an attack was triggered 90768 if (!this.wasTriggered) { 90769 // this currently causes a bit of trouble: 90770 // if a later release has been scheduled (via the play function) 90771 // a new earlier release won't interrupt it, because 90772 // this.wasTriggered has already been set to false. 90773 // If we want new earlier releases to override, then we need to 90774 // keep track of the last release time, and if the new release time is 90775 // earlier, then use it. 90776 return; 90777 } 90778 var now = p5sound.audiocontext.currentTime; 90779 var tFromNow = secondsFromNow || 0; 90780 var t = now + tFromNow; 90781 if (unit) { 90782 if (this.connection !== unit) { 90783 this.connect(unit); 90784 } 90785 } 90786 // get and set value (with linear or exponential ramp) to anchor automation 90787 var valToSet = this.control.getValueAtTime(t); 90788 if (this.isExponential === true) { 90789 this.control.exponentialRampToValueAtTime(this.checkExpInput(valToSet), t); 90790 } else { 90791 this.control.linearRampToValueAtTime(valToSet, t); 90792 } 90793 // release 90794 t += this.rTime; 90795 if (this.isExponential === true) { 90796 this.control.exponentialRampToValueAtTime(this.checkExpInput(this.rLevel), t); 90797 valToSet = this.checkExpInput(this.control.getValueAtTime(t)); 90798 this.control.cancelScheduledValues(t); 90799 this.control.exponentialRampToValueAtTime(valToSet, t); 90800 } else { 90801 this.control.linearRampToValueAtTime(this.rLevel, t); 90802 valToSet = this.control.getValueAtTime(t); 90803 this.control.cancelScheduledValues(t); 90804 this.control.linearRampToValueAtTime(valToSet, t); 90805 } 90806 this.wasTriggered = false;
90807 }; 90808 /** 90809 * Exponentially ramp to a value using the first two 90810 * values from <code><a href="#/p5.Envelope/setADSR">setADSR(attackTime, decayTime)</a></code> 90811 * as <a href="https://en.wikipedia.org/wiki/RC_time_constant"> 90812 * time constants</a> for simple exponential ramps. 90813 * If the value is higher than current value, it uses attackTime, 90814 * while a decrease uses decayTime. 90815 * 90816 * @method ramp 90817 * @param {Object} unit p5.sound Object or Web Audio Param 90818 * @param {Number} secondsFromNow When to trigger the ramp 90819 * @param {Number} v Target value 90820 * @param {Number} [v2] Second target value (optional) 90821 * @example 90822 * <div><code> 90823 * var env, osc, amp, cnv; 90824 * 90825 * var attackTime = 0.001; 90826 * var decayTime = 0.2; 90827 * var attackLevel = 1; 90828 * var decayLevel = 0; 90829 * 90830 * function setup() { 90831 * cnv = createCanvas(100, 100); 90832 * fill(0,255,0); 90833 * noStroke(); 90834 * 90835 * env = new p5.Envelope(); 90836 * env.setADSR(attackTime, decayTime); 90837 * 90838 * osc = new p5.Oscillator(); 90839 * osc.amp(env); 90840 * osc.start(); 90841 * 90842 * amp = new p5.Amplitude(); 90843 * 90844 * cnv.mousePressed(triggerRamp); 90845 * } 90846 * 90847 * function triggerRamp() { 90848 * env.ramp(osc, 0, attackLevel, decayLevel); 90849 * } 90850 * 90851 * function draw() { 90852 * background(20,20,20); 90853 * text('click me', 10, 20); 90854 * var h = map(amp.getLevel(), 0, 0.4, 0, height);; 90855 * 90856 * rect(0, height, width, -h); 90857 * } 90858 * </code></div> 90859 */ 90860 p5.Envelope.prototype.ramp = function (unit, secondsFromNow, v1, v2) { 90861 var now = p5sound.audiocontext.currentTime; 90862 var tFromNow = secondsFromNow || 0; 90863 var t = now + tFromNow; 90864 var destination1 = this.checkExpInput(v1); 90865 var destination2 = typeof v2 !== 'undefined' ? this.checkExpInput(v2) : undefined; 90866 // connect env to unit if not already connected 90867 if (unit) { 90868 if (this.connection !== unit) { 90869 this.connect(unit); 90870 } 90871 } 90872 //get current value 90873 var currentVal = this.checkExpInput(this.control.getValueAtTime(t)); 90874 // this.control.cancelScheduledValues(t); 90875 //if it's going up 90876 if (destination1 > currentVal) { 90877 this.control.setTargetAtTime(destination1, t, this._rampAttackTC); 90878 t += this._rampAttackTime; 90879 } else if (destination1 < currentVal) { 90880 this.control.setTargetAtTime(destination1, t, this._rampDecayTC); 90881 t += this._rampDecayTime; 90882 } 90883 // Now the second part of envelope begins 90884 if (destination2 === undefined) 90885 return; 90886 //if it's going up 90887 if (destination2 > destination1) { 90888 this.control.setTargetAtTime(destination2, t, this._rampAttackTC); 90889 } else if (destination2 < destination1) { 90890 this.control.setTargetAtTime(destination2, t, this._rampDecayTC); 90891 } 90892 }; 90893 p5.Envelope.prototype.connect = function (unit) { 90894 this.connection = unit; 90895 // assume we're talking about output gain 90896 // unless given a different audio param 90897 if (unit instanceof p5.Oscillator || unit instanceof p5.SoundFile || unit instanceof p5.AudioIn || unit instanceof p5.Reverb || unit instanceof p5.Noise || unit instanceof p5.Filter || unit instanceof p5.Delay) { 90898 unit = unit.output.gain; 90899 } 90900 if (unit instanceof AudioParam) { 90901 //set the initial value 90902 unit.setValueAtTime(0, p5sound.audiocontext.currentTime); 90903 } 90904 if (unit instanceof p5.Signal) { 90905 unit.setValue(0); 90906 } 90907 this.output.connect(unit); 90908 }; 90909 p5.Envelope.prototype.disconnect = function () { 90910 if (this.output) { 90911 this.output.disconnect(); 90912 } 90913 }; 90914 // Signal Math 90915 /** 90916 * Add a value to the p5.Oscillator's output amplitude, 90917 * and return the oscillator. Calling this method 90918 * again will override the initial add() with new values. 90919 * 90920 * @method add 90921 * @param {Number} number Constant number to add 90922 * @return {p5.Envelope} Envelope Returns this envelope 90923 * with scaled output 90924 */ 90925 p5.Envelope.prototype.add = function (num) { 90926 var add = new Add(num); 90927 var thisChain = this.mathOps.length; 90928 var nextChain = this.output; 90929 return p5.prototype._mathChain(this, add, thisChain, nextChain, Add); 90930 }; 90931 /** 90932 * Multiply the p5.Envelope's output amplitude 90933 * by a fixed value. Calling this method 90934 * again will override the initial mult() with new values. 90935 * 90936 * @method mult 90937 * @param {Number}
90937 number Constant number to multiply 90938 * @return {p5.Envelope} Envelope Returns this envelope 90939 * with scaled output 90940 */ 90941 p5.Envelope.prototype.mult = function (num) { 90942 var mult = new Mult(num); 90943 var thisChain = this.mathOps.length; 90944 var nextChain = this.output; 90945 return p5.prototype._mathChain(this, mult, thisChain, nextChain, Mult); 90946 }; 90947 /** 90948 * Scale this envelope's amplitude values to a given 90949 * range, and return the envelope. Calling this method 90950 * again will override the initial scale() with new values. 90951 * 90952 * @method scale 90953 * @param {Number} inMin input range minumum 90954 * @param {Number} inMax input range maximum 90955 * @param {Number} outMin input range minumum 90956 * @param {Number} outMax input range maximum 90957 * @return {p5.Envelope} Envelope Returns this envelope 90958 * with scaled output 90959 */ 90960 p5.Envelope.prototype.scale = function (inMin, inMax, outMin, outMax) { 90961 var scale = new Scale(inMin, inMax, outMin, outMax); 90962 var thisChain = this.mathOps.length; 90963 var nextChain = this.output; 90964 return p5.prototype._mathChain(this, scale, thisChain, nextChain, Scale); 90965 }; 90966 // get rid of the oscillator 90967 p5.Envelope.prototype.dispose = function () { 90968 // remove reference from soundArray 90969 var index = p5sound.soundArray.indexOf(this); 90970 p5sound.soundArray.splice(index, 1); 90971 this.disconnect(); 90972 if (this.control) { 90973 this.control.dispose(); 90974 this.control = null; 90975 } 90976 for (var i = 1; i < this.mathOps.length; i++) { 90977 this.mathOps[i].dispose(); 90978 } 90979 }; 90980 // Different name for backwards compatibility, replicates p5.Envelope class 90981 p5.Env = function (t1, l1, t2, l2, t3, l3) { 90982 console.warn('WARNING: p5.Env is now deprecated and may be removed in future versions. ' + 'Please use the new p5.Envelope instead.'); 90983 p5.Envelope.call(this, t1, l1, t2, l2, t3, l3); 90984 }; 90985 p5.Env.prototype = Object.create(p5.Envelope.prototype); 90986}(master, Tone_signal_Add, Tone_signal_Multiply, Tone_signal_Scale, Tone_signal_TimelineSignal, Tone_core_Tone); 90987var pulse; 90988'use strict'; 90989pulse = function () { 90990 var p5sound = master; 90991 /** 90992 * Creates a Pulse object, an oscillator that implements 90993 * Pulse Width Modulation. 90994 * The pulse is created with two oscillators. 90995 * Accepts a parameter for frequency, and to set the 90996 * width between the pulses. See <a href=" 90997 * http://p5js.org/reference/#/p5.Oscillator"> 90998 * <code>p5.Oscillator</code> for a full list of methods. 90999 * 91000 * @class p5.Pulse 91001 * @extends p5.Oscillator 91002 * @constructor 91003 * @param {Number} [freq] Frequency in oscillations per second (Hz) 91004 * @param {Number} [w] Width between the pulses (0 to 1.0, 91005 * defaults to 0) 91006 * @example 91007 * <div><code> 91008 * var pulse; 91009 * function setup() { 91010 * background(0); 91011 * 91012 * // Create and start the pulse wave oscillator 91013 * pulse = new p5.Pulse(); 91014 * pulse.amp(0.5); 91015 * pulse.freq(220); 91016 * pulse.start(); 91017 * } 91018 * 91019 * function draw() { 91020 * var w = map(mouseX, 0, width, 0, 1); 91021 * w = constrain(w, 0, 1); 91022 * pulse.width(w) 91023 * } 91024 * </code></div> 91025 */ 91026 p5.Pulse = function (freq, w) { 91027 p5.Oscillator.call(this, freq, 'sawtooth'); 91028 // width of PWM, should be betw 0 to 1.0 91029 this.w = w || 0; 91030 // create a second oscillator with inverse frequency 91031 this.osc2 = new p5.SawOsc(freq); 91032 // create a delay node 91033 this.dNode = p5sound.audiocontext.createDelay(); 91034 // dc offset 91035 this.dcOffset = createDCOffset(); 91036 this.dcGain = p5sound.audiocontext.createGain(); 91037 this.dcOffset.connect(this.dcGain); 91038 this.dcGain.connect(this.output); 91039 // set delay time based on PWM width 91040 this.f = freq || 440; 91041 var mW = this.w / this.oscillator.frequency.value; 91042 this.dNode.delayTime.value = mW; 91043 this.dcGain.gain.value = 1.7 * (0.5 - this.w); 91044 // disconnect osc2 and connect it to delay, which is connected to output 91045 this.osc2.disconnect(); 91046 this.osc2.panner.disconnect(); 91047 this.osc2.amp(-1); 91048 // inverted amplitude 91049 this.osc2.output.connect(this.dNode); 91050 this.dNode.connect(this.output); 91051 this.output.gain.value = 1; 91052 this.output.connect(this.panner); 91053 }; 91054 p5.Pulse.prototype = Object.create(p5.Oscillator.prototype); 91055 /** 91056 * Set the width of a Pulse object (an oscillator that implements 91057 * Pulse Width Modulation). 91058 * 91059 * @method width 91060 * @param {Number} [width] Width between the pulses (0 to 1.0, 91061 * defaults to 0) 91062 */ 91063 p5.Pulse.prototype.width = function (w) { 91064 if (typeof w === 'number') { 91065 if (w <= 1 && w >= 0) { 91066 this.w = w; 91067 // set delay time based on PWM width 91068 // var mW = map(this.w, 0, 1.0, 0, 1/this.f); 91069 var mW = this.w / this.oscillator.frequency.value; 91070 this.dNode.delayTime.value = mW; 91071 } 91072 this.dcGain.gain.value = 1.7 * (0.5 - this.w); 91073 } else { 91074 w.connect(this.dNode.delayTime); 91075 var sig = new p5.SignalAdd(-0.5); 91076 sig.setInput(w); 91077 sig = sig.mult(-1); 91078 sig = sig.mult(1.7); 91079 sig.connect(this.dcGain.gain); 91080 } 91081 }; 91082 p5.Pulse.prototype.start = function (f, time) { 91083 var now = p5sound.audiocontext.currentTime; 91084 var t = time || 0; 91085 if (!this.started) { 91086 var freq = f || this.f; 91087 var type = this.oscillator.type; 91088 this.oscillator = p5sound.audiocontext.createOscillator(); 91089 this.oscillator.frequency.setValueAtTime(freq, now); 91090 this.oscillator.type = type; 91091 this.oscillator.connect(this.output); 91092 this.oscillator.start(t + now); 91093 // set up osc2 91094 this.osc2.oscillator = p5sound.audiocontext.createOscillator(); 91095 this.osc2.oscillator.frequency.setValueAtTime(freq, t + now); 91096 this.osc2.oscillator.type = type; 91097 this.osc2.oscillator.connect(this.osc2.output); 91098 this.osc2.start(t + now); 91099 this.freqNode = [ 91100 this.oscillator.frequency, 91101 this.osc2.oscillator.frequency 91102 ]; 91103 // start dcOffset, too 91104 this.dcOffset = createDCOffset(); 91105 this.dcOffset.connect(this.dcGain); 91106 this.dcOffset.start(t + now); 91107 // if LFO connections depend on these oscillators 91108 if (this.mods !== undefined && this.mods.frequency !== undefined) { 91109 this.mods.frequency.connect(this.freqNode[0]); 91110 this.mods.frequency.connect(this.freqNode[1]); 91111 } 91112 this.started = true; 91113 this.osc2.started = true; 91114 } 91115 }; 91116 p5.Pulse.prototype.stop = function (time) { 91117 if (this.started) { 91118 var t = time || 0; 91119 var now = p5sound.audiocontext.currentTime; 91120 this.oscillator.stop(t + now); 91121 if (this.osc2.oscillator) { 91122 this.osc2.oscillator.stop(t + now); 91123 } 91124 this.dcOffset.stop(t + now); 91125 this.started = false;
91126 this.osc2.started = false; 91127 } 91128 }; 91129 p5.Pulse.prototype.freq = function (val, rampTime, tFromNow) { 91130 if (typeof val === 'number') { 91131 this.f = val; 91132 var now = p5sound.audiocontext.currentTime; 91133 var rampTime = rampTime || 0; 91134 var tFromNow = tFromNow || 0; 91135 var currentFreq = this.oscillator.frequency.value; 91136 this.oscillator.frequency.cancelScheduledValues(now); 91137 this.oscillator.frequency.setValueAtTime(currentFreq, now + tFromNow); 91138 this.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); 91139 this.osc2.oscillator.frequency.cancelScheduledValues(now); 91140 this.osc2.oscillator.frequency.setValueAtTime(currentFreq, now + tFromNow); 91141 this.osc2.oscillator.frequency.exponentialRampToValueAtTime(val, tFromNow + rampTime + now); 91142 if (this.freqMod) { 91143 this.freqMod.output.disconnect(); 91144 this.freqMod = null; 91145 } 91146 } else if (val.output) { 91147 val.output.disconnect(); 91148 val.output.connect(this.oscillator.frequency); 91149 val.output.connect(this.osc2.oscillator.frequency); 91150 this.freqMod = val; 91151 } 91152 }; 91153 // inspiration: http://webaudiodemos.appspot.com/oscilloscope/ 91154 function createDCOffset() { 91155 var ac = p5sound.audiocontext; 91156 var buffer = ac.createBuffer(1, 2048, ac.sampleRate); 91157 var data = buffer.getChannelData(0); 91158 for (var i = 0; i < 2048; i++) 91159 data[i] = 1; 91160 var bufferSource = ac.createBufferSource(); 91161 bufferSource.buffer = buffer; 91162 bufferSource.loop = true; 91163 return bufferSource; 91164 } 91165}(master, oscillator); 91166var noise; 91167'use strict'; 91168noise = function () { 91169 var p5sound = master; 91170 /** 91171 * Noise is a type of oscillator that generates a buffer with random values. 91172 * 91173 * @class p5.Noise 91174 * @extends p5.Oscillator 91175 * @constructor 91176 * @param {String} type Type of noise can be 'white' (default), 91177 * 'brown' or 'pink'. 91178 */ 91179 p5.Noise = function (type) { 91180 var assignType; 91181 p5.Oscillator.call(this); 91182 delete this.f; 91183 delete this.freq; 91184 delete this.oscillator; 91185 if (type === 'brown') { 91186 assignType = _brownNoise; 91187 } else if (type === 'pink') { 91188 assignType = _pinkNoise; 91189 } else { 91190 assignType = _whiteNoise; 91191 } 91192 this.buffer = assignType; 91193 }; 91194 p5.Noise.prototype = Object.create(p5.Oscillator.prototype); 91195 // generate noise buffers 91196 var _whiteNoise = function () { 91197 var bufferSize = 2 * p5sound.audiocontext.sampleRate; 91198 var whiteBuffer = p5sound.audiocontext.createBuffer(1, bufferSize, p5sound.audiocontext.sampleRate); 91199 var noiseData = whiteBuffer.getChannelData(0); 91200 for (var i = 0; i < bufferSize; i++) { 91201 noiseData[i] = Math.random() * 2 - 1; 91202 } 91203 whiteBuffer.type = 'white'; 91204 return whiteBuffer; 91205 }(); 91206 var _pinkNoise = function () { 91207 var bufferSize = 2 * p5sound.audiocontext.sampleRate; 91208 var pinkBuffer = p5sound.audiocontext.createBuffer(1, bufferSize, p5sound.audiocontext.sampleRate); 91209 var noiseData = pinkBuffer.getChannelData(0); 91210 var b0, b1, b2, b3, b4, b5, b6; 91211 b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0; 91212 for (var i = 0; i < bufferSize; i++) { 91213 var white = Math.random() * 2 - 1; 91214 b0 = 0.99886 * b0 + white * 0.0555179; 91215 b1 = 0.99332 * b1 + white * 0.0750759; 91216 b2 = 0.969 * b2 + white * 0.153852; 91217 b3 = 0.8665 * b3 + white * 0.3104856; 91218 b4 = 0.55 * b4 + white * 0.5329522; 91219 b5 = -0.7616 * b5 - white * 0.016898; 91220 noiseData[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; 91221 noiseData[i] *= 0.11; 91222 // (roughly) compensate for gain 91223 b6 = white * 0.115926; 91224 } 91225 pinkBuffer.type = 'pink'; 91226 return pinkBuffer; 91227 }(); 91228 var _brownNoise = function () { 91229 var bufferSize = 2 * p5sound.audiocontext.sampleRate; 91230 var brownBuffer = p5sound.audiocontext.createBuffer(1, bufferSize, p5sound.audiocontext.sampleRate); 91231 var noiseData = brownBuffer.getChannelData(0); 91232 var lastOut = 0; 91233 for (var i = 0; i < bufferSize; i++) { 91234 var white = Math.random() * 2 - 1; 91235 noiseData[i] = (lastOut + 0.02 * white) / 1.02; 91236 lastOut = noiseData[i]; 91237 noiseData[i] *= 3.5; 91238 } 91239 brownBuffer.type = 'brown'; 91240 return brownBuffer; 91241 }(); 91242 /** 91243 * Set type of noise to 'white', 'pink' or 'brown'. 91244 * White is the default. 91245 * 91246 * @method setType 91247 * @param {String} [type] 'white', 'pink' or 'brown' 91248 */ 91249 p5.Noise.prototype.setType = function (type) { 91250 switch (type) { 91251 case 'white': 91252 this.buffer = _whiteNoise; 91253 break; 91254 case 'pink': 91255 this.buffer = _pinkNoise; 91256 break; 91257 case 'brown': 91258 this.buffer = _brownNoise; 91259 break; 91260 default: 91261 this.buffer = _whiteNoise; 91262 } 91263 if (this.started) { 91264 var now = p5sound.audiocontext.currentTime; 91265 this.stop(now); 91266 this.start(now + 0.01); 91267 } 91268 }; 91269 p5.Noise.prototype.getType = function () { 91270 return this.buffer.type; 91271 }; 91272 p5.Noise.prototype.start = function () { 91273 if (this.started) { 91274 this.stop(); 91275 } 91276 this.noise = p5sound.audiocontext.createBufferSource(); 91277 this.noise.buffer = this.buffer; 91278 this.noise.loop = true; 91279 this.noise.connect(this.output); 91280 var now = p5sound.audiocontext.currentTime; 91281 this.noise.start(now); 91282 this.started = true; 91283 }; 91284 p5.Noise.prototype.stop = function () { 91285 var now = p5sound.audiocontext.currentTime; 91286 if (this.noise) { 91287 this.noise.stop(now); 91288 this.started = false;
91289 } 91290 }; 91291 p5.Noise.prototype.dispose = function () { 91292 var now = p5sound.audiocontext.currentTime; 91293 // remove reference from soundArray 91294 var index = p5sound.soundArray.indexOf(this); 91295 p5sound.soundArray.splice(index, 1); 91296 if (this.noise) { 91297 this.noise.disconnect(); 91298 this.stop(now); 91299 } 91300 if (this.output) { 91301 this.output.disconnect(); 91302 } 91303 if (this.panner) { 91304 this.panner.disconnect(); 91305 } 91306 this.output = null; 91307 this.panner = null; 91308 this.buffer = null; 91309 this.noise = null; 91310 }; 91311}(master); 91312var audioin; 91313'use strict'; 91314audioin = function () { 91315 var p5sound = master; 91316 // an array of input sources 91317 p5sound.inputSources = []; 91318 /** 91319 * <p>Get audio from an input, i.e. your computer's microphone.</p> 91320 * 91321 * <p>Turn the mic on/off with the start() and stop() methods. When the mic 91322 * is on, its volume can be measured with getLevel or by connecting an 91323 * FFT object.</p> 91324 * 91325 * <p>If you want to hear the AudioIn, use the .connect() method. 91326 * AudioIn does not connect to p5.sound output by default to prevent 91327 * feedback.</p> 91328 * 91329 * <p><em>Note: This uses the <a href="http://caniuse.com/stream">getUserMedia/ 91330 * Stream</a> API, which is not supported by certain browsers. Access in Chrome browser 91331 * is limited to localhost and https, but access over http may be limited.</em></p> 91332 * 91333 * @class p5.AudioIn 91334 * @constructor 91335 * @param {Function} [errorCallback] A function to call if there is an error 91336 * accessing the AudioIn. For example, 91337 * Safari and iOS devices do not 91338 * currently allow microphone access. 91339 * @example 91340 * <div><code> 91341 * var mic; 91342 * function setup(){ 91343 * mic = new p5.AudioIn() 91344 * mic.start(); 91345 * } 91346 * function draw(){ 91347 * background(0); 91348 * micLevel = mic.getLevel(); 91349 * ellipse(width/2, constrain(height-micLevel*height*5, 0, height), 10, 10); 91350 * } 91351 * </code></div> 91352 */ 91353 p5.AudioIn = function (errorCallback) { 91354 // set up audio input 91355 /** 91356 * @property {GainNode} input 91357 */ 91358 this.input = p5sound.audiocontext.createGain(); 91359 /** 91360 * @property {GainNode} output 91361 */ 91362 this.output = p5sound.audiocontext.createGain(); 91363 /** 91364 * @property {MediaStream|null} stream 91365 */ 91366 this.stream = null; 91367 /** 91368 * @property {MediaStreamAudioSourceNode|null} mediaStream 91369 */ 91370 this.mediaStream = null; 91371 /** 91372 * @property {Number|null} currentSource 91373 */ 91374 this.currentSource = null; 91375 /** 91376 * Client must allow browser to access their microphone / audioin source. 91377 * Default: false. Will become true when the client enables acces. 91378 * 91379 * @property {Boolean} enabled 91380 */ 91381 this.enabled = false; 91382 /** 91383 * Input amplitude, connect to it by default but not to master out 91384 * 91385 * @property {p5.Amplitude} amplitude 91386 */ 91387 this.amplitude = new p5.Amplitude(); 91388 this.output.connect(this.amplitude.input); 91389 if (!window.MediaStreamTrack || !window.navigator.mediaDevices || !window.navigator.mediaDevices.getUserMedia) { 91390 errorCallback ? errorCallback() : window.alert('This browser does not support MediaStreamTrack and mediaDevices'); 91391 } 91392 // add to soundArray so we can dispose on close 91393 p5sound.soundArray.push(this); 91394 }; 91395 /** 91396 * Start processing audio input. This enables the use of other 91397 * AudioIn methods like getLevel(). Note that by default, AudioIn 91398 * is not connected to p5.sound's output. So you won't hear 91399 * anything unless you use the connect() method.<br/> 91400 * 91401 * Certain browsers limit access to the user's microphone. For example, 91402 * Chrome only allows access from localhost and over https. For this reason, 91403 * you may want to include an errorCallbackâa function that is called in case 91404 * the browser won't provide mic access. 91405 * 91406 * @method start 91407 * @param {Function} [successCallback] Name of a function to call on 91408 * success. 91409 * @param {Function} [errorCallback] Name of a function to call if 91410 * there was an error. For example, 91411 * some browsers do not support 91412 * getUserMedia. 91413 */ 91414 p5.AudioIn.prototype.start = function (successCallback, errorCallback) { 91415 var self = this; 91416 if (this.stream) { 91417 this.stop(); 91418 } 91419 // set the audio source 91420 var audioSource = p5sound.inputSources[self.currentSource]; 91421 var constraints = { 91422 audio: { 91423 sampleRate: p5sound.audiocontext.sampleRate, 91424 echoCancellation: false 91425 } 91426 }; 91427 // if developers determine which source to use 91428 if (p5sound.inputSources[this.currentSource]) { 91429 constraints.audio.deviceId = audioSource.deviceId; 91430 } 91431 window.navigator.mediaDevices.getUserMedia(constraints).then(function (stream) { 91432 self.stream = stream; 91433 self.enabled = true; 91434 // Wrap a MediaStreamSourceNode around the live input 91435 self.mediaStream = p5sound.audiocontext.createMediaStreamSource(stream); 91436 self.mediaStream.connect(self.output); 91437 // only send to the Amplitude reader, so we can see it but not hear it. 91438 self.amplitude.setInput(self.output); 91439 if (successCallback) 91440 successCallback(); 91441 }).catch(function (err) { 91442 if (errorCallback) 91443 errorCallback(err); 91444 else 91445 console.error(err); 91446 }); 91447 }; 91448 /** 91449 * Turn the AudioIn off. If the AudioIn is stopped, it cannot getLevel(). 91450 * If re-starting, the user may be prompted for permission access. 91451 * 91452 * @method stop 91453 */ 91454 p5.AudioIn.prototype.stop = function () { 91455 if (this.stream) {
91456 this.stream.getTracks().forEach(function (track) { 91457 track.stop(); 91458 }); 91459 this.mediaStream.disconnect(); 91460 delete this.mediaStream; 91461 delete this.stream; 91462 } 91463 }; 91464 /** 91465 * Connect to an audio unit. If no parameter is provided, will 91466 * connect to the master output (i.e. your speakers).<br/> 91467 * 91468 * @method connect 91469 * @param {Object} [unit] An object that accepts audio input, 91470 * such as an FFT 91471 */ 91472 p5.AudioIn.prototype.connect = function (unit) { 91473 if (unit) { 91474 if (unit.hasOwnProperty('input')) { 91475 this.output.connect(unit.input); 91476 } else if (unit.hasOwnProperty('analyser')) { 91477 this.output.connect(unit.analyser); 91478 } else { 91479 this.output.connect(unit); 91480 } 91481 } else { 91482 this.output.connect(p5sound.input); 91483 } 91484 }; 91485 /** 91486 * Disconnect the AudioIn from all audio units. For example, if 91487 * connect() had been called, disconnect() will stop sending 91488 * signal to your speakers.<br/> 91489 * 91490 * @method disconnect 91491 */ 91492 p5.AudioIn.prototype.disconnect = function () { 91493 if (this.output) { 91494 this.output.disconnect(); 91495 // stay connected to amplitude even if not outputting to p5 91496 this.output.connect(this.amplitude.input); 91497 } 91498 }; 91499 /** 91500 * Read the Amplitude (volume level) of an AudioIn. The AudioIn 91501 * class contains its own instance of the Amplitude class to help 91502 * make it easy to get a microphone's volume level. Accepts an 91503 * optional smoothing value (0.0 < 1.0). <em>NOTE: AudioIn must 91504 * .start() before using .getLevel().</em><br/> 91505 * 91506 * @method getLevel 91507 * @param {Number} [smoothing] Smoothing is 0.0 by default. 91508 * Smooths values based on previous values. 91509 * @return {Number} Volume level (between 0.0 and 1.0) 91510 */ 91511 p5.AudioIn.prototype.getLevel = function (smoothing) { 91512 if (smoothing) { 91513 this.amplitude.smoothing = smoothing; 91514 } 91515 return this.amplitude.getLevel(); 91516 }; 91517 /** 91518 * Set amplitude (volume) of a mic input between 0 and 1.0. <br/> 91519 * 91520 * @method amp 91521 * @param {Number} vol between 0 and 1.0 91522 * @param {Number} [time] ramp time (optional) 91523 */ 91524 p5.AudioIn.prototype.amp = function (vol, t) { 91525 if (t) { 91526 var rampTime = t || 0; 91527 var currentVol = this.output.gain.value; 91528 this.output.gain.cancelScheduledValues(p5sound.audiocontext.currentTime); 91529 this.output.gain.setValueAtTime(currentVol, p5sound.audiocontext.currentTime); 91530 this.output.gain.linearRampToValueAtTime(vol, rampTime + p5sound.audiocontext.currentTime); 91531 } else { 91532 this.output.gain.cancelScheduledValues(p5sound.audiocontext.currentTime); 91533 this.output.gain.setValueAtTime(vol, p5sound.audiocontext.currentTime); 91534 } 91535 }; 91536 /** 91537 * Returns a list of available input sources. This is a wrapper 91538 * for <a title="MediaDevices.enumerateDevices() - Web APIs | MDN" target="_blank" href= 91539 * "https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices" 91540 * > and it returns a Promise. 91541 * 91542 * @method getSources 91543 * @param {Function} [successCallback] This callback function handles the sources when they 91544 * have been enumerated. The callback function 91545 * receives the deviceList array as its only argument 91546 * @param {Function} [errorCallback] This optional callback receives the error 91547 * message as its argument. 91548 * @returns {Promise} Returns a Promise that can be used in place of the callbacks, similar 91549 * to the enumerateDevices() method 91550 * @example 91551 * <div><code> 91552 * var audiograb; 91553 * 91554 * function setup(){ 91555 * //new audioIn 91556 * audioGrab = new p5.AudioIn(); 91557 * 91558 * audioGrab.getSources(function(deviceList) { 91559 * //print out the array of available sources 91560 * console.log(deviceList); 91561 * //set the source to the first item in the deviceList array 91562 * audioGrab.setSource(0); 91563 * }); 91564 * } 91565 * </code></div> 91566 */ 91567 p5.AudioIn.prototype.getSources = function (onSuccess, onError) { 91568 return new Promise(function (resolve, reject) { 91569 window.navigator.mediaDevices.enumerateDevices().then(function (devices) { 91570 p5sound.inputSources = devices.filter(function (device) { 91571 return device.kind === 'audioinput'; 91572 }); 91573 resolve(p5sound.inputSources); 91574 if (onSuccess) { 91575 onSuccess(p5sound.inputSources); 91576 } 91577 }).catch(function (error) { 91578 reject(error); 91579 if (onError) { 91580 onError(error); 91581 } else { 91582 console.error('This browser does not support MediaStreamTrack.getSources()'); 91583 } 91584 }); 91585 }); 91586 }; 91587 /** 91588 * Set the input source. Accepts a number representing a 91589 * position in the array returned by getSources(). 91590 * This is only available in browsers that support 91591 * <a title="MediaDevices.enumerateDevices() - Web APIs | MDN" target="_blank" href= 91592 * "https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices" 91593 * >navigator.mediaDevices.enumerateDevices()</a>.<br/> 91594 * 91595 * @method setSource 91596 * @param {number} num position of input source in the array 91597 */ 91598 p5.AudioIn.prototype.setSource = function (num) { 91599 if (p5sound.inputSources.length > 0 && num < p5sound.inputSources.length) { 91600 // set the current source 91601 this.currentSource = num; 91602 console.log('set source to ', p5sound.inputSources[this.currentSource]); 91603 } else { 91604 console.log('unable to set input source'); 91605 } 91606 // restart stream if currently active 91607 if (this.stream && this.stream.active) { 91608 this.start(); 91609 } 91610 }; 91611 // private method 91612 p5.AudioIn.prototype.dispose = function () { 91613 // remove reference from soundArray 91614 var index = p5sound.soundArray.indexOf(this); 91615 p5sound.soundArray.splice(index, 1); 91616 this.stop(); 91617 if (this.output) { 91618 this.output.disconnect(); 91619 } 91620 if (this.amplitude) { 91621 this.amplitude.disconnect(); 91622 } 91623 delete this.amplitude; 91624 delete this.output; 91625 }; 91626}(master); 91627/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 91628var Tone_signal_Negate; 91629Tone_signal_Negate = function (Tone) { 91630 'use strict'; 91631 Tone.Negate = function () { 91632 this._multiply = this.input = this.output = new Tone.Multiply(-1); 91633 }; 91634 Tone.extend(Tone.Negate, Tone.SignalBase); 91635 Tone.Negate.prototype.dispose = function () { 91636 Tone.prototype.dispose.call(this); 91637 this._multiply.dispose(); 91638 this._multiply = null; 91639 return this; 91640 }; 91641 return Tone.Negate; 91642}(Tone_core_Tone, Tone_signal_Multiply); 91643/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 91644var Tone_signal_Subtract; 91645Tone_signal_Subtract = function (Tone) { 91646 'use strict'; 91647 Tone.Subtract = function (value) { 91648 this.createInsOuts(2, 0); 91649 this._sum = this.input[0] = this.output = new Tone.Gain(); 91650 this._neg = new Tone.Negate(); 91651 this._param = this.input[1] = new Tone.Signal(value); 91652 this._param.chain(this._neg, this._sum); 91653 }; 91654 Tone.extend(Tone.Subtract, Tone.Signal); 91655 Tone.Subtract.prototype.dispose = function () { 91656 Tone.prototype.dispose.call(this); 91657 this._neg.dispose(); 91658 this._neg = null; 91659 this._sum.disconnect(); 91660 this._sum = null; 91661 this._param.dispose(); 91662 this._param = null; 91663 return this; 91664 }; 91665 return Tone.Subtract; 91666}(Tone_core_Tone, Tone_signal_Add, Tone_signal_Negate, Tone_signal_Signal); 91667/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 91668var Tone_signal_GreaterThanZero; 91669Tone_signal_GreaterThanZero = function (Tone) { 91670 'use strict'; 91671 Tone.GreaterThanZero = function () { 91672 this._thresh = this.output = new Tone.WaveShaper(function (val) { 91673 if (val <= 0) { 91674 return 0; 91675 } else { 91676 return 1; 91677 } 91678 }, 127); 91679 this._scale = this.input = new Tone.Multiply(10000); 91680 this._scale.connect(this._thresh); 91681 }; 91682 Tone.extend(Tone.GreaterThanZero, Tone.SignalBase); 91683 Tone.GreaterThanZero.prototype.dispose = function () { 91684 Tone.prototype.dispose.call(this); 91685 this._scale.dispose(); 91686 this._scale = null; 91687 this._thresh.dispose(); 91688 this._thresh = null; 91689 return this; 91690 }; 91691 return Tone.GreaterThanZero; 91692}(Tone_core_Tone, Tone_signal_Signal, Tone_signal_Multiply); 91693/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 91694var Tone_signal_GreaterThan; 91695Tone_signal_GreaterThan = function (Tone) { 91696 'use strict'; 91697 Tone.GreaterThan = function (value) { 91698 this.createInsOuts(2, 0); 91699 this._param = this.input[0] = new Tone.Subtract(value); 91700 this.input[1] = this._param.input[1]; 91701 this._gtz = this.output = new Tone.GreaterThanZero(); 91702 this._param.connect(this._gtz); 91703 }; 91704 Tone.extend(Tone.GreaterThan, Tone.Signal); 91705 Tone.GreaterThan.prototype.dispose = function () { 91706 Tone.prototype.dispose.call(this); 91707 this._param.dispose(); 91708 this._param = null; 91709 this._gtz.dispose(); 91710 this._gtz = null; 91711 return this; 91712 }; 91713 return Tone.GreaterThan; 91714}(Tone_core_Tone, Tone_signal_GreaterThanZero, Tone_signal_Subtract); 91715/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 91716var Tone_signal_Abs; 91717Tone_signal_Abs = function (Tone) { 91718 'use strict'; 91719 Tone.Abs = function () { 91720 this._abs = this.input = this.output = new Tone.WaveShaper(function (val) { 91721 if (val === 0) { 91722 return 0; 91723 } else { 91724 return Math.abs(val); 91725 } 91726 }, 127); 91727 }; 91728 Tone.extend(Tone.Abs, Tone.SignalBase); 91729 Tone.Abs.prototype.dispose = function () { 91730 Tone.prototype.dispose.call(this); 91731 this._abs.dispose(); 91732 this._abs = null; 91733 return this; 91734 }; 91735 return Tone.Abs; 91736}(Tone_core_Tone, Tone_signal_WaveShaper); 91737/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 91738var Tone_signal_Modulo; 91739Tone_signal_Modulo = function (Tone) { 91740 'use strict'; 91741 Tone.Modulo = function (modulus) { 91742 this.createInsOuts(1, 0); 91743 this._shaper = new Tone.WaveShaper(Math.pow(2, 16)); 91744 this._multiply = new Tone.Multiply(); 91745 this._subtract = this.output = new Tone.Subtract(); 91746 this._modSignal = new Tone.Signal(modulus); 91747 this.input.fan(this._shaper, this._subtract); 91748 this._modSignal.connect(this._multiply, 0, 0); 91749 this._shaper.connect(this._multiply, 0, 1); 91750 this._multiply.connect(this._subtract, 0, 1); 91751 this._setWaveShaper(modulus); 91752 }; 91753 Tone.extend(Tone.Modulo, Tone.SignalBase); 91754 Tone.Modulo.prototype._setWaveShaper = function (mod) { 91755 this._shaper.setMap(function (val) { 91756 var multiple = Math.floor((val + 0.0001) / mod); 91757 return multiple; 91758 }); 91759 }; 91760 Object.defineProperty(Tone.Modulo.prototype, 'value', { 91761 get: function () { 91762 return this._modSignal.value; 91763 }, 91764 set: function (mod) { 91765 this._modSignal.value = mod; 91766 this._setWaveShaper(mod); 91767 } 91768 }); 91769 Tone.Modulo.prototype.dispose = function () { 91770 Tone.prototype.dispose.call(this); 91771 this._shaper.dispose(); 91772 this._shaper = null; 91773 this._multiply.dispose(); 91774 this._multiply = null; 91775 this._subtract.dispose(); 91776 this._subtract = null;
91777 this._modSignal.dispose(); 91778 this._modSignal = null; 91779 return this; 91780 }; 91781 return Tone.Modulo; 91782}(Tone_core_Tone, Tone_signal_WaveShaper, Tone_signal_Multiply); 91783/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 91784var Tone_signal_Pow; 91785Tone_signal_Pow = function (Tone) { 91786 'use strict'; 91787 Tone.Pow = function (exp) { 91788 this._exp = this.defaultArg(exp, 1); 91789 this._expScaler = this.input = this.output = new Tone.WaveShaper(this._expFunc(this._exp), 8192); 91790 }; 91791 Tone.extend(Tone.Pow, Tone.SignalBase); 91792 Object.defineProperty(Tone.Pow.prototype, 'value', { 91793 get: function () { 91794 return this._exp; 91795 }, 91796 set: function (exp) { 91797 this._exp = exp; 91798 this._expScaler.setMap(this._expFunc(this._exp)); 91799 } 91800 }); 91801 Tone.Pow.prototype._expFunc = function (exp) { 91802 return function (val) { 91803 return Math.pow(Math.abs(val), exp); 91804 }; 91805 }; 91806 Tone.Pow.prototype.dispose = function () { 91807 Tone.prototype.dispose.call(this); 91808 this._expScaler.dispose(); 91809 this._expScaler = null; 91810 return this; 91811 }; 91812 return Tone.Pow; 91813}(Tone_core_Tone); 91814/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 91815var Tone_signal_AudioToGain; 91816Tone_signal_AudioToGain = function (Tone) { 91817 'use strict'; 91818 Tone.AudioToGain = function () { 91819 this._norm = this.input = this.output = new Tone.WaveShaper(function (x) { 91820 return (x + 1) / 2; 91821 }); 91822 }; 91823 Tone.extend(Tone.AudioToGain, Tone.SignalBase); 91824 Tone.AudioToGain.prototype.dispose = function () { 91825 Tone.prototype.dispose.call(this); 91826 this._norm.dispose(); 91827 this._norm = null; 91828 return this; 91829 }; 91830 return Tone.AudioToGain; 91831}(Tone_core_Tone, Tone_signal_WaveShaper); 91832/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 91833var Tone_signal_Expr; 91834Tone_signal_Expr = function (Tone) { 91835 'use strict'; 91836 Tone.Expr = function () { 91837 var expr = this._replacements(Array.prototype.slice.call(arguments)); 91838 var inputCount = this._parseInputs(expr); 91839 this._nodes = []; 91840 this.input = new Array(inputCount); 91841 for (var i = 0; i < inputCount; i++) { 91842 this.input[i] = this.context.createGain(); 91843 } 91844 var tree = this._parseTree(expr); 91845 var result; 91846 try { 91847 result = this._eval(tree); 91848 } catch (e) { 91849 this._disposeNodes(); 91850 throw new Error('Tone.Expr: Could evaluate expression: ' + expr); 91851 } 91852 this.output = result; 91853 }; 91854 Tone.extend(Tone.Expr, Tone.SignalBase); 91855 function applyBinary(Constructor, args, self) { 91856 var op = new Constructor(); 91857 self._eval(args[0]).connect(op, 0, 0); 91858 self._eval(args[1]).connect(op, 0, 1); 91859 return op; 91860 } 91861 function applyUnary(Constructor, args, self) { 91862 var op = new Constructor(); 91863 self._eval(args[0]).connect(op, 0, 0); 91864 return op; 91865 } 91866 function getNumber(arg) { 91867 return arg ? parseFloat(arg) : undefined; 91868 } 91869 function literalNumber(arg) { 91870 return arg && arg.args ? parseFloat(arg.args) : undefined; 91871 } 91872 Tone.Expr._Expressions = { 91873 'value': { 91874 'signal': { 91875 regexp: /^\d+\.\d+|^\d+/, 91876 method: function (arg) { 91877 var sig = new Tone.Signal(getNumber(arg)); 91878 return sig; 91879 } 91880 }, 91881 'input': { 91882 regexp: /^\$\d/, 91883 method: function (arg, self) { 91884 return self.input[getNumber(arg.substr(1))]; 91885 } 91886 } 91887 }, 91888 'glue': { 91889 '(': { regexp: /^\(/ }, 91890 ')': { regexp: /^\)/ }, 91891 ',': { regexp: /^,/ } 91892 }, 91893 'func': { 91894 'abs': { 91895 regexp: /^abs/, 91896 method: applyUnary.bind(this, Tone.Abs) 91897 }, 91898 'mod': { 91899 regexp: /^mod/, 91900 method: function (args, self) { 91901 var modulus = literalNumber(args[1]); 91902 var op = new Tone.Modulo(modulus); 91903 self._eval(args[0]).connect(op); 91904 return op; 91905 } 91906 }, 91907 'pow': { 91908 regexp: /^pow/, 91909 method: function (args, self) { 91910 var exp = literalNumber(args[1]); 91911 var op = new Tone.Pow(exp); 91912 self._eval(args[0]).connect(op); 91913 return op; 91914 } 91915 }, 91916 'a2g': { 91917 regexp: /^a2g/, 91918 method: function (args, self) { 91919 var op = new Tone.AudioToGain(); 91920 self._eval(args[0]).connect(op); 91921 return op; 91922 } 91923 } 91924 }, 91925 'binary': { 91926 '+': { 91927 regexp: /^\+/, 91928 precedence: 1, 91929 method: applyBinary.bind(this, Tone.Add) 91930 }, 91931 '-': { 91932 regexp: /^\-/, 91933 precedence: 1, 91934 method: function (args, self) { 91935 if (args.length === 1) { 91936 return applyUnary(Tone.Negate, args, self); 91937 } else { 91938 return applyBinary(Tone.Subtract, args, self); 91939 } 91940 } 91941 }, 91942 '*': { 91943 regexp: /^\*/, 91944 precedence: 0, 91945 method: applyBinary.bind(this, Tone.Multiply) 91946 } 91947 }, 91948 'unary': { 91949 '-': { 91950 regexp: /^\-/, 91951 method: applyUnary.bind(this, Tone.Negate) 91952 }, 91953 '!': { 91954 regexp: /^\!/, 91955 method: applyUnary.bind(this, Tone.NOT) 91956 } 91957 } 91958 }; 91959 Tone.Expr.prototype._parseInputs = function (expr) { 91960 var inputArray = expr.match(/\$\d/g); 91961 var inputMax = 0; 91962 if (inputArray !== null) { 91963 for (var i = 0; i < inputArray.length; i++) { 91964 var inputNum = parseInt(inputArray[i].substr(1)) + 1; 91965 inputMax = Math.max(inputMax, inputNum); 91966 } 91967 }
91968 return inputMax; 91969 }; 91970 Tone.Expr.prototype._replacements = function (args) { 91971 var expr = args.shift(); 91972 for (var i = 0; i < args.length; i++) { 91973 expr = expr.replace(/\%/i, args[i]); 91974 } 91975 return expr; 91976 }; 91977 Tone.Expr.prototype._tokenize = function (expr) { 91978 var position = -1; 91979 var tokens = []; 91980 while (expr.length > 0) { 91981 expr = expr.trim(); 91982 var token = getNextToken(expr); 91983 tokens.push(token); 91984 expr = expr.substr(token.value.length); 91985 } 91986 function getNextToken(expr) { 91987 for (var type in Tone.Expr._Expressions) { 91988 var group = Tone.Expr._Expressions[type]; 91989 for (var opName in group) { 91990 var op = group[opName]; 91991 var reg = op.regexp; 91992 var match = expr.match(reg); 91993 if (match !== null) { 91994 return { 91995 type: type, 91996 value: match[0], 91997 method: op.method 91998 }; 91999 } 92000 } 92001 } 92002 throw new SyntaxError('Tone.Expr: Unexpected token ' + expr); 92003 } 92004 return { 92005 next: function () { 92006 return tokens[++position]; 92007 }, 92008 peek: function () { 92009 return tokens[position + 1]; 92010 } 92011 }; 92012 }; 92013 Tone.Expr.prototype._parseTree = function (expr) { 92014 var lexer = this._tokenize(expr); 92015 var isUndef = this.isUndef.bind(this); 92016 function matchSyntax(token, syn) { 92017 return !isUndef(token) && token.type === 'glue' && token.value === syn; 92018 } 92019 function matchGroup(token, groupName, prec) { 92020 var ret = false;
92021 var group = Tone.Expr._Expressions[groupName]; 92022 if (!isUndef(token)) { 92023 for (var opName in group) { 92024 var op = group[opName]; 92025 if (op.regexp.test(token.value)) { 92026 if (!isUndef(prec)) { 92027 if (op.precedence === prec) { 92028 return true; 92029 } 92030 } else { 92031 return true; 92032 } 92033 } 92034 } 92035 } 92036 return ret; 92037 } 92038 function parseExpression(precedence) { 92039 if (isUndef(precedence)) { 92040 precedence = 5; 92041 } 92042 var expr; 92043 if (precedence < 0) { 92044 expr = parseUnary(); 92045 } else { 92046 expr = parseExpression(precedence - 1); 92047 } 92048 var token = lexer.peek(); 92049 while (matchGroup(token, 'binary', precedence)) { 92050 token = lexer.next(); 92051 expr = { 92052 operator: token.value, 92053 method: token.method, 92054 args: [ 92055 expr, 92056 parseExpression(precedence - 1) 92057 ] 92058 }; 92059 token = lexer.peek(); 92060 } 92061 return expr; 92062 } 92063 function parseUnary() { 92064 var token, expr; 92065 token = lexer.peek(); 92066 if (matchGroup(token, 'unary')) { 92067 token = lexer.next(); 92068 expr = parseUnary(); 92069 return { 92070 operator: token.value, 92071 method: token.method, 92072 args: [expr] 92073 }; 92074 } 92075 return parsePrimary(); 92076 } 92077 function parsePrimary() { 92078 var token, expr; 92079 token = lexer.peek(); 92080 if (isUndef(token)) { 92081 throw new SyntaxError('Tone.Expr: Unexpected termination of expression'); 92082 } 92083 if (token.type === 'func') { 92084 token = lexer.next(); 92085 return parseFunctionCall(token); 92086 } 92087 if (token.type === 'value') { 92088 token = lexer.next(); 92089 return { 92090 method: token.method, 92091 args: token.value 92092 }; 92093 } 92094 if (matchSyntax(token, '(')) { 92095 lexer.next(); 92096 expr = parseExpression(); 92097 token = lexer.next(); 92098 if (!matchSyntax(token, ')')) { 92099 throw new SyntaxError('Expected )'); 92100 } 92101 return expr; 92102 } 92103 throw new SyntaxError('Tone.Expr: Parse error, cannot process token ' + token.value); 92104 } 92105 function parseFunctionCall(func) { 92106 var token, args = []; 92107 token = lexer.next(); 92108 if (!matchSyntax(token, '(')) { 92109 throw new SyntaxError('Tone.Expr: Expected ( in a function call "' + func.value + '"'); 92110 } 92111 token = lexer.peek(); 92112 if (!matchSyntax(token, ')')) { 92113 args = parseArgumentList(); 92114 } 92115 token = lexer.next(); 92116 if (!matchSyntax(token, ')')) { 92117 throw new SyntaxError('Tone.Expr: Expected ) in a function call "' + func.value + '"'); 92118 } 92119 return { 92120 method: func.method, 92121 args: args, 92122 name: name 92123 }; 92124 } 92125 function parseArgumentList() { 92126 var token, expr, args = []; 92127 while (true) { 92128 expr = parseExpression(); 92129 if (isUndef(expr)) { 92130 break; 92131 } 92132 args.push(expr); 92133 token = lexer.peek(); 92134 if (!matchSyntax(token, ',')) { 92135 break; 92136 } 92137 lexer.next(); 92138 } 92139 return args; 92140 } 92141 return parseExpression(); 92142 }; 92143 Tone.Expr.prototype._eval = function (tree) { 92144 if (!this.isUndef(tree)) { 92145 var node = tree.method(tree.args, this); 92146 this._nodes.push(node); 92147 return node; 92148 } 92149 }; 92150 Tone.Expr.prototype._disposeNodes = function () { 92151 for (var i = 0; i < this._nodes.length; i++) { 92152 var node = this._nodes[i]; 92153 if (this.isFunction(node.dispose)) { 92154 node.dispose(); 92155 } else if (this.isFunction(node.disconnect)) { 92156 node.disconnect(); 92157 } 92158 node = null; 92159 this._nodes[i] = null; 92160 } 92161 this._nodes = null; 92162 }; 92163 Tone.Expr.prototype.dispose = function () { 92164 Tone.prototype.dispose.call(this); 92165 this._disposeNodes(); 92166 }; 92167 return Tone.Expr; 92168}(Tone_core_Tone, Tone_signal_Add, Tone_signal_Subtract, Tone_signal_Multiply, Tone_signal_GreaterThan, Tone_signal_GreaterThanZero, Tone_signal_Abs, Tone_signal_Negate, Tone_signal_Modulo, Tone_signal_Pow); 92169/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 92170var Tone_signal_EqualPowerGain; 92171Tone_signal_EqualPowerGain = function (Tone) { 92172 'use strict'; 92173 Tone.EqualPowerGain = function () { 92174 this._eqPower = this.input = this.output = new Tone.WaveShaper(function (val) { 92175 if (Math.abs(val) < 0.001) { 92176 return 0; 92177 } else { 92178 return this.equalPowerScale(val); 92179 } 92180 }.bind(this), 4096); 92181 }; 92182 Tone.extend(Tone.EqualPowerGain, Tone.SignalBase); 92183 Tone.EqualPowerGain.prototype.dispose = function () { 92184 Tone.prototype.dispose.call(this);
92185 this._eqPower.dispose(); 92186 this._eqPower = null; 92187 return this; 92188 }; 92189 return Tone.EqualPowerGain; 92190}(Tone_core_Tone); 92191/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 92192var Tone_component_CrossFade; 92193Tone_component_CrossFade = function (Tone) { 92194 'use strict'; 92195 Tone.CrossFade = function (initialFade) { 92196 this.createInsOuts(2, 1); 92197 this.a = this.input[0] = new Tone.Gain(); 92198 this.b = this.input[1] = new Tone.Gain(); 92199 this.fade = new Tone.Signal(this.defaultArg(initialFade, 0.5), Tone.Type.NormalRange); 92200 this._equalPowerA = new Tone.EqualPowerGain(); 92201 this._equalPowerB = new Tone.EqualPowerGain(); 92202 this._invert = new Tone.Expr('1 - $0'); 92203 this.a.connect(this.output); 92204 this.b.connect(this.output); 92205 this.fade.chain(this._equalPowerB, this.b.gain); 92206 this.fade.chain(this._invert, this._equalPowerA, this.a.gain); 92207 this._readOnly('fade'); 92208 }; 92209 Tone.extend(Tone.CrossFade); 92210 Tone.CrossFade.prototype.dispose = function () { 92211 Tone.prototype.dispose.call(this); 92212 this._writable('fade'); 92213 this._equalPowerA.dispose(); 92214 this._equalPowerA = null; 92215 this._equalPowerB.dispose(); 92216 this._equalPowerB = null; 92217 this.fade.dispose(); 92218 this.fade = null; 92219 this._invert.dispose(); 92220 this._invert = null; 92221 this.a.dispose(); 92222 this.a = null; 92223 this.b.dispose(); 92224 this.b = null; 92225 return this; 92226 }; 92227 return Tone.CrossFade; 92228}(Tone_core_Tone, Tone_signal_Signal, Tone_signal_Expr, Tone_signal_EqualPowerGain); 92229var effect; 92230'use strict'; 92231effect = function () { 92232 var p5sound = master; 92233 var CrossFade = Tone_component_CrossFade; 92234 /** 92235 * Effect is a base class for audio effects in p5. <br> 92236 * This module handles the nodes and methods that are 92237 * common and useful for current and future effects. 92238 * 92239 * 92240 * This class is extended by <a href="/reference/#/p5.Distortion">p5.Distortion</a>, 92241 * <a href="/reference/#/p5.Compressor">p5.Compressor</a>, 92242 * <a href="/reference/#/p5.Delay">p5.Delay</a>, 92243 * <a href="/reference/#/p5.Filter">p5.Filter</a>, 92244 * <a href="/reference/#/p5.Reverb">p5.Reverb</a>. 92245 * 92246 * @class p5.Effect 92247 * @constructor 92248 * 92249 * @param {Object} [ac] Reference to the audio context of the p5 object 92250 * @param {AudioNode} [input] Gain Node effect wrapper 92251 * @param {AudioNode} [output] Gain Node effect wrapper 92252 * @param {Object} [_drywet] Tone.JS CrossFade node (defaults to value: 1) 92253 * @param {AudioNode} [wet] Effects that extend this class should connect 92254 * to the wet signal to this gain node, so that dry and wet 92255 * signals are mixed properly. 92256 */ 92257 p5.Effect = function () { 92258 this.ac = p5sound.audiocontext; 92259 this.input = this.ac.createGain(); 92260 this.output = this.ac.createGain(); 92261 /** 92262 * The p5.Effect class is built 92263 * using Tone.js CrossFade 92264 * @private 92265 */ 92266 this._drywet = new CrossFade(1); 92267 /** 92268 * In classes that extend 92269 * p5.Effect, connect effect nodes 92270 * to the wet parameter 92271 */ 92272 this.wet = this.ac.createGain(); 92273 this.input.connect(this._drywet.a); 92274 this.wet.connect(this._drywet.b); 92275 this._drywet.connect(this.output); 92276 this.connect(); 92277 //Add to the soundArray 92278 p5sound.soundArray.push(this); 92279 }; 92280 /** 92281 * Set the output volume of the filter. 92282 * 92283 * @method amp 92284 * @param {Number} [vol] amplitude between 0 and 1.0 92285 * @param {Number} [rampTime] create a fade that lasts until rampTime 92286 * @param {Number} [tFromNow] schedule this event to happen in tFromNow seconds 92287 */ 92288 p5.Effect.prototype.amp = function (vol, rampTime, tFromNow) { 92289 var rampTime = rampTime || 0; 92290 var tFromNow = tFromNow || 0; 92291 var now = p5sound.audiocontext.currentTime; 92292 var currentVol = this.output.gain.value; 92293 this.output.gain.cancelScheduledValues(now); 92294 this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow + 0.001); 92295 this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime + 0.001); 92296 }; 92297 /** 92298 * Link effects together in a chain 92299 * Example usage: filter.chain(reverb, delay, panner); 92300 * May be used with an open-ended number of arguments 92301 * 92302 * @method chain 92303 * @param {Object} [arguments] Chain together multiple sound objects 92304 */ 92305 p5.Effect.prototype.chain = function () { 92306 if (arguments.length > 0) { 92307 this.connect(arguments[0]); 92308 for (var i = 1; i < arguments.length; i += 1) { 92309 arguments[i - 1].connect(arguments[i]); 92310 } 92311 } 92312 return this; 92313 }; 92314 /** 92315 * Adjust the dry/wet value. 92316 * 92317 * @method drywet 92318 * @param {Number} [fade] The desired drywet value (0 - 1.0) 92319 */ 92320 p5.Effect.prototype.drywet = function (fade) { 92321 if (typeof fade !== 'undefined') { 92322 this._drywet.fade.value = fade; 92323 } 92324 return this._drywet.fade.value; 92325 }; 92326 /** 92327 * Send output to a p5.js-sound, Web Audio Node, or use signal to 92328 * control an AudioParam 92329 * 92330 * @method connect 92331 * @param {Object} unit 92332 */ 92333 p5.Effect.prototype.connect = function (unit) { 92334 var u = unit || p5.soundOut.input; 92335 this.output.connect(u.input ? u.input : u); 92336 }; 92337 /** 92338 * Disconnect all output. 92339 * 92340 * @method disconnect 92341 */ 92342 p5.Effect.prototype.disconnect = function () { 92343 if (this.output) { 92344 this.output.disconnect(); 92345 } 92346 }; 92347 p5.Effect.prototype.dispose = function () { 92348 // remove refernce form soundArray 92349 var index = p5sound.soundArray.indexOf(this); 92350 p5sound.soundArray.splice(index, 1); 92351 if (this.input) { 92352 this.input.disconnect(); 92353 delete this.input; 92354 } 92355 if (this.output) { 92356 this.output.disconnect(); 92357 delete this.output; 92358 } 92359 if (this._drywet) { 92360 this._drywet.disconnect(); 92361 delete this._drywet; 92362 } 92363 if (this.wet) { 92364 this.wet.disconnect(); 92365 delete this.wet; 92366 } 92367 this.ac = undefined; 92368 };
92369 return p5.Effect; 92370}(master, Tone_component_CrossFade); 92371var filter; 92372'use strict'; 92373filter = function () { 92374 var p5sound = master; 92375 var Effect = effect; 92376 /** 92377 * <p>A p5.Filter uses a Web Audio Biquad Filter to filter 92378 * the frequency response of an input source. Subclasses 92379 * include:</p> 92380 * * <a href="/reference/#/p5.LowPass"><code>p5.LowPass</code></a>: 92381 * Allows frequencies below the cutoff frequency to pass through, 92382 * and attenuates frequencies above the cutoff.<br/> 92383 * * <a href="/reference/#/p5.HighPass"><code>p5.HighPass</code></a>: 92384 * The opposite of a lowpass filter. <br/> 92385 * * <a href="/reference/#/p5.BandPass"><code>p5.BandPass</code></a>: 92386 * Allows a range of frequencies to pass through and attenuates 92387 * the frequencies below and above this frequency range.<br/> 92388 * 92389 * The <code>.res()</code> method controls either width of the 92390 * bandpass, or resonance of the low/highpass cutoff frequency. 92391 * 92392 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 92393 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 92394 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 92395 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 92396 * 92397 * @class p5.Filter 92398 * @extends p5.Effect 92399 * @constructor 92400 * @param {String} [type] 'lowpass' (default), 'highpass', 'bandpass' 92401 * @example 92402 * <div><code> 92403 * var fft, noise, filter; 92404 * 92405 * function setup() { 92406 * fill(255, 40, 255); 92407 * 92408 * filter = new p5.BandPass(); 92409 * 92410 * noise = new p5.Noise(); 92411 * // disconnect unfiltered noise, 92412 * // and connect to filter 92413 * noise.disconnect(); 92414 * noise.connect(filter); 92415 * noise.start(); 92416 * 92417 * fft = new p5.FFT(); 92418 * } 92419 * 92420 * function draw() { 92421 * background(30); 92422 * 92423 * // set the BandPass frequency based on mouseX 92424 * var freq = map(mouseX, 0, width, 20, 10000); 92425 * filter.freq(freq); 92426 * // give the filter a narrow band (lower res = wider bandpass) 92427 * filter.res(50); 92428 * 92429 * // draw filtered spectrum 92430 * var spectrum = fft.analyze(); 92431 * noStroke(); 92432 * for (var i = 0; i < spectrum.length; i++) { 92433 * var x = map(i, 0, spectrum.length, 0, width); 92434 * var h = -height + map(spectrum[i], 0, 255, height, 0); 92435 * rect(x, height, width/spectrum.length, h); 92436 * } 92437 * 92438 * isMouseOverCanvas(); 92439 * } 92440 * 92441 * function isMouseOverCanvas() { 92442 * var mX = mouseX, mY = mouseY; 92443 * if (mX > 0 && mX < width && mY < height && mY > 0) { 92444 * noise.amp(0.5, 0.2); 92445 * } else { 92446 * noise.amp(0, 0.2); 92447 * } 92448 * } 92449 * </code></div> 92450 */ 92451 //constructor with inheritance 92452 p5.Filter = function (type) { 92453 Effect.call(this); 92454 //add extend Effect by adding a Biquad Filter 92455 /** 92456 * The p5.Filter is built with a 92457 * <a href="http://www.w3.org/TR/webaudio/#BiquadFilterNode"> 92458 * Web Audio BiquadFilter Node</a>. 92459 * 92460 * @property {DelayNode} biquadFilter 92461 */ 92462 this.biquad = this.ac.createBiquadFilter(); 92463 this.input.connect(this.biquad); 92464 this.biquad.connect(this.wet); 92465 if (type) { 92466 this.setType(type); 92467 } 92468 //Properties useful for the toggle method. 92469 this._on = true; 92470 this._untoggledType = this.biquad.type; 92471 }; 92472 p5.Filter.prototype = Object.create(Effect.prototype); 92473 /** 92474 * Filter an audio signal according to a set 92475 * of filter parameters. 92476 * 92477 * @method process 92478 * @param {Object} Signal An object that outputs audio 92479 * @param {Number} [freq] Frequency in Hz, from 10 to 22050 92480 * @param {Number} [res] Resonance/Width of the filter frequency 92481 * from 0.001 to 1000 92482 */ 92483 p5.Filter.prototype.process = function (src, freq, res, time) { 92484 src.connect(this.input); 92485 this.set(freq, res, time); 92486 }; 92487 /** 92488 * Set the frequency and the resonance of the filter. 92489 * 92490 * @method set 92491 * @param {Number} [freq] Frequency in Hz, from 10 to 22050 92492 * @param {Number} [res] Resonance (Q) from 0.001 to 1000 92493 * @param {Number} [timeFromNow] schedule this event to happen 92494 * seconds from now 92495 */ 92496 p5.Filter.prototype.set = function (freq, res, time) { 92497 if (freq) { 92498 this.freq(freq, time); 92499 } 92500 if (res) { 92501 this.res(res, time); 92502 } 92503 }; 92504 /** 92505 * Set the filter frequency, in Hz, from 10 to 22050 (the range of 92506 * human hearing, although in reality most people hear in a narrower 92507 * range). 92508 * 92509 * @method freq 92510 * @param {Number} freq Filter Frequency 92511 * @param {Number} [timeFromNow] schedule this event to happen 92512 * seconds from now 92513 * @return {Number} value Returns the current frequency value 92514 */ 92515 p5.Filter.prototype.freq = function (freq, time) { 92516 var t = time || 0; 92517 if (freq <= 0) { 92518 freq = 1; 92519 } 92520 if (typeof freq === 'number') { 92521 this.biquad.frequency.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 92522 this.biquad.frequency.exponentialRampToValueAtTime(freq, this.ac.currentTime + 0.02 + t); 92523 } else if (freq) { 92524 freq.connect(this.biquad.frequency); 92525 } 92526 return this.biquad.frequency.value; 92527 }; 92528 /** 92529 * Controls either width of a bandpass frequency, 92530 * or the resonance of a low/highpass cutoff frequency. 92531 * 92532 * @method res 92533 * @param {Number} res Resonance/Width of filter freq 92534 * from 0.001 to 1000 92535 * @param {Number} [timeFromNow] schedule this event to happen 92536 * seconds from now 92537 * @return {Number} value Returns the current res value 92538 */ 92539 p5.Filter.prototype.res = function (res, time) { 92540 var t = time || 0; 92541 if (typeof res === 'number') { 92542 this.biquad.Q.value = res; 92543 this.biquad.Q.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 92544 this.biquad.Q.linearRampToValueAtTime(res, this.ac.currentTime + 0.02 + t); 92545 } else if (res) { 92546 res.connect(this.biquad.Q); 92547 } 92548 return this.biquad.Q.value; 92549 }; 92550 /** 92551 * Controls the gain attribute of a Biquad Filter. 92552 * This is distinctly different from .amp() which is inherited from p5.Effect 92553 * .amp() controls the volume via the output gain node 92554 * p5.Filter.gain() controls the gain parameter of a Biquad Filter node. 92555 * 92556 * @method gain 92557 * @param {Number} gain 92558 * @return {Number} Returns the current or updated gain value 92559 */ 92560 p5.Filter.prototype.gain = function (gain, time) { 92561 var t = time || 0; 92562 if (typeof gain === 'number') { 92563 this.biquad.gain.value = gain; 92564 this.biquad.gain.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 92565 this.biquad.gain.linearRampToValueAtTime(gain, this.ac.currentTime + 0.02 + t); 92566 } else if (gain) { 92567 gain.connect(this.biquad.gain); 92568 } 92569 return this.biquad.gain.value; 92570 }; 92571 /** 92572 * Toggle function. Switches between the specified type and allpass 92573 * 92574 * @method toggle 92575 * @return {boolean} [Toggle value] 92576 */ 92577 p5.Filter.prototype.toggle = function () { 92578 this._on = !this._on; 92579 if (this._on === true) { 92580 this.biquad.type = this._untoggledType; 92581 } else if (this._on === false) { 92582 this.biquad.type = 'allpass'; 92583 } 92584 return this._on; 92585 }; 92586 /** 92587 * Set the type of a p5.Filter. Possible types include: 92588 * "lowpass" (default), "highpass", "bandpass", 92589 * "lowshelf", "highshelf", "peaking", "notch", 92590 * "allpass". 92591 * 92592 * @method setType 92593 * @param {String} t 92594 */ 92595 p5.Filter.prototype.setType = function (t) { 92596 this.biquad.type = t; 92597 this._untoggledType = this.biquad.type; 92598 }; 92599 p5.Filter.prototype.dispose = function () { 92600 // remove reference from soundArray 92601 Effect.prototype.dispose.apply(this); 92602 if (this.biquad) { 92603 this.biquad.disconnect(); 92604 delete this.biquad; 92605 } 92606 }; 92607 /** 92608 * Constructor: <code>new p5.LowPass()</code> Filter. 92609 * This is the same as creating a p5.Filter and then calling 92610 * its method <code>setType('lowpass')</code>. 92611 * See p5.Filter for methods. 92612 * 92613 * @class p5.LowPass 92614 * @constructor 92615 * @extends p5.Filter 92616 */ 92617 p5.LowPass = function () { 92618 p5.Filter.call(this, 'lowpass'); 92619 }; 92620 p5.LowPass.prototype = Object.create(p5.Filter.prototype); 92621 /** 92622 * Constructor: <code>new p5.HighPass()</code> Filter. 92623 * This is the same as creating a p5.Filter and then calling 92624 * its method <code>setType('highpass')</code>. 92625 * See p5.Filter for methods. 92626 * 92627 * @class p5.HighPass 92628 * @constructor 92629 * @extends p5.Filter 92630 */ 92631 p5.HighPass = function () { 92632 p5.Filter.call(this, 'highpass'); 92633 }; 92634 p5.HighPass.prototype = Object.create(p5.Filter.prototype); 92635 /** 92636 * Constructor: <code>new p5.BandPass()</code> Filter. 92637 * This is the same as creating a p5.Filter and then calling 92638 * its method <code>setType('bandpass')</code>. 92639 * See p5.Filter for methods. 92640 * 92641 * @class p5.BandPass 92642 * @constructor 92643 * @extends p5.Filter 92644 */ 92645 p5.BandPass = function () { 92646 p5.Filter.call(this, 'bandpass'); 92647 }; 92648 p5.BandPass.prototype = Object.create(p5.Filter.prototype); 92649 return p5.Filter; 92650}(master, effect); 92651var src_eqFilter; 92652'use strict'; 92653src_eqFilter = function () {
92654 var Filter = filter; 92655 var p5sound = master; 92656 /** 92657 * EQFilter extends p5.Filter with constraints 92658 * necessary for the p5.EQ 92659 * 92660 * @private 92661 */ 92662 var EQFilter = function (freq, res) { 92663 Filter.call(this, 'peaking'); 92664 this.disconnect(); 92665 this.set(freq, res); 92666 this.biquad.gain.value = 0; 92667 delete this.input; 92668 delete this.output; 92669 delete this._drywet; 92670 delete this.wet; 92671 }; 92672 EQFilter.prototype = Object.create(Filter.prototype); 92673 EQFilter.prototype.amp = function () { 92674 console.warn('`amp()` is not available for p5.EQ bands. Use `.gain()`'); 92675 }; 92676 EQFilter.prototype.drywet = function () { 92677 console.warn('`drywet()` is not available for p5.EQ bands.'); 92678 }; 92679 EQFilter.prototype.connect = function (unit) { 92680 var u = unit || p5.soundOut.input; 92681 if (this.biquad) { 92682 this.biquad.connect(u.input ? u.input : u); 92683 } else { 92684 this.output.connect(u.input ? u.input : u); 92685 } 92686 }; 92687 EQFilter.prototype.disconnect = function () { 92688 if (this.biquad) { 92689 this.biquad.disconnect(); 92690 } 92691 }; 92692 EQFilter.prototype.dispose = function () { 92693 // remove reference form soundArray 92694 var index = p5sound.soundArray.indexOf(this); 92695 p5sound.soundArray.splice(index, 1); 92696 this.disconnect(); 92697 delete this.biquad; 92698 }; 92699 return EQFilter; 92700}(filter, master); 92701var eq; 92702'use strict'; 92703eq = function () { 92704 var Effect = effect; 92705 var EQFilter = src_eqFilter; 92706 /** 92707 * p5.EQ is an audio effect that performs the function of a multiband 92708 * audio equalizer. Equalization is used to adjust the balance of 92709 * frequency compoenents of an audio signal. This process is commonly used 92710 * in sound production and recording to change the waveform before it reaches 92711 * a sound output device. EQ can also be used as an audio effect to create 92712 * interesting distortions by filtering out parts of the spectrum. p5.EQ is 92713 * built using a chain of Web Audio Biquad Filter Nodes and can be 92714 * instantiated with 3 or 8 bands. Bands can be added or removed from 92715 * the EQ by directly modifying p5.EQ.bands (the array that stores filters). 92716 * 92717 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 92718 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 92719 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 92720 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 92721 * 92722 * @class p5.EQ 92723 * @constructor 92724 * @extends p5.Effect 92725 * @param {Number} [_eqsize] Constructor will accept 3 or 8, defaults to 3 92726 * @return {Object} p5.EQ object 92727 * 92728 * @example 92729 * <div><code> 92730 * var eq; 92731 * var band_names; 92732 * var band_index; 92733 * 92734 * var soundFile, play; 92735 * 92736 * function preload() { 92737 * soundFormats('mp3', 'ogg'); 92738 * soundFile = loadSound('assets/beat'); 92739 * } 92740 * 92741 * function setup() { 92742 * eq = new p5.EQ(3); 92743 * soundFile.disconnect(); 92744 * eq.process(soundFile); 92745 * 92746 * band_names = ['lows','mids','highs']; 92747 * band_index = 0; 92748 * play = false; 92749 * textAlign(CENTER); 92750 * } 92751 * 92752 * function draw() { 92753 * background(30); 92754 * noStroke(); 92755 * fill(255); 92756 * text('click to kill',50,25); 92757 * 92758 * fill(255, 40, 255); 92759 * textSize(26); 92760 * text(band_names[band_index],50,55); 92761 * 92762 * fill(255); 92763 * textSize(9); 92764 * text('space = play/pause',50,80); 92765 * } 92766 * 92767 * //If mouse is over canvas, cycle to the next band and kill the frequency 92768 * function mouseClicked() { 92769 * for (var i = 0; i < eq.bands.length; i++) { 92770 * eq.bands[i].gain(0); 92771 * } 92772 * eq.bands[band_index].gain(-40); 92773 * if (mouseX > 0 && mouseX < width && mouseY < height && mouseY > 0) { 92774 * band_index === 2 ? band_index = 0 : band_index++; 92775 * } 92776 * } 92777 * 92778 * //use space bar to trigger play / pause 92779 * function keyPressed() { 92780 * if (key===' ') { 92781 * play = !play 92782 * play ? soundFile.loop() : soundFile.pause(); 92783 * } 92784 * } 92785 * </code></div> 92786 */ 92787 p5.EQ = function (_eqsize) { 92788 Effect.call(this); 92789 //p5.EQ can be of size (3) or (8), defaults to 3 92790 _eqsize = _eqsize === 3 || _eqsize === 8 ? _eqsize : 3; 92791 var factor; 92792 _eqsize === 3 ? factor = Math.pow(2, 3) : factor = 2; 92793 /** 92794 * The p5.EQ is built with abstracted p5.Filter objects. 92795 * To modify any bands, use methods of the <a 92796 * href="/reference/#/p5.Filter" title="p5.Filter reference"> 92797 * p5.Filter</a> API, especially `gain` and `freq`. 92798 * Bands are stored in an array, with indices 0 - 3, or 0 - 7 92799 * @property {Array} bands 92800 * 92801 */ 92802 this.bands = []; 92803 var freq, res; 92804 for (var i = 0; i < _eqsize; i++) { 92805 if (i === _eqsize - 1) { 92806 freq = 21000; 92807 res = 0.01; 92808 } else if (i === 0) { 92809 freq = 100; 92810 res = 0.1; 92811 } else if (i === 1) { 92812 freq = _eqsize === 3 ? 360 * factor : 360; 92813 res = 1; 92814 } else { 92815 freq = this.bands[i - 1].freq() * factor; 92816 res = 1; 92817 } 92818 this.bands[i] = this._newBand(freq, res); 92819 if (i > 0) { 92820 this.bands[i - 1].connect(this.bands[i].biquad); 92821 } else { 92822 this.input.connect(this.bands[i].biquad); 92823 } 92824 } 92825 this.bands[_eqsize - 1].connect(this.output); 92826 }; 92827 p5.EQ.prototype = Object.create(Effect.prototype); 92828 /** 92829 * Process an input by connecting it to the EQ 92830 * @method process 92831 * @param {Object} src Audio source 92832 */ 92833 p5.EQ.prototype.process = function (src) { 92834 src.connect(this.input); 92835 }; 92836 // /** 92837 // * Set the frequency and gain of each band in the EQ. This method should be 92838 // * called with 3 or 8 frequency and gain pairs, depending on the size of the EQ. 92839 // * ex. eq.set(freq0, gain0, freq1, gain1, freq2, gain2); 92840 // * 92841 // * @method set 92842 // * @param {Number} [freq0] Frequency value for band with index 0 92843 // * @param {Number} [gain0] Gain value for band with index 0 92844 // * @param {Number} [freq1] Frequency value for band with index 1 92845 // * @param {Number} [gain1] Gain value for band with index 1 92846 // * @param {Number} [freq2] Frequency value for band with index 2 92847 // * @param {Number} [gain2] Gain value for band with index 2 92848 // * @param {Number} [freq3] Frequency value for band with index 3 92849 // * @param {Number} [gain3] Gain value for band with index 3 92850 // * @param {Number} [freq4] Frequency value for band with index 4 92851 // * @param {Number} [gain4] Gain value for band with index 4 92852 // * @param {Number} [freq5] Frequency value for band with index 5 92853 // * @param {Number} [gain5] Gain value for band with index 5 92854 // * @param {Number} [freq6] Frequency value for band with index 6 92855 // * @param {Number} [gain6] Gain value for band with index 6 92856 // * @param {Number} [freq7] Frequency value for band with index 7 92857 // * @param {Number} [gain7] Gain value for band with index 7 92858 // */ 92859 p5.EQ.prototype.set = function () { 92860 if (arguments.length === this.bands.length * 2) { 92861 for (var i = 0; i < arguments.length; i += 2) { 92862 this.bands[i / 2].freq(arguments[i]); 92863 this.bands[i / 2].gain(arguments[i + 1]); 92864 } 92865 } else { 92866 console.error('Argument mismatch. .set() should be called with ' + this.bands.length * 2 + ' arguments. (one frequency and gain value pair for each band of the eq)'); 92867 } 92868 }; 92869 /** 92870 * Add a new band. Creates a p5.Filter and strips away everything but 92871 * the raw biquad filter. This method returns an abstracted p5.Filter, 92872 * which can be added to p5.EQ.bands, in order to create new EQ bands. 92873 * @private 92874 * @method _newBand 92875 * @param {Number} freq 92876 * @param {Number} res 92877 * @return {Object} Abstracted Filter 92878 */ 92879 p5.EQ.prototype._newBand = function (freq, res) { 92880 return new EQFilter(freq, res); 92881 }; 92882 p5.EQ.prototype.dispose = function () { 92883 Effect.prototype.dispose.apply(this); 92884 if (this.bands) { 92885 while (this.bands.length > 0) { 92886 delete this.bands.pop().dispose(); 92887 } 92888 delete this.bands; 92889 } 92890 }; 92891 return p5.EQ; 92892}(effect, src_eqFilter); 92893var panner3d; 92894'use strict'; 92895panner3d = function () { 92896 var p5sound = master; 92897 var Effect = effect; 92898 /** 92899 * Panner3D is based on the <a title="Web Audio Panner docs" href= 92900 * "https://developer.mozilla.org/en-US/docs/Web/API/PannerNode"> 92901 * Web Audio Spatial Panner Node</a>. 92902 * This panner is a spatial processing node that allows audio to be positioned 92903 * and oriented in 3D space. 92904 * 92905 * The position is relative to an <a title="Web Audio Listener docs" href= 92906 * "https://developer.mozilla.org/en-US/docs/Web/API/AudioListener"> 92907 * Audio Context Listener</a>, which can be accessed 92908 * by <code>p5.soundOut.audiocontext.listener</code> 92909 * 92910 * 92911 * @class p5.Panner3D 92912 * @constructor 92913 */ 92914 p5.Panner3D = function () { 92915 Effect.call(this); 92916 /** 92917 * <a title="Web Audio Panner docs" href= 92918 * "https://developer.mozilla.org/en-US/docs/Web/API/PannerNode"> 92919 * Web Audio Spatial Panner Node</a> 92920 * 92921 * Properties include 92922 * - <a title="w3 spec for Panning Model" 92923 * href="https://www.w3.org/TR/webaudio/#idl-def-PanningModelType" 92924 * >panningModel</a>: "equal power" or "HRTF" 92925 * - <a title="w3 spec for Distance Model" 92926 * href="https://www.w3.org/TR/webaudio/#idl-def-DistanceModelType" 92927 * >distanceModel</a>: "linear", "inverse", or "exponential" 92928 * 92929 * @property {AudioNode} panner 92930 * 92931 */ 92932 this.panner = this.ac.createPanner(); 92933 this.panner.panningModel = 'HRTF'; 92934 this.panner.distanceModel = 'linear'; 92935 this.panner.connect(this.output); 92936 this.input.connect(this.panner); 92937 }; 92938 p5.Panner3D.prototype = Object.create(Effect.prototype); 92939 /** 92940 * Connect an audio sorce 92941 * 92942 * @method process 92943 * @param {Object} src Input source 92944 */ 92945 p5.Panner3D.prototype.process = function (src) { 92946 src.connect(this.input); 92947 }; 92948 /** 92949 * Set the X,Y,Z position of the Panner 92950 * @method set 92951 * @param {Number} xVal 92952 * @param {Number} yVal 92953 * @param {Number} zVal 92954 * @param {Number} time 92955 * @return {Array} Updated x, y, z values as an array 92956 */ 92957 p5.Panner3D.prototype.set = function (xVal, yVal, zVal, time) { 92958 this.positionX(xVal, time); 92959 this.positionY(yVal, time); 92960 this.positionZ(zVal, time); 92961 return [ 92962 this.panner.positionX.value, 92963 this.panner.positionY.value, 92964 this.panner.positionZ.value 92965 ]; 92966 }; 92967 /** 92968 * Getter and setter methods for position coordinates 92969 * @method positionX 92970 * @return {Number} updated coordinate value 92971 */ 92972 /** 92973 * Getter and setter methods for position coordinates 92974 * @method positionY 92975 * @return {Number} updated coordinate value 92976 */ 92977 /** 92978 * Getter and setter methods for position coordinates 92979 * @method positionZ 92980 * @return {Number} updated coordinate value 92981 */ 92982 p5.Panner3D.prototype.positionX = function (xVal, time) { 92983 var t = time || 0; 92984 if (typeof xVal === 'number') { 92985 this.panner.positionX.value = xVal; 92986 this.panner.positionX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 92987 this.panner.positionX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 92988 } else if (xVal) { 92989 xVal.connect(this.panner.positionX); 92990 } 92991 return this.panner.positionX.value; 92992 }; 92993 p5.Panner3D.prototype.positionY = function (yVal, time) { 92994 var t = time || 0; 92995 if (typeof yVal === 'number') { 92996 this.panner.positionY.value = yVal; 92997 this.panner.positionY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 92998 this.panner.positionY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 92999 } else if (yVal) { 93000 yVal.connect(this.panner.positionY); 93001 } 93002 return this.panner.positionY.value; 93003 }; 93004 p5.Panner3D.prototype.positionZ = function (zVal, time) { 93005 var t = time || 0; 93006 if (typeof zVal === 'number') { 93007 this.panner.positionZ.value = zVal; 93008 this.panner.positionZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93009 this.panner.positionZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 93010 } else if (zVal) {
93011 zVal.connect(this.panner.positionZ); 93012 } 93013 return this.panner.positionZ.value; 93014 }; 93015 /** 93016 * Set the X,Y,Z position of the Panner 93017 * @method orient 93018 * @param {Number} xVal 93019 * @param {Number} yVal 93020 * @param {Number} zVal 93021 * @param {Number} time 93022 * @return {Array} Updated x, y, z values as an array 93023 */ 93024 p5.Panner3D.prototype.orient = function (xVal, yVal, zVal, time) { 93025 this.orientX(xVal, time); 93026 this.orientY(yVal, time); 93027 this.orientZ(zVal, time); 93028 return [ 93029 this.panner.orientationX.value, 93030 this.panner.orientationY.value, 93031 this.panner.orientationZ.value 93032 ]; 93033 }; 93034 /** 93035 * Getter and setter methods for orient coordinates 93036 * @method orientX 93037 * @return {Number} updated coordinate value 93038 */ 93039 /** 93040 * Getter and setter methods for orient coordinates 93041 * @method orientY 93042 * @return {Number} updated coordinate value 93043 */ 93044 /** 93045 * Getter and setter methods for orient coordinates 93046 * @method orientZ 93047 * @return {Number} updated coordinate value 93048 */ 93049 p5.Panner3D.prototype.orientX = function (xVal, time) { 93050 var t = time || 0; 93051 if (typeof xVal === 'number') { 93052 this.panner.orientationX.value = xVal; 93053 this.panner.orientationX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93054 this.panner.orientationX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 93055 } else if (xVal) { 93056 xVal.connect(this.panner.orientationX); 93057 } 93058 return this.panner.orientationX.value; 93059 }; 93060 p5.Panner3D.prototype.orientY = function (yVal, time) { 93061 var t = time || 0; 93062 if (typeof yVal === 'number') { 93063 this.panner.orientationY.value = yVal; 93064 this.panner.orientationY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93065 this.panner.orientationY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 93066 } else if (yVal) { 93067 yVal.connect(this.panner.orientationY); 93068 } 93069 return this.panner.orientationY.value; 93070 }; 93071 p5.Panner3D.prototype.orientZ = function (zVal, time) { 93072 var t = time || 0; 93073 if (typeof zVal === 'number') { 93074 this.panner.orientationZ.value = zVal; 93075 this.panner.orientationZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93076 this.panner.orientationZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 93077 } else if (zVal) { 93078 zVal.connect(this.panner.orientationZ); 93079 } 93080 return this.panner.orientationZ.value; 93081 }; 93082 /** 93083 * Set the rolloff factor and max distance 93084 * @method setFalloff 93085 * @param {Number} [maxDistance] 93086 * @param {Number} [rolloffFactor] 93087 */ 93088 p5.Panner3D.prototype.setFalloff = function (maxDistance, rolloffFactor) { 93089 this.maxDist(maxDistance); 93090 this.rolloff(rolloffFactor); 93091 }; 93092 /** 93093 * Maxium distance between the source and the listener 93094 * @method maxDist 93095 * @param {Number} maxDistance 93096 * @return {Number} updated value 93097 */ 93098 p5.Panner3D.prototype.maxDist = function (maxDistance) { 93099 if (typeof maxDistance === 'number') { 93100 this.panner.maxDistance = maxDistance; 93101 } 93102 return this.panner.maxDistance; 93103 }; 93104 /** 93105 * How quickly the volume is reduced as the source moves away from the listener 93106 * @method rollof 93107 * @param {Number} rolloffFactor 93108 * @return {Number} updated value 93109 */ 93110 p5.Panner3D.prototype.rolloff = function (rolloffFactor) { 93111 if (typeof rolloffFactor === 'number') { 93112 this.panner.rolloffFactor = rolloffFactor; 93113 } 93114 return this.panner.rolloffFactor; 93115 }; 93116 p5.Panner3D.dispose = function () { 93117 Effect.prototype.dispose.apply(this); 93118 if (this.panner) { 93119 this.panner.disconnect(); 93120 delete this.panner; 93121 } 93122 }; 93123 return p5.Panner3D; 93124}(master, effect); 93125var listener3d; 93126'use strict'; 93127listener3d = function () { 93128 var p5sound = master; 93129 var Effect = effect; 93130 // /** 93131 // * listener is a class that can construct both a Spatial Panner 93132 // * and a Spatial Listener. The panner is based on the 93133 // * Web Audio Spatial Panner Node 93134 // * https://www.w3.org/TR/webaudio/#the-listenernode-interface 93135 // * This panner is a spatial processing node that allows audio to be positioned 93136 // * and oriented in 3D space. 93137 // * 93138 // * The Listener modifies the properties of the Audio Context Listener. 93139 // * Both objects types use the same methods. The default is a spatial panner. 93140 // * 93141 // * <code>p5.Panner3D</code> - Constructs a Spatial Panner<br/> 93142 // * <code>p5.Listener3D</code> - Constructs a Spatial Listener<br/> 93143 // * 93144 // * @class listener 93145 // * @constructor 93146 // * @return {Object} p5.Listener3D Object 93147 // * 93148 // * @param {Web Audio Node} listener Web Audio Spatial Panning Node 93149 // * @param {AudioParam} listener.panningModel "equal power" or "HRTF" 93150 // * @param {AudioParam} listener.distanceModel "linear", "inverse", or "exponential" 93151 // * @param {String} [type] [Specify construction of a spatial panner or listener] 93152 // */ 93153 p5.Listener3D = function (type) { 93154 this.ac = p5sound.audiocontext; 93155 this.listener = this.ac.listener; 93156 }; 93157 // /** 93158 // * Connect an audio sorce 93159 // * @param {Object} src Input source 93160 // */ 93161 p5.Listener3D.prototype.process = function (src) { 93162 src.connect(this.input); 93163 }; 93164 // /** 93165 // * Set the X,Y,Z position of the Panner 93166 // * @param {[Number]} xVal 93167 // * @param {[Number]} yVal 93168 // * @param {[Number]} zVal 93169 // * @param {[Number]} time 93170 // * @return {[Array]} [Updated x, y, z values as an array] 93171 // */ 93172 p5.Listener3D.prototype.position = function (xVal, yVal, zVal, time) { 93173 this.positionX(xVal, time); 93174 this.positionY(yVal, time); 93175 this.positionZ(zVal, time); 93176 return [ 93177 this.listener.positionX.value, 93178 this.listener.positionY.value, 93179 this.listener.positionZ.value 93180 ]; 93181 }; 93182 // /** 93183 // * Getter and setter methods for position coordinates 93184 // * @return {Number} [updated coordinate value] 93185 // */ 93186 p5.Listener3D.prototype.positionX = function (xVal, time) { 93187 var t = time || 0; 93188 if (typeof xVal === 'number') { 93189 this.listener.positionX.value = xVal; 93190 this.listener.positionX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93191 this.listener.positionX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 93192 } else if (xVal) { 93193 xVal.connect(this.listener.positionX); 93194 } 93195 return this.listener.positionX.value; 93196 }; 93197 p5.Listener3D.prototype.positionY = function (yVal, time) { 93198 var t = time || 0; 93199 if (typeof yVal === 'number') { 93200 this.listener.positionY.value = yVal; 93201 this.listener.positionY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93202 this.listener.positionY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 93203 } else if (yVal) { 93204 yVal.connect(this.listener.positionY); 93205 } 93206 return this.listener.positionY.value; 93207 }; 93208 p5.Listener3D.prototype.positionZ = function (zVal, time) { 93209 var t = time || 0; 93210 if (typeof zVal === 'number') { 93211 this.listener.positionZ.value = zVal; 93212 this.listener.positionZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93213 this.listener.positionZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 93214 } else if (zVal) {
93215 zVal.connect(this.listener.positionZ); 93216 } 93217 return this.listener.positionZ.value; 93218 }; 93219 // cannot define method when class definition is commented 93220 // /** 93221 // * Overrides the listener orient() method because Listener has slightly 93222 // * different params. In human terms, Forward vectors are the direction the 93223 // * nose is pointing. Up vectors are the direction of the top of the head. 93224 // * 93225 // * @method orient 93226 // * @param {Number} xValF Forward vector X direction 93227 // * @param {Number} yValF Forward vector Y direction 93228 // * @param {Number} zValF Forward vector Z direction 93229 // * @param {Number} xValU Up vector X direction 93230 // * @param {Number} yValU Up vector Y direction 93231 // * @param {Number} zValU Up vector Z direction 93232 // * @param {Number} time 93233 // * @return {Array} All orienation params 93234 // */ 93235 p5.Listener3D.prototype.orient = function (xValF, yValF, zValF, xValU, yValU, zValU, time) { 93236 if (arguments.length === 3 || arguments.length === 4) { 93237 time = arguments[3]; 93238 this.orientForward(xValF, yValF, zValF, time); 93239 } else if (arguments.length === 6 || arguments === 7) { 93240 this.orientForward(xValF, yValF, zValF); 93241 this.orientUp(xValU, yValU, zValU, time); 93242 } 93243 return [ 93244 this.listener.forwardX.value, 93245 this.listener.forwardY.value, 93246 this.listener.forwardZ.value, 93247 this.listener.upX.value, 93248 this.listener.upY.value, 93249 this.listener.upZ.value 93250 ]; 93251 }; 93252 p5.Listener3D.prototype.orientForward = function (xValF, yValF, zValF, time) { 93253 this.forwardX(xValF, time); 93254 this.forwardY(yValF, time); 93255 this.forwardZ(zValF, time); 93256 return [ 93257 this.listener.forwardX, 93258 this.listener.forwardY, 93259 this.listener.forwardZ 93260 ]; 93261 }; 93262 p5.Listener3D.prototype.orientUp = function (xValU, yValU, zValU, time) { 93263 this.upX(xValU, time); 93264 this.upY(yValU, time); 93265 this.upZ(zValU, time); 93266 return [ 93267 this.listener.upX, 93268 this.listener.upY, 93269 this.listener.upZ 93270 ]; 93271 }; 93272 // /** 93273 // * Getter and setter methods for orient coordinates 93274 // * @return {Number} [updated coordinate value] 93275 // */ 93276 p5.Listener3D.prototype.forwardX = function (xVal, time) { 93277 var t = time || 0; 93278 if (typeof xVal === 'number') { 93279 this.listener.forwardX.value = xVal; 93280 this.listener.forwardX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93281 this.listener.forwardX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 93282 } else if (xVal) { 93283 xVal.connect(this.listener.forwardX); 93284 } 93285 return this.listener.forwardX.value; 93286 }; 93287 p5.Listener3D.prototype.forwardY = function (yVal, time) { 93288 var t = time || 0; 93289 if (typeof yVal === 'number') { 93290 this.listener.forwardY.value = yVal; 93291 this.listener.forwardY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93292 this.listener.forwardY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 93293 } else if (yVal) { 93294 yVal.connect(this.listener.forwardY); 93295 } 93296 return this.listener.forwardY.value; 93297 }; 93298 p5.Listener3D.prototype.forwardZ = function (zVal, time) { 93299 var t = time || 0; 93300 if (typeof zVal === 'number') { 93301 this.listener.forwardZ.value = zVal; 93302 this.listener.forwardZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93303 this.listener.forwardZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 93304 } else if (zVal) { 93305 zVal.connect(this.listener.forwardZ); 93306 } 93307 return this.listener.forwardZ.value; 93308 }; 93309 p5.Listener3D.prototype.upX = function (xVal, time) { 93310 var t = time || 0; 93311 if (typeof xVal === 'number') { 93312 this.listener.upX.value = xVal; 93313 this.listener.upX.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93314 this.listener.upX.linearRampToValueAtTime(xVal, this.ac.currentTime + 0.02 + t); 93315 } else if (xVal) { 93316 xVal.connect(this.listener.upX); 93317 } 93318 return this.listener.upX.value; 93319 }; 93320 p5.Listener3D.prototype.upY = function (yVal, time) { 93321 var t = time || 0; 93322 if (typeof yVal === 'number') { 93323 this.listener.upY.value = yVal; 93324 this.listener.upY.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93325 this.listener.upY.linearRampToValueAtTime(yVal, this.ac.currentTime + 0.02 + t); 93326 } else if (yVal) { 93327 yVal.connect(this.listener.upY); 93328 } 93329 return this.listener.upY.value; 93330 }; 93331 p5.Listener3D.prototype.upZ = function (zVal, time) { 93332 var t = time || 0; 93333 if (typeof zVal === 'number') { 93334 this.listener.upZ.value = zVal;
93335 this.listener.upZ.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 93336 this.listener.upZ.linearRampToValueAtTime(zVal, this.ac.currentTime + 0.02 + t); 93337 } else if (zVal) { 93338 zVal.connect(this.listener.upZ); 93339 } 93340 return this.listener.upZ.value; 93341 }; 93342 return p5.Listener3D; 93343}(master, effect); 93344var delay; 93345'use strict'; 93346delay = function () { 93347 var Filter = filter; 93348 var Effect = effect; 93349 /** 93350 * Delay is an echo effect. It processes an existing sound source, 93351 * and outputs a delayed version of that sound. The p5.Delay can 93352 * produce different effects depending on the delayTime, feedback, 93353 * filter, and type. In the example below, a feedback of 0.5 (the 93354 * defaul value) will produce a looping delay that decreases in 93355 * volume by 50% each repeat. A filter will cut out the high 93356 * frequencies so that the delay does not sound as piercing as the 93357 * original source. 93358 * 93359 * 93360 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 93361 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 93362 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 93363 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 93364 * @class p5.Delay 93365 * @extends p5.Effect 93366 * @constructor 93367 * @example 93368 * <div><code> 93369 * var noise, env, delay; 93370 * 93371 * function setup() { 93372 * background(0); 93373 * noStroke(); 93374 * fill(255); 93375 * textAlign(CENTER); 93376 * text('click to play', width/2, height/2); 93377 * 93378 * noise = new p5.Noise('brown'); 93379 * noise.amp(0); 93380 * noise.start(); 93381 * 93382 * delay = new p5.Delay(); 93383 * 93384 * // delay.process() accepts 4 parameters: 93385 * // source, delayTime, feedback, filter frequency 93386 * // play with these numbers!! 93387 * delay.process(noise, .12, .7, 2300); 93388 * 93389 * // play the noise with an envelope, 93390 * // a series of fades ( time / value pairs ) 93391 * env = new p5.Envelope(.01, 0.2, .2, .1); 93392 * } 93393 * 93394 * // mouseClick triggers envelope 93395 * function mouseClicked() { 93396 * // is mouse over canvas? 93397 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 93398 * env.play(noise); 93399 * } 93400 * } 93401 * </code></div> 93402 */ 93403 p5.Delay = function () { 93404 Effect.call(this); 93405 this._split = this.ac.createChannelSplitter(2); 93406 this._merge = this.ac.createChannelMerger(2); 93407 this._leftGain = this.ac.createGain(); 93408 this._rightGain = this.ac.createGain(); 93409 /** 93410 * The p5.Delay is built with two 93411 * <a href="http://www.w3.org/TR/webaudio/#DelayNode"> 93412 * Web Audio Delay Nodes</a>, one for each stereo channel. 93413 * 93414 * @property {DelayNode} leftDelay 93415 */ 93416 this.leftDelay = this.ac.createDelay(); 93417 /** 93418 * The p5.Delay is built with two 93419 * <a href="http://www.w3.org/TR/webaudio/#DelayNode"> 93420 * Web Audio Delay Nodes</a>, one for each stereo channel. 93421 * 93422 * @property {DelayNode} rightDelay 93423 */ 93424 this.rightDelay = this.ac.createDelay(); 93425 this._leftFilter = new Filter(); 93426 this._rightFilter = new Filter(); 93427 this._leftFilter.disconnect(); 93428 this._rightFilter.disconnect(); 93429 this._leftFilter.biquad.frequency.setValueAtTime(1200, this.ac.currentTime); 93430 this._rightFilter.biquad.frequency.setValueAtTime(1200, this.ac.currentTime); 93431 this._leftFilter.biquad.Q.setValueAtTime(0.3, this.ac.currentTime); 93432 this._rightFilter.biquad.Q.setValueAtTime(0.3, this.ac.currentTime); 93433 // graph routing 93434 this.input.connect(this._split); 93435 this.leftDelay.connect(this._leftGain); 93436 this.rightDelay.connect(this._rightGain); 93437 this._leftGain.connect(this._leftFilter.input); 93438 this._rightGain.connect(this._rightFilter.input); 93439 this._merge.connect(this.wet); 93440 this._leftFilter.biquad.gain.setValueAtTime(1, this.ac.currentTime); 93441 this._rightFilter.biquad.gain.setValueAtTime(1, this.ac.currentTime); 93442 // default routing 93443 this.setType(0); 93444 this._maxDelay = this.leftDelay.delayTime.maxValue; 93445 // set initial feedback to 0.5 93446 this.feedback(0.5); 93447 }; 93448 p5.Delay.prototype = Object.create(Effect.prototype); 93449 /** 93450 * Add delay to an audio signal according to a set 93451 * of delay parameters. 93452 * 93453 * @method process 93454 * @param {Object} Signal An object that outputs audio 93455 * @param {Number} [delayTime] Time (in seconds) of the delay/echo. 93456 * Some browsers limit delayTime to 93457 * 1 second. 93458 * @param {Number} [feedback] sends the delay back through itself 93459 * in a loop that decreases in volume 93460 * each time. 93461 * @param {Number} [lowPass] Cutoff frequency. Only frequencies 93462 * below the lowPass will be part of the 93463 * delay. 93464 */ 93465 p5.Delay.prototype.process = function (src, _delayTime, _feedback, _filter) { 93466 var feedback = _feedback || 0; 93467 var delayTime = _delayTime || 0; 93468 if (feedback >= 1) { 93469 throw new Error('Feedback value will force a positive feedback loop.'); 93470 } 93471 if (delayTime >= this._maxDelay) { 93472 throw new Error('Delay Time exceeds maximum delay time of ' + this._maxDelay + ' second.'); 93473 } 93474 src.connect(this.input); 93475 this.leftDelay.delayTime.setValueAtTime(delayTime, this.ac.currentTime); 93476 this.rightDelay.delayTime.setValueAtTime(delayTime, this.ac.currentTime); 93477 this._leftGain.gain.value = feedback; 93478 this._rightGain.gain.value = feedback; 93479 if (_filter) { 93480 this._leftFilter.freq(_filter); 93481 this._rightFilter.freq(_filter); 93482 } 93483 }; 93484 /** 93485 * Set the delay (echo) time, in seconds. Usually this value will be 93486 * a floating point number between 0.0 and 1.0. 93487 * 93488 * @method delayTime 93489 * @param {Number} delayTime Time (in seconds) of the delay 93490 */ 93491 p5.Delay.prototype.delayTime = function (t) {
93492 // if t is an audio node... 93493 if (typeof t !== 'number') { 93494 t.connect(this.leftDelay.delayTime); 93495 t.connect(this.rightDelay.delayTime); 93496 } else { 93497 this.leftDelay.delayTime.cancelScheduledValues(this.ac.currentTime); 93498 this.rightDelay.delayTime.cancelScheduledValues(this.ac.currentTime); 93499 this.leftDelay.delayTime.linearRampToValueAtTime(t, this.ac.currentTime); 93500 this.rightDelay.delayTime.linearRampToValueAtTime(t, this.ac.currentTime); 93501 } 93502 }; 93503 /** 93504 * Feedback occurs when Delay sends its signal back through its input 93505 * in a loop. The feedback amount determines how much signal to send each 93506 * time through the loop. A feedback greater than 1.0 is not desirable because 93507 * it will increase the overall output each time through the loop, 93508 * creating an infinite feedback loop. The default value is 0.5 93509 * 93510 * @method feedback 93511 * @param {Number|Object} feedback 0.0 to 1.0, or an object such as an 93512 * Oscillator that can be used to 93513 * modulate this param 93514 * @returns {Number} Feedback value 93515 * 93516 */ 93517 p5.Delay.prototype.feedback = function (f) { 93518 // if f is an audio node... 93519 if (f && typeof f !== 'number') { 93520 f.connect(this._leftGain.gain); 93521 f.connect(this._rightGain.gain); 93522 } else if (f >= 1) { 93523 throw new Error('Feedback value will force a positive feedback loop.'); 93524 } else if (typeof f === 'number') { 93525 this._leftGain.gain.value = f; 93526 this._rightGain.gain.value = f; 93527 } 93528 // return value of feedback 93529 return this._leftGain.gain.value; 93530 }; 93531 /** 93532 * Set a lowpass filter frequency for the delay. A lowpass filter 93533 * will cut off any frequencies higher than the filter frequency. 93534 * 93535 * @method filter 93536 * @param {Number|Object} cutoffFreq A lowpass filter will cut off any 93537 * frequencies higher than the filter frequency. 93538 * @param {Number|Object} res Resonance of the filter frequency 93539 * cutoff, or an object (i.e. a p5.Oscillator) 93540 * that can be used to modulate this parameter. 93541 * High numbers (i.e. 15) will produce a resonance, 93542 * low numbers (i.e. .2) will produce a slope. 93543 */ 93544 p5.Delay.prototype.filter = function (freq, q) { 93545 this._leftFilter.set(freq, q); 93546 this._rightFilter.set(freq, q); 93547 }; 93548 /** 93549 * Choose a preset type of delay. 'pingPong' bounces the signal 93550 * from the left to the right channel to produce a stereo effect. 93551 * Any other parameter will revert to the default delay setting. 93552 * 93553 * @method setType 93554 * @param {String|Number} type 'pingPong' (1) or 'default' (0) 93555 */ 93556 p5.Delay.prototype.setType = function (t) { 93557 if (t === 1) { 93558 t = 'pingPong'; 93559 } 93560 this._split.disconnect(); 93561 this._leftFilter.disconnect(); 93562 this._rightFilter.disconnect(); 93563 this._split.connect(this.leftDelay, 0); 93564 this._split.connect(this.rightDelay, 1); 93565 switch (t) { 93566 case 'pingPong': 93567 this._rightFilter.setType(this._leftFilter.biquad.type); 93568 this._leftFilter.output.connect(this._merge, 0, 0); 93569 this._rightFilter.output.connect(this._merge, 0, 1); 93570 this._leftFilter.output.connect(this.rightDelay); 93571 this._rightFilter.output.connect(this.leftDelay); 93572 break; 93573 default: 93574 this._leftFilter.output.connect(this._merge, 0, 0); 93575 this._rightFilter.output.connect(this._merge, 0, 1); 93576 this._leftFilter.output.connect(this.leftDelay); 93577 this._rightFilter.output.connect(this.rightDelay); 93578 } 93579 }; 93580 // DocBlocks for methods inherited from p5.Effect 93581 /** 93582 * Set the output level of the delay effect. 93583 * 93584 * @method amp 93585 * @param {Number} volume amplitude between 0 and 1.0 93586 * @param {Number} [rampTime] create a fade that lasts rampTime 93587 * @param {Number} [timeFromNow] schedule this event to happen 93588 * seconds from now 93589 */ 93590 /** 93591 * Send output to a p5.sound or web audio object 93592 * 93593 * @method connect 93594 * @param {Object} unit 93595 */ 93596 /** 93597 * Disconnect all output. 93598 * 93599 * @method disconnect 93600 */ 93601 p5.Delay.prototype.dispose = function () { 93602 Effect.prototype.dispose.apply(this); 93603 this._split.disconnect(); 93604 this._leftFilter.dispose(); 93605 this._rightFilter.dispose(); 93606 this._merge.disconnect(); 93607 this._leftGain.disconnect(); 93608 this._rightGain.disconnect(); 93609 this.leftDelay.disconnect(); 93610 this.rightDelay.disconnect(); 93611 this._split = undefined; 93612 this._leftFilter = undefined; 93613 this._rightFilter = undefined; 93614 this._merge = undefined; 93615 this._leftGain = undefined; 93616 this._rightGain = undefined; 93617 this.leftDelay = undefined; 93618 this.rightDelay = undefined; 93619 }; 93620}(filter, effect); 93621var reverb; 93622'use strict'; 93623reverb = function () { 93624 var CustomError = errorHandler; 93625 var Effect = effect; 93626 /** 93627 * Reverb adds depth to a sound through a large number of decaying 93628 * echoes. It creates the perception that sound is occurring in a 93629 * physical space. The p5.Reverb has paramters for Time (how long does the 93630 * reverb last) and decayRate (how much the sound decays with each echo) 93631 * that can be set with the .set() or .process() methods. The p5.Convolver 93632 * extends p5.Reverb allowing you to recreate the sound of actual physical 93633 * spaces through convolution. 93634 * 93635 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 93636 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 93637 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 93638 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 93639 * 93640 * @class p5.Reverb
93641 * @extends p5.Effect 93642 * @constructor 93643 * @example 93644 * <div><code> 93645 * var soundFile, reverb; 93646 * function preload() { 93647 * soundFile = loadSound('assets/Damscray_DancingTiger.mp3'); 93648 * } 93649 * 93650 * function setup() { 93651 * reverb = new p5.Reverb(); 93652 * soundFile.disconnect(); // so we'll only hear reverb... 93653 * 93654 * // connect soundFile to reverb, process w/ 93655 * // 3 second reverbTime, decayRate of 2% 93656 * reverb.process(soundFile, 3, 2); 93657 * soundFile.play(); 93658 * } 93659 * </code></div> 93660 */ 93661 p5.Reverb = function () { 93662 Effect.call(this); 93663 this._initConvolverNode(); 93664 // otherwise, Safari distorts 93665 this.input.gain.value = 0.5; 93666 // default params 93667 this._seconds = 3; 93668 this._decay = 2; 93669 this._reverse = false; 93670 this._buildImpulse(); 93671 }; 93672 p5.Reverb.prototype = Object.create(Effect.prototype); 93673 p5.Reverb.prototype._initConvolverNode = function () { 93674 this.convolverNode = this.ac.createConvolver(); 93675 this.input.connect(this.convolverNode); 93676 this.convolverNode.connect(this.wet); 93677 }; 93678 p5.Reverb.prototype._teardownConvolverNode = function () { 93679 if (this.convolverNode) { 93680 this.convolverNode.disconnect(); 93681 delete this.convolverNode; 93682 } 93683 }; 93684 p5.Reverb.prototype._setBuffer = function (audioBuffer) { 93685 this._teardownConvolverNode(); 93686 this._initConvolverNode(); 93687 this.convolverNode.buffer = audioBuffer; 93688 }; 93689 /** 93690 * Connect a source to the reverb, and assign reverb parameters. 93691 * 93692 * @method process 93693 * @param {Object} src p5.sound / Web Audio object with a sound 93694 * output. 93695 * @param {Number} [seconds] Duration of the reverb, in seconds. 93696 * Min: 0, Max: 10. Defaults to 3. 93697 * @param {Number} [decayRate] Percentage of decay with each echo. 93698 * Min: 0, Max: 100. Defaults to 2. 93699 * @param {Boolean} [reverse] Play the reverb backwards or forwards. 93700 */ 93701 p5.Reverb.prototype.process = function (src, seconds, decayRate, reverse) { 93702 src.connect(this.input); 93703 var rebuild = false; 93704 if (seconds) { 93705 this._seconds = seconds; 93706 rebuild = true; 93707 } 93708 if (decayRate) { 93709 this._decay = decayRate; 93710 } 93711 if (reverse) { 93712 this._reverse = reverse; 93713 } 93714 if (rebuild) { 93715 this._buildImpulse(); 93716 } 93717 }; 93718 /** 93719 * Set the reverb settings. Similar to .process(), but without 93720 * assigning a new input. 93721 * 93722 * @method set 93723 * @param {Number} [seconds] Duration of the reverb, in seconds. 93724 * Min: 0, Max: 10. Defaults to 3. 93725 * @param {Number} [decayRate] Percentage of decay with each echo. 93726 * Min: 0, Max: 100. Defaults to 2. 93727 * @param {Boolean} [reverse] Play the reverb backwards or forwards. 93728 */ 93729 p5.Reverb.prototype.set = function (seconds, decayRate, reverse) { 93730 var rebuild = false; 93731 if (seconds) { 93732 this._seconds = seconds; 93733 rebuild = true; 93734 } 93735 if (decayRate) { 93736 this._decay = decayRate; 93737 } 93738 if (reverse) { 93739 this._reverse = reverse; 93740 } 93741 if (rebuild) { 93742 this._buildImpulse(); 93743 } 93744 }; 93745 // DocBlocks for methods inherited from p5.Effect 93746 /** 93747 * Set the output level of the reverb effect. 93748 * 93749 * @method amp 93750 * @param {Number} volume amplitude between 0 and 1.0 93751 * @param {Number} [rampTime] create a fade that lasts rampTime 93752 * @param {Number} [timeFromNow] schedule this event to happen 93753 * seconds from now 93754 */ 93755 /** 93756 * Send output to a p5.sound or web audio object 93757 * 93758 * @method connect 93759 * @param {Object} unit 93760 */ 93761 /** 93762 * Disconnect all output. 93763 * 93764 * @method disconnect 93765 */ 93766 /** 93767 * Inspired by Simple Reverb by Jordan Santell 93768 * https://github.com/web-audio-components/simple-reverb/blob/master/index.js 93769 * 93770 * Utility function for building an impulse response 93771 * based on the module parameters. 93772 * 93773 * @private 93774 */ 93775 p5.Reverb.prototype._buildImpulse = function () { 93776 var rate = this.ac.sampleRate; 93777 var length = rate * this._seconds; 93778 var decay = this._decay; 93779 var impulse = this.ac.createBuffer(2, length, rate); 93780 var impulseL = impulse.getChannelData(0); 93781 var impulseR = impulse.getChannelData(1); 93782 var n, i; 93783 for (i = 0; i < length; i++) { 93784 n = this._reverse ? length - i : i; 93785 impulseL[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, decay); 93786 impulseR[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, decay); 93787 } 93788 this._setBuffer(impulse); 93789 }; 93790 p5.Reverb.prototype.dispose = function () { 93791 Effect.prototype.dispose.apply(this); 93792 this._teardownConvolverNode(); 93793 }; 93794 // ======================================================================= 93795 // *** p5.Convolver *** 93796 // ======================================================================= 93797 /** 93798 * <p>p5.Convolver extends p5.Reverb. It can emulate the sound of real 93799 * physical spaces through a process called <a href=" 93800 * https://en.wikipedia.org/wiki/Convolution_reverb#Real_space_simulation"> 93801 * convolution</a>.</p> 93802 * 93803 * <p>Convolution multiplies any audio input by an "impulse response" 93804 * to simulate the dispersion of sound over time. The impulse response is 93805 * generated from an audio file that you provide. One way to 93806 * generate an impulse response is to pop a balloon in a reverberant space 93807 * and record the echo. Convolution can also be used to experiment with 93808 * sound.</p> 93809 * 93810 * <p>Use the method <code>createConvolution(path)</code> to instantiate a 93811 * p5.Convolver with a path to your impulse response audio file.</p> 93812 * 93813 * @class p5.Convolver
93814 * @extends p5.Effect 93815 * @constructor 93816 * @param {String} path path to a sound file 93817 * @param {Function} [callback] function to call when loading succeeds 93818 * @param {Function} [errorCallback] function to call if loading fails. 93819 * This function will receive an error or 93820 * XMLHttpRequest object with information 93821 * about what went wrong. 93822 * @example 93823 * <div><code> 93824 * var cVerb, sound; 93825 * function preload() { 93826 * // We have both MP3 and OGG versions of all sound assets 93827 * soundFormats('ogg', 'mp3'); 93828 * 93829 * // Try replacing 'bx-spring' with other soundfiles like 93830 * // 'concrete-tunnel' 'small-plate' 'drum' 'beatbox' 93831 * cVerb = createConvolver('assets/bx-spring.mp3'); 93832 * 93833 * // Try replacing 'Damscray_DancingTiger' with 93834 * // 'beat', 'doorbell', lucky_dragons_-_power_melody' 93835 * sound = loadSound('assets/Damscray_DancingTiger.mp3'); 93836 * } 93837 * 93838 * function setup() { 93839 * // disconnect from master output... 93840 * sound.disconnect(); 93841 * 93842 * // ...and process with cVerb 93843 * // so that we only hear the convolution 93844 * cVerb.process(sound); 93845 * 93846 * sound.play(); 93847 * } 93848 * </code></div> 93849 */ 93850 p5.Convolver = function (path, callback, errorCallback) { 93851 p5.Reverb.call(this); 93852 /** 93853 * Internally, the p5.Convolver uses the a 93854 * <a href="http://www.w3.org/TR/webaudio/#ConvolverNode"> 93855 * Web Audio Convolver Node</a>. 93856 * 93857 * @property {ConvolverNode} convolverNode 93858 */ 93859 this._initConvolverNode(); 93860 // otherwise, Safari distorts 93861 this.input.gain.value = 0.5; 93862 if (path) { 93863 this.impulses = []; 93864 this._loadBuffer(path, callback, errorCallback); 93865 } else { 93866 // parameters 93867 this._seconds = 3; 93868 this._decay = 2; 93869 this._reverse = false; 93870 this._buildImpulse(); 93871 } 93872 }; 93873 p5.Convolver.prototype = Object.create(p5.Reverb.prototype); 93874 p5.prototype.registerPreloadMethod('createConvolver', p5.prototype); 93875 /** 93876 * Create a p5.Convolver. Accepts a path to a soundfile 93877 * that will be used to generate an impulse response. 93878 * 93879 * @method createConvolver 93880 * @param {String} path path to a sound file 93881 * @param {Function} [callback] function to call if loading is successful. 93882 * The object will be passed in as the argument 93883 * to the callback function. 93884 * @param {Function} [errorCallback] function to call if loading is not successful. 93885 * A custom error will be passed in as the argument 93886 * to the callback function. 93887 * @return {p5.Convolver} 93888 * @example 93889 * <div><code> 93890 * var cVerb, sound; 93891 * function preload() { 93892 * // We have both MP3 and OGG versions of all sound assets 93893 * soundFormats('ogg', 'mp3'); 93894 * 93895 * // Try replacing 'bx-spring' with other soundfiles like 93896 * // 'concrete-tunnel' 'small-plate' 'drum' 'beatbox' 93897 * cVerb = createConvolver('assets/bx-spring.mp3'); 93898 * 93899 * // Try replacing 'Damscray_DancingTiger' with 93900 * // 'beat', 'doorbell', lucky_dragons_-_power_melody' 93901 * sound = loadSound('assets/Damscray_DancingTiger.mp3'); 93902 * } 93903 * 93904 * function setup() { 93905 * // disconnect from master output... 93906 * sound.disconnect(); 93907 * 93908 * // ...and process with cVerb 93909 * // so that we only hear the convolution 93910 * cVerb.process(sound); 93911 * 93912 * sound.play(); 93913 * } 93914 * </code></div> 93915 */ 93916 p5.prototype.createConvolver = function (path, callback, errorCallback) { 93917 // if loading locally without a server 93918 if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') { 93919 alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS'); 93920 } 93921 var self = this; 93922 var cReverb = new p5.Convolver(path, function (buffer) { 93923 if (typeof callback === 'function') { 93924 callback(buffer); 93925 } 93926 if (typeof self._decrementPreload === 'function') { 93927 self._decrementPreload(); 93928 } 93929 }, errorCallback); 93930 cReverb.impulses = []; 93931 return cReverb; 93932 }; 93933 /** 93934 * Private method to load a buffer as an Impulse Response, 93935 * assign it to the convolverNode, and add to the Array of .impulses. 93936 *
93937 * @param {String} path 93938 * @param {Function} callback 93939 * @param {Function} errorCallback 93940 * @private 93941 */ 93942 p5.Convolver.prototype._loadBuffer = function (path, callback, errorCallback) { 93943 var path = p5.prototype._checkFileFormats(path); 93944 var self = this; 93945 var errorTrace = new Error().stack; 93946 var ac = p5.prototype.getAudioContext(); 93947 var request = new XMLHttpRequest(); 93948 request.open('GET', path, true); 93949 request.responseType = 'arraybuffer'; 93950 request.onload = function () { 93951 if (request.status === 200) { 93952 // on success loading file: 93953 ac.decodeAudioData(request.response, function (buff) { 93954 var buffer = {}; 93955 var chunks = path.split('/'); 93956 buffer.name = chunks[chunks.length - 1]; 93957 buffer.audioBuffer = buff; 93958 self.impulses.push(buffer); 93959 self._setBuffer(buffer.audioBuffer); 93960 if (callback) { 93961 callback(buffer); 93962 } 93963 }, // error decoding buffer. "e" is undefined in Chrome 11/22/2015 93964 function () { 93965 var err = new CustomError('decodeAudioData', errorTrace, self.url); 93966 var msg = 'AudioContext error at decodeAudioData for ' + self.url; 93967 if (errorCallback) { 93968 err.msg = msg; 93969 errorCallback(err); 93970 } else { 93971 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 93972 } 93973 }); 93974 } else { 93975 var err = new CustomError('loadConvolver', errorTrace, self.url); 93976 var msg = 'Unable to load ' + self.url + '. The request status was: ' + request.status + ' (' + request.statusText + ')'; 93977 if (errorCallback) { 93978 err.message = msg; 93979 errorCallback(err); 93980 } else { 93981 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 93982 } 93983 } 93984 }; 93985 // if there is another error, aside from 404... 93986 request.onerror = function () { 93987 var err = new CustomError('loadConvolver', errorTrace, self.url); 93988 var msg = 'There was no response from the server at ' + self.url + '. Check the url and internet connectivity.'; 93989 if (errorCallback) { 93990 err.message = msg; 93991 errorCallback(err); 93992 } else { 93993 console.error(msg + '\n The error stack trace includes: \n' + err.stack); 93994 } 93995 }; 93996 request.send(); 93997 }; 93998 p5.Convolver.prototype.set = null; 93999 /** 94000 * Connect a source to the reverb, and assign reverb parameters. 94001 * 94002 * @method process 94003 * @param {Object} src p5.sound / Web Audio object with a sound 94004 * output. 94005 * @example 94006 * <div><code> 94007 * var cVerb, sound; 94008 * function preload() { 94009 * soundFormats('ogg', 'mp3'); 94010 * 94011 * cVerb = createConvolver('assets/concrete-tunnel.mp3'); 94012 * 94013 * sound = loadSound('assets/beat.mp3'); 94014 * } 94015 * 94016 * function setup() { 94017 * // disconnect from master output... 94018 * sound.disconnect(); 94019 * 94020 * // ...and process with (i.e. connect to) cVerb 94021 * // so that we only hear the convolution 94022 * cVerb.process(sound); 94023 * 94024 * sound.play(); 94025 * } 94026 * </code></div> 94027 */ 94028 p5.Convolver.prototype.process = function (src) { 94029 src.connect(this.input); 94030 }; 94031 /** 94032 * If you load multiple impulse files using the .addImpulse method, 94033 * they will be stored as Objects in this Array. Toggle between them 94034 * with the <code>toggleImpulse(id)</code> method. 94035 * 94036 * @property {Array} impulses 94037 */ 94038 p5.Convolver.prototype.impulses = []; 94039 /** 94040 * Load and assign a new Impulse Response to the p5.Convolver. 94041 * The impulse is added to the <code>.impulses</code> array. Previous 94042 * impulses can be accessed with the <code>.toggleImpulse(id)</code> 94043 * method. 94044 * 94045 * @method addImpulse 94046 * @param {String} path path to a sound file 94047 * @param {Function} callback function (optional) 94048 * @param {Function} errorCallback function (optional) 94049 */ 94050 p5.Convolver.prototype.addImpulse = function (path, callback, errorCallback) { 94051 // if loading locally without a server 94052 if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') { 94053 alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS'); 94054 } 94055 this._loadBuffer(path, callback, errorCallback); 94056 }; 94057 /** 94058 * Similar to .addImpulse, except that the <code>.impulses</code> 94059 * Array is reset to save memory. A new <code>.impulses</code> 94060 * array is created with this impulse as the only item. 94061 * 94062 * @method resetImpulse 94063 * @param {String} path path to a sound file 94064 * @param {Function} callback function (optional) 94065 * @param {Function} errorCallback function (optional) 94066 */ 94067 p5.Convolver.prototype.resetImpulse = function (path, callback, errorCallback) { 94068 // if loading locally without a server 94069 if (window.location.origin.indexOf('file://') > -1 && window.cordova === 'undefined') { 94070 alert('This sketch may require a server to load external files. Please see http://bit.ly/1qcInwS'); 94071 } 94072 this.impulses = []; 94073 this._loadBuffer(path, callback, errorCallback); 94074 }; 94075 /** 94076 * If you have used <code>.addImpulse()</code> to add multiple impulses 94077 * to a p5.Convolver, then you can use this method to toggle between 94078 * the items in the <code>.impulses</code> Array. Accepts a parameter 94079 * to identify which impulse you wish to use, identified either by its 94080 * original filename (String) or by its position in the <code>.impulses 94081 * </code> Array (Number).<br/> 94082 * You can access the objects in the .impulses Array directly. Each 94083 * Object has two attributes: an <code>.audioBuffer</code> (type: 94084 * Web Audio <a href=" 94085 * http://webaudio.github.io/web-audio-api/#the-audiobuffer-interface"> 94086 * AudioBuffer)</a> and a <code>.name</code>, a String that corresponds 94087 * with the original filename. 94088 * 94089 * @method toggleImpulse 94090 * @param {String|Number} id Identify the impulse by its original filename 94091 * (String), or by its position in the 94092 * <code>.impulses</code> Array (Number). 94093 */ 94094 p5.Convolver.prototype.toggleImpulse = function (id) { 94095 if (typeof id === 'number' && id < this.impulses.length) { 94096 this._setBuffer(this.impulses[id].audioBuffer); 94097 } 94098 if (typeof id === 'string') { 94099 for (var i = 0; i < this.impulses.length; i++) { 94100 if (this.impulses[i].name === id) { 94101 this._setBuffer(this.impulses[i].audioBuffer); 94102 break; 94103 } 94104 } 94105 } 94106 }; 94107 p5.Convolver.prototype.dispose = function () { 94108 p5.Reverb.prototype.dispose.apply(this); 94109 // remove all the Impulse Response buffers 94110 for (var i in this.impulses) { 94111 if (this.impulses[i]) { 94112 this.impulses[i] = null; 94113 } 94114 } 94115 }; 94116}(errorHandler, effect); 94117/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 94118var Tone_core_TimelineState; 94119Tone_core_TimelineState = function (Tone) { 94120 'use strict'; 94121 Tone.TimelineState = function (initial) { 94122 Tone.Timeline.call(this); 94123 this._initial = initial; 94124 }; 94125 Tone.extend(Tone.TimelineState, Tone.Timeline); 94126 Tone.TimelineState.prototype.getValueAtTime = function (time) { 94127 var event = this.get(time); 94128 if (event !== null) { 94129 return event.state; 94130 } else { 94131 return this._initial; 94132 } 94133 }; 94134 Tone.TimelineState.prototype.setStateAtTime = function (state, time) { 94135 this.add({ 94136 'state': state, 94137 'time': time 94138 }); 94139 }; 94140 return Tone.TimelineState; 94141}(Tone_core_Tone, Tone_core_Timeline); 94142/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/ 94143var Tone_core_Clock; 94144Tone_core_Clock = function (Tone) { 94145 'use strict'; 94146 Tone.Clock = function () { 94147 Tone.Emitter.call(this); 94148 var options = this.optionsObject(arguments, [ 94149 'callback', 94150 'frequency' 94151 ], Tone.Clock.defaults); 94152 this.callback = options.callback; 94153 this._nextTick = 0; 94154 this._lastState = Tone.State.Stopped; 94155 this.frequency = new Tone.TimelineSignal(options.frequency, Tone.Type.Frequency); 94156 this._readOnly('frequency'); 94157 this.ticks = 0; 94158 this._state = new Tone.TimelineState(Tone.State.Stopped); 94159 this._boundLoop = this._loop.bind(this); 94160 this.context.on('tick', this._boundLoop); 94161 }; 94162 Tone.extend(Tone.Clock, Tone.Emitter); 94163 Tone.Clock.defaults = { 94164 'callback': Tone.noOp, 94165 'frequency': 1, 94166 'lookAhead': 'auto' 94167 }; 94168 Object.defineProperty(Tone.Clock.prototype, 'state', { 94169 get: function () { 94170 return this._state.getValueAtTime(this.now()); 94171 } 94172 }); 94173 Tone.Clock.prototype.start = function (time, offset) { 94174 time = this.toSeconds(time); 94175 if (this._state.getValueAtTime(time) !== Tone.State.Started) { 94176 this._state.add({ 94177 'state': Tone.State.Started, 94178 'time': time, 94179 'offset': offset 94180 }); 94181 } 94182 return this; 94183 }; 94184 Tone.Clock.prototype.stop = function (time) { 94185 time = this.toSeconds(time); 94186 this._state.cancel(time);
94187 this._state.setStateAtTime(Tone.State.Stopped, time); 94188 return this; 94189 }; 94190 Tone.Clock.prototype.pause = function (time) { 94191 time = this.toSeconds(time); 94192 if (this._state.getValueAtTime(time) === Tone.State.Started) { 94193 this._state.setStateAtTime(Tone.State.Paused, time); 94194 } 94195 return this; 94196 }; 94197 Tone.Clock.prototype._loop = function () { 94198 var now = this.now(); 94199 var lookAhead = this.context.lookAhead; 94200 var updateInterval = this.context.updateInterval; 94201 var lagCompensation = this.context.lag * 2; 94202 var loopInterval = now + lookAhead + updateInterval + lagCompensation; 94203 while (loopInterval > this._nextTick && this._state) { 94204 var currentState = this._state.getValueAtTime(this._nextTick); 94205 if (currentState !== this._lastState) { 94206 this._lastState = currentState; 94207 var event = this._state.get(this._nextTick); 94208 if (currentState === Tone.State.Started) { 94209 this._nextTick = event.time; 94210 if (!this.isUndef(event.offset)) { 94211 this.ticks = event.offset; 94212 } 94213 this.emit('start', event.time, this.ticks); 94214 } else if (currentState === Tone.State.Stopped) { 94215 this.ticks = 0; 94216 this.emit('stop', event.time); 94217 } else if (currentState === Tone.State.Paused) { 94218 this.emit('pause', event.time); 94219 } 94220 } 94221 var tickTime = this._nextTick; 94222 if (this.frequency) { 94223 this._nextTick += 1 / this.frequency.getValueAtTime(this._nextTick); 94224 if (currentState === Tone.State.Started) { 94225 this.callback(tickTime); 94226 this.ticks++; 94227 } 94228 } 94229 } 94230 }; 94231 Tone.Clock.prototype.getStateAtTime = function (time) { 94232 time = this.toSeconds(time); 94233 return this._state.getValueAtTime(time); 94234 }; 94235 Tone.Clock.prototype.dispose = function () { 94236 Tone.Emitter.prototype.dispose.call(this); 94237 this.context.off('tick', this._boundLoop); 94238 this._writable('frequency'); 94239 this.frequency.dispose(); 94240 this.frequency = null; 94241 this._boundLoop = null; 94242 this._nextTick = Infinity; 94243 this.callback = null; 94244 this._state.dispose(); 94245 this._state = null; 94246 }; 94247 return Tone.Clock; 94248}(Tone_core_Tone, Tone_signal_TimelineSignal, Tone_core_TimelineState, Tone_core_Emitter); 94249var metro; 94250'use strict'; 94251metro = function () { 94252 var p5sound = master; 94253 // requires the Tone.js library's Clock (MIT license, Yotam Mann) 94254 // https://github.com/TONEnoTONE/Tone.js/ 94255 var Clock = Tone_core_Clock; 94256 p5.Metro = function () { 94257 this.clock = new Clock({ 'callback': this.ontick.bind(this) }); 94258 this.syncedParts = []; 94259 this.bpm = 120; 94260 // gets overridden by p5.Part 94261 this._init(); 94262 this.prevTick = 0; 94263 this.tatumTime = 0; 94264 this.tickCallback = function () { 94265 }; 94266 }; 94267 p5.Metro.prototype.ontick = function (tickTime) { 94268 var elapsedTime = tickTime - this.prevTick; 94269 var secondsFromNow = tickTime - p5sound.audiocontext.currentTime; 94270 if (elapsedTime - this.tatumTime <= -0.02) { 94271 return; 94272 } else { 94273 // console.log('ok', this.syncedParts[0].phrases[0].name); 94274 this.prevTick = tickTime; 94275 // for all of the active things on the metro: 94276 var self = this; 94277 this.syncedParts.forEach(function (thisPart) { 94278 if (!thisPart.isPlaying) 94279 return; 94280 thisPart.incrementStep(secondsFromNow); 94281 // each synced source keeps track of its own beat number 94282 thisPart.phrases.forEach(function (thisPhrase) { 94283 var phraseArray = thisPhrase.sequence; 94284 var bNum = self.metroTicks % phraseArray.length; 94285 if (phraseArray[bNum] !== 0 && (self.metroTicks < phraseArray.length || !thisPhrase.looping)) { 94286 thisPhrase.callback(secondsFromNow, phraseArray[bNum]); 94287 } 94288 }); 94289 }); 94290 this.metroTicks += 1; 94291 this.tickCallback(secondsFromNow); 94292 } 94293 }; 94294 p5.Metro.prototype.setBPM = function (bpm, rampTime) { 94295 var beatTime = 60 / (bpm * this.tatums); 94296 var now = p5sound.audiocontext.currentTime; 94297 this.tatumTime = beatTime; 94298 var rampTime = rampTime || 0; 94299 this.clock.frequency.setValueAtTime(this.clock.frequency.value, now); 94300 this.clock.frequency.linearRampToValueAtTime(bpm, now + rampTime); 94301 this.bpm = bpm; 94302 }; 94303 p5.Metro.prototype.getBPM = function () { 94304 return this.clock.getRate() / this.tatums * 60; 94305 }; 94306 p5.Metro.prototype._init = function () {
94307 this.metroTicks = 0; 94308 }; 94309 // clear existing synced parts, add only this one 94310 p5.Metro.prototype.resetSync = function (part) { 94311 this.syncedParts = [part]; 94312 }; 94313 // push a new synced part to the array 94314 p5.Metro.prototype.pushSync = function (part) { 94315 this.syncedParts.push(part); 94316 }; 94317 p5.Metro.prototype.start = function (timeFromNow) { 94318 var t = timeFromNow || 0; 94319 var now = p5sound.audiocontext.currentTime; 94320 this.clock.start(now + t); 94321 this.setBPM(this.bpm); 94322 }; 94323 p5.Metro.prototype.stop = function (timeFromNow) { 94324 var t = timeFromNow || 0; 94325 var now = p5sound.audiocontext.currentTime; 94326 this.clock.stop(now + t); 94327 }; 94328 p5.Metro.prototype.beatLength = function (tatums) { 94329 this.tatums = 1 / tatums / 4; 94330 }; 94331}(master, Tone_core_Clock); 94332var looper; 94333'use strict'; 94334looper = function () { 94335 var p5sound = master; 94336 var BPM = 120; 94337 /** 94338 * Set the global tempo, in beats per minute, for all 94339 * p5.Parts. This method will impact all active p5.Parts. 94340 * 94341 * @method setBPM 94342 * @param {Number} BPM Beats Per Minute 94343 * @param {Number} rampTime Seconds from now 94344 */ 94345 p5.prototype.setBPM = function (bpm, rampTime) { 94346 BPM = bpm; 94347 for (var i in p5sound.parts) { 94348 if (p5sound.parts[i]) { 94349 p5sound.parts[i].setBPM(bpm, rampTime); 94350 } 94351 } 94352 }; 94353 /** 94354 * <p>A phrase is a pattern of musical events over time, i.e. 94355 * a series of notes and rests.</p> 94356 * 94357 * <p>Phrases must be added to a p5.Part for playback, and 94358 * each part can play multiple phrases at the same time. 94359 * For example, one Phrase might be a kick drum, another 94360 * could be a snare, and another could be the bassline.</p> 94361 * 94362 * <p>The first parameter is a name so that the phrase can be 94363 * modified or deleted later. The callback is a a function that 94364 * this phrase will call at every stepâfor example it might be 94365 * called <code>playNote(value){}</code>. The array determines 94366 * which value is passed into the callback at each step of the 94367 * phrase. It can be numbers, an object with multiple numbers, 94368 * or a zero (0) indicates a rest so the callback won't be called).</p> 94369 * 94370 * @class p5.Phrase 94371 * @constructor 94372 * @param {String} name Name so that you can access the Phrase. 94373 * @param {Function} callback The name of a function that this phrase 94374 * will call. Typically it will play a sound, 94375 * and accept two parameters: a time at which 94376 * to play the sound (in seconds from now), 94377 * and a value from the sequence array. The 94378 * time should be passed into the play() or 94379 * start() method to ensure precision. 94380 * @param {Array} sequence Array of values to pass into the callback 94381 * at each step of the phrase. 94382 * @example 94383 * <div><code> 94384 * var mySound, myPhrase, myPart; 94385 * var pattern = [1,0,0,2,0,2,0,0]; 94386 * var msg = 'click to play'; 94387 * 94388 * function preload() { 94389 * mySound = loadSound('assets/beatbox.mp3'); 94390 * } 94391 * 94392 * function setup() { 94393 * noStroke(); 94394 * fill(255); 94395 * textAlign(CENTER); 94396 * masterVolume(0.1); 94397 * 94398 * myPhrase = new p5.Phrase('bbox', makeSound, pattern); 94399 * myPart = new p5.Part(); 94400 * myPart.addPhrase(myPhrase); 94401 * myPart.setBPM(60); 94402 * } 94403 * 94404 * function draw() { 94405 * background(0); 94406 * text(msg, width/2, height/2); 94407 * } 94408 * 94409 * function makeSound(time, playbackRate) { 94410 * mySound.rate(playbackRate); 94411 * mySound.play(time); 94412 * } 94413 * 94414 * function mouseClicked() { 94415 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 94416 * myPart.start(); 94417 * msg = 'playing pattern'; 94418 * } 94419 * } 94420 * 94421 * </code></div> 94422 */ 94423 p5.Phrase = function (name, callback, sequence) { 94424 this.phraseStep = 0; 94425 this.name = name; 94426 this.callback = callback; 94427 /** 94428 * Array of values to pass into the callback 94429 * at each step of the phrase. Depending on the callback 94430 * function's requirements, these values may be numbers, 94431 * strings, or an object with multiple parameters. 94432 * Zero (0) indicates a rest. 94433 * 94434 * @property {Array} sequence 94435 */ 94436 this.sequence = sequence; 94437 }; 94438 /** 94439 * <p>A p5.Part plays back one or more p5.Phrases. Instantiate a part 94440 * with steps and tatums. By default, each step represents a 1/16th note.</p> 94441 * 94442 * <p>See p5.Phrase for more about musical timing.</p> 94443 * 94444 * @class p5.Part 94445 * @constructor 94446 * @param {Number} [steps] Steps in the part 94447 * @param {Number} [tatums] Divisions of a beat, e.g. use 1/4, or 0.25 for a quater note (default is 1/16, a sixteenth note) 94448 * @example 94449 * <div><code> 94450 * var box, drum, myPart; 94451 * var boxPat = [1,0,0,2,0,2,0,0]; 94452 * var drumPat = [0,1,1,0,2,0,1,0]; 94453 * var msg = 'click to play'; 94454 * 94455 * function preload() { 94456 * box = loadSound('assets/beatbox.mp3'); 94457 * drum = loadSound('assets/drum.mp3'); 94458 * } 94459 * 94460 * function setup() { 94461 * noStroke(); 94462 * fill(255); 94463 * textAlign(CENTER); 94464 * masterVolume(0.1); 94465 * 94466 * var boxPhrase = new p5.Phrase('box', playBox, boxPat); 94467 * var drumPhrase = new p5.Phrase('drum', playDrum, drumPat); 94468 * myPart = new p5.Part(); 94469 * myPart.addPhrase(boxPhrase); 94470 * myPart.addPhrase(drumPhrase); 94471 * myPart.setBPM(60); 94472 * masterVolume(0.1); 94473 * } 94474 * 94475 * function draw() { 94476 * background(0); 94477 * text(msg, width/2, height/2); 94478 * } 94479 * 94480 * function playBox(time, playbackRate) { 94481 * box.rate(playbackRate); 94482 * box.play(time); 94483 * } 94484 * 94485 * function playDrum(time, playbackRate) { 94486 * drum.rate(playbackRate); 94487 * drum.play(time); 94488 * } 94489 * 94490 * function mouseClicked() { 94491 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 94492 * myPart.start(); 94493 * msg = 'playing part'; 94494 * } 94495 * } 94496 * </code></div> 94497 */ 94498 p5.Part = function (steps, bLength) { 94499 this.length = steps || 0; 94500 // how many beats
94501 this.partStep = 0; 94502 this.phrases = []; 94503 this.isPlaying = false; 94504 this.noLoop(); 94505 this.tatums = bLength || 0.0625; 94506 // defaults to quarter note 94507 this.metro = new p5.Metro(); 94508 this.metro._init(); 94509 this.metro.beatLength(this.tatums); 94510 this.metro.setBPM(BPM); 94511 p5sound.parts.push(this); 94512 this.callback = function () { 94513 }; 94514 }; 94515 /** 94516 * Set the tempo of this part, in Beats Per Minute. 94517 * 94518 * @method setBPM 94519 * @param {Number} BPM Beats Per Minute 94520 * @param {Number} [rampTime] Seconds from now 94521 */ 94522 p5.Part.prototype.setBPM = function (tempo, rampTime) { 94523 this.metro.setBPM(tempo, rampTime); 94524 }; 94525 /** 94526 * Returns the tempo, in Beats Per Minute, of this part. 94527 * 94528 * @method getBPM 94529 * @return {Number} 94530 */ 94531 p5.Part.prototype.getBPM = function () { 94532 return this.metro.getBPM(); 94533 }; 94534 /** 94535 * Start playback of this part. It will play 94536 * through all of its phrases at a speed 94537 * determined by setBPM. 94538 * 94539 * @method start 94540 * @param {Number} [time] seconds from now 94541 */ 94542 p5.Part.prototype.start = function (time) { 94543 if (!this.isPlaying) { 94544 this.isPlaying = true; 94545 this.metro.resetSync(this); 94546 var t = time || 0; 94547 this.metro.start(t); 94548 } 94549 }; 94550 /** 94551 * Loop playback of this part. It will begin 94552 * looping through all of its phrases at a speed 94553 * determined by setBPM. 94554 * 94555 * @method loop 94556 * @param {Number} [time] seconds from now 94557 */ 94558 p5.Part.prototype.loop = function (time) { 94559 this.looping = true; 94560 // rest onended function 94561 this.onended = function () { 94562 this.partStep = 0; 94563 }; 94564 var t = time || 0; 94565 this.start(t); 94566 }; 94567 /** 94568 * Tell the part to stop looping. 94569 * 94570 * @method noLoop 94571 */ 94572 p5.Part.prototype.noLoop = function () { 94573 this.looping = false; 94574 // rest onended function 94575 this.onended = function () { 94576 this.stop(); 94577 }; 94578 }; 94579 /** 94580 * Stop the part and cue it to step 0. Playback will resume from the begining of the Part when it is played again. 94581 * 94582 * @method stop 94583 * @param {Number} [time] seconds from now 94584 */ 94585 p5.Part.prototype.stop = function (time) { 94586 this.partStep = 0; 94587 this.pause(time); 94588 }; 94589 /** 94590 * Pause the part. Playback will resume 94591 * from the current step. 94592 * 94593 * @method pause 94594 * @param {Number} time seconds from now 94595 */ 94596 p5.Part.prototype.pause = function (time) { 94597 this.isPlaying = false; 94598 var t = time || 0; 94599 this.metro.stop(t); 94600 }; 94601 /** 94602 * Add a p5.Phrase to this Part. 94603 * 94604 * @method addPhrase 94605 * @param {p5.Phrase} phrase reference to a p5.Phrase 94606 */ 94607 p5.Part.prototype.addPhrase = function (name, callback, array) { 94608 var p; 94609 if (arguments.length === 3) { 94610 p = new p5.Phrase(name, callback, array); 94611 } else if (arguments[0] instanceof p5.Phrase) { 94612 p = arguments[0]; 94613 } else { 94614 throw 'invalid input. addPhrase accepts name, callback, array or a p5.Phrase'; 94615 } 94616 this.phrases.push(p); 94617 // reset the length if phrase is longer than part's existing length 94618 if (p.sequence.length > this.length) { 94619 this.length = p.sequence.length; 94620 } 94621 }; 94622 /** 94623 * Remove a phrase from this part, based on the name it was 94624 * given when it was created. 94625 * 94626 * @method removePhrase 94627 * @param {String} phraseName 94628 */ 94629 p5.Part.prototype.removePhrase = function (name) { 94630 for (var i in this.phrases) { 94631 if (this.phrases[i].name === name) { 94632 this.phrases.splice(i, 1); 94633 } 94634 } 94635 }; 94636 /** 94637 * Get a phrase from this part, based on the name it was 94638 * given when it was created. Now you can modify its array. 94639 * 94640 * @method getPhrase 94641 * @param {String} phraseName 94642 */ 94643 p5.Part.prototype.getPhrase = function (name) { 94644 for (var i in this.phrases) { 94645 if (this.phrases[i].name === name) { 94646 return this.phrases[i]; 94647 } 94648 } 94649 }; 94650 /** 94651 * Find all sequences with the specified name, and replace their patterns with the specified array. 94652 * 94653 * @method replaceSequence 94654 * @param {String} phraseName 94655 * @param {Array} sequence Array of values to pass into the callback 94656 * at each step of the phrase. 94657 */ 94658 p5.Part.prototype.replaceSequence = function (name, array) { 94659 for (var i in this.phrases) { 94660 if (this.phrases[i].name === name) { 94661 this.phrases[i].sequence = array; 94662 } 94663 } 94664 }; 94665 p5.Part.prototype.incrementStep = function (time) { 94666 if (this.partStep < this.length - 1) { 94667 this.callback(time); 94668 this.partStep += 1; 94669 } else {
94670 if (!this.looping && this.partStep === this.length - 1) { 94671 console.log('done'); 94672 // this.callback(time); 94673 this.onended(); 94674 } 94675 } 94676 }; 94677 /** 94678 * Set the function that will be called at every step. This will clear the previous function. 94679 * 94680 * @method onStep 94681 * @param {Function} callback The name of the callback 94682 * you want to fire 94683 * on every beat/tatum. 94684 */ 94685 p5.Part.prototype.onStep = function (callback) { 94686 this.callback = callback; 94687 }; 94688 // =============== 94689 // p5.Score 94690 // =============== 94691 /** 94692 * A Score consists of a series of Parts. The parts will 94693 * be played back in order. For example, you could have an 94694 * A part, a B part, and a C part, and play them back in this order 94695 * <code>new p5.Score(a, a, b, a, c)</code> 94696 * 94697 * @class p5.Score 94698 * @constructor 94699 * @param {p5.Part} [...parts] One or multiple parts, to be played in sequence. 94700 */ 94701 p5.Score = function () { 94702 // for all of the arguments 94703 this.parts = []; 94704 this.currentPart = 0; 94705 var thisScore = this; 94706 for (var i in arguments) { 94707 if (arguments[i] && this.parts[i]) { 94708 this.parts[i] = arguments[i]; 94709 this.parts[i].nextPart = this.parts[i + 1]; 94710 this.parts[i].onended = function () { 94711 thisScore.resetPart(i); 94712 playNextPart(thisScore); 94713 }; 94714 } 94715 } 94716 this.looping = false; 94717 }; 94718 p5.Score.prototype.onended = function () { 94719 if (this.looping) { 94720 // this.resetParts(); 94721 this.parts[0].start(); 94722 } else { 94723 this.parts[this.parts.length - 1].onended = function () { 94724 this.stop(); 94725 this.resetParts(); 94726 }; 94727 } 94728 this.currentPart = 0; 94729 }; 94730 /** 94731 * Start playback of the score. 94732 * 94733 * @method start 94734 */ 94735 p5.Score.prototype.start = function () { 94736 this.parts[this.currentPart].start(); 94737 this.scoreStep = 0; 94738 }; 94739 /** 94740 * Stop playback of the score. 94741 * 94742 * @method stop 94743 */ 94744 p5.Score.prototype.stop = function () { 94745 this.parts[this.currentPart].stop(); 94746 this.currentPart = 0; 94747 this.scoreStep = 0; 94748 }; 94749 /** 94750 * Pause playback of the score. 94751 * 94752 * @method pause 94753 */ 94754 p5.Score.prototype.pause = function () { 94755 this.parts[this.currentPart].stop(); 94756 }; 94757 /** 94758 * Loop playback of the score. 94759 * 94760 * @method loop 94761 */ 94762 p5.Score.prototype.loop = function () { 94763 this.looping = true; 94764 this.start(); 94765 }; 94766 /** 94767 * Stop looping playback of the score. If it 94768 * is currently playing, this will go into effect 94769 * after the current round of playback completes. 94770 * 94771 * @method noLoop 94772 */ 94773 p5.Score.prototype.noLoop = function () { 94774 this.looping = false; 94775 }; 94776 p5.Score.prototype.resetParts = function () { 94777 var self = this; 94778 this.parts.forEach(function (part) { 94779 self.resetParts[part]; 94780 }); 94781 }; 94782 p5.Score.prototype.resetPart = function (i) { 94783 this.parts[i].stop(); 94784 this.parts[i].partStep = 0; 94785 for (var p in this.parts[i].phrases) { 94786 if (this.parts[i]) { 94787 this.parts[i].phrases[p].phraseStep = 0; 94788 } 94789 } 94790 }; 94791 /** 94792 * Set the tempo for all parts in the score 94793 * 94794 * @method setBPM 94795 * @param {Number} BPM Beats Per Minute 94796 * @param {Number} rampTime Seconds from now 94797 */ 94798 p5.Score.prototype.setBPM = function (bpm, rampTime) { 94799 for (var i in this.parts) { 94800 if (this.parts[i]) { 94801 this.parts[i].setBPM(bpm, rampTime); 94802 } 94803 } 94804 }; 94805 function playNextPart(aScore) { 94806 aScore.currentPart++; 94807 if (aScore.currentPart >= aScore.parts.length) { 94808 aScore.scoreStep = 0; 94809 aScore.onended(); 94810 } else { 94811 aScore.scoreStep = 0; 94812 aScore.parts[aScore.currentPart - 1].stop(); 94813 aScore.parts[aScore.currentPart].start(); 94814 } 94815 } 94816}(master); 94817var soundloop; 94818'use strict'; 94819soundloop = function () { 94820 var p5sound = master; 94821 var Clock = Tone_core_Clock; 94822 /** 94823 * SoundLoop 94824 * 94825 * @class p5.SoundLoop 94826 * @constructor 94827 * 94828 * @param {Function} callback this function will be called on each iteration of theloop 94829 * @param {Number|String} [interval] amount of time or beats for each iteration of the loop 94830 * defaults to 1 94831 * 94832 * @example 94833 * <div><code> 94834 * var click; 94835 * var looper1; 94836 * 94837 * function preload() { 94838 * click = loadSound('assets/drum.mp3'); 94839 * } 94840 * 94841 * function setup() { 94842 * //the looper's callback is passed the timeFromNow 94843 * //this value should be used as a reference point from 94844 * //which to schedule sounds 94845 * looper1 = new p5.SoundLoop(function(timeFromNow){ 94846 * click.play(timeFromNow); 94847 * background(255 * (looper1.iterations % 2)); 94848 * }, 2); 94849 * 94850 * //stop after 10 iteratios; 94851 * looper1.maxIterations = 10; 94852 * //start the loop 94853 * looper1.start(); 94854 * } 94855 * </code></div> 94856 */ 94857 p5.SoundLoop = function (callback, interval) { 94858 this.callback = callback; 94859 /** 94860 * musicalTimeMode uses <a href = "https://github.com/Tonejs/Tone.js/wiki/Time">Tone.Time</a> convention 94861 * true if string, false if number 94862 * @property {Boolean} musicalTimeMode 94863 */ 94864 this.musicalTimeMode = typeof this._interval === 'number' ? false : true; 94865 this._interval = interval || 1; 94866 /** 94867 * musicalTimeMode variables 94868 * modify these only when the interval is specified in musicalTime format as a string 94869 */ 94870 this._timeSignature = 4; 94871 this._bpm = 60; 94872 this.isPlaying = false;
94873 /** 94874 * Set a limit to the number of loops to play. defaults to Infinity 94875 * @property {Number} maxIterations 94876 */ 94877 this.maxIterations = Infinity; 94878 var self = this; 94879 this.clock = new Clock({ 94880 'callback': function (time) { 94881 var timeFromNow = time - p5sound.audiocontext.currentTime; 94882 /** 94883 * Do not initiate the callback if timeFromNow is < 0 94884 * This ususually occurs for a few milliseconds when the page 94885 * is not fully loaded 94886 * 94887 * The callback should only be called until maxIterations is reached 94888 */ 94889 if (timeFromNow > 0 && self.iterations <= self.maxIterations) { 94890 self.callback(timeFromNow); 94891 } 94892 }, 94893 'frequency': this._calcFreq() 94894 }); 94895 }; 94896 /** 94897 * Start the loop 94898 * @method start 94899 * @param {Number} [timeFromNow] schedule a starting time 94900 */ 94901 p5.SoundLoop.prototype.start = function (timeFromNow) { 94902 var t = timeFromNow || 0; 94903 var now = p5sound.audiocontext.currentTime; 94904 if (!this.isPlaying) { 94905 this.clock.start(now + t); 94906 this.isPlaying = true; 94907 } 94908 }; 94909 /** 94910 * Stop the loop 94911 * @method stop 94912 * @param {Number} [timeFromNow] schedule a stopping time 94913 */ 94914 p5.SoundLoop.prototype.stop = function (timeFromNow) { 94915 var t = timeFromNow || 0; 94916 var now = p5sound.audiocontext.currentTime; 94917 if (this.isPlaying) { 94918 this.clock.stop(now + t); 94919 this.isPlaying = false; 94920 } 94921 }; 94922 /** 94923 * Pause the loop 94924 * @method pause 94925 * @param {Number} [timeFromNow] schedule a pausing time 94926 */ 94927 p5.SoundLoop.prototype.pause = function (timeFromNow) { 94928 var t = timeFromNow || 0; 94929 var now = p5sound.audiocontext.currentTime; 94930 if (this.isPlaying) { 94931 this.clock.pause(now + t); 94932 this.isPlaying = false; 94933 } 94934 }; 94935 /** 94936 * Synchronize loops. Use this method to start two more more loops in synchronization 94937 * or to start a loop in synchronization with a loop that is already playing 94938 * This method will schedule the implicit loop in sync with the explicit master loop 94939 * i.e. loopToStart.syncedStart(loopToSyncWith) 94940 * 94941 * @method syncedStart 94942 * @param {Object} otherLoop a p5.SoundLoop to sync with 94943 * @param {Number} [timeFromNow] Start the loops in sync after timeFromNow seconds 94944 */ 94945 p5.SoundLoop.prototype.syncedStart = function (otherLoop, timeFromNow) { 94946 var t = timeFromNow || 0; 94947 var now = p5sound.audiocontext.currentTime; 94948 if (!otherLoop.isPlaying) { 94949 otherLoop.clock.start(now + t); 94950 otherLoop.isPlaying = true; 94951 this.clock.start(now + t); 94952 this.isPlaying = true; 94953 } else if (otherLoop.isPlaying) { 94954 var time = otherLoop.clock._nextTick - p5sound.audiocontext.currentTime; 94955 this.clock.start(now + time); 94956 this.isPlaying = true; 94957 } 94958 }; 94959 /** 94960 * Updates frequency value, reflected in next callback 94961 * @private 94962 * @method _update 94963 */ 94964 p5.SoundLoop.prototype._update = function () { 94965 this.clock.frequency.value = this._calcFreq(); 94966 }; 94967 /** 94968 * Calculate the frequency of the clock's callback based on bpm, interval, and timesignature 94969 * @private 94970 * @method _calcFreq 94971 * @return {Number} new clock frequency value 94972 */ 94973 p5.SoundLoop.prototype._calcFreq = function () { 94974 //Seconds mode, bpm / timesignature has no effect 94975 if (typeof this._interval === 'number') { 94976 this.musicalTimeMode = false; 94977 return 1 / this._interval; 94978 } else if (typeof this._interval === 'string') { 94979 this.musicalTimeMode = true; 94980 return this._bpm / 60 / this._convertNotation(this._interval) * (this._timeSignature / 4); 94981 } 94982 }; 94983 /** 94984 * Convert notation from musical time format to seconds 94985 * Uses <a href = "https://github.com/Tonejs/Tone.js/wiki/Time">Tone.Time</a> convention 94986 * @private 94987 * @method _convertNotation 94988 * @param {String} value value to be converted 94989 * @return {Number} converted value in seconds 94990 */ 94991 p5.SoundLoop.prototype._convertNotation = function (value) { 94992 var type = value.slice(-1); 94993 value = Number(value.slice(0, -1)); 94994 switch (type) { 94995 case 'm': 94996 return this._measure(value); 94997 case 'n': 94998 return this._note(value); 94999 default: 95000 console.warn('Specified interval is not formatted correctly. See Tone.js ' + 'timing reference for more info: https://github.com/Tonejs/Tone.js/wiki/Time'); 95001 } 95002 }; 95003 /** 95004 * Helper conversion methods of measure and note 95005 * @private 95006 * @method _measure 95007 * @private 95008 * @method _note 95009 */ 95010 p5.SoundLoop.prototype._measure = function (value) { 95011 return value * this._timeSignature; 95012 }; 95013 p5.SoundLoop.prototype._note = function (value) { 95014 return this._timeSignature / value; 95015 }; 95016 /** 95017 * Getters and Setters, setting any paramter will result in a change in the clock's 95018 * frequency, that will be reflected after the next callback 95019 * beats per minute (defaults to 60) 95020 * @property {Number} bpm 95021 */ 95022 Object.defineProperty(p5.SoundLoop.prototype, 'bpm', { 95023 get: function () { 95024 return this._bpm; 95025 }, 95026 set: function (bpm) { 95027 if (!this.musicalTimeMode) { 95028 console.warn('Changing the BPM in "seconds" mode has no effect. ' + 'BPM is only relevant in musicalTimeMode ' + 'when the interval is specified as a string ' + '("2n", "4n", "1m"...etc)'); 95029 } 95030 this._bpm = bpm; 95031 this._update(); 95032 } 95033 }); 95034 /** 95035 * number of quarter notes in a measure (defaults to 4) 95036 * @property {Number} timeSignature 95037 */ 95038 Object.defineProperty(p5.SoundLoop.prototype, 'timeSignature', { 95039 get: function () { 95040 return this._timeSignature; 95041 }, 95042 set: function (timeSig) { 95043 if (!this.musicalTimeMode) { 95044 console.warn('Changing the timeSignature in "seconds" mode has no effect. ' + 'BPM is only relevant in musicalTimeMode ' + 'when the interval is specified as a string ' + '("2n", "4n", "1m"...etc)'); 95045 } 95046 this._timeSignature = timeSig; 95047 this._update(); 95048 } 95049 }); 95050 /** 95051 * length of the loops interval 95052 * @property {Number|String} interval 95053 */ 95054 Object.defineProperty(p5.SoundLoop.prototype, 'interval', { 95055 get: function () { 95056 return this._interval; 95057 }, 95058 set: function (interval) { 95059 this.musicalTimeMode = typeof interval === 'Number' ? false : true; 95060 this._interval = interval; 95061 this._update(); 95062 } 95063 }); 95064 /** 95065 * how many times the callback has been called so far 95066 * @property {Number} iterations 95067 * @readonly 95068 */ 95069 Object.defineProperty(p5.SoundLoop.prototype, 'iterations', { 95070 get: function () { 95071 return this.clock.ticks; 95072 } 95073 }); 95074 return p5.SoundLoop; 95075}(master, Tone_core_Clock); 95076var compressor; 95077compressor = function () { 95078 'use strict'; 95079 var p5sound = master; 95080 var Effect = effect; 95081 var CustomError = errorHandler; 95082 /** 95083 * Compressor is an audio effect class that performs dynamics compression 95084 * on an audio input source. This is a very commonly used technique in music 95085 * and sound production. Compression creates an overall louder, richer, 95086 * and fuller sound by lowering the volume of louds and raising that of softs. 95087 * Compression can be used to avoid clipping (sound distortion due to 95088 * peaks in volume) and is especially useful when many sounds are played 95089 * at once. Compression can be used on indivudal sound sources in addition 95090 * to the master output. 95091 * 95092 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 95093 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 95094 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 95095 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 95096 * 95097 * @class p5.Compressor 95098 * @constructor
95099 * @extends p5.Effect 95100 * 95101 * 95102 */ 95103 p5.Compressor = function () { 95104 Effect.call(this); 95105 /** 95106 * The p5.Compressor is built with a <a href="https://www.w3.org/TR/webaudio/#the-dynamicscompressornode-interface" 95107 * target="_blank" title="W3 spec for Dynamics Compressor Node">Web Audio Dynamics Compressor Node 95108 * </a> 95109 * @property {AudioNode} compressor 95110 */ 95111 this.compressor = this.ac.createDynamicsCompressor(); 95112 this.input.connect(this.compressor); 95113 this.compressor.connect(this.wet); 95114 }; 95115 p5.Compressor.prototype = Object.create(Effect.prototype); 95116 /** 95117 * Performs the same function as .connect, but also accepts 95118 * optional parameters to set compressor's audioParams 95119 * @method process 95120 * 95121 * @param {Object} src Sound source to be connected 95122 * 95123 * @param {Number} [attack] The amount of time (in seconds) to reduce the gain by 10dB, 95124 * default = .003, range 0 - 1 95125 * @param {Number} [knee] A decibel value representing the range above the 95126 * threshold where the curve smoothly transitions to the "ratio" portion. 95127 * default = 30, range 0 - 40 95128 * @param {Number} [ratio] The amount of dB change in input for a 1 dB change in output 95129 * default = 12, range 1 - 20 95130 * @param {Number} [threshold] The decibel value above which the compression will start taking effect 95131 * default = -24, range -100 - 0 95132 * @param {Number} [release] The amount of time (in seconds) to increase the gain by 10dB 95133 * default = .25, range 0 - 1 95134 */ 95135 p5.Compressor.prototype.process = function (src, attack, knee, ratio, threshold, release) { 95136 src.connect(this.input); 95137 this.set(attack, knee, ratio, threshold, release); 95138 }; 95139 /** 95140 * Set the paramters of a compressor. 95141 * @method set 95142 * @param {Number} attack The amount of time (in seconds) to reduce the gain by 10dB, 95143 * default = .003, range 0 - 1 95144 * @param {Number} knee A decibel value representing the range above the 95145 * threshold where the curve smoothly transitions to the "ratio" portion. 95146 * default = 30, range 0 - 40 95147 * @param {Number} ratio The amount of dB change in input for a 1 dB change in output 95148 * default = 12, range 1 - 20 95149 * @param {Number} threshold The decibel value above which the compression will start taking effect 95150 * default = -24, range -100 - 0 95151 * @param {Number} release The amount of time (in seconds) to increase the gain by 10dB 95152 * default = .25, range 0 - 1 95153 */ 95154 p5.Compressor.prototype.set = function (attack, knee, ratio, threshold, release) { 95155 if (typeof attack !== 'undefined') { 95156 this.attack(attack); 95157 } 95158 if (typeof knee !== 'undefined') { 95159 this.knee(knee); 95160 } 95161 if (typeof ratio !== 'undefined') { 95162 this.ratio(ratio); 95163 } 95164 if (typeof threshold !== 'undefined') { 95165 this.threshold(threshold); 95166 } 95167 if (typeof release !== 'undefined') { 95168 this.release(release); 95169 } 95170 }; 95171 /** 95172 * Get current attack or set value w/ time ramp 95173 * 95174 * 95175 * @method attack 95176 * @param {Number} [attack] Attack is the amount of time (in seconds) to reduce the gain by 10dB, 95177 * default = .003, range 0 - 1 95178 * @param {Number} [time] Assign time value to schedule the change in value 95179 */ 95180 p5.Compressor.prototype.attack = function (attack, time) { 95181 var t = time || 0; 95182 if (typeof attack == 'number') { 95183 this.compressor.attack.value = attack; 95184 this.compressor.attack.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 95185 this.compressor.attack.linearRampToValueAtTime(attack, this.ac.currentTime + 0.02 + t); 95186 } else if (typeof attack !== 'undefined') { 95187 attack.connect(this.compressor.attack); 95188 } 95189 return this.compressor.attack.value; 95190 }; 95191 /** 95192 * Get current knee or set value w/ time ramp 95193 * 95194 * @method knee 95195 * @param {Number} [knee] A decibel value representing the range above the 95196 * threshold where the curve smoothly transitions to the "ratio" portion. 95197 * default = 30, range 0 - 40 95198 * @param {Number} [time] Assign time value to schedule the change in value 95199 */ 95200 p5.Compressor.prototype.knee = function (knee, time) { 95201 var t = time || 0; 95202 if (typeof knee == 'number') { 95203 this.compressor.knee.value = knee; 95204 this.compressor.knee.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 95205 this.compressor.knee.linearRampToValueAtTime(knee, this.ac.currentTime + 0.02 + t); 95206 } else if (typeof knee !== 'undefined') { 95207 knee.connect(this.compressor.knee); 95208 } 95209 return this.compressor.knee.value; 95210 }; 95211 /** 95212 * Get current ratio or set value w/ time ramp 95213 * @method ratio 95214 * 95215 * @param {Number} [ratio] The amount of dB change in input for a 1 dB change in output 95216 * default = 12, range 1 - 20 95217 * @param {Number} [time] Assign time value to schedule the change in value 95218 */ 95219 p5.Compressor.prototype.ratio = function (ratio, time) { 95220 var t = time || 0; 95221 if (typeof ratio == 'number') { 95222 this.compressor.ratio.value = ratio; 95223 this.compressor.ratio.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 95224 this.compressor.ratio.linearRampToValueAtTime(ratio, this.ac.currentTime + 0.02 + t); 95225 } else if (typeof ratio !== 'undefined') { 95226 ratio.connect(this.compressor.ratio); 95227 } 95228 return this.compressor.ratio.value; 95229 }; 95230 /** 95231 * Get current threshold or set value w/ time ramp 95232 * @method threshold 95233 * 95234 * @param {Number} threshold The decibel value above which the compression will start taking effect 95235 * default = -24, range -100 - 0 95236 * @param {Number} [time] Assign time value to schedule the change in value 95237 */ 95238 p5.Compressor.prototype.threshold = function (threshold, time) { 95239 var t = time || 0; 95240 if (typeof threshold == 'number') { 95241 this.compressor.threshold.value = threshold; 95242 this.compressor.threshold.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 95243 this.compressor.threshold.linearRampToValueAtTime(threshold, this.ac.currentTime + 0.02 + t); 95244 } else if (typeof threshold !== 'undefined') { 95245 threshold.connect(this.compressor.threshold); 95246 } 95247 return this.compressor.threshold.value; 95248 }; 95249 /** 95250 * Get current release or set value w/ time ramp 95251 * @method release 95252 * 95253 * @param {Number} release The amount of time (in seconds) to increase the gain by 10dB 95254 * default = .25, range 0 - 1 95255 * 95256 * @param {Number} [time] Assign time value to schedule the change in value 95257 */ 95258 p5.Compressor.prototype.release = function (release, time) { 95259 var t = time || 0; 95260 if (typeof release == 'number') { 95261 this.compressor.release.value = release; 95262 this.compressor.release.cancelScheduledValues(this.ac.currentTime + 0.01 + t); 95263 this.compressor.release.linearRampToValueAtTime(release, this.ac.currentTime + 0.02 + t); 95264 } else if (typeof number !== 'undefined') { 95265 release.connect(this.compressor.release); 95266 } 95267 return this.compressor.release.value; 95268 }; 95269 /** 95270 * Return the current reduction value 95271 * 95272 * @method reduction 95273 * @return {Number} Value of the amount of gain reduction that is applied to the signal 95274 */ 95275 p5.Compressor.prototype.reduction = function () { 95276 return this.compressor.reduction.value; 95277 }; 95278 p5.Compressor.prototype.dispose = function () { 95279 Effect.prototype.dispose.apply(this); 95280 if (this.compressor) { 95281 this.compressor.disconnect(); 95282 delete this.compressor; 95283 } 95284 }; 95285 return p5.Compressor; 95286}(master, effect, errorHandler); 95287var soundRecorder; 95288'use strict'; 95289soundRecorder = function () { 95290 // inspiration: recorder.js, Tone.js & typedarray.org 95291 var p5sound = master; 95292 var convertToWav = helpers.convertToWav; 95293 var ac = p5sound.audiocontext; 95294 /** 95295 * <p>
95295Record sounds for playback and/or to save as a .wav file. 95296 * The p5.SoundRecorder records all sound output from your sketch, 95297 * or can be assigned a specific source with setInput().</p> 95298 * <p>The record() method accepts a p5.SoundFile as a parameter. 95299 * When playback is stopped (either after the given amount of time, 95300 * or with the stop() method), the p5.SoundRecorder will send its 95301 * recording to that p5.SoundFile for playback.</p> 95302 * 95303 * @class p5.SoundRecorder 95304 * @constructor 95305 * @example 95306 * <div><code> 95307 * var mic, recorder, soundFile; 95308 * var state = 0; 95309 * 95310 * function setup() { 95311 * background(200); 95312 * // create an audio in 95313 * mic = new p5.AudioIn(); 95314 * 95315 * // prompts user to enable their browser mic 95316 * mic.start(); 95317 * 95318 * // create a sound recorder 95319 * recorder = new p5.SoundRecorder(); 95320 * 95321 * // connect the mic to the recorder 95322 * recorder.setInput(mic); 95323 * 95324 * // this sound file will be used to 95325 * // playback & save the recording 95326 * soundFile = new p5.SoundFile(); 95327 * 95328 * text('keyPress to record', 20, 20); 95329 * } 95330 * 95331 * function keyPressed() { 95332 * // make sure user enabled the mic 95333 * if (state === 0 && mic.enabled) { 95334 * 95335 * // record to our p5.SoundFile 95336 * recorder.record(soundFile); 95337 * 95338 * background(255,0,0); 95339 * text('Recording!', 20, 20); 95340 * state++; 95341 * } 95342 * else if (state === 1) { 95343 * background(0,255,0); 95344 * 95345 * // stop recorder and 95346 * // send result to soundFile 95347 * recorder.stop(); 95348 * 95349 * text('Stopped', 20, 20); 95350 * state++; 95351 * } 95352 * 95353 * else if (state === 2) { 95354 * soundFile.play(); // play the result! 95355 * save(soundFile, 'mySound.wav'); 95356 * state++; 95357 * } 95358 * } 95359 * </div></code> 95360 */ 95361 p5.SoundRecorder = function () { 95362 this.input = ac.createGain(); 95363 this.output = ac.createGain(); 95364 this.recording = false; 95365 this.bufferSize = 1024; 95366 this._channels = 2; 95367 // stereo (default) 95368 this._clear(); 95369 // initialize variables 95370 this._jsNode = ac.createScriptProcessor(this.bufferSize, this._channels, 2); 95371 this._jsNode.onaudioprocess = this._audioprocess.bind(this); 95372 /** 95373 * callback invoked when the recording is over 95374 * @private 95375 * @type Function(Float32Array) 95376 */ 95377 this._callback = function () { 95378 }; 95379 // connections 95380 this._jsNode.connect(p5.soundOut._silentNode); 95381 this.setInput(); 95382 // add this p5.SoundFile to the soundArray 95383 p5sound.soundArray.push(this); 95384 }; 95385 /** 95386 * Connect a specific device to the p5.SoundRecorder. 95387 * If no parameter is given, p5.SoundRecorer will record 95388 * all audible p5.sound from your sketch. 95389 * 95390 * @method setInput 95391 * @param {Object} [unit] p5.sound object or a web audio unit 95392 * that outputs sound 95393 */ 95394 p5.SoundRecorder.prototype.setInput = function (unit) { 95395 this.input.disconnect(); 95396 this.input = null; 95397 this.input = ac.createGain(); 95398 this.input.connect(this._jsNode); 95399 this.input.connect(this.output); 95400 if (unit) { 95401 unit.connect(this.input); 95402 } else { 95403 p5.soundOut.output.connect(this.input); 95404 } 95405 }; 95406 /** 95407 * Start recording. To access the recording, provide 95408 * a p5.SoundFile as the first parameter. The p5.SoundRecorder 95409 * will send its recording to that p5.SoundFile for playback once 95410 * recording is complete. Optional parameters include duration 95411 * (in seconds) of the recording, and a callback function that 95412 * will be called once the complete recording has been 95413 * transfered to the p5.SoundFile. 95414 * 95415 * @method record 95416 * @param {p5.SoundFile} soundFile p5.SoundFile 95417 * @param {Number} [duration] Time (in seconds) 95418 * @param {Function} [callback] The name of a function that will be 95419 * called once the recording completes 95420 */ 95421 p5.SoundRecorder.prototype.record = function (sFile, duration, callback) { 95422 this.recording = true; 95423 if (duration) { 95424 this.sampleLimit = Math.round(duration * ac.sampleRate); 95425 } 95426 if (sFile && callback) { 95427 this._callback = function () { 95428 this.buffer = this._getBuffer(); 95429 sFile.setBuffer(this.buffer); 95430 callback(); 95431 }; 95432 } else if (sFile) { 95433 this._callback = function () { 95434 this.buffer = this._getBuffer(); 95435 sFile.setBuffer(this.buffer); 95436 }; 95437 } 95438 }; 95439 /** 95440 * Stop the recording. Once the recording is stopped, 95441 * the results will be sent to the p5.SoundFile that 95442 * was given on .record(), and if a callback function 95443 * was provided on record, that function will be called. 95444 * 95445 * @method stop 95446 */ 95447 p5.SoundRecorder.prototype.stop = function () { 95448 this.recording = false;
95449 this._callback(); 95450 this._clear(); 95451 }; 95452 p5.SoundRecorder.prototype._clear = function () { 95453 this._leftBuffers = []; 95454 this._rightBuffers = []; 95455 this.recordedSamples = 0; 95456 this.sampleLimit = null; 95457 }; 95458 /** 95459 * internal method called on audio process 95460 * 95461 * @private 95462 * @param {AudioProcessorEvent} event 95463 */ 95464 p5.SoundRecorder.prototype._audioprocess = function (event) { 95465 if (this.recording === false) { 95466 return; 95467 } else if (this.recording === true) { 95468 // if we are past the duration, then stop... else: 95469 if (this.sampleLimit && this.recordedSamples >= this.sampleLimit) { 95470 this.stop(); 95471 } else { 95472 // get channel data 95473 var left = event.inputBuffer.getChannelData(0); 95474 var right = event.inputBuffer.getChannelData(1); 95475 // clone the samples 95476 this._leftBuffers.push(new Float32Array(left)); 95477 this._rightBuffers.push(new Float32Array(right)); 95478 this.recordedSamples += this.bufferSize; 95479 } 95480 } 95481 }; 95482 p5.SoundRecorder.prototype._getBuffer = function () { 95483 var buffers = []; 95484 buffers.push(this._mergeBuffers(this._leftBuffers)); 95485 buffers.push(this._mergeBuffers(this._rightBuffers)); 95486 return buffers; 95487 }; 95488 p5.SoundRecorder.prototype._mergeBuffers = function (channelBuffer) { 95489 var result = new Float32Array(this.recordedSamples); 95490 var offset = 0; 95491 var lng = channelBuffer.length; 95492 for (var i = 0; i < lng; i++) { 95493 var buffer = channelBuffer[i]; 95494 result.set(buffer, offset); 95495 offset += buffer.length; 95496 } 95497 return result; 95498 }; 95499 p5.SoundRecorder.prototype.dispose = function () { 95500 this._clear(); 95501 // remove reference from soundArray 95502 var index = p5sound.soundArray.indexOf(this); 95503 p5sound.soundArray.splice(index, 1); 95504 this._callback = function () { 95505 }; 95506 if (this.input) { 95507 this.input.disconnect(); 95508 } 95509 this.input = null; 95510 this._jsNode = null; 95511 }; 95512 /** 95513 * Save a p5.SoundFile as a .wav file. The browser will prompt the user 95514 * to download the file to their device. 95515 * For uploading audio to a server, use 95516 * <a href="/docs/reference/#/p5.SoundFile/saveBlob">`p5.SoundFile.saveBlob`</a>. 95517 * 95518 * @for p5 95519 * @method saveSound 95520 * @param {p5.SoundFile} soundFile p5.SoundFile that you wish to save 95521 * @param {String} fileName name of the resulting .wav file. 95522 */ 95523 // add to p5.prototype as this is used by the p5 `save()` method. 95524 p5.prototype.saveSound = function (soundFile, fileName) { 95525 const dataView = convertToWav(soundFile.buffer); 95526 p5.prototype.writeFile([dataView], fileName, 'wav'); 95527 }; 95528}(master, helpers); 95529var peakdetect; 95530'use strict'; 95531peakdetect = function () { 95532 /** 95533 * <p>PeakDetect works in conjunction with p5.FFT to 95534 * look for onsets in some or all of the frequency spectrum. 95535 * </p> 95536 * <p> 95537 * To use p5.PeakDetect, call <code>update</code> in the draw loop 95538 * and pass in a p5.FFT object. 95539 * </p> 95540 * <p> 95541 * You can listen for a specific part of the frequency spectrum by 95542 * setting the range between <code>freq1</code> and <code>freq2</code>. 95543 * </p> 95544 * 95545 * <p><code>threshold</code> is the threshold for detecting a peak, 95546 * scaled between 0 and 1. It is logarithmic, so 0.1 is half as loud 95547 * as 1.0.</p> 95548 * 95549 * <p> 95550 * The update method is meant to be run in the draw loop, and 95551 * <b>frames</b> determines how many loops must pass before 95552 * another peak can be detected. 95553 * For example, if the frameRate() = 60, you could detect the beat of a 95554 * 120 beat-per-minute song with this equation: 95555 * <code> framesPerPeak = 60 / (estimatedBPM / 60 );</code> 95556 * </p> 95557 * 95558 * <p> 95559 * Based on example contribtued by @b2renger, and a simple beat detection 95560 * explanation by <a 95561 * href="http://www.airtightinteractive.com/2013/10/making-audio-reactive-visuals/" 95562 * target="_blank">Felix Turner</a>. 95563 * </p> 95564 * 95565 * @class p5.PeakDetect 95566 * @constructor 95567 * @param {Number} [freq1] lowFrequency - defaults to 20Hz 95568 * @param {Number} [freq2] highFrequency - defaults to 20000 Hz 95569 * @param {Number} [threshold] Threshold for detecting a beat between 0 and 1 95570 * scaled logarithmically where 0.1 is 1/2 the loudness 95571 * of 1.0. Defaults to 0.35. 95572 * @param {Number} [framesPerPeak] Defaults to 20. 95573 * @example 95574 * <div><code> 95575 * 95576 * var cnv, soundFile, fft, peakDetect; 95577 * var ellipseWidth = 10; 95578 * 95579 * function preload() { 95580 * soundFile = loadSound('assets/beat.mp3'); 95581 * } 95582 * 95583 * function setup() { 95584 * background(0); 95585 * noStroke(); 95586 * fill(255); 95587 * textAlign(CENTER); 95588 * 95589 * // p5.PeakDetect requires a p5.FFT 95590 * fft = new p5.FFT(); 95591 * peakDetect = new p5.PeakDetect(); 95592 * } 95593 * 95594 * function draw() { 95595 * background(0); 95596 * text('click to play/pause', width/2, height/2); 95597 * 95598 * // peakDetect accepts an fft post-analysis 95599 * fft.analyze(); 95600 * peakDetect.update(fft); 95601 * 95602 * if ( peakDetect.isDetected ) { 95603 * ellipseWidth = 50; 95604 * } else { 95605 * ellipseWidth *= 0.95; 95606 * } 95607 * 95608 * ellipse(width/2, height/2, ellipseWidth, ellipseWidth); 95609 * } 95610 * 95611 * // toggle play/stop when canvas is clicked 95612 * function mouseClicked() { 95613 * if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { 95614 * if (soundFile.isPlaying() ) { 95615 * soundFile.stop(); 95616 * } else { 95617 * soundFile.play(); 95618 * } 95619 * } 95620 * } 95621 * </code></div> 95622 */ 95623 p5.PeakDetect = function (freq1, freq2, threshold, _framesPerPeak) { 95624 // framesPerPeak determines how often to look for a beat. 95625 // If a beat is provided, try to look for a beat based on bpm 95626 this.framesPerPeak = _framesPerPeak || 20; 95627 this.framesSinceLastPeak = 0; 95628 this.decayRate = 0.95; 95629 this.threshold = threshold || 0.35; 95630 this.cutoff = 0; 95631 // how much to increase the cutoff 95632 // TO DO: document this / figure out how to make it accessible 95633 this.cutoffMult = 1.5; 95634 this.energy = 0; 95635 this.penergy = 0; 95636 // TO DO: document this property / figure out how to make it accessible 95637 this.currentValue = 0; 95638 /** 95639 * isDetected is set to true when a peak is detected. 95640 * 95641 * @attribute isDetected {Boolean} 95642 * @default false 95643 */ 95644 this.isDetected = false;
95645 this.f1 = freq1 || 40; 95646 this.f2 = freq2 || 20000; 95647 // function to call when a peak is detected 95648 this._onPeak = function () { 95649 }; 95650 }; 95651 /** 95652 * The update method is run in the draw loop. 95653 * 95654 * Accepts an FFT object. You must call .analyze() 95655 * on the FFT object prior to updating the peakDetect 95656 * because it relies on a completed FFT analysis. 95657 * 95658 * @method update 95659 * @param {p5.FFT} fftObject A p5.FFT object 95660 */ 95661 p5.PeakDetect.prototype.update = function (fftObject) { 95662 var nrg = this.energy = fftObject.getEnergy(this.f1, this.f2) / 255; 95663 if (nrg > this.cutoff && nrg > this.threshold && nrg - this.penergy > 0) { 95664 // trigger callback 95665 this._onPeak(); 95666 this.isDetected = true; 95667 // debounce 95668 this.cutoff = nrg * this.cutoffMult; 95669 this.framesSinceLastPeak = 0; 95670 } else { 95671 this.isDetected = false; 95672 if (this.framesSinceLastPeak <= this.framesPerPeak) { 95673 this.framesSinceLastPeak++; 95674 } else { 95675 this.cutoff *= this.decayRate; 95676 this.cutoff = Math.max(this.cutoff, this.threshold); 95677 } 95678 } 95679 this.currentValue = nrg; 95680 this.penergy = nrg; 95681 }; 95682 /** 95683 * onPeak accepts two arguments: a function to call when 95684 * a peak is detected. The value of the peak, 95685 * between 0.0 and 1.0, is passed to the callback. 95686 * 95687 * @method onPeak 95688 * @param {Function} callback Name of a function that will 95689 * be called when a peak is 95690 * detected. 95691 * @param {Object} [val] Optional value to pass 95692 * into the function when 95693 * a peak is detected. 95694 * @example 95695 * <div><code> 95696 * var cnv, soundFile, fft, peakDetect; 95697 * var ellipseWidth = 0; 95698 * 95699 * function preload() { 95700 * soundFile = loadSound('assets/beat.mp3'); 95701 * } 95702 * 95703 * function setup() { 95704 * cnv = createCanvas(100,100); 95705 * textAlign(CENTER); 95706 * 95707 * fft = new p5.FFT(); 95708 * peakDetect = new p5.PeakDetect(); 95709 * 95710 * setupSound(); 95711 * 95712 * // when a beat is detected, call triggerBeat() 95713 * peakDetect.onPeak(triggerBeat); 95714 * } 95715 * 95716 * function draw() { 95717 * background(0); 95718 * fill(255); 95719 * text('click to play', width/2, height/2); 95720 * 95721 * fft.analyze(); 95722 * peakDetect.update(fft); 95723 * 95724 * ellipseWidth *= 0.95; 95725 * ellipse(width/2, height/2, ellipseWidth, ellipseWidth); 95726 * } 95727 * 95728 * // this function is called by peakDetect.onPeak 95729 * function triggerBeat() { 95730 * ellipseWidth = 50; 95731 * } 95732 * 95733 * // mouseclick starts/stops sound 95734 * function setupSound() { 95735 * cnv.mouseClicked( function() { 95736 * if (soundFile.isPlaying() ) { 95737 * soundFile.stop(); 95738 * } else { 95739 * soundFile.play(); 95740 * } 95741 * }); 95742 * } 95743 * </code></div> 95744 */ 95745 p5.PeakDetect.prototype.onPeak = function (callback, val) { 95746 var self = this; 95747 self._onPeak = function () { 95748 callback(self.energy, val); 95749 }; 95750 }; 95751}(); 95752var gain; 95753'use strict'; 95754gain = function () { 95755 var p5sound = master; 95756 /** 95757 * A gain node is usefull to set the relative volume of sound. 95758 * It's typically used to build mixers. 95759 * 95760 * @class p5.Gain 95761 * @constructor 95762 * @example 95763 * <div><code> 95764 * 95765 * // load two soundfile and crossfade beetween them 95766 * var sound1,sound2; 95767 * var gain1, gain2, gain3; 95768 * 95769 * function preload(){ 95770 * soundFormats('ogg', 'mp3'); 95771 * sound1 = loadSound('assets/Damscray_-_Dancing_Tiger_01'); 95772 * sound2 = loadSound('assets/beat.mp3'); 95773 * } 95774 * 95775 * function setup() { 95776 * createCanvas(400,200); 95777 * 95778 * // create a 'master' gain to which we will connect both soundfiles 95779 * gain3 = new p5.Gain(); 95780 * gain3.connect(); 95781 * 95782 * // setup first sound for playing 95783 * sound1.rate(1); 95784 * sound1.loop(); 95785 * sound1.disconnect(); // diconnect from p5 output 95786 * 95787 * gain1 = new p5.Gain(); // setup a gain node 95788 * gain1.setInput(sound1); // connect the first sound to its input 95789 * gain1.connect(gain3); // connect its output to the 'master' 95790 * 95791 * sound2.rate(1); 95792 * sound2.disconnect(); 95793 * sound2.loop(); 95794 * 95795 * gain2 = new p5.Gain(); 95796 * gain2.setInput(sound2); 95797 * gain2.connect(gain3); 95798 * 95799 * } 95800 * 95801 * function draw(){ 95802 * background(180); 95803 * 95804 * // calculate the horizontal distance beetween the mouse and the right of the screen 95805 * var d = dist(mouseX,0,width,0); 95806 * 95807 * // map the horizontal position of the mouse to values useable for volume control of sound1 95808 * var vol1 = map(mouseX,0,width,0,1); 95809 * var vol2 = 1-vol1; // when sound1 is loud, sound2 is quiet and vice versa 95810 * 95811 * gain1.amp(vol1,0.5,0); 95812 * gain2.amp(vol2,0.5,0); 95813 * 95814 * // map the vertical position of the mouse to values useable for 'master volume control' 95815 * var vol3 = map(mouseY,0,height,0,1); 95816 * gain3.amp(vol3,0.5,0); 95817 * } 95818 *</code></div> 95819 * 95820 */ 95821 p5.Gain = function () { 95822 this.ac = p5sound.audiocontext; 95823 this.input = this.ac.createGain(); 95824 this.output = this.ac.createGain(); 95825 // otherwise, Safari distorts 95826 this.input.gain.value = 0.5; 95827 this.input.connect(this.output); 95828 // add to the soundArray 95829 p5sound.soundArray.push(this); 95830 }; 95831 /** 95832 * Connect a source to the gain node. 95833 * 95834 * @method setInput 95835 * @param {Object} src p5.sound / Web Audio object with a sound 95836 * output. 95837 */ 95838 p5.Gain.prototype.setInput = function (src) { 95839 src.connect(this.input); 95840 }; 95841 /** 95842 * Send output to a p5.sound or web audio object 95843 * 95844 * @method connect 95845 * @param {Object} unit 95846 */ 95847 p5.Gain.prototype.connect = function (unit) { 95848 var u = unit || p5.soundOut.input; 95849 this.output.connect(u.input ? u.input : u); 95850 }; 95851 /** 95852 * Disconnect all output. 95853 * 95854 * @method disconnect 95855 */ 95856 p5.Gain.prototype.disconnect = function () { 95857 if (this.output) { 95858 this.output.disconnect(); 95859 } 95860 }; 95861 /** 95862 * Set the output level of the gain node. 95863 * 95864 * @method amp 95865 * @param {Number} volume amplitude between 0 and 1.0 95866 * @param {Number} [rampTime] create a fade that lasts rampTime 95867 * @param {Number} [timeFromNow] schedule this event to happen 95868 * seconds from now 95869 */ 95870 p5.Gain.prototype.amp = function (vol, rampTime, tFromNow) { 95871 var rampTime = rampTime || 0; 95872 var tFromNow = tFromNow || 0; 95873 var now = p5sound.audiocontext.currentTime; 95874 var currentVol = this.output.gain.value; 95875 this.output.gain.cancelScheduledValues(now); 95876 this.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow); 95877 this.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime); 95878 }; 95879 p5.Gain.prototype.dispose = function () { 95880 // remove reference from soundArray 95881 var index = p5sound.soundArray.indexOf(this); 95882 p5sound.soundArray.splice(index, 1); 95883 if (this.output) { 95884 this.output.disconnect(); 95885 delete this.output; 95886 } 95887 if (this.input) { 95888 this.input.disconnect(); 95889 delete this.input; 95890 } 95891 }; 95892}(master); 95893var audioVoice; 95894'use strict'; 95895audioVoice = function () { 95896 var p5sound = master; 95897 /** 95898 * Base class for monophonic synthesizers. Any extensions of this class 95899 * should follow the API and implement the methods below in order to 95900 * remain compatible with p5.PolySynth(); 95901 * 95902 * @class p5.AudioVoice 95903 * @constructor 95904 */ 95905 p5.AudioVoice = function () { 95906 this.ac = p5sound.audiocontext; 95907 this.output = this.ac.createGain(); 95908 this.connect(); 95909 p5sound.soundArray.push(this); 95910 }; 95911 p5.AudioVoice.prototype.play = function (note, velocity, secondsFromNow, sustime) { 95912 }; 95913 p5.AudioVoice.prototype.triggerAttack = function (note, velocity, secondsFromNow) { 95914 }; 95915 p5.AudioVoice.prototype.triggerRelease = function (secondsFromNow) { 95916 }; 95917 p5.AudioVoice.prototype.amp = function (vol, rampTime) { 95918 }; 95919 /** 95920 * Connect to p5 objects or Web Audio Nodes 95921 * @method connect 95922 * @param {Object} unit 95923 */ 95924 p5.AudioVoice.prototype.connect = function (unit) { 95925 var u = unit || p5sound.input; 95926 this.output.connect(u.input ? u.input : u); 95927 }; 95928 /** 95929 * Disconnect from soundOut 95930 * @method disconnect 95931 */ 95932 p5.AudioVoice.prototype.disconnect = function () { 95933 this.output.disconnect(); 95934 }; 95935 p5.AudioVoice.prototype.dispose = function () { 95936 if (this.output) { 95937 this.output.disconnect(); 95938 delete this.output; 95939 } 95940 }; 95941 return p5.AudioVoice; 95942}(master); 95943var monosynth; 95944'use strict'; 95945monosynth = function () { 95946 var p5sound = master; 95947 var AudioVoice = audioVoice; 95948 var noteToFreq = helpers.noteToFreq; 95949 var DEFAULT_SUSTAIN = 0.15; 95950 /** 95951 * A MonoSynth is used as a single voice for sound synthesis. 95952 * This is a class to be used in conjunction with the PolySynth 95953 * class. Custom synthetisers should be built inheriting from 95954 * this class. 95955 * 95956 * @class p5.MonoSynth 95957 * @constructor 95958 * @example 95959 * <div><code> 95960 * var monoSynth; 95961 * 95962 * function setup() { 95963 * var cnv = createCanvas(100, 100); 95964 * cnv.mousePressed(playSynth); 95965 * 95966 * monoSynth = new p5.MonoSynth(); 95967 * 95968 * textAlign(CENTER); 95969 * text('click to play', width/2, height/2); 95970 * } 95971 * 95972 * function playSynth() { 95973 * // time from now (in seconds) 95974 * var time = 0; 95975 * // note duration (in seconds) 95976 * var dur = 0.25; 95977 * // velocity (volume, from 0 to 1) 95978 * var v = 0.2; 95979 * 95980 * monoSynth.play("G3", v, time, dur);
95981 * monoSynth.play("C4", v, time += dur, dur); 95982 * 95983 * background(random(255), random(255), 255); 95984 * text('click to play', width/2, height/2); 95985 * } 95986 * </code></div> 95987 **/ 95988 p5.MonoSynth = function () { 95989 AudioVoice.call(this); 95990 this.oscillator = new p5.Oscillator(); 95991 this.env = new p5.Envelope(); 95992 this.env.setRange(1, 0); 95993 this.env.setExp(true); 95994 //set params 95995 this.setADSR(0.02, 0.25, 0.05, 0.35); 95996 // oscillator --> env --> this.output (gain) --> p5.soundOut 95997 this.oscillator.disconnect(); 95998 this.oscillator.connect(this.output); 95999 this.env.disconnect(); 96000 this.env.setInput(this.output.gain); 96001 // reset oscillator gain to 1.0 96002 this.oscillator.output.gain.value = 1; 96003 this.oscillator.start(); 96004 this.connect(); 96005 p5sound.soundArray.push(this); 96006 }; 96007 p5.MonoSynth.prototype = Object.create(p5.AudioVoice.prototype); 96008 /** 96009 * Play tells the MonoSynth to start playing a note. This method schedules 96010 * the calling of .triggerAttack and .triggerRelease. 96011 * 96012 * @method play 96013 * @param {String | Number} note the note you want to play, specified as a 96014 * frequency in Hertz (Number) or as a midi 96015 * value in Note/Octave format ("C4", "Eb3"...etc") 96016 * See <a href = "https://github.com/Tonejs/Tone.js/wiki/Instruments"> 96017 * Tone</a>. Defaults to 440 hz. 96018 * @param {Number} [velocity] velocity of the note to play (ranging from 0 to 1) 96019 * @param {Number} [secondsFromNow] time from now (in seconds) at which to play 96020 * @param {Number} [sustainTime] time to sustain before releasing the envelope 96021 * @example 96022 * <div><code> 96023 * var monoSynth; 96024 * 96025 * function setup() { 96026 * var cnv = createCanvas(100, 100); 96027 * cnv.mousePressed(playSynth); 96028 * 96029 * monoSynth = new p5.MonoSynth(); 96030 * 96031 * textAlign(CENTER); 96032 * text('click to play', width/2, height/2); 96033 * } 96034 * 96035 * function playSynth() { 96036 * // time from now (in seconds) 96037 * var time = 0; 96038 * // note duration (in seconds) 96039 * var dur = 1/6; 96040 * // note velocity (volume, from 0 to 1) 96041 * var v = random(); 96042 * 96043 * monoSynth.play("Fb3", v, 0, dur); 96044 * monoSynth.play("Gb3", v, time += dur, dur); 96045 * 96046 * background(random(255), random(255), 255); 96047 * text('click to play', width/2, height/2); 96048 * } 96049 * </code></div> 96050 * 96051 */ 96052 p5.MonoSynth.prototype.play = function (note, velocity, secondsFromNow, susTime) { 96053 this.triggerAttack(note, velocity, ~~secondsFromNow); 96054 this.triggerRelease(~~secondsFromNow + (susTime || DEFAULT_SUSTAIN)); 96055 }; 96056 /** 96057 * Trigger the Attack, and Decay portion of the Envelope. 96058 * Similar to holding down a key on a piano, but it will 96059 * hold the sustain level until you let go. 96060 * 96061 * @param {String | Number} note the note you want to play, specified as a 96062 * frequency in Hertz (Number) or as a midi 96063 * value in Note/Octave format ("C4", "Eb3"...etc") 96064 * See <a href = "https://github.com/Tonejs/Tone.js/wiki/Instruments"> 96065 * Tone</a>. Defaults to 440 hz 96066 * @param {Number} [velocity] velocity of the note to play (ranging from 0 to 1) 96067 * @param {Number} [secondsFromNow] time from now (in seconds) at which to play 96068 * @method triggerAttack 96069 * @example 96070 * <div><code> 96071 * var monoSynth = new p5.MonoSynth(); 96072 * 96073 * function mousePressed() { 96074 * monoSynth.triggerAttack("E3"); 96075 * } 96076 * 96077 * function mouseReleased() { 96078 * monoSynth.triggerRelease(); 96079 * } 96080 * </code></div> 96081 */ 96082 p5.MonoSynth.prototype.triggerAttack = function (note, velocity, secondsFromNow) { 96083 var secondsFromNow = ~~secondsFromNow; 96084 var freq = noteToFreq(note); 96085 var vel = velocity || 0.1; 96086 this.oscillator.freq(freq, 0, secondsFromNow); 96087 this.env.ramp(this.output.gain, secondsFromNow, vel); 96088 }; 96089 /** 96090 * Trigger the release of the Envelope. This is similar to releasing 96091 * the key on a piano and letting the sound fade according to the 96092 * release level and release time. 96093 * 96094 * @param {Number} secondsFromNow time to trigger the release 96095 * @method triggerRelease 96096 * @example 96097 * <div><code> 96098 * var monoSynth = new p5.MonoSynth(); 96099 * 96100 * function mousePressed() { 96101 * monoSynth.triggerAttack("E3"); 96102 * } 96103 * 96104 * function mouseReleased() { 96105 * monoSynth.triggerRelease(); 96106 * } 96107 * </code></div> 96108 */ 96109 p5.MonoSynth.prototype.triggerRelease = function (secondsFromNow) { 96110 var secondsFromNow = secondsFromNow || 0; 96111 this.env.ramp(this.output.gain, secondsFromNow, 0); 96112 }; 96113 /** 96114 * Set values like a traditional 96115 * <a href="https://en.wikipedia.org/wiki/Synthesizer#/media/File:ADSR_parameter.svg"> 96116 * ADSR envelope 96117 * </a>. 96118 * 96119 * @method setADSR 96120 * @param {Number} attackTime Time (in seconds before envelope 96121 * reaches Attack Level 96122 * @param {Number} [decayTime] Time (in seconds) before envelope 96123 * reaches Decay/Sustain Level 96124 * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, 96125 * where 1.0 = attackLevel, 0.0 = releaseLevel. 96126 * The susRatio determines the decayLevel and the level at which the 96127 * sustain portion of the envelope will sustain. 96128 * For example, if attackLevel is 0.4, releaseLevel is 0, 96129 * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is 96130 * increased to 1.0 (using <code>setRange</code>), 96131 * then decayLevel would increase proportionally, to become 0.5. 96132 * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) 96133 */ 96134 p5.MonoSynth.prototype.setADSR = function (attack, decay, sustain, release) { 96135 this.env.setADSR(attack, decay, sustain, release); 96136 }; 96137 /** 96138 * Getters and Setters 96139 * @property {Number} attack 96140 */ 96141 /** 96142 * @property {Number} decay 96143 */ 96144 /** 96145 * @property {Number} sustain 96146 */ 96147 /** 96148 * @property {Number} release 96149 */ 96150 Object.defineProperties(p5.MonoSynth.prototype, { 96151 'attack': { 96152 get: function () { 96153 return this.env.aTime; 96154 }, 96155 set: function (attack) { 96156 this.env.setADSR(attack, this.env.dTime, this.env.sPercent, this.env.rTime); 96157 } 96158 }, 96159 'decay': { 96160 get: function () { 96161 return this.env.dTime; 96162 }, 96163 set: function (decay) { 96164 this.env.setADSR(this.env.aTime, decay, this.env.sPercent, this.env.rTime); 96165 } 96166 }, 96167 'sustain': { 96168 get: function () { 96169 return this.env.sPercent; 96170 }, 96171 set: function (sustain) { 96172 this.env.setADSR(this.env.aTime, this.env.dTime, sustain, this.env.rTime); 96173 } 96174 }, 96175 'release': { 96176 get: function () { 96177 return this.env.rTime; 96178 }, 96179 set: function (release) { 96180 this.env.setADSR(this.env.aTime, this.env.dTime, this.env.sPercent, release); 96181 } 96182 } 96183 }); 96184 /** 96185 * MonoSynth amp 96186 * @method amp 96187 * @param {Number} vol desired volume 96188 * @param {Number} [rampTime] Time to reach new volume 96189 * @return {Number} new volume value 96190 */ 96191 p5.MonoSynth.prototype.amp = function (vol, rampTime) { 96192 var t = rampTime || 0; 96193 if (typeof vol !== 'undefined') { 96194 this.oscillator.amp(vol, t); 96195 } 96196 return this.oscillator.amp().value; 96197 }; 96198 /** 96199 * Connect to a p5.sound / Web Audio object. 96200 * 96201 * @method connect 96202 * @param {Object} unit A p5.sound or Web Audio object 96203 */ 96204 p5.MonoSynth.prototype.connect = function (unit) { 96205 var u = unit || p5sound.input; 96206 this.output.connect(u.input ? u.input : u); 96207 }; 96208 /** 96209 * Disconnect all outputs 96210 * 96211 * @method disconnect 96212 */ 96213 p5.MonoSynth.prototype.disconnect = function () { 96214 if (this.output) { 96215 this.output.disconnect(); 96216 } 96217 }; 96218 /** 96219 * Get rid of the MonoSynth and free up its resources / memory. 96220 * 96221 * @method dispose 96222 */ 96223 p5.MonoSynth.prototype.dispose = function () { 96224 AudioVoice.prototype.dispose.apply(this); 96225 if (this.env) { 96226 this.env.dispose(); 96227 } 96228 if (this.oscillator) { 96229 this.oscillator.dispose(); 96230 } 96231 }; 96232}(master, audioVoice, helpers); 96233var polysynth; 96234'use strict'; 96235polysynth = function () { 96236 var p5sound = master; 96237 var TimelineSignal = Tone_signal_TimelineSignal; 96238 var noteToFreq = helpers.noteToFreq; 96239 /** 96240 * An AudioVoice is used as a single voice for sound synthesis. 96241 * The PolySynth class holds an array of AudioVoice, and deals 96242 * with voices allocations, with setting notes to be played, and 96243 * parameters to be set. 96244 * 96245 * @class p5.PolySynth 96246 * @constructor 96247 * 96248 * @param {Number} [synthVoice] A monophonic synth voice inheriting 96249 * the AudioVoice class. Defaults to p5.MonoSynth 96250 * @param {Number} [maxVoices] Number of voices, defaults to 8; 96251 * @example 96252 * <div><code> 96253 * var polySynth; 96254 * 96255 * function setup() { 96256 * var cnv = createCanvas(100, 100); 96257 * cnv.mousePressed(playSynth); 96258 * 96259 * polySynth = new p5.PolySynth(); 96260 * 96261 * textAlign(CENTER); 96262 * text('click to play', width/2, height/2); 96263 * } 96264 * 96265 * function playSynth() { 96266 * // note duration (in seconds) 96267 * var dur = 1.5; 96268 * 96269 * // time from now (in seconds) 96270 * var time = 0; 96271 * 96272 * // velocity (volume, from 0 to 1) 96273 * var vel = 0.1; 96274 * 96275 * // notes can overlap with each other 96276 * polySynth.play("G2", vel, 0, dur);
96277 * polySynth.play("C3", vel, time += 1/3, dur); 96278 * polySynth.play("G3", vel, time += 1/3, dur); 96279 * 96280 * background(random(255), random(255), 255); 96281 * text('click to play', width/2, height/2); 96282 * } 96283 * </code></div> 96284 **/ 96285 p5.PolySynth = function (audioVoice, maxVoices) { 96286 //audiovoices will contain maxVoices many monophonic synths 96287 this.audiovoices = []; 96288 /** 96289 * An object that holds information about which notes have been played and 96290 * which notes are currently being played. New notes are added as keys 96291 * on the fly. While a note has been attacked, but not released, the value of the 96292 * key is the audiovoice which is generating that note. When notes are released, 96293 * the value of the key becomes undefined. 96294 * @property notes 96295 */ 96296 this.notes = {}; 96297 //indices of the most recently used, and least recently used audiovoice 96298 this._newest = 0; 96299 this._oldest = 0; 96300 /** 96301 * A PolySynth must have at least 1 voice, defaults to 8 96302 * @property polyvalue 96303 */ 96304 this.maxVoices = maxVoices || 8; 96305 /** 96306 * Monosynth that generates the sound for each note that is triggered. The 96307 * p5.PolySynth defaults to using the p5.MonoSynth as its voice. 96308 * @property AudioVoice 96309 */ 96310 this.AudioVoice = audioVoice === undefined ? p5.MonoSynth : audioVoice; 96311 /** 96312 * This value must only change as a note is attacked or released. Due to delay 96313 * and sustain times, Tone.TimelineSignal is required to schedule the change in value. 96314 * @private 96315 * @property {Tone.TimelineSignal} _voicesInUse 96316 */ 96317 this._voicesInUse = new TimelineSignal(0); 96318 this.output = p5sound.audiocontext.createGain(); 96319 this.connect(); 96320 //Construct the appropriate number of audiovoices 96321 this._allocateVoices(); 96322 p5sound.soundArray.push(this); 96323 }; 96324 /** 96325 * Construct the appropriate number of audiovoices 96326 * @private 96327 * @method _allocateVoices 96328 */ 96329 p5.PolySynth.prototype._allocateVoices = function () { 96330 for (var i = 0; i < this.maxVoices; i++) { 96331 this.audiovoices.push(new this.AudioVoice()); 96332 this.audiovoices[i].disconnect(); 96333 this.audiovoices[i].connect(this.output); 96334 } 96335 }; 96336 /** 96337 * Play a note by triggering noteAttack and noteRelease with sustain time 96338 * 96339 * @method play 96340 * @param {Number} [note] midi note to play (ranging from 0 to 127 - 60 being a middle C) 96341 * @param {Number} [velocity] velocity of the note to play (ranging from 0 to 1) 96342 * @param {Number} [secondsFromNow] time from now (in seconds) at which to play 96343 * @param {Number} [sustainTime] time to sustain before releasing the envelope 96344 * @example 96345 * <div><code> 96346 * var polySynth; 96347 * 96348 * function setup() { 96349 * var cnv = createCanvas(100, 100); 96350 * cnv.mousePressed(playSynth); 96351 * 96352 * polySynth = new p5.PolySynth(); 96353 * 96354 * textAlign(CENTER); 96355 * text('click to play', width/2, height/2); 96356 * } 96357 * 96358 * function playSynth() { 96359 * // note duration (in seconds) 96360 * var dur = 0.1; 96361 * 96362 * // time from now (in seconds) 96363 * var time = 0; 96364 * 96365 * // velocity (volume, from 0 to 1) 96366 * var vel = 0.1; 96367 * 96368 * polySynth.play("G2", vel, 0, dur); 96369 * polySynth.play("C3", vel, 0, dur); 96370 * polySynth.play("G3", vel, 0, dur); 96371 * 96372 * background(random(255), random(255), 255); 96373 * text('click to play', width/2, height/2); 96374 * } 96375 * </code></div> 96376 */ 96377 p5.PolySynth.prototype.play = function (note, velocity, secondsFromNow, susTime) { 96378 var susTime = susTime || 1; 96379 this.noteAttack(note, velocity, secondsFromNow); 96380 this.noteRelease(note, secondsFromNow + susTime); 96381 }; 96382 /** 96383 * noteADSR sets the envelope for a specific note that has just been triggered. 96384 * Using this method modifies the envelope of whichever audiovoice is being used 96385 * to play the desired note. The envelope should be reset before noteRelease is called 96386 * in order to prevent the modified envelope from being used on other notes. 96387 * 96388 * @method noteADSR 96389 * @param {Number} [note] Midi note on which ADSR should be set. 96390 * @param {Number} [attackTime] Time (in seconds before envelope 96391 * reaches Attack Level 96392 * @param {Number} [decayTime] Time (in seconds) before envelope 96393 * reaches Decay/Sustain Level 96394 * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, 96395 * where 1.0 = attackLevel, 0.0 = releaseLevel. 96396 * The susRatio determines the decayLevel and the level at which the 96397 * sustain portion of the envelope will sustain. 96398 * For example, if attackLevel is 0.4, releaseLevel is 0, 96399 * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is 96400 * increased to 1.0 (using <code>setRange</code>), 96401 * then decayLevel would increase proportionally, to become 0.5. 96402 * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) 96403 **/ 96404 p5.PolySynth.prototype.noteADSR = function (note, a, d, s, r, timeFromNow) { 96405 var now = p5sound.audiocontext.currentTime; 96406 var timeFromNow = timeFromNow || 0; 96407 var t = now + timeFromNow; 96408 this.audiovoices[this.notes[note].getValueAtTime(t)].setADSR(a, d, s, r); 96409 }; 96410 /** 96411 * Set the PolySynths global envelope. This method modifies the envelopes of each 96412 * monosynth so that all notes are played with this envelope. 96413 * 96414 * @method setADSR 96415 * @param {Number} [attackTime] Time (in seconds before envelope 96416 * reaches Attack Level 96417 * @param {Number} [decayTime] Time (in seconds) before envelope 96418 * reaches Decay/Sustain Level 96419 * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, 96420 * where 1.0 = attackLevel, 0.0 = releaseLevel. 96421 * The susRatio determines the decayLevel and the level at which the 96422 * sustain portion of the envelope will sustain. 96423 * For example, if attackLevel is 0.4, releaseLevel is 0, 96424 * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is 96425 * increased to 1.0 (using <code>setRange</code>), 96426 * then decayLevel would increase proportionally, to become 0.5. 96427 * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) 96428 **/ 96429 p5.PolySynth.prototype.setADSR = function (a, d, s, r) {
96430 this.audiovoices.forEach(function (voice) { 96431 voice.setADSR(a, d, s, r); 96432 }); 96433 }; 96434 /** 96435 * Trigger the Attack, and Decay portion of a MonoSynth. 96436 * Similar to holding down a key on a piano, but it will 96437 * hold the sustain level until you let go. 96438 * 96439 * @method noteAttack 96440 * @param {Number} [note] midi note on which attack should be triggered. 96441 * @param {Number} [velocity] velocity of the note to play (ranging from 0 to 1)/ 96442 * @param {Number} [secondsFromNow] time from now (in seconds) 96443 * @example 96444 * <div><code> 96445 * var polySynth = new p5.PolySynth(); 96446 * var pitches = ["G", "D", "G", "C"]; 96447 * var octaves = [2, 3, 4]; 96448 * 96449 * function mousePressed() { 96450 * // play a chord: multiple notes at the same time 96451 * for (var i = 0; i < 4; i++) { 96452 * var note = random(pitches) + random(octaves); 96453 * polySynth.noteAttack(note, 0.1); 96454 * } 96455 * } 96456 * 96457 * function mouseReleased() { 96458 * // release all voices 96459 * polySynth.noteRelease(); 96460 * } 96461 * </code></div> 96462 */ 96463 p5.PolySynth.prototype.noteAttack = function (_note, _velocity, secondsFromNow) { 96464 //this value goes to the audiovoices which handle their own scheduling 96465 var secondsFromNow = ~~secondsFromNow; 96466 //this value is used by this._voicesInUse 96467 var acTime = p5sound.audiocontext.currentTime + secondsFromNow; 96468 //Convert note to frequency if necessary. This is because entries into this.notes 96469 //should be based on frequency for the sake of consistency. 96470 var note = noteToFreq(_note); 96471 var velocity = _velocity || 0.1; 96472 var currentVoice; 96473 //Release the note if it is already playing 96474 if (this.notes[note] && this.notes[note].getValueAtTime(acTime) !== null) { 96475 this.noteRelease(note, 0); 96476 } 96477 //Check to see how many voices are in use at the time the note will start 96478 if (this._voicesInUse.getValueAtTime(acTime) < this.maxVoices) { 96479 currentVoice = Math.max(~~this._voicesInUse.getValueAtTime(acTime), 0); 96480 } else { 96481 currentVoice = this._oldest; 96482 var oldestNote = p5.prototype.freqToMidi(this.audiovoices[this._oldest].oscillator.freq().value); 96483 this.noteRelease(oldestNote); 96484 this._oldest = (this._oldest + 1) % (this.maxVoices - 1); 96485 } 96486 //Overrite the entry in the notes object. A note (frequency value) 96487 //corresponds to the index of the audiovoice that is playing it 96488 this.notes[note] = new TimelineSignal(); 96489 this.notes[note].setValueAtTime(currentVoice, acTime); 96490 //Find the scheduled change in this._voicesInUse that will be previous to this new note 96491 //Add 1 and schedule this value at time 't', when this note will start playing 96492 var previousVal = this._voicesInUse._searchBefore(acTime) === null ? 0 : this._voicesInUse._searchBefore(acTime).value; 96493 this._voicesInUse.setValueAtTime(previousVal + 1, acTime); 96494 //Then update all scheduled values that follow to increase by 1 96495 this._updateAfter(acTime, 1); 96496 this._newest = currentVoice; 96497 //The audiovoice handles the actual scheduling of the note 96498 if (typeof velocity === 'number') { 96499 var maxRange = 1 / this._voicesInUse.getValueAtTime(acTime) * 2; 96500 velocity = velocity > maxRange ? maxRange : velocity; 96501 } 96502 this.audiovoices[currentVoice].triggerAttack(note, velocity, secondsFromNow); 96503 }; 96504 /** 96505 * Private method to ensure accurate values of this._voicesInUse 96506 * Any time a new value is scheduled, it is necessary to increment all subsequent 96507 * scheduledValues after attack, and decrement all subsequent 96508 * scheduledValues after release 96509 * 96510 * @private 96511 * @param {[type]} time [description] 96512 * @param {[type]} value [description] 96513 * @return {[type]} [description] 96514 */ 96515 p5.PolySynth.prototype._updateAfter = function (time, value) { 96516 if (this._voicesInUse._searchAfter(time) === null) { 96517 return; 96518 } else { 96519 this._voicesInUse._searchAfter(time).value += value; 96520 var nextTime = this._voicesInUse._searchAfter(time).time; 96521 this._updateAfter(nextTime, value); 96522 } 96523 }; 96524 /** 96525 * Trigger the Release of an AudioVoice note. This is similar to releasing 96526 * the key on a piano and letting the sound fade according to the 96527 * release level and release time. 96528 * 96529 * @method noteRelease 96530 * @param {Number} [note] midi note on which attack should be triggered. 96531 * If no value is provided, all notes will be released. 96532 * @param {Number} [secondsFromNow] time to trigger the release 96533 * @example 96534 * <div><code> 96535 * var pitches = ["G", "D", "G", "C"]; 96536 * var octaves = [2, 3, 4]; 96537 * var polySynth = new p5.PolySynth(); 96538 * 96539 * function mousePressed() { 96540 * // play a chord: multiple notes at the same time 96541 * for (var i = 0; i < 4; i++) { 96542 * var note = random(pitches) + random(octaves); 96543 * polySynth.noteAttack(note, 0.1); 96544 * } 96545 * } 96546 * 96547 * function mouseReleased() { 96548 * // release all voices 96549 * polySynth.noteRelease(); 96550 * } 96551 * </code></div> 96552 * 96553 */ 96554 p5.PolySynth.prototype.noteRelease = function (_note, secondsFromNow) { 96555 var now = p5sound.audiocontext.currentTime; 96556 var tFromNow = secondsFromNow || 0; 96557 var t = now + tFromNow; 96558 // if a note value is not provided, release all voices 96559 if (!_note) {
96560 this.audiovoices.forEach(function (voice) { 96561 voice.triggerRelease(tFromNow); 96562 }); 96563 this._voicesInUse.setValueAtTime(0, t); 96564 for (var n in this.notes) { 96565 this.notes[n].dispose(); 96566 delete this.notes[n]; 96567 } 96568 return; 96569 } 96570 //Make sure note is in frequency inorder to query the this.notes object 96571 var note = noteToFreq(_note); 96572 if (!this.notes[note] || this.notes[note].getValueAtTime(t) === null) { 96573 console.warn('Cannot release a note that is not already playing'); 96574 } else { 96575 //Find the scheduled change in this._voicesInUse that will be previous to this new note 96576 //subtract 1 and schedule this value at time 't', when this note will stop playing 96577 var previousVal = Math.max(~~this._voicesInUse.getValueAtTime(t).value, 1); 96578 this._voicesInUse.setValueAtTime(previousVal - 1, t); 96579 //Then update all scheduled values that follow to decrease by 1 but never go below 0 96580 if (previousVal > 0) { 96581 this._updateAfter(t, -1); 96582 } 96583 this.audiovoices[this.notes[note].getValueAtTime(t)].triggerRelease(tFromNow); 96584 this.notes[note].dispose(); 96585 delete this.notes[note]; 96586 this._newest = this._newest === 0 ? 0 : (this._newest - 1) % (this.maxVoices - 1); 96587 } 96588 }; 96589 /** 96590 * Connect to a p5.sound / Web Audio object. 96591 * 96592 * @method connect 96593 * @param {Object} unit A p5.sound or Web Audio object 96594 */ 96595 p5.PolySynth.prototype.connect = function (unit) { 96596 var u = unit || p5sound.input; 96597 this.output.connect(u.input ? u.input : u); 96598 }; 96599 /** 96600 * Disconnect all outputs 96601 * 96602 * @method disconnect 96603 */ 96604 p5.PolySynth.prototype.disconnect = function () { 96605 if (this.output) { 96606 this.output.disconnect(); 96607 } 96608 }; 96609 /** 96610 * Get rid of the MonoSynth and free up its resources / memory. 96611 * 96612 * @method dispose 96613 */ 96614 p5.PolySynth.prototype.dispose = function () { 96615 this.audiovoices.forEach(function (voice) { 96616 voice.dispose(); 96617 }); 96618 if (this.output) { 96619 this.output.disconnect(); 96620 delete this.output; 96621 } 96622 }; 96623}(master, Tone_signal_TimelineSignal, helpers); 96624var distortion; 96625'use strict'; 96626distortion = function () { 96627 var Effect = effect; 96628 /* 96629 * Adapted from [Kevin Ennis on StackOverflow](http://stackoverflow.com/questions/22312841/waveshaper-node-in-webaudio-how-to-emulate-distortion) 96630 */ 96631 function makeDistortionCurve(amount) { 96632 var k = typeof amount === 'number' ? amount : 50; 96633 var numSamples = 44100; 96634 var curve = new Float32Array(numSamples); 96635 var deg = Math.PI / 180; 96636 var i = 0; 96637 var x; 96638 for (; i < numSamples; ++i) { 96639 x = i * 2 / numSamples - 1; 96640 curve[i] = (3 + k) * x * 20 * deg / (Math.PI + k * Math.abs(x)); 96641 } 96642 return curve; 96643 } 96644 /** 96645 * A Distortion effect created with a Waveshaper Node, 96646 * with an approach adapted from 96647 * [Kevin Ennis](http://stackoverflow.com/questions/22312841/waveshaper-node-in-webaudio-how-to-emulate-distortion) 96648 * 96649 * This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>. 96650 * Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>, 96651 * <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and 96652 * <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available. 96653 * 96654 * @class p5.Distortion 96655 * @extends p5.Effect 96656 * @constructor 96657 * @param {Number} [amount=0.25] Unbounded distortion amount. 96658 * Normal values range from 0-1. 96659 * @param {String} [oversample='none'] 'none', '2x', or '4x'. 96660 * 96661 */ 96662 p5.Distortion = function (amount, oversample) { 96663 Effect.call(this); 96664 if (typeof amount === 'undefined') { 96665 amount = 0.25; 96666 } 96667 if (typeof amount !== 'number') { 96668 throw new Error('amount must be a number'); 96669 } 96670 if (typeof oversample === 'undefined') { 96671 oversample = '2x'; 96672 } 96673 if (typeof oversample !== 'string') { 96674 throw new Error('oversample must be a String'); 96675 } 96676 var curveAmount = p5.prototype.map(amount, 0, 1, 0, 2000); 96677 /** 96678 * The p5.Distortion is built with a 96679 * <a href="http://www.w3.org/TR/webaudio/#WaveShaperNode"> 96680 * Web Audio WaveShaper Node</a>. 96681 * 96682 * @property {AudioNode} WaveShaperNode 96683 */ 96684 this.waveShaperNode = this.ac.createWaveShaper(); 96685 this.amount = curveAmount; 96686 this.waveShaperNode.curve = makeDistortionCurve(curveAmount); 96687 this.waveShaperNode.oversample = oversample; 96688 this.input.connect(this.waveShaperNode); 96689 this.waveShaperNode.connect(this.wet); 96690 }; 96691 p5.Distortion.prototype = Object.create(Effect.prototype); 96692 /** 96693 * Process a sound source, optionally specify amount and oversample values. 96694 * 96695 * @method process 96696 * @param {Number} [amount=0.25] Unbounded distortion amount. 96697 * Normal values range from 0-1. 96698 * @param {String} [oversample='none'] 'none', '2x', or '4x'. 96699 */ 96700 p5.Distortion.prototype.process = function (src, amount, oversample) { 96701 src.connect(this.input); 96702 this.set(amount, oversample); 96703 }; 96704 /** 96705 * Set the amount and oversample of the waveshaper distortion. 96706 * 96707 * @method set 96708 * @param {Number} [amount=0.25] Unbounded distortion amount. 96709 * Normal values range from 0-1. 96710 * @param {String} [oversample='none'] 'none', '2x', or '4x'. 96711 */ 96712 p5.Distortion.prototype.set = function (amount, oversample) { 96713 if (amount) { 96714 var curveAmount = p5.prototype.map(amount, 0, 1, 0, 2000); 96715 this.amount = curveAmount; 96716 this.waveShaperNode.curve = makeDistortionCurve(curveAmount); 96717 } 96718 if (oversample) { 96719 this.waveShaperNode.oversample = oversample; 96720 } 96721 }; 96722 /** 96723 * Return the distortion amount, typically between 0-1. 96724 * 96725 * @method getAmount 96726 * @return {Number} Unbounded distortion amount. 96727 * Normal values range from 0-1. 96728 */ 96729 p5.Distortion.prototype.getAmount = function () { 96730 return this.amount; 96731 }; 96732 /** 96733 * Return the oversampling. 96734 * 96735 * @method getOversample 96736 * 96737 * @return {String} Oversample can either be 'none', '2x', or '4x'. 96738 */ 96739 p5.Distortion.prototype.getOversample = function () { 96740 return this.waveShaperNode.oversample; 96741 }; 96742 p5.Distortion.prototype.dispose = function () { 96743 Effect.prototype.dispose.apply(this); 96744 if (this.waveShaperNode) { 96745 this.waveShaperNode.disconnect(); 96746 this.waveShaperNode = null; 96747 } 96748 }; 96749}(effect); 96750var src_app; 96751'use strict'; 96752src_app = function () { 96753 var p5SOUND = master; 96754 return p5SOUND; 96755}(shims, audiocontext, master, helpers, errorHandler, panner, soundfile, amplitude, fft, signal, oscillator, envelope, pulse, noise, audioin, filter, eq, panner3d, listener3d, delay, reverb, metro, looper, soundloop, compressor, soundRecorder, peakdetect, gain, monosynth, polysynth, distortion, audioVoice, monosynth, polysynth); 96756})); 96757},{"../p5":"../node_modules/p5/lib/p5.js"}],"images/clock.png":[function(require,module,exports) { 96758module.exports = "/clock.903ff57b.png"; 96759},{}],"images/mokuhyou_tassei_man.png":[function(require,module,exports) { 96760module.exports = "/mokuhyou_tassei_man.8c5a209c.png"; 96761},{}],"images/mokuhyou_tassei_woman.png":[function(require,module,exports) { 96762module.exports = "/mokuhyou_tassei_woman.c2505a38.png"; 96763},{}],"images/musician_trumpet_man.png":[function(require,module,exports) { 96764module.exports = "/musician_trumpet_man.a4a6179c.png"; 96765},{}],"se/people_people-stadium-cheer1.mp3":[function(require,module,exports) { 96766module.exports = "/people_people-stadium-cheer1.5c7a3fa7.mp3"; 96767},{}],"se/trumpet-dub1.mp3":[function(require,module,exports) { 96768module.exports = "/trumpet-dub1.2ea8e318.mp3"; 96769},{}],"js/app.js":[function(require,module,exports) { 96770"use strict"; 96771 96772require("../scss/style.scss"); 96773 96774var _p = _interopRequireDefault(require("p5")); 96775 96776require("p5/lib/addons/p5.sound"); 96777 96778var _clock = _interopRequireDefault(require("../images/clock.png")); 96779 96780var _mokuhyou_tassei_man = _interopRequireDefault(require("../images/mokuhyou_tassei_man.png")); 96781 96782var _mokuhyou_tassei_woman = _interopRequireDefault(require("../images/mokuhyou_tassei_woman.png")); 96783 96784var _musician_trumpet_man = _interopRequireDefault(require("../images/musician_trumpet_man.png")); 96785 96786var _people_peopleStadiumCheer = _interopRequireDefault(require("../se/people_people-stadium-cheer1.mp3")); 96787 96788var _trumpetDub = _interopRequireDefault(require("../se/trumpet-dub1.mp3")); 96789 96790function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 96791 96792var sketch = function sketch(p) { 96793 var PEOPLE_TYPE_MAN = "MAN"; 96794 var PEOPLE_TYPE_WOMAN = "WOMAN"; 96795 var HOURS_LINE_LENGTH = 160; 96796 var MINUTES_LINE_LENGTH = 200; 96797 var SECONDS_LINE_LENGTH = 230; //ç»é¢æç»ç¨ãããã¡ 96798 96799 var bufferedImage; //ç»åï¼æè¨æ¬ä½ 96800 96801 var imgClock; //ç»åï¼å ±ãããã³ 96802 96803 var imgRewardMan; //ç»åï¼å ±ããã¦ã¼ãã³ 96804 96805 var imgRewardWoman; //ç»åï¼ãã©ã³ããããã³ 96806 96807 var imgTrumpetMan; //广é³ï¼å ±ããã 96808 96809 var seReward; //广é³ï¼ï¼ï¼æ 96810 96811 var seTwelve; //ãã¦ã¹ãé·æ¼ãããæé 96812 96813 var mousePressedTime = 0; //å ç®ããæé 96814 96815 var addTime = 0; //åãã¬ã¼ã ã®é·éçééãªãå¤å®ã®çµæãä¿æãã¦ãã 96816 96817 var prevCheckResult = null; //å ±ããå¦çã«ã¦ã³ã¿ 96818 96819 var rewardCount = 0;
96819 //å ±ããå¦çä¸ã®äººç©æç»ç¨é å 96820 96821 var rewardPeopleList; //é·éã¨çéã®è² 96822 96823 var hoursMinutesColor; //ç§éã®è² 96824 96825 var secondsColor; //æå¾ã«å ±ãããæ 96826 96827 var lastRewardHours; //æ¥ä»å¤æ´å¦çã«ã¦ã³ã¿ 96828 96829 var newDayCount = 0; //ç»åã®æ¡å¤§ç 96830 96831 var magnification = 1.0; //é³å£°åæåãã©ã°(iOS対ç) 96832 96833 var isInitSE = false; //åæåå¦ç(ç»åã¨å¹æé³èªã¿è¾¼ã¿) 96834 96835 p.preload = function () { 96836 imgClock = p.loadImage(_clock.default); 96837 imgRewardMan = p.loadImage(_mokuhyou_tassei_man.default); 96838 imgRewardWoman = p.loadImage(_mokuhyou_tassei_woman.default); 96839 imgTrumpetMan = p.loadImage(_musician_trumpet_man.default); 96840 seReward = p.loadSound(_people_peopleStadiumCheer.default); 96841 seTwelve = p.loadSound(_trumpetDub.default); 96842 }; //åæåå¦ç(ç»é¢æç»è¨å®ãªã©) 96843 96844 96845 p.setup = function () { 96846 p.createCanvas(p.windowWidth, p.windowHeight); 96847 bufferedImage = p.createGraphics(p.windowWidth, p.windowHeight); 96848 p.setMagnification(); 96849 bufferedImage.noStroke(); 96850 bufferedImage.imageMode(p.CENTER); 96851 p.background(255); 96852 p.frameRate(30); 96853 p.angleMode(p.DEGREES); 96854 hoursMinutesColor = p.color(0, 0, 0); 96855 secondsColor = p.color(255, 0, 0); 96856 }; //ç»é¢æç»å¦ç 96857 96858 96859 p.draw = function () { 96860 //èæ¯æç»(åãã¬ã¼ã ã®æç»å 容ãå¡ãã¤ã¶ã) 96861 bufferedImage.background(200); //æè¨æç» 96862 96863 p.drawResizedImage(bufferedImage, imgClock, p.windowWidth / 2, p.windowHeight / 2); //ç»é¢é·æ¼ãã§æãå éããã 96864 96865 if (p.mouseIsPressed) { 96866 mousePressedTime++; 96867 96868 if (mousePressedTime > 30) { 96869 addTime++; 96870 } 96871 } else { 96872 mousePressedTime = 0; 96873 } //éæç» 96874 96875 96876 var now = new Date(); 96877 var hours = now.getHours(); 96878 var minutes = now.getMinutes() + addTime; 96879 var seconds = now.getSeconds(); 96880 var milliSeconds = now.getMilliseconds(); 96881 96882 while (minutes >= 60) { 96883 hours++; 96884 minutes -= 60; 96885 } 96886 96887 hours = hours % 24; //é·é表示 96888 96889 bufferedImage.strokeWeight(20 * magnification); 96890 bufferedImage.stroke(hoursMinutesColor); 96891 var hoursDeg = p.reviceAngle((hours + minutes / 60) * 30 - 90); 96892 p.drawHand(HOURS_LINE_LENGTH, hoursDeg); //çé表示 96893 96894 var minutesDeg = p.reviceAngle((minutes + seconds / 60) * 6 - 90); 96895 p.drawHand(MINUTES_LINE_LENGTH, minutesDeg); //ç§é表示 96896 96897 bufferedImage.strokeWeight(10 * magnification); 96898 bufferedImage.stroke(secondsColor); 96899 var secondsDeg = p.reviceAngle((seconds + milliSeconds / 1000) * 6 - 90); 96900 p.drawHand(SECONDS_LINE_LENGTH, secondsDeg); 96901 96902 if (hours !== 11 && hours !== 23 && hours !== 12 && hours !== 0 && lastRewardHours !== hours) { 96903 var overlapCheckResult = p.checkOverlap(hoursDeg, minutesDeg); 96904 96905 if (overlapCheckResult === 0 || prevCheckResult === -1 && overlapCheckResult === 1) { 96906 lastRewardHours = hours; 96907 p.initReward(); 96908 } 96909 96910 prevCheckResult = overlapCheckResult; 96911 } 96912 96913 if (lastRewardHours === 10 && hours === 12 || lastRewardHours === 22 && hours === 0) { 96914 //12æéãã 96915 lastRewardHours = 0; 96916 newDayCount = 1; 96917 seTwelve.play(); 96918 } 96919 96920 if (newDayCount > 0) { 96921 p.drawResizedImage(bufferedImage, imgTrumpetMan, bufferedImage.width / 2, bufferedImage.height / 2, imgTrumpetMan.width + p.getRandFromRange(0, 40), imgTrumpetMan.height + p.getRandFromRange(0, 40)); 96922 newDayCount++; 96923 96924 if (newDayCount >= 150) { 96925 newDayCount = 0; 96926 } 96927 } 96928 96929 if (rewardCount > 0) { 96930 rewardPeopleList.forEach(function (people) { 96931 p.drawResizedImage(bufferedImage, people.type === PEOPLE_TYPE_MAN ? imgRewardMan : imgRewardWoman, people.x + p.getRandFromRange(-2, 3), people.y + p.getRandFromRange(-2, 3)); 96932 }); 96933 rewardCount++; 96934 96935 if (rewardCount > 60) { 96936 rewardCount = 0; 96937 } 96938 } //ãããã¡ã«åºåããæç»å 容ãcanvasã«è¡¨ç¤º 96939 96940 96941 p.image(bufferedImage, 0, 0); 96942 }; 96943 /** 96944 * ã¦ã£ã³ãã¦ãµã¤ãºå¤æ´æã¤ãã³ã 96945 */ 96946 96947 96948 p.windowResized = function () { 96949 //夿´ãããã¦ã£ã³ãã¦ãµã¤ãºã«åããã¦ãã£ã³ãã¹ã®ãµã¤ãºãæ´æ° 96950 p.updateCanvasSize(); 96951 }; 96952 /** 96953 * ç»é¢ã¿ããæã1度ã ãç¡é³ã§å¹æé³ãåçãã 96954 * (iOS対ç) 96955 */ 96956 96957 96958 p.touchStarted = function () { 96959 if (isInitSE) { 96960 return; 96961 } 96962 96963 seReward.play(); 96964 seReward.stop(); 96965 isInitSE = true; 96966 }; 96967 /** 96968 * ãã£ã³ãã¹ãµã¤ãºæ´æ° 96969 */ 96970 96971 96972 p.updateCanvasSize = function () { 96973 p.resizeCanvas(p.windowWidth, p.windowHeight); 96974 bufferedImage.resizeCanvas(p.windowWidth, p.windowHeight); 96975 p.setMagnification(); 96976 }; 96977 96978 p.setMagnification = function () {
96979 //ç»é¢ãµã¤ãºã«åããã¦æç»ããç»åã®æ¡å¤§çãæå® 96980 var shorterWindowSize = p.windowWidth < p.windowHeight ? p.windowWidth : p.windowHeight; 96981 96982 if (shorterWindowSize < imgClock.width) { 96983 magnification = shorterWindowSize / imgClock.width; 96984 } 96985 }; 96986 /** 96987 * è§åº¦è£æ£ 96988 */ 96989 96990 96991 p.reviceAngle = function (deg) { 96992 while (deg >= 360) { 96993 deg -= 360; 96994 } 96995 96996 return deg; 96997 }; 96998 /** 96999 * éãæç»ãã 97000 **/ 97001 97002 97003 p.drawHand = function (len, deg) { 97004 //é·ãã¨è§åº¦ããéã®çµç«¯åº§æ¨ãç®åº 97005 var sx = bufferedImage.width / 2; 97006 var sy = bufferedImage.height / 2; 97007 var ex = sx + len * magnification * p.cos(deg); 97008 var ey = sy + len * magnification * p.sin(deg); //æç» 97009 97010 bufferedImage.line(sx, sy, ex, ey); 97011 }; 97012 /** 97013 * é追ãè¶ãå¤å® 97014 */ 97015 97016 97017 p.checkOverlap = function (hoursDeg, minutesDeg) { 97018 var roundHoursDeg = Math.round(hoursDeg) % 360; 97019 var roundMinutesDeg = Math.round(minutesDeg) % 360; 97020 97021 if (roundHoursDeg < 0) { 97022 roundHoursDeg += 360; 97023 } 97024 97025 if (roundMinutesDeg < 0) { 97026 roundMinutesDeg += 360; 97027 } //é·éãçéã追ãè¶ãç´å 97028 97029 97030 if (roundHoursDeg > roundMinutesDeg && p.abs(roundHoursDeg - roundMinutesDeg) < 10) { 97031 return -1; 97032 } //çéã¨é·éãä¸åº¦éãªã 97033 97034 97035 if (roundHoursDeg === roundMinutesDeg) { 97036 return 0; 97037 } 97038 97039 return 1; 97040 }; 97041 /** 97042 * ä¹±æ°åå¾(minï½max(maxå«ã¾ã)) 97043 */ 97044 97045 97046 p.getRandFromRange = function (min, max) { 97047 return Math.floor(p.random(max - min)) + min; 97048 }; 97049 /** 97050 * ç»åããµã¤ãºèª¿æ´ãã¦æç» 97051 */ 97052 97053 97054 p.drawResizedImage = function (baseImage, targetImage, x, y, width, height) { 97055 if (width && height) { 97056 baseImage.image(targetImage, x, y, width * magnification, height * magnification); 97057 return; 97058 } 97059 97060 baseImage.image(targetImage, x, y, targetImage.width * magnification, targetImage.height * magnification); 97061 }; 97062 /** 97063 * å ±ããå¦çåæå 97064 */ 97065 97066 97067 p.initReward = function () { 97068 rewardCount = 1; 97069 rewardPeopleList = []; 97070 var poopleCount = p.getRandFromRange(15, 30); 97071 97072 while (rewardPeopleList.length < poopleCount) { 97073 var peopleType = p.getRandFromRange(0, 2) === 0 ? PEOPLE_TYPE_MAN : PEOPLE_TYPE_WOMAN; 97074 rewardPeopleList.push({ 97075 type: peopleType, 97076 x: p.getRandFromRange(0, p.windowWidth), 97077 y: p.getRandFromRange(0, p.windowHeight) 97078 }); 97079 } 97080 97081 seReward.play(); 97082 }; 97083}; 97084 97085new _p.default(sketch); 97086},{"../scss/style.scss":"scss/style.scss","p5":"../node_modules/p5/lib/p5.js","p5/lib/addons/p5.sound":"../node_modules/p5/lib/addons/p5.sound.js","../images/clock.png":"images/clock.png","../images/mokuhyou_tassei_man.png":"images/mokuhyou_tassei_man.png","../images/mokuhyou_tassei_woman.png":"images/mokuhyou_tassei_woman.png","../images/musician_trumpet_man.png":"images/musician_trumpet_man.png","../se/people_people-stadium-cheer1.mp3":"se/people_people-stadium-cheer1.mp3","../se/trumpet-dub1.mp3":"se/trumpet-dub1.mp3"}],"C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/src/builtins/hmr-runtime.js":[function(require,module,exports) { 97087var global = arguments[3]; 97088var OVERLAY_ID = '__parcel__error__overlay__'; 97089var OldModule = module.bundle.Module; 97090 97091function Module(moduleName) { 97092 OldModule.call(this, moduleName); 97093 this.hot = { 97094 data: module.bundle.hotData, 97095 _acceptCallbacks: [], 97096 _disposeCallbacks: [], 97097 accept: function (fn) { 97098 this._acceptCallbacks.push(fn || function () {}); 97099 }, 97100 dispose: function (fn) { 97101 this._disposeCallbacks.push(fn); 97102 } 97103 }; 97104 module.bundle.hotData = null; 97105} 97106 97107module.bundle.Module = Module; 97108var checkedAssets, assetsToAccept; 97109var parent = module.bundle.parent; 97110 97111if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') { 97112 var hostname = "" || location.hostname; 97113 var protocol = location.protocol === 'https:' ? 'wss' : 'ws'; 97114 var ws = new WebSocket(protocol + '://' + hostname + ':' + "9821" + '/'); 97115 97116 ws.onmessage = function (event) { 97117 checkedAssets = {}; 97118 assetsToAccept = []; 97119 var data = JSON.parse(event.data); 97120 97121 if (data.type === 'update') { 97122 var handled = false;
vendor: 4,230 bytes, lines 97123-97289
97123 data.assets.forEach(function (asset) { 97124 if (!asset.isNew) { 97125 var didAccept = hmrAcceptCheck(global.parcelRequire, asset.id); 97126 97127 if (didAccept) { 97128 handled = true; 97129 } 97130 } 97131 }); // Enable HMR for CSS by default. 97132 97133 handled = handled || data.assets.every(function (asset) { 97134 return asset.type === 'css' && asset.generated.js; 97135 }); 97136 97137 if (handled) { 97138 console.clear(); 97139 data.assets.forEach(function (asset) { 97140 hmrApply(global.parcelRequire, asset); 97141 }); 97142 assetsToAccept.forEach(function (v) { 97143 hmrAcceptRun(v[0], v[1]); 97144 }); 97145 } else { 97146 window.location.reload(); 97147 } 97148 } 97149 97150 if (data.type === 'reload') { 97151 ws.close(); 97152 97153 ws.onclose = function () { 97154 location.reload(); 97155 }; 97156 } 97157 97158 if (data.type === 'error-resolved') { 97159 console.log('[parcel] ⨠Error resolved'); 97160 removeErrorOverlay(); 97161 } 97162 97163 if (data.type === 'error') { 97164 console.error('[parcel] ð¨ ' + data.error.message + '\n' + data.error.stack); 97165 removeErrorOverlay(); 97166 var overlay = createErrorOverlay(data); 97167 document.body.appendChild(overlay); 97168 } 97169 }; 97170} 97171 97172function removeErrorOverlay() { 97173 var overlay = document.getElementById(OVERLAY_ID); 97174 97175 if (overlay) { 97176 overlay.remove(); 97177 } 97178} 97179 97180function createErrorOverlay(data) { 97181 var overlay = document.createElement('div'); 97182 overlay.id = OVERLAY_ID; // html encode message and stack trace 97183 97184 var message = document.createElement('div'); 97185 var stackTrace = document.createElement('pre'); 97186 message.innerText = data.error.message; 97187 stackTrace.innerText = data.error.stack; 97188 overlay.innerHTML = '<div style="background: black; font-size: 16px; color: white; position: fixed; height: 100%; width: 100%; top: 0px; left: 0px; padding: 30px; opacity: 0.85; font-family: Menlo, Consolas, monospace; z-index: 9999;">' + '<span style="background: red; padding: 2px 4px; border-radius: 2px;">ERROR</span>' + '<span style="top: 2px; margin-left: 5px; position: relative;">ð¨</span>' + '<div style="font-size: 18px; font-weight: bold; margin-top: 20px;">' + message.innerHTML + '</div>' + '<pre>' + stackTrace.innerHTML + '</pre>' + '</div>'; 97189 return overlay; 97190} 97191 97192function getParents(bundle, id) { 97193 var modules = bundle.modules; 97194 97195 if (!modules) { 97196 return []; 97197 } 97198 97199 var parents = []; 97200 var k, d, dep; 97201 97202 for (k in modules) { 97203 for (d in modules[k][1]) { 97204 dep = modules[k][1][d]; 97205 97206 if (dep === id || Array.isArray(dep) && dep[dep.length - 1] === id) { 97207 parents.push(k); 97208 } 97209 } 97210 } 97211 97212 if (bundle.parent) { 97213 parents = parents.concat(getParents(bundle.parent, id)); 97214 } 97215 97216 return parents; 97217} 97218 97219function hmrApply(bundle, asset) { 97220 var modules = bundle.modules; 97221 97222 if (!modules) { 97223 return; 97224 } 97225 97226 if (modules[asset.id] || !bundle.parent) { 97227 var fn = new Function('require', 'module', 'exports', asset.generated.js); 97228 asset.isNew = !modules[asset.id]; 97229 modules[asset.id] = [fn, asset.deps]; 97230 } else if (bundle.parent) { 97231 hmrApply(bundle.parent, asset); 97232 } 97233} 97234 97235function hmrAcceptCheck(bundle, id) { 97236 var modules = bundle.modules; 97237 97238 if (!modules) { 97239 return; 97240 } 97241 97242 if (!modules[id] && bundle.parent) { 97243 return hmrAcceptCheck(bundle.parent, id); 97244 } 97245 97246 if (checkedAssets[id]) { 97247 return; 97248 } 97249 97250 checkedAssets[id] = true; 97251 var cached = bundle.cache[id]; 97252 assetsToAccept.push([bundle, id]); 97253 97254 if (cached && cached.hot && cached.hot._acceptCallbacks.length) { 97255 return true; 97256 } 97257 97258 return getParents(global.parcelRequire, id).some(function (id) { 97259 return hmrAcceptCheck(global.parcelRequire, id); 97260 }); 97261} 97262 97263function hmrAcceptRun(bundle, id) { 97264 var cached = bundle.cache[id]; 97265 bundle.hotData = {}; 97266 97267 if (cached) { 97268 cached.hot.data = bundle.hotData; 97269 } 97270 97271 if (cached && cached.hot && cached.hot._disposeCallbacks.length) { 97272 cached.hot._disposeCallbacks.forEach(function (cb) { 97273 cb(bundle.hotData); 97274 }); 97275 } 97276 97277 delete bundle.cache[id]; 97278 bundle(id); 97279 cached = bundle.cache[id]; 97280 97281 if (cached && cached.hot && cached.hot._acceptCallbacks.length) { 97282 cached.hot._acceptCallbacks.forEach(function (cb) { 97283 cb(); 97284 }); 97285 97286 return true; 97287 } 97288} 97289},{}]},{}
97289,["C:/Users/tekur/AppData/Roaming/npm/node_modules/parcel-bundler/src/builtins/hmr-runtime.js","js/app.js"], null) 97290//# sourceMappingURL=/app.c3f9f951.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.