diff --git a/algFract.js b/algFract.js new file mode 100644 index 0000000..058c5d3 --- /dev/null +++ b/algFract.js @@ -0,0 +1,319 @@ +class Neighbourhood { + constructor(x, y, color) { + this.x = x; + this.y = y; + this.eps = EPSILON; + this.color = color; + } + contain(x, y) { + return Math.abs(x - this.x) <= this.eps && Math.abs(y - this.y) <= this.eps; + } +} + +var Colors = { + Red: [240, 60, 50], + Green: [100, 240, 60], + Blue: [60, 100, 240], + White: [255, 255, 255], + Black: [0, 0, 0] +}; + +function getColor(actualIterations, attractor) { + switch (coloringType) { + case "Classic": + if (fractalType === "Newton Fractal") { + return attractor.color; + } + return actualIterations === 0 ? Colors.Black : Colors.White; + case "Zebra": + return actualIterations % 2 === 0 ? Colors.Black : Colors.White; + case "Rainbow": + var c = HSVtoRGB(maxIterations / actualIterations, 1, + maxIterations / actualIterations % 0.8); + var color = [c.r, c.g, c.b]; + return color; + case "Levels": + var brightness = maxIterations > 1 ? + 255 * actualIterations / (maxIterations - 1) : 0; + var color = []; + for (var i = 0; i < 3; i++) { + color[i] = brightness + } + return color; + default: + return actualIterations === 0 ? Colors.Black : Colors.White; + } +} + +class JuliaSet { + getPointColor(i, j) { + var i0 = i; + var j0 = j; + var i1 = 0; + var j1 = 0; + var k = 0; + while (k < maxIterations) { + if (i0 * i0 + j0 * j0 > 4) + return getColor(k); + i1 = i0 * i0 - j0 * j0 + re; + j1 = 2 * i0 * j0 + im; + i0 = i1; + j0 = j1; + k++; + } + return getColor(0); + } +} + +class MandelbrotSet { + getPointColor(x, y) { + var i0 = 0; + var j0 = 0; + var i1 = 0; + var j1 = 0; + var k = 0; + while (k < maxIterations) { + i1 = i0 * i0 - j0 * j0 + x; + j1 = 2 * i0 * j0 + y; + if (i1 * i1 + j1 * j1 > 4) + return getColor(k); + i0 = i1; + j0 = j1; + k++; + } + return getColor(0); + } +} + +class NewtonFractal { + constructor() { + this.attractors = [ + new Neighbourhood(1, 0, Colors.Red), + new Neighbourhood(-Math.cos(Math.PI / 3), Math.sin(Math.PI / 3), Colors.Blue), + new Neighbourhood(-Math.cos(Math.PI / 3), -Math.sin(Math.PI / 3), Colors.Green) + ]; + } + + nextPoint(p) { + var x = p.x; + var y = p.y; + + return { + x: 2 / 3 * x + 1 / 3 * (x * x - y * y) / Math.pow(x * x + y * y, 2), + y: 2 / 3 * y * (1 - x / Math.pow(x * x + y * y, 2)) + }; + } + + getPointColor(x, y) { + var point = { x: x, y: y }; + for (var i = 0; i < maxIterations; i++) { + for (var j = 0; j < this.attractors.length; j++) { + if (this.attractors[j].contain(point.x, point.y)) { + return getColor(i, this.attractors[j]); + } + } + point = this.nextPoint(point); + } + return Colors.White; + } +} + +const defaultBorder = 2; +var fractalBorder = { + top: -defaultBorder, + bottom: defaultBorder, + left: -defaultBorder, + right: defaultBorder +} + +function resetBorder() { + fractalBorder.top = -defaultBorder; + fractalBorder.bottom = defaultBorder; + fractalBorder.left = -defaultBorder; + fractalBorder.right = defaultBorder; +} + +function getRealCoordinate(i, j) { + return { + x: fractalBorder.left + i * (fractalBorder.right - fractalBorder.left) / (width - 1), + y: fractalBorder.top + j * (fractalBorder.bottom - fractalBorder.top) / (height - 1) + }; +} + +const EPSILON = 0.001; +var im; +var re; + +var NewtonFract = new NewtonFractal(); +var Mandelbrot = new MandelbrotSet(); +var Julia = new JuliaSet(); + +var fractalSelect; +var fractalType; +var coloringSelect; +var iteraionsSlider; +var maxIterations; +var screenshotButton; +var drawButton; +var reSlider; +var imSider; + +function setup() { + createCanvas(600, 600); + pixelDensity(1); + setGUI(); + drawFractal(); +} + +function coloringSelectEvent() { + coloringType = coloringSelect.value(); + drawFractal(); +} + +function fractalTypeSelectEvent() { + fractalType = fractalSelect.value(); + resetBorder(); + drawFractal(); +} + +function resetViewAndDraw() { + resetBorder(); + drawFractal(); +} + +function drawFractal() { + loadPixels(); + maxIterations = iteraionsSlider.value(); + re = reSlider.value(); + im = imSlider.value(); + + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + var coord = getRealCoordinate(x, y); + var color = getFractalPointColor(coord.x, coord.y, coloringType); + drawPixel(x, y, color[0], color[1], color[2]); + } + } + updatePixels(); +} + +function getFractalPointColor(x, y, coloringType) { + switch (fractalType) { + case "Newton Fractal": + return NewtonFract.getPointColor(x, y); + case "Mandelbrot Set": + return Mandelbrot.getPointColor(x, y); + case "Julia Set": + return Julia.getPointColor(x, y); + default: + return NewtonFract.getPointColor(x, y); + } +} + +function drawPixel(x, y, r, g, b) { + pix = (x + y * width) * 4; + pixels[pix + 0] = r; + pixels[pix + 1] = g; + pixels[pix + 2] = b; + pixels[pix + 3] = 255; +} + +function mousePressed() { + //Обработка только тех нажатий, которые произошли на канвасе + if (mouseX > width || mouseY > height) + return; + var halfWidth = Math.abs(fractalBorder.left - fractalBorder.right) / 4; + var realPoint = getRealCoordinate(mouseX, mouseY); + fractalBorder.top = realPoint.y - halfWidth; + fractalBorder.bottom = realPoint.y + halfWidth; + fractalBorder.left = realPoint.x - halfWidth; + fractalBorder.right = realPoint.x + halfWidth; + + console.log(fractalBorder); + drawFractal(); +} + +function takeScreenshot() { + var fractalName = fractalSelect.value(); + saveCanvas(fractalName, 'png'); +} + +function HSVtoRGB(h, s, v) { + var r, g, b, i, f, p, q, t; + if (arguments.length === 1) { + s = h.s, v = h.v, h = h.h; + } + i = Math.floor(h * 6); + f = h * 6 - i; + p = v * (1 - s); + q = v * (1 - f * s); + t = v * (1 - (1 - f) * s); + switch (i % 6) { + case 0: + r = v, g = t, b = p; + break; + case 1: + r = q, g = v, b = p; + break; + case 2: + r = p, g = v, b = t; + break; + case 3: + r = p, g = q, b = v; + break; + case 4: + r = t, g = p, b = v; + break; + case 5: + r = v, g = p, b = q; + break; + } + return { + r: Math.round(r * 255), + g: Math.round(g * 255), + b: Math.round(b * 255) + }; +} + +//Надеюсь сюда никто не посмотрит... +function setGUI() { + drawButton = createButton('Draw'); + drawButton.mousePressed(drawFractal); + drawButton.position(width + 10, 10); + screenshotButton = createButton('Save image'); + screenshotButton.mousePressed(takeScreenshot); + screenshotButton.position(width + 180, 10) + resetViewButton = createButton('Reset view'); + resetViewButton.mousePressed(resetViewAndDraw); + resetViewButton.position(width + 80, 10); + var sl = createP('Max iterations slider'); + sl.position(width + 10, 60); + iteraionsSlider = createSlider(2, 200, 50, 1); + iteraionsSlider.position(width + 10, 100); + maxIterations = iteraionsSlider.value(); + fractalSelect = createSelect(); + fractalSelect.option('Newton Fractal'); + fractalSelect.option('Mandelbrot Set'); + fractalSelect.option('Julia Set'); + fractalSelect.changed(fractalTypeSelectEvent); + fractalSelect.position(width + 10, 40); + fractalType = fractalSelect.value(); + coloringSelect = createSelect(); + coloringSelect.option('Classic'); + coloringSelect.option('Levels'); + coloringSelect.option('Zebra'); + coloringSelect.option('Rainbow'); + coloringSelect.changed(coloringSelectEvent); + coloringSelect.position(width + 150, 40); + coloringType = coloringSelect.value(); + sl = createP('Julia set re im sliders'); + sl.position(width + 10, 120); + + reSlider = createSlider(-1, 1, 0.4, 0.01); + reSlider.position(width + 10, 160); + imSlider = createSlider(-1, 1, -0.3, 0.01); + imSlider.position(width + 10, 190); + + re = reSlider.value(); + im = imSlider.value(); +} \ No newline at end of file diff --git a/index.html b/index.html index 9ddbbf2..61f767a 100644 --- a/index.html +++ b/index.html @@ -1,80 +1,13 @@ - - - - - - + + + + + + - - + + \ No newline at end of file diff --git a/lib/p5.dom.js b/lib/p5.dom.js new file mode 100644 index 0000000..5696d0a --- /dev/null +++ b/lib/p5.dom.js @@ -0,0 +1,2035 @@ +/*! p5.dom.js v0.2.9 March 3, 2016 */ +/** + *

The web is much more than just canvas and p5.dom makes it easy to interact + * with other HTML5 objects, including text, hyperlink, image, input, video, + * audio, and webcam.

+ *

There is a set of creation methods, DOM manipulation methods, and + * an extended p5.Element that supports a range of HTML elements. See the + * + * beyond the canvas tutorial for a full overview of how this addon works. + * + *

Methods and properties shown in black are part of the p5.js core, items in + * blue are part of the p5.dom library. You will need to include an extra file + * in order to access the blue functions. See the + * using a library + * section for information on how to include this library. p5.dom comes with + * p5 complete or you can download the single file + * + * here.

+ *

See tutorial: beyond the canvas + * for more info on how to use this libary. + * + * @module p5.dom + * @submodule p5.dom + * @for p5.dom + * @main + */ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) + define('p5.dom', ['p5'], function (p5) { (factory(p5));}); + else if (typeof exports === 'object') + factory(require('../p5')); + else + factory(root['p5']); +}(this, function (p5) { +// ============================================================================= +// p5 additions +// ============================================================================= + + /** + * Searches the page for an element with the given ID, class, or tag name (using the '#' or '.' + * prefixes to specify an ID or class respectively, and none for a tag) and returns it as + * a p5.Element. If a class or tag name is given with more than 1 element, + * only the first element will be returned. + * The DOM node itself can be accessed with .elt. + * Returns null if none found. You can also specify a container to search within. + * + * @method select + * @param {String} name id, class, or tag name of element to search for + * @param {String} [container] id, p5.Element, or HTML element to search within + * @return {Object/p5.Element|Null} p5.Element containing node found + * @example + *

+ * function setup() { + * createCanvas(100,100); + * //translates canvas 50px down + * select('canvas').position(100, 100); + * } + *
+ *
+ * // these are all valid calls to select() + * var a = select('#moo'); + * var b = select('#blah', '#myContainer'); + * var c = select('#foo', b); + * var d = document.getElementById('beep'); + * var e = select('p', d); + *
+ * + */ + p5.prototype.select = function (e, p) { + var res = null; + var container = getContainer(p); + if (e[0] === '.'){ + e = e.slice(1); + res = container.getElementsByClassName(e); + if (res.length) { + res = res[0]; + } else { + res = null; + } + }else if (e[0] === '#'){ + e = e.slice(1); + res = container.getElementById(e); + }else { + res = container.getElementsByTagName(e); + if (res.length) { + res = res[0]; + } else { + res = null; + } + } + if (res) { + return wrapElement(res); + } else { + return null; + } + }; + + /** + * Searches the page for elements with the given class or tag name (using the '.' prefix + * to specify a class and no prefix for a tag) and returns them as p5.Elements + * in an array. + * The DOM node itself can be accessed with .elt. + * Returns an empty array if none found. + * You can also specify a container to search within. + * + * @method selectAll + * @param {String} name class or tag name of elements to search for + * @param {String} [container] id, p5.Element, or HTML element to search within + * @return {Array} Array of p5.Elements containing nodes found + * @example + *
+ * function setup() { + * createButton('btn'); + * createButton('2nd btn'); + * createButton('3rd btn'); + * var buttons = selectAll('button'); + * + * for (var i = 0; i < buttons.length; i++){ + * buttons[i].size(100,100); + * } + * } + *
+ *
+ * // these are all valid calls to selectAll() + * var a = selectAll('.moo'); + * var b = selectAll('div'); + * var c = selectAll('button', '#myContainer'); + * var d = select('#container'); + * var e = selectAll('p', d); + * var f = document.getElementById('beep'); + * var g = select('.blah', f); + *
+ * + */ + p5.prototype.selectAll = function (e, p) { + var arr = []; + var res; + var container = getContainer(p); + if (e[0] === '.'){ + e = e.slice(1); + res = container.getElementsByClassName(e); + } else { + res = container.getElementsByTagName(e); + } + if (res) { + for (var j = 0; j < res.length; j++) { + var obj = wrapElement(res[j]); + arr.push(obj); + } + } + return arr; + }; + + /** + * Helper function for select and selectAll + */ + function getContainer(p) { + var container = document; + if (typeof p === 'string' && p[0] === '#'){ + p = p.slice(1); + container = document.getElementById(p) || document; + } else if (p instanceof p5.Element){ + container = p.elt; + } else if (p instanceof HTMLElement){ + container = p; + } + return container; + } + + /** + * Helper function for getElement and getElements. + */ + function wrapElement(elt) { + if(elt.tagName === "INPUT" && elt.type === "checkbox") { + var converted = new p5.Element(elt); + converted.checked = function(){ + if (arguments.length === 0){ + return this.elt.checked; + } else if(arguments[0]) { + this.elt.checked = true; + } else { + this.elt.checked = false; + } + return this; + }; + return converted; + } else if (elt.tagName === "VIDEO" || elt.tagName === "AUDIO") { + return new p5.MediaElement(elt); + } else { + return new p5.Element(elt); + } + } + + /** + * Removes all elements created by p5, except any canvas / graphics + * elements created by createCanvas or createGraphics. + * Event handlers are removed, and element is removed from the DOM. + * @method removeElements + * @example + *
+ * function setup() { + * createCanvas(100, 100); + * createDiv('this is some text'); + * createP('this is a paragraph'); + * } + * function mousePressed() { + * removeElements(); // this will remove the div and p, not canvas + * } + *
+ * + */ + p5.prototype.removeElements = function (e) { + for (var i=0; i + * var myDiv; + * function setup() { + * myDiv = createDiv('this is some text'); + * } + * + */ + + /** + * Creates a <p></p> element in the DOM with given inner HTML. Used + * for paragraph length text. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createP + * @param {String} html inner HTML for element created + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var myP; + * function setup() { + * myP = createP('this is some text'); + * } + *
+ */ + + /** + * Creates a <span></span> element in the DOM with given inner HTML. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createSpan + * @param {String} html inner HTML for element created + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var mySpan; + * function setup() { + * mySpan = createSpan('this is some text'); + * } + *
+ */ + var tags = ['div', 'p', 'span']; + tags.forEach(function(tag) { + var method = 'create' + tag.charAt(0).toUpperCase() + tag.slice(1); + p5.prototype[method] = function(html) { + var elt = document.createElement(tag); + elt.innerHTML = typeof html === undefined ? "" : html; + return addElement(elt, this); + } + }); + + /** + * Creates an <img /> element in the DOM with given src and + * alternate text. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createImg + * @param {String} src src path or url for image + * @param {String} [alt] alternate text to be used if image does not load + * @param {Function} [successCallback] callback to be called once image data is loaded + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var img; + * function setup() { + * img = createImg('http://p5js.org/img/asterisk-01.png'); + * } + *
+ */ + p5.prototype.createImg = function() { + var elt = document.createElement('img'); + var args = arguments; + var self; + var setAttrs = function(){ + self.width = elt.offsetWidth; + self.height = elt.offsetHeight; + if (args.length > 1 && typeof args[1] === 'function'){ + self.fn = args[1]; + self.fn(); + }else if (args.length > 1 && typeof args[2] === 'function'){ + self.fn = args[2]; + self.fn(); + } + }; + elt.src = args[0]; + if (args.length > 1 && typeof args[1] === 'string'){ + elt.alt = args[1]; + } + elt.onload = function(){ + setAttrs(); + } + self = addElement(elt, this); + return self; + }; + + /** + * Creates an <a></a> element in the DOM for including a hyperlink. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createA + * @param {String} href url of page to link to + * @param {String} html inner html of link element to display + * @param {String} [target] target where new link should open, + * could be _blank, _self, _parent, _top. + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var myLink; + * function setup() { + * myLink = createA('http://p5js.org/', 'this is a link'); + * } + *
+ */ + p5.prototype.createA = function(href, html, target) { + var elt = document.createElement('a'); + elt.href = href; + elt.innerHTML = html; + if (target) elt.target = target; + return addElement(elt, this); + }; + + /** INPUT **/ + + + /** + * Creates a slider <input></input> element in the DOM. + * Use .size() to set the display length of the slider. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createSlider + * @param {Number} min minimum value of the slider + * @param {Number} max maximum value of the slider + * @param {Number} [value] default value of the slider + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var slider; + * function setup() { + * slider = createSlider(0, 255, 100); + * slider.position(10, 10); + * slider.style('width', '80px'); + * } + * + * function draw() { + * var val = slider.value(); + * background(val); + * } + *
+ */ + p5.prototype.createSlider = function(min, max, value, step) { + var elt = document.createElement('input'); + elt.type = 'range'; + elt.min = min; + elt.max = max; + if (step) elt.step = step; + if (typeof(value) === "number") elt.value = value; + return addElement(elt, this); + }; + + /** + * Creates a <button></button> element in the DOM. + * Use .size() to set the display size of the button. + * Use .mousePressed() to specify behavior on press. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createButton + * @param {String} label label displayed on the button + * @param {String} [value] value of the button + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var button; + * function setup() { + * createCanvas(100, 100); + * background(0); + * button = createButton('click me'); + * button.position(19, 19); + * button.mousePressed(changeBG); + * } + * + * function changeBG() { + * var val = random(255); + * background(val); + * } + *
+ */ + p5.prototype.createButton = function(label, value) { + var elt = document.createElement('button'); + elt.innerHTML = label; + elt.value = value; + if (value) elt.value = value; + return addElement(elt, this); + }; + + /** + * Creates a checkbox <input></input> element in the DOM. + * Calling .checked() on a checkbox returns if it is checked or not + * + * @method createCheckbox + * @param {String} [label] label displayed after checkbox + * @param {boolean} [value] value of the checkbox; checked is true, unchecked is false.Unchecked if no value given + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var checkbox; + * + * function setup() { + * checkbox = createCheckbox('label', false); + * checkbox.changed(myCheckedEvent); + * } + * + * function myCheckedEvent() { + * if (this.checked()) { + * console.log("Unchecking!"); + * } else { + * console.log("Checking!"); + * } + * + *
+ */ + p5.prototype.createCheckbox = function() { + var elt = document.createElement('input'); + elt.type = 'checkbox'; + //checkbox must be wrapped in p5.Element before label so that label appears after + var self = addElement(elt, this); + self.checked = function(){ + if (arguments.length === 0){ + return self.elt.checked; + }else if(arguments[0]){ + self.elt.checked = true; + }else{ + self.elt.checked = false; + } + return self; + }; + this.value = function(val){ + self.value = val; + return this; + }; + if (arguments[0]){ + var ran = Math.random().toString(36).slice(2); + var label = document.createElement('label'); + elt.setAttribute('id', ran); + label.htmlFor = ran; + self.value(arguments[0]); + label.appendChild(document.createTextNode(arguments[0])); + addElement(label, this); + } + if (arguments[1]){ + elt.checked = true; + } + return self; + }; + + /** + * Creates a dropdown menu <select></select> element in the DOM. + * @method createSelect + * @param {boolean} [multiple] [true if dropdown should support multiple selections] + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * var sel; + * + * function setup() { + * textAlign(CENTER); + * background(200); + * sel = createSelect(); + * sel.position(10, 10); + * sel.option('pear'); + * sel.option('kiwi'); + * sel.option('grape'); + * sel.changed(mySelectEvent); + * } + * + * function mySelectEvent() { + * var item = sel.value(); + * background(200); + * text("it's a "+item+"!", 50, 50); + * } + *
+ */ + p5.prototype.createSelect = function(mult) { + var elt = document.createElement('select'); + if (mult){ + elt.setAttribute('multiple', 'true'); + } + var self = addElement(elt, this); + self.option = function(name, value){ + var opt = document.createElement('option'); + opt.innerHTML = name; + if (arguments.length > 1) + opt.value = value; + else + opt.value = name; + elt.appendChild(opt); + }; + self.selected = function(value){ + var arr = []; + if (arguments.length > 0){ + for (var i = 0; i < this.elt.length; i++){ + if (value.toString() === this.elt[i].value){ + this.elt.selectedIndex = i; + } + } + return this; + }else{ + if (mult){ + for (var i = 0; i < this.elt.selectedOptions.length; i++){ + arr.push(this.elt.selectedOptions[i].value); + } + return arr; + }else{ + return this.elt.value; + } + } + }; + return self; + }; + + /** + * Creates a radio button <input></input> element in the DOM. + * + * @method createRadio + * @param {String} [divId] the id and name of the created div and input field respectively + * @return {Object/p5.Element} pointer to p5.Element holding created node + */ + p5.prototype.createRadio = function() { + var radios = document.querySelectorAll("input[type=radio]"); + var count = 0; + if(radios.length > 1){ + console.log(radios,radios[0].name); + var length = radios.length; + var prev=radios[0].name; + var current = radios[1].name; + count=1; + for(var i = 1; i < length; i++ ){ + current = radios[i].name; + if(prev != current){ + count++; + } + prev = current; + } + } + else if (radios.length == 1){ + count = 1; + } + var elt = document.createElement('div'); + var self = addElement(elt, this); + var times = -1; + self.option = function(name, value){ + var opt = document.createElement('input'); + opt.type = 'radio'; + opt.innerHTML = name; + if (arguments.length > 1) + opt.value = value; + else + opt.value = name; + opt.setAttribute('name',"defaultradio"+count); + elt.appendChild(opt); + if (name){ + times++; + var ran = Math.random().toString(36).slice(2); + var label = document.createElement('label'); + opt.setAttribute('id', "defaultradio"+count+"-"+times); + label.htmlFor = "defaultradio"+count+"-"+times; + label.appendChild(document.createTextNode(name)); + elt.appendChild(label); + } + return opt; + }; + self.selected = function(){ + var length = this.elt.childNodes.length; + if(arguments[0]) { + for (var i = 0; i < length; i+=2){ + if(this.elt.childNodes[i].value == arguments[0]) + this.elt.childNodes[i].checked = true; + } + return this; + } else { + for (var i = 0; i < length; i+=2){ + if(this.elt.childNodes[i].checked == true) + return this.elt.childNodes[i].value; + } + } + }; + self.value = function(){ + var length = this.elt.childNodes.length; + if(arguments[0]) { + for (var i = 0; i < length; i+=2){ + if(this.elt.childNodes[i].value == arguments[0]) + this.elt.childNodes[i].checked = true; + } + return this; + } else { + for (var i = 0; i < length; i+=2){ + if(this.elt.childNodes[i].checked == true) + return this.elt.childNodes[i].value; + } + return ""; + } + }; + return self + }; + + /** + * Creates an <input></input> element in the DOM for text input. + * Use .size() to set the display length of the box. + * Appends to the container node if one is specified, otherwise + * appends to body. + * + * @method createInput + * @param {Number} [value] default value of the input box + * @return {Object/p5.Element} pointer to p5.Element holding created node + * @example + *
+ * function setup(){ + * var inp = createInput(''); + * inp.input(myInputEvent); + * } + * + * function myInputEvent(){ + * console.log('you are typing: ', this.value()); + * } + * + *
+ */ + p5.prototype.createInput = function(value) { + var elt = document.createElement('input'); + elt.type = 'text'; + if (value) elt.value = value; + return addElement(elt, this); + }; + + /** + * Creates an <input></input> element in the DOM of type 'file'. + * This allows users to select local files for use in a sketch. + * + * @method createFileInput + * @param {Function} [callback] callback function for when a file loaded + * @param {String} [multiple] optional to allow multiple files selected + * @return {Object/p5.Element} pointer to p5.Element holding created DOM element + */ + p5.prototype.createFileInput = function(callback, multiple) { + + // Is the file stuff supported? + if (window.File && window.FileReader && window.FileList && window.Blob) { + // Yup, we're ok and make an input file selector + var elt = document.createElement('input'); + elt.type = 'file'; + + // If we get a second argument that evaluates to true + // then we are looking for multiple files + if (multiple) { + // Anything gets the job done + elt.multiple = 'multiple'; + } + + // Function to handle when a file is selected + // We're simplifying life and assuming that we always + // want to load every selected file + function handleFileSelect(evt) { + // These are the files + var files = evt.target.files; + // Load each one and trigger a callback + for (var i = 0; i < files.length; i++) { + var f = files[i]; + var reader = new FileReader(); + function makeLoader(theFile) { + // Making a p5.File object + var p5file = new p5.File(theFile); + return function(e) { + p5file.data = e.target.result; + callback(p5file); + }; + }; + reader.onload = makeLoader(f); + + // Text or data? + // This should likely be improved + if (f.type.indexOf('text') > -1) { + reader.readAsText(f); + } else { + reader.readAsDataURL(f); + } + } + } + + // Now let's handle when a file was selected + elt.addEventListener('change', handleFileSelect, false); + return addElement(elt, this); + } else { + console.log('The File APIs are not fully supported in this browser. Cannot create element.'); + } + }; + + + /** VIDEO STUFF **/ + + function createMedia(pInst, type, src, callback) { + var elt = document.createElement(type); + + // allow src to be empty + var src = src || ''; + if (typeof src === 'string') { + src = [src]; + } + for (var i=0; i