├── .gitignore
├── README.md
├── mobile-examples
├── 01_first
│ ├── index.html
│ ├── libraries
│ │ ├── p5.dom.js
│ │ ├── p5.js
│ │ └── p5.sound.js
│ └── sketch.js
├── 02_touchIsDown
│ ├── index.html
│ ├── libraries
│ │ ├── p5.dom.js
│ │ ├── p5.js
│ │ └── p5.sound.js
│ └── sketch.js
├── 03_touch_coords
│ ├── index.html
│ ├── libraries
│ │ ├── p5.dom.js
│ │ ├── p5.js
│ │ └── p5.sound.js
│ └── sketch.js
├── 04_touch_callbacks
│ ├── index.html
│ ├── libraries
│ │ ├── p5.dom.js
│ │ ├── p5.js
│ │ └── p5.sound.js
│ └── sketch.js
├── 05_multitouch
│ ├── index.html
│ ├── libraries
│ │ ├── p5.dom.js
│ │ ├── p5.js
│ │ └── p5.sound.js
│ └── sketch.js
└── 06_rotation
│ ├── index.html
│ ├── libraries
│ ├── p5.dom.js
│ ├── p5.js
│ └── p5.sound.js
│ └── sketch.js
└── node-examples
├── aleph.js
├── genesis.txt
├── hello.js
├── markov-bot.js
├── markov-server.js
├── markov.js
├── package.json
└── word-count.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Polytechnic School of Engineering of New York University
2 | Integrated Digital Media
3 | Technology, Culture and Society
4 |
5 | # DM-GY 6063 B Creative Coding
6 |
7 | Fall 2015 / Thursdays 6:30-9:20pm MAGNET 825
8 |
9 | Your professor: [Allison Parrish](http://www.decontextualize.com/). E-mail me: [aparrish@nyu.edu](mailto:aparrish@nyu.edu).
10 |
11 | Office hours: Wednesdays, 4pm to 5:30pm at MAGNET (adjunct's work area)
12 |
13 | ##Course description
14 |
15 | This course is an introductory programming class, appropriate for students with
16 | no prior programming experience. Traditionally, introductory programming
17 | teaches algorithmic problem-solving, where a sequence of instructions describe
18 | the steps necessary to achieve a desired result. In this course, students are
19 | trained to go beyond this sequential thinking, to think concurrently and
20 | modularly. By its end, students are empowered to write and read code for
21 | event-driven, object-oriented, graphical user interfaces.
22 |
23 | ## IDM program objectives
24 |
25 | Students will:
26 |
27 | * Develop **conceptual thinking skills** to generate ideas and content in
28 | order to solve problems or create opportunities.
29 |
30 | * Develop **technical skills** to realize their ideas.
31 |
32 | * Develop **critical thinking skills** that will allow them to analyze and
33 | position their work within cultural, historic, aesthetic, economic, and
34 | technological contexts.
35 |
36 | * Gain knowledge of **professional practices and organizations** by developing
37 | their verbal, visual, and written communication for documentation and
38 | presentation, exhibition and promotion, networking, and career preparation.
39 |
40 | * Develop **collaboration skills** to actively and effectively work in a team
41 | or group.
42 |
43 | ## Course objectives
44 |
45 | Students in this course will:
46 |
47 | * Understand the basics of creative coding in Javascript (p5.js/node.js).
48 | * Apply their understanding of digital media to software.
49 | * Learn best practices for designing software within an event-driven,
50 | object-oriented, real time framework.
51 | * Experiment with different techniques for user input and output, including
52 | sensors and non-traditional screens.
53 | * Propose and develop a complete software experience as a final project.
54 |
55 | ## Methodology
56 |
57 | The course is presented in a tutorial format: most class sessions will consist
58 | of the instructor demonstrating and explaining some aspect of computer
59 | programming. The first seven weeks of the course are centered around basic
60 | programming concepts, with a focus on computer visuals; following that, the
61 | approach of the course is oriented toward particular topics. (These topics are
62 | subject to change as the interests of the students become more clear.)
63 |
64 | We'll also be critiquing student work in-class, generally in an informal way
65 | and on a volunteer basis.
66 |
67 | ## Technology
68 |
69 | We'll be learning [p5.js](http://p5js.org/), a Javascript port of the perennial
70 | favorite [Processing](https://processing.org/).
71 |
72 | There are lots of ways to program with p5.js. We're going to try out the p5.js
73 | editor. [Download it here](http://p5js.org/download/#editor) (for Mac and PC).
74 |
75 | ## Requirements
76 |
77 | * Students are responsible for ten weekly assignments, each of which is
78 | designed to give students the opportunity to demonstrate and deepen their
79 | mastery of the technical topics presented in class.
80 | * Students must document their work using the IDM wordpress installation on
81 | [http://sites.bxmc.poly.edu](http://sites.bxmc.poly.edu/) (or similar
82 | blogging site)
83 | * In the last week of class, students will present a final project. The shape,
84 | form, and content of the final project are left up to the student, but the
85 | project should demonstrate significant mastery over the technical concepts
86 | discussed in class. Students are responsible for presenting their project in
87 | class *and* for accompanying documentation of the project (including the
88 | full source code). More details on this as the semester progresses!
89 |
90 | ##Assignments
91 |
92 | The assignments are your opportunity to be on the hook for putting your skills
93 | to the test. They're designed to test and deepen your knowledge while giving me
94 | valuable information about how you're progressing in the class.
95 |
96 | [Turn in your assignments using this Google
97 | Form.](https://docs.google.com/forms/d/1jEqJ5a88ZY_GI-7bbdJihJbTv2rnjYCTCHAwc3ZQmR8/viewform?usp=send_form)
98 |
99 | Specific requirements for assignments:
100 |
101 | * Each assignment should be accompanied by a blog post that documents your
102 | process in fulfilling the assignment's objectives.
103 | * You'll need somewhere to upload your completed sketches. If you already have
104 | your own web hosting service ([DreamHost](https://www.dreamhost.com/), say),
105 | that's great! If not, I'll show you how to set up a
106 | [Neocities](https://neocities.org/) account in class.
107 | * Assignments must be turned in *before class* on the day they're due. Late
108 | assignments will not be accepted.
109 | * Assignments will be graded on their technical mastery and creativity.
110 |
111 | ## Reading
112 |
113 | There is no assigned textbook for this class, but I may assign one-off readings
114 | throughout the semester for in-class discussion. If you're the kind of student
115 | that benefits from having a textbook close at hand, please buy [Make: Getting
116 | Started with p5.js: Making Interactive Graphics in JavaScript and
117 | Processing](http://www.amazon.com/Make-Interactive-Graphics-JavaScript-Processing/dp/1457186772/), by Lauren McCarthy, Ben Fry, and Casey Reas (when it's
118 | released!).
119 |
120 | If you're looking for other supplementary sources of programming knowledge and
121 | exercises, [refer to Katherine Bennet's excellent list of
122 | resources](https://github.com/IDMNYU/DM-UY1133-B_CreativeCodingFA15/blob/master/dm113-B_Resources.md).
123 |
124 | ## Grading policy
125 |
126 | | Component | Percentage |
127 | | --------- | ---------- |
128 | | Attendance and participation | 30% |
129 | | IDM Coursework Documentation | 5% |
130 | | Assignments | 10 x 4% = 40% |
131 | | Final project | 25% |
132 |
133 | ## Attendance, lateness and in-class behavior
134 |
135 | ### Attendance
136 |
137 | You are expected to attend all class sessions. Absences due to non-emergency
138 | situations will only be cleared if you let me know a week (or more) in advance,
139 | and even then only for compelling personal or professional reasons (e.g.,
140 | attending an important conference, going to a wedding). If you're unable to
141 | attend class due to contagious or incapacitating illness, please let me know
142 | (by e-mail) before class begins.
143 |
144 | Each unexcused absence will deduct 5% from your final grade. If you have three
145 | or more unexcused absences, you risk failing the course.
146 |
147 | ### Lateness
148 |
149 | Be on time to class. If you're more than fifteen minutes late, or if you leave
150 | early (without my clearance), it will count as an unexcused absence.
151 |
152 | ### In-class behavior
153 |
154 | Laptops must be closed while your fellow students are presenting work. You're
155 | otherwise welcome to use laptops in class, but only to follow along with the
156 | in-class tutorials and to take notes. ([Keeping all of this in
157 | mind.](https://medium.com/@cshirky/why-i-just-asked-my-students-to-put-their-laptops-away-7f5f7c50f368))
158 |
159 | ### Procedures should punch up
160 |
161 | Read Leonard Richardson's [Bots should punch
162 | up](http://www.crummy.com/2013/11/27/0). "You can poke fun at yourself
163 | (Stephen Colbert famously said 'There's no status I would not surrender for a
164 | joke'), you can make a joke at the expense of someone with higher social status
165 | than you, but if you mock someone with lower status, it's not cool." Be
166 | sensitive to what your classmates might find offensive, triggering, or violent;
167 | be graceful and listen carefully when your work gets called out.
168 |
169 | ##Academic Integrity
170 |
171 | Please review [NYU's School of Engineering's academic dishonesty
172 | policy](http://engineering.nyu.edu/academics/code-of-conduct/academic-dishonesty) in its
173 | entirety. For the purposes of this class, "plagiarism" that violates the
174 | academic integrity policy is defined as representing someone else's code (or
175 | other procedure) as your own. (We will, of course, liberally be using media that
176 | other people have created as source material for our code and procedures—this
177 | does not violate the academic integrity policy. You are, however, expected to
178 | cite the sources of these materials where possible and appropriate.)
179 |
180 | ##Disability accommodations
181 |
182 | If you are student with a disability who is requesting accommodations, please
183 | contact New York University’s Moses Center for Students with Disabilities at
184 | 212-998-4980 or mosescsd@nyu.edu. You must be registered with CSD to receive
185 | accommodations. Information about the Moses Center can be found at
186 | http://www.nyu.edu/csd. The Moses Center is located at 726 Broadway on the 2nd
187 | floor.
188 |
189 | ## Schedule
190 |
191 | ###Session 01: September 3
192 |
193 | * Course introduction: What is programming?
194 | * Syllabus overview
195 | * Using [the p5.js application](http://p5js.org/download/#editor)
196 | * Uploading to the Internet
197 | * Your first sketch
198 |
199 | Works cited:
200 |
201 | * Sol LeWitt, [Wall Drawing instructions](http://solvingsol.com/solutions/) (link is to "Solving Sol," a site where programmers attempt to interpret the instructions with code)
202 | * Casey Reas, [Process Compendium](http://reas.com/compendium_text/) ([example](http://reas.com/p11_s/) of what the realization looks like)
203 | * Yoko Ono, [Grapefruit](http://en.wikipedia.org/wiki/Grapefruit_%28book%29)
204 | * [Fluxus Performance Workbook](http://www.deluxxe.com/beat/fluxusworkbook.pdf)
205 | * Jackson Mac Low, [Insect Assassins](http://www.poets.org/poetsorg/poem/insect-assassins) and [Call Me Ishmael](http://www.poets.org/poetsorg/poem/call-me-ishmael) (examples of "diastic")
206 |
207 | Notes:
208 |
209 | * [First steps with p5.js](http://creative-coding.decontextualize.com/first-steps/)
210 |
211 | Additional resources:
212 |
213 | * [Learning p5.js](https://vimeo.com/channels/learningp5js), video tutorials
214 | from [Dan Shiffman](http://shiffman.net/)
215 | * [p5.js tutorials](http://p5js.org/tutorials/)
216 |
217 | Assignment #1, due September 10: Create a drawing with p5.js and upload the
218 | source code for your drawing to the Internet. Limit yourself to the following
219 | Processing functions: `line()`, `triangle()`, `quad()`, `rect()`, `ellipse()`,
220 | `fill()`, `stroke()`, and `strokeWeight()`. Draw something beautiful or
221 | intentionally banal.
222 |
223 | ###Session 02: September 10
224 |
225 | * Processing: More shapes
226 | * Values, types, and expressions
227 | * Variables
228 | * Loops
229 |
230 | Notes:
231 |
232 | * [Expressions, variables and loops](http://creative-coding.decontextualize.com/expressions-variables-and-loops/)
233 |
234 | Assignment #2, due September 18: Rework your first assignment to make use of
235 | variables, expressions and loops. In your documentation, include screenshots of
236 | how changing a single variable in your sketch effects the way the sketch looks.
237 | EXTRA CREDIT: use a nested `for` loop (i.e., one `for` loop inside of another).
238 |
239 | ###Session 03: September 17
240 |
241 | * Javascript details: Comments, code formatting, numbers
242 | * Changes over time
243 | * Simple interactivity
244 | * Flow control (if/else)
245 | * Randomness
246 |
247 | Notes:
248 |
249 | * [Changes over time](http://creative-coding.decontextualize.com/changes-over-time/)
250 | * [Interaction](http://creative-coding.decontextualize.com/interaction/)
251 |
252 | Assignment #3, due September 24: Create an artwork that responds to user input
253 | and changes over time. Your work should make use of one of the methods of
254 | oscillation discussed in class, at least one of the three variables we
255 | discussed for making use of mouse input, and the code should contain at least
256 | one `if` statement.
257 |
258 | ###Session 04: September 24
259 |
260 | * [Transformations and functions](http://creative-coding.decontextualize.com/transformations-and-functions/)
261 |
262 | Assignment #4, due October 1: Create a visual work that makes use of functions,
263 | loops and transformations to form repeating shapes and patterns with subtle
264 | variation. (You can incorporate interactivity and change over time if you'd
265 | like, but it's not necessary.) Some visual references: [Casey Reas, Yes
266 | No](http://reas.com/yesno_s2/); [Gerhard Richter, 180
267 | Farben](http://www.philamuseum.org/collections/permanent/92487.html),
268 | [Untitled, Jean Arp](http://www.moma.org/collection/works/37013),
269 | [Lacey Micallef's animated gifs](http://laceymicallef.com/).
270 |
271 | ###Session 05: October 1
272 |
273 | * [Working with media: images and audio](http://creative-coding.decontextualize.com/media/)
274 |
275 | Assignment #5, due October 8: Create an overwhelming interactive audio visual
276 | experience using images and audio. (References TK.)
277 |
278 | ###Session 06: October 8
279 |
280 | * [Arrays, objects, and working with data](http://creative-coding.decontextualize.com/arrays-and-objects/)
281 |
282 | Assignment #6, due October 22: Create a sketch that keeps track of user action
283 | over the course of each instance of the sketch being run (clicks, keypresses,
284 | etc). Alternatively (or as a bonus): Use data from a CSV file to draw a simple
285 | data visualization.
286 |
287 | ###Session 07: October 19 (this is a make-up session for October 15)
288 |
289 | * [More about
290 | functions](http://creative-coding.decontextualize.com/functions-continued/);
291 | [objects with
292 | methods](http://creative-coding.decontextualize.com/objects-with-methods/).
293 |
294 |
295 | ###Session 08: October 22
296 |
297 | * Text and type. [Notes.](http://creative-coding.decontextualize.com/text-and-type/)
298 |
299 | Combined assignments #7/#8: Create a work of *electronic literature*. See [the
300 | Electronic Literature Collection](http://collection.eliterature.org/) for
301 | inspiration ([volume 1](http://collection.eliterature.org/1/), [volume
302 | 2](http://collection.eliterature.org/2/)). See also [Ubuweb: Visual
303 | Poetry](http://www.ubu.com/vp/). EXTRA CREDIT: Use object-oriented programming
304 | somewhere in your sketch.
305 |
306 | ###Session 09: October 29
307 |
308 | * [Browser
309 | controls](http://creative-coding.decontextualize.com/browser-controls/)
310 | * [Video](http://creative-coding.decontextualize.com/video/)
311 |
312 | Assignment #9, due November 5. Make a sketch that meets one (or more) of the
313 | following descriptions: (a) Adapt an earlier homework so that it uses HTML
314 | controls (like buttons, sliders, text input fields). BONUS: Incorporate an HTML
315 | control from `p5.dom` that we *didn't* talk about in class. (b) Make a sketch
316 | that creatively re-interprets the pixels in a video (whether pre-recorded or
317 | from the webcam). For inspiration, see the work of [Nam June
318 | Paik](https://www.youtube.com/results?search_query=nam+june+paik), [Golan
319 | Levin](http://www.flong.com/projects/), [Zach
320 | Lieberman](http://thesystemis.com/projects/).
321 |
322 | ###Session 10: November 5
323 |
324 | * [Using external
325 | libraries](http://creative-coding.decontextualize.com/external-libraries)
326 | * [Simple generative language techniques with
327 | RiTaJS](http://creative-coding.decontextualize.com/intro-to-ritajs/)
328 | * More, if time! (Markov chain generation, p5.speech)
329 |
330 | Assignment #10, due November 12. Two options this week. (1) Make a sketch that
331 | modifies or generates language creatively, using the RiTaJS library. This can
332 | be an extension of assignment #7/8, if you want. Bonus points for using
333 | features of RiTaJS that we *didn't* discuss in class. (2) Make a sketch that
334 | uses *some other* 3rd-party library for p5.js. [Here's a
335 | list](http://p5js.org/libraries/) (check in the "Contributed" section).
336 |
337 | *Supplementary assignment.* Come prepared on Nov 12 to pitch an idea for your
338 | final project. We'll discuss these in class. If you have a prototype: even
339 | better!
340 |
341 | ###Session 11: November 12
342 |
343 | * Final project proposals
344 | * [Games and game-like things with p5.play](http://creative-coding.decontextualize.com/making-games-with-p5-play/)
345 |
346 | ###Session 12: November 19
347 |
348 | * Final project check-in
349 | * p5.play continued
350 | * [p5.js and mobile devices](http://creative-coding.decontextualize.com/mobile/) (code examples in this repository)
351 |
352 | ###Session 13: December 3
353 |
354 | * Final project check-in
355 | * [Node.js overview](http://creative-coding.decontextualize.com/node/) (code
356 | examples in this repository)
357 |
358 | ###Session 14: December 10
359 |
360 | * Final project check-ins
361 | * In-class work or topics selected by class
362 |
363 | ###Session 15: December 17
364 |
365 | * Final project presentations
366 |
367 |
--------------------------------------------------------------------------------
/mobile-examples/01_first/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 01_first
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/mobile-examples/01_first/libraries/p5.dom.js:
--------------------------------------------------------------------------------
1 | /*! p5.dom.js v0.2.4 October 6, 2015 */
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 | // p5 additions
38 | // =============================================================================
39 |
40 | /**
41 | * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.'
42 | * prefixes to specify an ID or class respectively, and none for a tag) and returns it as
43 | * a p5.Element. If a class or tag name is given with more than 1 element,
44 | * only the first element will be returned.
45 | * The DOM node itself can be accessed with .elt.
46 | * Returns null if none found.
47 | *
48 | * @method select
49 | * @param {String} name id, class, or tag name of element to search for
50 | * @return {Object/p5.Element|Null} p5.Element containing node found
51 | */
52 | p5.prototype.select = function (e) {
53 | var res;
54 | var str;
55 | if (e[0] === '.'){
56 | str = e.slice(1);
57 | res = document.getElementsByClassName(str);
58 | if (res) {
59 | return wrapElement(res[0]);
60 | }else {
61 | return null;
62 | }
63 | }else if (e[0] === '#'){
64 | str = e.slice(1);
65 | res = document.getElementById(str);
66 | if (res) {
67 | return wrapElement(res);
68 | }else {
69 | return null;
70 | }
71 | }else{
72 | res = document.getElementsByTagName(e);
73 | if (res) {
74 | return wrapElement(res[0]);
75 | }else {
76 | return null;
77 | }
78 | }
79 | };
80 |
81 | /**
82 | * Searches the page for elements with the given class or tag name (using the '.' prefix
83 | * to specify a class and no prefix for a tag) and returns them as p5.Elements
84 | * in an array.
85 | * The DOM node itself can be accessed with .elt.
86 | * Returns null if none found.
87 | *
88 | * @method selectAll
89 | * @param {String} name class or tag name of elements to search for
90 | * @return {Array} Array of p5.Elements containing nodes found
91 | */
92 | p5.prototype.selectAll = function (e) {
93 | var arr = [];
94 | var res;
95 | var str;
96 | if (e[0] === '.'){
97 | str = e.slice(1);
98 | res = document.getElementsByClassName(str);
99 | }else {
100 | res = document.getElementsByTagName(e);
101 | }
102 | if (res) {
103 | for (var j = 0; j < res.length; j++) {
104 | var obj = wrapElement(res[j]);
105 | arr.push(obj);
106 | }
107 | }
108 | return arr;
109 | };
110 |
111 | /**
112 | * Helper function for getElement and getElements.
113 | */
114 | function wrapElement(elt) {
115 | if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") {
116 | return new p5.MediaElement(elt);
117 | } else {
118 | return new p5.Element(elt);
119 | }
120 | }
121 |
122 | /**
123 | * Removes all elements created by p5, except any canvas / graphics
124 | * elements created by createCanvas or createGraphics.
125 | * Event handlers are removed, and element is removed from the DOM.
126 | * @method removeElements
127 | * @example
128 | *
129 | * function setup() {
130 | * createCanvas(100, 100);
131 | * createDiv('this is some text');
132 | * createP('this is a paragraph');
133 | * }
134 | * function mousePressed() {
135 | * removeElements(); // this will remove the div and p, not canvas
136 | * }
137 | *
138 | *
139 | */
140 | p5.prototype.removeElements = function (e) {
141 | for (var i=0; i
169 | * var myDiv;
170 | * function setup() {
171 | * myDiv = createDiv('this is some text');
172 | * }
173 | *
174 | */
175 |
176 | /**
177 | * Creates a <p></p> element in the DOM with given inner HTML. Used
178 | * for paragraph length text.
179 | * Appends to the container node if one is specified, otherwise
180 | * appends to body.
181 | *
182 | * @method createP
183 | * @param {String} html inner HTML for element created
184 | * @return {Object/p5.Element} pointer to p5.Element holding created node
185 | * @example
186 | *
187 | * var myP;
188 | * function setup() {
189 | * myP = createP('this is some text');
190 | * }
191 | *
192 | */
193 |
194 | /**
195 | * Creates a <span></span> element in the DOM with given inner HTML.
196 | * Appends to the container node if one is specified, otherwise
197 | * appends to body.
198 | *
199 | * @method createSpan
200 | * @param {String} html inner HTML for element created
201 | * @return {Object/p5.Element} pointer to p5.Element holding created node
202 | * @example
203 | *
204 | * var mySpan;
205 | * function setup() {
206 | * mySpan = createSpan('this is some text');
207 | * }
208 | *
209 | */
210 | var tags = ['div', 'p', 'span'];
211 | tags.forEach(function(tag) {
212 | var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1);
213 | p5.prototype[method] = function(html) {
214 | var elt = document.createElement(tag);
215 | elt.innerHTML = typeof html === undefined ? "" : html;
216 | return addElement(elt, this);
217 | }
218 | });
219 |
220 | /**
221 | * Creates an <img /> element in the DOM with given src and
222 | * alternate text.
223 | * Appends to the container node if one is specified, otherwise
224 | * appends to body.
225 | *
226 | * @method createImg
227 | * @param {String} src src path or url for image
228 | * @param {String} [alt] alternate text to be used if image does not load
229 | * @param {Function} [successCallback] callback to be called once image data is loaded
230 | * @return {Object/p5.Element} pointer to p5.Element holding created node
231 | * @example
232 | *
233 | * var img;
234 | * function setup() {
235 | * img = createImg('http://p5js.org/img/asterisk-01.png');
236 | * }
237 | *
238 | */
239 | p5.prototype.createImg = function() {
240 | var elt = document.createElement('img');
241 | var args = arguments;
242 | var self;
243 | var setAttrs = function(){
244 | self.width = elt.offsetWidth;
245 | self.height = elt.offsetHeight;
246 | if (args.length > 1 && typeof args[1] === 'function'){
247 | self.fn = args[1];
248 | self.fn();
249 | }else if (args.length > 1 && typeof args[2] === 'function'){
250 | self.fn = args[2];
251 | self.fn();
252 | }
253 | };
254 | elt.src = args[0];
255 | if (args.length > 1 && typeof args[1] === 'string'){
256 | elt.alt = args[1];
257 | }
258 | elt.onload = function(){
259 | setAttrs();
260 | }
261 | self = addElement(elt, this);
262 | return self;
263 | };
264 |
265 | /**
266 | * Creates an <a></a> element in the DOM for including a hyperlink.
267 | * Appends to the container node if one is specified, otherwise
268 | * appends to body.
269 | *
270 | * @method createA
271 | * @param {String} href url of page to link to
272 | * @param {String} html inner html of link element to display
273 | * @param {String} [target] target where new link should open,
274 | * could be _blank, _self, _parent, _top.
275 | * @return {Object/p5.Element} pointer to p5.Element holding created node
276 | * @example
277 | *
278 | * var myLink;
279 | * function setup() {
280 | * myLink = createA('http://p5js.org/', 'this is a link');
281 | * }
282 | *
283 | */
284 | p5.prototype.createA = function(href, html, target) {
285 | var elt = document.createElement('a');
286 | elt.href = href;
287 | elt.innerHTML = html;
288 | if (target) elt.target = target;
289 | return addElement(elt, this);
290 | };
291 |
292 | /** INPUT **/
293 |
294 |
295 | /**
296 | * Creates a slider <input></input> element in the DOM.
297 | * Use .size() to set the display length of the slider.
298 | * Appends to the container node if one is specified, otherwise
299 | * appends to body.
300 | *
301 | * @method createSlider
302 | * @param {Number} min minimum value of the slider
303 | * @param {Number} max maximum value of the slider
304 | * @param {Number} [value] default value of the slider
305 | * @return {Object/p5.Element} pointer to p5.Element holding created node
306 | * @example
307 | *
308 | * var slider;
309 | * function setup() {
310 | * slider = createSlider(0, 255, 100);
311 | * slider.position(10, 10);
312 | * slider.style('width', '80px');
313 | * }
314 | *
315 | * function draw() {
316 | * var val = slider.value();
317 | * background(val);
318 | * }
319 | *
320 | */
321 | p5.prototype.createSlider = function(min, max, value, step) {
322 | var elt = document.createElement('input');
323 | elt.type = 'range';
324 | elt.min = min;
325 | elt.max = max;
326 | if (step) elt.step = step;
327 | if (typeof(value) === "number") elt.value = value;
328 | return addElement(elt, this);
329 | };
330 |
331 | /**
332 | * Creates a <button></button> element in the DOM.
333 | * Use .size() to set the display size of the button.
334 | * Use .mousePressed() to specify behavior on press.
335 | * Appends to the container node if one is specified, otherwise
336 | * appends to body.
337 | *
338 | * @method createButton
339 | * @param {String} label label displayed on the button
340 | * @param {String} [value] value of the button
341 | * @return {Object/p5.Element} pointer to p5.Element holding created node
342 | * @example
343 | *
344 | * var button;
345 | * function setup() {
346 | * createCanvas(100, 100);
347 | * background(0);
348 | * button = createButton('click me');
349 | * button.position(19, 19);
350 | * button.mousePressed(changeBG);
351 | * }
352 | *
353 | * function changeBG() {
354 | * var val = random(255);
355 | * background(val);
356 | * }
357 | *
358 | */
359 | p5.prototype.createButton = function(label, value) {
360 | var elt = document.createElement('button');
361 | elt.innerHTML = label;
362 | elt.value = value;
363 | if (value) elt.value = value;
364 | return addElement(elt, this);
365 | };
366 |
367 | /**
368 | * Creates a checkbox <input></input> element in the DOM.
369 | *
370 | * @method createCheckbox
371 | * @param {String} [label] label displayed after checkbox
372 | * @param {boolean} [value] value of the checkbox; checked is true, unchecked is false. Unchecked if no value given
373 | * @return {Object/p5.Element} pointer to p5.Element holding created node
374 | */
375 | p5.prototype.createCheckbox = function() {
376 | var elt = document.createElement('input');
377 | elt.type = 'checkbox';
378 | //checkbox must be wrapped in p5.Element before label so that label appears after
379 | var self = addElement(elt, this);
380 | self.checked = function(){
381 | if (arguments.length === 0){
382 | return self.elt.checked;
383 | }else if(arguments[0]){
384 | self.elt.checked = true;
385 | }else{
386 | self.elt.checked = false;
387 | }
388 | return self;
389 | };
390 | this.value = function(val){
391 | self.value = val;
392 | return this;
393 | };
394 | if (arguments[0]){
395 | var ran = Math.random().toString(36).slice(2);
396 | var label = document.createElement('label');
397 | elt.setAttribute('id', ran);
398 | label.htmlFor = ran;
399 | self.value(arguments[0]);
400 | label.appendChild(document.createTextNode(arguments[0]));
401 | addElement(label, this);
402 | }
403 | if (arguments[1]){
404 | elt.checked = true;
405 | }
406 | return self;
407 | };
408 |
409 | /**
410 | * Creates a dropdown menu <select></select> element in the DOM.
411 | * @method createSelect
412 | * @param {boolean} [multiple] [true if dropdown should support multiple selections]
413 | * @return {Object/p5.Element} pointer to p5.Element holding created node
414 | */
415 | p5.prototype.createSelect = function(mult) {
416 | var elt = document.createElement('select');
417 | if (mult){
418 | elt.setAttribute('multiple', 'true');
419 | }
420 | var self = addElement(elt, this);
421 | self.option = function(name, value){
422 | var opt = document.createElement('option');
423 | opt.innerHTML = name;
424 | if (arguments.length > 1)
425 | opt.value = value;
426 | else
427 | opt.value = name;
428 | elt.appendChild(opt);
429 | };
430 | self.selected = function(value){
431 | var arr = [];
432 | if (arguments.length > 0){
433 | for (var i = 0; i < this.elt.length; i++){
434 | if (value.toString() === this.elt[i].value){
435 | this.elt.selectedIndex = i;
436 | }
437 | }
438 | return this;
439 | }else{
440 | if (mult){
441 | for (var i = 0; i < this.elt.selectedOptions.length; i++){
442 | arr.push(this.elt.selectedOptions[i].value);
443 | }
444 | return arr;
445 | }else{
446 | return this.elt.value;
447 | }
448 | }
449 | };
450 | return self;
451 | };
452 |
453 | /**
454 | * Creates an <input></input> element in the DOM for text input.
455 | * Use .size() to set the display length of the box.
456 | * Appends to the container node if one is specified, otherwise
457 | * appends to body.
458 | *
459 | * @method createInput
460 | * @param {Number} [value] default value of the input box
461 | * @return {Object/p5.Element} pointer to p5.Element holding created node
462 | */
463 | p5.prototype.createInput = function(value) {
464 | var elt = document.createElement('input');
465 | elt.type = 'text';
466 | if (value) elt.value = value;
467 | return addElement(elt, this);
468 | };
469 |
470 | /**
471 | * Creates an <input></input> element in the DOM of type 'file'.
472 | * This allows users to select local files for use in a sketch.
473 | *
474 | * @method createFileInput
475 | * @param {Function} [callback] callback function for when a file loaded
476 | * @param {String} [multiple] optional to allow multiple files selected
477 | * @return {Object/p5.Element} pointer to p5.Element holding created DOM element
478 | */
479 | p5.prototype.createFileInput = function(callback, multiple) {
480 |
481 | // Is the file stuff supported?
482 | if (window.File && window.FileReader && window.FileList && window.Blob) {
483 | // Yup, we're ok and make an input file selector
484 | var elt = document.createElement('input');
485 | elt.type = 'file';
486 |
487 | // If we get a second argument that evaluates to true
488 | // then we are looking for multiple files
489 | if (multiple) {
490 | // Anything gets the job done
491 | elt.multiple = 'multiple';
492 | }
493 |
494 | // Now let's handle when a file was selected
495 | elt.addEventListener('change', handleFileSelect, false);
496 |
497 | // Function to handle when a file is selected
498 | // We're simplifying life and assuming that we always
499 | // want to load every selected file
500 | function handleFileSelect(evt) {
501 | // These are the files
502 | var files = evt.target.files;
503 | // Load each one and trigger a callback
504 | for (var i = 0; i < files.length; i++) {
505 | var f = files[i];
506 | var reader = new FileReader();
507 | reader.onload = makeLoader(f);
508 | function makeLoader(theFile) {
509 | // Making a p5.File object
510 | var p5file = new p5.File(theFile);
511 | return function(e) {
512 | p5file.data = e.target.result;
513 | callback(p5file);
514 | };
515 | };
516 |
517 | // Text or data?
518 | // This should likely be improved
519 | if (f.type.indexOf('text') > -1) {
520 | reader.readAsText(f);
521 | } else {
522 | reader.readAsDataURL(f);
523 | }
524 | }
525 | }
526 | return addElement(elt, this);
527 | } else {
528 | console.log('The File APIs are not fully supported in this browser. Cannot create element.');
529 | }
530 | };
531 |
532 |
533 | /** VIDEO STUFF **/
534 |
535 | function createMedia(pInst, type, src, callback) {
536 | var elt = document.createElement(type);
537 | if (typeof src === 'string') {
538 | src = [src];
539 | }
540 | for (var i=0; ithis
571 | * page for further information about supported formats.
572 | *
573 | * @method createVideo
574 | * @param {String|Array} src path to a video file, or array of paths for
575 | * supporting different browsers
576 | * @param {Object} [callback] callback function to be called upon
577 | * 'canplaythrough' event fire, that is, when the
578 | * browser can play the media, and estimates that
579 | * enough data has been loaded to play the media
580 | * up to its end without having to stop for
581 | * further buffering of content
582 | * @return {Object/p5.Element} pointer to video p5.Element
583 | */
584 | p5.prototype.createVideo = function(src, callback) {
585 | return createMedia(this, 'video', src, callback);
586 | };
587 |
588 | /** AUDIO STUFF **/
589 |
590 | /**
591 | * Creates a hidden HTML5 <audio> element in the DOM for simple audio
592 | * playback. Appends to the container node if one is specified,
593 | * otherwise appends to body. The first parameter
594 | * can be either a single string path to a audio file, or an array of string
595 | * paths to different formats of the same audio. This is useful for ensuring
596 | * that your audio can play across different browsers, as each supports
597 | * different formats. See this
598 | * page for further information about supported formats.
599 | *
600 | * @method createAudio
601 | * @param {String|Array} src path to an audio file, or array of paths for
602 | * supporting different browsers
603 | * @param {Object} [callback] callback function to be called upon
604 | * 'canplaythrough' event fire, that is, when the
605 | * browser can play the media, and estimates that
606 | * enough data has been loaded to play the media
607 | * up to its end without having to stop for
608 | * further buffering of content
609 | * @return {Object/p5.Element} pointer to audio p5.Element
610 | */
611 | p5.prototype.createAudio = function(src, callback) {
612 | return createMedia(this, 'audio', src, callback);
613 | };
614 |
615 |
616 | /** CAMERA STUFF **/
617 |
618 | p5.prototype.VIDEO = 'video';
619 | p5.prototype.AUDIO = 'audio';
620 |
621 | navigator.getUserMedia = navigator.getUserMedia ||
622 | navigator.webkitGetUserMedia ||
623 | navigator.mozGetUserMedia ||
624 | navigator.msGetUserMedia;
625 |
626 | /**
627 | * Creates a new <video> element that contains the audio/video feed
628 | * from a webcam. This can be drawn onto the canvas using video(). More
629 | * specific properties of the stream can be passing in a Constraints object.
630 | * See the
631 | * W3C
632 | * spec for possible properties. Note that not all of these are supported
633 | * by all browsers.
634 | *
635 | * @method createCapture
636 | * @param {String|Constant|Object} type type of capture, either VIDEO or
637 | * AUDIO if none specified, default both,
638 | * or a Constraints boject
639 | * @param {Function} callback function to be called once
640 | * stream has loaded
641 | * @return {Object/p5.Element} capture video p5.Element
642 | * @example
643 | *
644 | * var capture;
645 | *
646 | * function setup() {
647 | * createCanvas(480, 120);
648 | * capture = createCapture(VIDEO);
649 | * }
650 | *
651 | * function draw() {
652 | * image(capture, 0, 0, width, width*capture.height/capture.width);
653 | * filter(INVERT);
654 | * }
655 | *
656 | *
657 | * function setup() {
658 | * createCanvas(480, 120);
659 | * var constraints = {
660 | * video: {
661 | * mandatory: {
662 | * minWidth: 1280,
663 | * minHeight: 720
664 | * },
665 | * optional: [
666 | * { maxFrameRate: 10 }
667 | * ]
668 | * },
669 | * audio: true
670 | * };
671 | * createCapture(constraints, function(stream) {
672 | * console.log(stream);
673 | * });
674 | * }
675 | *
676 | */
677 | p5.prototype.createCapture = function() {
678 | var useVideo = true;
679 | var useAudio = true;
680 | var constraints;
681 | var cb;
682 | for (var i=0; i
792 | * var div0 = createDiv('this is the parent');
793 | * var div1 = createDiv('this is the child');
794 | * div0.child(div1); // use p5.Element
795 | *
796 | *
797 | * var div0 = createDiv('this is the parent');
798 | * var div1 = createDiv('this is the child');
799 | * div1.id('apples');
800 | * div0.child('apples'); // use id
801 | *
802 | *
803 | * var div0 = createDiv('this is the parent');
804 | * var elt = document.getElementById('myChildDiv');
805 | * div0.child(elt); // use element from page
806 | *
807 | */
808 | p5.Element.prototype.child = function(c) {
809 | if (typeof c === 'string') {
810 | c = document.getElementById(c);
811 | } else if (c instanceof p5.Element) {
812 | c = c.elt;
813 | }
814 | this.elt.appendChild(c);
815 | return this;
816 | };
817 |
818 |
819 | /**
820 | *
821 | * If an argument is given, sets the inner HTML of the element,
822 | * replacing any existing html. If no arguments are given, returns
823 | * the inner HTML of the element.
824 | *
825 | * @for p5.Element
826 | * @method html
827 | * @param {String} [html] the HTML to be placed inside the element
828 | * @return {Object/p5.Element|String}
829 | */
830 | p5.Element.prototype.html = function(html) {
831 | if (typeof html !== 'undefined') {
832 | this.elt.innerHTML = html;
833 | return this;
834 | } else {
835 | return this.elt.innerHTML;
836 | }
837 | };
838 |
839 | /**
840 | *
841 | * Sets the position of the element relative to (0, 0) of the
842 | * window. Essentially, sets position:absolute and left and top
843 | * properties of style. If no arguments given returns the x and y position
844 | * of the element in an object.
845 | *
846 | * @method position
847 | * @param {Number} [x] x-position relative to upper left of window
848 | * @param {Number} [y] y-position relative to upper left of window
849 | * @return {Object/p5.Element}
850 | * @example
851 | *
852 | * function setup() {
853 | * var cnv = createCanvas(100, 100);
854 | * // positions canvas 50px to the right and 100px
855 | * // below upper left corner of the window
856 | * cnv.position(50, 100);
857 | * }
858 | *
859 | */
860 | p5.Element.prototype.position = function() {
861 | if (arguments.length === 0){
862 | return { 'x' : this.elt.offsetLeft , 'y' : this.elt.offsetTop };
863 | }else{
864 | this.elt.style.position = 'absolute';
865 | this.elt.style.left = arguments[0]+'px';
866 | this.elt.style.top = arguments[1]+'px';
867 | this.x = arguments[0];
868 | this.y = arguments[1];
869 | return this;
870 | }
871 | };
872 |
873 | /**
874 | * Translates an element with css transforms in either 2d (if 2 arguments given)
875 | * or 3d (if 3 arguments given) space.
876 | * @method translate
877 | * @param {Number} x x-position in px
878 | * @param {Number} y y-position in px
879 | * @param {Number} [z] z-position in px
880 | * @param {Number} [perspective] sets the perspective of the parent element in px,
881 | * default value set to 1000px
882 | * @return {Object/p5.Element}
883 | * @example
884 | *
885 | * function setup() {
886 | * createCanvas(100,100);
887 | * //translates canvas 50px down
888 | * select('canvas').translate(0,50);
889 | * }
890 | *
891 | */
892 | p5.Element.prototype.translate = function(){
893 | this.elt.style.position = 'absolute';
894 | if (arguments.length === 2){
895 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
896 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
897 | this.elt.style.transform = 'translate('+arguments[0]+'px, '+arguments[1]+'px)';
898 | this.elt.style.transform += style;
899 | }else if (arguments.length === 3){
900 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
901 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
902 | this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
903 | this.elt.style.transform += style;
904 | this.elt.parentElement.style.perspective = '1000px';
905 | }else if (arguments.length === 4){
906 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
907 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
908 | this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
909 | this.elt.style.transform += style;
910 | this.elt.parentElement.style.perspective = arguments[3]+'px';
911 | }
912 | return this;
913 | };
914 |
915 | /**
916 | * Rotates an element with css transforms in either 2d (if 2 arguments given)
917 | * or 3d (if 3 arguments given) space.
918 | * @method rotate
919 | * @param {Number} x amount of degrees to rotate the element along the x-axis in deg
920 | * @param {Number} [y] amount of degrees to rotate the element along the y-axis in deg
921 | * @param {Number} [z] amount of degrees to rotate the element along the z-axis in deg
922 | * @return {Object/p5.Element}
923 | * @example
924 | *
925 | * var x = 0,
926 | * y = 0,
927 | * z = 0;
928 | * function setup(){
929 | * createCanvas(100,100);
930 | * }
931 | * function draw(){
932 | * x+=.5 % 360;
933 | * y+=.5 % 360;
934 | * z+=.5 % 360;
935 | * //rotates the canvas .5deg (degrees) on every axis each frame.
936 | * select('canvas').rotate(x,y,z);
937 | * }
938 | *
939 | */
940 | p5.Element.prototype.rotate = function(){
941 | if (arguments.length === 1){
942 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
943 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
944 | this.elt.style.transform = 'rotate('+arguments[0]+'deg)';
945 | this.elt.style.transform += style;
946 | }else if (arguments.length === 2){
947 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
948 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
949 | this.elt.style.transform = 'rotate('+arguments[0]+'deg, '+arguments[1]+'deg)';
950 | this.elt.style.transform += style;
951 | }else if (arguments.length === 3){
952 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
953 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
954 | this.elt.style.transform = 'rotateX('+arguments[0]+'deg)';
955 | this.elt.style.transform += 'rotateY('+arguments[1]+'deg)';
956 | this.elt.style.transform += 'rotateZ('+arguments[2]+'deg)';
957 | this.elt.style.transform += style;
958 | }
959 | return this;
960 | };
961 |
962 | /**
963 | * Sets the given style (css) property (1st arg) of the element with the
964 | * given value (2nd arg). If a single argument is given, .style()
965 | * returns the value of the given property; however, if the single argument
966 | * is given in css syntax ('text-align:center'), .style() sets the css
967 | * appropriatly. .style() also handles 2d and 3d css transforms. If
968 | * the 1st arg is 'rotate', 'translate', or 'position', the following arguments
969 | * accept Numbers as values. ('translate', 10, 100, 50);
970 | *
971 | * @method style
972 | * @param {String} property property to be set
973 | * @param {String|Number} [value] value to assign to property
974 | * @param {String|Number} [value] value to assign to property (rotate/translate)
975 | * @param {String|Number} [value] value to assign to property (rotate/translate)
976 | * @param {String|Number} [value] value to assign to property (translate)
977 | * @return {String|Object/p5.Element} value of property, if no value is specified
978 | * or p5.Element
979 | * @example
980 | *
981 | * var myDiv = createDiv("I like pandas.");
982 | * myDiv.style("color", "#ff0000");
983 | * myDiv.style("font-size", "18px");
984 | *
985 | */
986 | p5.Element.prototype.style = function(prop, val) {
987 | var self = this;
988 |
989 | if (typeof val === 'undefined') {
990 | if (prop.indexOf(':') === -1) {
991 | var styles = window.getComputedStyle(self.elt);
992 | var style = styles.getPropertyValue(prop);
993 | return style;
994 | } else {
995 | var attrs = prop.split(';');
996 | for (var i = 0; i < attrs.length; i++) {
997 | var parts = attrs[i].split(':');
998 | if (parts[0] && parts[1]) {
999 | this.elt.style[parts[0].trim()] = parts[1].trim();
1000 | }
1001 | }
1002 | }
1003 | } else {
1004 | if (prop === 'rotate'){
1005 | if (arguments.length === 2) {
1006 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1007 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
1008 | this.elt.style.transform = 'rotate(' + arguments[0] + 'deg)';
1009 | this.elt.style.transform += style;
1010 | } else if (arguments.length === 3) {
1011 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1012 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
1013 | this.elt.style.transform = 'rotate(' + arguments[0] + 'deg, ' + arguments[1] + 'deg)';
1014 | this.elt.style.transform += style;
1015 | } else if (arguments.length === 4) {
1016 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1017 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
1018 | this.elt.style.transform = 'rotateX(' + arguments[0] + 'deg)';
1019 | this.elt.style.transform += 'rotateY(' + arguments[1] + 'deg)';
1020 | this.elt.style.transform += 'rotateZ(' + arguments[2] + 'deg)';
1021 | this.elt.style.transform += style;
1022 | }
1023 | } else if (prop === 'translate') {
1024 | if (arguments.length === 3) {
1025 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1026 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
1027 | this.elt.style.transform = 'translate(' + arguments[0] + 'px, ' + arguments[1] + 'px)';
1028 | this.elt.style.transform += style;
1029 | } else if (arguments.length === 4) {
1030 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1031 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
1032 | this.elt.style.transform = 'translate3d(' + arguments[0] + 'px,' + arguments[1] + 'px,' + arguments[2] + 'px)';
1033 | this.elt.style.transform += style;
1034 | this.elt.parentElement.style.perspective = '1000px';
1035 | } else if (arguments.length === 5) {
1036 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1037 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
1038 | this.elt.style.transform = 'translate3d(' + arguments[0] + 'px,' + arguments[1] + 'px,' + arguments[2] + 'px)';
1039 | this.elt.style.transform += style;
1040 | this.elt.parentElement.style.perspective = arguments[3] + 'px';
1041 | }
1042 | } else if (prop === 'position') {
1043 | this.elt.style.left = arguments[1] + 'px';
1044 | this.elt.style.top = arguments[2] + 'px';
1045 | this.x = arguments[1];
1046 | this.y = arguments[2];
1047 | } else {
1048 | this.elt.style[prop] = val;
1049 | if (prop === 'width' || prop === 'height' || prop === 'left' || prop === 'top') {
1050 | var numVal = val.replace(/\D+/g, '');
1051 | this[prop] = parseInt(numVal, 10);
1052 | }
1053 | }
1054 | }
1055 | return this;
1056 | };
1057 |
1058 |
1059 | /**
1060 | *
1061 | * Adds a new attribute or changes the value of an existing attribute
1062 | * on the specified element. If no value is specified, returns the
1063 | * value of the given attribute, or null if attribute is not set.
1064 | *
1065 | * @method attribute
1066 | * @param {String} attr attribute to set
1067 | * @param {String} [value] value to assign to attribute
1068 | * @return {String|Object/p5.Element} value of attribute, if no value is
1069 | * specified or p5.Element
1070 | * @example
1071 | *
1072 | * var myDiv = createDiv("I like pandas.");
1073 | *myDiv.attribute("align", "center");
1074 | *
1075 | */
1076 | p5.Element.prototype.attribute = function(attr, value) {
1077 | if (typeof value === 'undefined') {
1078 | return this.elt.getAttribute(attr);
1079 | } else {
1080 | this.elt.setAttribute(attr, value);
1081 | return this;
1082 | }
1083 | };
1084 |
1085 |
1086 | /**
1087 | * Either returns the value of the element if no arguments
1088 | * given, or sets the value of the element.
1089 | *
1090 | * @method value
1091 | * @param {String|Number} [value]
1092 | * @return {String|Object/p5.Element} value of element if no value is specified or p5.Element
1093 | */
1094 | p5.Element.prototype.value = function() {
1095 | if (arguments.length > 0) {
1096 | this.elt.value = arguments[0];
1097 | return this;
1098 | } else {
1099 | if (this.elt.type === 'range') {
1100 | return parseFloat(this.elt.value);
1101 | }
1102 | else return this.elt.value;
1103 | }
1104 | };
1105 |
1106 | /**
1107 | *
1108 | * Shows the current element. Essentially, setting display:block for the style.
1109 | *
1110 | * @method show
1111 | * @return {Object/p5.Element}
1112 | */
1113 | p5.Element.prototype.show = function() {
1114 | this.elt.style.display = 'block';
1115 | return this;
1116 | };
1117 |
1118 | /**
1119 | * Hides the current element. Essentially, setting display:none for the style.
1120 | *
1121 | * @method hide
1122 | * @return {Object/p5.Element}
1123 | */
1124 | p5.Element.prototype.hide = function() {
1125 | this.elt.style.display = 'none';
1126 | return this;
1127 | };
1128 |
1129 | /**
1130 | *
1131 | * Sets the width and height of the element. AUTO can be used to
1132 | * only adjust one dimension. If no arguments given returns the width and height
1133 | * of the element in an object.
1134 | *
1135 | * @method size
1136 | * @param {Number} [w] width of the element
1137 | * @param {Number} [h] height of the element
1138 | * @return {Object/p5.Element}
1139 | */
1140 | p5.Element.prototype.size = function(w, h) {
1141 | if (arguments.length === 0){
1142 | return { 'width' : this.elt.offsetWidth , 'height' : this.elt.offsetHeight };
1143 | }else{
1144 | var aW = w;
1145 | var aH = h;
1146 | var AUTO = p5.prototype.AUTO;
1147 | if (aW !== AUTO || aH !== AUTO) {
1148 | if (aW === AUTO) {
1149 | aW = h * this.width / this.height;
1150 | } else if (aH === AUTO) {
1151 | aH = w * this.height / this.width;
1152 | }
1153 | // set diff for cnv vs normal div
1154 | if (this.elt instanceof HTMLCanvasElement) {
1155 | var j = {};
1156 | var k = this.elt.getContext('2d');
1157 | for (var prop in k) {
1158 | j[prop] = k[prop];
1159 | }
1160 | this.elt.setAttribute('width', aW * this._pInst._pixelDensity);
1161 | this.elt.setAttribute('height', aH * this._pInst._pixelDensity);
1162 | this.elt.setAttribute('style', 'width:' + aW + 'px; height:' + aH + 'px');
1163 | this._pInst.scale(this._pInst._pixelDensity, this._pInst._pixelDensity);
1164 | for (var prop in j) {
1165 | this.elt.getContext('2d')[prop] = j[prop];
1166 | }
1167 | } else {
1168 | this.elt.style.width = aW+'px';
1169 | this.elt.style.height = aH+'px';
1170 | this.elt.width = aW;
1171 | this.elt.height = aH;
1172 | this.width = aW;
1173 | this.height = aH;
1174 | }
1175 |
1176 | this.width = this.elt.offsetWidth;
1177 | this.height = this.elt.offsetHeight;
1178 |
1179 | if (this._pInst) { // main canvas associated with p5 instance
1180 | if (this._pInst._curElement.elt === this.elt) {
1181 | this._pInst._setProperty('width', this.elt.offsetWidth);
1182 | this._pInst._setProperty('height', this.elt.offsetHeight);
1183 | }
1184 | }
1185 | }
1186 | return this;
1187 | }
1188 | };
1189 |
1190 | /**
1191 | * Removes the element and deregisters all listeners.
1192 | * @method remove
1193 | * @example
1194 | *
1195 | * var myDiv = createDiv('this is some text');
1196 | * myDiv.remove();
1197 | *
1198 | */
1199 | p5.Element.prototype.remove = function() {
1200 | // deregister events
1201 | for (var ev in this._events) {
1202 | this.elt.removeEventListener(ev, this._events[ev]);
1203 | }
1204 | if (this.elt.parentNode) {
1205 | this.elt.parentNode.removeChild(this.elt);
1206 | }
1207 | delete(this);
1208 | };
1209 |
1210 |
1211 |
1212 | // =============================================================================
1213 | // p5.MediaElement additions
1214 | // =============================================================================
1215 |
1216 |
1217 | /**
1218 | * Extends p5.Element to handle audio and video. In addition to the methods
1219 | * of p5.Element, it also contains methods for controlling media. It is not
1220 | * called directly, but p5.MediaElements are created by calling createVideo,
1221 | * createAudio, and createCapture.
1222 | *
1223 | * @class p5.MediaElement
1224 | * @constructor
1225 | * @param {String} elt DOM node that is wrapped
1226 | * @param {Object} [pInst] pointer to p5 instance
1227 | */
1228 | p5.MediaElement = function(elt, pInst) {
1229 | p5.Element.call(this, elt, pInst);
1230 |
1231 |
1232 | this._prevTime = 0;
1233 | this._cueIDCounter = 0;
1234 | this._cues = [];
1235 | this.pixelDensity = 1;
1236 |
1237 | };
1238 | p5.MediaElement.prototype = Object.create(p5.Element.prototype);
1239 |
1240 |
1241 |
1242 |
1243 | /**
1244 | * Play an HTML5 media element.
1245 | *
1246 | * @method play
1247 | * @return {Object/p5.Element}
1248 | */
1249 | p5.MediaElement.prototype.play = function() {
1250 | if (this.elt.currentTime === this.elt.duration) {
1251 | this.elt.currentTime = 0;
1252 | }
1253 |
1254 | if (this.elt.readyState > 1) {
1255 | this.elt.play();
1256 | } else {
1257 | // in Chrome, playback cannot resume after being stopped and must reload
1258 | this.elt.load();
1259 | this.elt.play();
1260 | }
1261 | return this;
1262 | };
1263 |
1264 | /**
1265 | * Stops an HTML5 media element (sets current time to zero).
1266 | *
1267 | * @method stop
1268 | * @return {Object/p5.Element}
1269 | */
1270 | p5.MediaElement.prototype.stop = function() {
1271 | this.elt.pause();
1272 | this.elt.currentTime = 0;
1273 | return this;
1274 | };
1275 |
1276 | /**
1277 | * Pauses an HTML5 media element.
1278 | *
1279 | * @method pause
1280 | * @return {Object/p5.Element}
1281 | */
1282 | p5.MediaElement.prototype.pause = function() {
1283 | this.elt.pause();
1284 | return this;
1285 | };
1286 |
1287 | /**
1288 | * Set 'loop' to true for an HTML5 media element, and starts playing.
1289 | *
1290 | * @method loop
1291 | * @return {Object/p5.Element}
1292 | */
1293 | p5.MediaElement.prototype.loop = function() {
1294 | this.elt.setAttribute('loop', true);
1295 | this.play();
1296 | return this;
1297 | };
1298 | /**
1299 | * Set 'loop' to false for an HTML5 media element. Element will stop
1300 | * when it reaches the end.
1301 | *
1302 | * @method noLoop
1303 | * @return {Object/p5.Element}
1304 | */
1305 | p5.MediaElement.prototype.noLoop = function() {
1306 | this.elt.setAttribute('loop', false);
1307 | return this;
1308 | };
1309 |
1310 |
1311 | /**
1312 | * Set HTML5 media element to autoplay or not.
1313 | *
1314 | * @method autoplay
1315 | * @param {Boolean} autoplay whether the element should autoplay
1316 | * @return {Object/p5.Element}
1317 | */
1318 | p5.MediaElement.prototype.autoplay = function(val) {
1319 | this.elt.setAttribute('autoplay', val);
1320 | return this;
1321 | };
1322 |
1323 | /**
1324 | * Sets volume for this HTML5 media element. If no argument is given,
1325 | * returns the current volume.
1326 | *
1327 | * @param {Number} [val] volume between 0.0 and 1.0
1328 | * @return {Number|p5.MediaElement} current volume or p5.MediaElement
1329 | * @method volume
1330 | */
1331 | p5.MediaElement.prototype.volume = function(val) {
1332 | if (typeof val === 'undefined') {
1333 | return this.elt.volume;
1334 | } else {
1335 | this.elt.volume = val;
1336 | }
1337 | };
1338 |
1339 | /**
1340 | * If no arguments are given, returns the current time of the elmeent.
1341 | * If an argument is given the current time of the element is set to it.
1342 | *
1343 | * @method time
1344 | * @param {Number} [time] time to jump to (in seconds)
1345 | * @return {Number|Object/p5.MediaElement} current time (in seconds)
1346 | * or p5.MediaElement
1347 | */
1348 | p5.MediaElement.prototype.time = function(val) {
1349 | if (typeof val === 'undefined') {
1350 | return this.elt.currentTime;
1351 | } else {
1352 | this.elt.currentTime = val;
1353 | }
1354 | };
1355 |
1356 | /**
1357 | * Returns the duration of the HTML5 media element.
1358 | *
1359 | * @method duration
1360 | * @return {Number} duration
1361 | */
1362 | p5.MediaElement.prototype.duration = function() {
1363 | return this.elt.duration;
1364 | };
1365 | p5.MediaElement.prototype.pixels = [];
1366 | p5.MediaElement.prototype.loadPixels = function() {
1367 | if (this.loadedmetadata) { // wait for metadata for w/h
1368 | if (!this.canvas) {
1369 | this.canvas = document.createElement('canvas');
1370 | this.canvas.width = this.width;
1371 | this.canvas.height = this.height;
1372 | this.drawingContext = this.canvas.getContext('2d');
1373 | }
1374 | this.drawingContext.drawImage(this.elt, 0, 0, this.width, this.height);
1375 | p5.Renderer2D.prototype.loadPixels.call(this);
1376 | }
1377 | return this;
1378 | }
1379 | p5.MediaElement.prototype.updatePixels = function(x, y, w, h){
1380 | if (this.loadedmetadata) { // wait for metadata
1381 | p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h);
1382 | }
1383 | return this;
1384 | }
1385 | p5.MediaElement.prototype.get = function(x, y, w, h){
1386 | if (this.loadedmetadata) { // wait for metadata
1387 | return p5.Renderer2D.prototype.get.call(this, x, y, w, h);
1388 | } else return [0, 0, 0, 255];
1389 | };
1390 | p5.MediaElement.prototype.set = function(x, y, imgOrCol){
1391 | if (this.loadedmetadata) { // wait for metadata
1392 | p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol);
1393 | }
1394 | };
1395 |
1396 | /*** CONNECT TO WEB AUDIO API / p5.sound.js ***/
1397 |
1398 | /**
1399 | * Send the audio output of this element to a specified audioNode or
1400 | * p5.sound object. If no element is provided, connects to p5's master
1401 | * output. That connection is established when this method is first called.
1402 | * All connections are removed by the .disconnect() method.
1403 | *
1404 | * This method is meant to be used with the p5.sound.js addon library.
1405 | *
1406 | * @method connect
1407 | * @param {AudioNode|p5.sound object} audioNode AudioNode from the Web Audio API,
1408 | * or an object from the p5.sound library
1409 | */
1410 | p5.MediaElement.prototype.connect = function(obj) {
1411 | var audioContext, masterOutput;
1412 |
1413 | // if p5.sound exists, same audio context
1414 | if (typeof p5.prototype.getAudioContext === 'function') {
1415 | audioContext = p5.prototype.getAudioContext();
1416 | masterOutput = p5.soundOut.input;
1417 | } else {
1418 | try {
1419 | audioContext = obj.context;
1420 | masterOutput = audioContext.destination
1421 | } catch(e) {
1422 | throw 'connect() is meant to be used with Web Audio API or p5.sound.js'
1423 | }
1424 | }
1425 |
1426 | // create a Web Audio MediaElementAudioSourceNode if none already exists
1427 | if (!this.audioSourceNode) {
1428 | this.audioSourceNode = audioContext.createMediaElementSource(this.elt);
1429 |
1430 | // connect to master output when this method is first called
1431 | this.audioSourceNode.connect(masterOutput);
1432 | }
1433 |
1434 | // connect to object if provided
1435 | if (obj) {
1436 | if (obj.input) {
1437 | this.audioSourceNode.connect(obj.input);
1438 | } else {
1439 | this.audioSourceNode.connect(obj);
1440 | }
1441 | }
1442 |
1443 | // otherwise connect to master output of p5.sound / AudioContext
1444 | else {
1445 | this.audioSourceNode.connect(masterOutput);
1446 | }
1447 |
1448 | };
1449 |
1450 | /**
1451 | * Disconnect all Web Audio routing, including to master output.
1452 | * This is useful if you want to re-route the output through
1453 | * audio effects, for example.
1454 | *
1455 | * @method disconnect
1456 | */
1457 | p5.MediaElement.prototype.disconnect = function() {
1458 | if (this.audioSourceNode) {
1459 | this.audioSourceNode.disconnect();
1460 | } else {
1461 | throw 'nothing to disconnect';
1462 | }
1463 | };
1464 |
1465 |
1466 | /*** SHOW / HIDE CONTROLS ***/
1467 |
1468 | /**
1469 | * Show the default MediaElement controls, as determined by the web browser.
1470 | *
1471 | * @method showControls
1472 | */
1473 | p5.MediaElement.prototype.showControls = function() {
1474 | // must set style for the element to show on the page
1475 | this.elt.style['text-align'] = 'inherit';
1476 | this.elt.controls = true;
1477 | };
1478 |
1479 | /**
1480 | * Hide the default mediaElement controls.
1481 | *
1482 | * @method hideControls
1483 | */
1484 | p5.MediaElement.prototype.hideControls = function() {
1485 | this.elt.controls = false;
1486 | };
1487 |
1488 |
1489 | /*** SCHEDULE EVENTS ***/
1490 |
1491 | /**
1492 | * Schedule events to trigger every time a MediaElement
1493 | * (audio/video) reaches a playback cue point.
1494 | *
1495 | * Accepts a callback function, a time (in seconds) at which to trigger
1496 | * the callback, and an optional parameter for the callback.
1497 | *
1498 | * Time will be passed as the first parameter to the callback function,
1499 | * and param will be the second parameter.
1500 | *
1501 | *
1502 | * @method addCue
1503 | * @param {Number} time Time in seconds, relative to this media
1504 | * element's playback. For example, to trigger
1505 | * an event every time playback reaches two
1506 | * seconds, pass in the number 2. This will be
1507 | * passed as the first parameter to
1508 | * the callback function.
1509 | * @param {Function} callback Name of a function that will be
1510 | * called at the given time. The callback will
1511 | * receive time and (optionally) param as its
1512 | * two parameters.
1513 | * @param {Object} [value] An object to be passed as the
1514 | * second parameter to the
1515 | * callback function.
1516 | * @return {Number} id ID of this cue,
1517 | * useful for removeCue(id)
1518 | * @example
1519 | *
1520 | * function setup() {
1521 | * background(255,255,255);
1522 | *
1523 | * audioEl = createAudio('assets/beat.mp3');
1524 | * audioEl.showControls();
1525 | *
1526 | * // schedule three calls to changeBackground
1527 | * audioEl.addCue(0.5, changeBackground, color(255,0,0) );
1528 | * audioEl.addCue(1.0, changeBackground, color(0,255,0) );
1529 | * audioEl.addCue(2.5, changeBackground, color(0,0,255) );
1530 | * audioEl.addCue(3.0, changeBackground, color(0,255,255) );
1531 | * audioEl.addCue(4.2, changeBackground, color(255,255,0) );
1532 | * audioEl.addCue(5.0, changeBackground, color(255,255,0) );
1533 | * }
1534 | *
1535 | * function changeBackground(val) {
1536 | * background(val);
1537 | * }
1538 | *
1539 | */
1540 | p5.MediaElement.prototype.addCue = function(time, callback, val) {
1541 | var id = this._cueIDCounter++;
1542 |
1543 | var cue = new Cue(callback, time, id, val);
1544 | this._cues.push(cue);
1545 |
1546 | if (!this.elt.ontimeupdate) {
1547 | this.elt.ontimeupdate = this._onTimeUpdate.bind(this);
1548 | }
1549 |
1550 | return id;
1551 | };
1552 |
1553 | /**
1554 | * Remove a callback based on its ID. The ID is returned by the
1555 | * addCue method.
1556 | *
1557 | * @method removeCue
1558 | * @param {Number} id ID of the cue, as returned by addCue
1559 | */
1560 | p5.MediaElement.prototype.removeCue = function(id) {
1561 | for (var i = 0; i < this._cues.length; i++) {
1562 | var cue = this._cues[i];
1563 | if (cue.id === id) {
1564 | this.cues.splice(i, 1);
1565 | }
1566 | }
1567 |
1568 | if (this._cues.length === 0) {
1569 | this.elt.ontimeupdate = null
1570 | }
1571 | };
1572 |
1573 | /**
1574 | * Remove all of the callbacks that had originally been scheduled
1575 | * via the addCue method.
1576 | *
1577 | * @method clearCues
1578 | */
1579 | p5.MediaElement.prototype.clearCues = function() {
1580 | this._cues = [];
1581 | this.elt.ontimeupdate = null;
1582 | };
1583 |
1584 | // private method that checks for cues to be fired if events
1585 | // have been scheduled using addCue(callback, time).
1586 | p5.MediaElement.prototype._onTimeUpdate = function() {
1587 | var playbackTime = this.time();
1588 |
1589 | for (var i = 0 ; i < this._cues.length; i++) {
1590 | var callbackTime = this._cues[i].time;
1591 | var val = this._cues[i].val;
1592 |
1593 |
1594 | if (this._prevTime < callbackTime && callbackTime <= playbackTime) {
1595 |
1596 | // pass the scheduled callbackTime as parameter to the callback
1597 | this._cues[i].callback(val);
1598 | }
1599 |
1600 | }
1601 |
1602 | this._prevTime = playbackTime;
1603 | };
1604 |
1605 |
1606 | // Cue inspired by JavaScript setTimeout, and the
1607 | // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org
1608 | var Cue = function(callback, time, id, val) {
1609 | this.callback = callback;
1610 | this.time = time;
1611 | this.id = id;
1612 | this.val = val;
1613 | };
1614 |
1615 | // =============================================================================
1616 | // p5.File
1617 | // =============================================================================
1618 |
1619 |
1620 | /**
1621 | * Base class for a file
1622 | * Using this for createFileInput
1623 | *
1624 | * @class p5.File
1625 | * @constructor
1626 | * @param {File} file File that is wrapped
1627 | * @param {Object} [pInst] pointer to p5 instance
1628 | */
1629 | p5.File = function(file, pInst) {
1630 | /**
1631 | * Underlying File object. All normal File methods can be called on this.
1632 | *
1633 | * @property file
1634 | */
1635 | this.file = file;
1636 |
1637 | this._pInst = pInst;
1638 |
1639 | // Splitting out the file type into two components
1640 | // This makes determining if image or text etc simpler
1641 | var typeList = file.type.split('/');
1642 | /**
1643 | * File type (image, text, etc.)
1644 | *
1645 | * @property type
1646 | */
1647 | this.type = typeList[0];
1648 | /**
1649 | * File subtype (usually the file extension jpg, png, xml, etc.)
1650 | *
1651 | * @property subtype
1652 | */
1653 | this.subtype = typeList[1];
1654 | /**
1655 | * File name
1656 | *
1657 | * @property name
1658 | */
1659 | this.name = file.name;
1660 | /**
1661 | * File size
1662 | *
1663 | * @property size
1664 | */
1665 | this.size = file.size;
1666 |
1667 | // Data not loaded yet
1668 | this.data = undefined;
1669 | };
1670 |
1671 | }));
1672 |
--------------------------------------------------------------------------------
/mobile-examples/01_first/sketch.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | createCanvas(displayWidth, displayHeight);
3 | }
4 |
5 | function draw() {
6 | background(0);
7 | fill(255);
8 | ellipse(width/2, height/2, 100, 100);
9 | }
--------------------------------------------------------------------------------
/mobile-examples/02_touchIsDown/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 01_touchIsDown
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/mobile-examples/02_touchIsDown/libraries/p5.dom.js:
--------------------------------------------------------------------------------
1 | /*! p5.dom.js v0.2.4 October 6, 2015 */
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 | // p5 additions
38 | // =============================================================================
39 |
40 | /**
41 | * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.'
42 | * prefixes to specify an ID or class respectively, and none for a tag) and returns it as
43 | * a p5.Element. If a class or tag name is given with more than 1 element,
44 | * only the first element will be returned.
45 | * The DOM node itself can be accessed with .elt.
46 | * Returns null if none found.
47 | *
48 | * @method select
49 | * @param {String} name id, class, or tag name of element to search for
50 | * @return {Object/p5.Element|Null} p5.Element containing node found
51 | */
52 | p5.prototype.select = function (e) {
53 | var res;
54 | var str;
55 | if (e[0] === '.'){
56 | str = e.slice(1);
57 | res = document.getElementsByClassName(str);
58 | if (res) {
59 | return wrapElement(res[0]);
60 | }else {
61 | return null;
62 | }
63 | }else if (e[0] === '#'){
64 | str = e.slice(1);
65 | res = document.getElementById(str);
66 | if (res) {
67 | return wrapElement(res);
68 | }else {
69 | return null;
70 | }
71 | }else{
72 | res = document.getElementsByTagName(e);
73 | if (res) {
74 | return wrapElement(res[0]);
75 | }else {
76 | return null;
77 | }
78 | }
79 | };
80 |
81 | /**
82 | * Searches the page for elements with the given class or tag name (using the '.' prefix
83 | * to specify a class and no prefix for a tag) and returns them as p5.Elements
84 | * in an array.
85 | * The DOM node itself can be accessed with .elt.
86 | * Returns null if none found.
87 | *
88 | * @method selectAll
89 | * @param {String} name class or tag name of elements to search for
90 | * @return {Array} Array of p5.Elements containing nodes found
91 | */
92 | p5.prototype.selectAll = function (e) {
93 | var arr = [];
94 | var res;
95 | var str;
96 | if (e[0] === '.'){
97 | str = e.slice(1);
98 | res = document.getElementsByClassName(str);
99 | }else {
100 | res = document.getElementsByTagName(e);
101 | }
102 | if (res) {
103 | for (var j = 0; j < res.length; j++) {
104 | var obj = wrapElement(res[j]);
105 | arr.push(obj);
106 | }
107 | }
108 | return arr;
109 | };
110 |
111 | /**
112 | * Helper function for getElement and getElements.
113 | */
114 | function wrapElement(elt) {
115 | if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") {
116 | return new p5.MediaElement(elt);
117 | } else {
118 | return new p5.Element(elt);
119 | }
120 | }
121 |
122 | /**
123 | * Removes all elements created by p5, except any canvas / graphics
124 | * elements created by createCanvas or createGraphics.
125 | * Event handlers are removed, and element is removed from the DOM.
126 | * @method removeElements
127 | * @example
128 | *
129 | * function setup() {
130 | * createCanvas(100, 100);
131 | * createDiv('this is some text');
132 | * createP('this is a paragraph');
133 | * }
134 | * function mousePressed() {
135 | * removeElements(); // this will remove the div and p, not canvas
136 | * }
137 | *
138 | *
139 | */
140 | p5.prototype.removeElements = function (e) {
141 | for (var i=0; i
169 | * var myDiv;
170 | * function setup() {
171 | * myDiv = createDiv('this is some text');
172 | * }
173 | *
174 | */
175 |
176 | /**
177 | * Creates a <p></p> element in the DOM with given inner HTML. Used
178 | * for paragraph length text.
179 | * Appends to the container node if one is specified, otherwise
180 | * appends to body.
181 | *
182 | * @method createP
183 | * @param {String} html inner HTML for element created
184 | * @return {Object/p5.Element} pointer to p5.Element holding created node
185 | * @example
186 | *
187 | * var myP;
188 | * function setup() {
189 | * myP = createP('this is some text');
190 | * }
191 | *
192 | */
193 |
194 | /**
195 | * Creates a <span></span> element in the DOM with given inner HTML.
196 | * Appends to the container node if one is specified, otherwise
197 | * appends to body.
198 | *
199 | * @method createSpan
200 | * @param {String} html inner HTML for element created
201 | * @return {Object/p5.Element} pointer to p5.Element holding created node
202 | * @example
203 | *
204 | * var mySpan;
205 | * function setup() {
206 | * mySpan = createSpan('this is some text');
207 | * }
208 | *
209 | */
210 | var tags = ['div', 'p', 'span'];
211 | tags.forEach(function(tag) {
212 | var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1);
213 | p5.prototype[method] = function(html) {
214 | var elt = document.createElement(tag);
215 | elt.innerHTML = typeof html === undefined ? "" : html;
216 | return addElement(elt, this);
217 | }
218 | });
219 |
220 | /**
221 | * Creates an <img /> element in the DOM with given src and
222 | * alternate text.
223 | * Appends to the container node if one is specified, otherwise
224 | * appends to body.
225 | *
226 | * @method createImg
227 | * @param {String} src src path or url for image
228 | * @param {String} [alt] alternate text to be used if image does not load
229 | * @param {Function} [successCallback] callback to be called once image data is loaded
230 | * @return {Object/p5.Element} pointer to p5.Element holding created node
231 | * @example
232 | *
233 | * var img;
234 | * function setup() {
235 | * img = createImg('http://p5js.org/img/asterisk-01.png');
236 | * }
237 | *
238 | */
239 | p5.prototype.createImg = function() {
240 | var elt = document.createElement('img');
241 | var args = arguments;
242 | var self;
243 | var setAttrs = function(){
244 | self.width = elt.offsetWidth;
245 | self.height = elt.offsetHeight;
246 | if (args.length > 1 && typeof args[1] === 'function'){
247 | self.fn = args[1];
248 | self.fn();
249 | }else if (args.length > 1 && typeof args[2] === 'function'){
250 | self.fn = args[2];
251 | self.fn();
252 | }
253 | };
254 | elt.src = args[0];
255 | if (args.length > 1 && typeof args[1] === 'string'){
256 | elt.alt = args[1];
257 | }
258 | elt.onload = function(){
259 | setAttrs();
260 | }
261 | self = addElement(elt, this);
262 | return self;
263 | };
264 |
265 | /**
266 | * Creates an <a></a> element in the DOM for including a hyperlink.
267 | * Appends to the container node if one is specified, otherwise
268 | * appends to body.
269 | *
270 | * @method createA
271 | * @param {String} href url of page to link to
272 | * @param {String} html inner html of link element to display
273 | * @param {String} [target] target where new link should open,
274 | * could be _blank, _self, _parent, _top.
275 | * @return {Object/p5.Element} pointer to p5.Element holding created node
276 | * @example
277 | *
278 | * var myLink;
279 | * function setup() {
280 | * myLink = createA('http://p5js.org/', 'this is a link');
281 | * }
282 | *
283 | */
284 | p5.prototype.createA = function(href, html, target) {
285 | var elt = document.createElement('a');
286 | elt.href = href;
287 | elt.innerHTML = html;
288 | if (target) elt.target = target;
289 | return addElement(elt, this);
290 | };
291 |
292 | /** INPUT **/
293 |
294 |
295 | /**
296 | * Creates a slider <input></input> element in the DOM.
297 | * Use .size() to set the display length of the slider.
298 | * Appends to the container node if one is specified, otherwise
299 | * appends to body.
300 | *
301 | * @method createSlider
302 | * @param {Number} min minimum value of the slider
303 | * @param {Number} max maximum value of the slider
304 | * @param {Number} [value] default value of the slider
305 | * @return {Object/p5.Element} pointer to p5.Element holding created node
306 | * @example
307 | *
308 | * var slider;
309 | * function setup() {
310 | * slider = createSlider(0, 255, 100);
311 | * slider.position(10, 10);
312 | * slider.style('width', '80px');
313 | * }
314 | *
315 | * function draw() {
316 | * var val = slider.value();
317 | * background(val);
318 | * }
319 | *
320 | */
321 | p5.prototype.createSlider = function(min, max, value, step) {
322 | var elt = document.createElement('input');
323 | elt.type = 'range';
324 | elt.min = min;
325 | elt.max = max;
326 | if (step) elt.step = step;
327 | if (typeof(value) === "number") elt.value = value;
328 | return addElement(elt, this);
329 | };
330 |
331 | /**
332 | * Creates a <button></button> element in the DOM.
333 | * Use .size() to set the display size of the button.
334 | * Use .mousePressed() to specify behavior on press.
335 | * Appends to the container node if one is specified, otherwise
336 | * appends to body.
337 | *
338 | * @method createButton
339 | * @param {String} label label displayed on the button
340 | * @param {String} [value] value of the button
341 | * @return {Object/p5.Element} pointer to p5.Element holding created node
342 | * @example
343 | *
344 | * var button;
345 | * function setup() {
346 | * createCanvas(100, 100);
347 | * background(0);
348 | * button = createButton('click me');
349 | * button.position(19, 19);
350 | * button.mousePressed(changeBG);
351 | * }
352 | *
353 | * function changeBG() {
354 | * var val = random(255);
355 | * background(val);
356 | * }
357 | *
358 | */
359 | p5.prototype.createButton = function(label, value) {
360 | var elt = document.createElement('button');
361 | elt.innerHTML = label;
362 | elt.value = value;
363 | if (value) elt.value = value;
364 | return addElement(elt, this);
365 | };
366 |
367 | /**
368 | * Creates a checkbox <input></input> element in the DOM.
369 | *
370 | * @method createCheckbox
371 | * @param {String} [label] label displayed after checkbox
372 | * @param {boolean} [value] value of the checkbox; checked is true, unchecked is false. Unchecked if no value given
373 | * @return {Object/p5.Element} pointer to p5.Element holding created node
374 | */
375 | p5.prototype.createCheckbox = function() {
376 | var elt = document.createElement('input');
377 | elt.type = 'checkbox';
378 | //checkbox must be wrapped in p5.Element before label so that label appears after
379 | var self = addElement(elt, this);
380 | self.checked = function(){
381 | if (arguments.length === 0){
382 | return self.elt.checked;
383 | }else if(arguments[0]){
384 | self.elt.checked = true;
385 | }else{
386 | self.elt.checked = false;
387 | }
388 | return self;
389 | };
390 | this.value = function(val){
391 | self.value = val;
392 | return this;
393 | };
394 | if (arguments[0]){
395 | var ran = Math.random().toString(36).slice(2);
396 | var label = document.createElement('label');
397 | elt.setAttribute('id', ran);
398 | label.htmlFor = ran;
399 | self.value(arguments[0]);
400 | label.appendChild(document.createTextNode(arguments[0]));
401 | addElement(label, this);
402 | }
403 | if (arguments[1]){
404 | elt.checked = true;
405 | }
406 | return self;
407 | };
408 |
409 | /**
410 | * Creates a dropdown menu <select></select> element in the DOM.
411 | * @method createSelect
412 | * @param {boolean} [multiple] [true if dropdown should support multiple selections]
413 | * @return {Object/p5.Element} pointer to p5.Element holding created node
414 | */
415 | p5.prototype.createSelect = function(mult) {
416 | var elt = document.createElement('select');
417 | if (mult){
418 | elt.setAttribute('multiple', 'true');
419 | }
420 | var self = addElement(elt, this);
421 | self.option = function(name, value){
422 | var opt = document.createElement('option');
423 | opt.innerHTML = name;
424 | if (arguments.length > 1)
425 | opt.value = value;
426 | else
427 | opt.value = name;
428 | elt.appendChild(opt);
429 | };
430 | self.selected = function(value){
431 | var arr = [];
432 | if (arguments.length > 0){
433 | for (var i = 0; i < this.elt.length; i++){
434 | if (value.toString() === this.elt[i].value){
435 | this.elt.selectedIndex = i;
436 | }
437 | }
438 | return this;
439 | }else{
440 | if (mult){
441 | for (var i = 0; i < this.elt.selectedOptions.length; i++){
442 | arr.push(this.elt.selectedOptions[i].value);
443 | }
444 | return arr;
445 | }else{
446 | return this.elt.value;
447 | }
448 | }
449 | };
450 | return self;
451 | };
452 |
453 | /**
454 | * Creates an <input></input> element in the DOM for text input.
455 | * Use .size() to set the display length of the box.
456 | * Appends to the container node if one is specified, otherwise
457 | * appends to body.
458 | *
459 | * @method createInput
460 | * @param {Number} [value] default value of the input box
461 | * @return {Object/p5.Element} pointer to p5.Element holding created node
462 | */
463 | p5.prototype.createInput = function(value) {
464 | var elt = document.createElement('input');
465 | elt.type = 'text';
466 | if (value) elt.value = value;
467 | return addElement(elt, this);
468 | };
469 |
470 | /**
471 | * Creates an <input></input> element in the DOM of type 'file'.
472 | * This allows users to select local files for use in a sketch.
473 | *
474 | * @method createFileInput
475 | * @param {Function} [callback] callback function for when a file loaded
476 | * @param {String} [multiple] optional to allow multiple files selected
477 | * @return {Object/p5.Element} pointer to p5.Element holding created DOM element
478 | */
479 | p5.prototype.createFileInput = function(callback, multiple) {
480 |
481 | // Is the file stuff supported?
482 | if (window.File && window.FileReader && window.FileList && window.Blob) {
483 | // Yup, we're ok and make an input file selector
484 | var elt = document.createElement('input');
485 | elt.type = 'file';
486 |
487 | // If we get a second argument that evaluates to true
488 | // then we are looking for multiple files
489 | if (multiple) {
490 | // Anything gets the job done
491 | elt.multiple = 'multiple';
492 | }
493 |
494 | // Now let's handle when a file was selected
495 | elt.addEventListener('change', handleFileSelect, false);
496 |
497 | // Function to handle when a file is selected
498 | // We're simplifying life and assuming that we always
499 | // want to load every selected file
500 | function handleFileSelect(evt) {
501 | // These are the files
502 | var files = evt.target.files;
503 | // Load each one and trigger a callback
504 | for (var i = 0; i < files.length; i++) {
505 | var f = files[i];
506 | var reader = new FileReader();
507 | reader.onload = makeLoader(f);
508 | function makeLoader(theFile) {
509 | // Making a p5.File object
510 | var p5file = new p5.File(theFile);
511 | return function(e) {
512 | p5file.data = e.target.result;
513 | callback(p5file);
514 | };
515 | };
516 |
517 | // Text or data?
518 | // This should likely be improved
519 | if (f.type.indexOf('text') > -1) {
520 | reader.readAsText(f);
521 | } else {
522 | reader.readAsDataURL(f);
523 | }
524 | }
525 | }
526 | return addElement(elt, this);
527 | } else {
528 | console.log('The File APIs are not fully supported in this browser. Cannot create element.');
529 | }
530 | };
531 |
532 |
533 | /** VIDEO STUFF **/
534 |
535 | function createMedia(pInst, type, src, callback) {
536 | var elt = document.createElement(type);
537 | if (typeof src === 'string') {
538 | src = [src];
539 | }
540 | for (var i=0; ithis
571 | * page for further information about supported formats.
572 | *
573 | * @method createVideo
574 | * @param {String|Array} src path to a video file, or array of paths for
575 | * supporting different browsers
576 | * @param {Object} [callback] callback function to be called upon
577 | * 'canplaythrough' event fire, that is, when the
578 | * browser can play the media, and estimates that
579 | * enough data has been loaded to play the media
580 | * up to its end without having to stop for
581 | * further buffering of content
582 | * @return {Object/p5.Element} pointer to video p5.Element
583 | */
584 | p5.prototype.createVideo = function(src, callback) {
585 | return createMedia(this, 'video', src, callback);
586 | };
587 |
588 | /** AUDIO STUFF **/
589 |
590 | /**
591 | * Creates a hidden HTML5 <audio> element in the DOM for simple audio
592 | * playback. Appends to the container node if one is specified,
593 | * otherwise appends to body. The first parameter
594 | * can be either a single string path to a audio file, or an array of string
595 | * paths to different formats of the same audio. This is useful for ensuring
596 | * that your audio can play across different browsers, as each supports
597 | * different formats. See this
598 | * page for further information about supported formats.
599 | *
600 | * @method createAudio
601 | * @param {String|Array} src path to an audio file, or array of paths for
602 | * supporting different browsers
603 | * @param {Object} [callback] callback function to be called upon
604 | * 'canplaythrough' event fire, that is, when the
605 | * browser can play the media, and estimates that
606 | * enough data has been loaded to play the media
607 | * up to its end without having to stop for
608 | * further buffering of content
609 | * @return {Object/p5.Element} pointer to audio p5.Element
610 | */
611 | p5.prototype.createAudio = function(src, callback) {
612 | return createMedia(this, 'audio', src, callback);
613 | };
614 |
615 |
616 | /** CAMERA STUFF **/
617 |
618 | p5.prototype.VIDEO = 'video';
619 | p5.prototype.AUDIO = 'audio';
620 |
621 | navigator.getUserMedia = navigator.getUserMedia ||
622 | navigator.webkitGetUserMedia ||
623 | navigator.mozGetUserMedia ||
624 | navigator.msGetUserMedia;
625 |
626 | /**
627 | * Creates a new <video> element that contains the audio/video feed
628 | * from a webcam. This can be drawn onto the canvas using video(). More
629 | * specific properties of the stream can be passing in a Constraints object.
630 | * See the
631 | * W3C
632 | * spec for possible properties. Note that not all of these are supported
633 | * by all browsers.
634 | *
635 | * @method createCapture
636 | * @param {String|Constant|Object} type type of capture, either VIDEO or
637 | * AUDIO if none specified, default both,
638 | * or a Constraints boject
639 | * @param {Function} callback function to be called once
640 | * stream has loaded
641 | * @return {Object/p5.Element} capture video p5.Element
642 | * @example
643 | *
644 | * var capture;
645 | *
646 | * function setup() {
647 | * createCanvas(480, 120);
648 | * capture = createCapture(VIDEO);
649 | * }
650 | *
651 | * function draw() {
652 | * image(capture, 0, 0, width, width*capture.height/capture.width);
653 | * filter(INVERT);
654 | * }
655 | *
656 | *
657 | * function setup() {
658 | * createCanvas(480, 120);
659 | * var constraints = {
660 | * video: {
661 | * mandatory: {
662 | * minWidth: 1280,
663 | * minHeight: 720
664 | * },
665 | * optional: [
666 | * { maxFrameRate: 10 }
667 | * ]
668 | * },
669 | * audio: true
670 | * };
671 | * createCapture(constraints, function(stream) {
672 | * console.log(stream);
673 | * });
674 | * }
675 | *
676 | */
677 | p5.prototype.createCapture = function() {
678 | var useVideo = true;
679 | var useAudio = true;
680 | var constraints;
681 | var cb;
682 | for (var i=0; i
792 | * var div0 = createDiv('this is the parent');
793 | * var div1 = createDiv('this is the child');
794 | * div0.child(div1); // use p5.Element
795 | *
796 | *
797 | * var div0 = createDiv('this is the parent');
798 | * var div1 = createDiv('this is the child');
799 | * div1.id('apples');
800 | * div0.child('apples'); // use id
801 | *
802 | *
803 | * var div0 = createDiv('this is the parent');
804 | * var elt = document.getElementById('myChildDiv');
805 | * div0.child(elt); // use element from page
806 | *
807 | */
808 | p5.Element.prototype.child = function(c) {
809 | if (typeof c === 'string') {
810 | c = document.getElementById(c);
811 | } else if (c instanceof p5.Element) {
812 | c = c.elt;
813 | }
814 | this.elt.appendChild(c);
815 | return this;
816 | };
817 |
818 |
819 | /**
820 | *
821 | * If an argument is given, sets the inner HTML of the element,
822 | * replacing any existing html. If no arguments are given, returns
823 | * the inner HTML of the element.
824 | *
825 | * @for p5.Element
826 | * @method html
827 | * @param {String} [html] the HTML to be placed inside the element
828 | * @return {Object/p5.Element|String}
829 | */
830 | p5.Element.prototype.html = function(html) {
831 | if (typeof html !== 'undefined') {
832 | this.elt.innerHTML = html;
833 | return this;
834 | } else {
835 | return this.elt.innerHTML;
836 | }
837 | };
838 |
839 | /**
840 | *
841 | * Sets the position of the element relative to (0, 0) of the
842 | * window. Essentially, sets position:absolute and left and top
843 | * properties of style. If no arguments given returns the x and y position
844 | * of the element in an object.
845 | *
846 | * @method position
847 | * @param {Number} [x] x-position relative to upper left of window
848 | * @param {Number} [y] y-position relative to upper left of window
849 | * @return {Object/p5.Element}
850 | * @example
851 | *
852 | * function setup() {
853 | * var cnv = createCanvas(100, 100);
854 | * // positions canvas 50px to the right and 100px
855 | * // below upper left corner of the window
856 | * cnv.position(50, 100);
857 | * }
858 | *
859 | */
860 | p5.Element.prototype.position = function() {
861 | if (arguments.length === 0){
862 | return { 'x' : this.elt.offsetLeft , 'y' : this.elt.offsetTop };
863 | }else{
864 | this.elt.style.position = 'absolute';
865 | this.elt.style.left = arguments[0]+'px';
866 | this.elt.style.top = arguments[1]+'px';
867 | this.x = arguments[0];
868 | this.y = arguments[1];
869 | return this;
870 | }
871 | };
872 |
873 | /**
874 | * Translates an element with css transforms in either 2d (if 2 arguments given)
875 | * or 3d (if 3 arguments given) space.
876 | * @method translate
877 | * @param {Number} x x-position in px
878 | * @param {Number} y y-position in px
879 | * @param {Number} [z] z-position in px
880 | * @param {Number} [perspective] sets the perspective of the parent element in px,
881 | * default value set to 1000px
882 | * @return {Object/p5.Element}
883 | * @example
884 | *
885 | * function setup() {
886 | * createCanvas(100,100);
887 | * //translates canvas 50px down
888 | * select('canvas').translate(0,50);
889 | * }
890 | *
891 | */
892 | p5.Element.prototype.translate = function(){
893 | this.elt.style.position = 'absolute';
894 | if (arguments.length === 2){
895 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
896 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
897 | this.elt.style.transform = 'translate('+arguments[0]+'px, '+arguments[1]+'px)';
898 | this.elt.style.transform += style;
899 | }else if (arguments.length === 3){
900 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
901 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
902 | this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
903 | this.elt.style.transform += style;
904 | this.elt.parentElement.style.perspective = '1000px';
905 | }else if (arguments.length === 4){
906 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
907 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
908 | this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
909 | this.elt.style.transform += style;
910 | this.elt.parentElement.style.perspective = arguments[3]+'px';
911 | }
912 | return this;
913 | };
914 |
915 | /**
916 | * Rotates an element with css transforms in either 2d (if 2 arguments given)
917 | * or 3d (if 3 arguments given) space.
918 | * @method rotate
919 | * @param {Number} x amount of degrees to rotate the element along the x-axis in deg
920 | * @param {Number} [y] amount of degrees to rotate the element along the y-axis in deg
921 | * @param {Number} [z] amount of degrees to rotate the element along the z-axis in deg
922 | * @return {Object/p5.Element}
923 | * @example
924 | *
925 | * var x = 0,
926 | * y = 0,
927 | * z = 0;
928 | * function setup(){
929 | * createCanvas(100,100);
930 | * }
931 | * function draw(){
932 | * x+=.5 % 360;
933 | * y+=.5 % 360;
934 | * z+=.5 % 360;
935 | * //rotates the canvas .5deg (degrees) on every axis each frame.
936 | * select('canvas').rotate(x,y,z);
937 | * }
938 | *
939 | */
940 | p5.Element.prototype.rotate = function(){
941 | if (arguments.length === 1){
942 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
943 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
944 | this.elt.style.transform = 'rotate('+arguments[0]+'deg)';
945 | this.elt.style.transform += style;
946 | }else if (arguments.length === 2){
947 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
948 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
949 | this.elt.style.transform = 'rotate('+arguments[0]+'deg, '+arguments[1]+'deg)';
950 | this.elt.style.transform += style;
951 | }else if (arguments.length === 3){
952 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
953 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
954 | this.elt.style.transform = 'rotateX('+arguments[0]+'deg)';
955 | this.elt.style.transform += 'rotateY('+arguments[1]+'deg)';
956 | this.elt.style.transform += 'rotateZ('+arguments[2]+'deg)';
957 | this.elt.style.transform += style;
958 | }
959 | return this;
960 | };
961 |
962 | /**
963 | * Sets the given style (css) property (1st arg) of the element with the
964 | * given value (2nd arg). If a single argument is given, .style()
965 | * returns the value of the given property; however, if the single argument
966 | * is given in css syntax ('text-align:center'), .style() sets the css
967 | * appropriatly. .style() also handles 2d and 3d css transforms. If
968 | * the 1st arg is 'rotate', 'translate', or 'position', the following arguments
969 | * accept Numbers as values. ('translate', 10, 100, 50);
970 | *
971 | * @method style
972 | * @param {String} property property to be set
973 | * @param {String|Number} [value] value to assign to property
974 | * @param {String|Number} [value] value to assign to property (rotate/translate)
975 | * @param {String|Number} [value] value to assign to property (rotate/translate)
976 | * @param {String|Number} [value] value to assign to property (translate)
977 | * @return {String|Object/p5.Element} value of property, if no value is specified
978 | * or p5.Element
979 | * @example
980 | *
981 | * var myDiv = createDiv("I like pandas.");
982 | * myDiv.style("color", "#ff0000");
983 | * myDiv.style("font-size", "18px");
984 | *
985 | */
986 | p5.Element.prototype.style = function(prop, val) {
987 | var self = this;
988 |
989 | if (typeof val === 'undefined') {
990 | if (prop.indexOf(':') === -1) {
991 | var styles = window.getComputedStyle(self.elt);
992 | var style = styles.getPropertyValue(prop);
993 | return style;
994 | } else {
995 | var attrs = prop.split(';');
996 | for (var i = 0; i < attrs.length; i++) {
997 | var parts = attrs[i].split(':');
998 | if (parts[0] && parts[1]) {
999 | this.elt.style[parts[0].trim()] = parts[1].trim();
1000 | }
1001 | }
1002 | }
1003 | } else {
1004 | if (prop === 'rotate'){
1005 | if (arguments.length === 2) {
1006 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1007 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
1008 | this.elt.style.transform = 'rotate(' + arguments[0] + 'deg)';
1009 | this.elt.style.transform += style;
1010 | } else if (arguments.length === 3) {
1011 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1012 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
1013 | this.elt.style.transform = 'rotate(' + arguments[0] + 'deg, ' + arguments[1] + 'deg)';
1014 | this.elt.style.transform += style;
1015 | } else if (arguments.length === 4) {
1016 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1017 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
1018 | this.elt.style.transform = 'rotateX(' + arguments[0] + 'deg)';
1019 | this.elt.style.transform += 'rotateY(' + arguments[1] + 'deg)';
1020 | this.elt.style.transform += 'rotateZ(' + arguments[2] + 'deg)';
1021 | this.elt.style.transform += style;
1022 | }
1023 | } else if (prop === 'translate') {
1024 | if (arguments.length === 3) {
1025 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1026 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
1027 | this.elt.style.transform = 'translate(' + arguments[0] + 'px, ' + arguments[1] + 'px)';
1028 | this.elt.style.transform += style;
1029 | } else if (arguments.length === 4) {
1030 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1031 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
1032 | this.elt.style.transform = 'translate3d(' + arguments[0] + 'px,' + arguments[1] + 'px,' + arguments[2] + 'px)';
1033 | this.elt.style.transform += style;
1034 | this.elt.parentElement.style.perspective = '1000px';
1035 | } else if (arguments.length === 5) {
1036 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1037 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
1038 | this.elt.style.transform = 'translate3d(' + arguments[0] + 'px,' + arguments[1] + 'px,' + arguments[2] + 'px)';
1039 | this.elt.style.transform += style;
1040 | this.elt.parentElement.style.perspective = arguments[3] + 'px';
1041 | }
1042 | } else if (prop === 'position') {
1043 | this.elt.style.left = arguments[1] + 'px';
1044 | this.elt.style.top = arguments[2] + 'px';
1045 | this.x = arguments[1];
1046 | this.y = arguments[2];
1047 | } else {
1048 | this.elt.style[prop] = val;
1049 | if (prop === 'width' || prop === 'height' || prop === 'left' || prop === 'top') {
1050 | var numVal = val.replace(/\D+/g, '');
1051 | this[prop] = parseInt(numVal, 10);
1052 | }
1053 | }
1054 | }
1055 | return this;
1056 | };
1057 |
1058 |
1059 | /**
1060 | *
1061 | * Adds a new attribute or changes the value of an existing attribute
1062 | * on the specified element. If no value is specified, returns the
1063 | * value of the given attribute, or null if attribute is not set.
1064 | *
1065 | * @method attribute
1066 | * @param {String} attr attribute to set
1067 | * @param {String} [value] value to assign to attribute
1068 | * @return {String|Object/p5.Element} value of attribute, if no value is
1069 | * specified or p5.Element
1070 | * @example
1071 | *
1072 | * var myDiv = createDiv("I like pandas.");
1073 | *myDiv.attribute("align", "center");
1074 | *
1075 | */
1076 | p5.Element.prototype.attribute = function(attr, value) {
1077 | if (typeof value === 'undefined') {
1078 | return this.elt.getAttribute(attr);
1079 | } else {
1080 | this.elt.setAttribute(attr, value);
1081 | return this;
1082 | }
1083 | };
1084 |
1085 |
1086 | /**
1087 | * Either returns the value of the element if no arguments
1088 | * given, or sets the value of the element.
1089 | *
1090 | * @method value
1091 | * @param {String|Number} [value]
1092 | * @return {String|Object/p5.Element} value of element if no value is specified or p5.Element
1093 | */
1094 | p5.Element.prototype.value = function() {
1095 | if (arguments.length > 0) {
1096 | this.elt.value = arguments[0];
1097 | return this;
1098 | } else {
1099 | if (this.elt.type === 'range') {
1100 | return parseFloat(this.elt.value);
1101 | }
1102 | else return this.elt.value;
1103 | }
1104 | };
1105 |
1106 | /**
1107 | *
1108 | * Shows the current element. Essentially, setting display:block for the style.
1109 | *
1110 | * @method show
1111 | * @return {Object/p5.Element}
1112 | */
1113 | p5.Element.prototype.show = function() {
1114 | this.elt.style.display = 'block';
1115 | return this;
1116 | };
1117 |
1118 | /**
1119 | * Hides the current element. Essentially, setting display:none for the style.
1120 | *
1121 | * @method hide
1122 | * @return {Object/p5.Element}
1123 | */
1124 | p5.Element.prototype.hide = function() {
1125 | this.elt.style.display = 'none';
1126 | return this;
1127 | };
1128 |
1129 | /**
1130 | *
1131 | * Sets the width and height of the element. AUTO can be used to
1132 | * only adjust one dimension. If no arguments given returns the width and height
1133 | * of the element in an object.
1134 | *
1135 | * @method size
1136 | * @param {Number} [w] width of the element
1137 | * @param {Number} [h] height of the element
1138 | * @return {Object/p5.Element}
1139 | */
1140 | p5.Element.prototype.size = function(w, h) {
1141 | if (arguments.length === 0){
1142 | return { 'width' : this.elt.offsetWidth , 'height' : this.elt.offsetHeight };
1143 | }else{
1144 | var aW = w;
1145 | var aH = h;
1146 | var AUTO = p5.prototype.AUTO;
1147 | if (aW !== AUTO || aH !== AUTO) {
1148 | if (aW === AUTO) {
1149 | aW = h * this.width / this.height;
1150 | } else if (aH === AUTO) {
1151 | aH = w * this.height / this.width;
1152 | }
1153 | // set diff for cnv vs normal div
1154 | if (this.elt instanceof HTMLCanvasElement) {
1155 | var j = {};
1156 | var k = this.elt.getContext('2d');
1157 | for (var prop in k) {
1158 | j[prop] = k[prop];
1159 | }
1160 | this.elt.setAttribute('width', aW * this._pInst._pixelDensity);
1161 | this.elt.setAttribute('height', aH * this._pInst._pixelDensity);
1162 | this.elt.setAttribute('style', 'width:' + aW + 'px; height:' + aH + 'px');
1163 | this._pInst.scale(this._pInst._pixelDensity, this._pInst._pixelDensity);
1164 | for (var prop in j) {
1165 | this.elt.getContext('2d')[prop] = j[prop];
1166 | }
1167 | } else {
1168 | this.elt.style.width = aW+'px';
1169 | this.elt.style.height = aH+'px';
1170 | this.elt.width = aW;
1171 | this.elt.height = aH;
1172 | this.width = aW;
1173 | this.height = aH;
1174 | }
1175 |
1176 | this.width = this.elt.offsetWidth;
1177 | this.height = this.elt.offsetHeight;
1178 |
1179 | if (this._pInst) { // main canvas associated with p5 instance
1180 | if (this._pInst._curElement.elt === this.elt) {
1181 | this._pInst._setProperty('width', this.elt.offsetWidth);
1182 | this._pInst._setProperty('height', this.elt.offsetHeight);
1183 | }
1184 | }
1185 | }
1186 | return this;
1187 | }
1188 | };
1189 |
1190 | /**
1191 | * Removes the element and deregisters all listeners.
1192 | * @method remove
1193 | * @example
1194 | *
1195 | * var myDiv = createDiv('this is some text');
1196 | * myDiv.remove();
1197 | *
1198 | */
1199 | p5.Element.prototype.remove = function() {
1200 | // deregister events
1201 | for (var ev in this._events) {
1202 | this.elt.removeEventListener(ev, this._events[ev]);
1203 | }
1204 | if (this.elt.parentNode) {
1205 | this.elt.parentNode.removeChild(this.elt);
1206 | }
1207 | delete(this);
1208 | };
1209 |
1210 |
1211 |
1212 | // =============================================================================
1213 | // p5.MediaElement additions
1214 | // =============================================================================
1215 |
1216 |
1217 | /**
1218 | * Extends p5.Element to handle audio and video. In addition to the methods
1219 | * of p5.Element, it also contains methods for controlling media. It is not
1220 | * called directly, but p5.MediaElements are created by calling createVideo,
1221 | * createAudio, and createCapture.
1222 | *
1223 | * @class p5.MediaElement
1224 | * @constructor
1225 | * @param {String} elt DOM node that is wrapped
1226 | * @param {Object} [pInst] pointer to p5 instance
1227 | */
1228 | p5.MediaElement = function(elt, pInst) {
1229 | p5.Element.call(this, elt, pInst);
1230 |
1231 |
1232 | this._prevTime = 0;
1233 | this._cueIDCounter = 0;
1234 | this._cues = [];
1235 | this.pixelDensity = 1;
1236 |
1237 | };
1238 | p5.MediaElement.prototype = Object.create(p5.Element.prototype);
1239 |
1240 |
1241 |
1242 |
1243 | /**
1244 | * Play an HTML5 media element.
1245 | *
1246 | * @method play
1247 | * @return {Object/p5.Element}
1248 | */
1249 | p5.MediaElement.prototype.play = function() {
1250 | if (this.elt.currentTime === this.elt.duration) {
1251 | this.elt.currentTime = 0;
1252 | }
1253 |
1254 | if (this.elt.readyState > 1) {
1255 | this.elt.play();
1256 | } else {
1257 | // in Chrome, playback cannot resume after being stopped and must reload
1258 | this.elt.load();
1259 | this.elt.play();
1260 | }
1261 | return this;
1262 | };
1263 |
1264 | /**
1265 | * Stops an HTML5 media element (sets current time to zero).
1266 | *
1267 | * @method stop
1268 | * @return {Object/p5.Element}
1269 | */
1270 | p5.MediaElement.prototype.stop = function() {
1271 | this.elt.pause();
1272 | this.elt.currentTime = 0;
1273 | return this;
1274 | };
1275 |
1276 | /**
1277 | * Pauses an HTML5 media element.
1278 | *
1279 | * @method pause
1280 | * @return {Object/p5.Element}
1281 | */
1282 | p5.MediaElement.prototype.pause = function() {
1283 | this.elt.pause();
1284 | return this;
1285 | };
1286 |
1287 | /**
1288 | * Set 'loop' to true for an HTML5 media element, and starts playing.
1289 | *
1290 | * @method loop
1291 | * @return {Object/p5.Element}
1292 | */
1293 | p5.MediaElement.prototype.loop = function() {
1294 | this.elt.setAttribute('loop', true);
1295 | this.play();
1296 | return this;
1297 | };
1298 | /**
1299 | * Set 'loop' to false for an HTML5 media element. Element will stop
1300 | * when it reaches the end.
1301 | *
1302 | * @method noLoop
1303 | * @return {Object/p5.Element}
1304 | */
1305 | p5.MediaElement.prototype.noLoop = function() {
1306 | this.elt.setAttribute('loop', false);
1307 | return this;
1308 | };
1309 |
1310 |
1311 | /**
1312 | * Set HTML5 media element to autoplay or not.
1313 | *
1314 | * @method autoplay
1315 | * @param {Boolean} autoplay whether the element should autoplay
1316 | * @return {Object/p5.Element}
1317 | */
1318 | p5.MediaElement.prototype.autoplay = function(val) {
1319 | this.elt.setAttribute('autoplay', val);
1320 | return this;
1321 | };
1322 |
1323 | /**
1324 | * Sets volume for this HTML5 media element. If no argument is given,
1325 | * returns the current volume.
1326 | *
1327 | * @param {Number} [val] volume between 0.0 and 1.0
1328 | * @return {Number|p5.MediaElement} current volume or p5.MediaElement
1329 | * @method volume
1330 | */
1331 | p5.MediaElement.prototype.volume = function(val) {
1332 | if (typeof val === 'undefined') {
1333 | return this.elt.volume;
1334 | } else {
1335 | this.elt.volume = val;
1336 | }
1337 | };
1338 |
1339 | /**
1340 | * If no arguments are given, returns the current time of the elmeent.
1341 | * If an argument is given the current time of the element is set to it.
1342 | *
1343 | * @method time
1344 | * @param {Number} [time] time to jump to (in seconds)
1345 | * @return {Number|Object/p5.MediaElement} current time (in seconds)
1346 | * or p5.MediaElement
1347 | */
1348 | p5.MediaElement.prototype.time = function(val) {
1349 | if (typeof val === 'undefined') {
1350 | return this.elt.currentTime;
1351 | } else {
1352 | this.elt.currentTime = val;
1353 | }
1354 | };
1355 |
1356 | /**
1357 | * Returns the duration of the HTML5 media element.
1358 | *
1359 | * @method duration
1360 | * @return {Number} duration
1361 | */
1362 | p5.MediaElement.prototype.duration = function() {
1363 | return this.elt.duration;
1364 | };
1365 | p5.MediaElement.prototype.pixels = [];
1366 | p5.MediaElement.prototype.loadPixels = function() {
1367 | if (this.loadedmetadata) { // wait for metadata for w/h
1368 | if (!this.canvas) {
1369 | this.canvas = document.createElement('canvas');
1370 | this.canvas.width = this.width;
1371 | this.canvas.height = this.height;
1372 | this.drawingContext = this.canvas.getContext('2d');
1373 | }
1374 | this.drawingContext.drawImage(this.elt, 0, 0, this.width, this.height);
1375 | p5.Renderer2D.prototype.loadPixels.call(this);
1376 | }
1377 | return this;
1378 | }
1379 | p5.MediaElement.prototype.updatePixels = function(x, y, w, h){
1380 | if (this.loadedmetadata) { // wait for metadata
1381 | p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h);
1382 | }
1383 | return this;
1384 | }
1385 | p5.MediaElement.prototype.get = function(x, y, w, h){
1386 | if (this.loadedmetadata) { // wait for metadata
1387 | return p5.Renderer2D.prototype.get.call(this, x, y, w, h);
1388 | } else return [0, 0, 0, 255];
1389 | };
1390 | p5.MediaElement.prototype.set = function(x, y, imgOrCol){
1391 | if (this.loadedmetadata) { // wait for metadata
1392 | p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol);
1393 | }
1394 | };
1395 |
1396 | /*** CONNECT TO WEB AUDIO API / p5.sound.js ***/
1397 |
1398 | /**
1399 | * Send the audio output of this element to a specified audioNode or
1400 | * p5.sound object. If no element is provided, connects to p5's master
1401 | * output. That connection is established when this method is first called.
1402 | * All connections are removed by the .disconnect() method.
1403 | *
1404 | * This method is meant to be used with the p5.sound.js addon library.
1405 | *
1406 | * @method connect
1407 | * @param {AudioNode|p5.sound object} audioNode AudioNode from the Web Audio API,
1408 | * or an object from the p5.sound library
1409 | */
1410 | p5.MediaElement.prototype.connect = function(obj) {
1411 | var audioContext, masterOutput;
1412 |
1413 | // if p5.sound exists, same audio context
1414 | if (typeof p5.prototype.getAudioContext === 'function') {
1415 | audioContext = p5.prototype.getAudioContext();
1416 | masterOutput = p5.soundOut.input;
1417 | } else {
1418 | try {
1419 | audioContext = obj.context;
1420 | masterOutput = audioContext.destination
1421 | } catch(e) {
1422 | throw 'connect() is meant to be used with Web Audio API or p5.sound.js'
1423 | }
1424 | }
1425 |
1426 | // create a Web Audio MediaElementAudioSourceNode if none already exists
1427 | if (!this.audioSourceNode) {
1428 | this.audioSourceNode = audioContext.createMediaElementSource(this.elt);
1429 |
1430 | // connect to master output when this method is first called
1431 | this.audioSourceNode.connect(masterOutput);
1432 | }
1433 |
1434 | // connect to object if provided
1435 | if (obj) {
1436 | if (obj.input) {
1437 | this.audioSourceNode.connect(obj.input);
1438 | } else {
1439 | this.audioSourceNode.connect(obj);
1440 | }
1441 | }
1442 |
1443 | // otherwise connect to master output of p5.sound / AudioContext
1444 | else {
1445 | this.audioSourceNode.connect(masterOutput);
1446 | }
1447 |
1448 | };
1449 |
1450 | /**
1451 | * Disconnect all Web Audio routing, including to master output.
1452 | * This is useful if you want to re-route the output through
1453 | * audio effects, for example.
1454 | *
1455 | * @method disconnect
1456 | */
1457 | p5.MediaElement.prototype.disconnect = function() {
1458 | if (this.audioSourceNode) {
1459 | this.audioSourceNode.disconnect();
1460 | } else {
1461 | throw 'nothing to disconnect';
1462 | }
1463 | };
1464 |
1465 |
1466 | /*** SHOW / HIDE CONTROLS ***/
1467 |
1468 | /**
1469 | * Show the default MediaElement controls, as determined by the web browser.
1470 | *
1471 | * @method showControls
1472 | */
1473 | p5.MediaElement.prototype.showControls = function() {
1474 | // must set style for the element to show on the page
1475 | this.elt.style['text-align'] = 'inherit';
1476 | this.elt.controls = true;
1477 | };
1478 |
1479 | /**
1480 | * Hide the default mediaElement controls.
1481 | *
1482 | * @method hideControls
1483 | */
1484 | p5.MediaElement.prototype.hideControls = function() {
1485 | this.elt.controls = false;
1486 | };
1487 |
1488 |
1489 | /*** SCHEDULE EVENTS ***/
1490 |
1491 | /**
1492 | * Schedule events to trigger every time a MediaElement
1493 | * (audio/video) reaches a playback cue point.
1494 | *
1495 | * Accepts a callback function, a time (in seconds) at which to trigger
1496 | * the callback, and an optional parameter for the callback.
1497 | *
1498 | * Time will be passed as the first parameter to the callback function,
1499 | * and param will be the second parameter.
1500 | *
1501 | *
1502 | * @method addCue
1503 | * @param {Number} time Time in seconds, relative to this media
1504 | * element's playback. For example, to trigger
1505 | * an event every time playback reaches two
1506 | * seconds, pass in the number 2. This will be
1507 | * passed as the first parameter to
1508 | * the callback function.
1509 | * @param {Function} callback Name of a function that will be
1510 | * called at the given time. The callback will
1511 | * receive time and (optionally) param as its
1512 | * two parameters.
1513 | * @param {Object} [value] An object to be passed as the
1514 | * second parameter to the
1515 | * callback function.
1516 | * @return {Number} id ID of this cue,
1517 | * useful for removeCue(id)
1518 | * @example
1519 | *
1520 | * function setup() {
1521 | * background(255,255,255);
1522 | *
1523 | * audioEl = createAudio('assets/beat.mp3');
1524 | * audioEl.showControls();
1525 | *
1526 | * // schedule three calls to changeBackground
1527 | * audioEl.addCue(0.5, changeBackground, color(255,0,0) );
1528 | * audioEl.addCue(1.0, changeBackground, color(0,255,0) );
1529 | * audioEl.addCue(2.5, changeBackground, color(0,0,255) );
1530 | * audioEl.addCue(3.0, changeBackground, color(0,255,255) );
1531 | * audioEl.addCue(4.2, changeBackground, color(255,255,0) );
1532 | * audioEl.addCue(5.0, changeBackground, color(255,255,0) );
1533 | * }
1534 | *
1535 | * function changeBackground(val) {
1536 | * background(val);
1537 | * }
1538 | *
1539 | */
1540 | p5.MediaElement.prototype.addCue = function(time, callback, val) {
1541 | var id = this._cueIDCounter++;
1542 |
1543 | var cue = new Cue(callback, time, id, val);
1544 | this._cues.push(cue);
1545 |
1546 | if (!this.elt.ontimeupdate) {
1547 | this.elt.ontimeupdate = this._onTimeUpdate.bind(this);
1548 | }
1549 |
1550 | return id;
1551 | };
1552 |
1553 | /**
1554 | * Remove a callback based on its ID. The ID is returned by the
1555 | * addCue method.
1556 | *
1557 | * @method removeCue
1558 | * @param {Number} id ID of the cue, as returned by addCue
1559 | */
1560 | p5.MediaElement.prototype.removeCue = function(id) {
1561 | for (var i = 0; i < this._cues.length; i++) {
1562 | var cue = this._cues[i];
1563 | if (cue.id === id) {
1564 | this.cues.splice(i, 1);
1565 | }
1566 | }
1567 |
1568 | if (this._cues.length === 0) {
1569 | this.elt.ontimeupdate = null
1570 | }
1571 | };
1572 |
1573 | /**
1574 | * Remove all of the callbacks that had originally been scheduled
1575 | * via the addCue method.
1576 | *
1577 | * @method clearCues
1578 | */
1579 | p5.MediaElement.prototype.clearCues = function() {
1580 | this._cues = [];
1581 | this.elt.ontimeupdate = null;
1582 | };
1583 |
1584 | // private method that checks for cues to be fired if events
1585 | // have been scheduled using addCue(callback, time).
1586 | p5.MediaElement.prototype._onTimeUpdate = function() {
1587 | var playbackTime = this.time();
1588 |
1589 | for (var i = 0 ; i < this._cues.length; i++) {
1590 | var callbackTime = this._cues[i].time;
1591 | var val = this._cues[i].val;
1592 |
1593 |
1594 | if (this._prevTime < callbackTime && callbackTime <= playbackTime) {
1595 |
1596 | // pass the scheduled callbackTime as parameter to the callback
1597 | this._cues[i].callback(val);
1598 | }
1599 |
1600 | }
1601 |
1602 | this._prevTime = playbackTime;
1603 | };
1604 |
1605 |
1606 | // Cue inspired by JavaScript setTimeout, and the
1607 | // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org
1608 | var Cue = function(callback, time, id, val) {
1609 | this.callback = callback;
1610 | this.time = time;
1611 | this.id = id;
1612 | this.val = val;
1613 | };
1614 |
1615 | // =============================================================================
1616 | // p5.File
1617 | // =============================================================================
1618 |
1619 |
1620 | /**
1621 | * Base class for a file
1622 | * Using this for createFileInput
1623 | *
1624 | * @class p5.File
1625 | * @constructor
1626 | * @param {File} file File that is wrapped
1627 | * @param {Object} [pInst] pointer to p5 instance
1628 | */
1629 | p5.File = function(file, pInst) {
1630 | /**
1631 | * Underlying File object. All normal File methods can be called on this.
1632 | *
1633 | * @property file
1634 | */
1635 | this.file = file;
1636 |
1637 | this._pInst = pInst;
1638 |
1639 | // Splitting out the file type into two components
1640 | // This makes determining if image or text etc simpler
1641 | var typeList = file.type.split('/');
1642 | /**
1643 | * File type (image, text, etc.)
1644 | *
1645 | * @property type
1646 | */
1647 | this.type = typeList[0];
1648 | /**
1649 | * File subtype (usually the file extension jpg, png, xml, etc.)
1650 | *
1651 | * @property subtype
1652 | */
1653 | this.subtype = typeList[1];
1654 | /**
1655 | * File name
1656 | *
1657 | * @property name
1658 | */
1659 | this.name = file.name;
1660 | /**
1661 | * File size
1662 | *
1663 | * @property size
1664 | */
1665 | this.size = file.size;
1666 |
1667 | // Data not loaded yet
1668 | this.data = undefined;
1669 | };
1670 |
1671 | }));
1672 |
--------------------------------------------------------------------------------
/mobile-examples/02_touchIsDown/sketch.js:
--------------------------------------------------------------------------------
1 | var bg = 0;
2 | function setup() {
3 | createCanvas(displayWidth, displayHeight);
4 | }
5 |
6 | function draw() {
7 | background(bg);
8 | if (touchIsDown) {
9 | bg = 255;
10 | }
11 | else {
12 | bg = bg - 5;
13 | }
14 | if (bg < 0) {
15 | bg = 0;
16 | }
17 | }
--------------------------------------------------------------------------------
/mobile-examples/03_touch_coords/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 03_touch_coords
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/mobile-examples/03_touch_coords/sketch.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | createCanvas(displayWidth, displayHeight);
3 | rectMode(CENTER);
4 | }
5 |
6 | function draw() {
7 | background(50);
8 | noStroke();
9 | fill(255);
10 | rect(width/2, height/2, touchX, touchY);
11 | }
12 |
13 | function touchMoved() {
14 | // otherwise the display will move around
15 | // with your touch :(
16 | return false;
17 | }
--------------------------------------------------------------------------------
/mobile-examples/04_touch_callbacks/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 04_touch_callbacks
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/mobile-examples/04_touch_callbacks/sketch.js:
--------------------------------------------------------------------------------
1 | var fillEllipse = true;
2 | var bg = 50;
3 | function setup() {
4 | createCanvas(displayWidth, displayHeight);
5 | rectMode(CENTER);
6 | }
7 | function draw() {
8 | background(bg);
9 | if (fillEllipse) {
10 | fill(255);
11 | }
12 | else {
13 | noFill();
14 | }
15 | rect(width/2, height/2, 100, 100);
16 | }
17 | function touchStarted() {
18 | fillEllipse = !fillEllipse;
19 | bg = 128;
20 | }
21 | function touchEnded() {
22 | bg = 50;
23 | }
24 | function touchMoved() {
25 | // otherwise the display will move around
26 | // with your touch :(
27 | return false;
28 | }
--------------------------------------------------------------------------------
/mobile-examples/05_multitouch/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 05_multitouch
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/mobile-examples/05_multitouch/sketch.js:
--------------------------------------------------------------------------------
1 | function setup() {
2 | createCanvas(displayWidth, displayHeight);
3 | }
4 |
5 | function draw() {
6 | background(50);
7 | noStroke();
8 | fill(255, 192);
9 | for (var i = 0; i < touches.length; i++) {
10 | ellipse(touches[i].x, touches[i].y,
11 | 100+sin(i+frameCount*0.1)*50,
12 | 100+sin(i+frameCount*0.1)*50);
13 | }
14 | }
15 |
16 | function touchMoved() {
17 | return false;
18 | }
--------------------------------------------------------------------------------
/mobile-examples/06_rotation/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 06_rotation
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/mobile-examples/06_rotation/libraries/p5.dom.js:
--------------------------------------------------------------------------------
1 | /*! p5.dom.js v0.2.4 October 6, 2015 */
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 | // p5 additions
38 | // =============================================================================
39 |
40 | /**
41 | * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.'
42 | * prefixes to specify an ID or class respectively, and none for a tag) and returns it as
43 | * a p5.Element. If a class or tag name is given with more than 1 element,
44 | * only the first element will be returned.
45 | * The DOM node itself can be accessed with .elt.
46 | * Returns null if none found.
47 | *
48 | * @method select
49 | * @param {String} name id, class, or tag name of element to search for
50 | * @return {Object/p5.Element|Null} p5.Element containing node found
51 | */
52 | p5.prototype.select = function (e) {
53 | var res;
54 | var str;
55 | if (e[0] === '.'){
56 | str = e.slice(1);
57 | res = document.getElementsByClassName(str);
58 | if (res) {
59 | return wrapElement(res[0]);
60 | }else {
61 | return null;
62 | }
63 | }else if (e[0] === '#'){
64 | str = e.slice(1);
65 | res = document.getElementById(str);
66 | if (res) {
67 | return wrapElement(res);
68 | }else {
69 | return null;
70 | }
71 | }else{
72 | res = document.getElementsByTagName(e);
73 | if (res) {
74 | return wrapElement(res[0]);
75 | }else {
76 | return null;
77 | }
78 | }
79 | };
80 |
81 | /**
82 | * Searches the page for elements with the given class or tag name (using the '.' prefix
83 | * to specify a class and no prefix for a tag) and returns them as p5.Elements
84 | * in an array.
85 | * The DOM node itself can be accessed with .elt.
86 | * Returns null if none found.
87 | *
88 | * @method selectAll
89 | * @param {String} name class or tag name of elements to search for
90 | * @return {Array} Array of p5.Elements containing nodes found
91 | */
92 | p5.prototype.selectAll = function (e) {
93 | var arr = [];
94 | var res;
95 | var str;
96 | if (e[0] === '.'){
97 | str = e.slice(1);
98 | res = document.getElementsByClassName(str);
99 | }else {
100 | res = document.getElementsByTagName(e);
101 | }
102 | if (res) {
103 | for (var j = 0; j < res.length; j++) {
104 | var obj = wrapElement(res[j]);
105 | arr.push(obj);
106 | }
107 | }
108 | return arr;
109 | };
110 |
111 | /**
112 | * Helper function for getElement and getElements.
113 | */
114 | function wrapElement(elt) {
115 | if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") {
116 | return new p5.MediaElement(elt);
117 | } else {
118 | return new p5.Element(elt);
119 | }
120 | }
121 |
122 | /**
123 | * Removes all elements created by p5, except any canvas / graphics
124 | * elements created by createCanvas or createGraphics.
125 | * Event handlers are removed, and element is removed from the DOM.
126 | * @method removeElements
127 | * @example
128 | *
129 | * function setup() {
130 | * createCanvas(100, 100);
131 | * createDiv('this is some text');
132 | * createP('this is a paragraph');
133 | * }
134 | * function mousePressed() {
135 | * removeElements(); // this will remove the div and p, not canvas
136 | * }
137 | *
138 | *
139 | */
140 | p5.prototype.removeElements = function (e) {
141 | for (var i=0; i
169 | * var myDiv;
170 | * function setup() {
171 | * myDiv = createDiv('this is some text');
172 | * }
173 | *
174 | */
175 |
176 | /**
177 | * Creates a <p></p> element in the DOM with given inner HTML. Used
178 | * for paragraph length text.
179 | * Appends to the container node if one is specified, otherwise
180 | * appends to body.
181 | *
182 | * @method createP
183 | * @param {String} html inner HTML for element created
184 | * @return {Object/p5.Element} pointer to p5.Element holding created node
185 | * @example
186 | *
187 | * var myP;
188 | * function setup() {
189 | * myP = createP('this is some text');
190 | * }
191 | *
192 | */
193 |
194 | /**
195 | * Creates a <span></span> element in the DOM with given inner HTML.
196 | * Appends to the container node if one is specified, otherwise
197 | * appends to body.
198 | *
199 | * @method createSpan
200 | * @param {String} html inner HTML for element created
201 | * @return {Object/p5.Element} pointer to p5.Element holding created node
202 | * @example
203 | *
204 | * var mySpan;
205 | * function setup() {
206 | * mySpan = createSpan('this is some text');
207 | * }
208 | *
209 | */
210 | var tags = ['div', 'p', 'span'];
211 | tags.forEach(function(tag) {
212 | var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1);
213 | p5.prototype[method] = function(html) {
214 | var elt = document.createElement(tag);
215 | elt.innerHTML = typeof html === undefined ? "" : html;
216 | return addElement(elt, this);
217 | }
218 | });
219 |
220 | /**
221 | * Creates an <img /> element in the DOM with given src and
222 | * alternate text.
223 | * Appends to the container node if one is specified, otherwise
224 | * appends to body.
225 | *
226 | * @method createImg
227 | * @param {String} src src path or url for image
228 | * @param {String} [alt] alternate text to be used if image does not load
229 | * @param {Function} [successCallback] callback to be called once image data is loaded
230 | * @return {Object/p5.Element} pointer to p5.Element holding created node
231 | * @example
232 | *
233 | * var img;
234 | * function setup() {
235 | * img = createImg('http://p5js.org/img/asterisk-01.png');
236 | * }
237 | *
238 | */
239 | p5.prototype.createImg = function() {
240 | var elt = document.createElement('img');
241 | var args = arguments;
242 | var self;
243 | var setAttrs = function(){
244 | self.width = elt.offsetWidth;
245 | self.height = elt.offsetHeight;
246 | if (args.length > 1 && typeof args[1] === 'function'){
247 | self.fn = args[1];
248 | self.fn();
249 | }else if (args.length > 1 && typeof args[2] === 'function'){
250 | self.fn = args[2];
251 | self.fn();
252 | }
253 | };
254 | elt.src = args[0];
255 | if (args.length > 1 && typeof args[1] === 'string'){
256 | elt.alt = args[1];
257 | }
258 | elt.onload = function(){
259 | setAttrs();
260 | }
261 | self = addElement(elt, this);
262 | return self;
263 | };
264 |
265 | /**
266 | * Creates an <a></a> element in the DOM for including a hyperlink.
267 | * Appends to the container node if one is specified, otherwise
268 | * appends to body.
269 | *
270 | * @method createA
271 | * @param {String} href url of page to link to
272 | * @param {String} html inner html of link element to display
273 | * @param {String} [target] target where new link should open,
274 | * could be _blank, _self, _parent, _top.
275 | * @return {Object/p5.Element} pointer to p5.Element holding created node
276 | * @example
277 | *
278 | * var myLink;
279 | * function setup() {
280 | * myLink = createA('http://p5js.org/', 'this is a link');
281 | * }
282 | *
283 | */
284 | p5.prototype.createA = function(href, html, target) {
285 | var elt = document.createElement('a');
286 | elt.href = href;
287 | elt.innerHTML = html;
288 | if (target) elt.target = target;
289 | return addElement(elt, this);
290 | };
291 |
292 | /** INPUT **/
293 |
294 |
295 | /**
296 | * Creates a slider <input></input> element in the DOM.
297 | * Use .size() to set the display length of the slider.
298 | * Appends to the container node if one is specified, otherwise
299 | * appends to body.
300 | *
301 | * @method createSlider
302 | * @param {Number} min minimum value of the slider
303 | * @param {Number} max maximum value of the slider
304 | * @param {Number} [value] default value of the slider
305 | * @return {Object/p5.Element} pointer to p5.Element holding created node
306 | * @example
307 | *
308 | * var slider;
309 | * function setup() {
310 | * slider = createSlider(0, 255, 100);
311 | * slider.position(10, 10);
312 | * slider.style('width', '80px');
313 | * }
314 | *
315 | * function draw() {
316 | * var val = slider.value();
317 | * background(val);
318 | * }
319 | *
320 | */
321 | p5.prototype.createSlider = function(min, max, value, step) {
322 | var elt = document.createElement('input');
323 | elt.type = 'range';
324 | elt.min = min;
325 | elt.max = max;
326 | if (step) elt.step = step;
327 | if (typeof(value) === "number") elt.value = value;
328 | return addElement(elt, this);
329 | };
330 |
331 | /**
332 | * Creates a <button></button> element in the DOM.
333 | * Use .size() to set the display size of the button.
334 | * Use .mousePressed() to specify behavior on press.
335 | * Appends to the container node if one is specified, otherwise
336 | * appends to body.
337 | *
338 | * @method createButton
339 | * @param {String} label label displayed on the button
340 | * @param {String} [value] value of the button
341 | * @return {Object/p5.Element} pointer to p5.Element holding created node
342 | * @example
343 | *
344 | * var button;
345 | * function setup() {
346 | * createCanvas(100, 100);
347 | * background(0);
348 | * button = createButton('click me');
349 | * button.position(19, 19);
350 | * button.mousePressed(changeBG);
351 | * }
352 | *
353 | * function changeBG() {
354 | * var val = random(255);
355 | * background(val);
356 | * }
357 | *
358 | */
359 | p5.prototype.createButton = function(label, value) {
360 | var elt = document.createElement('button');
361 | elt.innerHTML = label;
362 | elt.value = value;
363 | if (value) elt.value = value;
364 | return addElement(elt, this);
365 | };
366 |
367 | /**
368 | * Creates a checkbox <input></input> element in the DOM.
369 | *
370 | * @method createCheckbox
371 | * @param {String} [label] label displayed after checkbox
372 | * @param {boolean} [value] value of the checkbox; checked is true, unchecked is false. Unchecked if no value given
373 | * @return {Object/p5.Element} pointer to p5.Element holding created node
374 | */
375 | p5.prototype.createCheckbox = function() {
376 | var elt = document.createElement('input');
377 | elt.type = 'checkbox';
378 | //checkbox must be wrapped in p5.Element before label so that label appears after
379 | var self = addElement(elt, this);
380 | self.checked = function(){
381 | if (arguments.length === 0){
382 | return self.elt.checked;
383 | }else if(arguments[0]){
384 | self.elt.checked = true;
385 | }else{
386 | self.elt.checked = false;
387 | }
388 | return self;
389 | };
390 | this.value = function(val){
391 | self.value = val;
392 | return this;
393 | };
394 | if (arguments[0]){
395 | var ran = Math.random().toString(36).slice(2);
396 | var label = document.createElement('label');
397 | elt.setAttribute('id', ran);
398 | label.htmlFor = ran;
399 | self.value(arguments[0]);
400 | label.appendChild(document.createTextNode(arguments[0]));
401 | addElement(label, this);
402 | }
403 | if (arguments[1]){
404 | elt.checked = true;
405 | }
406 | return self;
407 | };
408 |
409 | /**
410 | * Creates a dropdown menu <select></select> element in the DOM.
411 | * @method createSelect
412 | * @param {boolean} [multiple] [true if dropdown should support multiple selections]
413 | * @return {Object/p5.Element} pointer to p5.Element holding created node
414 | */
415 | p5.prototype.createSelect = function(mult) {
416 | var elt = document.createElement('select');
417 | if (mult){
418 | elt.setAttribute('multiple', 'true');
419 | }
420 | var self = addElement(elt, this);
421 | self.option = function(name, value){
422 | var opt = document.createElement('option');
423 | opt.innerHTML = name;
424 | if (arguments.length > 1)
425 | opt.value = value;
426 | else
427 | opt.value = name;
428 | elt.appendChild(opt);
429 | };
430 | self.selected = function(value){
431 | var arr = [];
432 | if (arguments.length > 0){
433 | for (var i = 0; i < this.elt.length; i++){
434 | if (value.toString() === this.elt[i].value){
435 | this.elt.selectedIndex = i;
436 | }
437 | }
438 | return this;
439 | }else{
440 | if (mult){
441 | for (var i = 0; i < this.elt.selectedOptions.length; i++){
442 | arr.push(this.elt.selectedOptions[i].value);
443 | }
444 | return arr;
445 | }else{
446 | return this.elt.value;
447 | }
448 | }
449 | };
450 | return self;
451 | };
452 |
453 | /**
454 | * Creates an <input></input> element in the DOM for text input.
455 | * Use .size() to set the display length of the box.
456 | * Appends to the container node if one is specified, otherwise
457 | * appends to body.
458 | *
459 | * @method createInput
460 | * @param {Number} [value] default value of the input box
461 | * @return {Object/p5.Element} pointer to p5.Element holding created node
462 | */
463 | p5.prototype.createInput = function(value) {
464 | var elt = document.createElement('input');
465 | elt.type = 'text';
466 | if (value) elt.value = value;
467 | return addElement(elt, this);
468 | };
469 |
470 | /**
471 | * Creates an <input></input> element in the DOM of type 'file'.
472 | * This allows users to select local files for use in a sketch.
473 | *
474 | * @method createFileInput
475 | * @param {Function} [callback] callback function for when a file loaded
476 | * @param {String} [multiple] optional to allow multiple files selected
477 | * @return {Object/p5.Element} pointer to p5.Element holding created DOM element
478 | */
479 | p5.prototype.createFileInput = function(callback, multiple) {
480 |
481 | // Is the file stuff supported?
482 | if (window.File && window.FileReader && window.FileList && window.Blob) {
483 | // Yup, we're ok and make an input file selector
484 | var elt = document.createElement('input');
485 | elt.type = 'file';
486 |
487 | // If we get a second argument that evaluates to true
488 | // then we are looking for multiple files
489 | if (multiple) {
490 | // Anything gets the job done
491 | elt.multiple = 'multiple';
492 | }
493 |
494 | // Now let's handle when a file was selected
495 | elt.addEventListener('change', handleFileSelect, false);
496 |
497 | // Function to handle when a file is selected
498 | // We're simplifying life and assuming that we always
499 | // want to load every selected file
500 | function handleFileSelect(evt) {
501 | // These are the files
502 | var files = evt.target.files;
503 | // Load each one and trigger a callback
504 | for (var i = 0; i < files.length; i++) {
505 | var f = files[i];
506 | var reader = new FileReader();
507 | reader.onload = makeLoader(f);
508 | function makeLoader(theFile) {
509 | // Making a p5.File object
510 | var p5file = new p5.File(theFile);
511 | return function(e) {
512 | p5file.data = e.target.result;
513 | callback(p5file);
514 | };
515 | };
516 |
517 | // Text or data?
518 | // This should likely be improved
519 | if (f.type.indexOf('text') > -1) {
520 | reader.readAsText(f);
521 | } else {
522 | reader.readAsDataURL(f);
523 | }
524 | }
525 | }
526 | return addElement(elt, this);
527 | } else {
528 | console.log('The File APIs are not fully supported in this browser. Cannot create element.');
529 | }
530 | };
531 |
532 |
533 | /** VIDEO STUFF **/
534 |
535 | function createMedia(pInst, type, src, callback) {
536 | var elt = document.createElement(type);
537 | if (typeof src === 'string') {
538 | src = [src];
539 | }
540 | for (var i=0; ithis
571 | * page for further information about supported formats.
572 | *
573 | * @method createVideo
574 | * @param {String|Array} src path to a video file, or array of paths for
575 | * supporting different browsers
576 | * @param {Object} [callback] callback function to be called upon
577 | * 'canplaythrough' event fire, that is, when the
578 | * browser can play the media, and estimates that
579 | * enough data has been loaded to play the media
580 | * up to its end without having to stop for
581 | * further buffering of content
582 | * @return {Object/p5.Element} pointer to video p5.Element
583 | */
584 | p5.prototype.createVideo = function(src, callback) {
585 | return createMedia(this, 'video', src, callback);
586 | };
587 |
588 | /** AUDIO STUFF **/
589 |
590 | /**
591 | * Creates a hidden HTML5 <audio> element in the DOM for simple audio
592 | * playback. Appends to the container node if one is specified,
593 | * otherwise appends to body. The first parameter
594 | * can be either a single string path to a audio file, or an array of string
595 | * paths to different formats of the same audio. This is useful for ensuring
596 | * that your audio can play across different browsers, as each supports
597 | * different formats. See this
598 | * page for further information about supported formats.
599 | *
600 | * @method createAudio
601 | * @param {String|Array} src path to an audio file, or array of paths for
602 | * supporting different browsers
603 | * @param {Object} [callback] callback function to be called upon
604 | * 'canplaythrough' event fire, that is, when the
605 | * browser can play the media, and estimates that
606 | * enough data has been loaded to play the media
607 | * up to its end without having to stop for
608 | * further buffering of content
609 | * @return {Object/p5.Element} pointer to audio p5.Element
610 | */
611 | p5.prototype.createAudio = function(src, callback) {
612 | return createMedia(this, 'audio', src, callback);
613 | };
614 |
615 |
616 | /** CAMERA STUFF **/
617 |
618 | p5.prototype.VIDEO = 'video';
619 | p5.prototype.AUDIO = 'audio';
620 |
621 | navigator.getUserMedia = navigator.getUserMedia ||
622 | navigator.webkitGetUserMedia ||
623 | navigator.mozGetUserMedia ||
624 | navigator.msGetUserMedia;
625 |
626 | /**
627 | * Creates a new <video> element that contains the audio/video feed
628 | * from a webcam. This can be drawn onto the canvas using video(). More
629 | * specific properties of the stream can be passing in a Constraints object.
630 | * See the
631 | * W3C
632 | * spec for possible properties. Note that not all of these are supported
633 | * by all browsers.
634 | *
635 | * @method createCapture
636 | * @param {String|Constant|Object} type type of capture, either VIDEO or
637 | * AUDIO if none specified, default both,
638 | * or a Constraints boject
639 | * @param {Function} callback function to be called once
640 | * stream has loaded
641 | * @return {Object/p5.Element} capture video p5.Element
642 | * @example
643 | *
644 | * var capture;
645 | *
646 | * function setup() {
647 | * createCanvas(480, 120);
648 | * capture = createCapture(VIDEO);
649 | * }
650 | *
651 | * function draw() {
652 | * image(capture, 0, 0, width, width*capture.height/capture.width);
653 | * filter(INVERT);
654 | * }
655 | *
656 | *
657 | * function setup() {
658 | * createCanvas(480, 120);
659 | * var constraints = {
660 | * video: {
661 | * mandatory: {
662 | * minWidth: 1280,
663 | * minHeight: 720
664 | * },
665 | * optional: [
666 | * { maxFrameRate: 10 }
667 | * ]
668 | * },
669 | * audio: true
670 | * };
671 | * createCapture(constraints, function(stream) {
672 | * console.log(stream);
673 | * });
674 | * }
675 | *
676 | */
677 | p5.prototype.createCapture = function() {
678 | var useVideo = true;
679 | var useAudio = true;
680 | var constraints;
681 | var cb;
682 | for (var i=0; i
792 | * var div0 = createDiv('this is the parent');
793 | * var div1 = createDiv('this is the child');
794 | * div0.child(div1); // use p5.Element
795 | *
796 | *
797 | * var div0 = createDiv('this is the parent');
798 | * var div1 = createDiv('this is the child');
799 | * div1.id('apples');
800 | * div0.child('apples'); // use id
801 | *
802 | *
803 | * var div0 = createDiv('this is the parent');
804 | * var elt = document.getElementById('myChildDiv');
805 | * div0.child(elt); // use element from page
806 | *
807 | */
808 | p5.Element.prototype.child = function(c) {
809 | if (typeof c === 'string') {
810 | c = document.getElementById(c);
811 | } else if (c instanceof p5.Element) {
812 | c = c.elt;
813 | }
814 | this.elt.appendChild(c);
815 | return this;
816 | };
817 |
818 |
819 | /**
820 | *
821 | * If an argument is given, sets the inner HTML of the element,
822 | * replacing any existing html. If no arguments are given, returns
823 | * the inner HTML of the element.
824 | *
825 | * @for p5.Element
826 | * @method html
827 | * @param {String} [html] the HTML to be placed inside the element
828 | * @return {Object/p5.Element|String}
829 | */
830 | p5.Element.prototype.html = function(html) {
831 | if (typeof html !== 'undefined') {
832 | this.elt.innerHTML = html;
833 | return this;
834 | } else {
835 | return this.elt.innerHTML;
836 | }
837 | };
838 |
839 | /**
840 | *
841 | * Sets the position of the element relative to (0, 0) of the
842 | * window. Essentially, sets position:absolute and left and top
843 | * properties of style. If no arguments given returns the x and y position
844 | * of the element in an object.
845 | *
846 | * @method position
847 | * @param {Number} [x] x-position relative to upper left of window
848 | * @param {Number} [y] y-position relative to upper left of window
849 | * @return {Object/p5.Element}
850 | * @example
851 | *
852 | * function setup() {
853 | * var cnv = createCanvas(100, 100);
854 | * // positions canvas 50px to the right and 100px
855 | * // below upper left corner of the window
856 | * cnv.position(50, 100);
857 | * }
858 | *
859 | */
860 | p5.Element.prototype.position = function() {
861 | if (arguments.length === 0){
862 | return { 'x' : this.elt.offsetLeft , 'y' : this.elt.offsetTop };
863 | }else{
864 | this.elt.style.position = 'absolute';
865 | this.elt.style.left = arguments[0]+'px';
866 | this.elt.style.top = arguments[1]+'px';
867 | this.x = arguments[0];
868 | this.y = arguments[1];
869 | return this;
870 | }
871 | };
872 |
873 | /**
874 | * Translates an element with css transforms in either 2d (if 2 arguments given)
875 | * or 3d (if 3 arguments given) space.
876 | * @method translate
877 | * @param {Number} x x-position in px
878 | * @param {Number} y y-position in px
879 | * @param {Number} [z] z-position in px
880 | * @param {Number} [perspective] sets the perspective of the parent element in px,
881 | * default value set to 1000px
882 | * @return {Object/p5.Element}
883 | * @example
884 | *
885 | * function setup() {
886 | * createCanvas(100,100);
887 | * //translates canvas 50px down
888 | * select('canvas').translate(0,50);
889 | * }
890 | *
891 | */
892 | p5.Element.prototype.translate = function(){
893 | this.elt.style.position = 'absolute';
894 | if (arguments.length === 2){
895 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
896 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
897 | this.elt.style.transform = 'translate('+arguments[0]+'px, '+arguments[1]+'px)';
898 | this.elt.style.transform += style;
899 | }else if (arguments.length === 3){
900 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
901 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
902 | this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
903 | this.elt.style.transform += style;
904 | this.elt.parentElement.style.perspective = '1000px';
905 | }else if (arguments.length === 4){
906 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
907 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
908 | this.elt.style.transform = 'translate3d('+arguments[0]+'px,'+arguments[1]+'px,'+arguments[2]+'px)';
909 | this.elt.style.transform += style;
910 | this.elt.parentElement.style.perspective = arguments[3]+'px';
911 | }
912 | return this;
913 | };
914 |
915 | /**
916 | * Rotates an element with css transforms in either 2d (if 2 arguments given)
917 | * or 3d (if 3 arguments given) space.
918 | * @method rotate
919 | * @param {Number} x amount of degrees to rotate the element along the x-axis in deg
920 | * @param {Number} [y] amount of degrees to rotate the element along the y-axis in deg
921 | * @param {Number} [z] amount of degrees to rotate the element along the z-axis in deg
922 | * @return {Object/p5.Element}
923 | * @example
924 | *
925 | * var x = 0,
926 | * y = 0,
927 | * z = 0;
928 | * function setup(){
929 | * createCanvas(100,100);
930 | * }
931 | * function draw(){
932 | * x+=.5 % 360;
933 | * y+=.5 % 360;
934 | * z+=.5 % 360;
935 | * //rotates the canvas .5deg (degrees) on every axis each frame.
936 | * select('canvas').rotate(x,y,z);
937 | * }
938 | *
939 | */
940 | p5.Element.prototype.rotate = function(){
941 | if (arguments.length === 1){
942 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
943 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
944 | this.elt.style.transform = 'rotate('+arguments[0]+'deg)';
945 | this.elt.style.transform += style;
946 | }else if (arguments.length === 2){
947 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
948 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
949 | this.elt.style.transform = 'rotate('+arguments[0]+'deg, '+arguments[1]+'deg)';
950 | this.elt.style.transform += style;
951 | }else if (arguments.length === 3){
952 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
953 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
954 | this.elt.style.transform = 'rotateX('+arguments[0]+'deg)';
955 | this.elt.style.transform += 'rotateY('+arguments[1]+'deg)';
956 | this.elt.style.transform += 'rotateZ('+arguments[2]+'deg)';
957 | this.elt.style.transform += style;
958 | }
959 | return this;
960 | };
961 |
962 | /**
963 | * Sets the given style (css) property (1st arg) of the element with the
964 | * given value (2nd arg). If a single argument is given, .style()
965 | * returns the value of the given property; however, if the single argument
966 | * is given in css syntax ('text-align:center'), .style() sets the css
967 | * appropriatly. .style() also handles 2d and 3d css transforms. If
968 | * the 1st arg is 'rotate', 'translate', or 'position', the following arguments
969 | * accept Numbers as values. ('translate', 10, 100, 50);
970 | *
971 | * @method style
972 | * @param {String} property property to be set
973 | * @param {String|Number} [value] value to assign to property
974 | * @param {String|Number} [value] value to assign to property (rotate/translate)
975 | * @param {String|Number} [value] value to assign to property (rotate/translate)
976 | * @param {String|Number} [value] value to assign to property (translate)
977 | * @return {String|Object/p5.Element} value of property, if no value is specified
978 | * or p5.Element
979 | * @example
980 | *
981 | * var myDiv = createDiv("I like pandas.");
982 | * myDiv.style("color", "#ff0000");
983 | * myDiv.style("font-size", "18px");
984 | *
985 | */
986 | p5.Element.prototype.style = function(prop, val) {
987 | var self = this;
988 |
989 | if (typeof val === 'undefined') {
990 | if (prop.indexOf(':') === -1) {
991 | var styles = window.getComputedStyle(self.elt);
992 | var style = styles.getPropertyValue(prop);
993 | return style;
994 | } else {
995 | var attrs = prop.split(';');
996 | for (var i = 0; i < attrs.length; i++) {
997 | var parts = attrs[i].split(':');
998 | if (parts[0] && parts[1]) {
999 | this.elt.style[parts[0].trim()] = parts[1].trim();
1000 | }
1001 | }
1002 | }
1003 | } else {
1004 | if (prop === 'rotate'){
1005 | if (arguments.length === 2) {
1006 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1007 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
1008 | this.elt.style.transform = 'rotate(' + arguments[0] + 'deg)';
1009 | this.elt.style.transform += style;
1010 | } else if (arguments.length === 3) {
1011 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1012 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
1013 | this.elt.style.transform = 'rotate(' + arguments[0] + 'deg, ' + arguments[1] + 'deg)';
1014 | this.elt.style.transform += style;
1015 | } else if (arguments.length === 4) {
1016 | var style = this.elt.style.transform.replace(/rotate3d\(.*\)/g, '');
1017 | style = style.replace(/rotate[X-Z]?\(.*\)/g, '');
1018 | this.elt.style.transform = 'rotateX(' + arguments[0] + 'deg)';
1019 | this.elt.style.transform += 'rotateY(' + arguments[1] + 'deg)';
1020 | this.elt.style.transform += 'rotateZ(' + arguments[2] + 'deg)';
1021 | this.elt.style.transform += style;
1022 | }
1023 | } else if (prop === 'translate') {
1024 | if (arguments.length === 3) {
1025 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1026 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
1027 | this.elt.style.transform = 'translate(' + arguments[0] + 'px, ' + arguments[1] + 'px)';
1028 | this.elt.style.transform += style;
1029 | } else if (arguments.length === 4) {
1030 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1031 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
1032 | this.elt.style.transform = 'translate3d(' + arguments[0] + 'px,' + arguments[1] + 'px,' + arguments[2] + 'px)';
1033 | this.elt.style.transform += style;
1034 | this.elt.parentElement.style.perspective = '1000px';
1035 | } else if (arguments.length === 5) {
1036 | var style = this.elt.style.transform.replace(/translate3d\(.*\)/g, '');
1037 | style = style.replace(/translate[X-Z]?\(.*\)/g, '');
1038 | this.elt.style.transform = 'translate3d(' + arguments[0] + 'px,' + arguments[1] + 'px,' + arguments[2] + 'px)';
1039 | this.elt.style.transform += style;
1040 | this.elt.parentElement.style.perspective = arguments[3] + 'px';
1041 | }
1042 | } else if (prop === 'position') {
1043 | this.elt.style.left = arguments[1] + 'px';
1044 | this.elt.style.top = arguments[2] + 'px';
1045 | this.x = arguments[1];
1046 | this.y = arguments[2];
1047 | } else {
1048 | this.elt.style[prop] = val;
1049 | if (prop === 'width' || prop === 'height' || prop === 'left' || prop === 'top') {
1050 | var numVal = val.replace(/\D+/g, '');
1051 | this[prop] = parseInt(numVal, 10);
1052 | }
1053 | }
1054 | }
1055 | return this;
1056 | };
1057 |
1058 |
1059 | /**
1060 | *
1061 | * Adds a new attribute or changes the value of an existing attribute
1062 | * on the specified element. If no value is specified, returns the
1063 | * value of the given attribute, or null if attribute is not set.
1064 | *
1065 | * @method attribute
1066 | * @param {String} attr attribute to set
1067 | * @param {String} [value] value to assign to attribute
1068 | * @return {String|Object/p5.Element} value of attribute, if no value is
1069 | * specified or p5.Element
1070 | * @example
1071 | *
1072 | * var myDiv = createDiv("I like pandas.");
1073 | *myDiv.attribute("align", "center");
1074 | *
1075 | */
1076 | p5.Element.prototype.attribute = function(attr, value) {
1077 | if (typeof value === 'undefined') {
1078 | return this.elt.getAttribute(attr);
1079 | } else {
1080 | this.elt.setAttribute(attr, value);
1081 | return this;
1082 | }
1083 | };
1084 |
1085 |
1086 | /**
1087 | * Either returns the value of the element if no arguments
1088 | * given, or sets the value of the element.
1089 | *
1090 | * @method value
1091 | * @param {String|Number} [value]
1092 | * @return {String|Object/p5.Element} value of element if no value is specified or p5.Element
1093 | */
1094 | p5.Element.prototype.value = function() {
1095 | if (arguments.length > 0) {
1096 | this.elt.value = arguments[0];
1097 | return this;
1098 | } else {
1099 | if (this.elt.type === 'range') {
1100 | return parseFloat(this.elt.value);
1101 | }
1102 | else return this.elt.value;
1103 | }
1104 | };
1105 |
1106 | /**
1107 | *
1108 | * Shows the current element. Essentially, setting display:block for the style.
1109 | *
1110 | * @method show
1111 | * @return {Object/p5.Element}
1112 | */
1113 | p5.Element.prototype.show = function() {
1114 | this.elt.style.display = 'block';
1115 | return this;
1116 | };
1117 |
1118 | /**
1119 | * Hides the current element. Essentially, setting display:none for the style.
1120 | *
1121 | * @method hide
1122 | * @return {Object/p5.Element}
1123 | */
1124 | p5.Element.prototype.hide = function() {
1125 | this.elt.style.display = 'none';
1126 | return this;
1127 | };
1128 |
1129 | /**
1130 | *
1131 | * Sets the width and height of the element. AUTO can be used to
1132 | * only adjust one dimension. If no arguments given returns the width and height
1133 | * of the element in an object.
1134 | *
1135 | * @method size
1136 | * @param {Number} [w] width of the element
1137 | * @param {Number} [h] height of the element
1138 | * @return {Object/p5.Element}
1139 | */
1140 | p5.Element.prototype.size = function(w, h) {
1141 | if (arguments.length === 0){
1142 | return { 'width' : this.elt.offsetWidth , 'height' : this.elt.offsetHeight };
1143 | }else{
1144 | var aW = w;
1145 | var aH = h;
1146 | var AUTO = p5.prototype.AUTO;
1147 | if (aW !== AUTO || aH !== AUTO) {
1148 | if (aW === AUTO) {
1149 | aW = h * this.width / this.height;
1150 | } else if (aH === AUTO) {
1151 | aH = w * this.height / this.width;
1152 | }
1153 | // set diff for cnv vs normal div
1154 | if (this.elt instanceof HTMLCanvasElement) {
1155 | var j = {};
1156 | var k = this.elt.getContext('2d');
1157 | for (var prop in k) {
1158 | j[prop] = k[prop];
1159 | }
1160 | this.elt.setAttribute('width', aW * this._pInst._pixelDensity);
1161 | this.elt.setAttribute('height', aH * this._pInst._pixelDensity);
1162 | this.elt.setAttribute('style', 'width:' + aW + 'px; height:' + aH + 'px');
1163 | this._pInst.scale(this._pInst._pixelDensity, this._pInst._pixelDensity);
1164 | for (var prop in j) {
1165 | this.elt.getContext('2d')[prop] = j[prop];
1166 | }
1167 | } else {
1168 | this.elt.style.width = aW+'px';
1169 | this.elt.style.height = aH+'px';
1170 | this.elt.width = aW;
1171 | this.elt.height = aH;
1172 | this.width = aW;
1173 | this.height = aH;
1174 | }
1175 |
1176 | this.width = this.elt.offsetWidth;
1177 | this.height = this.elt.offsetHeight;
1178 |
1179 | if (this._pInst) { // main canvas associated with p5 instance
1180 | if (this._pInst._curElement.elt === this.elt) {
1181 | this._pInst._setProperty('width', this.elt.offsetWidth);
1182 | this._pInst._setProperty('height', this.elt.offsetHeight);
1183 | }
1184 | }
1185 | }
1186 | return this;
1187 | }
1188 | };
1189 |
1190 | /**
1191 | * Removes the element and deregisters all listeners.
1192 | * @method remove
1193 | * @example
1194 | *
1195 | * var myDiv = createDiv('this is some text');
1196 | * myDiv.remove();
1197 | *
1198 | */
1199 | p5.Element.prototype.remove = function() {
1200 | // deregister events
1201 | for (var ev in this._events) {
1202 | this.elt.removeEventListener(ev, this._events[ev]);
1203 | }
1204 | if (this.elt.parentNode) {
1205 | this.elt.parentNode.removeChild(this.elt);
1206 | }
1207 | delete(this);
1208 | };
1209 |
1210 |
1211 |
1212 | // =============================================================================
1213 | // p5.MediaElement additions
1214 | // =============================================================================
1215 |
1216 |
1217 | /**
1218 | * Extends p5.Element to handle audio and video. In addition to the methods
1219 | * of p5.Element, it also contains methods for controlling media. It is not
1220 | * called directly, but p5.MediaElements are created by calling createVideo,
1221 | * createAudio, and createCapture.
1222 | *
1223 | * @class p5.MediaElement
1224 | * @constructor
1225 | * @param {String} elt DOM node that is wrapped
1226 | * @param {Object} [pInst] pointer to p5 instance
1227 | */
1228 | p5.MediaElement = function(elt, pInst) {
1229 | p5.Element.call(this, elt, pInst);
1230 |
1231 |
1232 | this._prevTime = 0;
1233 | this._cueIDCounter = 0;
1234 | this._cues = [];
1235 | this.pixelDensity = 1;
1236 |
1237 | };
1238 | p5.MediaElement.prototype = Object.create(p5.Element.prototype);
1239 |
1240 |
1241 |
1242 |
1243 | /**
1244 | * Play an HTML5 media element.
1245 | *
1246 | * @method play
1247 | * @return {Object/p5.Element}
1248 | */
1249 | p5.MediaElement.prototype.play = function() {
1250 | if (this.elt.currentTime === this.elt.duration) {
1251 | this.elt.currentTime = 0;
1252 | }
1253 |
1254 | if (this.elt.readyState > 1) {
1255 | this.elt.play();
1256 | } else {
1257 | // in Chrome, playback cannot resume after being stopped and must reload
1258 | this.elt.load();
1259 | this.elt.play();
1260 | }
1261 | return this;
1262 | };
1263 |
1264 | /**
1265 | * Stops an HTML5 media element (sets current time to zero).
1266 | *
1267 | * @method stop
1268 | * @return {Object/p5.Element}
1269 | */
1270 | p5.MediaElement.prototype.stop = function() {
1271 | this.elt.pause();
1272 | this.elt.currentTime = 0;
1273 | return this;
1274 | };
1275 |
1276 | /**
1277 | * Pauses an HTML5 media element.
1278 | *
1279 | * @method pause
1280 | * @return {Object/p5.Element}
1281 | */
1282 | p5.MediaElement.prototype.pause = function() {
1283 | this.elt.pause();
1284 | return this;
1285 | };
1286 |
1287 | /**
1288 | * Set 'loop' to true for an HTML5 media element, and starts playing.
1289 | *
1290 | * @method loop
1291 | * @return {Object/p5.Element}
1292 | */
1293 | p5.MediaElement.prototype.loop = function() {
1294 | this.elt.setAttribute('loop', true);
1295 | this.play();
1296 | return this;
1297 | };
1298 | /**
1299 | * Set 'loop' to false for an HTML5 media element. Element will stop
1300 | * when it reaches the end.
1301 | *
1302 | * @method noLoop
1303 | * @return {Object/p5.Element}
1304 | */
1305 | p5.MediaElement.prototype.noLoop = function() {
1306 | this.elt.setAttribute('loop', false);
1307 | return this;
1308 | };
1309 |
1310 |
1311 | /**
1312 | * Set HTML5 media element to autoplay or not.
1313 | *
1314 | * @method autoplay
1315 | * @param {Boolean} autoplay whether the element should autoplay
1316 | * @return {Object/p5.Element}
1317 | */
1318 | p5.MediaElement.prototype.autoplay = function(val) {
1319 | this.elt.setAttribute('autoplay', val);
1320 | return this;
1321 | };
1322 |
1323 | /**
1324 | * Sets volume for this HTML5 media element. If no argument is given,
1325 | * returns the current volume.
1326 | *
1327 | * @param {Number} [val] volume between 0.0 and 1.0
1328 | * @return {Number|p5.MediaElement} current volume or p5.MediaElement
1329 | * @method volume
1330 | */
1331 | p5.MediaElement.prototype.volume = function(val) {
1332 | if (typeof val === 'undefined') {
1333 | return this.elt.volume;
1334 | } else {
1335 | this.elt.volume = val;
1336 | }
1337 | };
1338 |
1339 | /**
1340 | * If no arguments are given, returns the current time of the elmeent.
1341 | * If an argument is given the current time of the element is set to it.
1342 | *
1343 | * @method time
1344 | * @param {Number} [time] time to jump to (in seconds)
1345 | * @return {Number|Object/p5.MediaElement} current time (in seconds)
1346 | * or p5.MediaElement
1347 | */
1348 | p5.MediaElement.prototype.time = function(val) {
1349 | if (typeof val === 'undefined') {
1350 | return this.elt.currentTime;
1351 | } else {
1352 | this.elt.currentTime = val;
1353 | }
1354 | };
1355 |
1356 | /**
1357 | * Returns the duration of the HTML5 media element.
1358 | *
1359 | * @method duration
1360 | * @return {Number} duration
1361 | */
1362 | p5.MediaElement.prototype.duration = function() {
1363 | return this.elt.duration;
1364 | };
1365 | p5.MediaElement.prototype.pixels = [];
1366 | p5.MediaElement.prototype.loadPixels = function() {
1367 | if (this.loadedmetadata) { // wait for metadata for w/h
1368 | if (!this.canvas) {
1369 | this.canvas = document.createElement('canvas');
1370 | this.canvas.width = this.width;
1371 | this.canvas.height = this.height;
1372 | this.drawingContext = this.canvas.getContext('2d');
1373 | }
1374 | this.drawingContext.drawImage(this.elt, 0, 0, this.width, this.height);
1375 | p5.Renderer2D.prototype.loadPixels.call(this);
1376 | }
1377 | return this;
1378 | }
1379 | p5.MediaElement.prototype.updatePixels = function(x, y, w, h){
1380 | if (this.loadedmetadata) { // wait for metadata
1381 | p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h);
1382 | }
1383 | return this;
1384 | }
1385 | p5.MediaElement.prototype.get = function(x, y, w, h){
1386 | if (this.loadedmetadata) { // wait for metadata
1387 | return p5.Renderer2D.prototype.get.call(this, x, y, w, h);
1388 | } else return [0, 0, 0, 255];
1389 | };
1390 | p5.MediaElement.prototype.set = function(x, y, imgOrCol){
1391 | if (this.loadedmetadata) { // wait for metadata
1392 | p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol);
1393 | }
1394 | };
1395 |
1396 | /*** CONNECT TO WEB AUDIO API / p5.sound.js ***/
1397 |
1398 | /**
1399 | * Send the audio output of this element to a specified audioNode or
1400 | * p5.sound object. If no element is provided, connects to p5's master
1401 | * output. That connection is established when this method is first called.
1402 | * All connections are removed by the .disconnect() method.
1403 | *
1404 | * This method is meant to be used with the p5.sound.js addon library.
1405 | *
1406 | * @method connect
1407 | * @param {AudioNode|p5.sound object} audioNode AudioNode from the Web Audio API,
1408 | * or an object from the p5.sound library
1409 | */
1410 | p5.MediaElement.prototype.connect = function(obj) {
1411 | var audioContext, masterOutput;
1412 |
1413 | // if p5.sound exists, same audio context
1414 | if (typeof p5.prototype.getAudioContext === 'function') {
1415 | audioContext = p5.prototype.getAudioContext();
1416 | masterOutput = p5.soundOut.input;
1417 | } else {
1418 | try {
1419 | audioContext = obj.context;
1420 | masterOutput = audioContext.destination
1421 | } catch(e) {
1422 | throw 'connect() is meant to be used with Web Audio API or p5.sound.js'
1423 | }
1424 | }
1425 |
1426 | // create a Web Audio MediaElementAudioSourceNode if none already exists
1427 | if (!this.audioSourceNode) {
1428 | this.audioSourceNode = audioContext.createMediaElementSource(this.elt);
1429 |
1430 | // connect to master output when this method is first called
1431 | this.audioSourceNode.connect(masterOutput);
1432 | }
1433 |
1434 | // connect to object if provided
1435 | if (obj) {
1436 | if (obj.input) {
1437 | this.audioSourceNode.connect(obj.input);
1438 | } else {
1439 | this.audioSourceNode.connect(obj);
1440 | }
1441 | }
1442 |
1443 | // otherwise connect to master output of p5.sound / AudioContext
1444 | else {
1445 | this.audioSourceNode.connect(masterOutput);
1446 | }
1447 |
1448 | };
1449 |
1450 | /**
1451 | * Disconnect all Web Audio routing, including to master output.
1452 | * This is useful if you want to re-route the output through
1453 | * audio effects, for example.
1454 | *
1455 | * @method disconnect
1456 | */
1457 | p5.MediaElement.prototype.disconnect = function() {
1458 | if (this.audioSourceNode) {
1459 | this.audioSourceNode.disconnect();
1460 | } else {
1461 | throw 'nothing to disconnect';
1462 | }
1463 | };
1464 |
1465 |
1466 | /*** SHOW / HIDE CONTROLS ***/
1467 |
1468 | /**
1469 | * Show the default MediaElement controls, as determined by the web browser.
1470 | *
1471 | * @method showControls
1472 | */
1473 | p5.MediaElement.prototype.showControls = function() {
1474 | // must set style for the element to show on the page
1475 | this.elt.style['text-align'] = 'inherit';
1476 | this.elt.controls = true;
1477 | };
1478 |
1479 | /**
1480 | * Hide the default mediaElement controls.
1481 | *
1482 | * @method hideControls
1483 | */
1484 | p5.MediaElement.prototype.hideControls = function() {
1485 | this.elt.controls = false;
1486 | };
1487 |
1488 |
1489 | /*** SCHEDULE EVENTS ***/
1490 |
1491 | /**
1492 | * Schedule events to trigger every time a MediaElement
1493 | * (audio/video) reaches a playback cue point.
1494 | *
1495 | * Accepts a callback function, a time (in seconds) at which to trigger
1496 | * the callback, and an optional parameter for the callback.
1497 | *
1498 | * Time will be passed as the first parameter to the callback function,
1499 | * and param will be the second parameter.
1500 | *
1501 | *
1502 | * @method addCue
1503 | * @param {Number} time Time in seconds, relative to this media
1504 | * element's playback. For example, to trigger
1505 | * an event every time playback reaches two
1506 | * seconds, pass in the number 2. This will be
1507 | * passed as the first parameter to
1508 | * the callback function.
1509 | * @param {Function} callback Name of a function that will be
1510 | * called at the given time. The callback will
1511 | * receive time and (optionally) param as its
1512 | * two parameters.
1513 | * @param {Object} [value] An object to be passed as the
1514 | * second parameter to the
1515 | * callback function.
1516 | * @return {Number} id ID of this cue,
1517 | * useful for removeCue(id)
1518 | * @example
1519 | *
1520 | * function setup() {
1521 | * background(255,255,255);
1522 | *
1523 | * audioEl = createAudio('assets/beat.mp3');
1524 | * audioEl.showControls();
1525 | *
1526 | * // schedule three calls to changeBackground
1527 | * audioEl.addCue(0.5, changeBackground, color(255,0,0) );
1528 | * audioEl.addCue(1.0, changeBackground, color(0,255,0) );
1529 | * audioEl.addCue(2.5, changeBackground, color(0,0,255) );
1530 | * audioEl.addCue(3.0, changeBackground, color(0,255,255) );
1531 | * audioEl.addCue(4.2, changeBackground, color(255,255,0) );
1532 | * audioEl.addCue(5.0, changeBackground, color(255,255,0) );
1533 | * }
1534 | *
1535 | * function changeBackground(val) {
1536 | * background(val);
1537 | * }
1538 | *
1539 | */
1540 | p5.MediaElement.prototype.addCue = function(time, callback, val) {
1541 | var id = this._cueIDCounter++;
1542 |
1543 | var cue = new Cue(callback, time, id, val);
1544 | this._cues.push(cue);
1545 |
1546 | if (!this.elt.ontimeupdate) {
1547 | this.elt.ontimeupdate = this._onTimeUpdate.bind(this);
1548 | }
1549 |
1550 | return id;
1551 | };
1552 |
1553 | /**
1554 | * Remove a callback based on its ID. The ID is returned by the
1555 | * addCue method.
1556 | *
1557 | * @method removeCue
1558 | * @param {Number} id ID of the cue, as returned by addCue
1559 | */
1560 | p5.MediaElement.prototype.removeCue = function(id) {
1561 | for (var i = 0; i < this._cues.length; i++) {
1562 | var cue = this._cues[i];
1563 | if (cue.id === id) {
1564 | this.cues.splice(i, 1);
1565 | }
1566 | }
1567 |
1568 | if (this._cues.length === 0) {
1569 | this.elt.ontimeupdate = null
1570 | }
1571 | };
1572 |
1573 | /**
1574 | * Remove all of the callbacks that had originally been scheduled
1575 | * via the addCue method.
1576 | *
1577 | * @method clearCues
1578 | */
1579 | p5.MediaElement.prototype.clearCues = function() {
1580 | this._cues = [];
1581 | this.elt.ontimeupdate = null;
1582 | };
1583 |
1584 | // private method that checks for cues to be fired if events
1585 | // have been scheduled using addCue(callback, time).
1586 | p5.MediaElement.prototype._onTimeUpdate = function() {
1587 | var playbackTime = this.time();
1588 |
1589 | for (var i = 0 ; i < this._cues.length; i++) {
1590 | var callbackTime = this._cues[i].time;
1591 | var val = this._cues[i].val;
1592 |
1593 |
1594 | if (this._prevTime < callbackTime && callbackTime <= playbackTime) {
1595 |
1596 | // pass the scheduled callbackTime as parameter to the callback
1597 | this._cues[i].callback(val);
1598 | }
1599 |
1600 | }
1601 |
1602 | this._prevTime = playbackTime;
1603 | };
1604 |
1605 |
1606 | // Cue inspired by JavaScript setTimeout, and the
1607 | // Tone.js Transport Timeline Event, MIT License Yotam Mann 2015 tonejs.org
1608 | var Cue = function(callback, time, id, val) {
1609 | this.callback = callback;
1610 | this.time = time;
1611 | this.id = id;
1612 | this.val = val;
1613 | };
1614 |
1615 | // =============================================================================
1616 | // p5.File
1617 | // =============================================================================
1618 |
1619 |
1620 | /**
1621 | * Base class for a file
1622 | * Using this for createFileInput
1623 | *
1624 | * @class p5.File
1625 | * @constructor
1626 | * @param {File} file File that is wrapped
1627 | * @param {Object} [pInst] pointer to p5 instance
1628 | */
1629 | p5.File = function(file, pInst) {
1630 | /**
1631 | * Underlying File object. All normal File methods can be called on this.
1632 | *
1633 | * @property file
1634 | */
1635 | this.file = file;
1636 |
1637 | this._pInst = pInst;
1638 |
1639 | // Splitting out the file type into two components
1640 | // This makes determining if image or text etc simpler
1641 | var typeList = file.type.split('/');
1642 | /**
1643 | * File type (image, text, etc.)
1644 | *
1645 | * @property type
1646 | */
1647 | this.type = typeList[0];
1648 | /**
1649 | * File subtype (usually the file extension jpg, png, xml, etc.)
1650 | *
1651 | * @property subtype
1652 | */
1653 | this.subtype = typeList[1];
1654 | /**
1655 | * File name
1656 | *
1657 | * @property name
1658 | */
1659 | this.name = file.name;
1660 | /**
1661 | * File size
1662 | *
1663 | * @property size
1664 | */
1665 | this.size = file.size;
1666 |
1667 | // Data not loaded yet
1668 | this.data = undefined;
1669 | };
1670 |
1671 | }));
1672 |
--------------------------------------------------------------------------------
/mobile-examples/06_rotation/sketch.js:
--------------------------------------------------------------------------------
1 | var rx = 0;
2 | var ry = 0;
3 | var rz = 0;
4 | function setup() {
5 | createCanvas(displayWidth, displayHeight);
6 | rectMode(CENTER);
7 | setMoveThreshold(0.1);
8 | }
9 |
10 | function draw() {
11 | background(50);
12 | noStroke();
13 | fill(255);
14 | push();
15 | translate(ry, rx);
16 | rotate(rz);
17 | rect(0, 0, 150, 150);
18 | pop();
19 | }
20 |
21 | function deviceMoved() {
22 | rx = map(rotationX, -90, 90, 0, displayHeight);
23 | ry = map(rotationY, -90, 90, 0, displayWidth);
24 | rz = radians(rotationZ);
25 | }
--------------------------------------------------------------------------------
/node-examples/aleph.js:
--------------------------------------------------------------------------------
1 | // a simple javascript re-implementation of david hirmes' "Aleph"
2 | // http://hirmes.com/aleph/
3 | var fs = require('fs');
4 | var rita = require('rita');
5 |
6 | // this line stores whatever you type after "node program.js" on the command
7 | // line in the variable "fname". I'm using it here to let you specify the name
8 | // of the file you want to use on the command-line, instead of hard-coding it
9 | // in the file.
10 | var fname = process.argv[2];
11 | var text = fs.readFileSync(fname, 'utf8');
12 |
13 | // a list of tokens (words) from the text; a corresponding list of
14 | // part-of-speech tags
15 | var tokens = rita.RiTa.tokenize(text);
16 | var tags = rita.RiTa.getPosTags(tokens);
17 |
18 | var whatISaw = [];
19 | for (var i = 0; i < tokens.length; i++) {
20 | if (tags[i] == 'nn') {
21 | whatISaw.push("I saw the " + tokens[i] + ".");
22 | }
23 | }
24 |
25 | console.log(whatISaw.join(" "));
26 |
--------------------------------------------------------------------------------
/node-examples/genesis.txt:
--------------------------------------------------------------------------------
1 | In the beginning God created the heaven and the earth.
2 | And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.
3 | And God said, Let there be light: and there was light.
4 | And God saw the light, that it was good: and God divided the light from the darkness.
5 | And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day.
6 | And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters.
7 | And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so.
8 | And God called the firmament Heaven. And the evening and the morning were the second day.
9 | And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so.
10 | And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good.
11 | And God said, Let the earth bring forth grass, the herb yielding seed, and the fruit tree yielding fruit after his kind, whose seed is in itself, upon the earth: and it was so.
12 | And the earth brought forth grass, and herb yielding seed after his kind, and the tree yielding fruit, whose seed was in itself, after his kind: and God saw that it was good.
13 | And the evening and the morning were the third day.
14 | And God said, Let there be lights in the firmament of the heaven to divide the day from the night; and let them be for signs, and for seasons, and for days, and years:
15 | And let them be for lights in the firmament of the heaven to give light upon the earth: and it was so.
16 | And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: he made the stars also.
17 | And God set them in the firmament of the heaven to give light upon the earth,
18 | And to rule over the day and over the night, and to divide the light from the darkness: and God saw that it was good.
19 | And the evening and the morning were the fourth day.
20 | And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl that may fly above the earth in the open firmament of heaven.
21 | And God created great whales, and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that it was good.
22 | And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth.
23 | And the evening and the morning were the fifth day.
24 | And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so.
25 | And God made the beast of the earth after his kind, and cattle after their kind, and every thing that creepeth upon the earth after his kind: and God saw that it was good.
26 | And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth.
27 | So God created man in his own image, in the image of God created he him; male and female created he them.
28 | And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth.
29 | And God said, Behold, I have given you every herb bearing seed, which is upon the face of all the earth, and every tree, in the which is the fruit of a tree yielding seed; to you it shall be for meat.
30 | And to every beast of the earth, and to every fowl of the air, and to every thing that creepeth upon the earth, wherein there is life, I have given every green herb for meat: and it was so.
31 | And God saw every thing that he had made, and, behold, it was very good. And the evening and the morning were the sixth day.
32 |
--------------------------------------------------------------------------------
/node-examples/hello.js:
--------------------------------------------------------------------------------
1 | var greetings = ["hello", "greetings", "hey there", "hi", "howdy"];
2 | var places = ["city", "country", "world", "solar system", "galaxy"];
3 |
4 | function choice(t) {
5 | return t[Math.floor(Math.random()*t.length)];
6 | }
7 |
8 | for (var i = 0; i < 10; i++) {
9 | console.log(choice(greetings) + ", " + choice(places));
10 | }
11 |
--------------------------------------------------------------------------------
/node-examples/markov-bot.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var rita = require('rita');
3 | var TwitterAPI = require('node-twitter-api');
4 |
5 | // create markov model
6 | var text = fs.readFileSync("genesis.txt", 'utf8');
7 | var markov = rita.RiMarkov(3);
8 | markov.loadText(text);
9 |
10 | // grab keys from the command-line; see notes for instructions on how
11 | // to obtain keys!
12 | var cKey = process.argv[2];
13 | var cSecret = process.argv[3];
14 | var accessToken = process.argv[4];
15 | var tokenSecret = process.argv[5];
16 |
17 | // create a twitter API object
18 | var twitter = TwitterAPI({
19 | consumerKey: cKey,
20 | consumerSecret: cSecret});
21 |
22 | // post the status update. the value for the key "status" in the object below
23 | // will be the content of the post.
24 | twitter.statuses("update",
25 | {"status": markov.generateSentences(1)[0]},
26 | accessToken,
27 | tokenSecret,
28 | function(error, data, response) {
29 | // code in this function will be executed after the request to post
30 | // a status update.
31 | if (error) {
32 | console.log(error);
33 | }
34 | }
35 | );
36 |
--------------------------------------------------------------------------------
/node-examples/markov-server.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var http = require('http');
3 | var rita = require('rita');
4 |
5 | var text = fs.readFileSync("genesis.txt", 'utf8');
6 |
7 | var markov = rita.RiMarkov(3);
8 | markov.loadText(text);
9 |
10 | http.createServer(function(request, response) {
11 | response.writeHead(200, {"Content-Type": "text/plain"});
12 | response.write(markov.generateSentences(1)[0]);
13 | response.end();
14 | }).listen(8888);
15 |
16 | console.log("web server now available at http://127.0.0.1:8888");
17 | console.log("ctrl+C to quit");
18 |
19 |
--------------------------------------------------------------------------------
/node-examples/markov.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var rita = require('rita');
3 |
4 | var text = fs.readFileSync("genesis.txt", 'utf8');
5 |
6 | var markov = rita.RiMarkov(3);
7 | markov.loadText(text);
8 |
9 | for (var i = 0; i < 10; i++) {
10 | console.log(markov.generateSentences(1)[0]);
11 | }
12 |
--------------------------------------------------------------------------------
/node-examples/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-examples",
3 | "version": "1.0.0",
4 | "description": "node examples by Allison Parrish",
5 | "main": "hello.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "node-twitter-api": "^1.6.2",
14 | "rita": "^1.1.21"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/node-examples/word-count.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 |
3 | // read contents of genesis.txt, decode to string with
4 | // utf8 encoding
5 | var text = fs.readFileSync("genesis.txt", "utf8");
6 |
7 | var words = text.split(" ");
8 | console.log(words.length);
9 |
10 |
--------------------------------------------------------------------------------