├── addons
├── .DS_Store
├── p5.dom.js
├── p5.dom.min.js
├── p5.sound.js
└── p5.sound.min.js
├── empty-example
├── index.html
└── sketch.js
├── p5.js
└── p5.min.js
/addons/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hibernationTheory/p5js-complete/8a401c21d57ed95a800a052c63daf4ba6afdb1cd/addons/.DS_Store
--------------------------------------------------------------------------------
/addons/p5.dom.js:
--------------------------------------------------------------------------------
1 | /*! p5.dom.js v0.3.4 Aug 11, 2017 */
2 | /**
3 | *
The web is much more than just canvas and p5.dom makes it easy to interact
4 | * with other HTML5 objects, including text, hyperlink, image, input, video,
5 | * audio, and webcam.
6 | * There is a set of creation methods, DOM manipulation methods, and
7 | * an extended p5.Element that supports a range of HTML elements. See the
8 | *
9 | * beyond the canvas tutorial for a full overview of how this addon works.
10 | *
11 | *
Methods and properties shown in black are part of the p5.js core, items in
12 | * blue are part of the p5.dom library. You will need to include an extra file
13 | * in order to access the blue functions. See the
14 | * using a library
15 | * section for information on how to include this library. p5.dom comes with
16 | * p5 complete or you can download the single file
17 | *
18 | * here.
19 | * See tutorial: beyond the canvas
20 | * for more info on how to use this libary.
21 | *
22 | * @module p5.dom
23 | * @submodule p5.dom
24 | * @for p5.dom
25 | * @main
26 | */
27 |
28 | (function (root, factory) {
29 | if (typeof define === 'function' && define.amd)
30 | define('p5.dom', ['p5'], function (p5) { (factory(p5));});
31 | else if (typeof exports === 'object')
32 | factory(require('../p5'));
33 | else
34 | factory(root['p5']);
35 | }(this, function (p5) {
36 |
37 | // =============================================================================
38 | // p5 additions
39 | // =============================================================================
40 |
41 | /**
42 | * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.'
43 | * prefixes to specify an ID or class respectively, and none for a tag) and returns it as
44 | * a p5.Element. If a class or tag name is given with more than 1 element,
45 | * only the first element will be returned.
46 | * The DOM node itself can be accessed with .elt.
47 | * Returns null if none found. You can also specify a container to search within.
48 | *
49 | * @method select
50 | * @param {String} name id, class, or tag name of element to search for
51 | * @param {String} [container] id, p5.Element, or HTML element to search within
52 | * @return {Object|p5.Element|Null} p5.Element containing node found
53 | * @example
54 | *
55 | * function setup() {
56 | * createCanvas(100,100);
57 | * //translates canvas 50px down
58 | * select('canvas').position(100, 100);
59 | * }
60 | *
61 | *
62 | * // these are all valid calls to select()
63 | * var a = select('#moo');
64 | * var b = select('#blah', '#myContainer');
65 | * var c = select('#foo', b);
66 | * var d = document.getElementById('beep');
67 | * var e = select('p', d);
68 | *
69 | *
70 | */
71 | p5.prototype.select = function (e, p) {
72 | var res = null;
73 | var container = getContainer(p);
74 | if (e[0] === '.'){
75 | e = e.slice(1);
76 | res = container.getElementsByClassName(e);
77 | if (res.length) {
78 | res = res[0];
79 | } else {
80 | res = null;
81 | }
82 | }else if (e[0] === '#'){
83 | e = e.slice(1);
84 | res = container.getElementById(e);
85 | }else {
86 | res = container.getElementsByTagName(e);
87 | if (res.length) {
88 | res = res[0];
89 | } else {
90 | res = null;
91 | }
92 | }
93 | if (res) {
94 | return wrapElement(res);
95 | } else {
96 | return null;
97 | }
98 | };
99 |
100 | /**
101 | * Searches the page for elements with the given class or tag name (using the '.' prefix
102 | * to specify a class and no prefix for a tag) and returns them as p5.Elements
103 | * in an array.
104 | * The DOM node itself can be accessed with .elt.
105 | * Returns an empty array if none found.
106 | * You can also specify a container to search within.
107 | *
108 | * @method selectAll
109 | * @param {String} name class or tag name of elements to search for
110 | * @param {String} [container] id, p5.Element, or HTML element to search within
111 | * @return {Array} Array of p5.Elements containing nodes found
112 | * @example
113 | *
114 | * function setup() {
115 | * createButton('btn');
116 | * createButton('2nd btn');
117 | * createButton('3rd btn');
118 | * var buttons = selectAll('button');
119 | *
120 | * for (var i = 0; i < buttons.length; i++){
121 | * buttons[i].size(100,100);
122 | * }
123 | * }
124 | *
125 | *
126 | * // these are all valid calls to selectAll()
127 | * var a = selectAll('.moo');
128 | * var b = selectAll('div');
129 | * var c = selectAll('button', '#myContainer');
130 | * var d = select('#container');
131 | * var e = selectAll('p', d);
132 | * var f = document.getElementById('beep');
133 | * var g = select('.blah', f);
134 | *
135 | *
136 | */
137 | p5.prototype.selectAll = function (e, p) {
138 | var arr = [];
139 | var res;
140 | var container = getContainer(p);
141 | if (e[0] === '.'){
142 | e = e.slice(1);
143 | res = container.getElementsByClassName(e);
144 | } else {
145 | res = container.getElementsByTagName(e);
146 | }
147 | if (res) {
148 | for (var j = 0; j < res.length; j++) {
149 | var obj = wrapElement(res[j]);
150 | arr.push(obj);
151 | }
152 | }
153 | return arr;
154 | };
155 |
156 | /**
157 | * Helper function for select and selectAll
158 | */
159 | function getContainer(p) {
160 | var container = document;
161 | if (typeof p === 'string' && p[0] === '#'){
162 | p = p.slice(1);
163 | container = document.getElementById(p) || document;
164 | } else if (p instanceof p5.Element){
165 | container = p.elt;
166 | } else if (p instanceof HTMLElement){
167 | container = p;
168 | }
169 | return container;
170 | }
171 |
172 | /**
173 | * Helper function for getElement and getElements.
174 | */
175 | function wrapElement(elt) {
176 | if(elt.tagName === "INPUT" && elt.type === "checkbox") {
177 | var converted = new p5.Element(elt);
178 | converted.checked = function(){
179 | if (arguments.length === 0){
180 | return this.elt.checked;
181 | } else if(arguments[0]) {
182 | this.elt.checked = true;
183 | } else {
184 | this.elt.checked = false;
185 | }
186 | return this;
187 | };
188 | return converted;
189 | } else if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") {
190 | return new p5.MediaElement(elt);
191 | } else if ( elt.tagName === "SELECT" ){
192 | return createSelect( new p5.Element(elt) );
193 | }
194 | else {
195 | return new p5.Element(elt);
196 | }
197 | }
198 |
199 | /**
200 | * Removes all elements created by p5, except any canvas / graphics
201 | * elements created by createCanvas or createGraphics.
202 | * Event handlers are removed, and element is removed from the DOM.
203 | * @method removeElements
204 | * @example
205 | *
206 | * function setup() {
207 | * createCanvas(100, 100);
208 | * createDiv('this is some text');
209 | * createP('this is a paragraph');
210 | * }
211 | * function mousePressed() {
212 | * removeElements(); // this will remove the div and p, not canvas
213 | * }
214 | *
215 | *
216 | */
217 | p5.prototype.removeElements = function (e) {
218 | for (var i=0; i
246 | * var myDiv;
247 | * function setup() {
248 | * myDiv = createDiv('this is some text');
249 | * }
250 | *
251 | */
252 |
253 | /**
254 | * Creates a <p></p> element in the DOM with given inner HTML. Used
255 | * for paragraph length text.
256 | * Appends to the container node if one is specified, otherwise
257 | * appends to body.
258 | *
259 | * @method createP
260 | * @param {String} [html] inner HTML for element created
261 | * @return {Object|p5.Element} pointer to p5.Element holding created node
262 | * @example
263 | *
264 | * var myP;
265 | * function setup() {
266 | * myP = createP('this is some text');
267 | * }
268 | *
269 | */
270 |
271 | /**
272 | * Creates a <span></span> element in the DOM with given inner HTML.
273 | * Appends to the container node if one is specified, otherwise
274 | * appends to body.
275 | *
276 | * @method createSpan
277 | * @param {String} [html] inner HTML for element created
278 | * @return {Object|p5.Element} pointer to p5.Element holding created node
279 | * @example
280 | *
281 | * var mySpan;
282 | * function setup() {
283 | * mySpan = createSpan('this is some text');
284 | * }
285 | *
286 | */
287 | var tags = ['div', 'p', 'span'];
288 | tags.forEach(function(tag) {
289 | var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1);
290 | p5.prototype[method] = function(html) {
291 | var elt = document.createElement(tag);
292 | elt.innerHTML = typeof html === undefined ? "" : html;
293 | return addElement(elt, this);
294 | }
295 | });
296 |
297 | /**
298 | * Creates an <img> element in the DOM with given src and
299 | * alternate text.
300 | * Appends to the container node if one is specified, otherwise
301 | * appends to body.
302 | *
303 | * @method createImg
304 | * @param {String} src src path or url for image
305 | * @param {String} [alt] alternate text to be used if image does not load
306 | * @param {Function} [successCallback] callback to be called once image data is loaded
307 | * @return {Object|p5.Element} pointer to p5.Element holding created node
308 | * @example
309 | *
310 | * var img;
311 | * function setup() {
312 | * img = createImg('http://p5js.org/img/asterisk-01.png');
313 | * }
314 | *
315 | */
316 | p5.prototype.createImg = function() {
317 | var elt = document.createElement('img');
318 | var args = arguments;
319 | var self;
320 | var setAttrs = function(){
321 | self.width = elt.offsetWidth || elt.width;
322 | self.height = elt.offsetHeight || elt.height;
323 | if (args.length > 1 && typeof args[1] === 'function'){
324 | self.fn = args[1];
325 | self.fn();
326 | }else if (args.length > 1 && typeof args[2] === 'function'){
327 | self.fn = args[2];
328 | self.fn();
329 | }
330 | };
331 | elt.src = args[0];
332 | if (args.length > 1 && typeof args[1] === 'string'){
333 | elt.alt = args[1];
334 | }
335 | elt.onload = function(){
336 | setAttrs();
337 | }
338 | self = addElement(elt, this);
339 | return self;
340 | };
341 |
342 | /**
343 | * Creates an <a></a> element in the DOM for including a hyperlink.
344 | * Appends to the container node if one is specified, otherwise
345 | * appends to body.
346 | *
347 | * @method createA
348 | * @param {String} href url of page to link to
349 | * @param {String} html inner html of link element to display
350 | * @param {String} [target] target where new link should open,
351 | * could be _blank, _self, _parent, _top.
352 | * @return {Object|p5.Element} pointer to p5.Element holding created node
353 | * @example
354 | *
355 | * var myLink;
356 | * function setup() {
357 | * myLink = createA('http://p5js.org/', 'this is a link');
358 | * }
359 | *
360 | */
361 | p5.prototype.createA = function(href, html, target) {
362 | var elt = document.createElement('a');
363 | elt.href = href;
364 | elt.innerHTML = html;
365 | if (target) elt.target = target;
366 | return addElement(elt, this);
367 | };
368 |
369 | /** INPUT **/
370 |
371 |
372 | /**
373 | * Creates a slider <input></input> element in the DOM.
374 | * Use .size() to set the display length of the slider.
375 | * Appends to the container node if one is specified, otherwise
376 | * appends to body.
377 | *
378 | * @method createSlider
379 | * @param {Number} min minimum value of the slider
380 | * @param {Number} max maximum value of the slider
381 | * @param {Number} [value] default value of the slider
382 | * @param {Number} [step] 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)
383 | * @return {Object|p5.Element} pointer to p5.Element holding created node
384 | * @example
385 | *
386 | * var slider;
387 | * function setup() {
388 | * slider = createSlider(0, 255, 100);
389 | * slider.position(10, 10);
390 | * slider.style('width', '80px');
391 | * }
392 | *
393 | * function draw() {
394 | * var val = slider.value();
395 | * background(val);
396 | * }
397 | *
398 | *
399 | *
400 | * var slider;
401 | * function setup() {
402 | * colorMode(HSB);
403 | * slider = createSlider(0, 360, 60, 40);
404 | * slider.position(10, 10);
405 | * slider.style('width', '80px');
406 | * }
407 | *
408 | * function draw() {
409 | * var val = slider.value();
410 | * background(val, 100, 100, 1);
411 | * }
412 | *
413 | */
414 | p5.prototype.createSlider = function(min, max, value, step) {
415 | var elt = document.createElement('input');
416 | elt.type = 'range';
417 | elt.min = min;
418 | elt.max = max;
419 | if (step === 0) {
420 | elt.step = .000000000000000001; // smallest valid step
421 | } else if (step) {
422 | elt.step = step;
423 | }
424 | if (typeof(value) === "number") elt.value = value;
425 | return addElement(elt, this);
426 | };
427 |
428 | /**
429 | * Creates a <button></button> element in the DOM.
430 | * Use .size() to set the display size of the button.
431 | * Use .mousePressed() to specify behavior on press.
432 | * Appends to the container node if one is specified, otherwise
433 | * appends to body.
434 | *
435 | * @method createButton
436 | * @param {String} label label displayed on the button
437 | * @param {String} [value] value of the button
438 | * @return {Object|p5.Element} pointer to p5.Element holding created node
439 | * @example
440 | *
441 | * var button;
442 | * function setup() {
443 | * createCanvas(100, 100);
444 | * background(0);
445 | * button = createButton('click me');
446 | * button.position(19, 19);
447 | * button.mousePressed(changeBG);
448 | * }
449 | *
450 | * function changeBG() {
451 | * var val = random(255);
452 | * background(val);
453 | * }
454 | *
455 | */
456 | p5.prototype.createButton = function(label, value) {
457 | var elt = document.createElement('button');
458 | elt.innerHTML = label;
459 | if (value) elt.value = value;
460 | return addElement(elt, this);
461 | };
462 |
463 | /**
464 | * Creates a checkbox <input></input> element in the DOM.
465 | * Calling .checked() on a checkbox returns if it is checked or not
466 | *
467 | * @method createCheckbox
468 | * @param {String} [label] label displayed after checkbox
469 | * @param {boolean} [value] value of the checkbox; checked is true, unchecked is false.Unchecked if no value given
470 | * @return {Object|p5.Element} pointer to p5.Element holding created node
471 | * @example
472 | *
473 | * var checkbox;
474 | *
475 | * function setup() {
476 | * checkbox = createCheckbox('label', false);
477 | * checkbox.changed(myCheckedEvent);
478 | * }
479 | *
480 | * function myCheckedEvent() {
481 | * if (this.checked()) {
482 | * console.log("Checking!");
483 | * } else {
484 | * console.log("Unchecking!");
485 | * }
486 | * }
487 | *
488 | */
489 | p5.prototype.createCheckbox = function() {
490 | var elt = document.createElement('div');
491 | var checkbox = document.createElement('input');
492 | checkbox.type = 'checkbox';
493 | elt.appendChild(checkbox);
494 | //checkbox must be wrapped in p5.Element before label so that label appears after
495 | var self = addElement(elt, this);
496 | self.checked = function(){
497 | var cb = self.elt.getElementsByTagName('input')[0];
498 | if (cb) {
499 | if (arguments.length === 0){
500 | return cb.checked;
501 | }else if(arguments[0]){
502 | cb.checked = true;
503 | }else{
504 | cb.checked = false;
505 | }
506 | }
507 | return self;
508 | };
509 | this.value = function(val){
510 | self.value = val;
511 | return this;
512 | };
513 | if (arguments[0]){
514 | var ran = Math.random().toString(36).slice(2);
515 | var label = document.createElement('label');
516 | checkbox.setAttribute('id', ran);
517 | label.htmlFor = ran;
518 | self.value(arguments[0]);
519 | label.appendChild(document.createTextNode(arguments[0]));
520 | elt.appendChild(label);
521 | }
522 | if (arguments[1]){
523 | checkbox.checked = true;
524 | }
525 | return self;
526 | };
527 |
528 | /**
529 | * Creates a dropdown menu <select></select> element in the DOM.
530 | * It also helps to assign select-box methods to p5.Element when selecting existing select box
531 | * @method createSelect
532 | * @param {boolean} [multiple] true if dropdown should support multiple selections
533 | * @return {p5.Element}
534 | * @example
535 | *
536 | * var sel;
537 | *
538 | * function setup() {
539 | * textAlign(CENTER);
540 | * background(200);
541 | * sel = createSelect();
542 | * sel.position(10, 10);
543 | * sel.option('pear');
544 | * sel.option('kiwi');
545 | * sel.option('grape');
546 | * sel.changed(mySelectEvent);
547 | * }
548 | *
549 | * function mySelectEvent() {
550 | * var item = sel.value();
551 | * background(200);
552 | * text("it's a "+item+"!", 50, 50);
553 | * }
554 | *
555 | */
556 | /**
557 | * @method createSelect
558 | * @param {Object} existing DOM select element
559 | * @return {p5.Element}
560 | */
561 |
562 | p5.prototype.createSelect = function() {
563 | var elt, self;
564 | var arg = arguments[0];
565 | if( typeof arg === 'object' && arg.elt.nodeName === 'SELECT' ) {
566 | self = arg;
567 | elt = this.elt = arg.elt;
568 | } else {
569 | elt = document.createElement('select');
570 | if( arg && typeof arg === 'boolean' ) {
571 | elt.setAttribute('multiple', 'true');
572 | }
573 | self = addElement(elt, this);
574 | }
575 | self.option = function(name, value) {
576 | var index;
577 | //see if there is already an option with this name
578 | for (var i = 0; i < this.elt.length; i++) {
579 | if(this.elt[i].innerHTML == name) {
580 | index = i;
581 | break;
582 | }
583 | }
584 | //if there is an option with this name we will modify it
585 | if(index !== undefined) {
586 | //if the user passed in false then delete that option
587 | if(value === false) {
588 | this.elt.remove(index);
589 | } else {
590 | //otherwise if the name and value are the same then change both
591 | if(this.elt[index].innerHTML == this.elt[index].value) {
592 | this.elt[index].innerHTML = this.elt[index].value = value;
593 | //otherwise just change the value
594 | } else {
595 | this.elt[index].value = value;
596 | }
597 | }
598 | }
599 | //if it doesn't exist make it
600 | else {
601 | var opt = document.createElement('option');
602 | opt.innerHTML = name;
603 | if (arguments.length > 1)
604 | opt.value = value;
605 | else
606 | opt.value = name;
607 | elt.appendChild(opt);
608 | }
609 | };
610 | self.selected = function(value) {
611 | var arr = [];
612 | if (arguments.length > 0) {
613 | for (var i = 0; i < this.elt.length; i++) {
614 | if (value.toString() === this.elt[i].value) {
615 | this.elt.selectedIndex = i;
616 | }
617 | }
618 | return this;
619 | } else {
620 | if (this.elt.getAttribute('multiple')) {
621 | for (var i = 0; i < this.elt.selectedOptions.length; i++) {
622 | arr.push(this.elt.selectedOptions[i].value);
623 | }
624 | return arr;
625 | } else {
626 | return this.elt.value;
627 | }
628 | }
629 | };
630 | return self;
631 | };
632 |
633 | /**
634 | * Creates a radio button <input></input> element in the DOM.
635 | * The .option() method can be used to set options for the radio after it is
636 | * created. The .value() method will return the currently selected option.
637 | *
638 | * @method createRadio
639 | * @param {String} [divId] the id and name of the created div and input field respectively
640 | * @return {Object|p5.Element} pointer to p5.Element holding created node
641 | * @example
642 | *
643 | * var radio;
644 | *
645 | * function setup() {
646 | * radio = createRadio();
647 | * radio.option("black");
648 | * radio.option("white");
649 | * radio.option("gray");
650 | * radio.style('width', '60px');
651 | * textAlign(CENTER);
652 | * fill(255, 0, 0);
653 | * }
654 | *
655 | * function draw() {
656 | * var val = radio.value();
657 | * background(val);
658 | * text(val, width/2, height/2);
659 | * }
660 | *
661 | *
662 | * var radio;
663 | *
664 | * function setup() {
665 | * radio = createRadio();
666 | * radio.option('apple', 1);
667 | * radio.option('bread', 2);
668 | * radio.option('juice', 3);
669 | * radio.style('width', '60px');
670 | * textAlign(CENTER);
671 | * }
672 | *
673 | * function draw() {
674 | * background(200);
675 | * var val = radio.value();
676 | * if (val) {
677 | * text('item cost is $'+val, width/2, height/2);
678 | * }
679 | * }
680 | *
681 | */
682 | p5.prototype.createRadio = function() {
683 | var radios = document.querySelectorAll("input[type=radio]");
684 | var count = 0;
685 | if(radios.length > 1){
686 | var length = radios.length;
687 | var prev=radios[0].name;
688 | var current = radios[1].name;
689 | count = 1;
690 | for(var i = 1; i < length; i++) {
691 | current = radios[i].name;
692 | if(prev != current){
693 | count++;
694 | }
695 | prev = current;
696 | }
697 | }
698 | else if (radios.length == 1){
699 | count = 1;
700 | }
701 | var elt = document.createElement('div');
702 | var self = addElement(elt, this);
703 | var times = -1;
704 | self.option = function(name, value){
705 | var opt = document.createElement('input');
706 | opt.type = 'radio';
707 | opt.innerHTML = name;
708 | if (arguments.length > 1)
709 | opt.value = value;
710 | else
711 | opt.value = name;
712 | opt.setAttribute('name',"defaultradio"+count);
713 | elt.appendChild(opt);
714 | if (name){
715 | times++;
716 | var ran = Math.random().toString(36).slice(2);
717 | var label = document.createElement('label');
718 | opt.setAttribute('id', "defaultradio"+count+"-"+times);
719 | label.htmlFor = "defaultradio"+count+"-"+times;
720 | label.appendChild(document.createTextNode(name));
721 | elt.appendChild(label);
722 | }
723 | return opt;
724 | };
725 | self.selected = function(){
726 | var length = this.elt.childNodes.length;
727 | if(arguments.length == 1) {
728 | for (var i = 0; i < length; i+=2){
729 | if(this.elt.childNodes[i].value == arguments[0])
730 | this.elt.childNodes[i].checked = true;
731 | }
732 | return this;
733 | } else {
734 | for (var i = 0; i < length; i+=2){
735 | if(this.elt.childNodes[i].checked == true)
736 | return this.elt.childNodes[i].value;
737 | }
738 | }
739 | };
740 | self.value = function(){
741 | var length = this.elt.childNodes.length;
742 | if(arguments.length == 1) {
743 | for (var i = 0; i < length; i+=2){
744 | if(this.elt.childNodes[i].value == arguments[0])
745 | this.elt.childNodes[i].checked = true;
746 | }
747 | return this;
748 | } else {
749 | for (var i = 0; i < length; i+=2){
750 | if(this.elt.childNodes[i].checked == true)
751 | return this.elt.childNodes[i].value;
752 | }
753 | return "";
754 | }
755 | };
756 | return self
757 | };
758 |
759 | /**
760 | * Creates an <input></input> element in the DOM for text input.
761 | * Use .size() to set the display length of the box.
762 | * Appends to the container node if one is specified, otherwise
763 | * appends to body.
764 | *
765 | * @method createInput
766 | * @param {Number} [value] default value of the input box
767 | * @param {String} [type] type of text, ie text, password etc. Defaults to text
768 | * @return {Object|p5.Element} pointer to p5.Element holding created node
769 | * @example
770 | *
771 | * function setup(){
772 | * var inp = createInput('');
773 | * inp.input(myInputEvent);
774 | * }
775 | *
776 | * function myInputEvent(){
777 | * console.log('you are typing: ', this.value());
778 | * }
779 | *
780 | *
781 | */
782 | p5.prototype.createInput = function(value, type) {
783 | var elt = document.createElement('input');
784 | elt.type = type ? type : 'text';
785 | if (value) elt.value = value;
786 | return addElement(elt, this);
787 | };
788 |
789 | /**
790 | * Creates an <input></input> element in the DOM of type 'file'.
791 | * This allows users to select local files for use in a sketch.
792 | *
793 | * @method createFileInput
794 | * @param {Function} [callback] callback function for when a file loaded
795 | * @param {String} [multiple] optional to allow multiple files selected
796 | * @return {Object|p5.Element} pointer to p5.Element holding created DOM element
797 | * @example
798 | * var input;
799 | * var img;
800 | *
801 | * function setup() {
802 | * input = createFileInput(handleFile);
803 | * input.position(0, 0);
804 | * }
805 | *
806 | * function draw() {
807 | * if (img) {
808 | * image(img, 0, 0, width, height);
809 | * }
810 | * }
811 | *
812 | * function handleFile(file) {
813 | * print(file);
814 | * if (file.type === 'image') {
815 | * img = createImg(file.data);
816 | * img.hide();
817 | * }
818 | * }
819 | */
820 | p5.prototype.createFileInput = function(callback, multiple) {
821 |
822 | // Is the file stuff supported?
823 | if (window.File && window.FileReader && window.FileList && window.Blob) {
824 | // Yup, we're ok and make an input file selector
825 | var elt = document.createElement('input');
826 | elt.type = 'file';
827 |
828 | // If we get a second argument that evaluates to true
829 | // then we are looking for multiple files
830 | if (multiple) {
831 | // Anything gets the job done
832 | elt.multiple = 'multiple';
833 | }
834 |
835 | // Function to handle when a file is selected
836 | // We're simplifying life and assuming that we always
837 | // want to load every selected file
838 | function handleFileSelect(evt) {
839 | // These are the files
840 | var files = evt.target.files;
841 | // Load each one and trigger a callback
842 | for (var i = 0; i < files.length; i++) {
843 | var f = files[i];
844 | var reader = new FileReader();
845 | function makeLoader(theFile) {
846 | // Making a p5.File object
847 | var p5file = new p5.File(theFile);
848 | return function(e) {
849 | p5file.data = e.target.result;
850 | callback(p5file);
851 | };
852 | };
853 | reader.onload = makeLoader(f);
854 |
855 | // Text or data?
856 | // This should likely be improved
857 | if (f.type.indexOf('text') > -1) {
858 | reader.readAsText(f);
859 | } else {
860 | reader.readAsDataURL(f);
861 | }
862 | }
863 | }
864 |
865 | // Now let's handle when a file was selected
866 | elt.addEventListener('change', handleFileSelect, false);
867 | return addElement(elt, this);
868 | } else {
869 | console.log('The File APIs are not fully supported in this browser. Cannot create element.');
870 | }
871 | };
872 |
873 |
874 | /** VIDEO STUFF **/
875 |
876 | function createMedia(pInst, type, src, callback) {
877 | var elt = document.createElement(type);
878 |
879 | // allow src to be empty
880 | var src = src || '';
881 | if (typeof src === 'string') {
882 | src = [src];
883 | }
884 | for (var i=0; ithis
920 | * page for further information about supported formats.
921 | *
922 | * @method createVideo
923 | * @param {String|Array} src path to a video file, or array of paths for
924 | * supporting different browsers
925 | * @param {Object} [callback] callback function to be called upon
926 | * 'canplaythrough' event fire, that is, when the
927 | * browser can play the media, and estimates that
928 | * enough data has been loaded to play the media
929 | * up to its end without having to stop for
930 | * further buffering of content
931 | * @return {p5.MediaElement|p5.Element} pointer to video p5.Element
932 | */
933 | p5.prototype.createVideo = function(src, callback) {
934 | return createMedia(this, 'video', src, callback);
935 | };
936 |
937 | /** AUDIO STUFF **/
938 |
939 | /**
940 | * Creates a hidden HTML5 <audio> element in the DOM for simple audio
941 | * playback. Appends to the container node if one is specified,
942 | * otherwise appends to body. The first parameter
943 | * can be either a single string path to a audio file, or an array of string
944 | * paths to different formats of the same audio. This is useful for ensuring
945 | * that your audio can play across different browsers, as each supports
946 | * different formats. See this
947 | * page for further information about supported formats.
948 | *
949 | * @method createAudio
950 | * @param {String|Array} src path to an audio file, or array of paths for
951 | * supporting different browsers
952 | * @param {Object} [callback] callback function to be called upon
953 | * 'canplaythrough' event fire, that is, when the
954 | * browser can play the media, and estimates that
955 | * enough data has been loaded to play the media
956 | * up to its end without having to stop for
957 | * further buffering of content
958 | * @return {p5.MediaElement|p5.Element} pointer to audio p5.Element
959 | */
960 | p5.prototype.createAudio = function(src, callback) {
961 | return createMedia(this, 'audio', src, callback);
962 | };
963 |
964 |
965 | /** CAMERA STUFF **/
966 |
967 | p5.prototype.VIDEO = 'video';
968 | p5.prototype.AUDIO = 'audio';
969 |
970 | // from: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
971 | // Older browsers might not implement mediaDevices at all, so we set an empty object first
972 | if (navigator.mediaDevices === undefined) {
973 | navigator.mediaDevices = {};
974 | }
975 |
976 | // Some browsers partially implement mediaDevices. We can't just assign an object
977 | // with getUserMedia as it would overwrite existing properties.
978 | // Here, we will just add the getUserMedia property if it's missing.
979 | if (navigator.mediaDevices.getUserMedia === undefined) {
980 | navigator.mediaDevices.getUserMedia = function(constraints) {
981 |
982 | // First get ahold of the legacy getUserMedia, if present
983 | var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
984 |
985 | // Some browsers just don't implement it - return a rejected promise with an error
986 | // to keep a consistent interface
987 | if (!getUserMedia) {
988 | return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
989 | }
990 |
991 | // Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
992 | return new Promise(function(resolve, reject) {
993 | getUserMedia.call(navigator, constraints, resolve, reject);
994 | });
995 | };
996 | }
997 |
998 | /**
999 | * Creates a new <video> element that contains the audio/video feed
1000 | * from a webcam. This can be drawn onto the canvas using video().
1001 | * More specific properties of the feed can be passing in a Constraints object.
1002 | * See the
1003 | * W3C
1004 | * spec for possible properties. Note that not all of these are supported
1005 | * by all browsers.
1006 | * Security note: A new browser security specification requires that getUserMedia,
1007 | * which is behind createCapture(), only works when you're running the code locally,
1008 | * or on HTTPS. Learn more here
1009 | * and here.
1010 | *
1011 | * @method createCapture
1012 | * @param {String|Constant|Object} type type of capture, either VIDEO or
1013 | * AUDIO if none specified, default both,
1014 | * or a Constraints object
1015 | * @param {Function} callback function to be called once
1016 | * stream has loaded
1017 | * @return {Object|p5.Element} capture video p5.Element
1018 | * @example
1019 | *
1020 | * var capture;
1021 | *
1022 | * function setup() {
1023 | * createCanvas(480, 120);
1024 | * capture = createCapture(VIDEO);
1025 | * }
1026 | *
1027 | * function draw() {
1028 | * image(capture, 0, 0, width, width*capture.height/capture.width);
1029 | * filter(INVERT);
1030 | * }
1031 | *
1032 | *
1033 | * function setup() {
1034 | * createCanvas(480, 120);
1035 | * var constraints = {
1036 | * video: {
1037 | * mandatory: {
1038 | * minWidth: 1280,
1039 | * minHeight: 720
1040 | * },
1041 | * optional: [
1042 | * { maxFrameRate: 10 }
1043 | * ]
1044 | * },
1045 | * audio: true
1046 | * };
1047 | * createCapture(constraints, function(stream) {
1048 | * console.log(stream);
1049 | * });
1050 | * }
1051 | *
1052 | */
1053 | p5.prototype.createCapture = function() {
1054 | var useVideo = true;
1055 | var useAudio = true;
1056 | var constraints;
1057 | var cb;
1058 | for (var i=0; i
1122 | * var h2 = createElement('h2','im an h2 p5.element!');
1123 | *
1124 | */
1125 | p5.prototype.createElement = function(tag, content) {
1126 | var elt = document.createElement(tag);
1127 | if (typeof content !== 'undefined') {
1128 | elt.innerHTML = content;
1129 | }
1130 | return addElement(elt, this);
1131 | };
1132 |
1133 |
1134 | // =============================================================================
1135 | // p5.Element additions
1136 | // =============================================================================
1137 | /**
1138 | *
1139 | * Adds specified class to the element.
1140 | *
1141 | * @for p5.Element
1142 | * @method addClass
1143 | * @param {String} class name of class to add
1144 | * @return {Object|p5.Element}
1145 | * @example
1146 | *
1147 | * var div = createDiv('div');
1148 | * div.addClass('myClass');
1149 | *
1150 | */
1151 | p5.Element.prototype.addClass = function(c) {
1152 | if (this.elt.className) {
1153 | // PEND don't add class more than once
1154 | //var regex = new RegExp('[^a-zA-Z\d:]?'+c+'[^a-zA-Z\d:]?');
1155 | //if (this.elt.className.search(/[^a-zA-Z\d:]?hi[^a-zA-Z\d:]?/) === -1) {
1156 | this.elt.className = this.elt.className+' '+c;
1157 | //}
1158 | } else {
1159 | this.elt.className = c;
1160 | }
1161 | return this;
1162 | }
1163 |
1164 | /**
1165 | *
1166 | * Removes specified class from the element.
1167 | *
1168 | * @method removeClass
1169 | * @param {String} class name of class to remove
1170 | * @return {Object|p5.Element}
1171 | */
1172 | p5.Element.prototype.removeClass = function(c) {
1173 | var regex = new RegExp('(?:^|\\s)'+c+'(?!\\S)');
1174 | this.elt.className = this.elt.className.replace(regex, '');
1175 | this.elt.className = this.elt.className.replace(/^\s+|\s+$/g, ""); //prettify (optional)
1176 | return this;
1177 | }
1178 |
1179 | /**
1180 | *
1181 | * Attaches the element as a child to the parent specified.
1182 | * Accepts either a string ID, DOM node, or p5.Element.
1183 | * If no argument is specified, an array of children DOM nodes is returned.
1184 | *
1185 | * @method child
1186 | * @param {String|Object|p5.Element} [child] the ID, DOM node, or p5.Element
1187 | * to add to the current element
1188 | * @return {p5.Element}
1189 | * @example
1190 | *
1191 | * var div0 = createDiv('this is the parent');
1192 | * var div1 = createDiv('this is the child');
1193 | * div0.child(div1); // use p5.Element
1194 | *
1195 | *
1196 | * var div0 = createDiv('this is the parent');
1197 | * var div1 = createDiv('this is the child');
1198 | * div1.id('apples');
1199 | * div0.child('apples'); // use id
1200 | *
1201 | *
1202 | * var div0 = createDiv('this is the parent');
1203 | * var elt = document.getElementById('myChildDiv');
1204 | * div0.child(elt); // use element from page
1205 | *
1206 | */
1207 | p5.Element.prototype.child = function(c) {
1208 | if (typeof c === 'undefined'){
1209 | return this.elt.childNodes
1210 | }
1211 | if (typeof c === 'string') {
1212 | if (c[0] === '#') {
1213 | c = c.substring(1);
1214 | }
1215 | c = document.getElementById(c);
1216 | } else if (c instanceof p5.Element) {
1217 | c = c.elt;
1218 | }
1219 | this.elt.appendChild(c);
1220 | return this;
1221 | };
1222 |
1223 | /**
1224 | * Centers a p5 Element either vertically, horizontally,
1225 | * or both, relative to its parent or according to
1226 | * the body if the Element has no parent. If no argument is passed
1227 | * the Element is aligned both vertically and horizontally.
1228 | *
1229 | * @param {String} align passing 'vertical', 'horizontal' aligns element accordingly
1230 | * @return {Object|p5.Element} pointer to p5.Element
1231 | * @example
1232 | *
1233 | * function setup() {
1234 | * var div = createDiv('').size(10,10);
1235 | * div.style('background-color','orange');
1236 | * div.center();
1237 | *
1238 | * }
1239 | *
1240 | */
1241 | p5.Element.prototype.center = function(align) {
1242 | var style = this.elt.style.display;
1243 | var hidden = this.elt.style.display === 'none';
1244 | var parentHidden = this.parent().style.display === 'none';
1245 | var pos = { x : this.elt.offsetLeft, y : this.elt.offsetTop };
1246 |
1247 | if (hidden) this.show();
1248 |
1249 | this.elt.style.display = 'block';
1250 | this.position(0,0);
1251 |
1252 | if (parentHidden) this.parent().style.display = 'block';
1253 |
1254 | var wOffset = Math.abs(this.parent().offsetWidth - this.elt.offsetWidth);
1255 | var hOffset = Math.abs(this.parent().offsetHeight - this.elt.offsetHeight);
1256 | var y = pos.y;
1257 | var x = pos.x;
1258 |
1259 | if (align === 'both' || align === undefined){
1260 | this.position(wOffset/2, hOffset/2);
1261 | }else if (align === 'horizontal'){
1262 | this.position(wOffset/2, y);
1263 | }else if (align === 'vertical'){
1264 | this.position(x, hOffset/2);
1265 | }
1266 |
1267 | this.style('display', style);
1268 |
1269 | if (hidden) this.hide();
1270 |
1271 | if (parentHidden) this.parent().style.display = 'none';
1272 |
1273 | return this;
1274 | };
1275 |
1276 | /**
1277 | *
1278 | * If an argument is given, sets the inner HTML of the element,
1279 | * replacing any existing html. If true is included as a second
1280 | * argument, html is appended instead of replacing existing html.
1281 | * If no arguments are given, returns
1282 | * the inner HTML of the element.
1283 | *
1284 | * @for p5.Element
1285 | * @method html
1286 | * @param {String} [html] the HTML to be placed inside the element
1287 | * @param {boolean} [append] whether to append HTML to existing
1288 | * @return {Object|p5.Element|String}
1289 | * @example
1290 | *
1291 | * var div = createDiv('').size(100,100);
1292 | * div.html('hi');
1293 | *
1294 | *
1295 | * var div = createDiv('Hello ').size(100,100);
1296 | * div.html('World', true);
1297 | *
1298 | */
1299 | p5.Element.prototype.html = function() {
1300 | if (arguments.length === 0) {
1301 | return this.elt.innerHTML;
1302 | } else if (arguments[1]) {
1303 | this.elt.innerHTML += arguments[0];
1304 | return this;
1305 | } else {
1306 | this.elt.innerHTML = arguments[0];
1307 | return this;
1308 | }
1309 | };
1310 |
1311 | /**
1312 | *
1313 | * Sets the position of the element relative to (0, 0) of the
1314 | * window. Essentially, sets position:absolute and left and top
1315 | * properties of style. If no arguments given returns the x and y position
1316 | * of the element in an object.
1317 | *
1318 | * @method position
1319 | * @param {Number} [x] x-position relative to upper left of window
1320 | * @param {Number} [y] y-position relative to upper left of window
1321 | * @return {Object|p5.Element}
1322 | * @example
1323 | *
1324 | * function setup() {
1325 | * var cnv = createCanvas(100, 100);
1326 | * // positions canvas 50px to the right and 100px
1327 | * // below upper left corner of the window
1328 | * cnv.position(50, 100);
1329 | * }
1330 | *
1331 | */
1332 | p5.Element.prototype.position = function() {
1333 | if (arguments.length === 0){
1334 | return { 'x' : this.elt.offsetLeft , 'y' : this.elt.offsetTop };
1335 | }else{
1336 | this.elt.style.position = 'absolute';
1337 | this.elt.style.left = arguments[0]+'px';
1338 | this.elt.style.top = arguments[1]+'px';
1339 | this.x = arguments[0];
1340 | this.y = arguments[1];
1341 | return this;
1342 | }
1343 | };
1344 |
1345 | /* Helper method called by p5.Element.style() */
1346 | p5.Element.prototype._translate = function(){
1347 | this.elt.style.position = 'absolute';
1348 | // save out initial non-translate transform styling
1349 | var transform = '';
1350 | if (this.elt.style.transform) {
1351 | transform = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1352 | transform = transform.replace(/translate[X-Z]?\(.*\)/g, '');
1353 | }
1354 | if (arguments.length === 2) {
1355 | this.elt.style.transform = 'translate('+arguments[0]+'px, '+arguments[1]+'px)';
1356 | } else if (arguments.length > 2) {
1357 | this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
1358 | if (arguments.length === 3) {
1359 | this.elt.parentElement.style.perspective = '1000px';
1360 | } else {
1361 | this.elt.parentElement.style.perspective = arguments[3]+'px';
1362 | }
1363 | }
1364 | // add any extra transform styling back on end
1365 | this.elt.style.transform += transform;
1366 | return this;
1367 | };
1368 |
1369 | /* Helper method called by p5.Element.style() */
1370 | p5.Element.prototype._rotate = function(){
1371 | // save out initial non-rotate transform styling
1372 | var transform = '';
1373 | if (this.elt.style.transform) {
1374 | var transform = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1375 | transform = transform.replace(/rotate[X-Z]?\(.*\)/g, '');
1376 | }
1377 |
1378 | if (arguments.length === 1){
1379 | this.elt.style.transform = 'rotate('+arguments[0]+'deg)';
1380 | }else if (arguments.length === 2){
1381 | this.elt.style.transform = 'rotate('+arguments[0]+'deg, '+arguments[1]+'deg)';
1382 | }else if (arguments.length === 3){
1383 | this.elt.style.transform = 'rotateX('+arguments[0]+'deg)';
1384 | this.elt.style.transform += 'rotateY('+arguments[1]+'deg)';
1385 | this.elt.style.transform += 'rotateZ('+arguments[2]+'deg)';
1386 | }
1387 | // add remaining transform back on
1388 | this.elt.style.transform += transform;
1389 | return this;
1390 | };
1391 |
1392 | /**
1393 | * Sets the given style (css) property (1st arg) of the element with the
1394 | * given value (2nd arg). If a single argument is given, .style()
1395 | * returns the value of the given property; however, if the single argument
1396 | * is given in css syntax ('text-align:center'), .style() sets the css
1397 | * appropriatly. .style() also handles 2d and 3d css transforms. If
1398 | * the 1st arg is 'rotate', 'translate', or 'position', the following arguments
1399 | * accept Numbers as values. ('translate', 10, 100, 50);
1400 | *
1401 | * @method style
1402 | * @param {String} property property to be set
1403 | * @param {String|Number|p5.Color} [value] value to assign to property (only String|Number for rotate/translate)
1404 | * @return {String|Object|p5.Element} value of property, if no value is specified
1405 | * or p5.Element
1406 | * @example
1407 | *
1408 | * var myDiv = createDiv("I like pandas.");
1409 | * myDiv.style("font-size", "18px");
1410 | * myDiv.style("color", "#ff0000");
1411 | *
1412 | *
1413 | * var col = color(25,23,200,50);
1414 | * var button = createButton("button");
1415 | * button.style("background-color", col);
1416 | * button.position(10, 10);
1417 | *
1418 | *
1419 | * var myDiv = createDiv("I like lizards.");
1420 | * myDiv.style("position", 20, 20);
1421 | * myDiv.style("rotate", 45);
1422 | *
1423 | *
1424 | * var myDiv;
1425 | * function setup() {
1426 | * background(200);
1427 | * myDiv = createDiv("I like gray.");
1428 | * myDiv.position(20, 20);
1429 | * }
1430 | *
1431 | * function draw() {
1432 | * myDiv.style("font-size", mouseX+"px");
1433 | * }
1434 | *
1435 | */
1436 | p5.Element.prototype.style = function(prop, val) {
1437 | var self = this;
1438 |
1439 | if (val instanceof p5.Color) {
1440 | val = 'rgba(' + val.levels[0] + ',' + val.levels[1] + ',' + val.levels[2] + ',' + val.levels[3]/255 + ')'
1441 | }
1442 |
1443 | if (typeof val === 'undefined') {
1444 | if (prop.indexOf(':') === -1) {
1445 | var styles = window.getComputedStyle(self.elt);
1446 | var style = styles.getPropertyValue(prop);
1447 | return style;
1448 | } else {
1449 | var attrs = prop.split(';');
1450 | for (var i = 0; i < attrs.length; i++) {
1451 | var parts = attrs[i].split(':');
1452 | if (parts[0] && parts[1]) {
1453 | this.elt.style[parts[0].trim()] = parts[1].trim();
1454 | }
1455 | }
1456 | }
1457 | } else {
1458 | if (prop === 'rotate' || prop === 'translate' || prop === 'position'){
1459 | var trans = Array.prototype.shift.apply(arguments);
1460 | var f = this[trans] || this['_'+trans];
1461 | f.apply(this, arguments);
1462 | } else {
1463 | this.elt.style[prop] = val;
1464 | if (prop === 'width' || prop === 'height' || prop === 'left' || prop === 'top') {
1465 | var numVal = val.replace(/\D+/g, '');
1466 | this[prop] = parseInt(numVal, 10); // pend: is this necessary?
1467 | }
1468 | }
1469 | }
1470 | return this;
1471 | };
1472 |
1473 |
1474 | /**
1475 | *
1476 | * Adds a new attribute or changes the value of an existing attribute
1477 | * on the specified element. If no value is specified, returns the
1478 | * value of the given attribute, or null if attribute is not set.
1479 | *
1480 | * @method attribute
1481 | * @param {String} attr attribute to set
1482 | * @param {String} [value] value to assign to attribute
1483 | * @return {String|Object|p5.Element} value of attribute, if no value is
1484 | * specified or p5.Element
1485 | * @example
1486 | *
1487 | * var myDiv = createDiv("I like pandas.");
1488 | * myDiv.attribute("align", "center");
1489 | *
1490 | */
1491 | p5.Element.prototype.attribute = function(attr, value) {
1492 | //handling for checkboxes and radios to ensure options get
1493 | //attributes not divs
1494 | if(this.elt.firstChild != null &&
1495 | (this.elt.firstChild.type === 'checkbox' ||
1496 | this.elt.firstChild.type === 'radio')) {
1497 | if(typeof value === 'undefined') {
1498 | return this.elt.firstChild.getAttribute(attr);
1499 | } else {
1500 | for(var i=0; i
1524 | * var button;
1525 | * var checkbox;
1526 | *
1527 | * function setup() {
1528 | * checkbox = createCheckbox('enable', true);
1529 | * checkbox.changed(enableButton);
1530 | * button = createButton('button');
1531 | * button.position(10, 10);
1532 | * }
1533 | *
1534 | * function enableButton() {
1535 | * if( this.checked() ) {
1536 | * // Re-enable the button
1537 | * button.removeAttribute('disabled');
1538 | * } else {
1539 | * // Disable the button
1540 | * button.attribute('disabled','');
1541 | * }
1542 | * }
1543 | *
1544 | */
1545 | p5.Element.prototype.removeAttribute = function(attr) {
1546 | if(this.elt.firstChild != null &&
1547 | (this.elt.firstChild.type === 'checkbox' ||
1548 | this.elt.firstChild.type === 'radio')) {
1549 | for(var i=0; i
1567 | * // gets the value
1568 | * var inp;
1569 | * function setup() {
1570 | * inp = createInput('');
1571 | * }
1572 | *
1573 | * function mousePressed() {
1574 | * print(inp.value());
1575 | * }
1576 | *
1577 | *
1578 | * // sets the value
1579 | * var inp;
1580 | * function setup() {
1581 | * inp = createInput('myValue');
1582 | * }
1583 | *
1584 | * function mousePressed() {
1585 | * inp.value("myValue");
1586 | * }
1587 | *
1588 | */
1589 | p5.Element.prototype.value = function() {
1590 | if (arguments.length > 0) {
1591 | this.elt.value = arguments[0];
1592 | return this;
1593 | } else {
1594 | if (this.elt.type === 'range') {
1595 | return parseFloat(this.elt.value);
1596 | }
1597 | else return this.elt.value;
1598 | }
1599 | };
1600 |
1601 | /**
1602 | *
1603 | * Shows the current element. Essentially, setting display:block for the style.
1604 | *
1605 | * @method show
1606 | * @return {Object|p5.Element}
1607 | * @example
1608 | *
1609 | * var div = createDiv('div');
1610 | * div.style("display", "none");
1611 | * div.show(); // turns display to block
1612 | *
1613 | */
1614 | p5.Element.prototype.show = function() {
1615 | this.elt.style.display = 'block';
1616 | return this;
1617 | };
1618 |
1619 | /**
1620 | * Hides the current element. Essentially, setting display:none for the style.
1621 | *
1622 | * @method hide
1623 | * @return {Object|p5.Element}
1624 | * @example
1625 | *
1626 | * var div = createDiv('this is a div');
1627 | * div.hide();
1628 | *
1629 | */
1630 | p5.Element.prototype.hide = function() {
1631 | this.elt.style.display = 'none';
1632 | return this;
1633 | };
1634 |
1635 | /**
1636 | *
1637 | * Sets the width and height of the element. AUTO can be used to
1638 | * only adjust one dimension. If no arguments given returns the width and height
1639 | * of the element in an object.
1640 | *
1641 | * @method size
1642 | * @param {Number} [w] width of the element
1643 | * @param {Number} [h] height of the element
1644 | * @return {Object|p5.Element}
1645 | * @example
1646 | *
1647 | * var div = createDiv('this is a div');
1648 | * div.size(100, 100);
1649 | *
1650 | */
1651 | p5.Element.prototype.size = function(w, h) {
1652 | if (arguments.length === 0){
1653 | return { 'width' : this.elt.offsetWidth , 'height' : this.elt.offsetHeight };
1654 | }else{
1655 | var aW = w;
1656 | var aH = h;
1657 | var AUTO = p5.prototype.AUTO;
1658 | if (aW !== AUTO || aH !== AUTO) {
1659 | if (aW === AUTO) {
1660 | aW = h * this.width / this.height;
1661 | } else if (aH === AUTO) {
1662 | aH = w * this.height / this.width;
1663 | }
1664 | // set diff for cnv vs normal div
1665 | if (this.elt instanceof HTMLCanvasElement) {
1666 | var j = {};
1667 | var k = this.elt.getContext('2d');
1668 | for (var prop in k) {
1669 | j[prop] = k[prop];
1670 | }
1671 | this.elt.setAttribute('width', aW * this._pInst._pixelDensity);
1672 | this.elt.setAttribute('height', aH * this._pInst._pixelDensity);
1673 | this.elt.setAttribute('style', 'width:' + aW + 'px; height:' + aH + 'px');
1674 | this._pInst.scale(this._pInst._pixelDensity, this._pInst._pixelDensity);
1675 | for (var prop in j) {
1676 | this.elt.getContext('2d')[prop] = j[prop];
1677 | }
1678 | } else {
1679 | this.elt.style.width = aW+'px';
1680 | this.elt.style.height = aH+'px';
1681 | this.elt.width = aW;
1682 | this.elt.height = aH;
1683 | this.width = aW;
1684 | this.height = aH;
1685 | }
1686 |
1687 | this.width = this.elt.offsetWidth;
1688 | this.height = this.elt.offsetHeight;
1689 |
1690 | if (this._pInst) { // main canvas associated with p5 instance
1691 | if (this._pInst._curElement.elt === this.elt) {
1692 | this._pInst._setProperty('width', this.elt.offsetWidth);
1693 | this._pInst._setProperty('height', this.elt.offsetHeight);
1694 | }
1695 | }
1696 | }
1697 | return this;
1698 | }
1699 | };
1700 |
1701 | /**
1702 | * Removes the element and deregisters all listeners.
1703 | * @method remove
1704 | * @example
1705 | *
1706 | * var myDiv = createDiv('this is some text');
1707 | * myDiv.remove();
1708 | *
1709 | */
1710 | p5.Element.prototype.remove = function() {
1711 | // deregister events
1712 | for (var ev in this._events) {
1713 | this.elt.removeEventListener(ev, this._events[ev]);
1714 | }
1715 | if (this.elt.parentNode) {
1716 | this.elt.parentNode.removeChild(this.elt);
1717 | }
1718 | delete(this);
1719 | };
1720 |
1721 |
1722 |
1723 | // =============================================================================
1724 | // p5.MediaElement additions
1725 | // =============================================================================
1726 |
1727 |
1728 | /**
1729 | * Extends p5.Element to handle audio and video. In addition to the methods
1730 | * of p5.Element, it also contains methods for controlling media. It is not
1731 | * called directly, but p5.MediaElements are created by calling createVideo,
1732 | * createAudio, and createCapture.
1733 | *
1734 | * @class p5.MediaElement
1735 | * @constructor
1736 | * @param {String} elt DOM node that is wrapped
1737 | */
1738 | p5.MediaElement = function(elt, pInst) {
1739 | p5.Element.call(this, elt, pInst);
1740 |
1741 | var self = this;
1742 | this.elt.crossOrigin = 'anonymous';
1743 |
1744 | this._prevTime = 0;
1745 | this._cueIDCounter = 0;
1746 | this._cues = [];
1747 | this._pixelDensity = 1;
1748 | this._modified = false;
1749 |
1750 | /**
1751 | * Path to the media element source.
1752 | *
1753 | * @property src
1754 | * @return {String} src
1755 | * @example
1756 | *
1757 | * var ele;
1758 | *
1759 | * function setup() {
1760 | * background(250);
1761 | *
1762 | * //p5.MediaElement objects are usually created
1763 | * //by calling the createAudio(), createVideo(),
1764 | * //and createCapture() functions.
1765 | *
1766 | * //In this example we create
1767 | * //a new p5.MediaElement via createAudio().
1768 | * ele = createAudio('assets/beat.mp3');
1769 | *
1770 | * //We'll set up our example so that
1771 | * //when you click on the text,
1772 | * //an alert box displays the MediaElement's
1773 | * //src field.
1774 | * textAlign(CENTER);
1775 | * text("Click Me!", width/2, height/2);
1776 | * }
1777 | *
1778 | * function mouseClicked() {
1779 | * //here we test if the mouse is over the
1780 | * //canvas element when it's clicked
1781 | * if(mouseX >= 0 && mouseX <= width &&
1782 | * mouseY >= 0 && mouseY <= height) {
1783 | * //Show our p5.MediaElement's src field
1784 | * alert(ele.src);
1785 | * }
1786 | * }
1787 | *
1788 | *
1789 | */
1790 | Object.defineProperty(self, 'src', {
1791 | get: function() {
1792 | var firstChildSrc = self.elt.children[0].src;
1793 | var srcVal = self.elt.src === window.location.href ? '' : self.elt.src;
1794 | var ret = firstChildSrc === window.location.href ? srcVal : firstChildSrc;
1795 | return ret;
1796 | },
1797 | set: function(newValue) {
1798 | for (var i = 0; i < self.elt.children.length; i++) {
1799 | self.elt.removeChild(self.elt.children[i]);
1800 | }
1801 | var source = document.createElement('source');
1802 | source.src = newValue;
1803 | elt.appendChild(source);
1804 | self.elt.src = newValue;
1805 | self.modified = true;
1806 | },
1807 | });
1808 |
1809 | // private _onended callback, set by the method: onended(callback)
1810 | self._onended = function() {};
1811 | self.elt.onended = function() {
1812 | self._onended(self);
1813 | }
1814 | };
1815 | p5.MediaElement.prototype = Object.create(p5.Element.prototype);
1816 |
1817 |
1818 |
1819 |
1820 | /**
1821 | * Play an HTML5 media element.
1822 | *
1823 | * @method play
1824 | * @return {Object|p5.Element}
1825 | * @example
1826 | *
1827 | * var ele;
1828 | *
1829 | * function setup() {
1830 | * //p5.MediaElement objects are usually created
1831 | * //by calling the createAudio(), createVideo(),
1832 | * //and createCapture() functions.
1833 | *
1834 | * //In this example we create
1835 | * //a new p5.MediaElement via createAudio().
1836 | * ele = createAudio('assets/beat.mp3');
1837 | *
1838 | * background(250);
1839 | * textAlign(CENTER);
1840 | * text("Click to Play!", width/2, height/2);
1841 | * }
1842 | *
1843 | * function mouseClicked() {
1844 | * //here we test if the mouse is over the
1845 | * //canvas element when it's clicked
1846 | * if(mouseX >= 0 && mouseX <= width &&
1847 | * mouseY >= 0 && mouseY <= height) {
1848 | *
1849 | * //Here we call the play() function on
1850 | * //the p5.MediaElement we created above.
1851 | * //This will start the audio sample.
1852 | * ele.play();
1853 | *
1854 | * background(200);
1855 | * text("You clicked Play!", width/2, height/2);
1856 | * }
1857 | * }
1858 | *
1859 | */
1860 | p5.MediaElement.prototype.play = function() {
1861 | if (this.elt.currentTime === this.elt.duration) {
1862 | this.elt.currentTime = 0;
1863 | }
1864 |
1865 | if (this.elt.readyState > 1) {
1866 | this.elt.play();
1867 | } else {
1868 | // in Chrome, playback cannot resume after being stopped and must reload
1869 | this.elt.load();
1870 | this.elt.play();
1871 | }
1872 | return this;
1873 | };
1874 |
1875 | /**
1876 | * Stops an HTML5 media element (sets current time to zero).
1877 | *
1878 | * @method stop
1879 | * @return {Object|p5.Element}
1880 | * @example
1881 | *
1882 | *
1883 | * //This example both starts
1884 | * //and stops a sound sample
1885 | * //when the user clicks the canvas
1886 | *
1887 | * //We will store the p5.MediaElement
1888 | * //object in here
1889 | * var ele;
1890 | *
1891 | * //while our audio is playing,
1892 | * //this will be set to true
1893 | * var sampleIsPlaying = false;
1894 | *
1895 | * function setup() {
1896 | * //Here we create a p5.MediaElement object
1897 | * //using the createAudio() function.
1898 | * ele = createAudio('assets/beat.mp3');
1899 | * background(200);
1900 | * textAlign(CENTER);
1901 | * text("Click to play!", width/2, height/2);
1902 | * }
1903 | *
1904 | * function mouseClicked() {
1905 | * //here we test if the mouse is over the
1906 | * //canvas element when it's clicked
1907 | * if(mouseX >= 0 && mouseX <= width &&
1908 | * mouseY >= 0 && mouseY <= height) {
1909 | * background(200);
1910 | *
1911 | * if(sampleIsPlaying) {
1912 | * //if the sample is currently playing
1913 | * //calling the stop() function on
1914 | * //our p5.MediaElement will stop
1915 | * //it and reset its current
1916 | * //time to 0 (i.e. it will start
1917 | * //at the beginning the next time
1918 | * //you play it)
1919 | * ele.stop();
1920 | *
1921 | * sampleIsPlaying = false;
1922 | * text("Click to play!", width/2, height/2);
1923 | * } else {
1924 | * //loop our sound element until we
1925 | * //call ele.stop() on it.
1926 | * ele.loop();
1927 | *
1928 | * sampleIsPlaying = true;
1929 | * text("Click to stop!", width/2, height/2);
1930 | * }
1931 | * }
1932 | * }
1933 | *
1934 | *
1935 | */
1936 | p5.MediaElement.prototype.stop = function() {
1937 | this.elt.pause();
1938 | this.elt.currentTime = 0;
1939 | return this;
1940 | };
1941 |
1942 | /**
1943 | * Pauses an HTML5 media element.
1944 | *
1945 | * @method pause
1946 | * @return {Object|p5.Element}
1947 | * @example
1948 | *
1949 | * //This example both starts
1950 | * //and pauses a sound sample
1951 | * //when the user clicks the canvas
1952 | *
1953 | * //We will store the p5.MediaElement
1954 | * //object in here
1955 | * var ele;
1956 | *
1957 | * //while our audio is playing,
1958 | * //this will be set to true
1959 | * var sampleIsPlaying = false;
1960 | *
1961 | * function setup() {
1962 | * //Here we create a p5.MediaElement object
1963 | * //using the createAudio() function.
1964 | * ele = createAudio('assets/lucky_dragons_-_power_melody.mp3');
1965 | * background(200);
1966 | * textAlign(CENTER);
1967 | * text("Click to play!", width/2, height/2);
1968 | * }
1969 | *
1970 | * function mouseClicked() {
1971 | * //here we test if the mouse is over the
1972 | * //canvas element when it's clicked
1973 | * if(mouseX >= 0 && mouseX <= width &&
1974 | * mouseY >= 0 && mouseY <= height) {
1975 | * background(200);
1976 | *
1977 | * if(sampleIsPlaying) {
1978 | * //Calling pause() on our
1979 | * //p5.MediaElement will stop it
1980 | * //playing, but when we call the
1981 | * //loop() or play() functions
1982 | * //the sample will start from
1983 | * //where we paused it.
1984 | * ele.pause();
1985 | *
1986 | * sampleIsPlaying = false;
1987 | * text("Click to resume!", width/2, height/2);
1988 | * } else {
1989 | * //loop our sound element until we
1990 | * //call ele.pause() on it.
1991 | * ele.loop();
1992 | *
1993 | * sampleIsPlaying = true;
1994 | * text("Click to pause!", width/2, height/2);
1995 | * }
1996 | * }
1997 | * }
1998 | *
1999 | *
2000 | */
2001 | p5.MediaElement.prototype.pause = function() {
2002 | this.elt.pause();
2003 | return this;
2004 | };
2005 |
2006 | /**
2007 | * Set 'loop' to true for an HTML5 media element, and starts playing.
2008 | *
2009 | * @method loop
2010 | * @return {Object|p5.Element}
2011 | * @example
2012 | *
2013 | * //Clicking the canvas will loop
2014 | * //the audio sample until the user
2015 | * //clicks again to stop it
2016 | *
2017 | * //We will store the p5.MediaElement
2018 | * //object in here
2019 | * var ele;
2020 | *
2021 | * //while our audio is playing,
2022 | * //this will be set to true
2023 | * var sampleIsLooping = false;
2024 | *
2025 | * function setup() {
2026 | * //Here we create a p5.MediaElement object
2027 | * //using the createAudio() function.
2028 | * ele = createAudio('assets/lucky_dragons_-_power_melody.mp3');
2029 | * background(200);
2030 | * textAlign(CENTER);
2031 | * text("Click to loop!", width/2, height/2);
2032 | * }
2033 | *
2034 | * function mouseClicked() {
2035 | * //here we test if the mouse is over the
2036 | * //canvas element when it's clicked
2037 | * if(mouseX >= 0 && mouseX <= width &&
2038 | * mouseY >= 0 && mouseY <= height) {
2039 | * background(200);
2040 | *
2041 | * if(sampleIsLooping == false) {
2042 | * //loop our sound element until we
2043 | * //call ele.stop() on it.
2044 | * ele.loop();
2045 | *
2046 | * sampleIsLooping = true;
2047 | * text("Click to stop!", width/2, height/2);
2048 | * } else {
2049 | * ele.stop();
2050 | *
2051 | * sampleIsLooping = false;
2052 | * text("Click to loop!", width/2, height/2);
2053 | * }
2054 | * }
2055 | * }
2056 | *
2057 | *
2058 | */
2059 | p5.MediaElement.prototype.loop = function() {
2060 | this.elt.setAttribute('loop', true);
2061 | this.play();
2062 | return this;
2063 | };
2064 | /**
2065 | * Set 'loop' to false for an HTML5 media element. Element will stop
2066 | * when it reaches the end.
2067 | *
2068 | * @method noLoop
2069 | * @return {Object|p5.Element}
2070 | */
2071 | p5.MediaElement.prototype.noLoop = function() {
2072 | this.elt.setAttribute('loop', false);
2073 | return this;
2074 | };
2075 |
2076 |
2077 | /**
2078 | * Set HTML5 media element to autoplay or not.
2079 | *
2080 | * @method autoplay
2081 | * @param {Boolean} autoplay whether the element should autoplay
2082 | * @return {Object|p5.Element}
2083 | */
2084 | p5.MediaElement.prototype.autoplay = function(val) {
2085 | this.elt.setAttribute('autoplay', val);
2086 | return this;
2087 | };
2088 |
2089 | /**
2090 | * Sets volume for this HTML5 media element. If no argument is given,
2091 | * returns the current volume.
2092 | *
2093 | * @param {Number} [val] volume between 0.0 and 1.0
2094 | * @return {Number|p5.MediaElement} current volume or p5.MediaElement
2095 | * @method volume
2096 | */
2097 | p5.MediaElement.prototype.volume = function(val) {
2098 | if (typeof val === 'undefined') {
2099 | return this.elt.volume;
2100 | } else {
2101 | this.elt.volume = val;
2102 | }
2103 | };
2104 |
2105 | /**
2106 | * If no arguments are given, returns the current playback speed of the
2107 | * element. The speed parameter sets the speed where 2.0 will play the
2108 | * element twice as fast, 0.5 will play at half the speed, and -1 will play
2109 | * the element in normal speed in reverse.(Note that not all browsers support
2110 | * backward playback and even if they do, playback might not be smooth.)
2111 | *
2112 | * @method speed
2113 | * @param {Number} [speed] speed multiplier for element playback
2114 | * @return {Number|Object|p5.MediaElement} current playback speed or p5.MediaElement
2115 | */
2116 | p5.MediaElement.prototype.speed = function(val) {
2117 | if (typeof val === 'undefined') {
2118 | return this.elt.playbackRate;
2119 | } else {
2120 | this.elt.playbackRate = val;
2121 | }
2122 | };
2123 |
2124 | /**
2125 | * If no arguments are given, returns the current time of the element.
2126 | * If an argument is given the current time of the element is set to it.
2127 | *
2128 | * @method time
2129 | * @param {Number} [time] time to jump to (in seconds)
2130 | * @return {Number|Object|p5.MediaElement} current time (in seconds)
2131 | * or p5.MediaElement
2132 | */
2133 | p5.MediaElement.prototype.time = function(val) {
2134 | if (typeof val === 'undefined') {
2135 | return this.elt.currentTime;
2136 | } else {
2137 | this.elt.currentTime = val;
2138 | }
2139 | };
2140 |
2141 | /**
2142 | * Returns the duration of the HTML5 media element.
2143 | *
2144 | * @method duration
2145 | * @return {Number} duration
2146 | */
2147 | p5.MediaElement.prototype.duration = function() {
2148 | return this.elt.duration;
2149 | };
2150 | p5.MediaElement.prototype.pixels = [];
2151 | p5.MediaElement.prototype.loadPixels = function() {
2152 | if (!this.canvas) {
2153 | this.canvas = document.createElement('canvas');
2154 | this.drawingContext = this.canvas.getContext('2d');
2155 | }
2156 | if (this.loadedmetadata) { // wait for metadata for w/h
2157 | if (this.canvas.width !== this.elt.width) {
2158 | this.canvas.width = this.elt.width;
2159 | this.canvas.height = this.elt.height;
2160 | this.width = this.canvas.width;
2161 | this.height = this.canvas.height;
2162 | }
2163 | this.drawingContext.drawImage(this.elt, 0, 0, this.canvas.width, this.canvas.height);
2164 | p5.Renderer2D.prototype.loadPixels.call(this);
2165 | }
2166 | this.setModified(true);
2167 | return this;
2168 | }
2169 | p5.MediaElement.prototype.updatePixels = function(x, y, w, h){
2170 | if (this.loadedmetadata) { // wait for metadata
2171 | p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h);
2172 | }
2173 | this.setModified(true);
2174 | return this;
2175 | }
2176 | p5.MediaElement.prototype.get = function(x, y, w, h){
2177 | if (this.loadedmetadata) { // wait for metadata
2178 | return p5.Renderer2D.prototype.get.call(this, x, y, w, h);
2179 | } else if (typeof x === 'undefined') {
2180 | return new p5.Image(1, 1);
2181 | } else if (w > 1) {
2182 | return new p5.Image(x, y, w, h);
2183 | } else {
2184 | return [0, 0, 0, 255];
2185 | }
2186 | };
2187 | p5.MediaElement.prototype.set = function(x, y, imgOrCol){
2188 | if (this.loadedmetadata) { // wait for metadata
2189 | p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol);
2190 | this.setModified(true);
2191 | }
2192 | };
2193 | p5.MediaElement.prototype.copy = function(){
2194 | p5.Renderer2D.prototype.copy.apply(this, arguments);
2195 | };
2196 | p5.MediaElement.prototype.mask = function(){
2197 | this.loadPixels();
2198 | this.setModified(true);
2199 | p5.Image.prototype.mask.apply(this, arguments);
2200 | };
2201 | /**
2202 | * helper method for web GL mode to figure out if the element
2203 | * has been modified and might need to be re-uploaded to texture
2204 | * memory between frames.
2205 | * @method isModified
2206 | * @private
2207 | * @return {boolean} a boolean indicating whether or not the
2208 | * image has been updated or modified since last texture upload.
2209 | */
2210 | p5.MediaElement.prototype.isModified = function () {
2211 | return this._modified;
2212 | }
2213 | /**
2214 | * helper method for web GL mode to indicate that an element has been
2215 | * changed or unchanged since last upload. gl texture upload will
2216 | * set this value to false after uploading the texture; or might set
2217 | * it to true if metadata has become available but there is no actual
2218 | * texture data available yet..
2219 | * @method setModified
2220 | * @param {boolean} val sets whether or not the element has been
2221 | * modified.
2222 | * @private
2223 | */
2224 | p5.MediaElement.prototype.setModified = function (value) {
2225 | this._modified = value;
2226 | }
2227 | /**
2228 | * Schedule an event to be called when the audio or video
2229 | * element reaches the end. If the element is looping,
2230 | * this will not be called. The element is passed in
2231 | * as the argument to the onended callback.
2232 | *
2233 | * @method onended
2234 | * @param {Function} callback function to call when the
2235 | * soundfile has ended. The
2236 | * media element will be passed
2237 | * in as the argument to the
2238 | * callback.
2239 | * @return {Object|p5.MediaElement}
2240 | * @example
2241 | *
2242 | * function setup() {
2243 | * audioEl = createAudio('assets/beat.mp3');
2244 | * audioEl.showControls(true);
2245 | * audioEl.onended(sayDone);
2246 | * }
2247 | *
2248 | * function sayDone(elt) {
2249 | * alert('done playing ' + elt.src );
2250 | * }
2251 | *
2252 | */
2253 | p5.MediaElement.prototype.onended = function(callback) {
2254 | this._onended = callback;
2255 | return this;
2256 | };
2257 |
2258 |
2259 | /*** CONNECT TO WEB AUDIO API / p5.sound.js ***/
2260 |
2261 | /**
2262 | * Send the audio output of this element to a specified audioNode or
2263 | * p5.sound object. If no element is provided, connects to p5's master
2264 | * output. That connection is established when this method is first called.
2265 | * All connections are removed by the .disconnect() method.
2266 | *
2267 | * This method is meant to be used with the p5.sound.js addon library.
2268 | *
2269 | * @method connect
2270 | * @param {AudioNode|Object} audioNode AudioNode from the Web Audio API,
2271 | * or an object from the p5.sound library
2272 | */
2273 | p5.MediaElement.prototype.connect = function(obj) {
2274 | var audioContext, masterOutput;
2275 |
2276 | // if p5.sound exists, same audio context
2277 | if (typeof p5.prototype.getAudioContext === 'function') {
2278 | audioContext = p5.prototype.getAudioContext();
2279 | masterOutput = p5.soundOut.input;
2280 | } else {
2281 | try {
2282 | audioContext = obj.context;
2283 | masterOutput = audioContext.destination
2284 | } catch(e) {
2285 | throw 'connect() is meant to be used with Web Audio API or p5.sound.js'
2286 | }
2287 | }
2288 |
2289 | // create a Web Audio MediaElementAudioSourceNode if none already exists
2290 | if (!this.audioSourceNode) {
2291 | this.audioSourceNode = audioContext.createMediaElementSource(this.elt);
2292 |
2293 | // connect to master output when this method is first called
2294 | this.audioSourceNode.connect(masterOutput);
2295 | }
2296 |
2297 | // connect to object if provided
2298 | if (obj) {
2299 | if (obj.input) {
2300 | this.audioSourceNode.connect(obj.input);
2301 | } else {
2302 | this.audioSourceNode.connect(obj);
2303 | }
2304 | }
2305 |
2306 | // otherwise connect to master output of p5.sound / AudioContext
2307 | else {
2308 | this.audioSourceNode.connect(masterOutput);
2309 | }
2310 |
2311 | };
2312 |
2313 | /**
2314 | * Disconnect all Web Audio routing, including to master output.
2315 | * This is useful if you want to re-route the output through
2316 | * audio effects, for example.
2317 | *
2318 | * @method disconnect
2319 | */
2320 | p5.MediaElement.prototype.disconnect = function() {
2321 | if (this.audioSourceNode) {
2322 | this.audioSourceNode.disconnect();
2323 | } else {
2324 | throw 'nothing to disconnect';
2325 | }
2326 | };
2327 |
2328 |
2329 | /*** SHOW / HIDE CONTROLS ***/
2330 |
2331 | /**
2332 | * Show the default MediaElement controls, as determined by the web browser.
2333 | *
2334 | * @method showControls
2335 | */
2336 | p5.MediaElement.prototype.showControls = function() {
2337 | // must set style for the element to show on the page
2338 | this.elt.style['text-align'] = 'inherit';
2339 | this.elt.controls = true;
2340 | };
2341 |
2342 | /**
2343 | * Hide the default mediaElement controls.
2344 | *
2345 | * @method hideControls
2346 | */
2347 | p5.MediaElement.prototype.hideControls = function() {
2348 | this.elt.controls = false;
2349 | };
2350 |
2351 | /*** SCHEDULE EVENTS ***/
2352 |
2353 | /**
2354 | * Schedule events to trigger every time a MediaElement
2355 | * (audio/video) reaches a playback cue point.
2356 | *
2357 | * Accepts a callback function, a time (in seconds) at which to trigger
2358 | * the callback, and an optional parameter for the callback.
2359 | *
2360 | * Time will be passed as the first parameter to the callback function,
2361 | * and param will be the second parameter.
2362 | *
2363 | *
2364 | * @method addCue
2365 | * @param {Number} time Time in seconds, relative to this media
2366 | * element's playback. For example, to trigger
2367 | * an event every time playback reaches two
2368 | * seconds, pass in the number 2. This will be
2369 | * passed as the first parameter to
2370 | * the callback function.
2371 | * @param {Function} callback Name of a function that will be
2372 | * called at the given time. The callback will
2373 | * receive time and (optionally) param as its
2374 | * two parameters.
2375 | * @param {Object} [value] An object to be passed as the
2376 | * second parameter to the
2377 | * callback function.
2378 | * @return {Number} id ID of this cue,
2379 | * useful for removeCue(id)
2380 | * @example
2381 | *
2382 | * function setup() {
2383 | * background(255,255,255);
2384 | *
2385 | * audioEl = createAudio('assets/beat.mp3');
2386 | * audioEl.showControls();
2387 | *
2388 | * // schedule three calls to changeBackground
2389 | * audioEl.addCue(0.5, changeBackground, color(255,0,0) );
2390 | * audioEl.addCue(1.0, changeBackground, color(0,255,0) );
2391 | * audioEl.addCue(2.5, changeBackground, color(0,0,255) );
2392 | * audioEl.addCue(3.0, changeBackground, color(0,255,255) );
2393 | * audioEl.addCue(4.2, changeBackground, color(255,255,0) );
2394 | * audioEl.addCue(5.0, changeBackground, color(255,255,0) );
2395 | * }
2396 | *
2397 | * function changeBackground(val) {
2398 | * background(val);
2399 | * }
2400 | *
2401 | */
2402 | p5.MediaElement.prototype.addCue = function(time, callback, val) {
2403 | var id = this._cueIDCounter++;
2404 |
2405 | var cue = new Cue(callback, time, id, val);
2406 | this._cues.push(cue);
2407 |
2408 | if (!this.elt.ontimeupdate) {
2409 | this.elt.ontimeupdate = this._onTimeUpdate.bind(this);
2410 | }
2411 |
2412 | return id;
2413 | };
2414 |
2415 | /**
2416 | * Remove a callback based on its ID. The ID is returned by the
2417 | * addCue method.
2418 | *
2419 | * @method removeCue
2420 | * @param {Number} id ID of the cue, as returned by addCue
2421 | */
2422 | p5.MediaElement.prototype.removeCue = function(id) {
2423 | for (var i = 0; i < this._cues.length; i++) {
2424 | if (this._cues[i] === id) {
2425 | console.log(id)
2426 | this._cues.splice(i, 1);
2427 | }
2428 | }
2429 |
2430 | if (this._cues.length === 0) {
2431 | this.elt.ontimeupdate = null
2432 | }
2433 | };
2434 |
2435 | /**
2436 | * Remove all of the callbacks that had originally been scheduled
2437 | * via the addCue method.
2438 | *
2439 | * @method clearCues
2440 | */
2441 | p5.MediaElement.prototype.clearCues = function() {
2442 | this._cues = [];
2443 | this.elt.ontimeupdate = null;
2444 | };
2445 |
2446 | // private method that checks for cues to be fired if events
2447 | // have been scheduled using addCue(callback, time).
2448 | p5.MediaElement.prototype._onTimeUpdate = function() {
2449 | var playbackTime = this.time();
2450 |
2451 | for (var i = 0 ; i < this._cues.length; i++) {
2452 | var callbackTime = this._cues[i].time;
2453 | var val = this._cues[i].val;
2454 |
2455 |
2456 | if (this._prevTime < callbackTime && callbackTime <= playbackTime) {
2457 |
2458 | // pass the scheduled callbackTime as parameter to the callback
2459 | this._cues[i].callback(val);
2460 | }
2461 |
2462 | }
2463 |
2464 | this._prevTime = playbackTime;
2465 | };
2466 |
2467 |
2468 | // Cue inspired by JavaScript setTimeout, and the
2469 | // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org
2470 | var Cue = function(callback, time, id, val) {
2471 | this.callback = callback;
2472 | this.time = time;
2473 | this.id = id;
2474 | this.val = val;
2475 | };
2476 |
2477 | // =============================================================================
2478 | // p5.File
2479 | // =============================================================================
2480 |
2481 |
2482 | /**
2483 | * Base class for a file
2484 | * Using this for createFileInput
2485 | *
2486 | * @class p5.File
2487 | * @constructor
2488 | * @param {File} file File that is wrapped
2489 | */
2490 | p5.File = function(file, pInst) {
2491 | /**
2492 | * Underlying File object. All normal File methods can be called on this.
2493 | *
2494 | * @property file
2495 | */
2496 | this.file = file;
2497 |
2498 | this._pInst = pInst;
2499 |
2500 | // Splitting out the file type into two components
2501 | // This makes determining if image or text etc simpler
2502 | var typeList = file.type.split('/');
2503 | /**
2504 | * File type (image, text, etc.)
2505 | *
2506 | * @property type
2507 | */
2508 | this.type = typeList[0];
2509 | /**
2510 | * File subtype (usually the file extension jpg, png, xml, etc.)
2511 | *
2512 | * @property subtype
2513 | */
2514 | this.subtype = typeList[1];
2515 | /**
2516 | * File name
2517 | *
2518 | * @property name
2519 | */
2520 | this.name = file.name;
2521 | /**
2522 | * File size
2523 | *
2524 | * @property size
2525 | */
2526 | this.size = file.size;
2527 |
2528 | /**
2529 | * URL string containing image data.
2530 | *
2531 | * @property data
2532 | */
2533 | this.data = undefined;
2534 | };
2535 |
2536 | }));
2537 |
--------------------------------------------------------------------------------
/addons/p5.dom.min.js:
--------------------------------------------------------------------------------
1 | /*! p5.js v0.5.16 October 11, 2017 */ !function(a,b){"function"==typeof define&&define.amd?define("p5.dom",["p5"],function(a){b(a)}):b("object"==typeof exports?require("../p5"):a.p5)}(this,function(a){function b(b){var c=document;return"string"==typeof b&&"#"===b[0]?(b=b.slice(1),c=document.getElementById(b)||document):b instanceof a.Element?c=b.elt:b instanceof HTMLElement&&(c=b),c}function c(b){if("INPUT"===b.tagName&&"checkbox"===b.type){var c=new a.Element(b);return c.checked=function(){return 0===arguments.length?this.elt.checked:(arguments[0]?this.elt.checked=!0:this.elt.checked=!1,this)},c}return"VIDEO"===b.tagName||"AUDIO"===b.tagName?new a.MediaElement(b):"SELECT"===b.tagName?createSelect(new a.Element(b)):new a.Element(b)}function d(b,c,d){(c._userNode?c._userNode:document.body).appendChild(b);var e=d?new a.MediaElement(b):new a.Element(b);return c._elements.push(e),e}function e(a,b,c,e){var f=document.createElement(b),c=c||"";"string"==typeof c&&(c=[c]);for(var g=0;g1&&"function"==typeof c[1]?(a.fn=c[1],a.fn()):c.length>1&&"function"==typeof c[2]&&(a.fn=c[2],a.fn())};return b.src=c[0],c.length>1&&"string"==typeof c[1]&&(b.alt=c[1]),b.onload=function(){e()},a=d(b,this)},a.prototype.createA=function(a,b,c){var e=document.createElement("a");return e.href=a,e.innerHTML=b,c&&(e.target=c),d(e,this)},a.prototype.createSlider=function(a,b,c,e){var f=document.createElement("input");return f.type="range",f.min=a,f.max=b,0===e?f.step=1e-18:e&&(f.step=e),"number"==typeof c&&(f.value=c),d(f,this)},a.prototype.createButton=function(a,b){var c=document.createElement("button");return c.innerHTML=a,b&&(c.value=b),d(c,this)},a.prototype.createCheckbox=function(){var a=document.createElement("div"),b=document.createElement("input");b.type="checkbox",a.appendChild(b);var c=d(a,this);if(c.checked=function(){var a=c.elt.getElementsByTagName("input")[0];if(a){if(0===arguments.length)return a.checked;arguments[0]?a.checked=!0:a.checked=!1}return c},this.value=function(a){return c.value=a,this},arguments[0]){var e=Math.random().toString(36).slice(2),f=document.createElement("label");b.setAttribute("id",e),f.htmlFor=e,c.value(arguments[0]),f.appendChild(document.createTextNode(arguments[0])),a.appendChild(f)}return arguments[1]&&(b.checked=!0),c},a.prototype.createSelect=function(){var a,b,c=arguments[0];return"object"==typeof c&&"SELECT"===c.elt.nodeName?(b=c,a=this.elt=c.elt):(a=document.createElement("select"),c&&"boolean"==typeof c&&a.setAttribute("multiple","true"),b=d(a,this)),b.option=function(b,c){for(var d,e=0;e1?f.value=c:f.value=b,a.appendChild(f)}},b.selected=function(a){var b=[];if(arguments.length>0){for(var c=0;c1){var c=a.length,e=a[0].name,f=a[1].name;b=1;for(var g=1;g1?d.value=c:d.value=a,d.setAttribute("name","defaultradio"+b),h.appendChild(d),a){j++;var e=(Math.random().toString(36).slice(2),document.createElement("label"));d.setAttribute("id","defaultradio"+b+"-"+j),e.htmlFor="defaultradio"+b+"-"+j,e.appendChild(document.createTextNode(a)),h.appendChild(e)}return d},i.selected=function(){var a=this.elt.childNodes.length;if(1==arguments.length){for(var b=0;b-1?h.readAsText(g):h.readAsDataURL(g)}}if(window.File&&window.FileReader&&window.FileList&&window.Blob){var f=document.createElement("input");return f.type="file",c&&(f.multiple="multiple"),f.addEventListener("change",e,!1),d(f,this)}console.log("The File APIs are not fully supported in this browser. Cannot create element.")},a.prototype.createVideo=function(a,b){return e(this,"video",a,b)},a.prototype.createAudio=function(a,b){return e(this,"audio",a,b)},a.prototype.VIDEO="video",a.prototype.AUDIO="audio",void 0===navigator.mediaDevices&&(navigator.mediaDevices={}),void 0===navigator.mediaDevices.getUserMedia&&(navigator.mediaDevices.getUserMedia=function(a){var b=navigator.webkitGetUserMedia||navigator.mozGetUserMedia;return b?new Promise(function(c,d){b.call(navigator,a,c,d)}):Promise.reject(new Error("getUserMedia is not implemented in this browser"))}),a.prototype.createCapture=function(){for(var b,c,e=!0,f=!0,g=0;g2&&(this.elt.style.transform="translate3d("+arguments[0]+"px,"+arguments[1]+"px,"+arguments[2]+"px)",3===arguments.length?this.elt.parentElement.style.perspective="1000px":this.elt.parentElement.style.perspective=arguments[3]+"px"),this.elt.style.transform+=a,this},a.Element.prototype._rotate=function(){var a="";if(this.elt.style.transform){var a=this.elt.style.transform.replace(/rotate3d\(.*\)/g,"");a=a.replace(/rotate[X-Z]?\(.*\)/g,"")}return 1===arguments.length?this.elt.style.transform="rotate("+arguments[0]+"deg)":2===arguments.length?this.elt.style.transform="rotate("+arguments[0]+"deg, "+arguments[1]+"deg)":3===arguments.length&&(this.elt.style.transform="rotateX("+arguments[0]+"deg)",this.elt.style.transform+="rotateY("+arguments[1]+"deg)",this.elt.style.transform+="rotateZ("+arguments[2]+"deg)"),this.elt.style.transform+=a,this},a.Element.prototype.style=function(b,c){var d=this;if(c instanceof a.Color&&(c="rgba("+c.levels[0]+","+c.levels[1]+","+c.levels[2]+","+c.levels[3]/255+")"),void 0===c){if(b.indexOf(":")===-1)return window.getComputedStyle(d.elt).getPropertyValue(b);for(var e=b.split(";"),f=0;f0?(this.elt.value=arguments[0],this):"range"===this.elt.type?parseFloat(this.elt.value):this.elt.value},a.Element.prototype.show=function(){return this.elt.style.display="block",this},a.Element.prototype.hide=function(){return this.elt.style.display="none",this},a.Element.prototype.size=function(b,c){if(0===arguments.length)return{width:this.elt.offsetWidth,height:this.elt.offsetHeight};var d=b,e=c,f=a.prototype.AUTO;if(d!==f||e!==f){if(d===f?d=c*this.width/this.height:e===f&&(e=b*this.height/this.width),this.elt instanceof HTMLCanvasElement){var g={},h=this.elt.getContext("2d");for(var i in h)g[i]=h[i];this.elt.setAttribute("width",d*this._pInst._pixelDensity),this.elt.setAttribute("height",e*this._pInst._pixelDensity),this.elt.setAttribute("style","width:"+d+"px; height:"+e+"px"),this._pInst.scale(this._pInst._pixelDensity,this._pInst._pixelDensity);for(var i in g)this.elt.getContext("2d")[i]=g[i]}else this.elt.style.width=d+"px",this.elt.style.height=e+"px",this.elt.width=d,this.elt.height=e,this.width=d,this.height=e;this.width=this.elt.offsetWidth,this.height=this.elt.offsetHeight,this._pInst&&this._pInst._curElement.elt===this.elt&&(this._pInst._setProperty("width",this.elt.offsetWidth),this._pInst._setProperty("height",this.elt.offsetHeight))}return this},a.Element.prototype.remove=function(){for(var a in this._events)this.elt.removeEventListener(a,this._events[a]);this.elt.parentNode&&this.elt.parentNode.removeChild(this.elt),delete this},a.MediaElement=function(b,c){a.Element.call(this,b,c);var d=this;this.elt.crossOrigin="anonymous",this._prevTime=0,this._cueIDCounter=0,this._cues=[],this._pixelDensity=1,this._modified=!1,Object.defineProperty(d,"src",{get:function(){var a=d.elt.children[0].src,b=d.elt.src===window.location.href?"":d.elt.src;return a===window.location.href?b:a},set:function(a){for(var c=0;c1?this.elt.play():(this.elt.load(),this.elt.play()),this},a.MediaElement.prototype.stop=function(){return this.elt.pause(),this.elt.currentTime=0,this},a.MediaElement.prototype.pause=function(){return this.elt.pause(),this},a.MediaElement.prototype.loop=function(){return this.elt.setAttribute("loop",!0),this.play(),this},a.MediaElement.prototype.noLoop=function(){return this.elt.setAttribute("loop",!1),this},a.MediaElement.prototype.autoplay=function(a){return this.elt.setAttribute("autoplay",a),this},a.MediaElement.prototype.volume=function(a){if(void 0===a)return this.elt.volume;this.elt.volume=a},a.MediaElement.prototype.speed=function(a){if(void 0===a)return this.elt.playbackRate;this.elt.playbackRate=a},a.MediaElement.prototype.time=function(a){if(void 0===a)return this.elt.currentTime;this.elt.currentTime=a},a.MediaElement.prototype.duration=function(){return this.elt.duration},a.MediaElement.prototype.pixels=[],a.MediaElement.prototype.loadPixels=function(){return this.canvas||(this.canvas=document.createElement("canvas"),this.drawingContext=this.canvas.getContext("2d")),this.loadedmetadata&&(this.canvas.width!==this.elt.width&&(this.canvas.width=this.elt.width,this.canvas.height=this.elt.height,this.width=this.canvas.width,this.height=this.canvas.height),this.drawingContext.drawImage(this.elt,0,0,this.canvas.width,this.canvas.height),a.Renderer2D.prototype.loadPixels.call(this)),this.setModified(!0),this},a.MediaElement.prototype.updatePixels=function(b,c,d,e){return this.loadedmetadata&&a.Renderer2D.prototype.updatePixels.call(this,b,c,d,e),this.setModified(!0),this},a.MediaElement.prototype.get=function(b,c,d,e){return this.loadedmetadata?a.Renderer2D.prototype.get.call(this,b,c,d,e):void 0===b?new a.Image(1,1):d>1?new a.Image(b,c,d,e):[0,0,0,255]},a.MediaElement.prototype.set=function(b,c,d){this.loadedmetadata&&(a.Renderer2D.prototype.set.call(this,b,c,d),this.setModified(!0))},a.MediaElement.prototype.copy=function(){a.Renderer2D.prototype.copy.apply(this,arguments)},a.MediaElement.prototype.mask=function(){this.loadPixels(),this.setModified(!0),a.Image.prototype.mask.apply(this,arguments)},a.MediaElement.prototype.isModified=function(){return this._modified},a.MediaElement.prototype.setModified=function(a){this._modified=a},a.MediaElement.prototype.onended=function(a){return this._onended=a,this},a.MediaElement.prototype.connect=function(b){var c,d;if("function"==typeof a.prototype.getAudioContext)c=a.prototype.getAudioContext(),d=a.soundOut.input;else try{c=b.context,d=c.destination}catch(a){throw"connect() is meant to be used with Web Audio API or p5.sound.js"}this.audioSourceNode||(this.audioSourceNode=c.createMediaElementSource(this.elt),this.audioSourceNode.connect(d)),b?b.input?this.audioSourceNode.connect(b.input):this.audioSourceNode.connect(b):this.audioSourceNode.connect(d)},a.MediaElement.prototype.disconnect=function(){if(!this.audioSourceNode)throw"nothing to disconnect";this.audioSourceNode.disconnect()},a.MediaElement.prototype.showControls=function(){this.elt.style["text-align"]="inherit",this.elt.controls=!0},a.MediaElement.prototype.hideControls=function(){this.elt.controls=!1},a.MediaElement.prototype.addCue=function(a,b,c){var d=this._cueIDCounter++,e=new f(b,a,d,c);return this._cues.push(e),this.elt.ontimeupdate||(this.elt.ontimeupdate=this._onTimeUpdate.bind(this)),d},a.MediaElement.prototype.removeCue=function(a){for(var b=0;b
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/empty-example/sketch.js:
--------------------------------------------------------------------------------
1 | var guessItem = null;
2 | // controls the frequency that a new random number is generated.
3 | var interval = 60; // changing this to make the game feel faster.
4 | // an array to store solution values
5 | var results = [];
6 | var solution = null;
7 | // stores if the game is over or not.
8 | var gameOver = false;
9 |
10 | function setup() {
11 | createCanvas(800, 300);
12 | }
13 |
14 | function draw() {
15 | // if there are 3 losses or 10 attempts stop the game.
16 | var gameScore = getGameScore(results);
17 | if (gameScore.loss === 3 || gameScore.total === 10) {
18 | gameOver = true;
19 | displayGameOver(gameScore);
20 | return;
21 | }
22 | background(0); // black background
23 | if (frameCount === 1 || frameCount % interval === 0) {
24 | solution = null;
25 | guessItem = new GuessItem(width/2, height/2, 1);
26 | }
27 |
28 | if (guessItem) {
29 | guessItem.render();
30 | }
31 |
32 | if (solution == true || solution === false) {
33 | // displaying a text on screen instead of flat color.
34 | solutionMessage(gameScore.total, solution);
35 | }
36 |
37 | }
38 |
39 | function solutionMessage(seed, solution) {
40 | // display a random message based on a true of false solution.
41 | var trueMessages = [
42 | 'GOOD JOB!',
43 | 'DOING GREAT!',
44 | 'OMG!',
45 | 'SUCH WIN!',
46 | 'I APPRECIATE YOU',
47 | 'IMPRESSIVE'
48 | ];
49 |
50 | var falseMessages = [
51 | 'OH NO!',
52 | 'BETTER LUCK NEXT TIME!',
53 | 'PFTTTT',
54 | ':('
55 | ];
56 |
57 | var messages;
58 |
59 | push();
60 | textAlign(CENTER, CENTER);
61 | fill(237, 34, 93);
62 | textSize(36);
63 | randomSeed(seed * 10000);
64 |
65 | if (solution === true) {
66 | background(255);
67 | messages = trueMessages;
68 | } else if (solution === false) {
69 | background(0);
70 | messages = falseMessages;
71 | }
72 |
73 | text(messages[parseInt(random(messages.length), 10)], width / 2, height / 2);
74 | pop();
75 | }
76 |
77 | function displayGameOver(score) {
78 | // create the Game Over screen
79 | push();
80 | background(255);
81 | textSize(24);
82 | textAlign(CENTER, CENTER);
83 | translate(width / 2, height / 2);
84 | fill(237, 34, 93);
85 | text('GAME OVER!', 0, 0);
86 | translate(0, 36);
87 | fill(0);
88 | // have spaces inside the string for the text to look proper.
89 | text('You have ' + score.win + ' correct guesses', 0, 0);
90 | translate(0, 100);
91 | textSize(16);
92 | var alternatingValue = map(sin(frameCount / 10), -1, 1, 0, 255);
93 | fill(237, 34, 93, alternatingValue);
94 | text('PRESS ENTER', 0, 0);
95 | pop();
96 | }
97 |
98 | function getGameScore(score) {
99 | // given a score array, calculate the number of wins and losses.
100 | var wins = 0;
101 | var losses = 0;
102 | var total = score.length;
103 |
104 | for (var i = 0; i < total; i++) {
105 | var item = score[i];
106 | if (item === true) {
107 | wins = wins + 1;
108 | } else {
109 | losses = losses + 1;
110 | }
111 | }
112 |
113 | return {
114 | win: wins,
115 | loss: losses,
116 | total: total
117 | };
118 | }
119 |
120 | function restartTheGame() {
121 | // sets the game state to start.
122 | results = [];
123 | solution = null;
124 | gameOver = false;
125 | }
126 |
127 | function keyPressed() {
128 | // if game is over, then restart the game on ENTER key press.
129 | if (gameOver === true) {
130 | if (keyCode === ENTER) {
131 | console.log('restart the game');
132 | restartTheGame();
133 | return;
134 | }
135 | }
136 |
137 | if (guessItem !== null) {
138 | // check to see if the pressed key matches to the displayed number.
139 | // if so set the solution global variable to a corresponding value.
140 | console.log('you pressed: ', key);
141 | solution = guessItem.solve(key);
142 | console.log(solution);
143 | if (solution) {
144 | results.push(true);
145 | } else {
146 | results.push(false);
147 | }
148 | guessItem = null;
149 | } else {
150 | console.log('nothing to be solved');
151 | }
152 | }
153 |
154 | function GuessItem(x, y, scl) {
155 | this.x = x;
156 | this.y = y;
157 | this.scale = scl;
158 | this.scaleIncrement = 0.25;
159 | this.clr = 255;
160 | this.content = getContent();
161 | this.alpha = 255;
162 | this.alphaDecrement = 6;
163 | this.solved = null;
164 | this.contentMap = {
165 | '1': 'one',
166 | '2': 'two',
167 | '3': 'three',
168 | '4': 'four',
169 | '5': 'five',
170 | '6': 'six',
171 | '7': 'seven',
172 | '8': 'eight',
173 | '9': 'nine',
174 | '0': 'zero'
175 | };
176 | this.colors = [
177 | [63, 184, 175],
178 | [127, 199, 175],
179 | [218, 216, 167],
180 | [255, 158, 157],
181 | [255, 61, 127],
182 | [55, 191, 211],
183 | [159, 223, 82],
184 | [234, 209, 43],
185 | [250, 69, 8],
186 | [194, 13, 0]
187 | ];
188 |
189 | function getContent() {
190 | // generate a random integer in between 0 and 9
191 | return String(parseInt(random(10), 10));
192 | }
193 |
194 | this.solve = function(input) {
195 | // check to see if the given input is equivalent to the content.
196 | // set solved to the corresponding value.
197 | var solved;
198 | if (input === this.content) {
199 | solved = true;
200 | } else {
201 | solved = false;
202 | }
203 | this.solved = solved;
204 | return solved;
205 | }
206 |
207 | this.drawEllipse = function(size, strkWeight, speedMultiplier, seed) {
208 | // draw an animated ellipse with a random color to the screen.
209 | push();
210 | randomSeed(seed);
211 | translate(this.x, this.y);
212 | var ellipseSize = this.scale * speedMultiplier;
213 | scale(ellipseSize);
214 | var clr = this.colors[parseInt(random(this.colors.length), 10)]
215 | stroke(clr);
216 | noFill();
217 | strokeWeight(strkWeight);
218 | ellipse(0, 0, size, size);
219 | pop();
220 | }
221 |
222 | this.render = function() {
223 | push();
224 | this.drawEllipse(100, 15, 2, 1 * this.content * 1000);
225 | this.drawEllipse(60, 7, 2, 1 * this.content * 2000);
226 | this.drawEllipse(35, 3, 1.2, 1 * this.content * 3000);
227 | pop();
228 |
229 | push();
230 | fill(this.clr, this.alpha);
231 | textAlign(CENTER, CENTER);
232 | translate(this.x, this.y);
233 | scale(this.scale);
234 | // display the word for the corresponding number
235 | text(this.contentMap[this.content], 0, 0);
236 | // increase the scale value by the increment value with each render
237 | this.scale = this.scale + this.scaleIncrement;
238 | // decrease the alpha value by the decrement value with each render
239 | this.alpha = this.alpha - this.alphaDecrement;
240 | pop();
241 | }
242 | }
--------------------------------------------------------------------------------