+ *
+ * @alt
+ * Left half of canvas light blue and right half light charcoal grey.
+ * Left half of canvas light purple and right half a royal blue.
+ * Left half of canvas salmon pink and the right half white.
+ * Yellow rect in middle right of canvas, with 55 pixel width and height.
+ * Yellow ellipse in top left canvas, black ellipse in bottom right,both 80x80.
+ * Bright fuschia rect in middle of canvas, 60 pixel width and height.
+ * Two bright green rects on opposite sides of the canvas, both 45x80.
+ * Four blue rects in each corner of the canvas, each are 35x35.
+ * Bright sea green rect on left and darker rect on right of canvas, both 45x80.
+ * Dark green rect on left and light green rect on right of canvas, both 45x80.
+ * Dark blue rect on left and light teal rect on right of canvas, both 45x80.
+ * blue rect on left and green on right, both with black outlines & 35x60.
+ * salmon pink rect on left and black on right, both 35x60.
+ * 4 rects, tan, brown, brownish purple and purple, with white outlines & 20x60.
+ * light pastel green rect on left and dark grey rect on right, both 35x60.
+ * yellow rect on left and red rect on right, both with black outlines & 35x60.
+ * grey canvas
+ * deep pink rect on left and grey rect on right, both 35x60.
+ */
+p5.prototype.alpha = function(c) {
+ if (c instanceof p5.Color || c instanceof Array) {
+ return this.color(c)._getAlpha();
+ } else {
+ throw new Error('Needs p5.Color or pixel array as argument.');
+ }
+};
+
+/**
+ * Extracts the blue value from a color or pixel array.
+ *
+ * @method blue
+ * @param {Object} obj p5.Color object or pixel array
+ * @example
+ *
+ *
+ * c = color(175, 100, 220); // Define color 'c'
+ * fill(c); // Use color variable 'c' as fill color
+ * rect(15, 20, 35, 60); // Draw left rectangle
+ *
+ * blueValue = blue(c); // Get blue in 'c'
+ * print(blueValue); // Prints "220.0"
+ * fill(0, 0, blueValue); // Use 'blueValue' in new fill
+ * rect(50, 20, 35, 60); // Draw right rectangle
+ *
+ *
+ *
+ * @alt
+ * Left half of canvas light purple and right half a royal blue.
+ *
+ */
+p5.prototype.blue = function(c) {
+ if (c instanceof p5.Color || c instanceof Array) {
+ return this.color(c)._getBlue();
+ } else {
+ throw new Error('Needs p5.Color or pixel array as argument.');
+ }
+};
+
+/**
+ * Extracts the HSB brightness value from a color or pixel array.
+ *
+ * @method brightness
+ * @param {Object} color p5.Color object or pixel array
+ * @example
+ *
+ *
+ * @alt
+ * Left half of canvas salmon pink and the right half white.
+ *
+ */
+p5.prototype.brightness = function(c) {
+ if (c instanceof p5.Color || c instanceof Array) {
+ return this.color(c)._getBrightness();
+ } else {
+ throw new Error('Needs p5.Color or pixel array as argument.');
+ }
+};
+
+/**
+ * Creates colors for storing in variables of the color datatype. The
+ * parameters are interpreted as RGB or HSB values depending on the
+ * current colorMode(). The default mode is RGB values from 0 to 255
+ * and, therefore, the function call color(255, 204, 0) will return a
+ * bright yellow color.
+ *
+ * Note that if only one value is provided to color(), it will be interpreted
+ * as a grayscale value. Add a second value, and it will be used for alpha
+ * transparency. When three values are specified, they are interpreted as
+ * either RGB or HSB values. Adding a fourth value applies alpha
+ * transparency. If a single string parameter is provided it will be
+ * interpreted as a CSS-compatible color string.
+ *
+ * Colors are stored as Numbers or Arrays.
+ *
+ * @method color
+ * @param {Number} gray number specifying value between white
+ * and black.
+ * @param {Number} [alpha] alpha value relative to current color range
+ * (default is 0-255)
+ * @return {Array} resulting color
+ *
+ * @example
+ *
+ *
+ * var c = color(255, 204, 0); // Define color 'c'
+ * fill(c); // Use color variable 'c' as fill color
+ * noStroke(); // Don't draw a stroke around shapes
+ * rect(30, 20, 55, 55); // Draw rectangle
+ *
+ *
+ *
+ *
+ *
+ * var c = color(255, 204, 0); // Define color 'c'
+ * fill(c); // Use color variable 'c' as fill color
+ * noStroke(); // Don't draw a stroke around shapes
+ * ellipse(25, 25, 80, 80); // Draw left circle
+ *
+ * // Using only one value with color()
+ * // generates a grayscale value.
+ * var c = color(65); // Update 'c' with grayscale value
+ * fill(c); // Use updated 'c' as fill color
+ * ellipse(75, 75, 80, 80); // Draw right circle
+ *
+ *
+ *
+ *
+ *
+ * // Named SVG & CSS colors may be used,
+ * var c = color('magenta');
+ * fill(c); // Use 'c' as fill color
+ * noStroke(); // Don't draw a stroke around shapes
+ * rect(20, 20, 60, 60); // Draw rectangle
+ *
+ *
+ *
+ *
+ *
+ * // as can hex color codes:
+ * noStroke(); // Don't draw a stroke around shapes
+ * var c = color('#0f0');
+ * fill(c); // Use 'c' as fill color
+ * rect(0, 10, 45, 80); // Draw rectangle
+ *
+ * c = color('#00ff00');
+ * fill(c); // Use updated 'c' as fill color
+ * rect(55, 10, 45, 80); // Draw rectangle
+ *
+ *
+ *
+ *
+ *
+ * // RGB and RGBA color strings are also supported:
+ * // these all set to the same color (solid blue)
+ * var c;
+ * noStroke(); // Don't draw a stroke around shapes
+ * c = color('rgb(0,0,255)');
+ * fill(c); // Use 'c' as fill color
+ * rect(10, 10, 35, 35); // Draw rectangle
+ *
+ * c = color('rgb(0%, 0%, 100%)');
+ * fill(c); // Use updated 'c' as fill color
+ * rect(55, 10, 35, 35); // Draw rectangle
+ *
+ * c = color('rgba(0, 0, 255, 1)');
+ * fill(c); // Use updated 'c' as fill color
+ * rect(10, 55, 35, 35); // Draw rectangle
+ *
+ * c = color('rgba(0%, 0%, 100%, 1)');
+ * fill(c); // Use updated 'c' as fill color
+ * rect(55, 55, 35, 35); // Draw rectangle
+ *
+ *
+ *
+ *
+ *
+ * // HSL color is also supported and can be specified
+ * // by value
+ * var c;
+ * noStroke(); // Don't draw a stroke around shapes
+ * c = color('hsl(160, 100%, 50%)');
+ * fill(c); // Use 'c' as fill color
+ * rect(0, 10, 45, 80); // Draw rectangle
+ *
+ * c = color('hsla(160, 100%, 50%, 0.5)');
+ * fill(c); // Use updated 'c' as fill color
+ * rect(55, 10, 45, 80); // Draw rectangle
+ *
+ *
+ *
+ *
+ *
+ * // HSB color is also supported and can be specified
+ * // by value
+ * var c;
+ * noStroke(); // Don't draw a stroke around shapes
+ * c = color('hsb(160, 100%, 50%)');
+ * fill(c); // Use 'c' as fill color
+ * rect(0, 10, 45, 80); // Draw rectangle
+ *
+ * c = color('hsba(160, 100%, 50%, 0.5)');
+ * fill(c); // Use updated 'c' as fill color
+ * rect(55, 10, 45, 80); // Draw rectangle
+ *
+ *
+ *
+ *
+ *
+ * var c; // Declare color 'c'
+ * noStroke(); // Don't draw a stroke around shapes
+ *
+ * // If no colorMode is specified, then the
+ * // default of RGB with scale of 0-255 is used.
+ * c = color(50, 55, 100); // Create a color for 'c'
+ * fill(c); // Use color variable 'c' as fill color
+ * rect(0, 10, 45, 80); // Draw left rect
+ *
+ * colorMode(HSB, 100); // Use HSB with scale of 0-100
+ * c = color(50, 55, 100); // Update 'c' with new color
+ * fill(c); // Use updated 'c' as fill color
+ * rect(55, 10, 45, 80); // Draw right rect
+ *
+ *
+ *
+ * @alt
+ * Yellow rect in middle right of canvas, with 55 pixel width and height.
+ * Yellow ellipse in top left of canvas, black ellipse in bottom right,both 80x80.
+ * Bright fuschia rect in middle of canvas, 60 pixel width and height.
+ * Two bright green rects on opposite sides of the canvas, both 45x80.
+ * Four blue rects in each corner of the canvas, each are 35x35.
+ * Bright sea green rect on left and darker rect on right of canvas, both 45x80.
+ * Dark green rect on left and lighter green rect on right of canvas, both 45x80.
+ * Dark blue rect on left and light teal rect on right of canvas, both 45x80.
+ *
+ */
+
+/**
+ * @method color
+ * @param {Number|String} v1 red or hue value relative to
+ * the current color range, or a color string
+ * @param {Number} v2 green or saturation value
+ * relative to the current color range
+ * @param {Number} v3 blue or brightness value
+ * relative to the current color range
+ * @param {Number} [alpha]
+ */
+
+p5.prototype.color = function() {
+ if (arguments[0] instanceof p5.Color) {
+ return arguments[0]; // Do nothing if argument is already a color object.
+ } else if (arguments[0] instanceof Array) {
+ if (this instanceof p5.Renderer) {
+ return new p5.Color(this, arguments[0]);
+ } else {
+ return new p5.Color(this._renderer, arguments[0]);
+ }
+ } else {
+ if (this instanceof p5.Renderer) {
+ return new p5.Color(this, arguments);
+ } else {
+ return new p5.Color(this._renderer, arguments);
+ }
+ }
+};
+
+/**
+ * Extracts the green value from a color or pixel array.
+ *
+ * @method green
+ * @param {Object} color p5.Color object or pixel array
+ * @example
+ *
+ *
+ * c = color(20, 75, 200); // Define color 'c'
+ * fill(c); // Use color variable 'c' as fill color
+ * rect(15, 20, 35, 60); // Draw left rectangle
+ *
+ * greenValue = green(c); // Get green in 'c'
+ * print(greenValue); // Print "75.0"
+ * fill(0, greenValue, 0); // Use 'greenValue' in new fill
+ * rect(50, 20, 35, 60); // Draw right rectangle
+ *
+ *
+ *
+ * @alt
+ * blue rect on left and green on right, both with black outlines & 35x60.
+ *
+ */
+
+p5.prototype.green = function(c) {
+ if (c instanceof p5.Color || c instanceof Array) {
+ return this.color(c)._getGreen();
+ } else {
+ throw new Error('Needs p5.Color or pixel array as argument.');
+ }
+};
+
+/**
+ * Extracts the hue value from a color or pixel array.
+ *
+ * Hue exists in both HSB and HSL. This function will return the
+ * HSB-normalized hue when supplied with an HSB color object (or when supplied
+ * with a pixel array while the color mode is HSB), but will default to the
+ * HSL-normalized hue otherwise. (The values will only be different if the
+ * maximum hue setting for each system is different.)
+ *
+ * @method hue
+ * @param {Object} color p5.Color object or pixel array
+ * @example
+ *
+ *
+ * @alt
+ * salmon pink rect on left and black on right, both 35x60.
+ *
+ */
+
+p5.prototype.hue = function(c) {
+ if (c instanceof p5.Color || c instanceof Array) {
+ return this.color(c)._getHue();
+ } else {
+ throw new Error('Needs p5.Color or pixel array as argument.');
+ }
+};
+
+/**
+ * Blends two colors to find a third color somewhere between them. The amt
+ * parameter is the amount to interpolate between the two values where 0.0
+ * equal to the first color, 0.1 is very near the first color, 0.5 is halfway
+ * in between, etc. An amount below 0 will be treated as 0. Likewise, amounts
+ * above 1 will be capped at 1. This is different from the behavior of lerp(),
+ * but necessary because otherwise numbers outside the range will produce
+ * strange and unexpected colors.
+ *
+ * The way that colours are interpolated depends on the current color mode.
+ *
+ * @method lerpColor
+ * @param {Array|Number} c1 interpolate from this color
+ * @param {Array|Number} c2 interpolate to this color
+ * @param {Number} amt number between 0 and 1
+ * @return {Array|Number} interpolated color
+ * @example
+ *
+ *
+ * @alt
+ * light pastel green rect on left and dark grey rect on right, both 35x60.
+ *
+ */
+p5.prototype.lightness = function(c) {
+ if (c instanceof p5.Color || c instanceof Array) {
+ return this.color(c)._getLightness();
+ } else {
+ throw new Error('Needs p5.Color or pixel array as argument.');
+ }
+};
+
+/**
+ * Extracts the red value from a color or pixel array.
+ *
+ * @method red
+ * @param {Object} obj p5.Color object or pixel array
+ * @example
+ *
+ *
+ * c = color(255, 204, 0); // Define color 'c'
+ * fill(c); // Use color variable 'c' as fill color
+ * rect(15, 20, 35, 60); // Draw left rectangle
+ *
+ * redValue = red(c); // Get red in 'c'
+ * print(redValue); // Print "255.0"
+ * fill(redValue, 0, 0); // Use 'redValue' in new fill
+ * rect(50, 20, 35, 60); // Draw right rectangle
+ *
+ *
+ *
+ * @alt
+ * yellow rect on left and red rect on right, both with black outlines and 35x60.
+ * grey canvas
+ */
+p5.prototype.red = function(c) {
+ if (c instanceof p5.Color || c instanceof Array) {
+ return this.color(c)._getRed();
+ } else {
+ throw new Error('Needs p5.Color or pixel array as argument.');
+ }
+};
+
+/**
+ * Extracts the saturation value from a color or pixel array.
+ *
+ * Saturation is scaled differently in HSB and HSL. This function will return
+ * the HSB saturation when supplied with an HSB color object (or when supplied
+ * with a pixel array while the color mode is HSB), but will default to the
+ * HSL saturation otherwise.
+ *
+ * @method saturation
+ * @param {Object} color p5.Color object or pixel array
+ * @example
+ *
+ *
+ * @alt
+ * canvas with darkest charcoal grey background.
+ * canvas with yellow background.
+ * canvas with royal blue background.
+ * canvas with red background.
+ * canvas with pink background.
+ * canvas with black background.
+ * canvas with bright green background.
+ * canvas with soft green background.
+ * canvas with red background.
+ * canvas with light purple background.
+ * canvas with blue background.
+ */
+
+/**
+ * @method background
+ * @param {String} colorstring color string, possible formats include: integer
+ * rgb() or rgba(), percentage rgb() or rgba(),
+ * 3-digit hex, 6-digit hex
+ * @param {Number} [a]
+ */
+
+/**
+ * @method background
+ * @param {Number} gray specifies a value between white and black
+ * @param {Number} [a]
+ */
+
+/**
+ * @method background
+ * @param {Number} v1 red or hue value (depending on the current color
+ * mode)
+ * @param {Number} v2 green or saturation value (depending on the current
+ * color mode)
+ * @param {Number} v3 blue or brightness value (depending on the current
+ * color mode)
+ * @param {Number} [a]
+ */
+
+/**
+ * @method background
+ * @param {p5.Image} image image created with loadImage() or createImage(),
+ * to set as background
+ * (must be same size as the sketch window)
+ * @param {Number} [a]
+ */
+p5.prototype.background = function() {
+ if (arguments[0] instanceof p5.Image) {
+ this.image(arguments[0], 0, 0, this.width, this.height);
+ } else {
+ this._renderer.background.apply(this._renderer, arguments);
+ }
+ return this;
+};
+
+/**
+ * Clears the pixels within a buffer. This function only works on p5.Canvas
+ * objects created with the createCanvas() function; it won't work with the
+ * main display window. Unlike the main graphics context, pixels in
+ * additional graphics areas created with createGraphics() can be entirely
+ * or partially transparent. This function clears everything to make all of
+ * the pixels 100% transparent.
+ *
+ * @method clear
+ * @example
+ *
+ *
+ * @alt
+ * 20x20 white ellipses are continually drawn at mouse x and y coordinates.
+ *
+ */
+
+p5.prototype.clear = function() {
+ this._renderer.clear();
+ return this;
+};
+
+/**
+ * colorMode() changes the way p5.js interprets color data. By default, the
+ * parameters for fill(), stroke(), background(), and color() are defined by
+ * values between 0 and 255 using the RGB color model. This is equivalent to
+ * setting colorMode(RGB, 255). Setting colorMode(HSB) lets you use the HSB
+ * system instead. By default, this is colorMode(HSB, 360, 100, 100, 1). You
+ * can also use HSL.
+ *
+ * Note: existing color objects remember the mode that they were created in,
+ * so you can change modes as you like without affecting their appearance.
+ *
+ * @method colorMode
+ * @param {Constant} mode either RGB or HSB, corresponding to
+ * Red/Green/Blue and Hue/Saturation/Brightness
+ * (or Lightness)
+ * @param {Number} [max1] range for the red or hue depending on the
+ * current color mode, or range for all values
+ * @param {Number} [max2] range for the green or saturation depending
+ * on the current color mode
+ * @param {Number} [max3] range for the blue or brightness/lighntess
+ * depending on the current color mode
+ * @param {Number} [maxA] range for the alpha
+ * @example
+ *
+ *
+ * @alt
+ *Green to red gradient from bottom L to top R. shading originates from top left.
+ *Rainbow gradient from left to right. Brightness increasing to white at top.
+ *unknown image.
+ *50x50 ellipse at middle L & 40x40 ellipse at center. Transluscent pink outlines.
+ *
+ */
+p5.prototype.colorMode = function() {
+ if (arguments[0] === constants.RGB ||
+ arguments[0] === constants.HSB ||
+ arguments[0] === constants.HSL) {
+
+ // Set color mode.
+ this._renderer._colorMode = arguments[0];
+
+ // Set color maxes.
+ var maxes = this._renderer._colorMaxes[this._renderer._colorMode];
+ if (arguments.length === 2) {
+ maxes[0] = arguments[1]; // Red
+ maxes[1] = arguments[1]; // Green
+ maxes[2] = arguments[1]; // Blue
+ maxes[3] = arguments[1]; // Alpha
+ } else if (arguments.length === 4) {
+ maxes[0] = arguments[1]; // Red
+ maxes[1] = arguments[2]; // Green
+ maxes[2] = arguments[3]; // Blue
+ } else if (arguments.length === 5) {
+ maxes[0] = arguments[1]; // Red
+ maxes[1] = arguments[2]; // Green
+ maxes[2] = arguments[3]; // Blue
+ maxes[3] = arguments[4]; // Alpha
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Sets the color used to fill shapes. For example, if you run
+ * fill(204, 102, 0), all subsequent shapes will be filled with orange. This
+ * color is either specified in terms of the RGB or HSB color depending on
+ * the current colorMode(). (The default color space is RGB, with each value
+ * in the range from 0 to 255).
+ *
+ * If a single string argument is provided, RGB, RGBA and Hex CSS color strings
+ * and all named color strings are supported. A p5 Color object can also be
+ * provided to set the fill color.
+ *
+ * @method fill
+ * @param {Number|Array|String|p5.Color} v1 gray value, red or hue value
+ * (depending on the current color
+ * mode), or color Array, or CSS
+ * color string
+ * @param {Number} [v2] green or saturation value
+ * (depending on the current
+ * color mode)
+ * @param {Number} [v3] blue or brightness value
+ * (depending on the current
+ * color mode)
+ * @param {Number} [a] opacity of the background
+ *
+ * @example
+ *
+ * @alt
+ * 60x60 dark charcoal grey rect with black outline in center of canvas.
+ * 60x60 yellow rect with black outline in center of canvas.
+ * 60x60 royal blue rect with black outline in center of canvas.
+ * 60x60 red rect with black outline in center of canvas.
+ * 60x60 pink rect with black outline in center of canvas.
+ * 60x60 black rect with black outline in center of canvas.
+ * 60x60 light green rect with black outline in center of canvas.
+ * 60x60 soft green rect with black outline in center of canvas.
+ * 60x60 red rect with black outline in center of canvas.
+ * 60x60 dark fushcia rect with black outline in center of canvas.
+ * 60x60 blue rect with black outline in center of canvas.
+ */
+
+p5.prototype.fill = function() {
+ this._renderer._setProperty('_fillSet', true);
+ this._renderer._setProperty('_doFill', true);
+ this._renderer.fill.apply(this._renderer, arguments);
+ return this;
+};
+
+/**
+ * Disables filling geometry. If both noStroke() and noFill() are called,
+ * nothing will be drawn to the screen.
+ *
+ * @method noFill
+ * @example
+ *
+ * @alt
+ * white rect top middle and noFill rect center. Both 60x60 with black outlines.
+ */
+p5.prototype.noFill = function() {
+ this._renderer._setProperty('_doFill', false);
+ return this;
+};
+
+/**
+ * Disables drawing the stroke (outline). If both noStroke() and noFill()
+ * are called, nothing will be drawn to the screen.
+ *
+ * @method noStroke
+ * @example
+ *
+ *
+ *
+ * @alt
+ *60x60 white rect at center. no outline.
+ *
+ */
+
+p5.prototype.noStroke = function() {
+ this._renderer._setProperty('_doStroke', false);
+ return this;
+};
+
+/**
+ * Sets the color used to draw lines and borders around shapes. This color
+ * is either specified in terms of the RGB or HSB color depending on the
+ * current colorMode() (the default color space is RGB, with each value in
+ * the range from 0 to 255).
+ *
+ * If a single string argument is provided, RGB, RGBA and Hex CSS color
+ * strings and all named color strings are supported. A p5 Color object
+ * can also be provided to set the stroke color.
+ *
+ * @method stroke
+ * @param {Number|Array|String|p5.Color} v1 gray value, red or hue value
+ * (depending on the current color
+ * mode), or color Array, or CSS
+ * color string
+ * @param {Number} [v2] green or saturation value
+ * (depending on the current
+ * color mode)
+ * @param {Number} [v3] blue or brightness value
+ * (depending on the current
+ * color mode)
+ * @param {Number} [a] opacity of the background
+ *
+ * @example
+ *
+ *
+ * @alt
+ * 60x60 white rect at center. Dark charcoal grey outline.
+ * 60x60 white rect at center. Yellow outline.
+ * 60x60 white rect at center. Royal blue outline.
+ * 60x60 white rect at center. Red outline.
+ * 60x60 white rect at center. Pink outline.
+ * 60x60 white rect at center. Black outline.
+ * 60x60 white rect at center. Bright green outline.
+ * 60x60 white rect at center. Soft green outline.
+ * 60x60 white rect at center. Red outline.
+ * 60x60 white rect at center. Dark fushcia outline.
+ * 60x60 white rect at center. Blue outline.
+ */
+
+p5.prototype.stroke = function() {
+ this._renderer._setProperty('_strokeSet', true);
+ this._renderer._setProperty('_doStroke', true);
+ this._renderer.stroke.apply(this._renderer, arguments);
+ return this;
+};
+
+module.exports = p5;
+
+},{"../core/constants":41,"../core/core":42,"./p5.Color":36}],38:[function(_dereq_,module,exports){
+/**
+ * @module Shape
+ * @submodule 2D Primitives
+ * @for p5
+ * @requires core
+ * @requires constants
+ */
+
+'use strict';
+
+var p5 = _dereq_('./core');
+var constants = _dereq_('./constants');
+var canvas = _dereq_('./canvas');
+_dereq_('./error_helpers');
+
+/**
+ * Draw an arc to the screen. If called with only a, b, c, d, start, and
+ * stop, the arc will be drawn as an open pie. If mode is provided, the arc
+ * will be drawn either open, as a chord, or as a pie as specified. The
+ * origin may be changed with the ellipseMode() function.
+ * Note that drawing a full circle (ex: 0 to TWO_PI) will appear blank
+ * because 0 and TWO_PI are the same position on the unit circle. The
+ * best way to handle this is by using the ellipse() function instead
+ * to create a closed ellipse, and to use the arc() function
+ * only to draw parts of an ellipse.
+ *
+ * @method arc
+ * @param {Number} a x-coordinate of the arc's ellipse
+ * @param {Number} b y-coordinate of the arc's ellipse
+ * @param {Number} c width of the arc's ellipse by default
+ * @param {Number} d height of the arc's ellipse by default
+ * @param {Number} start angle to start the arc, specified in radians
+ * @param {Number} stop angle to stop the arc, specified in radians
+ * @param {Constant} [mode] optional parameter to determine the way of drawing
+ * the arc
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ *shattered outline of an ellipse with a quarter of a white circle bottom-right.
+ *white ellipse with black outline with top right missing.
+ *white ellipse with top right missing with black outline around shape.
+ *white ellipse with top right quarter missing with black outline around the shape.
+ *
+ */
+p5.prototype.arc = function(x, y, w, h, start, stop, mode) {
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ if (!this._renderer._doStroke && !this._renderer._doFill) {
+ return this;
+ }
+ if (this._angleMode === constants.DEGREES) {
+ start = this.radians(start);
+ stop = this.radians(stop);
+ }
+
+ // Make all angles positive...
+ while (start < 0) {
+ start += constants.TWO_PI;
+ }
+ while (stop < 0) {
+ stop += constants.TWO_PI;
+ }
+ // ...and confine them to the interval [0,TWO_PI).
+ start %= constants.TWO_PI;
+ stop %= constants.TWO_PI;
+
+ // account for full circle
+ if (stop === start) {
+ stop += constants.TWO_PI;
+ }
+
+ // Adjust angles to counter linear scaling.
+ if (start <= constants.HALF_PI) {
+ start = Math.atan(w / h * Math.tan(start));
+ } else if (start > constants.HALF_PI && start <= 3 * constants.HALF_PI) {
+ start = Math.atan(w / h * Math.tan(start)) + constants.PI;
+ } else {
+ start = Math.atan(w / h * Math.tan(start)) + constants.TWO_PI;
+ }
+ if (stop <= constants.HALF_PI) {
+ stop = Math.atan(w / h * Math.tan(stop));
+ } else if (stop > constants.HALF_PI && stop <= 3 * constants.HALF_PI) {
+ stop = Math.atan(w / h * Math.tan(stop)) + constants.PI;
+ } else {
+ stop = Math.atan(w / h * Math.tan(stop)) + constants.TWO_PI;
+ }
+
+ // Exceed the interval if necessary in order to preserve the size and
+ // orientation of the arc.
+ if (start > stop) {
+ stop += constants.TWO_PI;
+ }
+ // p5 supports negative width and heights for ellipses
+ w = Math.abs(w);
+ h = Math.abs(h);
+ this._renderer.arc(x, y, w, h, start, stop, mode);
+ return this;
+};
+
+/**
+ * Draws an ellipse (oval) to the screen. An ellipse with equal width and
+ * height is a circle. By default, the first two parameters set the location,
+ * and the third and fourth parameters set the shape's width and height. If
+ * no height is specified, the value of width is used for both the width and
+ * height. If a negative height or width is specified, the absolute value is taken.
+ * The origin may be changed with the ellipseMode() function.
+ *
+ * @method ellipse
+ * @param {Number} x x-coordinate of the ellipse.
+ * @param {Number} y y-coordinate of the ellipse.
+ * @param {Number} w width of the ellipse.
+ * @param {Number} [h] height of the ellipse.
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * ellipse(56, 46, 55, 55);
+ *
+ *
+ *
+ * @alt
+ *white ellipse with black outline in middle-right of canvas that is 55x55.
+ *
+ */
+/**
+ * @method ellipse
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Number} w
+ * @param {Number} [h]
+ * @return {p5}
+ */
+p5.prototype.ellipse = function() {
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ // Duplicate 3rd argument if only 3 given.
+ if (args.length === 3) {
+ args.push(args[2]);
+ }
+ // p5 supports negative width and heights for rects
+ if (args[2] < 0){args[2] = Math.abs(args[2]);}
+ if (args[3] < 0){args[3] = Math.abs(args[3]);}
+ if (!this._renderer._doStroke && !this._renderer._doFill) {
+ return this;
+ }
+ var vals = canvas.modeAdjust(
+ args[0],
+ args[1],
+ args[2],
+ args[3],
+ this._renderer._ellipseMode);
+ args[0] = vals.x;
+ args[1] = vals.y;
+ args[2] = vals.w;
+ args[3] = vals.h;
+ this._renderer.ellipse(args);
+ return this;
+};
+/**
+ * Draws a line (a direct path between two points) to the screen. The version
+ * of line() with four parameters draws the line in 2D. To color a line, use
+ * the stroke() function. A line cannot be filled, therefore the fill()
+ * function will not affect the color of a line. 2D lines are drawn with a
+ * width of one pixel by default, but this can be changed with the
+ * strokeWeight() function.
+ *
+ * @method line
+ * @param {Number} x1 the x-coordinate of the first point
+ * @param {Number} y1 the y-coordinate of the first point
+ * @param {Number} x2 the x-coordinate of the second point
+ * @param {Number} y2 the y-coordinate of the second point
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ *line 78 pixels long running from mid-top to bottom-right of canvas.
+ *3 lines of various stroke sizes. Form top, bottom and right sides of a square.
+ *
+ */
+////commented out original
+// p5.prototype.line = function(x1, y1, x2, y2) {
+// if (!this._renderer._doStroke) {
+// return this;
+// }
+// if(this._renderer.isP3D){
+// } else {
+// this._renderer.line(x1, y1, x2, y2);
+// }
+// };
+p5.prototype.line = function() {
+ if (!this._renderer._doStroke) {
+ return this;
+ }
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ //check whether we should draw a 3d line or 2d
+ if(this._renderer.isP3D){
+ this._renderer.line(
+ args[0],
+ args[1],
+ args[2],
+ args[3],
+ args[4],
+ args[5]);
+ } else {
+ this._renderer.line(
+ args[0],
+ args[1],
+ args[2],
+ args[3]);
+ }
+ return this;
+};
+
+/**
+ * Draws a point, a coordinate in space at the dimension of one pixel.
+ * The first parameter is the horizontal value for the point, the second
+ * value is the vertical value for the point. The color of the point is
+ * determined by the current stroke.
+ *
+ * @method point
+ * @param {Number} x the x-coordinate
+ * @param {Number} y the y-coordinate
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ *4 points centered in the middle-right of the canvas.
+ *
+ */
+p5.prototype.point = function() {
+ if (!this._renderer._doStroke) {
+ return this;
+ }
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ //check whether we should draw a 3d line or 2d
+ if(this._renderer.isP3D){
+ this._renderer.point(
+ args[0],
+ args[1],
+ args[2]
+ );
+ } else {
+ this._renderer.point(
+ args[0],
+ args[1]
+ );
+ }
+ return this;
+};
+
+
+/**
+ * Draw a quad. A quad is a quadrilateral, a four sided polygon. It is
+ * similar to a rectangle, but the angles between its edges are not
+ * constrained to ninety degrees. The first pair of parameters (x1,y1)
+ * sets the first vertex and the subsequent pairs should proceed
+ * clockwise or counter-clockwise around the defined shape.
+ *
+ * @method quad
+ * @param {Number} x1 the x-coordinate of the first point
+ * @param {Number} y1 the y-coordinate of the first point
+ * @param {Number} x2 the x-coordinate of the second point
+ * @param {Number} y2 the y-coordinate of the second point
+ * @param {Number} x3 the x-coordinate of the third point
+ * @param {Number} y3 the y-coordinate of the third point
+ * @param {Number} x4 the x-coordinate of the fourth point
+ * @param {Number} y4 the y-coordinate of the fourth point
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ *irregular white quadrilateral shape with black outline mid-right of canvas.
+ *
+ */
+/**
+ * @method quad
+ * @param {Number} x1
+ * @param {Number} y1
+ * @param {Number} x2
+ * @param {Number} y2
+ * @param {Number} x3
+ * @param {Number} y3
+ * @param {Number} x4
+ * @param {Number} y4
+ * @return {p5} the p5 object
+ */
+p5.prototype.quad = function() {
+ if (!this._renderer._doStroke && !this._renderer._doFill) {
+ return this;
+ }
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ if(this._renderer.isP3D){
+ this._renderer.quad(
+ args[0],
+ args[1],
+ args[2],
+ args[3],
+ args[4],
+ args[5],
+ args[6],
+ args[7],
+ args[8],
+ args[9],
+ args[10],
+ args[11]
+ );
+ } else {
+ this._renderer.quad(
+ args[0],
+ args[1],
+ args[2],
+ args[3],
+ args[4],
+ args[5],
+ args[6],
+ args[7]
+ );
+ }
+ return this;
+};
+
+/**
+* Draws a rectangle to the screen. A rectangle is a four-sided shape with
+* every angle at ninety degrees. By default, the first two parameters set
+* the location of the upper-left corner, the third sets the width, and the
+* fourth sets the height. The way these parameters are interpreted, however,
+* may be changed with the rectMode() function.
+*
+* The fifth, sixth, seventh and eighth parameters, if specified,
+* determine corner radius for the top-right, top-left, lower-right and
+* lower-left corners, respectively. An omitted corner radius parameter is set
+* to the value of the previously specified radius value in the parameter list.
+*
+* @method rect
+* @param {Number} x x-coordinate of the rectangle.
+* @param {Number} y y-coordinate of the rectangle.
+* @param {Number} w width of the rectangle.
+* @param {Number} h height of the rectangle.
+* @param {Number} [tl] optional radius of top-left corner.
+* @param {Number} [tr] optional radius of top-right corner.
+* @param {Number} [br] optional radius of bottom-right corner.
+* @param {Number} [bl] optional radius of bottom-left corner.
+* @return {p5} the p5 object.
+* @example
+*
+*
+* // Draw a rectangle at location (30, 20) with a width and height of 55.
+* rect(30, 20, 55, 55);
+*
+*
+*
+*
+*
+* // Draw a rectangle with rounded corners, each having a radius of 20.
+* rect(30, 20, 55, 55, 20);
+*
+*
+*
+*
+*
+* // Draw a rectangle with rounded corners having the following radii:
+* // top-left = 20, top-right = 15, bottom-right = 10, bottom-left = 5.
+* rect(30, 20, 55, 55, 20, 15, 10, 5);
+*
+*
+*
+* @alt
+* 55x55 white rect with black outline in mid-right of canvas.
+* 55x55 white rect with black outline and rounded edges in mid-right of canvas.
+* 55x55 white rect with black outline and rounded edges of different radii.
+*/
+/**
+* @method rect
+* @param {Number} x
+* @param {Number} y
+* @param {Number} w
+* @param {Number} h
+* @param {Number} [detailX]
+* @param {Number} [detailY]
+* @return {p5} the p5 object.
+*/
+p5.prototype.rect = function () {
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ if (!this._renderer._doStroke && !this._renderer._doFill) {
+ return;
+ }
+ var vals = canvas.modeAdjust(
+ args[0],
+ args[1],
+ args[2],
+ args[3],
+ this._renderer._rectMode);
+ args[0] = vals.x;
+ args[1] = vals.y;
+ args[2] = vals.w;
+ args[3] = vals.h;
+ this._renderer.rect(args);
+ return this;
+};
+
+/**
+* A triangle is a plane created by connecting three points. The first two
+* arguments specify the first point, the middle two arguments specify the
+* second point, and the last two arguments specify the third point.
+*
+* @method triangle
+* @param {Number} x1 x-coordinate of the first point
+* @param {Number} y1 y-coordinate of the first point
+* @param {Number} x2 x-coordinate of the second point
+* @param {Number} y2 y-coordinate of the second point
+* @param {Number} x3 x-coordinate of the third point
+* @param {Number} y3 y-coordinate of the third point
+* @return {p5} the p5 object
+* @example
+*
+*
+* triangle(30, 75, 58, 20, 86, 75);
+*
+*
+*
+*@alt
+* white triangle with black outline in mid-right of canvas.
+*
+*/
+p5.prototype.triangle = function() {
+
+ if (!this._renderer._doStroke && !this._renderer._doFill) {
+ return this;
+ }
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ this._renderer.triangle(args);
+ return this;
+};
+
+module.exports = p5;
+
+},{"./canvas":40,"./constants":41,"./core":42,"./error_helpers":45}],39:[function(_dereq_,module,exports){
+/**
+ * @module Shape
+ * @submodule Attributes
+ * @for p5
+ * @requires core
+ * @requires constants
+ */
+
+'use strict';
+
+var p5 = _dereq_('./core');
+var constants = _dereq_('./constants');
+
+/**
+ * Modifies the location from which ellipses are drawn by changing the way
+ * in which parameters given to ellipse() are interpreted.
+ *
+ * The default mode is ellipseMode(CENTER), which interprets the first two
+ * parameters of ellipse() as the shape's center point, while the third and
+ * fourth parameters are its width and height.
+ *
+ * ellipseMode(RADIUS) also uses the first two parameters of ellipse() as
+ * the shape's center point, but uses the third and fourth parameters to
+ * specify half of the shapes's width and height.
+ *
+ * ellipseMode(CORNER) interprets the first two parameters of ellipse() as
+ * the upper-left corner of the shape, while the third and fourth parameters
+ * are its width and height.
+ *
+ * ellipseMode(CORNERS) interprets the first two parameters of ellipse() as
+ * the location of one corner of the ellipse's bounding box, and the third
+ * and fourth parameters as the location of the opposite corner.
+ *
+ * The parameter must be written in ALL CAPS because Javascript is a
+ * case-sensitive language.
+ *
+ * @method ellipseMode
+ * @param {Constant} mode either CENTER, RADIUS, CORNER, or CORNERS
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * ellipseMode(RADIUS); // Set ellipseMode to RADIUS
+ * fill(255); // Set fill to white
+ * ellipse(50, 50, 30, 30); // Draw white ellipse using RADIUS mode
+ *
+ * ellipseMode(CENTER); // Set ellipseMode to CENTER
+ * fill(100); // Set fill to gray
+ * ellipse(50, 50, 30, 30); // Draw gray ellipse using CENTER mode
+ *
+ *
+ *
+ *
+ *
+ * ellipseMode(CORNER); // Set ellipseMode is CORNER
+ * fill(255); // Set fill to white
+ * ellipse(25, 25, 50, 50); // Draw white ellipse using CORNER mode
+ *
+ * ellipseMode(CORNERS); // Set ellipseMode to CORNERS
+ * fill(100); // Set fill to gray
+ * ellipse(25, 25, 50, 50); // Draw gray ellipse using CORNERS mode
+ *
+ *
+ *
+ * @alt
+ * 60x60 white ellipse and 30x30 grey ellipse with black outlines at center.
+ * 60x60 white ellipse @center and 30x30 grey ellipse top-right, black outlines.
+ *
+ */
+p5.prototype.ellipseMode = function(m) {
+ if (m === constants.CORNER ||
+ m === constants.CORNERS ||
+ m === constants.RADIUS ||
+ m === constants.CENTER) {
+ this._renderer._ellipseMode = m;
+ }
+ return this;
+};
+
+/**
+ * Draws all geometry with jagged (aliased) edges. Note that smooth() is
+ * active by default, so it is necessary to call noSmooth() to disable
+ * smoothing of geometry, images, and fonts.
+ *
+ * @method noSmooth
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * 2 pixelated 36x36 white ellipses to left & right of center, black background
+ *
+ */
+p5.prototype.noSmooth = function() {
+ this._renderer.noSmooth();
+ return this;
+};
+
+/**
+ * Modifies the location from which rectangles are drawn by changing the way
+ * in which parameters given to rect() are interpreted.
+ *
+ * The default mode is rectMode(CORNER), which interprets the first two
+ * parameters of rect() as the upper-left corner of the shape, while the
+ * third and fourth parameters are its width and height.
+ *
+ * rectMode(CORNERS) interprets the first two parameters of rect() as the
+ * location of one corner, and the third and fourth parameters as the
+ * location of the opposite corner.
+ *
+ * rectMode(CENTER) interprets the first two parameters of rect() as the
+ * shape's center point, while the third and fourth parameters are its
+ * width and height.
+ *
+ * rectMode(RADIUS) also uses the first two parameters of rect() as the
+ * shape's center point, but uses the third and fourth parameters to specify
+ * half of the shapes's width and height.
+ *
+ * The parameter must be written in ALL CAPS because Javascript is a
+ * case-sensitive language.
+ *
+ * @method rectMode
+ * @param {Constant} mode either CORNER, CORNERS, CENTER, or RADIUS
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * rectMode(CORNER); // Default rectMode is CORNER
+ * fill(255); // Set fill to white
+ * rect(25, 25, 50, 50); // Draw white rect using CORNER mode
+ *
+ * rectMode(CORNERS); // Set rectMode to CORNERS
+ * fill(100); // Set fill to gray
+ * rect(25, 25, 50, 50); // Draw gray rect using CORNERS mode
+ *
+ *
+ *
+ *
+ *
+ * rectMode(RADIUS); // Set rectMode to RADIUS
+ * fill(255); // Set fill to white
+ * rect(50, 50, 30, 30); // Draw white rect using RADIUS mode
+ *
+ * rectMode(CENTER); // Set rectMode to CENTER
+ * fill(100); // Set fill to gray
+ * rect(50, 50, 30, 30); // Draw gray rect using CENTER mode
+ *
+ *
+ *
+ * @alt
+ * 50x50 white rect at center and 25x25 grey rect in the top left of the other.
+ * 50x50 white rect at center and 25x25 grey rect in the center of the other.
+ *
+ */
+p5.prototype.rectMode = function(m) {
+ if (m === constants.CORNER ||
+ m === constants.CORNERS ||
+ m === constants.RADIUS ||
+ m === constants.CENTER) {
+ this._renderer._rectMode = m;
+ }
+ return this;
+};
+
+/**
+ * Draws all geometry with smooth (anti-aliased) edges. smooth() will also
+ * improve image quality of resized images. Note that smooth() is active by
+ * default; noSmooth() can be used to disable smoothing of geometry,
+ * images, and fonts.
+ *
+ * @method smooth
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * 2 pixelated 36x36 white ellipses one left one right of center. On black.
+ *
+ */
+p5.prototype.smooth = function() {
+ this._renderer.smooth();
+ return this;
+};
+
+/**
+ * Sets the style for rendering line endings. These ends are either squared,
+ * extended, or rounded, each of which specified with the corresponding
+ * parameters: SQUARE, PROJECT, and ROUND. The default cap is ROUND.
+ *
+ * @method strokeCap
+ * @param {Number|Constant} cap either SQUARE, PROJECT, or ROUND
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * Right-facing arrowhead shape with pointed tip in center of canvas.
+ * Right-facing arrowhead shape with flat tip in center of canvas.
+ * Right-facing arrowhead shape with rounded tip in center of canvas.
+ *
+ */
+p5.prototype.strokeJoin = function(join) {
+ if (join === constants.ROUND ||
+ join === constants.BEVEL ||
+ join === constants.MITER) {
+ this._renderer.strokeJoin(join);
+ }
+ return this;
+};
+
+/**
+ * Sets the width of the stroke used for lines, points, and the border
+ * around shapes. All widths are set in units of pixels.
+ *
+ * @method strokeWeight
+ * @param {Number} weight the weight (in pixels) of the stroke
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * 3 horizontal black lines. Top line: thin, mid: medium, bottom:thick.
+ *
+ */
+p5.prototype.strokeWeight = function(w) {
+ this._renderer.strokeWeight(w);
+ return this;
+};
+
+module.exports = p5;
+
+},{"./constants":41,"./core":42}],40:[function(_dereq_,module,exports){
+/**
+ * @requires constants
+ */
+
+var constants = _dereq_('./constants');
+
+module.exports = {
+
+ modeAdjust: function(a, b, c, d, mode) {
+ if (mode === constants.CORNER) {
+ return { x: a, y: b, w: c, h: d };
+ } else if (mode === constants.CORNERS) {
+ return { x: a, y: b, w: c-a, h: d-b };
+ } else if (mode === constants.RADIUS) {
+ return { x: a-c, y: b-d, w: 2*c, h: 2*d };
+ } else if (mode === constants.CENTER) {
+ return { x: a-c*0.5, y: b-d*0.5, w: c, h: d };
+ }
+ },
+
+ arcModeAdjust: function(a, b, c, d, mode) {
+ if (mode === constants.CORNER) {
+ return { x: a+c*0.5, y: b+d*0.5, w: c, h: d };
+ } else if (mode === constants.CORNERS) {
+ return { x: a, y: b, w: c+a, h: d+b };
+ } else if (mode === constants.RADIUS) {
+ return { x: a, y: b, w: 2*c, h: 2*d };
+ } else if (mode === constants.CENTER) {
+ return { x: a, y: b, w: c, h: d };
+ }
+ }
+
+};
+
+
+},{"./constants":41}],41:[function(_dereq_,module,exports){
+/**
+ * @module Constants
+ * @submodule Constants
+ * @for p5
+ */
+
+var PI = Math.PI;
+
+module.exports = {
+
+ // GRAPHICS RENDERER
+ P2D: 'p2d',
+ WEBGL: 'webgl',
+
+ // ENVIRONMENT
+ ARROW: 'default',
+ CROSS: 'crosshair',
+ HAND: 'pointer',
+ MOVE: 'move',
+ TEXT: 'text',
+ WAIT: 'wait',
+
+ // TRIGONOMETRY
+
+ /**
+ * HALF_PI is a mathematical constant with the value
+ * 1.57079632679489661923. It is half the ratio of the
+ * circumference of a circle to its diameter. It is useful in
+ * combination with the trigonometric functions sin() and cos().
+ *
+ * @property HALF_PI
+ *
+ * @example
+ *
+ * arc(50, 50, 80, 80, 0, HALF_PI);
+ *
+ *
+ * @alt
+ * 80x80 white quarter-circle with curve toward bottom right of canvas.
+ *
+ */
+ HALF_PI: PI / 2,
+ /**
+ * PI is a mathematical constant with the value
+ * 3.14159265358979323846. It is the ratio of the circumference
+ * of a circle to its diameter. It is useful in combination with
+ * the trigonometric functions sin() and cos().
+ *
+ * @property PI
+ *
+ * @example
+ *
+ * arc(50, 50, 80, 80, 0, PI);
+ *
+ *
+ * @alt
+ * white half-circle with curve toward bottom of canvas.
+ *
+ */
+ PI: PI,
+ /**
+ * QUARTER_PI is a mathematical constant with the value 0.7853982.
+ * It is one quarter the ratio of the circumference of a circle to
+ * its diameter. It is useful in combination with the trigonometric
+ * functions sin() and cos().
+ *
+ * @property QUARTER_PI
+ *
+ * @example
+ *
+ * arc(50, 50, 80, 80, 0, QUARTER_PI);
+ *
+ *
+ * @alt
+ * white eighth-circle rotated about 40 degrees with curve bottom right canvas.
+ *
+ */
+ QUARTER_PI: PI / 4,
+ /**
+ * TAU is an alias for TWO_PI, a mathematical constant with the
+ * value 6.28318530717958647693. It is twice the ratio of the
+ * circumference of a circle to its diameter. It is useful in
+ * combination with the trigonometric functions sin() and cos().
+ *
+ * @property TAU
+ *
+ * @example
+ *
+ * arc(50, 50, 80, 80, 0, TAU);
+ *
+ *
+ * @alt
+ * 80x80 white ellipse shape in center of canvas.
+ *
+ */
+ TAU: PI * 2,
+ /**
+ * TWO_PI is a mathematical constant with the value
+ * 6.28318530717958647693. It is twice the ratio of the
+ * circumference of a circle to its diameter. It is useful in
+ * combination with the trigonometric functions sin() and cos().
+ *
+ * @property TWO_PI
+ *
+ * @example
+ *
+ * arc(50, 50, 80, 80, 0, TWO_PI);
+ *
+ *
+ * @alt
+ * 80x80 white ellipse shape in center of canvas.
+ *
+ */
+ TWO_PI: PI * 2,
+ DEGREES: 'degrees',
+ RADIANS: 'radians',
+
+ // SHAPE
+ CORNER: 'corner',
+ CORNERS: 'corners',
+ RADIUS: 'radius',
+ RIGHT: 'right',
+ LEFT: 'left',
+ CENTER: 'center',
+ TOP: 'top',
+ BOTTOM: 'bottom',
+ BASELINE: 'alphabetic',
+ POINTS: 0x0000,
+ LINES: 0x0001,
+ LINE_STRIP: 0x0003,
+ LINE_LOOP: 0x0002,
+ TRIANGLES: 0x0004,
+ TRIANGLE_FAN: 0x0006,
+ TRIANGLE_STRIP: 0x0005,
+ QUADS: 'quads',
+ QUAD_STRIP: 'quad_strip',
+ CLOSE: 'close',
+ OPEN: 'open',
+ CHORD: 'chord',
+ PIE: 'pie',
+ PROJECT: 'square', // PEND: careful this is counterintuitive
+ SQUARE: 'butt',
+ ROUND: 'round',
+ BEVEL: 'bevel',
+ MITER: 'miter',
+
+ // COLOR
+ RGB: 'rgb',
+ HSB: 'hsb',
+ HSL: 'hsl',
+
+ // DOM EXTENSION
+ AUTO: 'auto',
+
+ // INPUT
+ ALT: 18,
+ BACKSPACE: 8,
+ CONTROL: 17,
+ DELETE: 46,
+ DOWN_ARROW: 40,
+ ENTER: 13,
+ ESCAPE: 27,
+ LEFT_ARROW: 37,
+ OPTION: 18,
+ RETURN: 13,
+ RIGHT_ARROW: 39,
+ SHIFT: 16,
+ TAB: 9,
+ UP_ARROW: 38,
+
+ // RENDERING
+ BLEND: 'source-over',
+ ADD: 'lighter',
+ //ADD: 'add', //
+ //SUBTRACT: 'subtract', //
+ DARKEST: 'darken',
+ LIGHTEST: 'lighten',
+ DIFFERENCE: 'difference',
+ EXCLUSION: 'exclusion',
+ MULTIPLY: 'multiply',
+ SCREEN: 'screen',
+ REPLACE: 'copy',
+ OVERLAY: 'overlay',
+ HARD_LIGHT: 'hard-light',
+ SOFT_LIGHT: 'soft-light',
+ DODGE: 'color-dodge',
+ BURN: 'color-burn',
+
+ // FILTERS
+ THRESHOLD: 'threshold',
+ GRAY: 'gray',
+ OPAQUE: 'opaque',
+ INVERT: 'invert',
+ POSTERIZE: 'posterize',
+ DILATE: 'dilate',
+ ERODE: 'erode',
+ BLUR: 'blur',
+
+ // TYPOGRAPHY
+ NORMAL: 'normal',
+ ITALIC: 'italic',
+ BOLD: 'bold',
+
+ // TYPOGRAPHY-INTERNAL
+ _DEFAULT_TEXT_FILL: '#000000',
+ _DEFAULT_LEADMULT: 1.25,
+ _CTX_MIDDLE: 'middle',
+
+ // VERTICES
+ LINEAR: 'linear',
+ QUADRATIC: 'quadratic',
+ BEZIER: 'bezier',
+ CURVE: 'curve',
+
+ // DEFAULTS
+ _DEFAULT_STROKE: '#000000',
+ _DEFAULT_FILL: '#FFFFFF'
+
+};
+
+},{}],42:[function(_dereq_,module,exports){
+/**
+ * @module Structure
+ * @submodule Structure
+ * @for p5
+ * @requires constants
+ */
+
+'use strict';
+
+_dereq_('./shim');
+
+// Core needs the PVariables object
+var constants = _dereq_('./constants');
+
+/**
+ * This is the p5 instance constructor.
+ *
+ * A p5 instance holds all the properties and methods related to
+ * a p5 sketch. It expects an incoming sketch closure and it can also
+ * take an optional node parameter for attaching the generated p5 canvas
+ * to a node. The sketch closure takes the newly created p5 instance as
+ * its sole argument and may optionally set preload(), setup(), and/or
+ * draw() properties on it for running a sketch.
+ *
+ * A p5 sketch can run in "global" or "instance" mode:
+ * "global" - all properties and methods are attached to the window
+ * "instance" - all properties and methods are bound to this p5 object
+ *
+ * @param {Function} sketch a closure that can set optional preload(),
+ * setup(), and/or draw() properties on the
+ * given p5 instance
+ * @param {HTMLElement|boolean} [node] element to attach canvas to, if a
+ * boolean is passed in use it as sync
+ * @param {boolean} [sync] start synchronously (optional)
+ * @return {p5} a p5 instance
+ */
+var p5 = function(sketch, node, sync) {
+
+ if (arguments.length === 2 && typeof node === 'boolean') {
+ sync = node;
+ node = undefined;
+ }
+
+ //////////////////////////////////////////////
+ // PUBLIC p5 PROPERTIES AND METHODS
+ //////////////////////////////////////////////
+
+
+ /**
+ * Called directly before setup(), the preload() function is used to handle
+ * asynchronous loading of external files. If a preload function is
+ * defined, setup() will wait until any load calls within have finished.
+ * Nothing besides load calls should be inside preload (loadImage,
+ * loadJSON, loadFont, loadStrings, etc).
+ * By default the text "loading..." will be displayed. To make your own
+ * loading page, include an HTML element with id "p5_loading" in your
+ * page. More information here.
+ *
+ * @method preload
+ * @example
+ *
+ * var img;
+ * var c;
+ * function preload() { // preload() runs once
+ * img = loadImage('assets/laDefense.jpg');
+ * }
+ *
+ * function setup() { // setup() waits until preload() is done
+ * img.loadPixels();
+ * // get color of middle pixel
+ * c = img.get(img.width/2, img.height/2);
+ * }
+ *
+ * function draw() {
+ * background(c);
+ * image(img, 25, 25, 50, 50);
+ * }
+ *
+ *
+ * @alt
+ * nothing displayed
+ *
+ */
+
+ /**
+ * The setup() function is called once when the program starts. It's used to
+ * define initial environment properties such as screen size and background
+ * color and to load media such as images and fonts as the program starts.
+ * There can only be one setup() function for each program and it shouldn't
+ * be called again after its initial execution.
+ *
+ * Note: Variables declared within setup() are not accessible within other
+ * functions, including draw().
+ *
+ * @method setup
+ * @example
+ *
+ *
+ * @alt
+ * nothing displayed
+ *
+ */
+
+ /**
+ * Called directly after setup(), the draw() function continuously executes
+ * the lines of code contained inside its block until the program is stopped
+ * or noLoop() is called. Note if noLoop() is called in setup(), draw() will
+ * still be executed once before stopping. draw() is called automatically and
+ * should never be called explicitly.
+ *
+ * It should always be controlled with noLoop(), redraw() and loop(). After
+ * noLoop() stops the code in draw() from executing, redraw() causes the
+ * code inside draw() to execute once, and loop() will cause the code
+ * inside draw() to resume executing continuously.
+ *
+ * The number of times draw() executes in each second may be controlled with
+ * the frameRate() function.
+ *
+ * There can only be one draw() function for each sketch, and draw() must
+ * exist if you want the code to run continuously, or to process events such
+ * as mousePressed(). Sometimes, you might have an empty call to draw() in
+ * your program, as shown in the above example.
+ *
+ * It is important to note that the drawing coordinate system will be reset
+ * at the beginning of each draw() call. If any transformations are performed
+ * within draw() (ex: scale, rotate, translate, their effects will be
+ * undone at the beginning of draw(), so transformations will not accumulate
+ * over time. On the other hand, styling applied (ex: fill, stroke, etc) will
+ * remain in effect.
+ *
+ * @method draw
+ * @example
+ *
+ *
+ * @alt
+ * nothing displayed
+ *
+ */
+ this.remove = function() {
+ if (this._curElement) {
+
+ // stop draw
+ this._loop = false;
+ if (this._requestAnimId) {
+ window.cancelAnimationFrame(this._requestAnimId);
+ }
+
+ // unregister events sketch-wide
+ for (var ev in this._events) {
+ window.removeEventListener(ev, this._events[ev]);
+ }
+
+ // remove DOM elements created by p5, and listeners
+ for (var i=0; i Bezier curves were developed by French
+ * automotive engineer Pierre Bezier, and are commonly used in computer
+ * graphics to define gently sloping curves. See also curve().
+ *
+ * @method bezier
+ * @param {Number} x1 x-coordinate for the first anchor point
+ * @param {Number} y1 y-coordinate for the first anchor point
+ * @param {Number} x2 x-coordinate for the first control point
+ * @param {Number} y2 y-coordinate for the first control point
+ * @param {Number} x3 x-coordinate for the second control point
+ * @param {Number} y3 y-coordinate for the second control point
+ * @param {Number} x4 x-coordinate for the second anchor point
+ * @param {Number} y4 y-coordinate for the second anchor point
+ * @return {Object} the p5 object
+ * @example
+ *
+ * @alt
+ * stretched black s-shape in center with orange lines extending from end points.
+ * stretched black s-shape with 10 5x5 white ellipses along the shape.
+ * stretched black s-shape with 7 5x5 ellipses and orange lines along the shape.
+ * stretched black s-shape with 17 small orange lines extending from under shape.
+ * horseshoe shape with orange ends facing left and black curved center.
+ * horseshoe shape with orange ends facing left and black curved center.
+ * Line shaped like right-facing arrow,points move with mouse-x and warp shape.
+ * horizontal line that hooks downward on the right and 13 5x5 ellipses along it.
+ * right curving line mid-right of canvas with 7 short lines radiating from it.
+ */
+/**
+ * @method bezier
+ * @param {Number} z1 z-coordinate for the first anchor point
+ * @param {Number} z2 z-coordinate for the first control point
+ * @param {Number} z3 z-coordinate for the first anchor point
+ * @param {Number} z4 z-coordinate for the first control point
+ * @return {p5.Renderer3D} [description]
+ * @example
+ *
+ *
+ * @alt
+ * stretched black s-shape with 7 5x5 ellipses and orange lines along the shape.
+ *
+ */
+p5.prototype.bezierDetail = function(d) {
+ bezierDetail = d;
+ return this;
+};
+
+/**
+ * Evaluates the Bezier at position t for points a, b, c, d.
+ * The parameters a and d are the first and last points
+ * on the curve, and b and c are the control points.
+ * The final parameter t varies between 0 and 1.
+ * This can be done once with the x coordinates and a second time
+ * with the y coordinates to get the location of a bezier curve at t.
+ *
+ * @method bezierPoint
+ * @param {Number} a coordinate of first point on the curve
+ * @param {Number} b coordinate of first control point
+ * @param {Number} c coordinate of second control point
+ * @param {Number} d coordinate of second point on the curve
+ * @param {Number} t value between 0 and 1
+ * @return {Number} the value of the Bezier at position t
+ * @example
+ *
+ *
+ * @alt
+ * stretched black s-shape with 17 small orange lines extending from under shape.
+ *
+ */
+p5.prototype.bezierPoint = function(a, b, c, d, t) {
+ var adjustedT = 1-t;
+ return Math.pow(adjustedT,3)*a +
+ 3*(Math.pow(adjustedT,2))*t*b +
+ 3*adjustedT*Math.pow(t,2)*c +
+ Math.pow(t,3)*d;
+};
+
+/**
+ * Evaluates the tangent to the Bezier at position t for points a, b, c, d.
+ * The parameters a and d are the first and last points
+ * on the curve, and b and c are the control points.
+ * The final parameter t varies between 0 and 1.
+ *
+ * @method bezierTangent
+ * @param {Number} a coordinate of first point on the curve
+ * @param {Number} b coordinate of first control point
+ * @param {Number} c coordinate of second control point
+ * @param {Number} d coordinate of second point on the curve
+ * @param {Number} t value between 0 and 1
+ * @return {Number} the tangent at position t
+ * @example
+ *
+ *
+ * noFill();
+ * bezier(85, 20, 10, 10, 90, 90, 15, 80);
+ * steps = 6;
+ * fill(255);
+ * for (i = 0; i <= steps; i++) {
+ * t = i / steps;
+ * // Get the location of the point
+ * x = bezierPoint(85, 10, 90, 15, t);
+ * y = bezierPoint(20, 10, 90, 80, t);
+ * // Get the tangent points
+ * tx = bezierTangent(85, 10, 90, 15, t);
+ * ty = bezierTangent(20, 10, 90, 80, t);
+ * // Calculate an angle from the tangent points
+ * a = atan2(ty, tx);
+ * a += PI;
+ * stroke(255, 102, 0);
+ * line(x, y, cos(a)*30 + x, sin(a)*30 + y);
+ * // The following line of code makes a line
+ * // inverse of the above line
+ * //line(x, y, cos(a)*-30 + x, sin(a)*-30 + y);
+ * stroke(0);
+ * ellipse(x, y, 5, 5);
+ * }
+ *
+ *
+ *
+ *
+ *
+ * noFill();
+ * bezier(85, 20, 10, 10, 90, 90, 15, 80);
+ * stroke(255, 102, 0);
+ * steps = 16;
+ * for (i = 0; i <= steps; i++) {
+ * t = i / steps;
+ * x = bezierPoint(85, 10, 90, 15, t);
+ * y = bezierPoint(20, 10, 90, 80, t);
+ * tx = bezierTangent(85, 10, 90, 15, t);
+ * ty = bezierTangent(20, 10, 90, 80, t);
+ * a = atan2(ty, tx);
+ * a -= HALF_PI;
+ * line(x, y, cos(a)*8 + x, sin(a)*8 + y);
+ * }
+ *
+ *
+ *
+ * @alt
+ * s-shaped line with 17 short orange lines extending from underside of shape
+ *
+ */
+p5.prototype.bezierTangent = function(a, b, c, d, t) {
+ var adjustedT = 1-t;
+ return 3*d*Math.pow(t,2) -
+ 3*c*Math.pow(t,2) +
+ 6*c*adjustedT*t -
+ 6*b*adjustedT*t +
+ 3*b*Math.pow(adjustedT,2) -
+ 3*a*Math.pow(adjustedT,2);
+};
+
+/**
+ * Draws a curved line on the screen between two points, given as the
+ * middle four parameters. The first two parameters are a control point, as
+ * if the curve came from this point even though it's not drawn. The last
+ * two parameters similarly describe the other control point.
+ * Longer curves can be created by putting a series of curve() functions
+ * together or using curveVertex(). An additional function called
+ * curveTightness() provides control for the visual quality of the curve.
+ * The curve() function is an implementation of Catmull-Rom splines.
+ *
+ * @method curve
+ * @param {Number} x1 x-coordinate for the beginning control point
+ * @param {Number} y1 y-coordinate for the beginning control point
+ * @param {Number} x2 x-coordinate for the first point
+ * @param {Number} y2 y-coordinate for the first point
+ * @param {Number} x3 x-coordinate for the second point
+ * @param {Number} y3 y-coordinate for the second point
+ * @param {Number} x4 x-coordinate for the ending control point
+ * @param {Number} y4 y-coordinate for the ending control point
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * horseshoe shape with orange ends facing left and black curved center.
+ * horseshoe shape with orange ends facing left and black curved center.
+ *
+ */
+/**
+ * @method curve
+ * @param {Number} z1 z-coordinate for the beginning control point
+ * @param {Number} z2 z-coordinate for the first point
+ * @param {Number} z3 z-coordinate for the second point
+ * @param {Number} z4 z-coordinate for the ending control point
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * white arch shape in top-mid canvas.
+ *
+ */
+p5.prototype.curveDetail = function(d) {
+ curveDetail = d;
+ return this;
+};
+
+/**
+ * Modifies the quality of forms created with curve() and curveVertex().
+ * The parameter tightness determines how the curve fits to the vertex
+ * points. The value 0.0 is the default value for tightness (this value
+ * defines the curves to be Catmull-Rom splines) and the value 1.0 connects
+ * all the points with straight lines. Values within the range -5.0 and 5.0
+ * will deform the curves but will leave them recognizable and as values
+ * increase in magnitude, they will continue to deform.
+ *
+ * @method curveTightness
+ * @param {Number} amount of deformation from the original vertices
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * // Move the mouse left and right to see the curve change
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ * noFill();
+ * }
+ *
+ * function draw() {
+ * background(204);
+ * var t = map(mouseX, 0, width, -5, 5);
+ * curveTightness(t);
+ * beginShape();
+ * curveVertex(10, 26);
+ * curveVertex(10, 26);
+ * curveVertex(83, 24);
+ * curveVertex(83, 61);
+ * curveVertex(25, 65);
+ * curveVertex(25, 65);
+ * endShape();
+ * }
+ *
+ *
+ *
+ * @alt
+ * Line shaped like right-facing arrow,points move with mouse-x and warp shape.
+ */
+p5.prototype.curveTightness = function (t) {
+ this._renderer._curveTightness = t;
+};
+
+/**
+ * Evaluates the curve at position t for points a, b, c, d.
+ * The parameter t varies between 0 and 1, a and d are points
+ * on the curve, and b and c are the control points.
+ * This can be done once with the x coordinates and a second time
+ * with the y coordinates to get the location of a curve at t.
+ *
+ * @method curvePoint
+ * @param {Number} a coordinate of first point on the curve
+ * @param {Number} b coordinate of first control point
+ * @param {Number} c coordinate of second control point
+ * @param {Number} d coordinate of second point on the curve
+ * @param {Number} t value between 0 and 1
+ * @return {Number} bezier value at position t
+ * @example
+ *
+ *
+ * noFill();
+ * curve(5, 26, 5, 26, 73, 24, 73, 61);
+ * curve(5, 26, 73, 24, 73, 61, 15, 65);
+ * fill(255);
+ * ellipseMode(CENTER);
+ * steps = 6;
+ * for (i = 0; i <= steps; i++) {
+ * t = i / steps;
+ * x = curvePoint(5, 5, 73, 73, t);
+ * y = curvePoint(26, 26, 24, 61, t);
+ * ellipse(x, y, 5, 5);
+ * x = curvePoint(5, 73, 73, 15, t);
+ * y = curvePoint(26, 24, 61, 65, t);
+ * ellipse(x, y, 5, 5);
+ * }
+ *
+ *
+ *
+ *line hooking down to right-bottom with 13 5x5 white ellipse points
+ */
+p5.prototype.curvePoint = function(a, b, c, d, t) {
+ var t3 = t*t*t,
+ t2 = t*t,
+ f1 = -0.5 * t3 + t2 - 0.5 * t,
+ f2 = 1.5 * t3 - 2.5 * t2 + 1.0,
+ f3 = -1.5 * t3 + 2.0 * t2 + 0.5 * t,
+ f4 = 0.5 * t3 - 0.5 * t2;
+ return a*f1 + b*f2 + c*f3 + d*f4;
+};
+
+/**
+ * Evaluates the tangent to the curve at position t for points a, b, c, d.
+ * The parameter t varies between 0 and 1, a and d are points on the curve,
+ * and b and c are the control points.
+ *
+ * @method curveTangent
+ * @param {Number} a coordinate of first point on the curve
+ * @param {Number} b coordinate of first control point
+ * @param {Number} c coordinate of second control point
+ * @param {Number} d coordinate of second point on the curve
+ * @param {Number} t value between 0 and 1
+ * @return {Number} the tangent at position t
+ * @example
+ *
+ *
+ * noFill();
+ * curve(5, 26, 73, 24, 73, 61, 15, 65);
+ * steps = 6;
+ * for (i = 0; i <= steps; i++) {
+ * t = i / steps;
+ * x = curvePoint(5, 73, 73, 15, t);
+ * y = curvePoint(26, 24, 61, 65, t);
+ * //ellipse(x, y, 5, 5);
+ * tx = curveTangent(5, 73, 73, 15, t);
+ * ty = curveTangent(26, 24, 61, 65, t);
+ * a = atan2(ty, tx);
+ * a -= PI/2.0;
+ * line(x, y, cos(a)*8 + x, sin(a)*8 + y);
+ * }
+ *
+ *
+ *
+ * @alt
+ *right curving line mid-right of canvas with 7 short lines radiating from it.
+ */
+p5.prototype.curveTangent = function(a, b,c, d, t) {
+ var t2 = t*t,
+ f1 = (-3*t2)/2 + 2*t - 0.5,
+ f2 = (9*t2)/2 - 5*t,
+ f3 = (-9*t2)/2 + 4*t + 0.5,
+ f4 = (3*t2)/2 - t;
+ return a*f1 + b*f2 + c*f3 + d*f4;
+};
+
+module.exports = p5;
+
+},{"./core":42,"./error_helpers":45}],44:[function(_dereq_,module,exports){
+/**
+ * @module Environment
+ * @submodule Environment
+ * @for p5
+ * @requires core
+ * @requires constants
+ */
+
+'use strict';
+
+var p5 = _dereq_('./core');
+var C = _dereq_('./constants');
+
+var standardCursors = [C.ARROW, C.CROSS, C.HAND, C.MOVE, C.TEXT, C.WAIT];
+
+p5.prototype._frameRate = 0;
+p5.prototype._lastFrameTime = window.performance.now();
+p5.prototype._targetFrameRate = 60;
+
+var _windowPrint = window.print;
+
+
+if (window.console && console.log) {
+ /**
+ * The print() function writes to the console area of your browser.
+ * This function is often helpful for looking at the data a program is
+ * producing. This function creates a new line of text for each call to
+ * the function. Individual elements can be
+ * separated with quotes ("") and joined with the addition operator (+).
+ *
+ * While print() is similar to console.log(), it does not directly map to
+ * it in order to simulate easier to understand behavior than
+ * console.log(). Due to this, it is slower. For fastest results, use
+ * console.log().
+ *
+ * @method print
+ * @param {Any} contents any combination of Number, String, Object, Boolean,
+ * Array to print
+ * @example
+ *
+ * var x = 10;
+ * print("The value of x is " + x);
+ * // prints "The value of x is 10"
+ *
+ * @alt
+ * default grey canvas
+ */
+ // Converts passed args into a string and then parses that string to
+ // simulate synchronous behavior. This is a hack and is gross.
+ // Since this will not work on all objects, particularly circular
+ // structures, simply console.log() on error.
+ p5.prototype.print = function(args) {
+ try {
+ if (arguments.length === 0) {
+ _windowPrint();
+ }
+ else if (arguments.length > 1) {
+ console.log.apply(console, arguments);
+ } else {
+ var newArgs = JSON.parse(JSON.stringify(args));
+ console.log(newArgs);
+ }
+ } catch(err) {
+ console.log(args);
+ }
+ };
+} else {
+ p5.prototype.print = function() {};
+}
+
+
+/**
+ * The system variable frameCount contains the number of frames that have
+ * been displayed since the program started. Inside setup() the value is 0,
+ * after the first iteration of draw it is 1, etc.
+ *
+ * @property frameCount
+ * @example
+ *
+ *
+ * @alt
+ * numbers rapidly counting upward with frame count set to 30.
+ *
+ */
+p5.prototype.frameCount = 0;
+
+/**
+ * Confirms if the window a p5.js program is in is "focused," meaning that
+ * the sketch will accept mouse or keyboard input. This variable is
+ * "true" if the window is focused and "false" if not.
+ *
+ * @property focused
+ * @example
+ *
+ * // To demonstrate, put two windows side by side.
+ * // Click on the window that the p5 sketch isn't in!
+ * function draw() {
+ * background(200);
+ * noStroke();
+ * fill(0, 200, 0);
+ * ellipse(25, 25, 50, 50);
+ *
+ * if (!focused) { // or "if (focused === false)"
+ * stroke(200,0,0);
+ * line(0, 0, 100, 100);
+ * line(100, 0, 0, 100);
+ * }
+ * }
+ *
+ *
+ * @alt
+ * green 50x50 ellipse at top left. Red X covers canvas when page focus changes
+ *
+ */
+p5.prototype.focused = (document.hasFocus());
+
+/**
+ * Sets the cursor to a predefined symbol or an image, or makes it visible
+ * if already hidden. If you are trying to set an image as the cursor, the
+ * recommended size is 16x16 or 32x32 pixels. It is not possible to load an
+ * image as the cursor if you are exporting your program for the Web, and not
+ * all MODES work with all browsers. The values for parameters x and y must
+ * be less than the dimensions of the image.
+ *
+ * @method cursor
+ * @param {Number|Constant} type either ARROW, CROSS, HAND, MOVE, TEXT, or
+ * WAIT, or path for image
+ * @param {Number} [x] the horizontal active spot of the cursor
+ * @param {Number} [y] the vertical active spot of the cursor
+ * @example
+ *
+ * // Move the mouse left and right across the image
+ * // to see the cursor change from a cross to a hand
+ * function draw() {
+ * line(width/2, 0, width/2, height);
+ * if (mouseX < 50) {
+ * cursor(CROSS);
+ * } else {
+ * cursor(HAND);
+ * }
+ * }
+ *
+ *
+ * @alt
+ * horizontal line divides canvas. cursor on left is a cross, right is hand.
+ *
+ */
+p5.prototype.cursor = function(type, x, y) {
+ var cursor = 'auto';
+ var canvas = this._curElement.elt;
+ if (standardCursors.indexOf(type) > -1) {
+ // Standard css cursor
+ cursor = type;
+ } else if (typeof type === 'string') {
+ var coords = '';
+ if (x && y && (typeof x === 'number' && typeof y === 'number')) {
+ // Note that x and y values must be unit-less positive integers < 32
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
+ coords = x + ' ' + y;
+ }
+ if ((type.substring(0, 7) === 'http://') ||
+ (type.substring(0, 8) === 'https://')) {
+ // Image (absolute url)
+ cursor = 'url(' + type + ') ' + coords + ', auto';
+ } else if (/\.(cur|jpg|jpeg|gif|png|CUR|JPG|JPEG|GIF|PNG)$/.test(type)) {
+ // Image file (relative path) - Separated for performance reasons
+ cursor = 'url(' + type + ') ' + coords + ', auto';
+ } else {
+ // Any valid string for the css cursor property
+ cursor = type;
+ }
+ }
+ canvas.style.cursor = cursor;
+};
+
+/**
+ * Specifies the number of frames to be displayed every second. For example,
+ * the function call frameRate(30) will attempt to refresh 30 times a second.
+ * If the processor is not fast enough to maintain the specified rate, the
+ * frame rate will not be achieved. Setting the frame rate within setup() is
+ * recommended. The default rate is 60 frames per second. This is the same as
+ * setFrameRate(val).
+ *
+ * Calling frameRate() with no arguments returns the current framerate. The
+ * draw function must run at least once before it will return a value. This
+ * is the same as getFrameRate().
+ *
+ * Calling frameRate() with arguments that are not of the type numbers
+ * or are non positive also returns current framerate.
+ *
+ * @method frameRate
+ * @param {Number} [fps] number of frames to be displayed every second
+ * @return {Number} current frameRate
+ * @example
+ *
+ *
+ *
+ * @alt
+ * blue rect moves left to right, followed by red rect moving faster. Loops.
+ *
+ */
+p5.prototype.frameRate = function(fps) {
+ if (typeof fps !== 'number' || fps <= 0) {
+ return this._frameRate;
+ } else {
+ this._setProperty('_targetFrameRate', fps);
+ this._runFrames();
+ return this;
+ }
+};
+/**
+ * Returns the current framerate.
+ *
+ * @return {Number} current frameRate
+ */
+p5.prototype.getFrameRate = function() {
+ return this.frameRate();
+};
+
+/**
+ * Specifies the number of frames to be displayed every second. For example,
+ * the function call frameRate(30) will attempt to refresh 30 times a second.
+ * If the processor is not fast enough to maintain the specified rate, the
+ * frame rate will not be achieved. Setting the frame rate within setup() is
+ * recommended. The default rate is 60 frames per second.
+ *
+ * Calling frameRate() with no arguments returns the current framerate.
+ *
+ * @param {Number} [fps] number of frames to be displayed every second
+ */
+p5.prototype.setFrameRate = function(fps) {
+ return this.frameRate(fps);
+};
+
+/**
+ * Hides the cursor from view.
+ *
+ * @method noCursor
+ * @example
+ *
+ *
+ *
+ * @alt
+ * cursor becomes 10x 10 white ellipse the moves with mouse x and y.
+ *
+ */
+p5.prototype.noCursor = function() {
+ this._curElement.elt.style.cursor = 'none';
+};
+
+
+/**
+ * System variable that stores the width of the entire screen display. This
+ * is used to run a full-screen program on any display size.
+ *
+ * @property displayWidth
+ * @example
+ *
+ *
+ * @alt
+ * cursor becomes 10x 10 white ellipse the moves with mouse x and y.
+ *
+ */
+p5.prototype.displayWidth = screen.width;
+
+/**
+ * System variable that stores the height of the entire screen display. This
+ * is used to run a full-screen program on any display size.
+ *
+ * @property displayHeight
+ * @example
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.prototype.displayHeight = screen.height;
+
+/**
+ * System variable that stores the width of the inner window, it maps to
+ * window.innerWidth.
+ *
+ * @property windowWidth
+ * @example
+ *
+ * createCanvas(windowWidth, windowHeight);
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.prototype.windowWidth = getWindowWidth();
+/**
+ * System variable that stores the height of the inner window, it maps to
+ * window.innerHeight.
+ *
+ * @property windowHeight
+ * @example
+ *
+ * createCanvas(windowWidth, windowHeight);
+ *
+*@alt
+ * no display.
+ *
+*/
+p5.prototype.windowHeight = getWindowHeight();
+
+/**
+ * The windowResized() function is called once every time the browser window
+ * is resized. This is a good place to resize the canvas or do any other
+ * adjustments to accommodate the new window size.
+ *
+ * @method windowResized
+ * @example
+ *
+ * @alt
+ * no display.
+ */
+p5.prototype._onresize = function(e){
+ this._setProperty('windowWidth', getWindowWidth());
+ this._setProperty('windowHeight', getWindowHeight());
+ var context = this._isGlobal ? window : this;
+ var executeDefault;
+ if (typeof context.windowResized === 'function') {
+ executeDefault = context.windowResized(e);
+ if (executeDefault !== undefined && !executeDefault) {
+ e.preventDefault();
+ }
+ }
+};
+
+function getWindowWidth() {
+ return window.innerWidth ||
+ document.documentElement && document.documentElement.clientWidth ||
+ document.body && document.body.clientWidth ||
+ 0;
+}
+
+function getWindowHeight() {
+ return window.innerHeight ||
+ document.documentElement && document.documentElement.clientHeight ||
+ document.body && document.body.clientHeight ||
+ 0;
+}
+
+/**
+ * System variable that stores the width of the drawing canvas. This value
+ * is set by the first parameter of the createCanvas() function.
+ * For example, the function call createCanvas(320, 240) sets the width
+ * variable to the value 320. The value of width defaults to 100 if
+ * createCanvas() is not used in a program.
+ *
+ * @property width
+ */
+p5.prototype.width = 0;
+
+/**
+ * System variable that stores the height of the drawing canvas. This value
+ * is set by the second parameter of the createCanvas() function. For
+ * example, the function call createCanvas(320, 240) sets the height
+ * variable to the value 240. The value of height defaults to 100 if
+ * createCanvas() is not used in a program.
+ *
+ * @property height
+ */
+p5.prototype.height = 0;
+
+/**
+ * If argument is given, sets the sketch to fullscreen or not based on the
+ * value of the argument. If no argument is given, returns the current
+ * fullscreen state. Note that due to browser restrictions this can only
+ * be called on user input, for example, on mouse press like the example
+ * below.
+ *
+ * @method fullscreen
+ * @param {Boolean} [val] whether the sketch should be in fullscreen mode
+ * or not
+ * @return {Boolean} current fullscreen state
+ * @example
+ *
+ *
+ * // Clicking in the box toggles fullscreen on and off.
+ * function setup() {
+ * background(200);
+ * }
+ * function mousePressed() {
+ * if (mouseX > 0 && mouseX < 100 && mouseY > 0 && mouseY < 100) {
+ * var fs = fullscreen();
+ * fullscreen(!fs);
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.prototype.fullscreen = function(val) {
+ // no arguments, return fullscreen or not
+ if (typeof val === 'undefined') {
+ return document.fullscreenElement ||
+ document.webkitFullscreenElement ||
+ document.mozFullScreenElement ||
+ document.msFullscreenElement;
+ } else { // otherwise set to fullscreen or not
+ if (val) {
+ launchFullscreen(document.documentElement);
+ } else {
+ exitFullscreen();
+ }
+ }
+};
+
+/**
+ * Sets the pixel scaling for high pixel density displays. By default
+ * pixel density is set to match display density, call pixelDensity(1)
+ * to turn this off. Calling pixelDensity() with no arguments returns
+ * the current pixel density of the sketch.
+ *
+ *
+ * @method pixelDensity
+ * @param {Number} [val] whether or how much the sketch should scale
+ * @returns {Number} current pixel density of the sketch
+ * @example
+ *
+ *
+ * @alt
+ * fuzzy 50x50 white ellipse with black outline in center of canvas.
+ * sharp 50x50 white ellipse with black outline in center of canvas.
+ */
+p5.prototype.pixelDensity = function(val) {
+ if (typeof val === 'number') {
+ this._pixelDensity = val;
+ } else {
+ return this._pixelDensity;
+ }
+ this.resizeCanvas(this.width, this.height, true);
+};
+
+/**
+ * Returns the pixel density of the current display the sketch is running on.
+ *
+ * @method displayDensity
+ * @returns {Number} current pixel density of the display
+ * @example
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.prototype.getURLParams = function() {
+ var re = /[?&]([^&=]+)(?:[&=])([^&=]+)/gim;
+ var m;
+ var v={};
+ while ((m = re.exec(location.search)) != null) {
+ if (m.index === re.lastIndex) {
+ re.lastIndex++;
+ }
+ v[m[1]]=m[2];
+ }
+ return v;
+};
+
+module.exports = p5;
+
+},{"./constants":41,"./core":42}],45:[function(_dereq_,module,exports){
+/**
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('./core');
+var doFriendlyWelcome = false; // TEMP until we get it all working LM
+
+// -- Borrowed from jQuery 1.11.3 --
+var class2type = {};
+var toString = class2type.toString;
+var names = ['Boolean', 'Number', 'String', 'Function',
+ 'Array', 'Date', 'RegExp', 'Object', 'Error'];
+for (var n=0; n p5.js says: '+message+'%c'+
+ // '[https://github.com/processing/p5.js/wiki/Local-server]',
+ // 'background-color:' + color + ';color:#FFF;',
+ // 'background-color:transparent;color:' + color +';',
+ // 'background-color:' + color + ';color:#FFF;',
+ // 'background-color:transparent;color:' + color +';'
+ // );
+ // }
+ // else{
+ // console.log(
+ // '%c> p5.js says: '+message+'%c [http://p5js.org/reference/#p5/'+func+
+ // ']', 'background-color:' + color + ';color:#FFF;',
+ // 'background-color:transparent;color:' + color +';'
+ // );
+ // }
+}
+
+var errorCases = {
+ '0': {
+ fileType: 'image',
+ method: 'loadImage',
+ message: ' hosting the image online,'
+ },
+ '1': {
+ fileType: 'XML file',
+ method: 'loadXML'
+ },
+ '2': {
+ fileType: 'table file',
+ method: 'loadTable'
+ },
+ '3': {
+ fileType: 'text file',
+ method: 'loadStrings'
+ },
+ '4': {
+ fileType: 'font',
+ method: 'loadFont',
+ message: ' hosting the font online,'
+ },
+};
+p5._friendlyFileLoadError = function (errorType, filePath) {
+ var errorInfo = errorCases[ errorType ];
+ var message = 'It looks like there was a problem' +
+ ' loading your ' + errorInfo.fileType + '.' +
+ ' Try checking if the file path%c [' + filePath + '] %cis correct,' +
+ (errorInfo.message || '') + ' or running a local server.';
+ report(message, errorInfo.method, FILE_LOAD);
+};
+
+function friendlyWelcome() {
+ // p5.js brand - magenta: #ED225D
+ var astrixBgColor = 'transparent';
+ var astrixTxtColor = '#ED225D';
+ var welcomeBgColor = '#ED225D';
+ var welcomeTextColor = 'white';
+ console.log(
+ '%c _ \n'+
+ ' /\\| |/\\ \n'+
+ ' \\ ` \' / \n'+
+ ' / , . \\ \n'+
+ ' \\/|_|\\/ '+
+ '\n\n%c> p5.js says: Welcome! '+
+ 'This is your friendly debugger. ' +
+ 'To turn me off switch to using “p5.min.js”.',
+ 'background-color:'+astrixBgColor+';color:' + astrixTxtColor +';',
+ 'background-color:'+welcomeBgColor+';color:' + welcomeTextColor +';'
+ );
+}
+
+/**
+ * Prints out all the colors in the color pallete with white text.
+ * For color blindness testing.
+ */
+/* function testColors() {
+ var str = 'A box of biscuits, a box of mixed biscuits and a biscuit mixer';
+ report(str, 'print', '#ED225D'); // p5.js magenta
+ report(str, 'print', '#2D7BB6'); // p5.js blue
+ report(str, 'print', '#EE9900'); // p5.js orange
+ report(str, 'print', '#A67F59'); // p5.js light brown
+ report(str, 'print', '#704F21'); // p5.js gold
+ report(str, 'print', '#1CC581'); // auto cyan
+ report(str, 'print', '#FF6625'); // auto orange
+ report(str, 'print', '#79EB22'); // auto green
+ report(str, 'print', '#B40033'); // p5.js darkened magenta
+ report(str, 'print', '#084B7F'); // p5.js darkened blue
+ report(str, 'print', '#945F00'); // p5.js darkened orange
+ report(str, 'print', '#6B441D'); // p5.js darkened brown
+ report(str, 'print', '#2E1B00'); // p5.js darkened gold
+ report(str, 'print', '#008851'); // auto dark cyan
+ report(str, 'print', '#C83C00'); // auto dark orange
+ report(str, 'print', '#4DB200'); // auto dark green
+} */
+
+// This is a lazily-defined list of p5 symbols that may be
+// misused by beginners at top-level code, outside of setup/draw. We'd like
+// to detect these errors and help the user by suggesting they move them
+// into setup/draw.
+//
+// For more details, see https://github.com/processing/p5.js/issues/1121.
+var misusedAtTopLevelCode = null;
+var FAQ_URL = 'https://github.com/processing/p5.js/wiki/' +
+ 'Frequently-Asked-Questions' +
+ '#why-cant-i-assign-variables-using-p5-functions-and-' +
+ 'variables-before-setup';
+
+function defineMisusedAtTopLevelCode() {
+ var uniqueNamesFound = {};
+
+ var getSymbols = function(obj) {
+ return Object.getOwnPropertyNames(obj).filter(function(name) {
+ if (name[0] === '_') {
+ return false;
+ }
+ if (name in uniqueNamesFound) {
+ return false;
+ }
+
+ uniqueNamesFound[name] = true;
+
+ return true;
+ }).map(function(name) {
+ var type;
+
+ if (typeof(obj[name]) === 'function') {
+ type = 'function';
+ } else if (name === name.toUpperCase()) {
+ type = 'constant';
+ } else {
+ type = 'variable';
+ }
+
+ return {name: name, type: type};
+ });
+ };
+
+ misusedAtTopLevelCode = [].concat(
+ getSymbols(p5.prototype),
+ // At present, p5 only adds its constants to p5.prototype during
+ // construction, which may not have happened at the time a
+ // ReferenceError is thrown, so we'll manually add them to our list.
+ getSymbols(_dereq_('./constants'))
+ );
+
+ // This will ultimately ensure that we report the most specific error
+ // possible to the user, e.g. advising them about HALF_PI instead of PI
+ // when their code misuses the former.
+ misusedAtTopLevelCode.sort(function(a, b) {
+ return b.name.length - a.name.length;
+ });
+}
+
+function helpForMisusedAtTopLevelCode(e, log) {
+ if (!log) {
+ log = console.log.bind(console);
+ }
+
+ if (!misusedAtTopLevelCode) {
+ defineMisusedAtTopLevelCode();
+ }
+
+ // If we find that we're logging lots of false positives, we can
+ // uncomment the following code to avoid displaying anything if the
+ // user's code isn't likely to be using p5's global mode. (Note that
+ // setup/draw are more likely to be defined due to JS function hoisting.)
+ //
+ //if (!('setup' in window || 'draw' in window)) {
+ // return;
+ //}
+
+ misusedAtTopLevelCode.some(function(symbol) {
+ // Note that while just checking for the occurrence of the
+ // symbol name in the error message could result in false positives,
+ // a more rigorous test is difficult because different browsers
+ // log different messages, and the format of those messages may
+ // change over time.
+ //
+ // For example, if the user uses 'PI' in their code, it may result
+ // in any one of the following messages:
+ //
+ // * 'PI' is undefined (Microsoft Edge)
+ // * ReferenceError: PI is undefined (Firefox)
+ // * Uncaught ReferenceError: PI is not defined (Chrome)
+
+ if (e.message && e.message.match('\\W?'+symbol.name+'\\W') !== null) {
+ log('%cDid you just try to use p5.js\'s ' + symbol.name +
+ (symbol.type === 'function' ? '() ' : ' ') + symbol.type +
+ '? If so, you may want to ' +
+ 'move it into your sketch\'s setup() function.\n\n' +
+ 'For more details, see: ' + FAQ_URL,
+ 'color: #B40033' /* Dark magenta */);
+ return true;
+ }
+ });
+}
+
+// Exposing this primarily for unit testing.
+p5.prototype._helpForMisusedAtTopLevelCode = helpForMisusedAtTopLevelCode;
+
+if (document.readyState !== 'complete') {
+ window.addEventListener('error', helpForMisusedAtTopLevelCode, false);
+
+ // Our job is only to catch ReferenceErrors that are thrown when
+ // global (non-instance mode) p5 APIs are used at the top-level
+ // scope of a file, so we'll unbind our error listener now to make
+ // sure we don't log false positives later.
+ window.addEventListener('load', function() {
+ window.removeEventListener('error', helpForMisusedAtTopLevelCode, false);
+ });
+}
+
+module.exports = p5;
+
+},{"./constants":41,"./core":42}],46:[function(_dereq_,module,exports){
+/**
+ * @module DOM
+ * @submodule DOM
+ * @for p5.Element
+ */
+
+var p5 = _dereq_('./core');
+
+/**
+ * Base class for all elements added to a sketch, including canvas,
+ * graphics buffers, and other HTML elements. Methods in blue are
+ * included in the core functionality, methods in brown are added
+ * with the p5.dom
+ * library.
+ * It is not called directly, but p5.Element
+ * objects are created by calling createCanvas, createGraphics,
+ * or in the p5.dom library, createDiv, createImg, createInput, etc.
+ *
+ * @class p5.Element
+ * @constructor
+ * @param {String} elt DOM node that is wrapped
+ * @param {Object} [pInst] pointer to p5 instance
+ */
+p5.Element = function(elt, pInst) {
+ /**
+ * Underlying HTML element. All normal HTML methods can be called on this.
+ *
+ * @property elt
+ */
+ this.elt = elt;
+ this._pInst = pInst;
+ this._events = {};
+ this.width = this.elt.offsetWidth;
+ this.height = this.elt.offsetHeight;
+};
+
+/**
+ *
+ * Attaches the element to the parent specified. A way of setting
+ * the container for the element. Accepts either a string ID, DOM
+ * node, or p5.Element. If no arguments given, parent node is returned.
+ * For more ways to position the canvas, see the
+ *
+ * positioning the canvas wiki page.
+ *
+ * @method parent
+ * @param {String|Object} parent the ID, DOM node, or p5.Element
+ * of desired parent element
+ * @return {p5.Element}
+ * @example
+ *
+ * // in the html file:
+ * <div id="myContainer"></div>
+ * // in the js file:
+ * var cnv = createCanvas(100, 100);
+ * cnv.parent("myContainer");
+ *
+ *
+ * var div0 = createDiv('this is the parent');
+ * var div1 = createDiv('this is the child');
+ * div1.parent(div0); // use p5.Element
+ *
+ *
+ * var div0 = createDiv('this is the parent');
+ * div0.id('apples');
+ * var div1 = createDiv('this is the child');
+ * div1.parent('apples'); // use id
+ *
+ *
+ * var elt = document.getElementById('myParentDiv');
+ * var div1 = createDiv('this is the child');
+ * div1.parent(elt); // use element from page
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.parent = function(p) {
+ if (arguments.length === 0){
+ return this.elt.parentNode;
+ } else {
+ if (typeof p === 'string') {
+ if (p[0] === '#') {
+ p = p.substring(1);
+ }
+ p = document.getElementById(p);
+ } else if (p instanceof p5.Element) {
+ p = p.elt;
+ }
+ p.appendChild(this.elt);
+ return this;
+ }
+};
+
+/**
+ *
+ * Sets the ID of the element. If no ID argument is passed in, it instead
+ * returns the current ID of the element.
+ *
+ * @method id
+ * @param {String} [id] ID of the element
+ * @return {p5.Element|String}
+ * @example
+ *
+ * function setup() {
+ * var cnv = createCanvas(100, 100);
+ * // Assigns a CSS selector ID to
+ * // the canvas element.
+ * cnv.id("mycanvas");
+ * }
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.id = function(id) {
+ if (arguments.length === 0) {
+ return this.elt.id;
+ } else {
+ this.elt.id = id;
+ this.width = this.elt.offsetWidth;
+ this.height = this.elt.offsetHeight;
+ return this;
+ }
+};
+
+/**
+ *
+ * Adds given class to the element. If no class argument is passed in, it
+ * instead returns a string containing the current class(es) of the element.
+ *
+ * @method class
+ * @param {String} [class] class to add
+ * @return {p5.Element|String}
+ */
+p5.Element.prototype.class = function(c) {
+ if (arguments.length === 0) {
+ return this.elt.className;
+ } else {
+ this.elt.className = c;
+ return this;
+ }
+};
+
+/**
+ * The .mousePressed() function is called once after every time a
+ * mouse button is pressed over the element. This can be used to
+ * attach element specific event listeners.
+ *
+ * @method mousePressed
+ * @param {Function} fxn function to be fired when mouse is
+ * pressed over the element.
+ * @return {p5.Element}
+ * @example
+ *
+ * var cnv;
+ * var d;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.mousePressed(changeGray); // attach listener for
+ * // canvas click only
+ * d = 10;
+ * g = 100;
+ * }
+ *
+ * function draw() {
+ * background(g);
+ * ellipse(width/2, height/2, d, d);
+ * }
+ *
+ * // this function fires with any click anywhere
+ * function mousePressed() {
+ * d = d + 10;
+ * }
+ *
+ * // this function fires only when cnv is clicked
+ * function changeGray() {
+ * g = random(0, 255);
+ * }
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.mousePressed = function (fxn) {
+ attachListener('mousedown', fxn, this);
+ attachListener('touchstart', fxn, this);
+ return this;
+};
+
+/**
+ * The .mouseWheel() function is called once after every time a
+ * mouse wheel is scrolled over the element. This can be used to
+ * attach element specific event listeners.
+ *
+ * The function accepts a callback function as argument which will be executed
+ * when the `wheel` event is triggered on the element, the callabck function is
+ * passed one argument `event`. The `event.deltaY` property returns negative
+ * values if the mouse wheel is rotated up or away from the user and positive
+ * in the other direction. The `event.deltaX` does the same as `event.deltaY`
+ * except it reads the horizontal wheel scroll of the mouse wheel.
+ *
+ * On OS X with "natural" scrolling enabled, the `event.deltaY` values are
+ * reversed.
+ *
+ * @method mouseWheel
+ * @param {Function} fxn function to be fired when mouse wheel is
+ * scrolled over the element.
+ * @return {p5.Element}
+ * @example
+ *
+ * var cnv;
+ * var d;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.mouseWheel(changeSize); // attach listener for
+ * // activity on canvas only
+ * d = 10;
+ * g = 100;
+ * }
+ *
+ * function draw() {
+ * background(g);
+ * ellipse(width/2, height/2, d, d);
+ * }
+ *
+ * // this function fires with mousewheel movement
+ * // anywhere on screen
+ * function mouseWheel() {
+ * g = g + 10;
+ * }
+ *
+ * // this function fires with mousewheel movement
+ * // over canvas only
+ * function changeSize(event) {
+ * if (event.deltaY > 0) {
+ * d = d + 10;
+ * } else {
+ * d = d - 10;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.mouseWheel = function (fxn) {
+ attachListener('wheel', fxn, this);
+ return this;
+};
+
+/**
+ * The .mouseReleased() function is called once after every time a
+ * mouse button is released over the element. This can be used to
+ * attach element specific event listeners.
+ *
+ * @method mouseReleased
+ * @param {Function} fxn function to be fired when mouse is
+ * released over the element.
+ * @return {p5.Element}
+ * @example
+ *
+ * var cnv;
+ * var d;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.mouseReleased(changeGray); // attach listener for
+ * // activity on canvas only
+ * d = 10;
+ * g = 100;
+ * }
+ *
+ * function draw() {
+ * background(g);
+ * ellipse(width/2, height/2, d, d);
+ * }
+ *
+ * // this function fires after the mouse has been
+ * // released
+ * function mouseReleased() {
+ * d = d + 10;
+ * }
+ *
+ * // this function fires after the mouse has been
+ * // released while on canvas
+ * function changeGray() {
+ * g = random(0, 255);
+ * }
+ *
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.mouseReleased = function (fxn) {
+ attachListener('mouseup', fxn, this);
+ attachListener('touchend', fxn, this);
+ return this;
+};
+
+
+/**
+ * The .mouseClicked() function is called once after a mouse button is
+ * pressed and released over the element. This can be used to
+ * attach element specific event listeners.
+ *
+ * @method mouseClicked
+ * @param {Function} fxn function to be fired when mouse is
+ * clicked over the element.
+ * @return {p5.Element}
+ * @example
+ * var cnv;
+ * var d;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.mouseClicked(changeGray); // attach listener for
+ * // activity on canvas only
+ * d = 10;
+ * g = 100;
+ * }
+ *
+ * function draw() {
+ * background(g);
+ * ellipse(width/2, height/2, d, d);
+ * }
+ *
+ * // this function fires after the mouse has been
+ * // clicked anywhere
+ * function mouseClicked() {
+ * d = d + 10;
+ * }
+ *
+ * // this function fires after the mouse has been
+ * // clicked on canvas
+ * function changeGray() {
+ * g = random(0, 255);
+ * }
+ *
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.mouseClicked = function (fxn) {
+ attachListener('click', fxn, this);
+ return this;
+};
+
+/**
+ * The .mouseMoved() function is called once every time a
+ * mouse moves over the element. This can be used to attach an
+ * element specific event listener.
+ *
+ * @method mouseMoved
+ * @param {Function} fxn function to be fired when mouse is
+ * moved over the element.
+ * @return {p5.Element}
+ * @example
+ *
+ * var cnv;
+ * var d = 30;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.mouseMoved(changeSize); // attach listener for
+ * // activity on canvas only
+ * d = 10;
+ * g = 100;
+ * }
+ *
+ * function draw() {
+ * background(g);
+ * fill(200);
+ * ellipse(width/2, height/2, d, d);
+ * }
+ *
+ * // this function fires when mouse moves anywhere on
+ * // page
+ * function mouseMoved() {
+ * g = g + 5;
+ * if (g > 255) {
+ * g = 0;
+ * }
+ * }
+ *
+ * // this function fires when mouse moves over canvas
+ * function changeSize() {
+ * d = d + 2;
+ * if (d > 100) {
+ * d = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.mouseMoved = function (fxn) {
+ attachListener('mousemove', fxn, this);
+ attachListener('touchmove', fxn, this);
+ return this;
+};
+
+/**
+ * The .mouseOver() function is called once after every time a
+ * mouse moves onto the element. This can be used to attach an
+ * element specific event listener.
+ *
+ * @method mouseOver
+ * @param {Function} fxn function to be fired when mouse is
+ * moved over the element.
+ * @return {p5.Element}
+ * @example
+ *
+ * var cnv;
+ * var d;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.mouseOver(changeGray);
+ * d = 10;
+ * }
+ *
+ * function draw() {
+ * ellipse(width/2, height/2, d, d);
+ * }
+ *
+ * function changeGray() {
+ * d = d + 10;
+ * if (d > 100) {
+ * d = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.mouseOver = function (fxn) {
+ attachListener('mouseover', fxn, this);
+ return this;
+};
+
+
+/**
+ * The .changed() function is called when the value of an
+ * element is changed.
+ * This can be used to attach an element specific event listener.
+ *
+ * @method changed
+ * @param {Function} fxn function to be fired when the value of an
+ * element changes.
+ * @return {p5.Element}
+ * @example
+ *
+ *
+ * @alt
+ * dropdown: pear, kiwi, grape. When selected text "its a" + selection shown.
+ *
+ */
+p5.Element.prototype.changed = function (fxn) {
+ attachListener('change', fxn, this);
+ return this;
+};
+
+/**
+ * The .input() function is called when any user input is
+ * detected with an element. The input event is often used
+ * to detect keystrokes in a input element, or changes on a
+ * slider element. This can be used to attach an element specific
+ * event listener.
+ *
+ * @method input
+ * @param {Function} fxn function to be fired on user input.
+ * @return {p5.Element}
+ * @example
+ *
+ * // Open your console to see the output
+ * function setup() {
+ * var inp = createInput('');
+ * inp.input(myInputEvent);
+ * }
+ *
+ * function myInputEvent() {
+ * console.log('you are typing: ', this.value());
+ * }
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.input = function (fxn) {
+ attachListener('input', fxn, this);
+ return this;
+};
+
+/**
+ * The .mouseOut() function is called once after every time a
+ * mouse moves off the element. This can be used to attach an
+ * element specific event listener.
+ *
+ * @method mouseOut
+ * @param {Function} fxn function to be fired when mouse is
+ * moved off the element.
+ * @return {p5.Element}
+ * @example
+ *
+ * var cnv;
+ * var d;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.mouseOut(changeGray);
+ * d = 10;
+ * }
+ *
+ * function draw() {
+ * ellipse(width/2, height/2, d, d);
+ * }
+ *
+ * function changeGray() {
+ * d = d + 10;
+ * if (d > 100) {
+ * d = 0;
+ * }
+ * }
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.mouseOut = function (fxn) {
+ attachListener('mouseout', fxn, this);
+ return this;
+};
+
+/**
+ * The .touchStarted() function is called once after every time a touch is
+ * registered. This can be used to attach element specific event listeners.
+ *
+ * @method touchStarted
+ * @param {Function} fxn function to be fired when touch is
+ * started over the element.
+ * @return {p5.Element}
+ * @example
+ *
+ * var cnv;
+ * var d;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.touchStarted(changeGray); // attach listener for
+ * // canvas click only
+ * d = 10;
+ * g = 100;
+ * }
+ *
+ * function draw() {
+ * background(g);
+ * ellipse(width/2, height/2, d, d);
+ * }
+ *
+ * // this function fires with any touch anywhere
+ * function touchStarted() {
+ * d = d + 10;
+ * }
+ *
+ * // this function fires only when cnv is clicked
+ * function changeGray() {
+ * g = random(0, 255);
+ * }
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.touchStarted = function (fxn) {
+ attachListener('touchstart', fxn, this);
+ attachListener('mousedown', fxn, this);
+ return this;
+};
+
+/**
+ * The .touchMoved() function is called once after every time a touch move is
+ * registered. This can be used to attach element specific event listeners.
+ *
+ * @method touchMoved
+ * @param {Function} fxn function to be fired when touch is moved
+ * over the element.
+ * @return {p5.Element}
+ * @example
+ *
+ * var cnv;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.touchMoved(changeGray); // attach listener for
+ * // canvas click only
+ * g = 100;
+ * }
+ *
+ * function draw() {
+ * background(g);
+ * }
+ *
+ * // this function fires only when cnv is clicked
+ * function changeGray() {
+ * g = random(0, 255);
+ * }
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.touchMoved = function (fxn) {
+ attachListener('touchmove', fxn, this);
+ attachListener('mousemove', fxn, this);
+ return this;
+};
+
+/**
+ * The .touchEnded() function is called once after every time a touch is
+ * registered. This can be used to attach element specific event listeners.
+ *
+ * @method touchEnded
+ * @param {Function} fxn function to be fired when touch is
+ * ended over the element.
+ * @return {p5.Element}
+ * @example
+ *
+ * var cnv;
+ * var d;
+ * var g;
+ * function setup() {
+ * cnv = createCanvas(100, 100);
+ * cnv.touchEnded(changeGray); // attach listener for
+ * // canvas click only
+ * d = 10;
+ * g = 100;
+ * }
+ *
+ * function draw() {
+ * background(g);
+ * ellipse(width/2, height/2, d, d);
+ * }
+ *
+ * // this function fires with any touch anywhere
+ * function touchEnded() {
+ * d = d + 10;
+ * }
+ *
+ * // this function fires only when cnv is clicked
+ * function changeGray() {
+ * g = random(0, 255);
+ * }
+ *
+ *
+ *
+ * @alt
+ * no display.
+ *
+ */
+p5.Element.prototype.touchEnded = function (fxn) {
+ attachListener('touchend', fxn, this);
+ attachListener('mouseup', fxn, this);
+ return this;
+};
+
+
+
+/**
+ * The .dragOver() function is called once after every time a
+ * file is dragged over the element. This can be used to attach an
+ * element specific event listener.
+ *
+ * @method dragOver
+ * @param {Function} fxn function to be fired when mouse is
+ * dragged over the element.
+ * @return {p5.Element}
+ */
+p5.Element.prototype.dragOver = function (fxn) {
+ attachListener('dragover', fxn, this);
+ return this;
+};
+
+/**
+ * The .dragLeave() function is called once after every time a
+ * dragged file leaves the element area. This can be used to attach an
+ * element specific event listener.
+ *
+ * @method dragLeave
+ * @param {Function} fxn function to be fired when mouse is
+ * dragged over the element.
+ * @return {p5.Element}
+ */
+p5.Element.prototype.dragLeave = function (fxn) {
+ attachListener('dragleave', fxn, this);
+ return this;
+};
+
+/**
+ * The .drop() function is called for each file dropped on the element.
+ * It requires a callback that is passed a p5.File object. You can
+ * optionally pass two callbacks, the first one (required) is triggered
+ * for each file dropped when the file is loaded. The second (optional)
+ * is triggered just once when a file (or files) are dropped.
+ *
+ * @method drop
+ * @param {Function} callback callback triggered when files are dropped.
+ * @param {Function} fxn callback to receive loaded file.
+ * @return {p5.Element}
+ * @example
+ *
+ * function setup() {
+ * var c = createCanvas(100, 100);
+ * background(200);
+ * textAlign(CENTER);
+ * text('drop image', width/2, height/2);
+ * c.drop(gotFile);
+ * }
+ *
+ * function gotFile(file) {
+ * var img = createImg(file.data).hide();
+ * // Draw the image onto the canvas
+ * image(img, 0, 0, width, height);
+ * }
+ *
+ *
+ * @alt
+ * Canvas turns into whatever image is dragged/dropped onto it.
+ *
+ */
+p5.Element.prototype.drop = function (callback, fxn) {
+ // Make a file loader callback and trigger user's callback
+ function makeLoader(theFile) {
+ // Making a p5.File object
+ var p5file = new p5.File(theFile);
+ return function(e) {
+ p5file.data = e.target.result;
+ callback(p5file);
+ };
+ }
+
+ // Is the file stuff supported?
+ if (window.File && window.FileReader && window.FileList && window.Blob) {
+
+ // If you want to be able to drop you've got to turn off
+ // a lot of default behavior
+ attachListener('dragover',function(evt) {
+ evt.stopPropagation();
+ evt.preventDefault();
+ },this);
+
+ // If this is a drag area we need to turn off the default behavior
+ attachListener('dragleave',function(evt) {
+ evt.stopPropagation();
+ evt.preventDefault();
+ },this);
+
+ // If just one argument it's the callback for the files
+ if (arguments.length > 1) {
+ attachListener('drop', fxn, this);
+ }
+
+ // Deal with the files
+ attachListener('drop', function(evt) {
+
+ evt.stopPropagation();
+ evt.preventDefault();
+
+ // A FileList
+ var files = evt.dataTransfer.files;
+
+ // Load each one and trigger the callback
+ for (var i = 0; i < files.length; i++) {
+ var f = files[i];
+ var reader = new FileReader();
+ 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);
+ }
+ }
+ }, this);
+ } else {
+ console.log('The File APIs are not fully supported in this browser.');
+ }
+
+ return this;
+};
+
+
+
+
+function attachListener(ev, fxn, ctx) {
+ // LM removing, not sure why we had this?
+ // var _this = ctx;
+ // var f = function (e) { fxn(e, _this); };
+ var f = fxn.bind(ctx);
+ ctx.elt.addEventListener(ev, f, false);
+ ctx._events[ev] = f;
+}
+
+/**
+ * Helper fxn for sharing pixel methods
+ *
+ */
+p5.Element.prototype._setProperty = function (prop, value) {
+ this[prop] = value;
+};
+
+
+module.exports = p5.Element;
+
+},{"./core":42}],47:[function(_dereq_,module,exports){
+/**
+ * @module Rendering
+ * @submodule Rendering
+ * @for p5
+ */
+
+var p5 = _dereq_('./core');
+var constants = _dereq_('./constants');
+
+/**
+ * Thin wrapper around a renderer, to be used for creating a
+ * graphics buffer object. Use this class if you need
+ * to draw into an off-screen graphics buffer. The two parameters define the
+ * width and height in pixels. The fields and methods for this class are
+ * extensive, but mirror the normal drawing API for p5.
+ *
+ * @class p5.Graphics
+ * @constructor
+ * @extends p5.Element
+ * @param {String} elt DOM node that is wrapped
+ * @param {Object} [pInst] pointer to p5 instance
+ * @param {Boolean} whether we're using it as main canvas
+ */
+p5.Graphics = function(w, h, renderer, pInst) {
+
+ var r = renderer || constants.P2D;
+
+ var c = document.createElement('canvas');
+ var node = this._userNode || document.body;
+ node.appendChild(c);
+
+ p5.Element.call(this, c, pInst, false);
+ this._styles = [];
+ this.width = w;
+ this.height = h;
+ this._pixelDensity = pInst._pixelDensity;
+
+ if (r === constants.WEBGL) {
+ this._renderer = new p5.RendererGL(c, this, false);
+ } else {
+ this._renderer = new p5.Renderer2D(c, this, false);
+ }
+
+ this._renderer.resize(w, h);
+ this._renderer._applyDefaults();
+
+ pInst._elements.push(this);
+
+ // bind methods and props of p5 to the new object
+ for (var p in p5.prototype) {
+ if (!this[p]) {
+ if (typeof p5.prototype[p] === 'function') {
+ this[p] = p5.prototype[p].bind(this);
+ } else {
+ this[p] = p5.prototype[p];
+ }
+ }
+ }
+
+ return this;
+};
+
+p5.Graphics.prototype = Object.create(p5.Element.prototype);
+
+p5.Graphics.prototype.remove = function() {
+ if (this.elt.parentNode) {
+ this.elt.parentNode.removeChild(this.elt);
+ }
+ for (var elt_ev in this._events) {
+ this.elt.removeEventListener(elt_ev, this._events[elt_ev]);
+ }
+};
+
+module.exports = p5.Graphics;
+
+},{"./constants":41,"./core":42}],48:[function(_dereq_,module,exports){
+/**
+ * @module Rendering
+ * @submodule Rendering
+ * @for p5
+ */
+
+var p5 = _dereq_('./core');
+var constants = _dereq_('../core/constants');
+
+/**
+ * Main graphics and rendering context, as well as the base API
+ * implementation for p5.js "core". To be used as the superclass for
+ * Renderer2D and Renderer3D classes, respecitvely.
+ *
+ * @class p5.Renderer
+ * @constructor
+ * @extends p5.Element
+ * @param {String} elt DOM node that is wrapped
+ * @param {Object} [pInst] pointer to p5 instance
+ * @param {Boolean} whether we're using it as main canvas
+ */
+p5.Renderer = function(elt, pInst, isMainCanvas) {
+ p5.Element.call(this, elt, pInst);
+ this.canvas = elt;
+ this._pInst = pInst;
+ if (isMainCanvas) {
+ this._isMainCanvas = true;
+ // for pixel method sharing with pimage
+ this._pInst._setProperty('_curElement', this);
+ this._pInst._setProperty('canvas', this.canvas);
+ this._pInst._setProperty('width', this.width);
+ this._pInst._setProperty('height', this.height);
+ } else { // hide if offscreen buffer by default
+ this.canvas.style.display = 'none';
+ this._styles = []; // non-main elt styles stored in p5.Renderer
+ }
+
+
+ this._textSize = 12;
+ this._textLeading = 15;
+ this._textFont = 'sans-serif';
+ this._textStyle = constants.NORMAL;
+ this._textAscent = null;
+ this._textDescent = null;
+
+
+ this._rectMode = constants.CORNER;
+ this._ellipseMode = constants.CENTER;
+ this._curveTightness = 0;
+ this._imageMode = constants.CORNER;
+
+ this._tint = null;
+ this._doStroke = true;
+ this._doFill = true;
+ this._strokeSet = false;
+ this._fillSet = false;
+ this._colorMode = constants.RGB;
+ this._colorMaxes = {
+ rgb: [255, 255, 255, 255],
+ hsb: [360, 100, 100, 1],
+ hsl: [360, 100, 100, 1]
+ };
+
+};
+
+p5.Renderer.prototype = Object.create(p5.Element.prototype);
+
+
+
+
+/**
+ * Resize our canvas element.
+ */
+p5.Renderer.prototype.resize = function(w, h) {
+ this.width = w;
+ this.height = h;
+ this.elt.width = w * this._pInst._pixelDensity;
+ this.elt.height = h * this._pInst._pixelDensity;
+ this.elt.style.width = w +'px';
+ this.elt.style.height = h + 'px';
+ if (this._isMainCanvas) {
+ this._pInst._setProperty('width', this.width);
+ this._pInst._setProperty('height', this.height);
+ }
+};
+
+p5.Renderer.prototype.textLeading = function(l) {
+
+ if (arguments.length && arguments[0]) {
+
+ this._setProperty('_textLeading', l);
+ return this;
+ }
+
+ return this._textLeading;
+};
+
+p5.Renderer.prototype.textSize = function(s) {
+
+ if (arguments.length && arguments[0]) {
+
+ this._setProperty('_textSize', s);
+ this._setProperty('_textLeading', s * constants._DEFAULT_LEADMULT);
+ return this._applyTextProperties();
+ }
+
+ return this._textSize;
+};
+
+p5.Renderer.prototype.textStyle = function(s) {
+
+ if (arguments.length && arguments[0]) {
+
+ if (s === constants.NORMAL ||
+ s === constants.ITALIC ||
+ s === constants.BOLD) {
+ this._setProperty('_textStyle', s);
+ }
+
+ return this._applyTextProperties();
+ }
+
+ return this._textStyle;
+};
+
+p5.Renderer.prototype.textAscent = function() {
+ if (this._textAscent === null) {
+ this._updateTextMetrics();
+ }
+ return this._textAscent;
+};
+
+p5.Renderer.prototype.textDescent = function() {
+
+ if (this._textDescent === null) {
+ this._updateTextMetrics();
+ }
+ return this._textDescent;
+};
+
+p5.Renderer.prototype._applyDefaults = function(){
+ return this;
+};
+
+/**
+ * Helper fxn to check font type (system or otf)
+ */
+p5.Renderer.prototype._isOpenType = function(f) {
+
+ f = f || this._textFont;
+ return (typeof f === 'object' && f.font && f.font.supported);
+};
+
+p5.Renderer.prototype._updateTextMetrics = function() {
+
+ if (this._isOpenType()) {
+
+ this._setProperty('_textAscent', this._textFont._textAscent());
+ this._setProperty('_textDescent', this._textFont._textDescent());
+ return this;
+ }
+
+ // Adapted from http://stackoverflow.com/a/25355178
+ var text = document.createElement('span');
+ text.style.fontFamily = this._textFont;
+ text.style.fontSize = this._textSize + 'px';
+ text.innerHTML = 'ABCjgq|';
+
+ var block = document.createElement('div');
+ block.style.display = 'inline-block';
+ block.style.width = '1px';
+ block.style.height = '0px';
+
+ var container = document.createElement('div');
+ container.appendChild(text);
+ container.appendChild(block);
+
+ container.style.height = '0px';
+ container.style.overflow = 'hidden';
+ document.body.appendChild(container);
+
+ block.style.verticalAlign = 'baseline';
+ var blockOffset = calculateOffset(block);
+ var textOffset = calculateOffset(text);
+ var ascent = blockOffset[1] - textOffset[1];
+
+ block.style.verticalAlign = 'bottom';
+ blockOffset = calculateOffset(block);
+ textOffset = calculateOffset(text);
+ var height = blockOffset[1] - textOffset[1];
+ var descent = height - ascent;
+
+ document.body.removeChild(container);
+
+ this._setProperty('_textAscent', ascent);
+ this._setProperty('_textDescent', descent);
+
+ return this;
+};
+
+/**
+ * Helper fxn to measure ascent and descent.
+ * Adapted from http://stackoverflow.com/a/25355178
+ */
+function calculateOffset(object) {
+ var currentLeft = 0,
+ currentTop = 0;
+ if (object.offsetParent) {
+ do {
+ currentLeft += object.offsetLeft;
+ currentTop += object.offsetTop;
+ } while (object = object.offsetParent);
+ } else {
+ currentLeft += object.offsetLeft;
+ currentTop += object.offsetTop;
+ }
+ return [currentLeft, currentTop];
+}
+
+module.exports = p5.Renderer;
+
+},{"../core/constants":41,"./core":42}],49:[function(_dereq_,module,exports){
+
+var p5 = _dereq_('./core');
+var canvas = _dereq_('./canvas');
+var constants = _dereq_('./constants');
+var filters = _dereq_('../image/filters');
+
+_dereq_('./p5.Renderer');
+
+/**
+ * p5.Renderer2D
+ * The 2D graphics canvas renderer class.
+ * extends p5.Renderer
+ */
+var styleEmpty = 'rgba(0,0,0,0)';
+// var alphaThreshold = 0.00125; // minimum visible
+
+p5.Renderer2D = function(elt, pInst, isMainCanvas){
+ p5.Renderer.call(this, elt, pInst, isMainCanvas);
+ this.drawingContext = this.canvas.getContext('2d');
+ this._pInst._setProperty('drawingContext', this.drawingContext);
+ return this;
+};
+
+p5.Renderer2D.prototype = Object.create(p5.Renderer.prototype);
+
+p5.Renderer2D.prototype._applyDefaults = function() {
+ this.drawingContext.fillStyle = constants._DEFAULT_FILL;
+ this.drawingContext.strokeStyle = constants._DEFAULT_STROKE;
+ this.drawingContext.lineCap = constants.ROUND;
+ this.drawingContext.font = 'normal 12px sans-serif';
+};
+
+p5.Renderer2D.prototype.resize = function(w,h) {
+ p5.Renderer.prototype.resize.call(this, w,h);
+ this.drawingContext.scale(this._pInst._pixelDensity,
+ this._pInst._pixelDensity);
+};
+
+//////////////////////////////////////////////
+// COLOR | Setting
+//////////////////////////////////////////////
+
+p5.Renderer2D.prototype.background = function() {
+ this.drawingContext.save();
+ this.drawingContext.setTransform(1, 0, 0, 1, 0, 0);
+ this.drawingContext.scale(this._pInst._pixelDensity,
+ this._pInst._pixelDensity);
+
+ if (arguments[0] instanceof p5.Image) {
+ this._pInst.image(arguments[0], 0, 0, this.width, this.height);
+ } else {
+ var curFill = this.drawingContext.fillStyle;
+ // create background rect
+ var color = this._pInst.color.apply(this, arguments);
+ var newFill = color.toString();
+ this.drawingContext.fillStyle = newFill;
+ this.drawingContext.fillRect(0, 0, this.width, this.height);
+ // reset fill
+ this.drawingContext.fillStyle = curFill;
+ }
+ this.drawingContext.restore();
+};
+
+p5.Renderer2D.prototype.clear = function() {
+ this.drawingContext.clearRect(0, 0, this.width, this.height);
+};
+
+p5.Renderer2D.prototype.fill = function() {
+
+ var ctx = this.drawingContext;
+ var color = this._pInst.color.apply(this, arguments);
+ ctx.fillStyle = color.toString();
+};
+
+p5.Renderer2D.prototype.stroke = function() {
+ var ctx = this.drawingContext;
+ var color = this._pInst.color.apply(this, arguments);
+ ctx.strokeStyle = color.toString();
+};
+
+//////////////////////////////////////////////
+// IMAGE | Loading & Displaying
+//////////////////////////////////////////////
+
+p5.Renderer2D.prototype.image =
+ function (img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) {
+ var cnv;
+ try {
+ if (this._tint) {
+ if (p5.MediaElement && img instanceof p5.MediaElement) {
+ img.loadPixels();
+ }
+ if (img.canvas) {
+ cnv = this._getTintedImageCanvas(img);
+ }
+ }
+ if (!cnv) {
+ cnv = img.canvas || img.elt;
+ }
+ this.drawingContext.drawImage(cnv, sx, sy, sWidth, sHeight, dx, dy,
+ dWidth, dHeight);
+ } catch (e) {
+ if (e.name !== 'NS_ERROR_NOT_AVAILABLE') {
+ throw e;
+ }
+ }
+};
+
+p5.Renderer2D.prototype._getTintedImageCanvas = function (img) {
+ if (!img.canvas) {
+ return img;
+ }
+ var pixels = filters._toPixels(img.canvas);
+ var tmpCanvas = document.createElement('canvas');
+ tmpCanvas.width = img.canvas.width;
+ tmpCanvas.height = img.canvas.height;
+ var tmpCtx = tmpCanvas.getContext('2d');
+ var id = tmpCtx.createImageData(img.canvas.width, img.canvas.height);
+ var newPixels = id.data;
+ for (var i = 0; i < pixels.length; i += 4) {
+ var r = pixels[i];
+ var g = pixels[i + 1];
+ var b = pixels[i + 2];
+ var a = pixels[i + 3];
+ newPixels[i] = r * this._tint[0] / 255;
+ newPixels[i + 1] = g * this._tint[1] / 255;
+ newPixels[i + 2] = b * this._tint[2] / 255;
+ newPixels[i + 3] = a * this._tint[3] / 255;
+ }
+ tmpCtx.putImageData(id, 0, 0);
+ return tmpCanvas;
+};
+
+
+//////////////////////////////////////////////
+// IMAGE | Pixels
+//////////////////////////////////////////////
+
+p5.Renderer2D.prototype.blendMode = function(mode) {
+ this.drawingContext.globalCompositeOperation = mode;
+};
+p5.Renderer2D.prototype.blend = function() {
+ var currBlend = this.drawingContext.globalCompositeOperation;
+ var blendMode = arguments[arguments.length - 1];
+
+ var copyArgs = Array.prototype.slice.call(
+ arguments,
+ 0,
+ arguments.length - 1
+ );
+
+ this.drawingContext.globalCompositeOperation = blendMode;
+ if (this._pInst) {
+ this._pInst.copy.apply(this._pInst, copyArgs);
+ } else {
+ this.copy.apply(this, copyArgs);
+ }
+ this.drawingContext.globalCompositeOperation = currBlend;
+};
+
+p5.Renderer2D.prototype.copy = function () {
+ var srcImage, sx, sy, sw, sh, dx, dy, dw, dh;
+ if (arguments.length === 9) {
+ srcImage = arguments[0];
+ sx = arguments[1];
+ sy = arguments[2];
+ sw = arguments[3];
+ sh = arguments[4];
+ dx = arguments[5];
+ dy = arguments[6];
+ dw = arguments[7];
+ dh = arguments[8];
+ } else if (arguments.length === 8) {
+ srcImage = this._pInst;
+ sx = arguments[0];
+ sy = arguments[1];
+ sw = arguments[2];
+ sh = arguments[3];
+ dx = arguments[4];
+ dy = arguments[5];
+ dw = arguments[6];
+ dh = arguments[7];
+ } else {
+ throw new Error('Signature not supported');
+ }
+ p5.Renderer2D._copyHelper(srcImage, sx, sy, sw, sh, dx, dy, dw, dh);
+};
+
+p5.Renderer2D._copyHelper =
+function (srcImage, sx, sy, sw, sh, dx, dy, dw, dh) {
+ srcImage.loadPixels();
+ var s = srcImage.canvas.width / srcImage.width;
+ this.drawingContext.drawImage(srcImage.canvas,
+ s * sx, s * sy, s * sw, s * sh, dx, dy, dw, dh);
+};
+
+p5.Renderer2D.prototype.get = function(x, y, w, h) {
+ if (x === undefined && y === undefined &&
+ w === undefined && h === undefined){
+ x = 0;
+ y = 0;
+ w = this.width;
+ h = this.height;
+ } else if (w === undefined && h === undefined) {
+ w = 1;
+ h = 1;
+ }
+
+ // if the section does not overlap the canvas
+ if(x + w < 0 || y + h < 0 || x > this.width || y > this.height){
+ return [0, 0, 0, 255];
+ }
+
+ var ctx = this._pInst || this;
+ ctx.loadPixels();
+
+ var pd = ctx._pixelDensity;
+
+ // round down to get integer numbers
+ x = Math.floor(x);
+ y = Math.floor(y);
+ w = Math.floor(w);
+ h = Math.floor(h);
+
+ var sx = x * pd;
+ var sy = y * pd;
+ if (w === 1 && h === 1){
+ var imageData = this.drawingContext.getImageData(sx, sy, 1, 1).data;
+ //imageData = [0,0,0,0];
+ return [
+ imageData[0],
+ imageData[1],
+ imageData[2],
+ imageData[3]
+ ];
+ } else {
+ //auto constrain the width and height to
+ //dimensions of the source image
+ var dw = Math.min(w, ctx.width);
+ var dh = Math.min(h, ctx.height);
+ var sw = dw * pd;
+ var sh = dh * pd;
+
+ var region = new p5.Image(dw, dh);
+ region.canvas.getContext('2d').drawImage(this.canvas, sx, sy, sw, sh,
+ 0, 0, dw, dh);
+
+ return region;
+ }
+};
+
+p5.Renderer2D.prototype.loadPixels = function () {
+ var pd = this._pixelDensity || this._pInst._pixelDensity;
+ var w = this.width * pd;
+ var h = this.height * pd;
+ var imageData = this.drawingContext.getImageData(0, 0, w, h);
+ // @todo this should actually set pixels per object, so diff buffers can
+ // have diff pixel arrays.
+ if (this._pInst) {
+ this._pInst._setProperty('imageData', imageData);
+ this._pInst._setProperty('pixels', imageData.data);
+ } else { // if called by p5.Image
+ this._setProperty('imageData', imageData);
+ this._setProperty('pixels', imageData.data);
+ }
+};
+
+p5.Renderer2D.prototype.set = function (x, y, imgOrCol) {
+ // round down to get integer numbers
+ x = Math.floor(x);
+ y = Math.floor(y);
+ if (imgOrCol instanceof p5.Image) {
+ this.drawingContext.save();
+ this.drawingContext.setTransform(1, 0, 0, 1, 0, 0);
+ this.drawingContext.scale(this._pInst._pixelDensity,
+ this._pInst._pixelDensity);
+ this.drawingContext.drawImage(imgOrCol.canvas, x, y);
+ this.loadPixels.call(this._pInst);
+ this.drawingContext.restore();
+ } else {
+ var ctx = this._pInst || this;
+ var r = 0, g = 0, b = 0, a = 0;
+ var idx = 4*((y * ctx._pixelDensity) *
+ (this.width * ctx._pixelDensity) + (x * ctx._pixelDensity));
+ if (!ctx.imageData) {
+ ctx.loadPixels.call(ctx);
+ }
+ if (typeof imgOrCol === 'number') {
+ if (idx < ctx.pixels.length) {
+ r = imgOrCol;
+ g = imgOrCol;
+ b = imgOrCol;
+ a = 255;
+ //this.updatePixels.call(this);
+ }
+ }
+ else if (imgOrCol instanceof Array) {
+ if (imgOrCol.length < 4) {
+ throw new Error('pixel array must be of the form [R, G, B, A]');
+ }
+ if (idx < ctx.pixels.length) {
+ r = imgOrCol[0];
+ g = imgOrCol[1];
+ b = imgOrCol[2];
+ a = imgOrCol[3];
+ //this.updatePixels.call(this);
+ }
+ } else if (imgOrCol instanceof p5.Color) {
+ if (idx < ctx.pixels.length) {
+ r = imgOrCol.levels[0];
+ g = imgOrCol.levels[1];
+ b = imgOrCol.levels[2];
+ a = imgOrCol.levels[3];
+ //this.updatePixels.call(this);
+ }
+ }
+ // loop over pixelDensity * pixelDensity
+ for (var i = 0; i < ctx._pixelDensity; i++) {
+ for (var j = 0; j < ctx._pixelDensity; j++) {
+ // loop over
+ idx = 4*((y * ctx._pixelDensity + j) * this.width *
+ ctx._pixelDensity + (x * ctx._pixelDensity + i));
+ ctx.pixels[idx] = r;
+ ctx.pixels[idx+1] = g;
+ ctx.pixels[idx+2] = b;
+ ctx.pixels[idx+3] = a;
+ }
+ }
+ }
+};
+
+p5.Renderer2D.prototype.updatePixels = function (x, y, w, h) {
+ var pd = this._pixelDensity || this._pInst._pixelDensity;
+ if (x === undefined &&
+ y === undefined &&
+ w === undefined &&
+ h === undefined) {
+ x = 0;
+ y = 0;
+ w = this.width;
+ h = this.height;
+ }
+ w *= pd;
+ h *= pd;
+
+ if (this._pInst) {
+ this.drawingContext.putImageData(this._pInst.imageData, x, y, 0, 0, w, h);
+ } else {
+ this.drawingContext.putImageData(this.imageData, x, y, 0, 0, w, h);
+ }
+};
+
+//////////////////////////////////////////////
+// SHAPE | 2D Primitives
+//////////////////////////////////////////////
+
+/**
+ * Generate a cubic Bezier representing an arc on the unit circle of total
+ * angle `size` radians, beginning `start` radians above the x-axis. Up to
+ * four of these curves are combined to make a full arc.
+ *
+ * See www.joecridge.me/bezier.pdf for an explanation of the method.
+ */
+p5.Renderer2D.prototype._acuteArcToBezier =
+ function _acuteArcToBezier(start, size) {
+ // Evauate constants.
+ var alpha = size / 2.0,
+ cos_alpha = Math.cos(alpha),
+ sin_alpha = Math.sin(alpha),
+ cot_alpha = 1.0 / Math.tan(alpha),
+ phi = start + alpha, // This is how far the arc needs to be rotated.
+ cos_phi = Math.cos(phi),
+ sin_phi = Math.sin(phi),
+ lambda = (4.0 - cos_alpha) / 3.0,
+ mu = sin_alpha + (cos_alpha - lambda) * cot_alpha;
+
+ // Return rotated waypoints.
+ return {
+ ax: Math.cos(start),
+ ay: Math.sin(start),
+ bx: lambda * cos_phi + mu * sin_phi,
+ by: lambda * sin_phi - mu * cos_phi,
+ cx: lambda * cos_phi - mu * sin_phi,
+ cy: lambda * sin_phi + mu * cos_phi,
+ dx: Math.cos(start + size),
+ dy: Math.sin(start + size)
+ };
+};
+
+p5.Renderer2D.prototype.arc =
+ function(x, y, w, h, start, stop, mode) {
+ var ctx = this.drawingContext;
+ var vals = canvas.arcModeAdjust(x, y, w, h, this._ellipseMode);
+ var rx = vals.w / 2.0;
+ var ry = vals.h / 2.0;
+ var epsilon = 0.00001; // Smallest visible angle on displays up to 4K.
+ var arcToDraw = 0;
+ var curves = [];
+
+ // Create curves
+ while(stop - start > epsilon) {
+ arcToDraw = Math.min(stop - start, constants.HALF_PI);
+ curves.push(this._acuteArcToBezier(start, arcToDraw));
+ start += arcToDraw;
+ }
+
+ // Fill curves
+ if (this._doFill) {
+ ctx.beginPath();
+ curves.forEach(function (curve, index) {
+ if (index === 0) {
+ ctx.moveTo(vals.x + curve.ax * rx, vals.y + curve.ay * ry);
+ }
+ ctx.bezierCurveTo(vals.x + curve.bx * rx, vals.y + curve.by * ry,
+ vals.x + curve.cx * rx, vals.y + curve.cy * ry,
+ vals.x + curve.dx * rx, vals.y + curve.dy * ry);
+ });
+ if (mode === constants.PIE || mode == null) {
+ ctx.lineTo(vals.x, vals.y);
+ }
+ ctx.closePath();
+ ctx.fill();
+ }
+
+ // Stroke curves
+ if (this._doStroke) {
+ ctx.beginPath();
+ curves.forEach(function (curve, index) {
+ if (index === 0) {
+ ctx.moveTo(vals.x + curve.ax * rx, vals.y + curve.ay * ry);
+ }
+ ctx.bezierCurveTo(vals.x + curve.bx * rx, vals.y + curve.by * ry,
+ vals.x + curve.cx * rx, vals.y + curve.cy * ry,
+ vals.x + curve.dx * rx, vals.y + curve.dy * ry);
+ });
+ if (mode === constants.PIE) {
+ ctx.lineTo(vals.x, vals.y);
+ ctx.closePath();
+ } else if (mode === constants.CHORD) {
+ ctx.closePath();
+ }
+ ctx.stroke();
+ }
+ return this;
+};
+
+p5.Renderer2D.prototype.ellipse = function(args) {
+ var ctx = this.drawingContext;
+ var doFill = this._doFill, doStroke = this._doStroke;
+ var x = args[0],
+ y = args[1],
+ w = args[2],
+ h = args[3];
+ if (doFill && !doStroke) {
+ if(ctx.fillStyle === styleEmpty) {
+ return this;
+ }
+ } else if (!doFill && doStroke) {
+ if(ctx.strokeStyle === styleEmpty) {
+ return this;
+ }
+ }
+ var kappa = 0.5522847498,
+ ox = (w / 2) * kappa, // control point offset horizontal
+ oy = (h / 2) * kappa, // control point offset vertical
+ xe = x + w, // x-end
+ ye = y + h, // y-end
+ xm = x + w / 2, // x-middle
+ ym = y + h / 2; // y-middle
+ ctx.beginPath();
+ ctx.moveTo(x, ym);
+ ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
+ ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
+ ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
+ ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
+ ctx.closePath();
+ if (doFill) {
+ ctx.fill();
+ }
+ if (doStroke) {
+ ctx.stroke();
+ }
+};
+
+p5.Renderer2D.prototype.line = function(x1, y1, x2, y2) {
+ var ctx = this.drawingContext;
+ if (!this._doStroke) {
+ return this;
+ } else if(ctx.strokeStyle === styleEmpty){
+ return this;
+ }
+ // Translate the line by (0.5, 0.5) to draw it crisp
+ if (ctx.lineWidth % 2 === 1) {
+ ctx.translate(0.5, 0.5);
+ }
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
+ if (ctx.lineWidth % 2 === 1) {
+ ctx.translate(-0.5, -0.5);
+ }
+ return this;
+};
+
+p5.Renderer2D.prototype.point = function(x, y) {
+ var ctx = this.drawingContext;
+ var s = ctx.strokeStyle;
+ var f = ctx.fillStyle;
+ if (!this._doStroke) {
+ return this;
+ } else if(ctx.strokeStyle === styleEmpty){
+ return this;
+ }
+ x = Math.round(x);
+ y = Math.round(y);
+ ctx.fillStyle = s;
+ if (ctx.lineWidth > 1) {
+ ctx.beginPath();
+ ctx.arc(
+ x,
+ y,
+ ctx.lineWidth / 2,
+ 0,
+ constants.TWO_PI,
+ false
+ );
+ ctx.fill();
+ } else {
+ ctx.fillRect(x, y, 1, 1);
+ }
+ ctx.fillStyle = f;
+};
+
+p5.Renderer2D.prototype.quad =
+ function(x1, y1, x2, y2, x3, y3, x4, y4) {
+ var ctx = this.drawingContext;
+ var doFill = this._doFill, doStroke = this._doStroke;
+ if (doFill && !doStroke) {
+ if(ctx.fillStyle === styleEmpty) {
+ return this;
+ }
+ } else if (!doFill && doStroke) {
+ if(ctx.strokeStyle === styleEmpty) {
+ return this;
+ }
+ }
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.lineTo(x3, y3);
+ ctx.lineTo(x4, y4);
+ ctx.closePath();
+ if (doFill) {
+ ctx.fill();
+ }
+ if (doStroke) {
+ ctx.stroke();
+ }
+ return this;
+};
+
+p5.Renderer2D.prototype.rect = function(args) {
+ var x = args[0],
+ y = args[1],
+ w = args[2],
+ h = args[3],
+ tl = args[4],
+ tr = args[5],
+ br = args[6],
+ bl = args[7];
+ var ctx = this.drawingContext;
+ var doFill = this._doFill, doStroke = this._doStroke;
+ if (doFill && !doStroke) {
+ if(ctx.fillStyle === styleEmpty) {
+ return this;
+ }
+ } else if (!doFill && doStroke) {
+ if(ctx.strokeStyle === styleEmpty) {
+ return this;
+ }
+ }
+ // Translate the line by (0.5, 0.5) to draw a crisp rectangle border
+ if (this._doStroke && ctx.lineWidth % 2 === 1) {
+ ctx.translate(0.5, 0.5);
+ }
+ ctx.beginPath();
+
+ if (typeof tl === 'undefined') {
+ // No rounded corners
+ ctx.rect(x, y, w, h);
+ } else {
+ // At least one rounded corner
+ // Set defaults when not specified
+ if (typeof tr === 'undefined') { tr = tl; }
+ if (typeof br === 'undefined') { br = tr; }
+ if (typeof bl === 'undefined') { bl = br; }
+
+ var hw = w / 2;
+ var hh = h / 2;
+
+ // Clip radii
+ if (w < 2 * tl) { tl = hw; }
+ if (h < 2 * tl) { tl = hh; }
+ if (w < 2 * tr) { tr = hw; }
+ if (h < 2 * tr) { tr = hh; }
+ if (w < 2 * br) { br = hw; }
+ if (h < 2 * br) { br = hh; }
+ if (w < 2 * bl) { bl = hw; }
+ if (h < 2 * bl) { bl = hh; }
+
+ // Draw shape
+ ctx.beginPath();
+ ctx.moveTo(x + tl, y);
+ ctx.arcTo(x + w, y, x + w, y + h, tr);
+ ctx.arcTo(x + w, y + h, x, y + h, br);
+ ctx.arcTo(x, y + h, x, y, bl);
+ ctx.arcTo(x, y, x + w, y, tl);
+ ctx.closePath();
+ }
+ if (this._doFill) {
+ ctx.fill();
+ }
+ if (this._doStroke) {
+ ctx.stroke();
+ }
+ if (this._doStroke && ctx.lineWidth % 2 === 1) {
+ ctx.translate(-0.5, -0.5);
+ }
+ return this;
+};
+
+p5.Renderer2D.prototype.triangle = function(args) {
+ var ctx = this.drawingContext;
+ var doFill = this._doFill, doStroke = this._doStroke;
+ var x1=args[0], y1=args[1];
+ var x2=args[2], y2=args[3];
+ var x3=args[4], y3=args[5];
+ if (doFill && !doStroke) {
+ if(ctx.fillStyle === styleEmpty) {
+ return this;
+ }
+ } else if (!doFill && doStroke) {
+ if(ctx.strokeStyle === styleEmpty) {
+ return this;
+ }
+ }
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.lineTo(x3, y3);
+ ctx.closePath();
+ if (doFill) {
+ ctx.fill();
+ }
+ if (doStroke) {
+ ctx.stroke();
+ }
+};
+
+p5.Renderer2D.prototype.endShape =
+function (mode, vertices, isCurve, isBezier,
+ isQuadratic, isContour, shapeKind) {
+ if (vertices.length === 0) {
+ return this;
+ }
+ if (!this._doStroke && !this._doFill) {
+ return this;
+ }
+ var closeShape = mode === constants.CLOSE;
+ var v;
+ if (closeShape && !isContour) {
+ vertices.push(vertices[0]);
+ }
+ var i, j;
+ var numVerts = vertices.length;
+ if (isCurve && (shapeKind === constants.POLYGON || shapeKind === null)) {
+ if (numVerts > 3) {
+ var b = [], s = 1 - this._curveTightness;
+ this.drawingContext.beginPath();
+ this.drawingContext.moveTo(vertices[1][0], vertices[1][1]);
+ for (i = 1; i + 2 < numVerts; i++) {
+ v = vertices[i];
+ b[0] = [
+ v[0],
+ v[1]
+ ];
+ b[1] = [
+ v[0] + (s * vertices[i + 1][0] - s * vertices[i - 1][0]) / 6,
+ v[1] + (s * vertices[i + 1][1] - s * vertices[i - 1][1]) / 6
+ ];
+ b[2] = [
+ vertices[i + 1][0] +
+ (s * vertices[i][0]-s * vertices[i + 2][0]) / 6,
+ vertices[i + 1][1]+(s * vertices[i][1] - s*vertices[i + 2][1]) / 6
+ ];
+ b[3] = [
+ vertices[i + 1][0],
+ vertices[i + 1][1]
+ ];
+ this.drawingContext.bezierCurveTo(b[1][0],b[1][1],
+ b[2][0],b[2][1],b[3][0],b[3][1]);
+ }
+ if (closeShape) {
+ this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]);
+ }
+ this._doFillStrokeClose();
+ }
+ } else if (isBezier&&(shapeKind===constants.POLYGON ||shapeKind === null)) {
+ this.drawingContext.beginPath();
+ for (i = 0; i < numVerts; i++) {
+ if (vertices[i].isVert) {
+ if (vertices[i].moveTo) {
+ this.drawingContext.moveTo(vertices[i][0], vertices[i][1]);
+ } else {
+ this.drawingContext.lineTo(vertices[i][0], vertices[i][1]);
+ }
+ } else {
+ this.drawingContext.bezierCurveTo(vertices[i][0], vertices[i][1],
+ vertices[i][2], vertices[i][3], vertices[i][4], vertices[i][5]);
+ }
+ }
+ this._doFillStrokeClose();
+ } else if (isQuadratic &&
+ (shapeKind === constants.POLYGON || shapeKind === null)) {
+ this.drawingContext.beginPath();
+ for (i = 0; i < numVerts; i++) {
+ if (vertices[i].isVert) {
+ if (vertices[i].moveTo) {
+ this.drawingContext.moveTo([0], vertices[i][1]);
+ } else {
+ this.drawingContext.lineTo(vertices[i][0], vertices[i][1]);
+ }
+ } else {
+ this.drawingContext.quadraticCurveTo(vertices[i][0], vertices[i][1],
+ vertices[i][2], vertices[i][3]);
+ }
+ }
+ this._doFillStrokeClose();
+ } else {
+ if (shapeKind === constants.POINTS) {
+ for (i = 0; i < numVerts; i++) {
+ v = vertices[i];
+ if (this._doStroke) {
+ this._pInst.stroke(v[6]);
+ }
+ this._pInst.point(v[0], v[1]);
+ }
+ } else if (shapeKind === constants.LINES) {
+ for (i = 0; i + 1 < numVerts; i += 2) {
+ v = vertices[i];
+ if (this._doStroke) {
+ this._pInst.stroke(vertices[i + 1][6]);
+ }
+ this._pInst.line(v[0], v[1], vertices[i + 1][0], vertices[i + 1][1]);
+ }
+ } else if (shapeKind === constants.TRIANGLES) {
+ for (i = 0; i + 2 < numVerts; i += 3) {
+ v = vertices[i];
+ this.drawingContext.beginPath();
+ this.drawingContext.moveTo(v[0], v[1]);
+ this.drawingContext.lineTo(vertices[i + 1][0], vertices[i + 1][1]);
+ this.drawingContext.lineTo(vertices[i + 2][0], vertices[i + 2][1]);
+ this.drawingContext.lineTo(v[0], v[1]);
+ if (this._doFill) {
+ this._pInst.fill(vertices[i + 2][5]);
+ this.drawingContext.fill();
+ }
+ if (this._doStroke) {
+ this._pInst.stroke(vertices[i + 2][6]);
+ this.drawingContext.stroke();
+ }
+ this.drawingContext.closePath();
+ }
+ } else if (shapeKind === constants.TRIANGLE_STRIP) {
+ for (i = 0; i + 1 < numVerts; i++) {
+ v = vertices[i];
+ this.drawingContext.beginPath();
+ this.drawingContext.moveTo(vertices[i + 1][0], vertices[i + 1][1]);
+ this.drawingContext.lineTo(v[0], v[1]);
+ if (this._doStroke) {
+ this._pInst.stroke(vertices[i + 1][6]);
+ }
+ if (this._doFill) {
+ this._pInst.fill(vertices[i + 1][5]);
+ }
+ if (i + 2 < numVerts) {
+ this.drawingContext.lineTo(vertices[i + 2][0], vertices[i + 2][1]);
+ if (this._doStroke) {
+ this._pInst.stroke(vertices[i + 2][6]);
+ }
+ if (this._doFill) {
+ this._pInst.fill(vertices[i + 2][5]);
+ }
+ }
+ this._doFillStrokeClose();
+ }
+ } else if (shapeKind === constants.TRIANGLE_FAN) {
+ if (numVerts > 2) {
+ this.drawingContext.beginPath();
+ this.drawingContext.moveTo(vertices[0][0], vertices[0][1]);
+ this.drawingContext.lineTo(vertices[1][0], vertices[1][1]);
+ this.drawingContext.lineTo(vertices[2][0], vertices[2][1]);
+ if (this._doFill) {
+ this._pInst.fill(vertices[2][5]);
+ }
+ if (this._doStroke) {
+ this._pInst.stroke(vertices[2][6]);
+ }
+ this._doFillStrokeClose();
+ for (i = 3; i < numVerts; i++) {
+ v = vertices[i];
+ this.drawingContext.beginPath();
+ this.drawingContext.moveTo(vertices[0][0], vertices[0][1]);
+ this.drawingContext.lineTo(vertices[i - 1][0], vertices[i - 1][1]);
+ this.drawingContext.lineTo(v[0], v[1]);
+ if (this._doFill) {
+ this._pInst.fill(v[5]);
+ }
+ if (this._doStroke) {
+ this._pInst.stroke(v[6]);
+ }
+ this._doFillStrokeClose();
+ }
+ }
+ } else if (shapeKind === constants.QUADS) {
+ for (i = 0; i + 3 < numVerts; i += 4) {
+ v = vertices[i];
+ this.drawingContext.beginPath();
+ this.drawingContext.moveTo(v[0], v[1]);
+ for (j = 1; j < 4; j++) {
+ this.drawingContext.lineTo(vertices[i + j][0], vertices[i + j][1]);
+ }
+ this.drawingContext.lineTo(v[0], v[1]);
+ if (this._doFill) {
+ this._pInst.fill(vertices[i + 3][5]);
+ }
+ if (this._doStroke) {
+ this._pInst.stroke(vertices[i + 3][6]);
+ }
+ this._doFillStrokeClose();
+ }
+ } else if (shapeKind === constants.QUAD_STRIP) {
+ if (numVerts > 3) {
+ for (i = 0; i + 1 < numVerts; i += 2) {
+ v = vertices[i];
+ this.drawingContext.beginPath();
+ if (i + 3 < numVerts) {
+ this.drawingContext.moveTo(vertices[i + 2][0], vertices[i+2][1]);
+ this.drawingContext.lineTo(v[0], v[1]);
+ this.drawingContext.lineTo(vertices[i + 1][0], vertices[i+1][1]);
+ this.drawingContext.lineTo(vertices[i + 3][0], vertices[i+3][1]);
+ if (this._doFill) {
+ this._pInst.fill(vertices[i + 3][5]);
+ }
+ if (this._doStroke) {
+ this._pInst.stroke(vertices[i + 3][6]);
+ }
+ } else {
+ this.drawingContext.moveTo(v[0], v[1]);
+ this.drawingContext.lineTo(vertices[i + 1][0], vertices[i+1][1]);
+ }
+ this._doFillStrokeClose();
+ }
+ }
+ } else {
+ this.drawingContext.beginPath();
+ this.drawingContext.moveTo(vertices[0][0], vertices[0][1]);
+ for (i = 1; i < numVerts; i++) {
+ v = vertices[i];
+ if (v.isVert) {
+ if (v.moveTo) {
+ this.drawingContext.moveTo(v[0], v[1]);
+ } else {
+ this.drawingContext.lineTo(v[0], v[1]);
+ }
+ }
+ }
+ this._doFillStrokeClose();
+ }
+ }
+ isCurve = false;
+ isBezier = false;
+ isQuadratic = false;
+ isContour = false;
+ if (closeShape) {
+ vertices.pop();
+ }
+ return this;
+};
+//////////////////////////////////////////////
+// SHAPE | Attributes
+//////////////////////////////////////////////
+
+p5.Renderer2D.prototype.noSmooth = function() {
+ if ('imageSmoothingEnabled' in this.drawingContext) {
+ this.drawingContext.imageSmoothingEnabled = false;
+ }
+ else if ('mozImageSmoothingEnabled' in this.drawingContext) {
+ this.drawingContext.mozImageSmoothingEnabled = false;
+ }
+ else if ('webkitImageSmoothingEnabled' in this.drawingContext) {
+ this.drawingContext.webkitImageSmoothingEnabled = false;
+ }
+ else if ('msImageSmoothingEnabled' in this.drawingContext) {
+ this.drawingContext.msImageSmoothingEnabled = false;
+ }
+ return this;
+};
+
+p5.Renderer2D.prototype.smooth = function() {
+ if ('imageSmoothingEnabled' in this.drawingContext) {
+ this.drawingContext.imageSmoothingEnabled = true;
+ }
+ else if ('mozImageSmoothingEnabled' in this.drawingContext) {
+ this.drawingContext.mozImageSmoothingEnabled = true;
+ }
+ else if ('webkitImageSmoothingEnabled' in this.drawingContext) {
+ this.drawingContext.webkitImageSmoothingEnabled = true;
+ }
+ else if ('msImageSmoothingEnabled' in this.drawingContext) {
+ this.drawingContext.msImageSmoothingEnabled = true;
+ }
+ return this;
+};
+
+p5.Renderer2D.prototype.strokeCap = function(cap) {
+ if (cap === constants.ROUND ||
+ cap === constants.SQUARE ||
+ cap === constants.PROJECT) {
+ this.drawingContext.lineCap = cap;
+ }
+ return this;
+};
+
+p5.Renderer2D.prototype.strokeJoin = function(join) {
+ if (join === constants.ROUND ||
+ join === constants.BEVEL ||
+ join === constants.MITER) {
+ this.drawingContext.lineJoin = join;
+ }
+ return this;
+};
+
+p5.Renderer2D.prototype.strokeWeight = function(w) {
+ if (typeof w === 'undefined' || w === 0) {
+ // hack because lineWidth 0 doesn't work
+ this.drawingContext.lineWidth = 0.0001;
+ } else {
+ this.drawingContext.lineWidth = w;
+ }
+ return this;
+};
+
+p5.Renderer2D.prototype._getFill = function(){
+ return this.drawingContext.fillStyle;
+};
+
+p5.Renderer2D.prototype._getStroke = function(){
+ return this.drawingContext.strokeStyle;
+};
+
+//////////////////////////////////////////////
+// SHAPE | Curves
+//////////////////////////////////////////////
+p5.Renderer2D.prototype.bezier = function (x1, y1, x2, y2, x3, y3, x4, y4) {
+ this._pInst.beginShape();
+ this._pInst.vertex(x1, y1);
+ this._pInst.bezierVertex(x2, y2, x3, y3, x4, y4);
+ this._pInst.endShape();
+ return this;
+};
+
+p5.Renderer2D.prototype.curve = function (x1, y1, x2, y2, x3, y3, x4, y4) {
+ this._pInst.beginShape();
+ this._pInst.curveVertex(x1, y1);
+ this._pInst.curveVertex(x2, y2);
+ this._pInst.curveVertex(x3, y3);
+ this._pInst.curveVertex(x4, y4);
+ this._pInst.endShape();
+ return this;
+};
+
+//////////////////////////////////////////////
+// SHAPE | Vertex
+//////////////////////////////////////////////
+
+p5.Renderer2D.prototype._doFillStrokeClose = function () {
+ if (this._doFill) {
+ this.drawingContext.fill();
+ }
+ if (this._doStroke) {
+ this.drawingContext.stroke();
+ }
+ this.drawingContext.closePath();
+};
+
+//////////////////////////////////////////////
+// TRANSFORM
+//////////////////////////////////////////////
+
+p5.Renderer2D.prototype.applyMatrix =
+function(n00, n01, n02, n10, n11, n12) {
+ this.drawingContext.transform(n00, n01, n02, n10, n11, n12);
+};
+
+p5.Renderer2D.prototype.resetMatrix = function() {
+ this.drawingContext.setTransform(1, 0, 0, 1, 0, 0);
+ this.drawingContext.scale(this._pInst._pixelDensity,
+ this._pInst._pixelDensity);
+ return this;
+};
+
+p5.Renderer2D.prototype.rotate = function(r) {
+ this.drawingContext.rotate(r);
+};
+
+p5.Renderer2D.prototype.scale = function(x,y) {
+ this.drawingContext.scale(x, y);
+ return this;
+};
+
+p5.Renderer2D.prototype.shearX = function(angle) {
+ if (this._pInst._angleMode === constants.DEGREES) {
+ // undoing here, because it gets redone in tan()
+ angle = this._pInst.degrees(angle);
+ }
+ this.drawingContext.transform(1, 0, this._pInst.tan(angle), 1, 0, 0);
+ return this;
+};
+
+p5.Renderer2D.prototype.shearY = function(angle) {
+ if (this._pInst._angleMode === constants.DEGREES) {
+ // undoing here, because it gets redone in tan()
+ angle = this._pInst.degrees(angle);
+ }
+ this.drawingContext.transform(1, this._pInst.tan(angle), 0, 1, 0, 0);
+ return this;
+};
+
+p5.Renderer2D.prototype.translate = function(x, y) {
+ this.drawingContext.translate(x, y);
+ return this;
+};
+
+//////////////////////////////////////////////
+// TYPOGRAPHY
+//
+//////////////////////////////////////////////
+
+p5.Renderer2D.prototype.text = function (str, x, y, maxWidth, maxHeight) {
+
+ var p = this._pInst, cars, n, ii, jj, line, testLine,
+ testWidth, words, totalHeight, baselineHacked,
+ finalMaxHeight = Number.MAX_VALUE;
+
+ // baselineHacked: (HACK)
+ // A temporary fix to conform to Processing's implementation
+ // of BASELINE vertical alignment in a bounding box
+
+ if (!(this._doFill || this._doStroke)) {
+ return;
+ }
+
+ if (typeof str !== 'string') {
+ str = str.toString();
+ }
+
+ str = str.replace(/(\t)/g, ' ');
+ cars = str.split('\n');
+
+ if (typeof maxWidth !== 'undefined') {
+
+ totalHeight = 0;
+ for (ii = 0; ii < cars.length; ii++) {
+ line = '';
+ words = cars[ii].split(' ');
+ for (n = 0; n < words.length; n++) {
+ testLine = line + words[n] + ' ';
+ testWidth = this.textWidth(testLine);
+ if (testWidth > maxWidth) {
+ line = words[n] + ' ';
+ totalHeight += p.textLeading();
+ } else {
+ line = testLine;
+ }
+ }
+ }
+
+ if (this._rectMode === constants.CENTER) {
+
+ x -= maxWidth / 2;
+ y -= maxHeight / 2;
+ }
+
+ switch (this.drawingContext.textAlign) {
+
+ case constants.CENTER:
+ x += maxWidth / 2;
+ break;
+ case constants.RIGHT:
+ x += maxWidth;
+ break;
+ }
+
+ if (typeof maxHeight !== 'undefined') {
+
+ switch (this.drawingContext.textBaseline) {
+ case constants.BOTTOM:
+ y += (maxHeight - totalHeight);
+ break;
+ case constants._CTX_MIDDLE: // CENTER?
+ y += (maxHeight - totalHeight) / 2;
+ break;
+ case constants.BASELINE:
+ baselineHacked = true;
+ this.drawingContext.textBaseline = constants.TOP;
+ break;
+ }
+
+ // remember the max-allowed y-position for any line (fix to #928)
+ finalMaxHeight = (y + maxHeight) - p.textAscent();
+ }
+
+ for (ii = 0; ii < cars.length; ii++) {
+
+ line = '';
+ words = cars[ii].split(' ');
+ for (n = 0; n < words.length; n++) {
+ testLine = line + words[n] + ' ';
+ testWidth = this.textWidth(testLine);
+ if (testWidth > maxWidth && line.length > 0) {
+ this._renderText(p, line, x, y, finalMaxHeight);
+ line = words[n] + ' ';
+ y += p.textLeading();
+ } else {
+ line = testLine;
+ }
+ }
+
+ this._renderText(p, line, x, y, finalMaxHeight);
+ y += p.textLeading();
+ }
+ }
+ else {
+ // Offset to account for vertically centering multiple lines of text - no
+ // need to adjust anything for vertical align top or baseline
+ var offset = 0,
+ vAlign = p.textAlign().vertical;
+ if (vAlign === constants.CENTER) {
+ offset = ((cars.length - 1) * p.textLeading()) / 2;
+ } else if (vAlign === constants.BOTTOM) {
+ offset = (cars.length - 1) * p.textLeading();
+ }
+
+ for (jj = 0; jj < cars.length; jj++) {
+
+ this._renderText(p, cars[jj], x, y-offset, finalMaxHeight);
+ y += p.textLeading();
+ }
+ }
+
+ if (baselineHacked) {
+ this.drawingContext.textBaseline = constants.BASELINE;
+ }
+
+ return p;
+};
+
+p5.Renderer2D.prototype._renderText = function(p, line, x, y, maxY) {
+
+ if (y >= maxY) {
+ return; // don't render lines beyond our maxY position
+ }
+
+ p.push(); // fix to #803
+
+ if (!this._isOpenType()) { // a system/browser font
+
+ // no stroke unless specified by user
+ if (this._doStroke && this._strokeSet) {
+
+ this.drawingContext.strokeText(line, x, y);
+ }
+
+ if (this._doFill) {
+
+ // if fill hasn't been set by user, use default text fill
+ this.drawingContext.fillStyle = this._fillSet ?
+ this.drawingContext.fillStyle : constants._DEFAULT_TEXT_FILL;
+
+ this.drawingContext.fillText(line, x, y);
+ }
+ }
+ else { // an opentype font, let it handle the rendering
+
+ this._textFont._renderPath(line, x, y, { renderer: this });
+ }
+
+ p.pop();
+
+ return p;
+};
+
+p5.Renderer2D.prototype.textWidth = function(s) {
+
+ if (this._isOpenType()) {
+
+ return this._textFont._textWidth(s, this._textSize);
+ }
+
+ return this.drawingContext.measureText(s).width;
+};
+
+p5.Renderer2D.prototype.textAlign = function(h, v) {
+
+ if (arguments.length) {
+
+ if (h === constants.LEFT ||
+ h === constants.RIGHT ||
+ h === constants.CENTER) {
+
+ this.drawingContext.textAlign = h;
+ }
+
+ if (v === constants.TOP ||
+ v === constants.BOTTOM ||
+ v === constants.CENTER ||
+ v === constants.BASELINE) {
+
+ if (v === constants.CENTER) {
+ this.drawingContext.textBaseline = constants._CTX_MIDDLE;
+ } else {
+ this.drawingContext.textBaseline = v;
+ }
+ }
+
+ return this._pInst;
+
+ } else {
+
+ var valign = this.drawingContext.textBaseline;
+
+ if (valign === constants._CTX_MIDDLE) {
+
+ valign = constants.CENTER;
+ }
+
+ return {
+
+ horizontal: this.drawingContext.textAlign,
+ vertical: valign
+ };
+ }
+};
+
+p5.Renderer2D.prototype._applyTextProperties = function() {
+
+ var font, p = this._pInst;
+
+ this._setProperty('_textAscent', null);
+ this._setProperty('_textDescent', null);
+
+ font = this._textFont;
+
+ if (this._isOpenType()) {
+
+ font = this._textFont.font.familyName;
+ this._setProperty('_textStyle', this._textFont.font.styleName);
+ }
+
+ this.drawingContext.font = this._textStyle + ' ' +
+ this._textSize + 'px ' + font;
+
+ return p;
+};
+
+
+//////////////////////////////////////////////
+// STRUCTURE
+//////////////////////////////////////////////
+
+p5.Renderer2D.prototype.push = function() {
+ this.drawingContext.save();
+};
+
+p5.Renderer2D.prototype.pop = function() {
+ this.drawingContext.restore();
+};
+
+module.exports = p5.Renderer2D;
+
+},{"../image/filters":59,"./canvas":40,"./constants":41,"./core":42,"./p5.Renderer":48}],50:[function(_dereq_,module,exports){
+/**
+ * @module Rendering
+ * @submodule Rendering
+ * @for p5
+ */
+
+var p5 = _dereq_('./core');
+var constants = _dereq_('./constants');
+_dereq_('./p5.Graphics');
+_dereq_('./p5.Renderer2D');
+_dereq_('../webgl/p5.RendererGL');
+var defaultId = 'defaultCanvas0'; // this gets set again in createCanvas
+
+/**
+ * Creates a canvas element in the document, and sets the dimensions of it
+ * in pixels. This method should be called only once at the start of setup.
+ * Calling createCanvas more than once in a sketch will result in very
+ * unpredicable behavior. If you want more than one drawing canvas
+ * you could use createGraphics (hidden by default but it can be shown).
+ *
+ * The system variables width and height are set by the parameters passed
+ * to this function. If createCanvas() is not used, the window will be
+ * given a default size of 100x100 pixels.
+ *
+ * For more ways to position the canvas, see the
+ *
+ * positioning the canvas wiki page.
+ *
+ * @method createCanvas
+ * @param {Number} w width of the canvas
+ * @param {Number} h height of the canvas
+ * @param {Constant} [renderer] P2D or WEBGL
+ * @return {Object} canvas generated
+ * @example
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.prototype.noCanvas = function() {
+ if (this.canvas) {
+ this.canvas.parentNode.removeChild(this.canvas);
+ }
+};
+
+/**
+ * Creates and returns a new p5.Renderer object. Use this class if you need
+ * to draw into an off-screen graphics buffer. The two parameters define the
+ * width and height in pixels.
+ *
+ * @method createGraphics
+ * @param {Number} w width of the offscreen graphics buffer
+ * @param {Number} h height of the offscreen graphics buffer
+ * @param {Constant} [renderer] P2D or WEBGL
+ * undefined defaults to p2d
+ * @return {Object} offscreen graphics buffer
+ * @example
+ *
+ *
+ * @alt
+ * 4 grey squares alternating light and dark grey. White quarter circle mid-left.
+ *
+ */
+p5.prototype.createGraphics = function(w, h, renderer){
+ return new p5.Graphics(w, h, renderer, this);
+};
+
+/**
+ * Blends the pixels in the display window according to the defined mode.
+ * There is a choice of the following modes to blend the source pixels (A)
+ * with the ones of pixels already in the display window (B):
+ *
+ *
BLEND - linear interpolation of colours: C =
+ * A*factor + B. This is the default blending mode.
+ *
ADD - sum of A and B
+ *
DARKEST - only the darkest colour succeeds: C =
+ * min(A*factor, B).
+ *
LIGHTEST - only the lightest colour succeeds: C =
+ * max(A*factor, B).
+ *
DIFFERENCE - subtract colors from underlying image.
+ *
EXCLUSION - similar to DIFFERENCE, but less
+ * extreme.
+ *
MULTIPLY - multiply the colors, result will always be
+ * darker.
+ *
SCREEN - opposite multiply, uses inverse values of the
+ * colors.
+ *
REPLACE - the pixels entirely replace the others and
+ * don't utilize alpha (transparency) values.
+ *
OVERLAY - mix of MULTIPLY and SCREEN
+ * . Multiplies dark values, and screens light values.
+ *
HARD_LIGHT - SCREEN when greater than 50%
+ * gray, MULTIPLY when lower.
+ *
SOFT_LIGHT - mix of DARKEST and
+ * LIGHTEST. Works like OVERLAY, but not as harsh.
+ *
+ * @alt
+ * translucent image thick red & blue diagonal rounded lines intersecting center
+ * Thick red & blue diagonal rounded lines intersecting center. dark at overlap
+ *
+ */
+p5.prototype.blendMode = function(mode) {
+ if (mode === constants.BLEND || mode === constants.DARKEST ||
+ mode === constants.LIGHTEST || mode === constants.DIFFERENCE ||
+ mode === constants.MULTIPLY || mode === constants.EXCLUSION ||
+ mode === constants.SCREEN || mode === constants.REPLACE ||
+ mode === constants.OVERLAY || mode === constants.HARD_LIGHT ||
+ mode === constants.SOFT_LIGHT || mode === constants.DODGE ||
+ mode === constants.BURN || mode === constants.ADD ||
+ mode === constants.NORMAL) {
+ this._renderer.blendMode(mode);
+ } else {
+ throw new Error('Mode '+mode+' not recognized.');
+ }
+};
+
+module.exports = p5;
+
+},{"../webgl/p5.RendererGL":91,"./constants":41,"./core":42,"./p5.Graphics":47,"./p5.Renderer2D":49}],51:[function(_dereq_,module,exports){
+
+// requestAnim shim layer by Paul Irish
+window.requestAnimationFrame = (function(){
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback, element){
+ // should '60' here be framerate?
+ window.setTimeout(callback, 1000 / 60);
+ };
+})();
+
+// use window.performance() to get max fast and accurate time in milliseconds
+window.performance = window.performance || {};
+window.performance.now = (function(){
+ var load_date = Date.now();
+ return window.performance.now ||
+ window.performance.mozNow ||
+ window.performance.msNow ||
+ window.performance.oNow ||
+ window.performance.webkitNow ||
+ function () {
+ return Date.now() - load_date;
+ };
+})();
+
+/*
+// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+// http://my.opera.com/emoller/blog/2011/12/20/
+// requestanimationframe-for-smart-er-animating
+// requestAnimationFrame polyfill by Erik Möller
+// fixes from Paul Irish and Tino Zijdel
+(function() {
+ var lastTime = 0;
+ var vendors = ['ms', 'moz', 'webkit', 'o'];
+ for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
+ window.requestAnimationFrame =
+ window[vendors[x]+'RequestAnimationFrame'];
+ window.cancelAnimationFrame =
+ window[vendors[x]+'CancelAnimationFrame'] ||
+ window[vendors[x]+'CancelRequestAnimationFrame'];
+ }
+
+ if (!window.requestAnimationFrame) {
+ window.requestAnimationFrame = function(callback, element) {
+ var currTime = new Date().getTime();
+ var timeToCall = Math.max(0, 16 - (currTime - lastTime));
+ var id = window.setTimeout(function()
+ { callback(currTime + timeToCall); }, timeToCall);
+ lastTime = currTime + timeToCall;
+ return id;
+ };
+ }
+
+ if (!window.cancelAnimationFrame) {
+ window.cancelAnimationFrame = function(id) {
+ clearTimeout(id);
+ };
+ }
+}());
+*/
+
+/**
+ * shim for Uint8ClampedArray.slice
+ * (allows arrayCopy to work with pixels[])
+ * with thanks to http://halfpapstudios.com/blog/tag/html5-canvas/
+ * Enumerable set to false to protect for...in from
+ * Uint8ClampedArray.prototype pollution.
+ */
+(function () {
+ 'use strict';
+ if (typeof Uint8ClampedArray !== 'undefined' &&
+ !Uint8ClampedArray.prototype.slice) {
+ Object.defineProperty(Uint8ClampedArray.prototype, 'slice', {
+ value: Array.prototype.slice,
+ writable: true, configurable: true, enumerable: false
+ });
+ }
+}());
+
+},{}],52:[function(_dereq_,module,exports){
+/**
+ * @module Structure
+ * @submodule Structure
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('./core');
+
+p5.prototype.exit = function() {
+ throw 'exit() not implemented, see remove()';
+};
+/**
+ * Stops p5.js from continuously executing the code within draw().
+ * If loop() is called, the code in draw() begins to run continuously again.
+ * If using noLoop() in setup(), it should be the last line inside the block.
+ *
+ * When noLoop() is used, it's not possible to manipulate or access the
+ * screen inside event handling functions such as mousePressed() or
+ * keyPressed(). Instead, use those functions to call redraw() or loop(),
+ * which will run draw(), which can update the screen properly. This means
+ * that when noLoop() has been called, no drawing can happen, and functions
+ * like saveFrame() or loadPixels() may not be used.
+ *
+ * Note that if the sketch is resized, redraw() will be called to update
+ * the sketch, even after noLoop() has been specified. Otherwise, the sketch
+ * would enter an odd state until loop() was called.
+ *
+ * @method noLoop
+ * @example
+ *
+ * var x = 0;
+ * function setup() {
+ * createCanvas(100, 100);
+ * }
+ *
+ * function draw() {
+ * background(204);
+ * x = x + 0.1;
+ * if (x > width) {
+ * x = 0;
+ * }
+ * line(x, 0, x, height);
+ * }
+ *
+ * function mousePressed() {
+ * noLoop();
+ * }
+ *
+ * function mouseReleased() {
+ * loop();
+ * }
+ *
+ *
+ * @alt
+ * 113 pixel long line extending from top-left to bottom right of canvas.
+ * horizontal line moves slowly from left. Loops but stops on mouse press.
+ *
+ */
+p5.prototype.noLoop = function() {
+ this._loop = false;
+};
+/**
+ * By default, p5.js loops through draw() continuously, executing the code
+ * within it. However, the draw() loop may be stopped by calling noLoop().
+ * In that case, the draw() loop can be resumed with loop().
+ *
+ * @method loop
+ * @example
+ *
+ * var x = 0;
+ * function setup() {
+ * createCanvas(100, 100);
+ * noLoop();
+ * }
+ *
+ * function draw() {
+ * background(204);
+ * x = x + 0.1;
+ * if (x > width) {
+ * x = 0;
+ * }
+ * line(x, 0, x, height);
+ * }
+ *
+ * function mousePressed() {
+ * loop();
+ * }
+ *
+ * function mouseReleased() {
+ * noLoop();
+ * }
+ *
+ *
+ * @alt
+ * horizontal line moves slowly from left. Loops but stops on mouse press.
+ *
+ */
+
+p5.prototype.loop = function() {
+ this._loop = true;
+ this._draw();
+};
+
+/**
+ * The push() function saves the current drawing style settings and
+ * transformations, while pop() restores these settings. Note that these
+ * functions are always used together. They allow you to change the style
+ * and transformation settings and later return to what you had. When a new
+ * state is started with push(), it builds on the current style and transform
+ * information. The push() and pop() functions can be embedded to provide
+ * more control. (See the second example for a demonstration.)
+ *
+ * push() stores information related to the current transformation state
+ * and style settings controlled by the following functions: fill(),
+ * stroke(), tint(), strokeWeight(), strokeCap(), strokeJoin(),
+ * imageMode(), rectMode(), ellipseMode(), colorMode(), textAlign(),
+ * textFont(), textMode(), textSize(), textLeading().
+ *
+ * @method push
+ * @example
+ *
+ *
+ * ellipse(0, 50, 33, 33); // Left circle
+ *
+ * push(); // Start a new drawing state
+ * strokeWeight(10);
+ * fill(204, 153, 0);
+ * translate(50, 0);
+ * ellipse(0, 50, 33, 33); // Middle circle
+ * pop(); // Restore original state
+ *
+ * ellipse(100, 50, 33, 33); // Right circle
+ *
+ *
+ *
+ *
+ * ellipse(0, 50, 33, 33); // Left circle
+ *
+ * push(); // Start a new drawing state
+ * strokeWeight(10);
+ * fill(204, 153, 0);
+ * ellipse(33, 50, 33, 33); // Left-middle circle
+ *
+ * push(); // Start another new drawing state
+ * stroke(0, 102, 153);
+ * ellipse(66, 50, 33, 33); // Right-middle circle
+ * pop(); // Restore previous state
+ *
+ * pop(); // Restore original state
+ *
+ * ellipse(100, 50, 33, 33); // Right circle
+ *
+ *
+ *
+ * @alt
+ * Gold ellipse + thick black outline @center 2 white ellipses on left and right.
+ * 2 Gold ellipses left black right blue stroke. 2 white ellipses on left+right.
+ *
+ */
+p5.prototype.push = function () {
+ this._renderer.push();
+ this._styles.push({
+ _doStroke: this._renderer._doStroke,
+ _strokeSet: this._renderer._strokeSet,
+ _doFill: this._renderer._doFill,
+ _fillSet: this._renderer._fillSet,
+ _tint: this._renderer._tint,
+ _imageMode: this._renderer._imageMode,
+ _rectMode: this._renderer._rectMode,
+ _ellipseMode: this._renderer._ellipseMode,
+ _colorMode: this._renderer._colorMode,
+ _textFont: this._renderer._textFont,
+ _textLeading: this._renderer._textLeading,
+ _textSize: this._renderer._textSize,
+ _textStyle: this._renderer._textStyle
+ });
+};
+
+/**
+ * The push() function saves the current drawing style settings and
+ * transformations, while pop() restores these settings. Note that these
+ * functions are always used together. They allow you to change the style
+ * and transformation settings and later return to what you had. When a new
+ * state is started with push(), it builds on the current style and transform
+ * information. The push() and pop() functions can be embedded to provide
+ * more control. (See the second example for a demonstration.)
+ *
+ * push() stores information related to the current transformation state
+ * and style settings controlled by the following functions: fill(),
+ * stroke(), tint(), strokeWeight(), strokeCap(), strokeJoin(),
+ * imageMode(), rectMode(), ellipseMode(), colorMode(), textAlign(),
+ * textFont(), textMode(), textSize(), textLeading().
+ *
+ * @method pop
+ * @example
+ *
+ *
+ * ellipse(0, 50, 33, 33); // Left circle
+ *
+ * push(); // Start a new drawing state
+ * translate(50, 0);
+ * strokeWeight(10);
+ * fill(204, 153, 0);
+ * ellipse(0, 50, 33, 33); // Middle circle
+ * pop(); // Restore original state
+ *
+ * ellipse(100, 50, 33, 33); // Right circle
+ *
+ *
+ *
+ *
+ * ellipse(0, 50, 33, 33); // Left circle
+ *
+ * push(); // Start a new drawing state
+ * strokeWeight(10);
+ * fill(204, 153, 0);
+ * ellipse(33, 50, 33, 33); // Left-middle circle
+ *
+ * push(); // Start another new drawing state
+ * stroke(0, 102, 153);
+ * ellipse(66, 50, 33, 33); // Right-middle circle
+ * pop(); // Restore previous state
+ *
+ * pop(); // Restore original state
+ *
+ * ellipse(100, 50, 33, 33); // Right circle
+ *
+ *
+ *
+ * @alt
+ * Gold ellipse + thick black outline @center 2 white ellipses on left and right.
+ * 2 Gold ellipses left black right blue stroke. 2 white ellipses on left+right.
+ *
+ */
+p5.prototype.pop = function () {
+ this._renderer.pop();
+ var lastS = this._styles.pop();
+ for(var prop in lastS){
+ this._renderer[prop] = lastS[prop];
+ }
+};
+
+p5.prototype.pushStyle = function() {
+ throw new Error('pushStyle() not used, see push()');
+};
+
+p5.prototype.popStyle = function() {
+ throw new Error('popStyle() not used, see pop()');
+};
+
+/**
+ *
+ * Executes the code within draw() one time. This functions allows the
+ * program to update the display window only when necessary, for example
+ * when an event registered by mousePressed() or keyPressed() occurs.
+ *
+ * In structuring a program, it only makes sense to call redraw() within
+ * events such as mousePressed(). This is because redraw() does not run
+ * draw() immediately (it only sets a flag that indicates an update is
+ * needed).
+ *
+ * The redraw() function does not work properly when called inside draw().
+ * To enable/disable animations, use loop() and noLoop().
+ *
+ * In addition you can set the number of redraws per method call. Just
+ * add an integer as single parameter for the number of redraws.
+ *
+ * @method redraw
+ * @param {Integer} [n] Redraw for n-times. The default value is 1.
+ * @example
+ *
+ *
+ * @alt
+ * black line on far left of canvas
+ * black line on far left of canvas
+ *
+ */
+p5.prototype.redraw = function () {
+ this.resetMatrix();
+ if(this._renderer.isP3D){
+ this._renderer._update();
+ }
+
+ var numberOfRedraws = 1;
+ if (arguments.length === 1) {
+ try {
+ if (parseInt(arguments[0]) > 1) {
+ numberOfRedraws = parseInt(arguments[0]);
+ }
+ } catch (error) {
+ // Do nothing, because the default value didn't be changed.
+ }
+ }
+ var userSetup = this.setup || window.setup;
+ var userDraw = this.draw || window.draw;
+ if (typeof userDraw === 'function') {
+ if (typeof userSetup === 'undefined') {
+ this.scale(this._pixelDensity, this._pixelDensity);
+ }
+ var self = this;
+ var callMethod = function (f) {
+ f.call(self);
+ };
+ for (var idxRedraw = 0; idxRedraw < numberOfRedraws; idxRedraw++) {
+ this._registeredMethods.pre.forEach(callMethod);
+ userDraw();
+ this._registeredMethods.post.forEach(callMethod);
+ }
+ }
+};
+
+p5.prototype.size = function() {
+ var s = 'size() is not a valid p5 function, to set the size of the ';
+ s += 'drawing canvas, please use createCanvas() instead';
+ throw s;
+};
+
+
+module.exports = p5;
+
+},{"./core":42}],53:[function(_dereq_,module,exports){
+/**
+ * @module Transform
+ * @submodule Transform
+ * @for p5
+ * @requires core
+ * @requires constants
+ */
+
+
+'use strict';
+
+var p5 = _dereq_('./core');
+var constants = _dereq_('./constants');
+
+/**
+ * Multiplies the current matrix by the one specified through the parameters.
+ * This is very slow because it will try to calculate the inverse of the
+ * transform, so avoid it whenever possible.
+ *
+ * @method applyMatrix
+ * @param {Number} n00 numbers which define the 3x2 matrix to be multiplied
+ * @param {Number} n01 numbers which define the 3x2 matrix to be multiplied
+ * @param {Number} n02 numbers which define the 3x2 matrix to be multiplied
+ * @param {Number} n10 numbers which define the 3x2 matrix to be multiplied
+ * @param {Number} n11 numbers which define the 3x2 matrix to be multiplied
+ * @param {Number} n12 numbers which define the 3x2 matrix to be multiplied
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * // Example in the works.
+ *
+ *
+ *
+ * @alt
+ * no image diplayed
+ *
+ */
+p5.prototype.applyMatrix = function(n00, n01, n02, n10, n11, n12) {
+ this._renderer.applyMatrix(n00, n01, n02, n10, n11, n12);
+ return this;
+};
+
+p5.prototype.popMatrix = function() {
+ throw new Error('popMatrix() not used, see pop()');
+};
+
+p5.prototype.printMatrix = function() {
+ throw new Error('printMatrix() not implemented');
+};
+
+p5.prototype.pushMatrix = function() {
+ throw new Error('pushMatrix() not used, see push()');
+};
+
+/**
+ * Replaces the current matrix with the identity matrix.
+ *
+ * @method resetMatrix
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * // Example in the works.
+ *
+ *
+ *
+ * @alt
+ * no image diplayed
+ *
+ */
+p5.prototype.resetMatrix = function() {
+ this._renderer.resetMatrix();
+ return this;
+};
+
+/**
+ * Rotates a shape the amount specified by the angle parameter. This
+ * function accounts for angleMode, so angles can be entered in either
+ * RADIANS or DEGREES.
+ *
+ * Objects are always rotated around their relative position to the
+ * origin and positive numbers rotate objects in a clockwise direction.
+ * Transformations apply to everything that happens after and subsequent
+ * calls to the function accumulates the effect. For example, calling
+ * rotate(HALF_PI) and then rotate(HALF_PI) is the same as rotate(PI).
+ * All tranformations are reset when draw() begins again.
+ *
+ * Technically, rotate() multiplies the current transformation matrix
+ * by a rotation matrix. This function can be further controlled by
+ * the push() and pop().
+ *
+ * @method rotate
+ * @param {Number} angle the angle of rotation, specified in radians
+ * or degrees, depending on current angleMode
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * white 52x52 rect with black outline at center rotated counter 45 degrees
+ *
+ */
+/**
+ * @method rotate
+ * @param {Number} rad angle in radians
+ * @param {p5.Vector|Array} axis axis to rotate around
+ * @return {p5} the p5 object
+ */
+p5.prototype.rotate = function() {
+ var args = new Array(arguments.length);
+ var r;
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ if (this._angleMode === constants.DEGREES) {
+ r = this.radians(args[0]);
+ } else if (this._angleMode === constants.RADIANS){
+ r = args[0];
+ }
+ //in webgl mode
+ if(args.length > 1){
+ this._renderer.rotate(r, args[1]);
+ }
+ else {
+ this._renderer.rotate(r);
+ }
+ return this;
+};
+
+/**
+ * Rotates around X axis.
+ * @method rotateX
+ * @param {Number} rad angles in radians
+ * @return {p5} the p5 object
+ */
+p5.prototype.rotateX = function(rad) {
+ if (this._renderer.isP3D) {
+ this._renderer.rotateX(rad);
+ } else {
+ throw 'not supported in p2d. Please use webgl mode';
+ }
+ return this;
+};
+
+/**
+ * Rotates around Y axis.
+ * @method rotateY
+ * @param {Number} rad angles in radians
+ * @return {p5} the p5 object
+ */
+p5.prototype.rotateY = function(rad) {
+ if (this._renderer.isP3D) {
+ this._renderer.rotateY(rad);
+ } else {
+ throw 'not supported in p2d. Please use webgl mode';
+ }
+ return this;
+};
+
+/**
+ * Rotates around Z axis. Webgl mode only.
+ * @method rotateZ
+ * @param {Number} rad angles in radians
+ * @return {p5} the p5 object
+ */
+p5.prototype.rotateZ = function(rad) {
+ if (this._renderer.isP3D) {
+ this._renderer.rotateZ(rad);
+ } else {
+ throw 'not supported in p2d. Please use webgl mode';
+ }
+ return this;
+};
+
+/**
+ * Increases or decreases the size of a shape by expanding and contracting
+ * vertices. Objects always scale from their relative origin to the
+ * coordinate system. Scale values are specified as decimal percentages.
+ * For example, the function call scale(2.0) increases the dimension of a
+ * shape by 200%.
+ *
+ * Transformations apply to everything that happens after and subsequent
+ * calls to the function multiply the effect. For example, calling scale(2.0)
+ * and then scale(1.5) is the same as scale(3.0). If scale() is called
+ * within draw(), the transformation is reset when the loop begins again.
+ *
+ * Using this function with the z parameter is only available in WEBGL mode.
+ * This function can be further controlled with push() and pop().
+ *
+ * @method scale
+ * @param {Number|p5.Vector|Array} s
+ * percent to scale the object, or percentage to
+ * scale the object in the x-axis if multiple arguments
+ * are given
+ * @param {Number} [y] percent to scale the object in the y-axis
+ * @param {Number} [z] percent to scale the object in the z-axis (webgl only)
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * white 52x52 rect with black outline at center rotated counter 45 degrees
+ * 2 white rects with black outline- 1 50x50 at center. other 25x65 bottom left
+ *
+ */
+p5.prototype.scale = function() {
+ var x,y,z;
+ var args = new Array(arguments.length);
+ for(var i = 0; i < args.length; i++) {
+ args[i] = arguments[i];
+ }
+ if(args[0] instanceof p5.Vector){
+ x = args[0].x;
+ y = args[0].y;
+ z = args[0].z;
+ }
+ else if(args[0] instanceof Array){
+ x = args[0][0];
+ y = args[0][1];
+ z = args[0][2] || 1;
+ }
+ else {
+ if(args.length === 1){
+ x = y = z = args[0];
+ }
+ else {
+ x = args[0];
+ y = args[1];
+ z = args[2] || 1;
+ }
+ }
+
+ if(this._renderer.isP3D){
+ this._renderer.scale.call(this._renderer, x,y,z);
+ }
+ else {
+ this._renderer.scale.call(this._renderer, x,y);
+ }
+ return this;
+};
+
+/**
+ * Shears a shape around the x-axis the amount specified by the angle
+ * parameter. Angles should be specified in the current angleMode.
+ * Objects are always sheared around their relative position to the origin
+ * and positive numbers shear objects in a clockwise direction.
+ *
+ * Transformations apply to everything that happens after and subsequent
+ * calls to the function accumulates the effect. For example, calling
+ * shearX(PI/2) and then shearX(PI/2) is the same as shearX(PI).
+ * If shearX() is called within the draw(), the transformation is reset when
+ * the loop begins again.
+ *
+ * Technically, shearX() multiplies the current transformation matrix by a
+ * rotation matrix. This function can be further controlled by the
+ * push() and pop() functions.
+ *
+ * @method shearX
+ * @param {Number} angle angle of shear specified in radians or degrees,
+ * depending on current angleMode
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * white irregular quadrilateral with black outline at top middle.
+ *
+ */
+p5.prototype.shearX = function(angle) {
+ if (this._angleMode === constants.DEGREES) {
+ angle = this.radians(angle);
+ }
+ this._renderer.shearX(angle);
+ return this;
+};
+
+/**
+ * Shears a shape around the y-axis the amount specified by the angle
+ * parameter. Angles should be specified in the current angleMode. Objects
+ * are always sheared around their relative position to the origin and
+ * positive numbers shear objects in a clockwise direction.
+ *
+ * Transformations apply to everything that happens after and subsequent
+ * calls to the function accumulates the effect. For example, calling
+ * shearY(PI/2) and then shearY(PI/2) is the same as shearY(PI). If
+ * shearY() is called within the draw(), the transformation is reset when
+ * the loop begins again.
+ *
+ * Technically, shearY() multiplies the current transformation matrix by a
+ * rotation matrix. This function can be further controlled by the
+ * push() and pop() functions.
+ *
+ * @method shearY
+ * @param {Number} angle angle of shear specified in radians or degrees,
+ * depending on current angleMode
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * white irregular quadrilateral with black outline at middle bottom.
+ *
+ */
+p5.prototype.shearY = function(angle) {
+ if (this._angleMode === constants.DEGREES) {
+ angle = this.radians(angle);
+ }
+ this._renderer.shearY(angle);
+ return this;
+};
+
+/**
+ * Specifies an amount to displace objects within the display window.
+ * The x parameter specifies left/right translation, the y parameter
+ * specifies up/down translation.
+ *
+ * Transformations are cumulative and apply to everything that happens after
+ * and subsequent calls to the function accumulates the effect. For example,
+ * calling translate(50, 0) and then translate(20, 0) is the same as
+ * translate(70, 0). If translate() is called within draw(), the
+ * transformation is reset when the loop begins again. This function can be
+ * further controlled by using push() and pop().
+ *
+ * @method translate
+ * @param {Number} x left/right translation
+ * @param {Number} y up/down translation
+ * @param {Number} [z] forward/backward translation (webgl only)
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * rect(0, 0, 55, 55); // Draw rect at original 0,0
+ * translate(30, 20);
+ * rect(0, 0, 55, 55); // Draw rect at new 0,0
+ * translate(14, 14);
+ * rect(0, 0, 55, 55); // Draw rect at new 0,0
+ *
+ *
+ *
+ * @alt
+ * white 55x55 rect with black outline at center right.
+ * 3 white 55x55 rects with black outlines at top-l, center-r and bottom-r.
+ *
+ */
+p5.prototype.translate = function(x, y, z) {
+ if (this._renderer.isP3D) {
+ this._renderer.translate(x, y, z);
+ } else {
+ this._renderer.translate(x, y);
+ }
+ return this;
+};
+
+module.exports = p5;
+
+},{"./constants":41,"./core":42}],54:[function(_dereq_,module,exports){
+/**
+ * @module Shape
+ * @submodule Vertex
+ * @for p5
+ * @requires core
+ * @requires constants
+ */
+
+'use strict';
+
+var p5 = _dereq_('./core');
+var constants = _dereq_('./constants');
+var shapeKind = null;
+var vertices = [];
+var contourVertices = [];
+var isBezier = false;
+var isCurve = false;
+var isQuadratic = false;
+var isContour = false;
+var isFirstContour = true;
+
+/**
+ * Use the beginContour() and endContour() functions to create negative
+ * shapes within shapes such as the center of the letter 'O'. beginContour()
+ * begins recording vertices for the shape and endContour() stops recording.
+ * The vertices that define a negative shape must "wind" in the opposite
+ * direction from the exterior shape. First draw vertices for the exterior
+ * clockwise order, then for internal shapes, draw vertices
+ * shape in counter-clockwise.
+ *
+ * These functions can only be used within a beginShape()/endShape() pair and
+ * transformations such as translate(), rotate(), and scale() do not work
+ * within a beginContour()/endContour() pair. It is also not possible to use
+ * other shapes, such as ellipse() or rect() within.
+ *
+ * @method beginContour
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * white rect and smaller grey rect with red outlines in center of canvas.
+ *
+ */
+p5.prototype.beginContour = function() {
+ contourVertices = [];
+ isContour = true;
+ return this;
+};
+
+/**
+ * Using the beginShape() and endShape() functions allow creating more
+ * complex forms. beginShape() begins recording vertices for a shape and
+ * endShape() stops recording. The value of the kind parameter tells it which
+ * types of shapes to create from the provided vertices. With no mode
+ * specified, the shape can be any irregular polygon.
+ *
+ * The parameters available for beginShape() are POINTS, LINES, TRIANGLES,
+ * TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, and QUAD_STRIP. After calling the
+ * beginShape() function, a series of vertex() commands must follow. To stop
+ * drawing the shape, call endShape(). Each shape will be outlined with the
+ * current stroke color and filled with the fill color.
+ *
+ * Transformations such as translate(), rotate(), and scale() do not work
+ * within beginShape(). It is also not possible to use other shapes, such as
+ * ellipse() or rect() within beginShape().
+ *
+ * @method beginShape
+ * @param {Constant} kind either POINTS, LINES, TRIANGLES, TRIANGLE_FAN
+ * TRIANGLE_STRIP, QUADS, or QUAD_STRIP
+ * @return {Object} the p5 object
+ * @example
+ *
+ * @alt
+ * white square-shape with black outline in middle-right of canvas.
+ * 4 black points in a square shape in middle-right of canvas.
+ * 2 horizontal black lines. In the top-right and bottom-right of canvas.
+ * 3 line shape with horizontal on top, vertical in middle and horizontal bottom.
+ * square line shape in middle-right of canvas.
+ * 2 white triangle shapes mid-right canvas. left one pointing up and right down.
+ * 5 horizontal interlocking and alternating white triangles in mid-right canvas.
+ * 4 interlocking white triangles in 45 degree rotated square-shape.
+ * 2 white rectangle shapes in mid-right canvas. Both 20x55.
+ * 3 side-by-side white rectangles center rect is smaller in mid-right canvas.
+ * Thick white l-shape with black outline mid-top-left of canvas.
+ *
+ */
+p5.prototype.beginShape = function(kind) {
+ if (kind === constants.POINTS ||
+ kind === constants.LINES ||
+ kind === constants.TRIANGLES ||
+ kind === constants.TRIANGLE_FAN ||
+ kind === constants.TRIANGLE_STRIP ||
+ kind === constants.QUADS ||
+ kind === constants.QUAD_STRIP) {
+ shapeKind = kind;
+ } else {
+ shapeKind = null;
+ }
+ if(this._renderer.isP3D){
+ this._renderer.beginShape(kind);
+ } else {
+ vertices = [];
+ contourVertices = [];
+ }
+ return this;
+};
+
+/**
+ * Specifies vertex coordinates for Bezier curves. Each call to
+ * bezierVertex() defines the position of two control points and
+ * one anchor point of a Bezier curve, adding a new segment to a
+ * line or shape.
+ *
+ * The first time bezierVertex() is used within a
+ * beginShape() call, it must be prefaced with a call to vertex()
+ * to set the first anchor point. This function must be used between
+ * beginShape() and endShape() and only when there is no MODE
+ * parameter specified to beginShape().
+ *
+ * @method bezierVertex
+ * @param {Number} x2 x-coordinate for the first control point
+ * @param {Number} y2 y-coordinate for the first control point
+ * @param {Number} x3 x-coordinate for the second control point
+ * @param {Number} y3 y-coordinate for the second control point
+ * @param {Number} x4 x-coordinate for the anchor point
+ * @param {Number} y4 y-coordinate for the anchor point
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * crescent-shaped line in middle of canvas. Points facing left.
+ * white crescent shape in middle of canvas. Points facing left.
+ *
+ */
+p5.prototype.bezierVertex = function(x2, y2, x3, y3, x4, y4) {
+ if (vertices.length === 0) {
+ throw 'vertex() must be used once before calling bezierVertex()';
+ } else {
+ isBezier = true;
+ var vert = [];
+ for (var i = 0; i < arguments.length; i++) {
+ vert[i] = arguments[i];
+ }
+ vert.isVert = false;
+ if (isContour) {
+ contourVertices.push(vert);
+ } else {
+ vertices.push(vert);
+ }
+ }
+ return this;
+};
+
+/**
+ * Specifies vertex coordinates for curves. This function may only
+ * be used between beginShape() and endShape() and only when there
+ * is no MODE parameter specified to beginShape().
+ *
+ * The first and last points in a series of curveVertex() lines will be used to
+ * guide the beginning and end of a the curve. A minimum of four
+ * points is required to draw a tiny curve between the second and
+ * third points. Adding a fifth point with curveVertex() will draw
+ * the curve between the second, third, and fourth points. The
+ * curveVertex() function is an implementation of Catmull-Rom
+ * splines.
+ *
+ * @method curveVertex
+ * @param {Number} x x-coordinate of the vertex
+ * @param {Number} y y-coordinate of the vertex
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * Upside-down u-shape line, mid canvas. left point extends beyond canvas view.
+ *
+ */
+p5.prototype.curveVertex = function(x,y) {
+ isCurve = true;
+ this.vertex(x, y);
+ return this;
+};
+
+/**
+ * Use the beginContour() and endContour() functions to create negative
+ * shapes within shapes such as the center of the letter 'O'. beginContour()
+ * begins recording vertices for the shape and endContour() stops recording.
+ * The vertices that define a negative shape must "wind" in the opposite
+ * direction from the exterior shape. First draw vertices for the exterior
+ * clockwise order, then for internal shapes, draw vertices
+ * shape in counter-clockwise.
+ *
+ * These functions can only be used within a beginShape()/endShape() pair and
+ * transformations such as translate(), rotate(), and scale() do not work
+ * within a beginContour()/endContour() pair. It is also not possible to use
+ * other shapes, such as ellipse() or rect() within.
+ *
+ * @method endContour
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * white rect and smaller grey rect with red outlines in center of canvas.
+ *
+ */
+p5.prototype.endContour = function() {
+ var vert = contourVertices[0].slice(); // copy all data
+ vert.isVert = contourVertices[0].isVert;
+ vert.moveTo = false;
+ contourVertices.push(vert);
+
+ // prevent stray lines with multiple contours
+ if (isFirstContour) {
+ vertices.push(vertices[0]);
+ isFirstContour = false;
+ }
+
+ for (var i = 0; i < contourVertices.length; i++) {
+ vertices.push(contourVertices[i]);
+ }
+ return this;
+};
+
+/**
+ * The endShape() function is the companion to beginShape() and may only be
+ * called after beginShape(). When endshape() is called, all of image data
+ * defined since the previous call to beginShape() is written into the image
+ * buffer. The constant CLOSE as the value for the MODE parameter to close
+ * the shape (to connect the beginning and the end).
+ *
+ * @method endShape
+ * @param {Constant} mode use CLOSE to close the shape
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * Triangle line shape with smallest interior angle on bottom and upside-down L.
+ *
+ */
+p5.prototype.endShape = function(mode) {
+ if(this._renderer.isP3D){
+ this._renderer.endShape(mode, isCurve, isBezier,
+ isQuadratic, isContour, shapeKind);
+ }else{
+ if (vertices.length === 0) { return this; }
+ if (!this._renderer._doStroke && !this._renderer._doFill) { return this; }
+
+ var closeShape = mode === constants.CLOSE;
+
+ // if the shape is closed, the first element is also the last element
+ if (closeShape && !isContour) {
+ vertices.push(vertices[0]);
+ }
+
+ this._renderer.endShape(mode, vertices, isCurve, isBezier,
+ isQuadratic, isContour, shapeKind);
+
+ // Reset some settings
+ isCurve = false;
+ isBezier = false;
+ isQuadratic = false;
+ isContour = false;
+ isFirstContour = true;
+
+ // If the shape is closed, the first element was added as last element.
+ // We must remove it again to prevent the list of vertices from growing
+ // over successive calls to endShape(CLOSE)
+ if (closeShape) {
+ vertices.pop();
+ }
+ }
+ return this;
+};
+
+/**
+ * Specifies vertex coordinates for quadratic Bezier curves. Each call to
+ * quadraticVertex() defines the position of one control points and one
+ * anchor point of a Bezier curve, adding a new segment to a line or shape.
+ * The first time quadraticVertex() is used within a beginShape() call, it
+ * must be prefaced with a call to vertex() to set the first anchor point.
+ * This function must be used between beginShape() and endShape() and only
+ * when there is no MODE parameter specified to beginShape().
+ *
+ * @method quadraticVertex
+ * @param {Number} cx x-coordinate for the control point
+ * @param {Number} cy y-coordinate for the control point
+ * @param {Number} x3 x-coordinate for the anchor point
+ * @param {Number} y3 y-coordinate for the anchor point
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * arched-shaped black line with 4 pixel thick stroke weight.
+ * backwards s-shaped black line with 4 pixel thick stroke weight.
+ *
+ */
+p5.prototype.quadraticVertex = function(cx, cy, x3, y3) {
+ //if we're drawing a contour, put the points into an
+ // array for inside drawing
+ if(this._contourInited) {
+ var pt = {};
+ pt.x = cx;
+ pt.y = cy;
+ pt.x3 = x3;
+ pt.y3 = y3;
+ pt.type = constants.QUADRATIC;
+ this._contourVertices.push(pt);
+
+ return this;
+ }
+ if (vertices.length > 0) {
+ isQuadratic = true;
+ var vert = [];
+ for (var i = 0; i < arguments.length; i++) {
+ vert[i] = arguments[i];
+ }
+ vert.isVert = false;
+ if (isContour) {
+ contourVertices.push(vert);
+ } else {
+ vertices.push(vert);
+ }
+ } else {
+ throw 'vertex() must be used once before calling quadraticVertex()';
+ }
+ return this;
+};
+
+/**
+ * All shapes are constructed by connecting a series of vertices. vertex()
+ * is used to specify the vertex coordinates for points, lines, triangles,
+ * quads, and polygons. It is used exclusively within the beginShape() and
+ * endShape() functions.
+ *
+ * @method vertex
+ * @param {Number} x x-coordinate of the vertex
+ * @param {Number} y y-coordinate of the vertex
+ * @return {Object} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * 4 black points in a square shape in middle-right of canvas.
+ *
+ */
+p5.prototype.vertex = function(x, y, moveTo) {
+ if(this._renderer.isP3D){
+ this._renderer.vertex(x, y, moveTo);
+ }else{
+ var vert = [];
+ vert.isVert = true;
+ vert[0] = x;
+ vert[1] = y;
+ vert[2] = 0;
+ vert[3] = 0;
+ vert[4] = 0;
+ vert[5] = this._renderer._getFill();
+ vert[6] = this._renderer._getStroke();
+
+ if (moveTo) {
+ vert.moveTo = moveTo;
+ }
+ if (isContour) {
+ if (contourVertices.length === 0) {
+ vert.moveTo = true;
+ }
+ contourVertices.push(vert);
+ } else {
+ vertices.push(vert);
+ }
+ }
+ return this;
+};
+
+module.exports = p5;
+
+},{"./constants":41,"./core":42}],55:[function(_dereq_,module,exports){
+/**
+ * @module Events
+ * @submodule Acceleration
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * The system variable deviceOrientation always contains the orientation of
+ * the device. The value of this variable will either be set 'landscape'
+ * or 'portrait'. If no data is available it will be set to 'undefined'.
+ *
+ * @property deviceOrientation
+ */
+p5.prototype.deviceOrientation = undefined;
+
+/**
+ * The system variable accelerationX always contains the acceleration of the
+ * device along the x axis. Value is represented as meters per second squared.
+ *
+ * @property accelerationX
+ */
+p5.prototype.accelerationX = 0;
+
+/**
+ * The system variable accelerationY always contains the acceleration of the
+ * device along the y axis. Value is represented as meters per second squared.
+ *
+ * @property accelerationY
+ */
+p5.prototype.accelerationY = 0;
+
+/**
+ * The system variable accelerationZ always contains the acceleration of the
+ * device along the z axis. Value is represented as meters per second squared.
+ *
+ * @property accelerationZ
+ */
+p5.prototype.accelerationZ = 0;
+
+/**
+ * The system variable pAccelerationX always contains the acceleration of the
+ * device along the x axis in the frame previous to the current frame. Value
+ * is represented as meters per second squared.
+ *
+ * @property pAccelerationX
+ */
+p5.prototype.pAccelerationX = 0;
+
+/**
+ * The system variable pAccelerationY always contains the acceleration of the
+ * device along the y axis in the frame previous to the current frame. Value
+ * is represented as meters per second squared.
+ *
+ * @property pAccelerationY
+ */
+p5.prototype.pAccelerationY = 0;
+
+/**
+ * The system variable pAccelerationZ always contains the acceleration of the
+ * device along the z axis in the frame previous to the current frame. Value
+ * is represented as meters per second squared.
+ *
+ * @property pAccelerationZ
+ */
+p5.prototype.pAccelerationZ = 0;
+
+/**
+ * _updatePAccelerations updates the pAcceleration values
+ *
+ * @private
+ */
+p5.prototype._updatePAccelerations = function(){
+ this._setProperty('pAccelerationX', this.accelerationX);
+ this._setProperty('pAccelerationY', this.accelerationY);
+ this._setProperty('pAccelerationZ', this.accelerationZ);
+};
+
+/**
+ * The system variable rotationX always contains the rotation of the
+ * device along the x axis. Value is represented as 0 to +/-180 degrees.
+ *
+ * Note: The order the rotations are called is important, ie. if used
+ * together, it must be called in the order Z-X-Y or there might be
+ * unexpected behaviour.
+ *
+ * @example
+ *
+ *
+ * @property rotationX
+ *
+ * @alt
+ * red horizontal line right, green vertical line bottom. black background.
+ *
+ */
+p5.prototype.rotationX = 0;
+
+/**
+ * The system variable rotationY always contains the rotation of the
+ * device along the y axis. Value is represented as 0 to +/-90 degrees.
+ *
+ * Note: The order the rotations are called is important, ie. if used
+ * together, it must be called in the order Z-X-Y or there might be
+ * unexpected behaviour.
+ *
+ * @example
+ *
+ *
+ * @property rotationY
+ *
+ * @alt
+ * red horizontal line right, green vertical line bottom. black background.
+ */
+p5.prototype.rotationY = 0;
+
+/**
+ * The system variable rotationZ always contains the rotation of the
+ * device along the z axis. Value is represented as 0 to 359 degrees.
+ *
+ * Unlike rotationX and rotationY, this variable is available for devices
+ * with a built-in compass only.
+ *
+ * Note: The order the rotations are called is important, ie. if used
+ * together, it must be called in the order Z-X-Y or there might be
+ * unexpected behaviour.
+ *
+ * @example
+ *
+ *
+ * @property rotationZ
+ *
+ * @alt
+ * red horizontal line right, green vertical line bottom. black background.
+ */
+p5.prototype.rotationZ = 0;
+
+/**
+ * The system variable pRotationX always contains the rotation of the
+ * device along the x axis in the frame previous to the current frame. Value
+ * is represented as 0 to +/-180 degrees.
+ *
+ * pRotationX can also be used with rotationX to determine the rotate
+ * direction of the device along the X-axis.
+ * @example
+ *
+ *
+ * // A simple if statement looking at whether
+ * // rotationX - pRotationX < 0 is true or not will be
+ * // sufficient for determining the rotate direction
+ * // in most cases.
+ *
+ * // Some extra logic is needed to account for cases where
+ * // the angles wrap around.
+ * var rotateDirection = 'clockwise';
+ *
+ * // Simple range conversion to make things simpler.
+ * // This is not absolutely neccessary but the logic
+ * // will be different in that case.
+ *
+ * var rX = rotationX + 180;
+ * var pRX = pRotationX + 180;
+ *
+ * if ((rX - pRX > 0 && rX - pRX < 270)|| rX - pRX < -270){
+ * rotateDirection = 'clockwise';
+ * } else if (rX - pRX < 0 || rX - pRX > 270){
+ * rotateDirection = 'counter-clockwise';
+ * }
+ *
+ *
+ *
+ * @alt
+ * no image to display.
+ *
+ *
+ * @property pRotationX
+ */
+p5.prototype.pRotationX = 0;
+
+/**
+ * The system variable pRotationY always contains the rotation of the
+ * device along the y axis in the frame previous to the current frame. Value
+ * is represented as 0 to +/-90 degrees.
+ *
+ * pRotationY can also be used with rotationY to determine the rotate
+ * direction of the device along the Y-axis.
+ * @example
+ *
+ *
+ * // A simple if statement looking at whether
+ * // rotationY - pRotationY < 0 is true or not will be
+ * // sufficient for determining the rotate direction
+ * // in most cases.
+ *
+ * // Some extra logic is needed to account for cases where
+ * // the angles wrap around.
+ * var rotateDirection = 'clockwise';
+ *
+ * // Simple range conversion to make things simpler.
+ * // This is not absolutely neccessary but the logic
+ * // will be different in that case.
+ *
+ * var rY = rotationY + 180;
+ * var pRY = pRotationY + 180;
+ *
+ * if ((rY - pRY > 0 && rY - pRY < 270)|| rY - pRY < -270){
+ * rotateDirection = 'clockwise';
+ * } else if (rY - pRY < 0 || rY - pRY > 270){
+ * rotateDirection = 'counter-clockwise';
+ * }
+ *
+ *
+ *
+ * @alt
+ * no image to display.
+ *
+ *
+ * @property pRotationY
+ */
+p5.prototype.pRotationY = 0;
+
+/**
+ * The system variable pRotationZ always contains the rotation of the
+ * device along the z axis in the frame previous to the current frame. Value
+ * is represented as 0 to 359 degrees.
+ *
+ * pRotationZ can also be used with rotationZ to determine the rotate
+ * direction of the device along the Z-axis.
+ * @example
+ *
+ *
+ * // A simple if statement looking at whether
+ * // rotationZ - pRotationZ < 0 is true or not will be
+ * // sufficient for determining the rotate direction
+ * // in most cases.
+ *
+ * // Some extra logic is needed to account for cases where
+ * // the angles wrap around.
+ * var rotateDirection = 'clockwise';
+ *
+ * if ((rotationZ - pRotationZ > 0 &&
+ * rotationZ - pRotationZ < 270)||
+ * rotationZ - pRotationZ < -270){
+ *
+ * rotateDirection = 'clockwise';
+ *
+ * } else if (rotationZ - pRotationZ < 0 ||
+ * rotationZ - pRotationZ > 270){
+ *
+ * rotateDirection = 'counter-clockwise';
+ *
+ * }
+ *
+ *
+ *
+ * @alt
+ * no image to display.
+ *
+ *
+ * @property pRotationZ
+ */
+p5.prototype.pRotationZ = 0;
+
+var startAngleX = 0;
+var startAngleY = 0;
+var startAngleZ = 0;
+
+var rotateDirectionX = 'clockwise';
+var rotateDirectionY = 'clockwise';
+var rotateDirectionZ = 'clockwise';
+
+var pRotateDirectionX;
+var pRotateDirectionY;
+var pRotateDirectionZ;
+
+p5.prototype._updatePRotations = function(){
+ this._setProperty('pRotationX', this.rotationX);
+ this._setProperty('pRotationY', this.rotationY);
+ this._setProperty('pRotationZ', this.rotationZ);
+};
+
+p5.prototype.turnAxis = undefined;
+
+var move_threshold = 0.5;
+var shake_threshold = 30;
+
+/**
+ * The setMoveThreshold() function is used to set the movement threshold for
+ * the deviceMoved() function. The default threshold is set to 0.5.
+ *
+ * @method setMoveThreshold
+ * @param {number} value The threshold value
+ */
+p5.prototype.setMoveThreshold = function(val){
+ if(typeof val === 'number'){
+ move_threshold = val;
+ }
+};
+
+/**
+ * The setShakeThreshold() function is used to set the movement threshold for
+ * the deviceShaken() function. The default threshold is set to 30.
+ *
+ * @method setShakeThreshold
+ * @param {number} value The threshold value
+ */
+p5.prototype.setShakeThreshold = function(val){
+ if(typeof val === 'number'){
+ shake_threshold = val;
+ }
+};
+
+/**
+ * The deviceMoved() function is called when the device is moved by more than
+ * the threshold value along X, Y or Z axis. The default threshold is set to
+ * 0.5.
+ * @method deviceMoved
+ * @example
+ *
+ *
+ * // Run this example on a mobile device
+ * // Move the device around
+ * // to change the value.
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function deviceMoved() {
+ * value = value + 5;
+ * if (value > 255) {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * 50x50 black rect in center of canvas. turns white on mobile when device moves
+ *
+ */
+
+/**
+ * The deviceTurned() function is called when the device rotates by
+ * more than 90 degrees continuously.
+ *
+ * The axis that triggers the deviceTurned() method is stored in the turnAxis
+ * variable. The deviceTurned() method can be locked to trigger on any axis:
+ * X, Y or Z by comparing the turnAxis variable to 'X', 'Y' or 'Z'.
+ *
+ * @method deviceTurned
+ * @example
+ *
+ *
+ * // Run this example on a mobile device
+ * // Rotate the device by 90 degrees
+ * // to change the value.
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function deviceTurned() {
+ * if (value == 0){
+ * value = 255
+ * } else if (value == 255) {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ *
+ * // Run this example on a mobile device
+ * // Rotate the device by 90 degrees in the
+ * // X-axis to change the value.
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function deviceTurned() {
+ * if (turnAxis == 'X'){
+ * if (value == 0){
+ * value = 255
+ * } else if (value == 255) {
+ * value = 0;
+ * }
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * 50x50 black rect in center of canvas. turns white on mobile when device turns
+ * 50x50 black rect in center of canvas. turns white on mobile when x-axis turns
+ *
+ */
+
+/**
+ * The deviceShaken() function is called when the device total acceleration
+ * changes of accelerationX and accelerationY values is more than
+ * the threshold value. The default threshold is set to 30.
+ * @method deviceShaken
+ * @example
+ *
+ *
+ * // Run this example on a mobile device
+ * // Shake the device to change the value.
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function deviceShaken() {
+ * value = value + 5;
+ * if (value > 255) {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * 50x50 black rect in center of canvas. turns white on mobile when device shakes
+ *
+ */
+
+p5.prototype._ondeviceorientation = function (e) {
+ this._updatePRotations();
+ this._setProperty('rotationX', e.beta);
+ this._setProperty('rotationY', e.gamma);
+ this._setProperty('rotationZ', e.alpha);
+ this._handleMotion();
+};
+p5.prototype._ondevicemotion = function (e) {
+ this._updatePAccelerations();
+ this._setProperty('accelerationX', e.acceleration.x * 2);
+ this._setProperty('accelerationY', e.acceleration.y * 2);
+ this._setProperty('accelerationZ', e.acceleration.z * 2);
+ this._handleMotion();
+};
+p5.prototype._handleMotion = function() {
+ if (window.orientation === 90 || window.orientation === -90) {
+ this._setProperty('deviceOrientation', 'landscape');
+ } else if (window.orientation === 0) {
+ this._setProperty('deviceOrientation', 'portrait');
+ } else if (window.orientation === undefined) {
+ this._setProperty('deviceOrientation', 'undefined');
+ }
+ var deviceMoved = this.deviceMoved || window.deviceMoved;
+ if (typeof deviceMoved === 'function') {
+ if (Math.abs(this.accelerationX - this.pAccelerationX) > move_threshold ||
+ Math.abs(this.accelerationY - this.pAccelerationY) > move_threshold ||
+ Math.abs(this.accelerationZ - this.pAccelerationZ) > move_threshold) {
+ deviceMoved();
+ }
+ }
+ var deviceTurned = this.deviceTurned || window.deviceTurned;
+ if (typeof deviceTurned === 'function') {
+ // The angles given by rotationX etc is from range -180 to 180.
+ // The following will convert them to 0 to 360 for ease of calculation
+ // of cases when the angles wrapped around.
+ // _startAngleX will be converted back at the end and updated.
+ var wRX = this.rotationX + 180;
+ var wPRX = this.pRotationX + 180;
+ var wSAX = startAngleX + 180;
+ if ((wRX - wPRX > 0 && wRX - wPRX < 270)|| wRX - wPRX < -270){
+ rotateDirectionX = 'clockwise';
+ } else if (wRX - wPRX < 0 || wRX - wPRX > 270){
+ rotateDirectionX = 'counter-clockwise';
+ }
+ if (rotateDirectionX !== pRotateDirectionX){
+ wSAX = wRX;
+ }
+ if (Math.abs(wRX - wSAX) > 90 && Math.abs(wRX - wSAX) < 270){
+ wSAX = wRX;
+ this._setProperty('turnAxis', 'X');
+ deviceTurned();
+ }
+ pRotateDirectionX = rotateDirectionX;
+ startAngleX = wSAX - 180;
+
+ // Y-axis is identical to X-axis except for changing some names.
+ var wRY = this.rotationY + 180;
+ var wPRY = this.pRotationY + 180;
+ var wSAY = startAngleY + 180;
+ if ((wRY - wPRY > 0 && wRY - wPRY < 270)|| wRY - wPRY < -270){
+ rotateDirectionY = 'clockwise';
+ } else if (wRY - wPRY < 0 || wRY - this.pRotationY > 270){
+ rotateDirectionY = 'counter-clockwise';
+ }
+ if (rotateDirectionY !== pRotateDirectionY){
+ wSAY = wRY;
+ }
+ if (Math.abs(wRY - wSAY) > 90 && Math.abs(wRY - wSAY) < 270){
+ wSAY = wRY;
+ this._setProperty('turnAxis', 'Y');
+ deviceTurned();
+ }
+ pRotateDirectionY = rotateDirectionY;
+ startAngleY = wSAY - 180;
+
+ // Z-axis is already in the range 0 to 360
+ // so no conversion is needed.
+ if ((this.rotationZ - this.pRotationZ > 0 &&
+ this.rotationZ - this.pRotationZ < 270)||
+ this.rotationZ - this.pRotationZ < -270){
+ rotateDirectionZ = 'clockwise';
+ } else if (this.rotationZ - this.pRotationZ < 0 ||
+ this.rotationZ - this.pRotationZ > 270){
+ rotateDirectionZ = 'counter-clockwise';
+ }
+ if (rotateDirectionZ !== pRotateDirectionZ){
+ startAngleZ = this.rotationZ;
+ }
+ if (Math.abs(this.rotationZ - startAngleZ) > 90 &&
+ Math.abs(this.rotationZ - startAngleZ) < 270){
+ startAngleZ = this.rotationZ;
+ this._setProperty('turnAxis', 'Z');
+ deviceTurned();
+ }
+ pRotateDirectionZ = rotateDirectionZ;
+ this._setProperty('turnAxis', undefined);
+ }
+ var deviceShaken = this.deviceShaken || window.deviceShaken;
+ if (typeof deviceShaken === 'function') {
+ var accelerationChangeX;
+ var accelerationChangeY;
+ // Add accelerationChangeZ if acceleration change on Z is needed
+ if (this.pAccelerationX !== null) {
+ accelerationChangeX = Math.abs(this.accelerationX - this.pAccelerationX);
+ accelerationChangeY = Math.abs(this.accelerationY - this.pAccelerationY);
+ }
+ if (accelerationChangeX + accelerationChangeY > shake_threshold) {
+ deviceShaken();
+ }
+ }
+};
+
+
+module.exports = p5;
+
+},{"../core/core":42}],56:[function(_dereq_,module,exports){
+/**
+ * @module Events
+ * @submodule Keyboard
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * Holds the key codes of currently pressed keys.
+ * @private
+ */
+var downKeys = {};
+
+/**
+ * The boolean system variable keyIsPressed is true if any key is pressed
+ * and false if no keys are pressed.
+ *
+ * @property keyIsPressed
+ * @example
+ *
+ *
+ * @alt
+ * 50x50 white rect that turns black on keypress.
+ *
+ */
+p5.prototype.isKeyPressed = false;
+p5.prototype.keyIsPressed = false; // khan
+
+/**
+ * The system variable key always contains the value of the most recent
+ * key on the keyboard that was typed. To get the proper capitalization, it
+ * is best to use it within keyTyped(). For non-ASCII keys, use the keyCode
+ * variable.
+ *
+ * @property key
+ * @example
+ *
+ * // Click any key to display it!
+ * // (Not Guaranteed to be Case Sensitive)
+ * function setup() {
+ * fill(245, 123, 158);
+ * textSize(50);
+ * }
+ *
+ * function draw() {
+ * background(200);
+ * text(key, 33,65); // Display last key pressed.
+ * }
+ *
+ *
+ * @alt
+ * canvas displays any key value that is pressed in pink font.
+ *
+ */
+p5.prototype.key = '';
+
+/**
+ * The variable keyCode is used to detect special keys such as BACKSPACE,
+ * DELETE, ENTER, RETURN, TAB, ESCAPE, SHIFT, CONTROL, OPTION, ALT, UP_ARROW,
+ * DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW.
+ * You can also check for custom keys by looking up the keyCode of any key
+ * on a site like this: keycode.info.
+ *
+ * @property keyCode
+ * @example
+ *
+ *
+ * @alt
+ * Grey rect center. turns white when up arrow pressed and black when down
+ *
+ */
+p5.prototype.keyCode = 0;
+
+/**
+ * The keyPressed() function is called once every time a key is pressed. The
+ * keyCode for the key that was pressed is stored in the keyCode variable.
+ *
+ * For non-ASCII keys, use the keyCode variable. You can check if the keyCode
+ * equals BACKSPACE, DELETE, ENTER, RETURN, TAB, ESCAPE, SHIFT, CONTROL,
+ * OPTION, ALT, UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW.
+ *
+ * For ASCII keys that was pressed is stored in the key variable. However, it
+ * does not distinguish between uppercase and lowercase. For this reason, it
+ * is recommended to use keyTyped() to read the key variable, in which the
+ * case of the variable will be distinguished.
+ *
+ * Because of how operating systems handle key repeats, holding down a key
+ * may cause multiple calls to keyTyped() (and keyReleased() as well). The
+ * rate of repeat is set by the operating system and how each computer is
+ * configured.
+ * Browsers may have different default
+ * behaviors attached to various key events. To prevent any default
+ * behavior for this event, add "return false" to the end of the method.
+ *
+ * @method keyPressed
+ * @example
+ *
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function keyPressed() {
+ * if (value === 0) {
+ * value = 255;
+ * } else {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function keyPressed() {
+ * if (keyCode === LEFT_ARROW) {
+ * value = 255;
+ * } else if (keyCode === RIGHT_ARROW) {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ *
+ * function keyPressed(){
+ * // Do something
+ * return false; // prevent any default behaviour
+ * }
+ *
+ *
+ * @alt
+ * black rect center. turns white when key pressed and black when released
+ * black rect center. turns white when left arrow pressed and black when right.
+ *
+ *
+ */
+p5.prototype._onkeydown = function (e) {
+ if (downKeys[e.which]) { // prevent multiple firings
+ return;
+ }
+ this._setProperty('isKeyPressed', true);
+ this._setProperty('keyIsPressed', true);
+ this._setProperty('keyCode', e.which);
+ downKeys[e.which] = true;
+ var key = String.fromCharCode(e.which);
+ if (!key) {
+ key = e.which;
+ }
+ this._setProperty('key', key);
+ var keyPressed = this.keyPressed || window.keyPressed;
+ if (typeof keyPressed === 'function' && !e.charCode) {
+ var executeDefault = keyPressed(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+};
+/**
+ * The keyReleased() function is called once every time a key is released.
+ * See key and keyCode for more information.
+ * Browsers may have different default
+ * behaviors attached to various key events. To prevent any default
+ * behavior for this event, add "return false" to the end of the method.
+ *
+ * @method keyReleased
+ * @example
+ *
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function keyReleased() {
+ * if (value === 0) {
+ * value = 255;
+ * } else {
+ * value = 0;
+ * }
+ * return false; // prevent any default behavior
+ * }
+ *
+ *
+ *
+ * @alt
+ * black rect center. turns white when key pressed and black when pressed again
+ *
+ */
+p5.prototype._onkeyup = function (e) {
+ var keyReleased = this.keyReleased || window.keyReleased;
+ downKeys[e.which] = false;
+
+ if(!areDownKeys()) {
+ this._setProperty('isKeyPressed', false);
+ this._setProperty('keyIsPressed', false);
+ }
+
+ this._setProperty('_lastKeyCodeTyped', null);
+
+ var key = String.fromCharCode(e.which);
+ if (!key) {
+ key = e.which;
+ }
+ this._setProperty('key', key);
+ this._setProperty('keyCode', e.which);
+ if (typeof keyReleased === 'function') {
+ var executeDefault = keyReleased(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+};
+
+/**
+ * The keyTyped() function is called once every time a key is pressed, but
+ * action keys such as Ctrl, Shift, and Alt are ignored. The most recent
+ * key pressed will be stored in the key variable.
+ *
+ * Because of how operating systems handle key repeats, holding down a key
+ * will cause multiple calls to keyTyped() (and keyReleased() as well). The
+ * rate of repeat is set by the operating system and how each computer is
+ * configured.
+ * Browsers may have different default behaviors attached to various key
+ * events. To prevent any default behavior for this event, add "return false"
+ * to the end of the method.
+ *
+ * @method keyTyped
+ * @example
+ *
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function keyTyped() {
+ * if (key === 'a') {
+ * value = 255;
+ * } else if (key === 'b') {
+ * value = 0;
+ * }
+ * // uncomment to prevent any default behavior
+ * // return false;
+ * }
+ *
+ *
+ *
+ * @alt
+ * black rect center. turns white when 'a' key typed and black when 'b' pressed
+ *
+ */
+p5.prototype._onkeypress = function (e) {
+ if (e.which === this._lastKeyCodeTyped) { // prevent multiple firings
+ return;
+ }
+ this._setProperty('keyCode', e.which);
+ this._setProperty('_lastKeyCodeTyped', e.which); // track last keyCode
+ this._setProperty('key', String.fromCharCode(e.which));
+ var keyTyped = this.keyTyped || window.keyTyped;
+ if (typeof keyTyped === 'function') {
+ var executeDefault = keyTyped(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+};
+/**
+ * The onblur function is called when the user is no longer focused
+ * on the p5 element. Because the keyup events will not fire if the user is
+ * not focused on the element we must assume all keys currently down have
+ * been released.
+ */
+p5.prototype._onblur = function (e) {
+ downKeys = {};
+};
+
+/**
+ * The keyIsDown() function checks if the key is currently down, i.e. pressed.
+ * It can be used if you have an object that moves, and you want several keys
+ * to be able to affect its behaviour simultaneously, such as moving a
+ * sprite diagonally. You can put in any number representing the keyCode of
+ * the key, or use any of the variable keyCode names listed
+ * here.
+ *
+ * @method keyIsDown
+ * @param {Number} code The key to check for.
+ * @return {Boolean} whether key is down or not
+ * @example
+ *
+ * var x = 100;
+ * var y = 100;
+ *
+ * function setup() {
+ * createCanvas(512, 512);
+ * }
+ *
+ * function draw() {
+ * if (keyIsDown(LEFT_ARROW))
+ * x-=5;
+ *
+ * if (keyIsDown(RIGHT_ARROW))
+ * x+=5;
+ *
+ * if (keyIsDown(UP_ARROW))
+ * y-=5;
+ *
+ * if (keyIsDown(DOWN_ARROW))
+ * y+=5;
+ *
+ * clear();
+ * fill(255, 0, 0);
+ * ellipse(x, y, 50, 50);
+ * }
+ *
+ *
+ * @alt
+ * 50x50 red ellipse moves left, right, up and down with arrow presses.
+ *
+ */
+p5.prototype.keyIsDown = function(code) {
+ return downKeys[code];
+};
+
+/**
+ * The checkDownKeys function returns a boolean true if any keys pressed
+ * and a false if no keys are currently pressed.
+
+ * Helps avoid instances where a multiple keys are pressed simultaneously and
+ * releasing a single key will then switch the
+ * keyIsPressed property to true.
+ * @private
+**/
+function areDownKeys() {
+ for (var key in downKeys) {
+ if (downKeys.hasOwnProperty(key) && downKeys[key] === true) {
+ return true;
+ }
+ }
+ return false;
+}
+
+module.exports = p5;
+
+},{"../core/core":42}],57:[function(_dereq_,module,exports){
+/**
+ * @module Events
+ * @submodule Mouse
+ * @for p5
+ * @requires core
+ * @requires constants
+ */
+
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+var constants = _dereq_('../core/constants');
+
+/*
+ * This is a flag which is false until the first time
+ * we receive a mouse event. The pmouseX and pmouseY
+ * values will match the mouseX and mouseY values until
+ * this interaction takes place.
+ */
+p5.prototype._hasMouseInteracted = false;
+
+/**
+ * The system variable mouseX always contains the current horizontal
+ * position of the mouse, relative to (0, 0) of the canvas. If touch is
+ * used instead of mouse input, mouseX will hold the x value of the most
+ * recent touch point.
+ *
+ * @property mouseX
+ *
+ * @example
+ *
+ *
+ * // Move the mouse across the canvas
+ * function draw() {
+ * background(244, 248, 252);
+ * line(mouseX, 0, mouseX, 100);
+ * }
+ *
+ *
+ *
+ * @alt
+ * horizontal black line moves left and right with mouse x-position
+ *
+ */
+p5.prototype.mouseX = 0;
+
+/**
+ * The system variable mouseY always contains the current vertical position
+ * of the mouse, relative to (0, 0) of the canvas. If touch is
+ * used instead of mouse input, mouseY will hold the y value of the most
+ * recent touch point.
+ *
+ * @property mouseY
+ *
+ * @example
+ *
+ *
+ * // Move the mouse across the canvas
+ * function draw() {
+ * background(244, 248, 252);
+ * line(0, mouseY, 100, mouseY);
+ *}
+ *
+ *
+ *
+ * @alt
+ * vertical black line moves up and down with mouse y-position
+ *
+ */
+p5.prototype.mouseY = 0;
+
+/**
+ * The system variable pmouseX always contains the horizontal position of
+ * the mouse or finger in the frame previous to the current frame, relative to
+ * (0, 0) of the canvas.
+ *
+ * @property pmouseX
+ *
+ * @example
+ *
+ *
+ * // Move the mouse across the canvas to leave a trail
+ * function setup() {
+ * //slow down the frameRate to make it more visible
+ * frameRate(10);
+ * }
+ *
+ * function draw() {
+ * background(244, 248, 252);
+ * line(mouseX, mouseY, pmouseX, pmouseY);
+ * print(pmouseX + " -> " + mouseX);
+ * }
+ *
+ *
+ *
+ *
+ * @alt
+ * line trail is created from cursor movements. faster movement make longer line.
+ *
+ */
+p5.prototype.pmouseX = 0;
+
+/**
+ * The system variable pmouseY always contains the vertical position of the
+ * mouse or finger in the frame previous to the current frame, relative to
+ * (0, 0) of the canvas.
+ *
+ * @property pmouseY
+ *
+ * @example
+ *
+ *
+ * function draw() {
+ * background(237, 34, 93);
+ * fill(0);
+ * //draw a square only if the mouse is not moving
+ * if(mouseY == pmouseY && mouseX == pmouseX)
+ * rect(20,20,60,60);
+ *
+ * print(pmouseY + " -> " + mouseY);
+ * }
+ *
+ *
+ *
+ *
+ * @alt
+ * 60x60 black rect center, fuschia background. rect flickers on mouse movement
+ *
+ */
+p5.prototype.pmouseY = 0;
+
+/**
+ * The system variable winMouseX always contains the current horizontal
+ * position of the mouse, relative to (0, 0) of the window.
+ *
+ * @property winMouseX
+ *
+ * @example
+ *
+ *
+ * var myCanvas;
+ *
+ * function setup() {
+ * //use a variable to store a pointer to the canvas
+ * myCanvas = createCanvas(100, 100);
+ * }
+ *
+ * function draw() {
+ * background(237, 34, 93);
+ * fill(0);
+ *
+ * //move the canvas to the horizontal mouse position
+ * //relative to the window
+ * myCanvas.position(winMouseX+1, windowHeight/2);
+ *
+ * //the y of the square is relative to the canvas
+ * rect(20,mouseY,60,60);
+ * }
+ *
+ *
+ *
+ *
+ * @alt
+ * 60x60 black rect y moves with mouse y and fuschia canvas moves with mouse x
+ *
+ */
+p5.prototype.winMouseX = 0;
+
+/**
+ * The system variable winMouseY always contains the current vertical
+ * position of the mouse, relative to (0, 0) of the window.
+ *
+ * @property winMouseY
+ *
+ * @example
+ *
+ *
+ *var myCanvas;
+ *
+ * function setup() {
+ * //use a variable to store a pointer to the canvas
+ * myCanvas = createCanvas(100, 100);
+ * }
+ *
+ * function draw() {
+ * background(237, 34, 93);
+ * fill(0);
+ *
+ * //move the canvas to the vertical mouse position
+ * //relative to the window
+ * myCanvas.position(windowWidth/2, winMouseY+1);
+ *
+ * //the x of the square is relative to the canvas
+ * rect(mouseX,20,60,60);
+ * }
+ *
+ *
+ *
+ *
+ * @alt
+ * 60x60 black rect x moves with mouse x and fuschia canvas y moves with mouse y
+ *
+ */
+p5.prototype.winMouseY = 0;
+
+/**
+ * The system variable pwinMouseX always contains the horizontal position
+ * of the mouse in the frame previous to the current frame, relative to
+ * (0, 0) of the window.
+ *
+ * @property pwinMouseX
+ *
+ * @example
+ *
+ *
+ *
+ * var myCanvas;
+ *
+ * function setup() {
+ * //use a variable to store a pointer to the canvas
+ * myCanvas = createCanvas(100, 100);
+ * noStroke();
+ * fill(237, 34, 93);
+ * }
+ *
+ * function draw() {
+ * clear();
+ * //the difference between previous and
+ * //current x position is the horizontal mouse speed
+ * var speed = abs(winMouseX-pwinMouseX);
+ * //change the size of the circle
+ * //according to the horizontal speed
+ * ellipse(50, 50, 10+speed*5, 10+speed*5);
+ * //move the canvas to the mouse position
+ * myCanvas.position( winMouseX+1, winMouseY+1);
+ * }
+ *
+ *
+ *
+ *
+ * @alt
+ * fuschia ellipse moves with mouse x and y. Grows and shrinks with mouse speed
+ *
+ */
+p5.prototype.pwinMouseX = 0;
+
+/**
+ * The system variable pwinMouseY always contains the vertical position of
+ * the mouse in the frame previous to the current frame, relative to (0, 0)
+ * of the window.
+ *
+ * @property pwinMouseY
+ *
+ *
+ * @example
+ *
+ *
+ *
+ * var myCanvas;
+ *
+ * function setup() {
+ * //use a variable to store a pointer to the canvas
+ * myCanvas = createCanvas(100, 100);
+ * noStroke();
+ * fill(237, 34, 93);
+ * }
+ *
+ * function draw() {
+ * clear();
+ * //the difference between previous and
+ * //current y position is the vertical mouse speed
+ * var speed = abs(winMouseY-pwinMouseY);
+ * //change the size of the circle
+ * //according to the vertical speed
+ * ellipse(50, 50, 10+speed*5, 10+speed*5);
+ * //move the canvas to the mouse position
+ * myCanvas.position( winMouseX+1, winMouseY+1);
+ * }
+ *
+ *
+ *
+ *
+ * @alt
+ * fuschia ellipse moves with mouse x and y. Grows and shrinks with mouse speed
+ *
+ */
+p5.prototype.pwinMouseY = 0;
+
+/**
+ * Processing automatically tracks if the mouse button is pressed and which
+ * button is pressed. The value of the system variable mouseButton is either
+ * LEFT, RIGHT, or CENTER depending on which button was pressed last.
+ * Warning: different browsers may track mouseButton differently.
+ *
+ * @property mouseButton
+ *
+ * @example
+ *
+ *
+ * @alt
+ * 50x50 black ellipse appears on center of fuschia canvas on mouse click/press.
+ *
+ */
+p5.prototype.mouseButton = 0;
+
+/**
+ * The boolean system variable mouseIsPressed is true if the mouse is pressed
+ * and false if not.
+ *
+ * @property mouseIsPressed
+ *
+ * @example
+ *
+ *
+ * @alt
+ * black 50x50 rect becomes ellipse with mouse click/press. fuschia background.
+ *
+ */
+p5.prototype.mouseIsPressed = false;
+p5.prototype.isMousePressed = false; // both are supported
+
+p5.prototype._updateNextMouseCoords = function(e) {
+ if(this._curElement !== null && (!e.touches || e.touches.length>0)) {
+ var mousePos = getMousePos(this._curElement.elt, this.width, this.height, e);
+ this._setProperty('mouseX', mousePos.x);
+ this._setProperty('mouseY', mousePos.y);
+ this._setProperty('winMouseX', mousePos.winX);
+ this._setProperty('winMouseY', mousePos.winY);
+ }
+ if (!this._hasMouseInteracted) {
+ // For first draw, make previous and next equal
+ this._updateMouseCoords();
+ this._setProperty('_hasMouseInteracted', true);
+ }
+};
+
+p5.prototype._updateMouseCoords = function() {
+ this._setProperty('pmouseX', this.mouseX);
+ this._setProperty('pmouseY', this.mouseY);
+ this._setProperty('pwinMouseX', this.winMouseX);
+ this._setProperty('pwinMouseY', this.winMouseY);
+};
+
+function getMousePos(canvas, w, h, evt) {
+ if (evt && !evt.clientX) { // use touches if touch and not mouse
+ if (evt.touches) {
+ evt = evt.touches[0];
+ } else if (evt.changedTouches) {
+ evt = evt.changedTouches[0];
+ }
+ }
+ var rect = canvas.getBoundingClientRect();
+ var sx = canvas.scrollWidth / w;
+ var sy = canvas.scrollHeight / h;
+ return {
+ x: (evt.clientX - rect.left) / sx,
+ y: (evt.clientY - rect.top) / sy,
+ winX: evt.clientX,
+ winY: evt.clientY,
+ id: evt.identifier
+ };
+}
+
+p5.prototype._setMouseButton = function(e) {
+ if (e.button === 1) {
+ this._setProperty('mouseButton', constants.CENTER);
+ } else if (e.button === 2) {
+ this._setProperty('mouseButton', constants.RIGHT);
+ } else {
+ this._setProperty('mouseButton', constants.LEFT);
+ }
+};
+
+/**
+ * The mouseMoved() function is called every time the mouse moves and a mouse
+ * button is not pressed.
+ * Browsers may have different default
+ * behaviors attached to various mouse events. To prevent any default
+ * behavior for this event, add "return false" to the end of the method.
+ *
+ * @method mouseMoved
+ * @example
+ *
+ *
+ * // Move the mouse across the page
+ * // to change its value
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function mouseMoved() {
+ * value = value + 5;
+ * if (value > 255) {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * black 50x50 rect becomes lighter with mouse movements until white then resets
+ * no image displayed
+ *
+ */
+
+/**
+ * The mouseDragged() function is called once every time the mouse moves and
+ * a mouse button is pressed. If no mouseDragged() function is defined, the
+ * touchMoved() function will be called instead if it is defined.
+ * Browsers may have different default
+ * behaviors attached to various mouse events. To prevent any default
+ * behavior for this event, add "return false" to the end of the method.
+ *
+ * @method mouseDragged
+ * @example
+ *
+ *
+ * // Drag the mouse across the page
+ * // to change its value
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function mouseDragged() {
+ * value = value + 5;
+ * if (value > 255) {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * black 50x50 rect turns lighter with mouse click and drag until white, resets
+ * no image displayed
+ *
+ */
+p5.prototype._onmousemove = function(e){
+ var context = this._isGlobal ? window : this;
+ var executeDefault;
+ this._updateNextMouseCoords(e);
+ if (!this.isMousePressed) {
+ if (typeof context.mouseMoved === 'function') {
+ executeDefault = context.mouseMoved(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+ }
+ else {
+ if (typeof context.mouseDragged === 'function') {
+ executeDefault = context.mouseDragged(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ } else if (typeof context.touchMoved === 'function') {
+ executeDefault = context.touchMoved(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+ }
+};
+
+/**
+ * The mousePressed() function is called once after every time a mouse button
+ * is pressed. The mouseButton variable (see the related reference entry)
+ * can be used to determine which button has been pressed. If no
+ * mousePressed() function is defined, the touchStarted() function will be
+ * called instead if it is defined.
+ * Browsers may have different default
+ * behaviors attached to various mouse events. To prevent any default
+ * behavior for this event, add "return false" to the end of the method.
+ *
+ * @method mousePressed
+ * @example
+ *
+ *
+ * // Click within the image to change
+ * // the value of the rectangle
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function mousePressed() {
+ * if (value == 0) {
+ * value = 255;
+ * } else {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * black 50x50 rect turns white with mouse click/press.
+ * no image displayed
+ *
+ */
+p5.prototype._onmousedown = function(e) {
+ var context = this._isGlobal ? window : this;
+ var executeDefault;
+ this._setProperty('isMousePressed', true);
+ this._setProperty('mouseIsPressed', true);
+ this._setMouseButton(e);
+ this._updateNextMouseCoords(e);
+ if (typeof context.mousePressed === 'function') {
+ executeDefault = context.mousePressed(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ } else if (typeof context.touchStarted === 'function') {
+ executeDefault = context.touchStarted(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+};
+
+/**
+ * The mouseReleased() function is called every time a mouse button is
+ * released. If no mouseReleased() function is defined, the touchEnded()
+ * function will be called instead if it is defined.
+ * Browsers may have different default
+ * behaviors attached to various mouse events. To prevent any default
+ * behavior for this event, add "return false" to the end of the method.
+ *
+ *
+ * @method mouseReleased
+ * @example
+ *
+ *
+ * // Click within the image to change
+ * // the value of the rectangle
+ * // after the mouse has been clicked
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function mouseReleased() {
+ * if (value == 0) {
+ * value = 255;
+ * } else {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * black 50x50 rect turns white with mouse click/press.
+ * no image displayed
+ *
+ */
+p5.prototype._onmouseup = function(e) {
+ var context = this._isGlobal ? window : this;
+ var executeDefault;
+ this._setProperty('isMousePressed', false);
+ this._setProperty('mouseIsPressed', false);
+ if (typeof context.mouseReleased === 'function') {
+ executeDefault = context.mouseReleased(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ } else if (typeof context.touchEnded === 'function') {
+ executeDefault = context.touchEnded(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+};
+
+p5.prototype._ondragend = p5.prototype._onmouseup;
+p5.prototype._ondragover = p5.prototype._onmousemove;
+
+/**
+ * The mouseClicked() function is called once after a mouse button has been
+ * pressed and then released.
+ * Browsers may have different default
+ * behaviors attached to various mouse events. To prevent any default
+ * behavior for this event, add "return false" to the end of the method.
+ *
+ * @method mouseClicked
+ * @example
+ *
+ *
+ * // Click within the image to change
+ * // the value of the rectangle
+ * // after the mouse has been clicked
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function mouseClicked() {
+ * if (value == 0) {
+ * value = 255;
+ * } else {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * black 50x50 rect turns white with mouse click/press.
+ * no image displayed
+ *
+ */
+p5.prototype._onclick = function(e) {
+ var context = this._isGlobal ? window : this;
+ if (typeof context.mouseClicked === 'function') {
+ var executeDefault = context.mouseClicked(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+};
+
+/**
+ * The function mouseWheel() is executed every time a vertical mouse wheel
+ * event is detected either triggered by an actual mouse wheel or by a
+ * touchpad.
+ * The event.delta property returns the amount the mouse wheel
+ * have scrolled. The values can be positive or negative depending on the
+ * scroll direction (on OS X with "natural" scrolling enabled, the signs
+ * are inverted).
+ * Browsers may have different default behaviors attached to various
+ * mouse events. To prevent any default behavior for this event, add
+ * "return false" to the end of the method.
+ * Due to the current support of the "wheel" event on Safari, the function
+ * may only work as expected if "return false" is included while using Safari.
+ *
+ * @method mouseWheel
+ *
+ * @example
+ *
+ *
+ * var pos = 25;
+ *
+ * function draw() {
+ * background(237, 34, 93);
+ * fill(0);
+ * rect(25, pos, 50, 50);
+ * }
+ *
+ * function mouseWheel(event) {
+ * print(event.delta);
+ * //move the square according to the vertical scroll amount
+ * pos += event.delta;
+ * //uncomment to block page scrolling
+ * //return false;
+ * }
+ *
+ *
+ *
+ * @alt
+ * black 50x50 rect moves up and down with vertical scroll. fuschia background
+ *
+ */
+p5.prototype._onwheel = function(e) {
+ var context = this._isGlobal ? window : this;
+ if (typeof context.mouseWheel === 'function') {
+ e.delta = e.deltaY;
+ var executeDefault = context.mouseWheel(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+};
+
+module.exports = p5;
+
+},{"../core/constants":41,"../core/core":42}],58:[function(_dereq_,module,exports){
+/**
+ * @module Events
+ * @submodule Touch
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * The system variable touches[] contains an array of the positions of all
+ * current touch points, relative to (0, 0) of the canvas, and IDs identifying a
+ * unique touch as it moves. Each element in the array is an object with x, y,
+ * and id properties.
+ *
+ * @property {Object[]} touches
+ */
+p5.prototype.touches = [];
+
+p5.prototype._updateTouchCoords = function(e) {
+ if (this._curElement !== null) {
+ var touches = [];
+ for(var i = 0; i < e.touches.length; i++){
+ touches[i] = getTouchInfo(this._curElement.elt,
+ this.width, this.height, e, i);
+ }
+ this._setProperty('touches', touches);
+ }
+};
+
+
+function getTouchInfo(canvas, w, h, e, i) {
+ i = i || 0;
+ var rect = canvas.getBoundingClientRect();
+ var sx = canvas.scrollWidth / w;
+ var sy = canvas.scrollHeight / h;
+ var touch = e.touches[i] || e.changedTouches[i];
+ return {
+ x: (touch.clientX - rect.left) / sx,
+ y: (touch.clientY - rect.top) / sy,
+ winX: touch.clientX,
+ winY: touch.clientY,
+ id: touch.identifier
+ };
+}
+
+/**
+ * The touchStarted() function is called once after every time a touch is
+ * registered. If no touchStarted() function is defined, the mousePressed()
+ * function will be called instead if it is defined.
+ * Browsers may have different default behaviors attached to various touch
+ * events. To prevent any default behavior for this event, add "return false"
+ * to the end of the method.
+ *
+ * @method touchStarted
+ * @example
+ *
+ *
+ * // Touch within the image to change
+ * // the value of the rectangle
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function touchStarted() {
+ * if (value == 0) {
+ * value = 255;
+ * } else {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * 50x50 black rect turns white with touch event.
+ * no image displayed
+ */
+p5.prototype._ontouchstart = function(e) {
+ var context = this._isGlobal ? window : this;
+ var executeDefault;
+ this._updateTouchCoords(e);
+ this._updateNextMouseCoords(e);
+ if(typeof context.touchStarted === 'function') {
+ executeDefault = context.touchStarted(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ } else if (typeof context.mousePressed === 'function') {
+ executeDefault = context.mousePressed(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ //this._setMouseButton(e);
+ }
+};
+
+/**
+ * The touchMoved() function is called every time a touch move is registered.
+ * If no touchMoved() function is defined, the mouseDragged() function will
+ * be called instead if it is defined.
+ * Browsers may have different default behaviors attached to various touch
+ * events. To prevent any default behavior for this event, add "return false"
+ * to the end of the method.
+ *
+ * @method touchMoved
+ * @example
+ *
+ *
+ * // Move your finger across the page
+ * // to change its value
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function touchMoved() {
+ * value = value + 5;
+ * if (value > 255) {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * 50x50 black rect turns lighter with touch until white. resets
+ * no image displayed
+ *
+ */
+p5.prototype._ontouchmove = function(e) {
+ var context = this._isGlobal ? window : this;
+ var executeDefault;
+ this._updateTouchCoords(e);
+ this._updateNextMouseCoords(e);
+ if (typeof context.touchMoved === 'function') {
+ executeDefault = context.touchMoved(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ } else if (typeof context.mouseDragged === 'function') {
+ executeDefault = context.mouseDragged(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ }
+};
+
+/**
+ * The touchEnded() function is called every time a touch ends. If no
+ * touchEnded() function is defined, the mouseReleased() function will be
+ * called instead if it is defined.
+ * Browsers may have different default behaviors attached to various touch
+ * events. To prevent any default behavior for this event, add "return false"
+ * to the end of the method.
+ *
+ * @method touchEnded
+ * @example
+ *
+ *
+ * // Release touch within the image to
+ * // change the value of the rectangle
+ *
+ * var value = 0;
+ * function draw() {
+ * fill(value);
+ * rect(25, 25, 50, 50);
+ * }
+ * function touchEnded() {
+ * if (value == 0) {
+ * value = 255;
+ * } else {
+ * value = 0;
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * 50x50 black rect turns white with touch.
+ * no image displayed
+ *
+ */
+p5.prototype._ontouchend = function(e) {
+ this._updateTouchCoords(e);
+ this._updateNextMouseCoords(e);
+ if (this.touches.length === 0) {
+ this._setProperty('touchIsDown', false);
+ }
+ var context = this._isGlobal ? window : this;
+ var executeDefault;
+ if (typeof context.touchEnded === 'function') {
+ executeDefault = context.touchEnded(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ } else if (typeof context.mouseReleased === 'function') {
+ executeDefault = context.mouseReleased(e);
+ if(executeDefault === false) {
+ e.preventDefault();
+ }
+ } else {
+ e.preventDefault();
+ return false;
+ }
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],59:[function(_dereq_,module,exports){
+/*global ImageData:false */
+
+/**
+ * This module defines the filters for use with image buffers.
+ *
+ * This module is basically a collection of functions stored in an object
+ * as opposed to modules. The functions are destructive, modifying
+ * the passed in canvas rather than creating a copy.
+ *
+ * Generally speaking users of this module will use the Filters.apply method
+ * on a canvas to create an effect.
+ *
+ * A number of functions are borrowed/adapted from
+ * http://www.html5rocks.com/en/tutorials/canvas/imagefilters/
+ * or the java processing implementation.
+ */
+
+'use strict';
+
+var Filters = {};
+
+
+/*
+ * Helper functions
+ */
+
+
+/**
+ * Returns the pixel buffer for a canvas
+ *
+ * @private
+ *
+ * @param {Canvas|ImageData} canvas the canvas to get pixels from
+ * @return {Uint8ClampedArray} a one-dimensional array containing
+ * the data in thc RGBA order, with integer
+ * values between 0 and 255
+ */
+Filters._toPixels = function (canvas) {
+ if (canvas instanceof ImageData) {
+ return canvas.data;
+ } else {
+ return canvas.getContext('2d').getImageData(
+ 0,
+ 0,
+ canvas.width,
+ canvas.height
+ ).data;
+ }
+};
+
+/**
+ * Returns a 32 bit number containing ARGB data at ith pixel in the
+ * 1D array containing pixels data.
+ *
+ * @private
+ *
+ * @param {Uint8ClampedArray} data array returned by _toPixels()
+ * @param {Integer} i index of a 1D Image Array
+ * @return {Integer} 32 bit integer value representing
+ * ARGB value.
+ */
+Filters._getARGB = function (data, i) {
+ var offset = i * 4;
+ return (data[offset+3] << 24) & 0xff000000 |
+ (data[offset] << 16) & 0x00ff0000 |
+ (data[offset+1] << 8) & 0x0000ff00 |
+ data[offset+2] & 0x000000ff;
+};
+
+/**
+ * Modifies pixels RGBA values to values contained in the data object.
+ *
+ * @private
+ *
+ * @param {Uint8ClampedArray} pixels array returned by _toPixels()
+ * @param {Int32Array} data source 1D array where each value
+ * represents ARGB values
+ */
+Filters._setPixels = function (pixels, data) {
+ var offset = 0;
+ for( var i = 0, al = pixels.length; i < al; i++) {
+ offset = i*4;
+ pixels[offset + 0] = (data[i] & 0x00ff0000)>>>16;
+ pixels[offset + 1] = (data[i] & 0x0000ff00)>>>8;
+ pixels[offset + 2] = (data[i] & 0x000000ff);
+ pixels[offset + 3] = (data[i] & 0xff000000)>>>24;
+ }
+};
+
+/**
+ * Returns the ImageData object for a canvas
+ * https://developer.mozilla.org/en-US/docs/Web/API/ImageData
+ *
+ * @private
+ *
+ * @param {Canvas|ImageData} canvas canvas to get image data from
+ * @return {ImageData} Holder of pixel data (and width and
+ * height) for a canvas
+ */
+Filters._toImageData = function (canvas) {
+ if (canvas instanceof ImageData) {
+ return canvas;
+ } else {
+ return canvas.getContext('2d').getImageData(
+ 0,
+ 0,
+ canvas.width,
+ canvas.height
+ );
+ }
+};
+
+/**
+ * Returns a blank ImageData object.
+ *
+ * @private
+ *
+ * @param {Integer} width
+ * @param {Integer} height
+ * @return {ImageData}
+ */
+Filters._createImageData = function (width, height) {
+ Filters._tmpCanvas = document.createElement('canvas');
+ Filters._tmpCtx = Filters._tmpCanvas.getContext('2d');
+ return this._tmpCtx.createImageData(width, height);
+};
+
+
+/**
+ * Applys a filter function to a canvas.
+ *
+ * The difference between this and the actual filter functions defined below
+ * is that the filter functions generally modify the pixel buffer but do
+ * not actually put that data back to the canvas (where it would actually
+ * update what is visible). By contrast this method does make the changes
+ * actually visible in the canvas.
+ *
+ * The apply method is the method that callers of this module would generally
+ * use. It has been separated from the actual filters to support an advanced
+ * use case of creating a filter chain that executes without actually updating
+ * the canvas in between everystep.
+ *
+ * @param {[type]} func [description]
+ * @param {[type]} canvas [description]
+ * @param {[type]} level [description]
+ * @return {[type]} [description]
+ */
+Filters.apply = function (canvas, func, filterParam) {
+ var ctx = canvas.getContext('2d');
+ var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+
+ //Filters can either return a new ImageData object, or just modify
+ //the one they received.
+ var newImageData = func(imageData, filterParam);
+ if (newImageData instanceof ImageData) {
+ ctx.putImageData(newImageData, 0, 0, 0, 0, canvas.width, canvas.height);
+ } else {
+ ctx.putImageData(imageData, 0, 0, 0, 0, canvas.width, canvas.height);
+ }
+};
+
+
+/*
+ * Filters
+ */
+
+
+/**
+ * Converts the image to black and white pixels depending if they are above or
+ * below the threshold defined by the level parameter. The parameter must be
+ * between 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is used.
+ *
+ * Borrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/
+ *
+ * @param {Canvas} canvas
+ * @param {Float} level
+ */
+Filters.threshold = function (canvas, level) {
+ var pixels = Filters._toPixels(canvas);
+
+ if (level === undefined) {
+ level = 0.5;
+ }
+ var thresh = Math.floor(level * 255);
+
+ for (var i = 0; i < pixels.length; i += 4) {
+ var r = pixels[i];
+ var g = pixels[i + 1];
+ var b = pixels[i + 2];
+ var gray = (0.2126 * r + 0.7152 * g + 0.0722 * b);
+ var val;
+ if (gray >= thresh) {
+ val = 255;
+ } else {
+ val = 0;
+ }
+ pixels[i] = pixels[i + 1] = pixels[i + 2] = val;
+ }
+
+};
+
+
+/**
+ * Converts any colors in the image to grayscale equivalents.
+ * No parameter is used.
+ *
+ * Borrowed from http://www.html5rocks.com/en/tutorials/canvas/imagefilters/
+ *
+ * @param {Canvas} canvas
+ */
+Filters.gray = function (canvas) {
+ var pixels = Filters._toPixels(canvas);
+
+ for (var i = 0; i < pixels.length; i += 4) {
+ var r = pixels[i];
+ var g = pixels[i + 1];
+ var b = pixels[i + 2];
+
+ // CIE luminance for RGB
+ var gray = (0.2126 * r + 0.7152 * g + 0.0722 * b);
+ pixels[i] = pixels[i + 1] = pixels[i + 2] = gray;
+ }
+};
+
+/**
+ * Sets the alpha channel to entirely opaque. No parameter is used.
+ *
+ * @param {Canvas} canvas
+ */
+Filters.opaque = function (canvas) {
+ var pixels = Filters._toPixels(canvas);
+
+ for (var i = 0; i < pixels.length; i += 4) {
+ pixels[i + 3] = 255;
+ }
+
+ return pixels;
+};
+
+/**
+ * Sets each pixel to its inverse value. No parameter is used.
+ * @param {Canvas} canvas
+ */
+Filters.invert = function (canvas) {
+ var pixels = Filters._toPixels(canvas);
+
+ for (var i = 0; i < pixels.length; i += 4) {
+ pixels[i] = 255 - pixels[i];
+ pixels[i + 1] = 255 - pixels[i + 1];
+ pixels[i + 2] = 255 - pixels[i + 2];
+ }
+
+};
+
+
+/**
+ * Limits each channel of the image to the number of colors specified as
+ * the parameter. The parameter can be set to values between 2 and 255, but
+ * results are most noticeable in the lower ranges.
+ *
+ * Adapted from java based processing implementation
+ *
+ * @param {Canvas} canvas
+ * @param {Integer} level
+ */
+Filters.posterize = function (canvas, level) {
+ var pixels = Filters._toPixels(canvas);
+
+ if ((level < 2) || (level > 255)) {
+ throw new Error(
+ 'Level must be greater than 2 and less than 255 for posterize'
+ );
+ }
+
+ var levels1 = level - 1;
+ for (var i = 0; i < pixels.length; i+=4) {
+ var rlevel = pixels[i];
+ var glevel = pixels[i + 1];
+ var blevel = pixels[i + 2];
+
+ pixels[i] = (((rlevel * level) >> 8) * 255) / levels1;
+ pixels[i + 1] = (((glevel * level) >> 8) * 255) / levels1;
+ pixels[i + 2] = (((blevel * level) >> 8) * 255) / levels1;
+ }
+};
+
+/**
+ * reduces the bright areas in an image
+ * @param {Canvas} canvas
+ *
+ */
+Filters.dilate = function (canvas) {
+ var pixels = Filters._toPixels(canvas);
+ var currIdx = 0;
+ var maxIdx = pixels.length ? pixels.length/4 : 0;
+ var out = new Int32Array(maxIdx);
+ var currRowIdx, maxRowIdx, colOrig, colOut, currLum;
+ var idxRight, idxLeft, idxUp, idxDown,
+ colRight, colLeft, colUp, colDown,
+ lumRight, lumLeft, lumUp, lumDown;
+
+ while(currIdx < maxIdx) {
+ currRowIdx = currIdx;
+ maxRowIdx = currIdx + canvas.width;
+ while (currIdx < maxRowIdx) {
+ colOrig = colOut = Filters._getARGB(pixels, currIdx);
+ idxLeft = currIdx - 1;
+ idxRight = currIdx + 1;
+ idxUp = currIdx - canvas.width;
+ idxDown = currIdx + canvas.width;
+
+ if (idxLeft < currRowIdx) {
+ idxLeft = currIdx;
+ }
+ if (idxRight >= maxRowIdx) {
+ idxRight = currIdx;
+ }
+ if (idxUp < 0){
+ idxUp = 0;
+ }
+ if (idxDown >= maxIdx) {
+ idxDown = currIdx;
+ }
+ colUp = Filters._getARGB(pixels, idxUp);
+ colLeft = Filters._getARGB(pixels, idxLeft);
+ colDown = Filters._getARGB(pixels, idxDown);
+ colRight = Filters._getARGB(pixels, idxRight);
+
+ //compute luminance
+ currLum = 77*(colOrig>>16&0xff) +
+ 151*(colOrig>>8&0xff) +
+ 28*(colOrig&0xff);
+ lumLeft = 77*(colLeft>>16&0xff) +
+ 151*(colLeft>>8&0xff) +
+ 28*(colLeft&0xff);
+ lumRight = 77*(colRight>>16&0xff) +
+ 151*(colRight>>8&0xff) +
+ 28*(colRight&0xff);
+ lumUp = 77*(colUp>>16&0xff) +
+ 151*(colUp>>8&0xff) +
+ 28*(colUp&0xff);
+ lumDown = 77*(colDown>>16&0xff) +
+ 151*(colDown>>8&0xff) +
+ 28*(colDown&0xff);
+
+ if (lumLeft > currLum) {
+ colOut = colLeft;
+ currLum = lumLeft;
+ }
+ if (lumRight > currLum) {
+ colOut = colRight;
+ currLum = lumRight;
+ }
+ if (lumUp > currLum) {
+ colOut = colUp;
+ currLum = lumUp;
+ }
+ if (lumDown > currLum) {
+ colOut = colDown;
+ currLum = lumDown;
+ }
+ out[currIdx++]=colOut;
+ }
+ }
+ Filters._setPixels(pixels, out);
+};
+
+/**
+ * increases the bright areas in an image
+ * @param {Canvas} canvas
+ *
+ */
+Filters.erode = function(canvas) {
+ var pixels = Filters._toPixels(canvas);
+ var currIdx = 0;
+ var maxIdx = pixels.length ? pixels.length/4 : 0;
+ var out = new Int32Array(maxIdx);
+ var currRowIdx, maxRowIdx, colOrig, colOut, currLum;
+ var idxRight, idxLeft, idxUp, idxDown,
+ colRight, colLeft, colUp, colDown,
+ lumRight, lumLeft, lumUp, lumDown;
+
+ while(currIdx < maxIdx) {
+ currRowIdx = currIdx;
+ maxRowIdx = currIdx + canvas.width;
+ while (currIdx < maxRowIdx) {
+ colOrig = colOut = Filters._getARGB(pixels, currIdx);
+ idxLeft = currIdx - 1;
+ idxRight = currIdx + 1;
+ idxUp = currIdx - canvas.width;
+ idxDown = currIdx + canvas.width;
+
+ if (idxLeft < currRowIdx) {
+ idxLeft = currIdx;
+ }
+ if (idxRight >= maxRowIdx) {
+ idxRight = currIdx;
+ }
+ if (idxUp < 0) {
+ idxUp = 0;
+ }
+ if (idxDown >= maxIdx) {
+ idxDown = currIdx;
+ }
+ colUp = Filters._getARGB(pixels, idxUp);
+ colLeft = Filters._getARGB(pixels, idxLeft);
+ colDown = Filters._getARGB(pixels, idxDown);
+ colRight = Filters._getARGB(pixels, idxRight);
+
+ //compute luminance
+ currLum = 77*(colOrig>>16&0xff) +
+ 151*(colOrig>>8&0xff) +
+ 28*(colOrig&0xff);
+ lumLeft = 77*(colLeft>>16&0xff) +
+ 151*(colLeft>>8&0xff) +
+ 28*(colLeft&0xff);
+ lumRight = 77*(colRight>>16&0xff) +
+ 151*(colRight>>8&0xff) +
+ 28*(colRight&0xff);
+ lumUp = 77*(colUp>>16&0xff) +
+ 151*(colUp>>8&0xff) +
+ 28*(colUp&0xff);
+ lumDown = 77*(colDown>>16&0xff) +
+ 151*(colDown>>8&0xff) +
+ 28*(colDown&0xff);
+
+ if (lumLeft < currLum) {
+ colOut = colLeft;
+ currLum = lumLeft;
+ }
+ if (lumRight < currLum) {
+ colOut = colRight;
+ currLum = lumRight;
+ }
+ if (lumUp < currLum) {
+ colOut = colUp;
+ currLum = lumUp;
+ }
+ if (lumDown < currLum) {
+ colOut = colDown;
+ currLum = lumDown;
+ }
+
+ out[currIdx++]=colOut;
+ }
+ }
+ Filters._setPixels(pixels, out);
+};
+
+// BLUR
+
+// internal kernel stuff for the gaussian blur filter
+var blurRadius;
+var blurKernelSize;
+var blurKernel;
+var blurMult;
+
+/*
+ * Port of https://github.com/processing/processing/blob/
+ * master/core/src/processing/core/PImage.java#L1250
+ *
+ * Optimized code for building the blur kernel.
+ * further optimized blur code (approx. 15% for radius=20)
+ * bigger speed gains for larger radii (~30%)
+ * added support for various image types (ALPHA, RGB, ARGB)
+ * [toxi 050728]
+ */
+function buildBlurKernel(r) {
+ var radius = (r * 3.5)|0;
+ radius = (radius < 1) ? 1 : ((radius < 248) ? radius : 248);
+
+ if (blurRadius !== radius) {
+ blurRadius = radius;
+ blurKernelSize = 1 + blurRadius<<1;
+ blurKernel = new Int32Array(blurKernelSize);
+ blurMult = new Array(blurKernelSize);
+ for(var l = 0; l < blurKernelSize; l++){
+ blurMult[l] = new Int32Array(256);
+ }
+
+ var bk,bki;
+ var bm,bmi;
+
+ for (var i = 1, radiusi = radius - 1; i < radius; i++) {
+ blurKernel[radius+i] = blurKernel[radiusi] = bki = radiusi * radiusi;
+ bm = blurMult[radius+i];
+ bmi = blurMult[radiusi--];
+ for (var j = 0; j < 256; j++){
+ bm[j] = bmi[j] = bki * j;
+ }
+ }
+ bk = blurKernel[radius] = radius * radius;
+ bm = blurMult[radius];
+
+ for (var k = 0; k < 256; k++){
+ bm[k] = bk * k;
+ }
+ }
+
+}
+
+// Port of https://github.com/processing/processing/blob/
+// master/core/src/processing/core/PImage.java#L1433
+function blurARGB(canvas, radius) {
+ var pixels = Filters._toPixels(canvas);
+ var width = canvas.width;
+ var height = canvas.height;
+ var numPackedPixels = width * height;
+ var argb = new Int32Array(numPackedPixels);
+ for (var j = 0; j < numPackedPixels; j++) {
+ argb[j] = Filters._getARGB(pixels, j);
+ }
+ var sum, cr, cg, cb, ca;
+ var read, ri, ym, ymi, bk0;
+ var a2 = new Int32Array(numPackedPixels);
+ var r2 = new Int32Array(numPackedPixels);
+ var g2 = new Int32Array(numPackedPixels);
+ var b2 = new Int32Array(numPackedPixels);
+ var yi = 0;
+ buildBlurKernel(radius);
+ var x, y, i;
+ var bm;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ cb = cg = cr = ca = sum = 0;
+ read = x - blurRadius;
+ if (read < 0) {
+ bk0 = -read;
+ read = 0;
+ } else {
+ if (read >= width) {
+ break;
+ }
+ bk0 = 0;
+ }
+ for (i = bk0; i < blurKernelSize; i++) {
+ if (read >= width) {
+ break;
+ }
+ var c = argb[read + yi];
+ bm = blurMult[i];
+ ca += bm[(c & -16777216) >>> 24];
+ cr += bm[(c & 16711680) >> 16];
+ cg += bm[(c & 65280) >> 8];
+ cb += bm[c & 255];
+ sum += blurKernel[i];
+ read++;
+ }
+ ri = yi + x;
+ a2[ri] = ca / sum;
+ r2[ri] = cr / sum;
+ g2[ri] = cg / sum;
+ b2[ri] = cb / sum;
+ }
+ yi += width;
+ }
+ yi = 0;
+ ym = -blurRadius;
+ ymi = ym * width;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ cb = cg = cr = ca = sum = 0;
+ if (ym < 0) {
+ bk0 = ri = -ym;
+ read = x;
+ } else {
+ if (ym >= height) {
+ break;
+ }
+ bk0 = 0;
+ ri = ym;
+ read = x + ymi;
+ }
+ for (i = bk0; i < blurKernelSize; i++) {
+ if (ri >= height) {
+ break;
+ }
+ bm = blurMult[i];
+ ca += bm[a2[read]];
+ cr += bm[r2[read]];
+ cg += bm[g2[read]];
+ cb += bm[b2[read]];
+ sum += blurKernel[i];
+ ri++;
+ read += width;
+ }
+ argb[x + yi] = (ca/sum)<<24 | (cr/sum)<<16 | (cg/sum)<<8 | (cb/sum);
+ }
+ yi += width;
+ ymi += width;
+ ym++;
+ }
+ Filters._setPixels(pixels, argb);
+}
+
+Filters.blur = function(canvas, radius){
+ blurARGB(canvas, radius);
+};
+
+
+module.exports = Filters;
+
+},{}],60:[function(_dereq_,module,exports){
+/**
+ * @module Image
+ * @submodule Image
+ * @for p5
+ * @requires core
+ */
+
+/**
+ * This module defines the p5 methods for the p5.Image class
+ * for drawing images to the main display canvas.
+ */
+'use strict';
+
+
+var p5 = _dereq_('../core/core');
+
+/* global frames:true */// This is not global, but JSHint is not aware that
+// this module is implicitly enclosed with Browserify: this overrides the
+// redefined-global error and permits using the name "frames" for the array
+// of saved animation frames.
+var frames = [];
+
+
+/**
+ * Creates a new p5.Image (the datatype for storing images). This provides a
+ * fresh buffer of pixels to play with. Set the size of the buffer with the
+ * width and height parameters.
+ *
+ * .pixels gives access to an array containing the values for all the pixels
+ * in the display window.
+ * These values are numbers. This array is the size (including an appropriate
+ * factor for the pixelDensity) of the display window x4,
+ * representing the R, G, B, A values in order for each pixel, moving from
+ * left to right across each row, then down each column. See .pixels for
+ * more info. It may also be simpler to use set() or get().
+ *
+ * Before accessing the pixels of an image, the data must loaded with the
+ * loadPixels() function. After the array data has been modified, the
+ * updatePixels() function must be run to update the changes.
+ *
+ * @method createImage
+ * @param {Integer} width width in pixels
+ * @param {Integer} height height in pixels
+ * @return {p5.Image} the p5.Image object
+ * @example
+ *
+ *
+ * @alt
+ * 66x66 dark turquoise rect in center of canvas.
+ * 2 gradated dark turquoise rects fade left. 1 center 1 bottom right of canvas
+ * no image displayed
+ *
+ */
+p5.prototype.createImage = function(width, height) {
+ return new p5.Image(width, height);
+};
+
+/**
+ * Save the current canvas as an image. In Safari, this will open the
+ * image in the window and the user must provide their own
+ * filename on save-as. Other browsers will either save the
+ * file immediately, or prompt the user with a dialogue window.
+ *
+ * @method saveCanvas
+ * @param {Canvas} [selectedCanvas] a variable representing a
+ * specific html5 canvas (optional)
+ * @param {String} [filename]
+ * @param {String} [extension] 'jpg' or 'png'
+ * @example
+ *
+ * function setup() {
+ * var c = createCanvas(100, 100);
+ * background(255, 0, 0);
+ * saveCanvas(c, 'myCanvas', 'jpg');
+ * }
+ *
+ *
+ * // note that this example has the same result as above
+ * // if no canvas is specified, defaults to main canvas
+ * function setup() {
+ * createCanvas(100, 100);
+ * background(255, 0, 0);
+ * saveCanvas('myCanvas', 'jpg');
+ * }
+ *
+ *
+ * // all of the following are valid
+ * saveCanvas(c, 'myCanvas', 'jpg');
+ * saveCanvas(c, 'myCanvas');
+ * saveCanvas(c);
+ * saveCanvas('myCanvas', 'png');
+ * saveCanvas('myCanvas');
+ * saveCanvas();
+ *
+ *
+ * @alt
+ * no image displayed
+ * no image displayed
+ * no image displayed
+ *
+ */
+p5.prototype.saveCanvas = function() {
+
+ var cnv, filename, extension;
+ if (arguments.length === 3) {
+ cnv = arguments[0];
+ filename = arguments[1];
+ extension = arguments[2];
+ } else if (arguments.length === 2) {
+ if (typeof arguments[0] === 'object') {
+ cnv = arguments[0];
+ filename = arguments[1];
+ } else {
+ filename = arguments[0];
+ extension = arguments[1];
+ }
+ } else if (arguments.length === 1) {
+ if (typeof arguments[0] === 'object') {
+ cnv = arguments[0];
+ } else {
+ filename = arguments[0];
+ }
+ }
+
+ if (cnv instanceof p5.Element) {
+ cnv = cnv.elt;
+ }
+ if (!(cnv instanceof HTMLCanvasElement)) {
+ cnv = null;
+ }
+
+ if (!extension) {
+ extension = p5.prototype._checkFileExtension(filename, extension)[1];
+ if (extension === '') {
+ extension = 'png';
+ }
+ }
+
+ if (!cnv) {
+ if (this._curElement && this._curElement.elt) {
+ cnv = this._curElement.elt;
+ }
+ }
+
+ if ( p5.prototype._isSafari() ) {
+ var aText = 'Hello, Safari user!\n';
+ aText += 'Now capturing a screenshot...\n';
+ aText += 'To save this image,\n';
+ aText += 'go to File --> Save As.\n';
+ alert(aText);
+ window.location.href = cnv.toDataURL();
+ } else {
+ var mimeType;
+ if (typeof(extension) === 'undefined') {
+ extension = 'png';
+ mimeType = 'image/png';
+ }
+ else {
+ switch(extension){
+ case 'png':
+ mimeType = 'image/png';
+ break;
+ case 'jpeg':
+ mimeType = 'image/jpeg';
+ break;
+ case 'jpg':
+ mimeType = 'image/jpeg';
+ break;
+ default:
+ mimeType = 'image/png';
+ break;
+ }
+ }
+ var downloadMime = 'image/octet-stream';
+ var imageData = cnv.toDataURL(mimeType);
+ imageData = imageData.replace(mimeType, downloadMime);
+
+ p5.prototype.downloadFile(imageData, filename, extension);
+ }
+};
+
+/**
+ * Capture a sequence of frames that can be used to create a movie.
+ * Accepts a callback. For example, you may wish to send the frames
+ * to a server where they can be stored or converted into a movie.
+ * If no callback is provided, the browser will pop up save dialogues in an
+ * attempt to download all of the images that have just been created. With the
+ * callback provided the image data isn't saved by default but instead passed
+ * as an argument to the callback function as an array of objects, with the
+ * size of array equal to the total number of frames.
+ *
+ * @method saveFrames
+ * @param {String} filename
+ * @param {String} extension 'jpg' or 'png'
+ * @param {Number} duration Duration in seconds to save the frames for.
+ * @param {Number} framerate Framerate to save the frames in.
+ * @param {Function} [callback] A callback function that will be executed
+ to handle the image data. This function
+ should accept an array as argument. The
+ array will contain the specified number of
+ frames of objects. Each object has three
+ properties: imageData - an
+ image/octet-stream, filename and extension.
+ * @example
+ *
+ * The image may not be immediately available for rendering
+ * If you want to ensure that the image is ready before doing
+ * anything with it, place the loadImage() call in preload().
+ * You may also supply a callback function to handle the image when it's ready.
+ *
+ * The path to the image should be relative to the HTML file
+ * that links in your sketch. Loading an from a URL or other
+ * remote location may be blocked due to your browser's built-in
+ * security.
+ *
+ * @method loadImage
+ * @param {String} path Path of the image to be loaded
+ * @param {Function(p5.Image)} [successCallback] Function to be called once
+ * the image is loaded. Will be passed the
+ * p5.Image.
+ * @param {Function(Event)} [failureCallback] called with event error if
+ * the image fails to load.
+ * @return {p5.Image} the p5.Image object
+ * @example
+ *
+ *
+ * function setup() {
+ * // here we use a callback to display the image after loading
+ * loadImage("assets/laDefense.jpg", function(img) {
+ * image(img, 0, 0);
+ * });
+ * }
+ *
+ *
+ *
+ * @alt
+ * image of the underside of a white umbrella and grided ceililng above
+ * image of the underside of a white umbrella and grided ceililng above
+ *
+ */
+p5.prototype.loadImage = function(path, successCallback, failureCallback) {
+ var img = new Image();
+ var pImg = new p5.Image(1, 1, this);
+ var decrementPreload = p5._getDecrementPreload.apply(this, arguments);
+
+ img.onload = function() {
+ pImg.width = pImg.canvas.width = img.width;
+ pImg.height = pImg.canvas.height = img.height;
+
+ // Draw the image into the backing canvas of the p5.Image
+ pImg.drawingContext.drawImage(img, 0, 0);
+
+ if (typeof successCallback === 'function') {
+ successCallback(pImg);
+ }
+ if (decrementPreload && (successCallback !== decrementPreload)) {
+ decrementPreload();
+ }
+ };
+ img.onerror = function(e) {
+ p5._friendlyFileLoadError(0,img.src);
+ // don't get failure callback mixed up with decrementPreload
+ if ((typeof failureCallback === 'function') &&
+ (failureCallback !== decrementPreload)) {
+ failureCallback(e);
+ }
+ };
+
+ //set crossOrigin in case image is served which CORS headers
+ //this will let us draw to canvas without tainting it.
+ //see https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image
+ // When using data-uris the file will be loaded locally
+ // so we don't need to worry about crossOrigin with base64 file types
+ if(path.indexOf('data:image/') !== 0) {
+ img.crossOrigin = 'Anonymous';
+ }
+
+ //start loading the image
+ img.src = path;
+
+ return pImg;
+};
+
+/**
+ * Validates clipping params. Per drawImage spec sWidth and sHight cannot be
+ * negative or greater than image intrinsic width and height
+ * @private
+ * @param {Number} sVal
+ * @param {Number} iVal
+ * @returns {Number}
+ * @private
+ */
+function _sAssign(sVal, iVal) {
+ if (sVal > 0 && sVal < iVal) {
+ return sVal;
+ }
+ else {
+ return iVal;
+ }
+}
+
+/**
+ * Draw an image to the main canvas of the p5js sketch
+ *
+ * @method image
+ * @param {p5.Image} img the image to display
+ * @param {Number} x the x-coordinate at which to place the top-left
+ * corner of the source image
+ * @param {Number} y the y-coordinate at which to place the top-left
+ * corner of the source image
+ * @param {Number} width the width to draw the image
+ * @param {Number} height the height to draw the image
+ * @example
+ *
+ *
+ * function setup() {
+ * // here we use a callback to display the image after loading
+ * loadImage("assets/laDefense.jpg", function(img) {
+ * image(img, 0, 0);
+ * });
+ * }
+ *
+ *
+ *
+ * @alt
+ * image of the underside of a white umbrella and grided ceiling above
+ * image of the underside of a white umbrella and grided ceiling above
+ *
+ */
+/**
+ * @method image
+ * @param {p5.Image} img
+ * @param {Number} dx the x-coordinate in the destination canvas at
+ * which to place the top-left corner of the
+ * source image
+ * @param {Number} dy the y-coordinate in the destination canvas at
+ * which to place the top-left corner of the
+ * source image
+ * @param {Number} dWidth the width to draw the image in the destination
+ * canvas
+ * @param {Number} dHeight the height to draw the image in the destination
+ * canvas
+ * @param {Number} sx the x-coordinate of the top left corner of the
+ * sub-rectangle of the source image to draw into
+ * the destination canvas
+ * @param {Number} sy the y-coordinate of the top left corner of the
+ * sub-rectangle of the source image to draw into
+ * the destination canvas
+ * @param {Number} [sWidth] the width of the sub-rectangle of the
+ * source image to draw into the destination
+ * canvas
+ * @param {Number} [sHeight] the height of the sub-rectangle of the
+ * source image to draw into the destination context
+ */
+p5.prototype.image =
+ function(img, dx, dy, dWidth, dHeight, sx, sy, sWidth, sHeight) {
+ // set defaults per spec: https://goo.gl/3ykfOq
+
+ var defW = img.width;
+ var defH = img.height;
+
+ if (img.elt && img.elt.videoWidth && !img.canvas) { // video no canvas
+ var actualW = img.elt.videoWidth;
+ var actualH = img.elt.videoHeight;
+ defW = img.elt.videoWidth;
+ defH = img.elt.width*actualH/actualW;
+ }
+
+ var _dx = dx;
+ var _dy = dy;
+ var _dw = dWidth || defW;
+ var _dh = dHeight || defH;
+ var _sx = sx || 0;
+ var _sy = sy || 0;
+ var _sw = sWidth || defW;
+ var _sh = sHeight || defH;
+
+ _sw = _sAssign(_sw, defW);
+ _sh = _sAssign(_sh, defH);
+
+
+ // This part needs cleanup and unit tests
+ // see issues https://github.com/processing/p5.js/issues/1741
+ // and https://github.com/processing/p5.js/issues/1673
+ var pd = 1;
+
+ if (img.elt && img.elt.videoWidth && img.elt.style.width && !img.canvas) {
+ pd = img.elt.videoWidth / parseInt(img.elt.style.width, 10);
+ }
+ else if (img.elt && img.elt.width && img.elt.style.width) {
+ pd = img.elt.width / parseInt(img.elt.style.width, 10);
+ }
+
+ _sx *= pd;
+ _sy *= pd;
+ _sh *= pd;
+ _sw *= pd;
+
+ var vals = canvas.modeAdjust(_dx, _dy, _dw, _dh,
+ this._renderer._imageMode);
+
+ // tint the image if there is a tint
+ this._renderer.image(img, _sx, _sy, _sw, _sh, vals.x, vals.y, vals.w,
+ vals.h);
+};
+
+
+/**
+ * Sets the fill value for displaying images. Images can be tinted to
+ * specified colors or made transparent by including an alpha value.
+ *
+ * To apply transparency to an image without affecting its color, use
+ * white as the tint color and specify an alpha value. For instance,
+ * tint(255, 128) will make an image 50% transparent (assuming the default
+ * alpha range of 0-255, which can be changed with colorMode()).
+ *
+ * The value for the gray parameter must be less than or equal to the current
+ * maximum value as specified by colorMode(). The default maximum value is
+ * 255.
+ *
+ * @method tint
+ * @param {Number|Array} v1 gray value, red or hue value (depending on the
+ * current color mode), or color Array
+ * @param {Number|Array} [v2] green or saturation value (depending on the
+ * current color mode)
+ * @param {Number|Array} [v3] blue or brightness value (depending on the
+ * current color mode)
+ * @param {Number|Array} [a] opacity of the background
+ * @example
+ *
+ *
+ * @alt
+ * 2 side by side images of umbrella and ceiling, one image with blue tint
+ * Images of umbrella and ceiling, one half of image with blue tint
+ * 2 side by side images of umbrella and ceiling, one image translucent
+ *
+ */
+p5.prototype.tint = function () {
+ var c = this.color.apply(this, arguments);
+ this._renderer._tint = c.levels;
+};
+
+/**
+ * Removes the current fill value for displaying images and reverts to
+ * displaying images with their original hues.
+ *
+ * @method noTint
+ * @example
+ *
+ *
+ * @alt
+ * 2 side by side images of bricks, left image with blue tint
+ *
+ */
+p5.prototype.noTint = function() {
+ this._renderer._tint = null;
+};
+
+/**
+ * Apply the current tint color to the input image, return the resulting
+ * canvas.
+ *
+ * @param {p5.Image} The image to be tinted
+ * @return {canvas} The resulting tinted canvas
+ *
+ */
+p5.prototype._getTintedImageCanvas = function(img) {
+ if (!img.canvas) {
+ return img;
+ }
+ var pixels = Filters._toPixels(img.canvas);
+ var tmpCanvas = document.createElement('canvas');
+ tmpCanvas.width = img.canvas.width;
+ tmpCanvas.height = img.canvas.height;
+ var tmpCtx = tmpCanvas.getContext('2d');
+ var id = tmpCtx.createImageData(img.canvas.width, img.canvas.height);
+ var newPixels = id.data;
+
+ for(var i = 0; i < pixels.length; i += 4) {
+ var r = pixels[i];
+ var g = pixels[i+1];
+ var b = pixels[i+2];
+ var a = pixels[i+3];
+
+ newPixels[i] = r*this._renderer._tint[0]/255;
+ newPixels[i+1] = g*this._renderer._tint[1]/255;
+ newPixels[i+2] = b*this._renderer._tint[2]/255;
+ newPixels[i+3] = a*this._renderer._tint[3]/255;
+ }
+
+ tmpCtx.putImageData(id, 0, 0);
+ return tmpCanvas;
+};
+
+/**
+ * Set image mode. Modifies the location from which images are drawn by
+ * changing the way in which parameters given to image() are interpreted.
+ * The default mode is imageMode(CORNER), which interprets the second and
+ * third parameters of image() as the upper-left corner of the image. If
+ * two additional parameters are specified, they are used to set the image's
+ * width and height.
+ *
+ * imageMode(CORNERS) interprets the second and third parameters of image()
+ * as the location of one corner, and the fourth and fifth parameters as the
+ * opposite corner.
+ *
+ * imageMode(CENTER) interprets the second and third parameters of image()
+ * as the image's center point. If two additional parameters are specified,
+ * they are used to set the image's width and height.
+ *
+ * @method imageMode
+ * @param {Constant} mode either CORNER, CORNERS, or CENTER
+ * @example
+ *
+ *
+ *
+ * @alt
+ * small square image of bricks
+ * horizontal rectangle image of bricks
+ * large square image of bricks
+ *
+ */
+p5.prototype.imageMode = function(m) {
+ if (m === constants.CORNER ||
+ m === constants.CORNERS ||
+ m === constants.CENTER) {
+ this._renderer._imageMode = m;
+ }
+};
+
+
+module.exports = p5;
+
+},{"../core/canvas":40,"../core/constants":41,"../core/core":42,"../core/error_helpers":45,"./filters":59}],62:[function(_dereq_,module,exports){
+/**
+ * @module Image
+ * @submodule Image
+ * @requires core
+ * @requires constants
+ * @requires filters
+ */
+
+/**
+ * This module defines the p5.Image class and P5 methods for
+ * drawing images to the main display canvas.
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+var Filters = _dereq_('./filters');
+
+/*
+ * Class methods
+ */
+
+/**
+ * Creates a new p5.Image. A p5.Image is a canvas backed representation of an
+ * image.
+ *
+ * p5 can display .gif, .jpg and .png images. Images may be displayed
+ * in 2D and 3D space. Before an image is used, it must be loaded with the
+ * loadImage() function. The p5.Image class contains fields for the width and
+ * height of the image, as well as an array called pixels[] that contains the
+ * values for every pixel in the image.
+ *
+ * The methods described below allow easy access to the image's pixels and
+ * alpha channel and simplify the process of compositing.
+ *
+ * Before using the pixels[] array, be sure to use the loadPixels() method on
+ * the image to make sure that the pixel data is properly loaded.
+ *
+ * @class p5.Image
+ * @constructor
+ * @param {Number} width
+ * @param {Number} height
+ * @param {Object} pInst An instance of a p5 sketch.
+ */
+p5.Image = function(width, height){
+ /**
+ * Image width.
+ * @property width
+ * @example
+ *
+ * var img;
+ * function preload() {
+ * img = loadImage("assets/rockies.jpg");
+ * }
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ * image(img, 0, 0);
+ * for (var i=0; i < img.width; i++) {
+ * var c = img.get(i, img.height/2);
+ * stroke(c);
+ * line(i, height/2, i, height);
+ * }
+ * }
+ *
+ *
+ * @alt
+ * rocky mountains in top and horizontal lines in corresponding colors in bottom.
+ *
+ */
+ this.width = width;
+ /**
+ * Image height.
+ * @property height
+ * @example
+ *
+ * var img;
+ * function preload() {
+ * img = loadImage("assets/rockies.jpg");
+ * }
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ * image(img, 0, 0);
+ * for (var i=0; i < img.height; i++) {
+ * var c = img.get(img.width/2, i);
+ * stroke(c);
+ * line(0, i, width/2, i);
+ * }
+ * }
+ *
+ *
+ * @alt
+ * rocky mountains on right and vertical lines in corresponding colors on left.
+ *
+ */
+ this.height = height;
+ this.canvas = document.createElement('canvas');
+ this.canvas.width = this.width;
+ this.canvas.height = this.height;
+ this.drawingContext = this.canvas.getContext('2d');
+ this._pixelDensity = 1;
+ //used for webgl texturing only
+ this.isTexture = false;
+ /**
+ * Array containing the values for all the pixels in the display window.
+ * These values are numbers. This array is the size (include an appropriate
+ * factor for pixelDensity) of the display window x4,
+ * representing the R, G, B, A values in order for each pixel, moving from
+ * left to right across each row, then down each column. Retina and other
+ * high denisty displays may have more pixels[] (by a factor of
+ * pixelDensity^2).
+ * For example, if the image is 100x100 pixels, there will be 40,000. With
+ * pixelDensity = 2, there will be 160,000. The first four values
+ * (indices 0-3) in the array will be the R, G, B, A values of the pixel at
+ * (0, 0). The second four values (indices 4-7) will contain the R, G, B, A
+ * values of the pixel at (1, 0). More generally, to set values for a pixel
+ * at (x, y):
+ * ```javascript
+ * var d = pixelDensity;
+ * for (var i = 0; i < d; i++) {
+ * for (var j = 0; j < d; j++) {
+ * // loop over
+ * idx = 4 * ((y * d + j) * width * d + (x * d + i));
+ * pixels[idx] = r;
+ * pixels[idx+1] = g;
+ * pixels[idx+2] = b;
+ * pixels[idx+3] = a;
+ * }
+ * }
+ * ```
+ *
+ * Before accessing this array, the data must loaded with the loadPixels()
+ * function. After the array data has been modified, the updatePixels()
+ * function must be run to update the changes.
+ * @property {Number[]} pixels
+ * @example
+ *
+ *
+ * @alt
+ * 2 images of rocky mountains vertically stacked
+ *
+ */
+p5.Image.prototype.loadPixels = function(){
+ p5.Renderer2D.prototype.loadPixels.call(this);
+};
+
+/**
+ * Updates the backing canvas for this image with the contents of
+ * the [pixels] array.
+ *
+ * @method updatePixels
+ * @param {Integer|undefined} x x-offset of the target update area for the
+ * underlying canvas
+ * @param {Integer|undefined} y y-offset of the target update area for the
+ * underlying canvas
+ * @param {Integer|undefined} w height of the target update area for the
+ * underlying canvas
+ * @param {Integer|undefined} h height of the target update area for the
+ * underlying canvas
+ * @example
+ *
+ *
+ * @alt
+ * 2 images of rocky mountains vertically stacked
+ *
+ */
+p5.Image.prototype.updatePixels = function(x, y, w, h){
+ p5.Renderer2D.prototype.updatePixels.call(this, x, y, w, h);
+};
+
+/**
+ * Get a region of pixels from an image.
+ *
+ * If no params are passed, those whole image is returned,
+ * if x and y are the only params passed a single pixel is extracted
+ * if all params are passed a rectangle region is extracted and a p5.Image
+ * is returned.
+ *
+ * Returns undefined if the region is outside the bounds of the image
+ *
+ * @method get
+ * @param {Number} [x] x-coordinate of the pixel
+ * @param {Number} [y] y-coordinate of the pixel
+ * @param {Number} [w] width
+ * @param {Number} [h] height
+ * @return {Array|Color|p5.Image} color of pixel at x,y in array format
+ * [R, G, B, A] or p5.Image
+ * @example
+ *
+ * var myImage;
+ * var c;
+ *
+ * function preload() {
+ * myImage = loadImage("assets/rockies.jpg");
+ * }
+ *
+ * function setup() {
+ * background(myImage);
+ * noStroke();
+ * c = myImage.get(60, 90);
+ * fill(c);
+ * rect(25, 25, 50, 50);
+ * }
+ *
+ * //get() returns color here
+ *
+ *
+ * @alt
+ * image of rocky mountains with 50x50 green rect in front
+ *
+ */
+p5.Image.prototype.get = function(x, y, w, h){
+ return p5.Renderer2D.prototype.get.call(this, x, y, w, h);
+};
+
+/**
+ * Set the color of a single pixel or write an image into
+ * this p5.Image.
+ *
+ * Note that for a large number of pixels this will
+ * be slower than directly manipulating the pixels array
+ * and then calling updatePixels().
+ *
+ * @method set
+ * @param {Number} x x-coordinate of the pixel
+ * @param {Number} y y-coordinate of the pixel
+ * @param {Number|Array|Object} a grayscale value | pixel array |
+ * a p5.Color | image to copy
+ * @example
+ *
+ *
+ * @alt
+ * 2 gradated dark turquoise rects fade left. 1 center 1 bottom right of canvas
+ *
+ */
+p5.Image.prototype.set = function(x, y, imgOrCol){
+ p5.Renderer2D.prototype.set.call(this, x, y, imgOrCol);
+};
+
+/**
+ * Resize the image to a new width and height. To make the image scale
+ * proportionally, use 0 as the value for the wide or high parameter.
+ * For instance, to make the width of an image 150 pixels, and change
+ * the height using the same proportion, use resize(150, 0).
+ *
+ * @method resize
+ * @param {Number} width the resized image width
+ * @param {Number} height the resized image height
+ * @example
+ *
+ *
+ * @alt
+ * image of rocky mountains. zoomed in
+ *
+ */
+p5.Image.prototype.resize = function(width, height){
+
+ // Copy contents to a temporary canvas, resize the original
+ // and then copy back.
+ //
+ // There is a faster approach that involves just one copy and swapping the
+ // this.canvas reference. We could switch to that approach if (as i think
+ // is the case) there an expectation that the user would not hold a
+ // reference to the backing canvas of a p5.Image. But since we do not
+ // enforce that at the moment, I am leaving in the slower, but safer
+ // implementation.
+
+ // auto-resize
+ if (width === 0 && height === 0) {
+ width = this.canvas.width;
+ height = this.canvas.height;
+ } else if (width === 0) {
+ width = this.canvas.width * height / this.canvas.height;
+ } else if (height === 0) {
+ height = this.canvas.height * width / this.canvas.width;
+ }
+
+ width = Math.floor(width);
+ height = Math.floor(height);
+
+ var tempCanvas = document.createElement('canvas');
+ tempCanvas.width = width;
+ tempCanvas.height = height;
+ tempCanvas.getContext('2d').drawImage(this.canvas,
+ 0, 0, this.canvas.width, this.canvas.height,
+ 0, 0, tempCanvas.width, tempCanvas.height
+ );
+
+
+ // Resize the original canvas, which will clear its contents
+ this.canvas.width = this.width = width;
+ this.canvas.height = this.height = height;
+
+ //Copy the image back
+
+ this.drawingContext.drawImage(tempCanvas,
+ 0, 0, width, height,
+ 0, 0, width, height
+ );
+
+ if(this.pixels.length > 0){
+ this.loadPixels();
+ }
+};
+
+/**
+ * Copies a region of pixels from one image to another. If no
+ * srcImage is specified this is used as the source. If the source
+ * and destination regions aren't the same size, it will
+ * automatically resize source pixels to fit the specified
+ * target region.
+ *
+ * @method copy
+ * @param {p5.Image|undefined} srcImage source image
+ * @param {Integer} sx X coordinate of the source's upper left corner
+ * @param {Integer} sy Y coordinate of the source's upper left corner
+ * @param {Integer} sw source image width
+ * @param {Integer} sh source image height
+ * @param {Integer} dx X coordinate of the destination's upper left corner
+ * @param {Integer} dy Y coordinate of the destination's upper left corner
+ * @param {Integer} dw destination image width
+ * @param {Integer} dh destination image height
+ * @example
+ *
+ * var photo;
+ * var bricks;
+ * var x;
+ * var y;
+ *
+ * function preload() {
+ * photo = loadImage("assets/rockies.jpg");
+ * bricks = loadImage("assets/bricks.jpg");
+ * }
+ *
+ * function setup() {
+ * x = bricks.width/2;
+ * y = bricks.height/2;
+ * photo.copy(bricks, 0, 0, x, y, 0, 0, x, y);
+ * image(photo, 0, 0);
+ * }
+ *
+ *
+ * @alt
+ * image of rocky mountains and smaller image on top of bricks at top left
+ *
+ */
+p5.Image.prototype.copy = function () {
+ p5.prototype.copy.apply(this, arguments);
+};
+
+/**
+ * Masks part of an image from displaying by loading another
+ * image and using it's alpha channel as an alpha channel for
+ * this image.
+ *
+ * @method mask
+ * @param {p5.Image} srcImage source image
+ * @example
+ *
+ *
+ * @alt
+ * image of rocky mountains. Brick images on left and right. Right overexposed
+ * image of rockies. Brickwall images on left and right. Right mortar transparent
+ * image of rockies. Brickwall images on left and right. Right translucent
+ *
+ */
+p5.Image.prototype.blend = function() {
+ p5.prototype.blend.apply(this, arguments);
+};
+
+/**
+ * Saves the image to a file and force the browser to download it.
+ * Accepts two strings for filename and file extension
+ * Supports png (default) and jpg.
+ *
+ * @method save
+ * @param {String} filename give your file a name
+ * @param {String} extension 'png' or 'jpg'
+ * @example
+ *
+ *
+ * @alt
+ * image of rocky mountains.
+ *
+ */
+p5.Image.prototype.save = function(filename, extension) {
+ var mimeType;
+ if (!extension) {
+ extension = 'png';
+ mimeType = 'image/png';
+ }
+ else {
+ // en.wikipedia.org/wiki/Comparison_of_web_browsers#Image_format_support
+ switch(extension.toLowerCase()){
+ case 'png':
+ mimeType = 'image/png';
+ break;
+ case 'jpeg':
+ mimeType = 'image/jpeg';
+ break;
+ case 'jpg':
+ mimeType = 'image/jpeg';
+ break;
+ default:
+ mimeType = 'image/png';
+ break;
+ }
+ }
+ var downloadMime = 'image/octet-stream';
+ var imageData = this.canvas.toDataURL(mimeType);
+ imageData = imageData.replace(mimeType, downloadMime);
+
+ //Make the browser download the file
+ p5.prototype.downloadFile(imageData, filename, extension);
+};
+
+module.exports = p5.Image;
+},{"../core/core":42,"./filters":59}],63:[function(_dereq_,module,exports){
+/**
+ * @module Image
+ * @submodule Pixels
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+var Filters = _dereq_('./filters');
+_dereq_('../color/p5.Color');
+
+/**
+ * Uint8ClampedArray
+ * containing the values for all the pixels in the display window.
+ * These values are numbers. This array is the size (include an appropriate
+ * factor for pixelDensity) of the display window x4,
+ * representing the R, G, B, A values in order for each pixel, moving from
+ * left to right across each row, then down each column. Retina and other
+ * high denisty displays will have more pixels[] (by a factor of
+ * pixelDensity^2).
+ * For example, if the image is 100x100 pixels, there will be 40,000. On a
+ * retina display, there will be 160,000.
+ *
+ * The first four values (indices 0-3) in the array will be the R, G, B, A
+ * values of the pixel at (0, 0). The second four values (indices 4-7) will
+ * contain the R, G, B, A values of the pixel at (1, 0). More generally, to
+ * set values for a pixel at (x, y):
+ * ```javascript
+ * var d = pixelDensity;
+ * for (var i = 0; i < d; i++) {
+ * for (var j = 0; j < d; j++) {
+ * // loop over
+ * idx = 4 * ((y * d + j) * width * d + (x * d + i));
+ * pixels[idx] = r;
+ * pixels[idx+1] = g;
+ * pixels[idx+2] = b;
+ * pixels[idx+3] = a;
+ * }
+ * }
+ * ```
+ *
While the above method is complex, it is flexible enough to work with
+ * any pixelDensity. Note that set() will automatically take care of
+ * setting all the appropriate values in pixels[] for a given (x, y) at
+ * any pixelDensity, but the performance may not be as fast when lots of
+ * modifications are made to the pixel array.
+ *
+ * Before accessing this array, the data must loaded with the loadPixels()
+ * function. After the array data has been modified, the updatePixels()
+ * function must be run to update the changes.
+ *
+ * Note that this is not a standard javascript array. This means that
+ * standard javascript functions such as slice() or
+ * arrayCopy() do not
+ * work.
+ *
+ * @alt
+ * top half of canvas pink, bottom grey
+ *
+ */
+p5.prototype.pixels = [];
+
+/**
+ * Copies a region of pixels from one image to another, using a specified
+ * blend mode to do the operation.
+ * Available blend modes are: BLEND | DARKEST | LIGHTEST | DIFFERENCE |
+ * MULTIPLY| EXCLUSION | SCREEN | REPLACE | OVERLAY | HARD_LIGHT |
+ * SOFT_LIGHT | DODGE | BURN | ADD | NORMAL
+ *
+ *
+ * @method blend
+ * @param {p5.Image|undefined} srcImage source image
+ * @param {Integer} sx X coordinate of the source's upper left corner
+ * @param {Integer} sy Y coordinate of the source's upper left corner
+ * @param {Integer} sw source image width
+ * @param {Integer} sh source image height
+ * @param {Integer} dx X coordinate of the destination's upper left corner
+ * @param {Integer} dy Y coordinate of the destination's upper left corner
+ * @param {Integer} dw destination image width
+ * @param {Integer} dh destination image height
+ * @param {Integer} blendMode the blend mode
+ *
+ * @example
+ *
+ *
+ * @alt
+ * image of rocky mountains. Brick images on left and right. Right overexposed
+ * image of rockies. Brickwall images on left and right. Right mortar transparent
+ * image of rockies. Brickwall images on left and right. Right translucent
+ *
+ *
+ */
+p5.prototype.blend = function() {
+ if (this._renderer) {
+ this._renderer.blend.apply(this._renderer, arguments);
+ } else {
+ p5.Renderer2D.prototype.blend.apply(this, arguments);
+ }
+};
+
+/**
+ * Copies a region of the canvas to another region of the canvas
+ * and copies a region of pixels from an image used as the srcImg parameter
+ * into the canvas srcImage is specified this is used as the source. If
+ * the source and destination regions aren't the same size, it will
+ * automatically resize source pixels to fit the specified
+ * target region.
+ *
+ * @method copy
+ * @param {p5.Image|undefined} srcImage source image
+ * @param {Integer} sx X coordinate of the source's upper left corner
+ * @param {Integer} sy Y coordinate of the source's upper left corner
+ * @param {Integer} sw source image width
+ * @param {Integer} sh source image height
+ * @param {Integer} dx X coordinate of the destination's upper left corner
+ * @param {Integer} dy Y coordinate of the destination's upper left corner
+ * @param {Integer} dw destination image width
+ * @param {Integer} dh destination image height
+ *
+ * @example
+ *
+ *
+ * @alt
+ * image of rocky mountains. Brick images on left and right. Right overexposed
+ * image of rockies. Brickwall images on left and right. Right mortar transparent
+ * image of rockies. Brickwall images on left and right. Right translucent
+ *
+ */
+p5.prototype.copy = function () {
+ p5.Renderer2D._copyHelper.apply(this, arguments);
+};
+
+/**
+ * Applies a filter to the canvas.
+ *
+ *
+ * The presets options are:
+ *
+ *
+ * THRESHOLD
+ * Converts the image to black and white pixels depending if they are above or
+ * below the threshold defined by the level parameter. The parameter must be
+ * between 0.0 (black) and 1.0 (white). If no level is specified, 0.5 is used.
+ *
+ *
+ * GRAY
+ * Converts any colors in the image to grayscale equivalents. No parameter
+ * is used.
+ *
+ *
+ * OPAQUE
+ * Sets the alpha channel to entirely opaque. No parameter is used.
+ *
+ *
+ * INVERT
+ * Sets each pixel to its inverse value. No parameter is used.
+ *
+ *
+ * POSTERIZE
+ * Limits each channel of the image to the number of colors specified as the
+ * parameter. The parameter can be set to values between 2 and 255, but
+ * results are most noticeable in the lower ranges.
+ *
+ *
+ * BLUR
+ * Executes a Guassian blur with the level parameter specifying the extent
+ * of the blurring. If no parameter is used, the blur is equivalent to
+ * Guassian blur of radius 1. Larger values increase the blur.
+ *
+ *
+ * ERODE
+ * Reduces the light areas. No parameter is used.
+ *
+ *
+ * DILATE
+ * Increases the light areas. No parameter is used.
+ *
+ * @method filter
+ * @param {Constant} filterType
+ * @param {Number} filterParam an optional parameter unique
+ * to each filter, see above
+ *
+ *
+ * @example
+ *
+ *
+ * @alt
+ * black and white image of a brick wall.
+ * greyscale image of a brickwall
+ * image of a brickwall
+ * jade colored image of a brickwall
+ * red and pink image of a brickwall
+ * image of a brickwall
+ * blurry image of a brickwall
+ * image of a brickwall
+ * image of a brickwall with less detail
+ *
+ */
+p5.prototype.filter = function(operation, value) {
+ if(this.canvas !== undefined) {
+ Filters.apply(this.canvas, Filters[operation.toLowerCase()], value);
+ }
+ else {
+ Filters.apply(this.elt, Filters[operation.toLowerCase()], value);
+ }
+};
+
+/**
+ * Returns an array of [R,G,B,A] values for any pixel or grabs a section of
+ * an image. If no parameters are specified, the entire image is returned.
+ * Use the x and y parameters to get the value of one pixel. Get a section of
+ * the display window by specifying additional w and h parameters. When
+ * getting an image, the x and y parameters define the coordinates for the
+ * upper-left corner of the image, regardless of the current imageMode().
+ *
+ * If the pixel requested is outside of the image window, [0,0,0,255] is
+ * returned. To get the numbers scaled according to the current color ranges
+ * and taking into account colorMode, use getColor instead of get.
+ *
+ * Getting the color of a single pixel with get(x, y) is easy, but not as fast
+ * as grabbing the data directly from pixels[]. The equivalent statement to
+ * get(x, y) using pixels[] with pixel density d is
+ *
+ * var off = (y * width + x) * d * 4;
+ * [pixels[off],
+ * pixels[off+1],
+ * pixels[off+2],
+ * pixels[off+3]]
+ *
+ * See the reference for pixels[] for more information.
+ *
+ * @method get
+ * @param {Number} [x] x-coordinate of the pixel
+ * @param {Number} [y] y-coordinate of the pixel
+ * @param {Number} [w] width
+ * @param {Number} [h] height
+ * @return {Array|p5.Image} values of pixel at x,y in array format
+ * [R, G, B, A] or p5.Image
+ * @example
+ *
+ *
+ * var img;
+ * function preload() {
+ * img = loadImage("assets/rockies.jpg");
+ * }
+ * function setup() {
+ * image(img, 0, 0);
+ * var c = get();
+ * image(c, width/2, 0);
+ * }
+ *
+ *
+ *
+ * @alt
+ * 2 images of the rocky mountains, side-by-side
+ * Image of the rocky mountains with 50x50 green rect in center of canvas
+ *
+ */
+p5.prototype.get = function(x, y, w, h){
+ return this._renderer.get(x, y, w, h);
+};
+
+/**
+ * Loads the pixel data for the display window into the pixels[] array. This
+ * function must always be called before reading from or writing to pixels[].
+ *
+ * @method loadPixels
+ * @example
+ *
+ *
+ * var img;
+ * function preload() {
+ * img = loadImage("assets/rockies.jpg");
+ * }
+ *
+ * function setup() {
+ * image(img, 0, 0);
+ * var d = pixelDensity();
+ * var halfImage = 4 * (img.width * d) *
+ (img.height/2 * d);
+ * loadPixels();
+ * for (var i = 0; i < halfImage; i++) {
+ * pixels[i+halfImage] = pixels[i];
+ * }
+ * updatePixels();
+ * }
+ *
+ *
+ *
+ * @alt
+ * two images of the rocky mountains. one on top, one on bottom of canvas.
+ *
+ */
+p5.prototype.loadPixels = function() {
+ this._renderer.loadPixels();
+};
+
+/**
+ *
Changes the color of any pixel, or writes an image directly to the
+ * display window.
+ *
The x and y parameters specify the pixel to change and the c parameter
+ * specifies the color value. This can be a p5.Color object, or [R, G, B, A]
+ * pixel array. It can also be a single grayscale value.
+ * When setting an image, the x and y parameters define the coordinates for
+ * the upper-left corner of the image, regardless of the current imageMode().
+ *
+ *
+ * After using set(), you must call updatePixels() for your changes to appear.
+ * This should be called once all pixels have been set, and must be called before
+ * calling .get() or drawing the image.
+ *
+ *
Setting the color of a single pixel with set(x, y) is easy, but not as
+ * fast as putting the data directly into pixels[]. Setting the pixels[]
+ * values directly may be complicated when working with a retina display,
+ * but will perform better when lots of pixels need to be set directly on
+ * every loop.
+ *
See the reference for pixels[] for more information.
+ *
+ * @method set
+ * @param {Number} x x-coordinate of the pixel
+ * @param {Number} y y-coordinate of the pixel
+ * @param {Number|Array|Object} c insert a grayscale value | a pixel array |
+ * a p5.Color object | a p5.Image to copy
+ * @example
+ *
+ *
+ * @alt
+ * 4 black points in the shape of a square middle-right of canvas.
+ * square with orangey-brown gradient lightening at bottom right.
+ * image of the rocky mountains. with lines like an 'x' through the center.
+ */
+p5.prototype.set = function (x, y, imgOrCol) {
+ this._renderer.set(x, y, imgOrCol);
+};
+/**
+ * Updates the display window with the data in the pixels[] array.
+ * Use in conjunction with loadPixels(). If you're only reading pixels from
+ * the array, there's no need to call updatePixels() — updating is only
+ * necessary to apply changes. updatePixels() should be called anytime the
+ * pixels array is manipulated or set() is called.
+ *
+ * @method updatePixels
+ * @param {Number} [x] x-coordinate of the upper-left corner of region
+ * to update
+ * @param {Number} [y] y-coordinate of the upper-left corner of region
+ * to update
+ * @param {Number} [w] width of region to update
+ * @param {Number} [h] height of region to update
+ * @example
+ *
+ * @alt
+ * two images of the rocky mountains. one on top, one on bottom of canvas.
+ */
+p5.prototype.updatePixels = function (x, y, w, h) {
+ // graceful fail - if loadPixels() or set() has not been called, pixel
+ // array will be empty, ignore call to updatePixels()
+ if (this.pixels.length === 0) {
+ return;
+ }
+ this._renderer.updatePixels(x, y, w, h);
+};
+
+module.exports = p5;
+
+},{"../color/p5.Color":36,"../core/core":42,"./filters":59}],64:[function(_dereq_,module,exports){
+/**
+ * @module IO
+ * @submodule Input
+ * @for p5
+ * @requires core
+ */
+
+/* globals Request: false */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+var opentype = _dereq_('opentype.js');
+_dereq_('whatwg-fetch');
+_dereq_('es6-promise').polyfill();
+var fetchJsonp = _dereq_('fetch-jsonp');
+_dereq_('../core/error_helpers');
+
+/**
+ * Checks if we are in preload and returns the last arg which will be the
+ * _decrementPreload function if called from a loadX() function. Should
+ * only be used in loadX() functions.
+ * @private
+ */
+p5._getDecrementPreload = function () {
+ var decrementPreload = arguments[arguments.length - 1];
+
+ // when in preload decrementPreload will always be the last arg as it is set
+ // with args.push() before invocation in _wrapPreload
+ if ((window.preload || (this && this.preload)) &&
+ typeof decrementPreload === 'function') {
+ return decrementPreload;
+ } else {
+ return null;
+ }
+};
+
+/**
+ * Loads an opentype font file (.otf, .ttf) from a file or a URL,
+ * and returns a PFont Object. This method is asynchronous,
+ * meaning it may not finish before the next line in your sketch
+ * is executed.
+ *
+ * The path to the font should be relative to the HTML file
+ * that links in your sketch. Loading an from a URL or other
+ * remote location may be blocked due to your browser's built-in
+ * security.
+ *
+ * @method loadFont
+ * @param {String} path name of the file or url to load
+ * @param {Function} [callback] function to be executed after
+ * loadFont()
+ * completes
+ * @return {Object} p5.Font object
+ * @example
+ *
+ *
Calling loadFont() inside preload() guarantees that the load
+ * operation will have completed before setup() and draw() are called.
+ *
+ * @alt
+ * p5*js in p5's theme dark pink
+ * p5*js in p5's theme dark pink
+ *
+ */
+p5.prototype.loadFont = function (path, onSuccess, onError) {
+
+ var p5Font = new p5.Font(this);
+ var decrementPreload = p5._getDecrementPreload.apply(this, arguments);
+
+ opentype.load(path, function (err, font) {
+
+ if (err) {
+
+ if ((typeof onError !== 'undefined') && (onError !== decrementPreload)) {
+ return onError(err);
+ }
+ p5._friendlyFileLoadError(4, path);
+ console.error(err, path);
+ return;
+ }
+
+ p5Font.font = font;
+
+ if (typeof onSuccess !== 'undefined') {
+ onSuccess(p5Font);
+ }
+
+ if (decrementPreload && (onSuccess !== decrementPreload)) {
+ decrementPreload();
+ }
+
+ // check that we have an acceptable font type
+ var validFontTypes = [ 'ttf', 'otf', 'woff', 'woff2' ],
+ fileNoPath = path.split('\\').pop().split('/').pop(),
+ lastDotIdx = fileNoPath.lastIndexOf('.'), fontFamily, newStyle,
+ fileExt = lastDotIdx < 1 ? null : fileNoPath.substr(lastDotIdx + 1);
+
+ // if so, add it to the DOM (name-only) for use with p5.dom
+ if (validFontTypes.indexOf(fileExt) > -1) {
+
+ fontFamily = fileNoPath.substr(0, lastDotIdx);
+ newStyle = document.createElement('style');
+ newStyle.appendChild(document.createTextNode('\n@font-face {' +
+ '\nfont-family: ' + fontFamily + ';\nsrc: url(' + path + ');\n}\n'));
+ document.head.appendChild(newStyle);
+ }
+
+ });
+
+ return p5Font;
+};
+
+//BufferedReader
+p5.prototype.createInput = function () {
+ // TODO
+ throw 'not yet implemented';
+};
+
+p5.prototype.createReader = function () {
+ // TODO
+ throw 'not yet implemented';
+};
+
+p5.prototype.loadBytes = function () {
+ // TODO
+ throw 'not yet implemented';
+};
+
+/**
+ * Loads a JSON file from a file or a URL, and returns an Object or Array.
+ * This method is asynchronous, meaning it may not finish before the next
+ * line in your sketch is executed. JSONP is supported via a polyfill and you
+ * can pass in as the second argument an object with definitions of the json
+ * callback following the syntax specified here.
+ *
+ * @method loadJSON
+ * @param {String} path name of the file or url to load
+ * @param {Object} [jsonpOptions] options object for jsonp related settings
+ * @param {String} [datatype] "json" or "jsonp"
+ * @param {Function} [callback] function to be executed after
+ * loadJSON() completes, data is passed
+ * in as first argument
+ * @param {Function} [errorCallback] function to be executed if
+ * there is an error, response is passed
+ * in as first argument
+ * @return {Object|Array} JSON data
+ * @example
+ *
+ *
Calling loadJSON() inside preload() guarantees to complete the
+ * operation before setup() and draw() are called.
+ *
+ *
+ * var weather;
+ * function preload() {
+ * var url = 'http://api.openweathermap.org/data/2.5/weather?q=London,UK'+
+ * '&APPID=7bbbb47522848e8b9c26ba35c226c734';
+ * weather = loadJSON(url);
+ * }
+ *
+ * function setup() {
+ * noLoop();
+ * }
+ *
+ * function draw() {
+ * background(200);
+ * // get the humidity value out of the loaded JSON
+ * var humidity = weather.main.humidity;
+ * fill(0, humidity); // use the humidity value to set the alpha
+ * ellipse(width/2, height/2, 50, 50);
+ * }
+ *
+ *
+ *
+ *
Outside of preload(), you may supply a callback function to handle the
+ * object:
+ *
+ * function setup() {
+ * noLoop();
+ * var url = 'http://api.openweathermap.org/data/2.5/weather?q=NewYork'+
+ * '&APPID=7bbbb47522848e8b9c26ba35c226c734';
+ * loadJSON(url, drawWeather);
+ * }
+ *
+ * function draw() {
+ * background(200);
+ * }
+ *
+ * function drawWeather(weather) {
+ * // get the humidity value out of the loaded JSON
+ * var humidity = weather.main.humidity;
+ * fill(0, humidity); // use the humidity value to set the alpha
+ * ellipse(width/2, height/2, 50, 50);
+ * }
+ *
+ *
+ * @alt
+ * 50x50 ellipse that changes from black to white depending on the current humidity
+ * 50x50 ellipse that changes from black to white depending on the current humidity
+ *
+ */
+p5.prototype.loadJSON = function () {
+ var path = arguments[0];
+ var callback;
+ var errorCallback;
+ var options;
+ var decrementPreload = p5._getDecrementPreload.apply(this, arguments);
+
+ var ret = {}; // object needed for preload
+ var t = 'json';
+
+ // check for explicit data type argument
+ for (var i = 1; i < arguments.length; i++) {
+ var arg = arguments[i];
+ if (typeof arg === 'string') {
+ if (arg === 'jsonp' || arg === 'json') {
+ t = arg;
+ }
+ } else if (typeof arg === 'function') {
+ if(!callback){
+ callback = arg;
+ }else{
+ errorCallback = arg;
+ }
+ } else if (typeof arg === 'object' && arg.hasOwnProperty('jsonpCallback')){
+ t = 'jsonp';
+ options = arg;
+ }
+ }
+
+ p5.prototype.httpDo(path, 'GET', options, t, function(resp){
+ for (var k in resp) {
+ ret[k] = resp[k];
+ }
+ if (typeof callback !== 'undefined') {
+ callback(resp);
+ }
+ if (decrementPreload && (callback !== decrementPreload)) {
+ decrementPreload();
+ }
+ }, errorCallback);
+
+ return ret;
+};
+
+/**
+ * Reads the contents of a file and creates a String array of its individual
+ * lines. If the name of the file is used as the parameter, as in the above
+ * example, the file must be located in the sketch directory/folder.
+ *
+ * Alternatively, the file maybe be loaded from anywhere on the local
+ * computer using an absolute path (something that starts with / on Unix and
+ * Linux, or a drive letter on Windows), or the filename parameter can be a
+ * URL for a file found on a network.
+ *
+ * This method is asynchronous, meaning it may not finish before the next
+ * line in your sketch is executed.
+ *
+ * @method loadStrings
+ * @param {String} filename name of the file or url to load
+ * @param {Function} [callback] function to be executed after loadStrings()
+ * completes, Array is passed in as first
+ * argument
+ * @param {Function} [errorCallback] function to be executed if
+ * there is an error, response is passed
+ * in as first argument
+ * @return {Array} Array of Strings
+ * @example
+ *
+ *
Calling loadStrings() inside preload() guarantees to complete the
+ * operation before setup() and draw() are called.
+ *
+ *
+ * var result;
+ * function preload() {
+ * result = loadStrings('assets/test.txt');
+ * }
+
+ * function setup() {
+ * background(200);
+ * var ind = floor(random(result.length));
+ * text(result[ind], 10, 10, 80, 80);
+ * }
+ *
+ *
+ *
Outside of preload(), you may supply a callback function to handle the
+ * object:
+ *
+ *
+ * function setup() {
+ * loadStrings('assets/test.txt', pickString);
+ * }
+ *
+ * function pickString(result) {
+ * background(200);
+ * var ind = floor(random(result.length));
+ * text(result[ind], 10, 10, 80, 80);
+ * }
+ *
+ *
+ * @alt
+ * randomly generated text from a file, for example "i smell like butter"
+ * randomly generated text from a file, for example "i have three feet"
+ *
+ */
+p5.prototype.loadStrings = function (path, callback, errorCallback) {
+ var ret = [];
+ var decrementPreload = p5._getDecrementPreload.apply(this, arguments);
+
+ p5.prototype.httpDo(path, 'GET', 'text', function(data){
+ var arr = data.match(/[^\r\n]+/g);
+ for (var k in arr) {
+ ret[k] = arr[k];
+ }
+
+ if (typeof callback !== 'undefined') {
+ callback(ret);
+ }
+ if (decrementPreload && (callback !== decrementPreload)) {
+ decrementPreload();
+ }
+ }, errorCallback);
+
+ return ret;
+};
+
+/**
+ *
Reads the contents of a file or URL and creates a p5.Table object with
+ * its values. If a file is specified, it must be located in the sketch's
+ * "data" folder. The filename parameter can also be a URL to a file found
+ * online. By default, the file is assumed to be comma-separated (in CSV
+ * format). Table only looks for a header row if the 'header' option is
+ * included.
+ *
+ *
Possible options include:
+ *
+ *
csv - parse the table as comma-separated values
+ *
tsv - parse the table as tab-separated values
+ *
header - this table has a header (title) row
+ *
+ *
+ *
+ *
When passing in multiple options, pass them in as separate parameters,
+ * seperated by commas. For example:
+ *
This method is asynchronous, meaning it may not finish before the next
+ * line in your sketch is executed. Calling loadTable() inside preload()
+ * guarantees to complete the operation before setup() and draw() are called.
+ *
Outside of preload(), you may supply a callback function to handle the
+ * object:
+ *
+ *
+ * @method loadTable
+ * @param {String} filename name of the file or URL to load
+ * @param {String} [options] "header" "csv" "tsv"
+ * @param {Function} [callback] function to be executed after
+ * loadTable() completes. On success, the
+ * Table object is passed in as the
+ * first argument.
+ * @param {Function} [errorCallback] function to be executed if
+ * there is an error, response is passed
+ * in as first argument
+ * @return {Object} Table object containing data
+ *
+ * @example
+ *
+ *
+ * // Given the following CSV file called "mammals.csv"
+ * // located in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * //the file can be remote
+ * //table = loadTable("http://p5js.org/reference/assets/mammals.csv",
+ * // "csv", "header");
+ * }
+ *
+ * function setup() {
+ * //count the columns
+ * print(table.getRowCount() + " total rows in table");
+ * print(table.getColumnCount() + " total columns in table");
+ *
+ * print(table.getColumn("name"));
+ * //["Goat", "Leopard", "Zebra"]
+ *
+ * //cycle through the table
+ * for (var r = 0; r < table.getRowCount(); r++)
+ * for (var c = 0; c < table.getColumnCount(); c++) {
+ * print(table.getString(r, c));
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * randomly generated text from a file, for example "i smell like butter"
+ * randomly generated text from a file, for example "i have three feet"
+ *
+ */
+p5.prototype.loadTable = function (path) {
+ var callback = null;
+ var errorCallback = null;
+ var options = [];
+ var header = false;
+ var sep = ',';
+ var separatorSet = false;
+ var decrementPreload = p5._getDecrementPreload.apply(this, arguments);
+
+ for (var i = 1; i < arguments.length; i++) {
+ if ((typeof (arguments[i]) === 'function') &&
+ (arguments[i] !== decrementPreload)) {
+ if(!callback){
+ callback = arguments[i];
+ }else{
+ errorCallback = arguments[i];
+ }
+ } else if (typeof (arguments[i]) === 'string') {
+ options.push(arguments[i]);
+ if (arguments[i] === 'header') {
+ header = true;
+ }
+ if (arguments[i] === 'csv') {
+ if (separatorSet) {
+ throw new Error('Cannot set multiple separator types.');
+ } else {
+ sep = ',';
+ separatorSet = true;
+ }
+ } else if (arguments[i] === 'tsv') {
+ if (separatorSet) {
+ throw new Error('Cannot set multiple separator types.');
+ } else {
+ sep = '\t';
+ separatorSet = true;
+ }
+ }
+ }
+ }
+
+ var t = new p5.Table();
+
+ p5.prototype.httpDo(path, 'GET', 'text', function(resp){
+ var state = {};
+
+ // define constants
+ var PRE_TOKEN = 0,
+ MID_TOKEN = 1,
+ POST_TOKEN = 2,
+ POST_RECORD = 4;
+
+ var QUOTE = '\"',
+ CR = '\r',
+ LF = '\n';
+
+ var records = [];
+ var offset = 0;
+ var currentRecord = null;
+ var currentChar;
+
+ var tokenBegin = function () {
+ state.currentState = PRE_TOKEN;
+ state.token = '';
+ };
+
+ var tokenEnd = function () {
+ currentRecord.push(state.token);
+ tokenBegin();
+ };
+
+ var recordBegin = function () {
+ state.escaped = false;
+ currentRecord = [];
+ tokenBegin();
+ };
+
+ var recordEnd = function () {
+ state.currentState = POST_RECORD;
+ records.push(currentRecord);
+ currentRecord = null;
+ };
+
+ while (true) {
+ currentChar = resp[offset++];
+
+ // EOF
+ if (currentChar == null) {
+ if (state.escaped) {
+ throw new Error('Unclosed quote in file.');
+ }
+ if (currentRecord) {
+ tokenEnd();
+ recordEnd();
+ break;
+ }
+ }
+ if (currentRecord === null) {
+ recordBegin();
+ }
+
+ // Handle opening quote
+ if (state.currentState === PRE_TOKEN) {
+ if (currentChar === QUOTE) {
+ state.escaped = true;
+ state.currentState = MID_TOKEN;
+ continue;
+ }
+ state.currentState = MID_TOKEN;
+ }
+
+ // mid-token and escaped, look for sequences and end quote
+ if (state.currentState === MID_TOKEN && state.escaped) {
+ if (currentChar === QUOTE) {
+ if (resp[offset] === QUOTE) {
+ state.token += QUOTE;
+ offset++;
+ } else {
+ state.escaped = false;
+ state.currentState = POST_TOKEN;
+ }
+ } else {
+ state.token += currentChar;
+ }
+ continue;
+ }
+
+ // fall-through: mid-token or post-token, not escaped
+ if (currentChar === CR) {
+ if (resp[offset] === LF) {
+ offset++;
+ }
+ tokenEnd();
+ recordEnd();
+ } else if (currentChar === LF) {
+ tokenEnd();
+ recordEnd();
+ } else if (currentChar === sep) {
+ tokenEnd();
+ } else if (state.currentState === MID_TOKEN) {
+ state.token += currentChar;
+ }
+ }
+
+ // set up column names
+ if (header) {
+ t.columns = records.shift();
+ } else {
+ for (i = 0; i < records[0].length; i++) {
+ t.columns[i] = 'null';
+ }
+ }
+ var row;
+ for (i = 0; i < records.length; i++) {
+ //Handles row of 'undefined' at end of some CSVs
+ if (i === records.length - 1 && records[i].length === 1) {
+ if (records[i][0] === 'undefined') {
+ break;
+ }
+ }
+ row = new p5.TableRow();
+ row.arr = records[i];
+ row.obj = makeObject(records[i], t.columns);
+ t.addRow(row);
+ }
+ if (callback !== null) {
+ callback(t);
+ }
+ if (decrementPreload && (callback !== decrementPreload)) {
+ decrementPreload();
+ }
+
+ }, function(err){
+ // Error handling
+ p5._friendlyFileLoadError(2, path);
+
+ if(errorCallback){
+ errorCallback(err.status + ' ' + err.statusText);
+ }else{
+ console.log(err.status + ' ' + err.statusText);
+ }
+ });
+
+ return t;
+};
+
+// helper function to turn a row into a JSON object
+function makeObject(row, headers) {
+ var ret = {};
+ headers = headers || [];
+ if (typeof (headers) === 'undefined') {
+ for (var j = 0; j < row.length; j++) {
+ headers[j.toString()] = j;
+ }
+ }
+ for (var i = 0; i < headers.length; i++) {
+ var key = headers[i];
+ var val = row[i];
+ ret[key] = val;
+ }
+ return ret;
+}
+
+/*global parseXML */
+p5.prototype.parseXML = function (two) {
+ var one = new p5.XML();
+ var i;
+ if (two.children.length) {
+ for ( i = 0; i < two.children.length; i++ ) {
+ var node = parseXML(two.children[i]);
+ one.addChild(node);
+ }
+ one.setName(two.nodeName);
+ one._setCont(two.textContent);
+ one._setAttributes(two);
+ for (var j = 0; j < one.children.length; j++) {
+ one.children[j].parent = one;
+ }
+ return one;
+ }
+ else {
+ one.setName(two.nodeName);
+ one._setCont(two.textContent);
+ one._setAttributes(two);
+ return one;
+ }
+};
+
+/**
+ * Reads the contents of a file and creates an XML object with its values.
+ * If the name of the file is used as the parameter, as in the above example,
+ * the file must be located in the sketch directory/folder.
+ *
+ * Alternatively, the file maybe be loaded from anywhere on the local
+ * computer using an absolute path (something that starts with / on Unix and
+ * Linux, or a drive letter on Windows), or the filename parameter can be a
+ * URL for a file found on a network.
+ *
+ * This method is asynchronous, meaning it may not finish before the next
+ * line in your sketch is executed. Calling loadXML() inside preload()
+ * guarantees to complete the operation before setup() and draw() are called.
+ *
+ *
Outside of preload(), you may supply a callback function to handle the
+ * object:
+ *
+ * @method loadXML
+ * @param {String} filename name of the file or URL to load
+ * @param {Function} [callback] function to be executed after loadXML()
+ * completes, XML object is passed in as
+ * first argument
+ * @param {Function} [errorCallback] function to be executed if
+ * there is an error, response is passed
+ * in as first argument
+ * @return {Object} XML object containing data
+ */
+p5.prototype.loadXML = function (path, callback, errorCallback) {
+ var ret = {};
+ var decrementPreload = p5._getDecrementPreload.apply(this, arguments);
+
+ p5.prototype.httpDo(path, 'GET', 'xml', function(xml){
+ for(var key in xml) {
+ ret[key] = xml[key];
+ }
+ if (typeof callback !== 'undefined') {
+ callback(ret);
+ }
+ if (decrementPreload && (callback !== decrementPreload)) {
+ decrementPreload();
+ }
+ }, errorCallback);
+
+ return ret;
+};
+
+// name clash with window.open
+// p5.prototype.open = function() {
+// // TODO
+
+// };
+
+p5.prototype.selectFolder = function () {
+ // TODO
+ throw 'not yet implemented';
+
+};
+
+p5.prototype.selectInput = function () {
+ // TODO
+ throw 'not yet implemented';
+
+};
+
+/**
+ * Method for executing an HTTP GET request. If data type is not specified,
+ * p5 will try to guess based on the URL, defaulting to text. This is equivalent to
+ * calling httpDo(path, 'GET').
+ *
+ * @method httpGet
+ * @param {String} path name of the file or url to load
+ * @param {String} [datatype] "json", "jsonp", "xml", or "text"
+ * @param {Object} [data] param data passed sent with request
+ * @param {Function} [callback] function to be executed after
+ * httpGet() completes, data is passed in
+ * as first argument
+ * @param {Function} [errorCallback] function to be executed if
+ * there is an error, response is passed
+ * in as first argument
+ */
+p5.prototype.httpGet = function () {
+ var args = new Array(arguments.length);
+ args[0] = arguments[0];
+ args[1] = 'GET';
+ for (var i = 2; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ p5.prototype.httpDo.apply(this, args);
+};
+
+/**
+ * Method for executing an HTTP POST request. If data type is not specified,
+ * p5 will try to guess based on the URL, defaulting to text. This is equivalent to
+ * calling httpDo(path, 'POST').
+ *
+ * @method httpPost
+ * @param {String} path name of the file or url to load
+ * @param {String} [datatype] "json", "jsonp", "xml", or "text"
+ * @param {Object} [data] param data passed sent with request
+ * @param {Function} [callback] function to be executed after
+ * httpGet() completes, data is passed in
+ * as first argument
+ * @param {Function} [errorCallback] function to be executed if
+ * there is an error, response is passed
+ * in as first argument
+ */
+p5.prototype.httpPost = function () {
+ var args = new Array(arguments.length);
+ args[0] = arguments[0];
+ args[1] = 'POST';
+ for (var i = 2; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ p5.prototype.httpDo.apply(this, args);
+};
+
+/**
+ * Method for executing an HTTP request. If data type is not specified,
+ * p5 will try to guess based on the URL, defaulting to text.
+ * For more advanced use, you may also pass in the path as the first argument
+ * and a object as the second argument, the signature follows the one specified
+ * in the Fetch API specification.
+ *
+ * @method httpDo
+ * @param {String} path name of the file or url to load
+ * @param {String} [method] either "GET", "POST", or "PUT",
+ * defaults to "GET"
+ * @param {String} [datatype] "json", "jsonp", "xml", or "text"
+ * @param {Object} [data] param data passed sent with request
+ * @param {Function} [callback] function to be executed after
+ * httpGet() completes, data is passed in
+ * as first argument
+ * @param {Function} [errorCallback] function to be executed if
+ * there is an error, response is passed
+ * in as first argument
+ */
+
+/**
+ * @method httpDo
+ * @param {String} path
+ * @param {Object} options Request object options as documented in the
+ * "fetch" API
+ * reference
+ * @param {Function} [callback]
+ * @param {Function} [errorCallback]
+ */
+p5.prototype.httpDo = function () {
+ var type = '';
+ var callback;
+ var errorCallback;
+ var request;
+ var jsonpOptions = {};
+ var cbCount = 0;
+ // Trim the callbacks off the end to get an idea of how many arguments are passed
+ for (var i = arguments.length-1; i > 0; i--){
+ if(typeof arguments[i] === 'function'){
+ cbCount++;
+ }else{
+ break;
+ }
+ }
+ // The number of arguments minus callbacks
+ var argsCount = arguments.length - cbCount;
+ if(argsCount === 2 &&
+ typeof arguments[0] === 'string' &&
+ typeof arguments[1] === 'object'){
+ // Intended for more advanced use, pass in Request parameters directly
+ request = new Request(arguments[0], arguments[1]);
+ callback = arguments[2];
+ errorCallback = arguments[3];
+
+ // do some sort of smart type checking
+ if (type === '') {
+ if (request.url.indexOf('json') !== -1) {
+ type = 'json';
+ } else if (request.url.indexOf('xml') !== -1) {
+ type = 'xml';
+ } else {
+ type = 'text';
+ }
+ }
+ }else{
+ // Provided with arguments
+ var path = arguments[0];
+ var method = 'GET';
+ var data;
+
+ for (var j = 1; j < arguments.length; j++) {
+ var a = arguments[j];
+ if (typeof a === 'string') {
+ if (a === 'GET' || a === 'POST' || a === 'PUT' || a === 'DELETE') {
+ method = a;
+ } else if(a === 'json' || a === 'jsonp' || a === 'xml' || a === 'text') {
+ type = a;
+ } else {
+ data = a;
+ }
+ } else if (typeof a === 'object') {
+ if(a.hasOwnProperty('jsonpCallback')){
+ for (var attr in a) {
+ jsonpOptions[attr] = a[attr];
+ }
+ }else{
+ data = JSON.stringify(a);
+ }
+ } else if (typeof a === 'function') {
+ if (!callback) {
+ callback = a;
+ } else {
+ errorCallback = a;
+ }
+ }
+ }
+ // do some sort of smart type checking
+ if (type === '') {
+ if (path.indexOf('json') !== -1) {
+ type = 'json';
+ } else if (path.indexOf('xml') !== -1) {
+ type = 'xml';
+ } else {
+ type = 'text';
+ }
+ }
+
+ request = new Request(path, {
+ method: method,
+ mode: 'cors',
+ body: data
+ });
+ }
+
+ if(type === 'jsonp'){
+ fetchJsonp(arguments[0], jsonpOptions)
+ .then(function(res){
+ if(res.ok){
+ return res.json();
+ }
+ throw res;
+ }).then(function(resp){
+ callback(resp);
+ }).catch(function(err){
+ if (errorCallback) {
+ errorCallback(err);
+ } else {
+ console.log(err.status + ' ' + err.statusText);
+ }
+ });
+ }else{
+ fetch(request)
+ .then(function(res){
+ if(res.ok){
+ if(type === 'json'){
+ return res.json();
+ }else{
+ return res.text();
+ }
+ }
+
+ throw res;
+ })
+ .then(function(resp){
+ if (type === 'xml'){
+ var parser = new DOMParser();
+ resp = parser.parseFromString(resp, 'text/xml');
+ resp = parseXML(resp.documentElement);
+ }
+ callback(resp);
+ }).catch(function(err, msg){
+ if (errorCallback) {
+ errorCallback(err);
+ } else {
+ console.log(err.status + ' ' + err.statusText);
+ }
+ });
+ }
+};
+
+/**
+ * @module IO
+ * @submodule Output
+ * @for p5
+ */
+
+window.URL = window.URL || window.webkitURL;
+
+// private array of p5.PrintWriter objects
+p5.prototype._pWriters = [];
+
+p5.prototype.beginRaw = function () {
+ // TODO
+ throw 'not yet implemented';
+
+};
+
+p5.prototype.beginRecord = function () {
+ // TODO
+ throw 'not yet implemented';
+
+};
+
+p5.prototype.createOutput = function () {
+ // TODO
+
+ throw 'not yet implemented';
+};
+
+p5.prototype.createWriter = function (name, extension) {
+ var newPW;
+ // check that it doesn't already exist
+ for (var i in p5.prototype._pWriters) {
+ if (p5.prototype._pWriters[i].name === name) {
+ // if a p5.PrintWriter w/ this name already exists...
+ // return p5.prototype._pWriters[i]; // return it w/ contents intact.
+ // or, could return a new, empty one with a unique name:
+ newPW = new p5.PrintWriter(name + window.millis(), extension);
+ p5.prototype._pWriters.push(newPW);
+ return newPW;
+ }
+ }
+ newPW = new p5.PrintWriter(name, extension);
+ p5.prototype._pWriters.push(newPW);
+ return newPW;
+};
+
+p5.prototype.endRaw = function () {
+ // TODO
+
+ throw 'not yet implemented';
+};
+
+p5.prototype.endRecord = function () {
+ // TODO
+ throw 'not yet implemented';
+
+};
+
+p5.PrintWriter = function (filename, extension) {
+ var self = this;
+ this.name = filename;
+ this.content = '';
+ this.print = function (data) {
+ this.content += data;
+ };
+ this.print = function (data) {
+ this.content += data + '\n';
+ };
+ this.flush = function () {
+ this.content = '';
+ };
+ this.close = function () {
+ // convert String to Array for the writeFile Blob
+ var arr = [];
+ arr.push(this.content);
+ p5.prototype.writeFile(arr, filename, extension);
+ // remove from _pWriters array and delete self
+ for (var i in p5.prototype._pWriters) {
+ if (p5.prototype._pWriters[i].name === this.name) {
+ // remove from _pWriters array
+ p5.prototype._pWriters.splice(i, 1);
+ }
+ }
+ self.flush();
+ self = {};
+ };
+};
+
+p5.prototype.saveBytes = function () {
+ // TODO
+ throw 'not yet implemented';
+
+};
+
+// object, filename, options --> saveJSON, saveStrings, saveTable
+// filename, [extension] [canvas] --> saveImage
+
+/**
+ *
Save an image, text, json, csv, wav, or html. Prompts download to
+ * the client's computer. Note that it is not recommended to call save()
+ * within draw if it's looping, as the save() function will open a new save
+ * dialog every frame.
+ *
The default behavior is to save the canvas as an image. You can
+ * optionally specify a filename.
+ * For example:
+ *
+ * save();
+ * save('myCanvas.jpg'); // save a specific canvas with a filename
+ *
+ *
+ *
Alternately, the first parameter can be a pointer to a canvas
+ * p5.Element, an Array of Strings,
+ * an Array of JSON, a JSON object, a p5.Table, a p5.Image, or a
+ * p5.SoundFile (requires p5.sound). The second parameter is a filename
+ * (including extension). The third parameter is for options specific
+ * to this type of object. This method will save a file that fits the
+ * given paramaters. For example:
+ *
+ *
+ *
+ * save('myCanvas.jpg'); // Saves canvas as an image
+ *
+ * var cnv = createCanvas(100, 100);
+ * save(cnv, 'myCanvas.jpg'); // Saves canvas as an image
+ *
+ * var gb = createGraphics(100, 100);
+ * save(gb, 'myGraphics.jpg'); // Saves p5.Renderer object as an image
+ *
+ * save(myTable, 'myTable.html'); // Saves table as html file
+ * save(myTable, 'myTable.csv',); // Comma Separated Values
+ * save(myTable, 'myTable.tsv'); // Tab Separated Values
+ *
+ * save(myJSON, 'my.json'); // Saves pretty JSON
+ * save(myJSON, 'my.json', true); // Optimizes JSON filesize
+ *
+ * save(img, 'my.png'); // Saves pImage as a png image
+ *
+ * save(arrayOfStrings, 'my.txt'); // Saves strings to a text file with line
+ * // breaks after each item in the array
+ *
+ *
+ * @method save
+ * @param {Object|String} [objectOrFilename] If filename is provided, will
+ * save canvas as an image with
+ * either png or jpg extension
+ * depending on the filename.
+ * If object is provided, will
+ * save depending on the object
+ * and filename (see examples
+ * above).
+ * @param {String} [filename] If an object is provided as the first
+ * parameter, then the second parameter
+ * indicates the filename,
+ * and should include an appropriate
+ * file extension (see examples above).
+ * @param {Boolean|String} [options] Additional options depend on
+ * filetype. For example, when saving JSON,
+ * true indicates that the
+ * output will be optimized for filesize,
+ * rather than readability.
+ */
+p5.prototype.save = function (object, _filename, _options) {
+ // parse the arguments and figure out which things we are saving
+ var args = arguments;
+ // =================================================
+ // OPTION 1: saveCanvas...
+
+ // if no arguments are provided, save canvas
+ var cnv = this._curElement.elt;
+ if (args.length === 0) {
+ p5.prototype.saveCanvas(cnv);
+ return;
+ }
+ // otherwise, parse the arguments
+
+ // if first param is a p5Graphics, then saveCanvas
+ else if (args[0] instanceof p5.Renderer ||
+ args[0] instanceof p5.Graphics) {
+ p5.prototype.saveCanvas(args[0].elt, args[1], args[2]);
+ return;
+ }
+
+ // if 1st param is String and only one arg, assume it is canvas filename
+ else if (args.length === 1 && typeof (args[0]) === 'string') {
+ p5.prototype.saveCanvas(cnv, args[0]);
+ }
+
+ // =================================================
+ // OPTION 2: extension clarifies saveStrings vs. saveJSON
+ else {
+ var extension = _checkFileExtension(args[1], args[2])[1];
+ switch (extension) {
+ case 'json':
+ p5.prototype.saveJSON(args[0], args[1], args[2]);
+ return;
+ case 'txt':
+ p5.prototype.saveStrings(args[0], args[1], args[2]);
+ return;
+ // =================================================
+ // OPTION 3: decide based on object...
+ default:
+ if (args[0] instanceof Array) {
+ p5.prototype.saveStrings(args[0], args[1], args[2]);
+ } else if (args[0] instanceof p5.Table) {
+ p5.prototype.saveTable(args[0], args[1], args[2], args[3]);
+ } else if (args[0] instanceof p5.Image) {
+ p5.prototype.saveCanvas(args[0].canvas, args[1]);
+ } else if (args[0] instanceof p5.SoundFile) {
+ p5.prototype.saveSound(args[0], args[1], args[2], args[3]);
+ }
+ }
+ }
+};
+
+/**
+ * Writes the contents of an Array or a JSON object to a .json file.
+ * The file saving process and location of the saved file will
+ * vary between web browsers.
+ *
+ * @method saveJSON
+ * @param {Array|Object} json
+ * @param {String} filename
+ * @param {Boolean} [optimize] If true, removes line breaks
+ * and spaces from the output
+ * file to optimize filesize
+ * (but not readability).
+ * @example
+ *
+ * var json;
+ *
+ * function setup() {
+ *
+ * json = {}; // new JSON Object
+ *
+ * json.id = 0;
+ * json.species = 'Panthera leo';
+ * json.name = 'Lion';
+ *
+ * // To save, un-comment the line below, then click 'run'
+ * // saveJSON(json, 'lion.json');
+ * }
+ *
+ * // Saves the following to a file called "lion.json":
+ * // {
+ * // "id": 0,
+ * // "species": "Panthera leo",
+ * // "name": "Lion"
+ * // }
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.prototype.saveJSON = function (json, filename, opt) {
+ var stringify;
+ if (opt) {
+ stringify = JSON.stringify(json);
+ } else {
+ stringify = JSON.stringify(json, undefined, 2);
+ }
+ console.log(stringify);
+ this.saveStrings(stringify.split('\n'), filename, 'json');
+};
+
+p5.prototype.saveJSONObject = p5.prototype.saveJSON;
+p5.prototype.saveJSONArray = p5.prototype.saveJSON;
+
+p5.prototype.saveStream = function () {
+ // TODO
+ throw 'not yet implemented';
+
+};
+
+/**
+ * Writes an array of Strings to a text file, one line per String.
+ * The file saving process and location of the saved file will
+ * vary between web browsers.
+ *
+ * @method saveStrings
+ * @param {Array} list string array to be written
+ * @param {String} filename filename for output
+ * @example
+ *
+ * var words = 'apple bear cat dog';
+ *
+ * // .split() outputs an Array
+ * var list = split(words, ' ');
+ *
+ * // To save the file, un-comment next line and click 'run'
+ * // saveStrings(list, 'nouns.txt');
+ *
+ * // Saves the following to a file called 'nouns.txt':
+ * //
+ * // apple
+ * // bear
+ * // cat
+ * // dog
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.prototype.saveStrings = function (list, filename, extension) {
+ var ext = extension || 'txt';
+ var pWriter = this.createWriter(filename, ext);
+ for (var i = 0; i < list.length; i++) {
+ if (i < list.length - 1) {
+ pWriter.print(list[i]);
+ } else {
+ pWriter.print(list[i]);
+ }
+ }
+ pWriter.close();
+ pWriter.flush();
+};
+
+p5.prototype.saveXML = function () {
+ // TODO
+ throw 'not yet implemented';
+
+};
+
+p5.prototype.selectOutput = function () {
+ // TODO
+ throw 'not yet implemented';
+
+};
+
+// =======
+// HELPERS
+// =======
+
+function escapeHelper(content) {
+ return content
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+}
+
+/**
+ * Writes the contents of a Table object to a file. Defaults to a
+ * text file with comma-separated-values ('csv') but can also
+ * use tab separation ('tsv'), or generate an HTML table ('html').
+ * The file saving process and location of the saved file will
+ * vary between web browsers.
+ *
+ * @method saveTable
+ * @param {p5.Table} Table the Table object to save to a file
+ * @param {String} filename the filename to which the Table should be saved
+ * @param {String} [options] can be one of "tsv", "csv", or "html"
+ * @example
+ *
+ * var table;
+ *
+ * function setup() {
+ * table = new p5.Table();
+ *
+ * table.addColumn('id');
+ * table.addColumn('species');
+ * table.addColumn('name');
+ *
+ * var newRow = table.addRow();
+ * newRow.setNum('id', table.getRowCount() - 1);
+ * newRow.setString('species', 'Panthera leo');
+ * newRow.setString('name', 'Lion');
+ *
+ * // To save, un-comment next line then click 'run'
+ * // saveTable(table, 'new.csv');
+ * }
+ *
+ * // Saves the following to a file called 'new.csv':
+ * // id,species,name
+ * // 0,Panthera leo,Lion
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.prototype.saveTable = function (table, filename, options) {
+ var pWriter = this.createWriter(filename, options);
+
+ var header = table.columns;
+
+ var sep = ','; // default to CSV
+ if (options === 'tsv') {
+ sep = '\t';
+ }
+ if (options !== 'html') {
+ // make header if it has values
+ if (header[0] !== '0') {
+ for (var h = 0; h < header.length; h++) {
+ if (h < header.length - 1) {
+ pWriter.print(header[h] + sep);
+ } else {
+ pWriter.print(header[h]);
+ }
+ }
+ }
+
+ // make rows
+ for (var i = 0; i < table.rows.length; i++) {
+ var j;
+ for (j = 0; j < table.rows[i].arr.length; j++) {
+ if (j < table.rows[i].arr.length - 1) {
+ pWriter.print(table.rows[i].arr[j] + sep);
+ } else if (i < table.rows.length - 1) {
+ pWriter.print(table.rows[i].arr[j]);
+ } else {
+ pWriter.print(table.rows[i].arr[j]); // no line break
+ }
+ }
+ }
+ }
+
+ // otherwise, make HTML
+ else {
+ pWriter.print('');
+ pWriter.print('');
+ var str = ' ';
+ pWriter.print(str);
+ pWriter.print('');
+
+ pWriter.print('');
+ pWriter.print('
');
+
+ // make header if it has values
+ if (header[0] !== '0') {
+ pWriter.print('
');
+ for (var k = 0; k < header.length; k++) {
+ var e = escapeHelper(header[k]);
+ pWriter.print('
');
+ for (var col = 0; col < table.columns.length; col++) {
+ var entry = table.rows[row].getString(col);
+ var htmlEntry = escapeHelper(entry);
+ pWriter.print('
' + htmlEntry);
+ pWriter.print('
');
+ }
+ pWriter.print('
');
+ }
+ pWriter.print('
');
+ pWriter.print('');
+ pWriter.print('');
+ }
+ // close and flush the pWriter
+ pWriter.close();
+ pWriter.flush();
+}; // end saveTable()
+
+/**
+ * Generate a blob of file data as a url to prepare for download.
+ * Accepts an array of data, a filename, and an extension (optional).
+ * This is a private function because it does not do any formatting,
+ * but it is used by saveStrings, saveJSON, saveTable etc.
+ *
+ * @param {Array} dataToDownload
+ * @param {String} filename
+ * @param {[String]} extension
+ * @private
+ */
+p5.prototype.writeFile = function (dataToDownload, filename, extension) {
+ var type = 'application\/octet-stream';
+ if (p5.prototype._isSafari()) {
+ type = 'text\/plain';
+ }
+ var blob = new Blob(dataToDownload, {
+ 'type': type
+ });
+ var href = window.URL.createObjectURL(blob);
+ p5.prototype.downloadFile(href, filename, extension);
+};
+
+/**
+ * Forces download. Accepts a url to filedata/blob, a filename,
+ * and an extension (optional).
+ * This is a private function because it does not do any formatting,
+ * but it is used by saveStrings, saveJSON, saveTable etc.
+ *
+ * @param {String} href i.e. an href generated by createObjectURL
+ * @param {[String]} filename
+ * @param {[String]} extension
+ */
+p5.prototype.downloadFile = function (href, fName, extension) {
+ var fx = _checkFileExtension(fName, extension);
+ var filename = fx[0];
+ var ext = fx[1];
+
+ var a = document.createElement('a');
+ a.href = href;
+ a.download = filename;
+
+ // Firefox requires the link to be added to the DOM before click()
+ a.onclick = function(e) {
+ destroyClickedElement(e);
+ e.stopPropagation();
+ };
+
+ a.style.display = 'none';
+ document.body.appendChild(a);
+
+ // Safari will open this file in the same page as a confusing Blob.
+ if (p5.prototype._isSafari()) {
+ var aText = 'Hello, Safari user! To download this file...\n';
+ aText += '1. Go to File --> Save As.\n';
+ aText += '2. Choose "Page Source" as the Format.\n';
+ aText += '3. Name it with this extension: .\"' + ext + '\"';
+ alert(aText);
+ }
+ a.click();
+ href = null;
+};
+
+/**
+ * Returns a file extension, or another string
+ * if the provided parameter has no extension.
+ *
+ * @param {String} filename
+ * @return {Array} [fileName, fileExtension]
+ *
+ * @private
+ */
+function _checkFileExtension(filename, extension) {
+ if (!extension || extension === true || extension === 'true') {
+ extension = '';
+ }
+ if (!filename) {
+ filename = 'untitled';
+ }
+ var ext = '';
+ // make sure the file will have a name, see if filename needs extension
+ if (filename && filename.indexOf('.') > -1) {
+ ext = filename.split('.').pop();
+ }
+ // append extension if it doesn't exist
+ if (extension) {
+ if (ext !== extension) {
+ ext = extension;
+ filename = filename + '.' + ext;
+ }
+ }
+ return [filename, ext];
+}
+p5.prototype._checkFileExtension = _checkFileExtension;
+
+/**
+ * Returns true if the browser is Safari, false if not.
+ * Safari makes trouble for downloading files.
+ *
+ * @return {Boolean} [description]
+ * @private
+ */
+p5.prototype._isSafari = function () {
+ var x = Object.prototype.toString.call(window.HTMLElement);
+ return x.indexOf('Constructor') > 0;
+};
+
+/**
+ * Helper function, a callback for download that deletes
+ * an invisible anchor element from the DOM once the file
+ * has been automatically downloaded.
+ *
+ * @private
+ */
+function destroyClickedElement(event) {
+ document.body.removeChild(event.target);
+}
+
+module.exports = p5;
+
+},{"../core/core":42,"../core/error_helpers":45,"es6-promise":2,"fetch-jsonp":3,"opentype.js":10,"whatwg-fetch":32}],65:[function(_dereq_,module,exports){
+/**
+ * @module IO
+ * @submodule Table
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+
+/**
+ * Table Options
+ *
Generic class for handling tabular data, typically from a
+ * CSV, TSV, or other sort of spreadsheet file.
+ *
CSV files are
+ *
+ * comma separated values, often with the data in quotes. TSV
+ * files use tabs as separators, and usually don't bother with the
+ * quotes.
+ *
File names should end with .csv if they're comma separated.
To save tables to your computer, use the save method
+ * or the saveTable method.
+ *
+ * Possible options include:
+ *
+ *
csv - parse the table as comma-separated values
+ *
tsv - parse the table as tab-separated values
+ *
header - this table has a header (title) row
+ *
+ */
+
+/**
+ * Table objects store data with multiple rows and columns, much
+ * like in a traditional spreadsheet. Tables can be generated from
+ * scratch, dynamically, or using data from an existing file.
+ *
+ * @class p5.Table
+ * @constructor
+ * @param {Array} [rows] An array of p5.TableRow objects
+ * @return {p5.Table} p5.Table generated
+ */
+p5.Table = function (rows) {
+ /**
+ * @property columns
+ * @type {Array}
+ */
+ this.columns = [];
+
+ /**
+ * @property rows
+ * @type {Array}
+ */
+ this.rows = [];
+};
+
+/**
+ * Use addRow() to add a new row of data to a p5.Table object. By default,
+ * an empty row is created. Typically, you would store a reference to
+ * the new row in a TableRow object (see newRow in the example above),
+ * and then set individual values using set().
+ *
+ * If a p5.TableRow object is included as a parameter, then that row is
+ * duplicated and added to the table.
+ *
+ * @method addRow
+ * @param {p5.TableRow} [row] row to be added to the table
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * //add a row
+ * var newRow = table.addRow();
+ * newRow.setString("id", table.getRowCount() - 1);
+ * newRow.setString("species", "Canis Lupus");
+ * newRow.setString("name", "Wolf");
+ *
+ * //print the results
+ * for (var r = 0; r < table.getRowCount(); r++)
+ * for (var c = 0; c < table.getColumnCount(); c++)
+ * print(table.getString(r, c));
+ * }
+ *
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.addRow = function(row) {
+ // make sure it is a valid TableRow
+ var r = row || new p5.TableRow();
+
+ if (typeof(r.arr) === 'undefined' || typeof(r.obj) === 'undefined') {
+ //r = new p5.prototype.TableRow(r);
+ throw 'invalid TableRow: ' + r;
+ }
+ r.table = this;
+ this.rows.push(r);
+ return r;
+};
+
+/**
+ * Removes a row from the table object.
+ *
+ * @method removeRow
+ * @param {Number} id ID number of the row to remove
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * //remove the first row
+ * var r = table.removeRow(0);
+ *
+ * //print the results
+ * for (var r = 0; r < table.getRowCount(); r++)
+ * for (var c = 0; c < table.getColumnCount(); c++)
+ * print(table.getString(r, c));
+ * }
+ *
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.removeRow = function(id) {
+ this.rows[id].table = null; // remove reference to table
+ var chunk = this.rows.splice(id+1, this.rows.length);
+ this.rows.pop();
+ this.rows = this.rows.concat(chunk);
+};
+
+
+/**
+ * Returns a reference to the specified p5.TableRow. The reference
+ * can then be used to get and set values of the selected row.
+ *
+ * @method getRow
+ * @param {Number} rowID ID number of the row to get
+ * @return {TableRow} p5.TableRow object
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * var row = table.getRow(1);
+ * //print it column by column
+ * //note: a row is an object, not an array
+ * for (var c = 0; c < table.getColumnCount(); c++)
+ * print(row.getString(c));
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.getRow = function(r) {
+ return this.rows[r];
+};
+
+/**
+ * Gets all rows from the table. Returns an array of p5.TableRows.
+ *
+ * @method getRows
+ * @return {Array} Array of p5.TableRows
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * var rows = table.getRows();
+ *
+ * //warning: rows is an array of objects
+ * for (var r = 0; r < rows.length; r++)
+ * rows[r].set("name", "Unicorn");
+ *
+ * //print the results
+ * for (var r = 0; r < table.getRowCount(); r++)
+ * for (var c = 0; c < table.getColumnCount(); c++)
+ * print(table.getString(r, c));
+ * }
+ *
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.getRows = function() {
+ return this.rows;
+};
+
+/**
+ * Finds the first row in the Table that contains the value
+ * provided, and returns a reference to that row. Even if
+ * multiple rows are possible matches, only the first matching
+ * row is returned. The column to search may be specified by
+ * either its ID or title.
+ *
+ * @method findRow
+ * @param {String} value The value to match
+ * @param {Number|String} column ID number or title of the
+ * column to search
+ * @return {TableRow}
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * //find the animal named zebra
+ * var row = table.findRow("Zebra", "name");
+ * //find the corresponding species
+ * print(row.getString("species"));
+ * }
+ *
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.findRow = function(value, column) {
+ // try the Object
+ if (typeof(column) === 'string') {
+ for (var i = 0; i < this.rows.length; i++){
+ if (this.rows[i].obj[column] === value) {
+ return this.rows[i];
+ }
+ }
+ }
+ // try the Array
+ else {
+ for (var j = 0; j < this.rows.length; j++){
+ if (this.rows[j].arr[column] === value) {
+ return this.rows[j];
+ }
+ }
+ }
+ // otherwise...
+ return null;
+};
+
+/**
+ * Finds the rows in the Table that contain the value
+ * provided, and returns references to those rows. Returns an
+ * Array, so for must be used to iterate through all the rows,
+ * as shown in the example above. The column to search may be
+ * specified by either its ID or title.
+ *
+ * @method findRows
+ * @param {String} value The value to match
+ * @param {Number|String} column ID number or title of the
+ * column to search
+ * @return {Array} An Array of TableRow objects
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * //add another goat
+ * var newRow = table.addRow();
+ * newRow.setString("id", table.getRowCount() - 1);
+ * newRow.setString("species", "Scape Goat");
+ * newRow.setString("name", "Goat");
+ *
+ * //find the rows containing animals named Goat
+ * var rows = table.findRows("Goat", "name");
+ * print(rows.length + " Goats found");
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.findRows = function(value, column) {
+ var ret = [];
+ if (typeof(column) === 'string') {
+ for (var i = 0; i < this.rows.length; i++){
+ if (this.rows[i].obj[column] === value) {
+ ret.push( this.rows[i] );
+ }
+ }
+ }
+ // try the Array
+ else {
+ for (var j = 0; j < this.rows.length; j++){
+ if (this.rows[j].arr[column] === value) {
+ ret.push( this.rows[j] );
+ }
+ }
+ }
+ return ret;
+};
+
+/**
+ * Finds the first row in the Table that matches the regular
+ * expression provided, and returns a reference to that row.
+ * Even if multiple rows are possible matches, only the first
+ * matching row is returned. The column to search may be
+ * specified by either its ID or title.
+ *
+ * @method matchRow
+ * @param {String} regexp The regular expression to match
+ * @param {String|Number} column The column ID (number) or
+ * title (string)
+ * @return {TableRow} TableRow object
+ */
+p5.Table.prototype.matchRow = function(regexp, column) {
+ if (typeof(column) === 'number') {
+ for (var j = 0; j < this.rows.length; j++) {
+ if ( this.rows[j].arr[column].match(regexp) ) {
+ return this.rows[j];
+ }
+ }
+ }
+
+ else {
+ for (var i = 0; i < this.rows.length; i++) {
+ if ( this.rows[i].obj[column].match(regexp) ) {
+ return this.rows[i];
+ }
+ }
+ }
+ return null;
+};
+
+/**
+ * Finds the rows in the Table that match the regular expression provided,
+ * and returns references to those rows. Returns an array, so for must be
+ * used to iterate through all the rows, as shown in the example. The
+ * column to search may be specified by either its ID or title.
+ *
+ * @method matchRows
+ * @param {String} regexp The regular expression to match
+ * @param {String|Number} [column] The column ID (number) or
+ * title (string)
+ * @return {Array} An Array of TableRow objects
+ * @example
+ * var table;
+ *
+ * function setup() {
+ *
+ * table = new p5.Table();
+ *
+ * table.addColumn('name');
+ * table.addColumn('type');
+ *
+ * var newRow = table.addRow();
+ * newRow.setString('name', 'Lion');
+ * newRow.setString('type', 'Mammal');
+ *
+ * newRow = table.addRow();
+ * newRow.setString('name', 'Snake');
+ * newRow.setString('type', 'Reptile');
+ *
+ * newRow = table.addRow();
+ * newRow.setString('name', 'Mosquito');
+ * newRow.setString('type', 'Insect');
+ *
+ * newRow = table.addRow();
+ * newRow.setString('name', 'Lizard');
+ * newRow.setString('type', 'Reptile');
+ *
+ * var rows = table.matchRows('R.*', 'type');
+ * for (var i = 0; i < rows.length; i++) {
+ * print(rows[i].getString('name') + ': ' + rows[i].getString('type'));
+ * }
+ * }
+ * // Sketch prints:
+ * // Snake: Reptile
+ * // Lizard: Reptile
+ */
+p5.Table.prototype.matchRows = function(regexp, column) {
+ var ret = [];
+ if (typeof(column) === 'number') {
+ for (var j = 0; j < this.rows.length; j++) {
+ if ( this.rows[j].arr[column].match(regexp) ) {
+ ret.push( this.rows[j] );
+ }
+ }
+ }
+
+ else {
+ for (var i = 0; i < this.rows.length; i++) {
+ if ( this.rows[i].obj[column].match(regexp) ) {
+ ret.push( this.rows[i] );
+ }
+ }
+ }
+ return ret;
+};
+
+
+/**
+ * Retrieves all values in the specified column, and returns them
+ * as an array. The column may be specified by either its ID or title.
+ *
+ * @method getColumn
+ * @param {String|Number} column String or Number of the column to return
+ * @return {Array} Array of column values
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * //getColumn returns an array that can be printed directly
+ * print(table.getColumn("species"));
+ * //outputs ["Capra hircus", "Panthera pardus", "Equus zebra"]
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.getColumn = function(value) {
+ var ret = [];
+ if (typeof(value) === 'string'){
+ for (var i = 0; i < this.rows.length; i++){
+ ret.push (this.rows[i].obj[value]);
+ }
+ } else {
+ for (var j = 0; j < this.rows.length; j++){
+ ret.push (this.rows[j].arr[value]);
+ }
+ }
+ return ret;
+};
+
+/**
+ * Removes all rows from a Table. While all rows are removed,
+ * columns and column titles are maintained.
+ *
+ * @method clearRows
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * table.clearRows();
+ * print(table.getRowCount() + " total rows in table");
+ * print(table.getColumnCount() + " total columns in table");
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.clearRows = function() {
+ delete this.rows;
+ this.rows = [];
+};
+
+/**
+ * Use addColumn() to add a new column to a Table object.
+ * Typically, you will want to specify a title, so the column
+ * may be easily referenced later by name. (If no title is
+ * specified, the new column's title will be null.)
+ *
+ * @method addColumn
+ * @param {String} [title] title of the given column
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * table.addColumn("carnivore");
+ * table.set(0, "carnivore", "no");
+ * table.set(1, "carnivore", "yes");
+ * table.set(2, "carnivore", "no");
+ *
+ * //print the results
+ * for (var r = 0; r < table.getRowCount(); r++)
+ * for (var c = 0; c < table.getColumnCount(); c++)
+ * print(table.getString(r, c));
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.addColumn = function(title) {
+ var t = title || null;
+ this.columns.push(t);
+};
+
+/**
+ * Returns the total number of columns in a Table.
+ *
+ * @return {Number} Number of columns in this table
+ */
+p5.Table.prototype.getColumnCount = function() {
+ return this.columns.length;
+};
+
+/**
+ * Returns the total number of rows in a Table.
+ *
+ * @method getRowCount
+ * @return {Number} Number of rows in this table
+
+ */
+p5.Table.prototype.getRowCount = function() {
+ return this.rows.length;
+};
+
+/**
+ *
Removes any of the specified characters (or "tokens").
+ *
+ *
If no column is specified, then the values in all columns and
+ * rows are processed. A specific column may be referenced by
+ * either its ID or title.
+ *
+ * @method removeTokens
+ * @param {String} chars String listing characters to be removed
+ * @param {String|Number} [column] Column ID (number)
+ * or name (string)
+ */
+p5.Table.prototype.removeTokens = function(chars, column) {
+ var escape= function(s) {
+ return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+ };
+ var charArray = [];
+ for (var i = 0; i < chars.length; i++) {
+ charArray.push( escape( chars.charAt(i) ) );
+ }
+ var regex = new RegExp(charArray.join('|'), 'g');
+
+ if (typeof(column) === 'undefined'){
+ for (var c = 0; c < this.columns.length; c++) {
+ for (var d = 0; d < this.rows.length; d++) {
+ var s = this.rows[d].arr[c];
+ s = s.replace(regex, '');
+ this.rows[d].arr[c] = s;
+ this.rows[d].obj[this.columns[c]] = s;
+ }
+ }
+ }
+ else if (typeof(column) === 'string'){
+ for (var j = 0; j < this.rows.length; j++) {
+ var val = this.rows[j].obj[column];
+ val = val.replace(regex, '');
+ this.rows[j].obj[column] = val;
+ var pos = this.columns.indexOf(column);
+ this.rows[j].arr[pos] = val;
+ }
+ }
+ else {
+ for (var k = 0; k < this.rows.length; k++) {
+ var str = this.rows[k].arr[column];
+ str = str.replace(regex, '');
+ this.rows[k].arr[column] = str;
+ this.rows[k].obj[this.columns[column]] = str;
+ }
+ }
+};
+
+/**
+ * Trims leading and trailing whitespace, such as spaces and tabs,
+ * from String table values. If no column is specified, then the
+ * values in all columns and rows are trimmed. A specific column
+ * may be referenced by either its ID or title.
+ *
+ * @method trim
+ * @param {String|Number} column Column ID (number)
+ * or name (string)
+ */
+p5.Table.prototype.trim = function(column) {
+ var regex = new RegExp( (' '), 'g');
+
+ if (typeof(column) === 'undefined'){
+ for (var c = 0; c < this.columns.length; c++) {
+ for (var d = 0; d < this.rows.length; d++) {
+ var s = this.rows[d].arr[c];
+ s = s.replace(regex, '');
+ this.rows[d].arr[c] = s;
+ this.rows[d].obj[this.columns[c]] = s;
+ }
+ }
+ }
+ else if (typeof(column) === 'string'){
+ for (var j = 0; j < this.rows.length; j++) {
+ var val = this.rows[j].obj[column];
+ val = val.replace(regex, '');
+ this.rows[j].obj[column] = val;
+ var pos = this.columns.indexOf(column);
+ this.rows[j].arr[pos] = val;
+ }
+ }
+ else {
+ for (var k = 0; k < this.rows.length; k++) {
+ var str = this.rows[k].arr[column];
+ str = str.replace(regex, '');
+ this.rows[k].arr[column] = str;
+ this.rows[k].obj[this.columns[column]] = str;
+ }
+ }
+};
+
+/**
+ * Use removeColumn() to remove an existing column from a Table
+ * object. The column to be removed may be identified by either
+ * its title (a String) or its index value (an int).
+ * removeColumn(0) would remove the first column, removeColumn(1)
+ * would remove the second column, and so on.
+ *
+ * @method removeColumn
+ * @param {String|Number} column columnName (string) or ID (number)
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * table.removeColumn("id");
+ * print(table.getColumnCount());
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.removeColumn = function(c) {
+ var cString;
+ var cNumber;
+ if (typeof(c) === 'string') {
+ // find the position of c in the columns
+ cString = c;
+ cNumber = this.columns.indexOf(c);
+ console.log('string');
+ }
+ else{
+ cNumber = c;
+ cString = this.columns[c];
+ }
+
+ var chunk = this.columns.splice(cNumber+1, this.columns.length);
+ this.columns.pop();
+ this.columns = this.columns.concat(chunk);
+
+ for (var i = 0; i < this.rows.length; i++){
+ var tempR = this.rows[i].arr;
+ var chip = tempR.splice(cNumber+1, tempR.length);
+ tempR.pop();
+ this.rows[i].arr = tempR.concat(chip);
+ delete this.rows[i].obj[cString];
+ }
+
+};
+
+
+/**
+ * Stores a value in the Table's specified row and column.
+ * The row is specified by its ID, while the column may be specified
+ * by either its ID or title.
+ *
+ * @method set
+ * @param {String|Number} column column ID (Number)
+ * or title (String)
+ * @param {String|Number} value value to assign
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * table.set(0, "species", "Canis Lupus");
+ * table.set(0, "name", "Wolf");
+ *
+ * //print the results
+ * for (var r = 0; r < table.getRowCount(); r++)
+ * for (var c = 0; c < table.getColumnCount(); c++)
+ * print(table.getString(r, c));
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.set = function(row, column, value) {
+ this.rows[row].set(column, value);
+};
+
+/**
+ * Stores a Float value in the Table's specified row and column.
+ * The row is specified by its ID, while the column may be specified
+ * by either its ID or title.
+ *
+ * @method setNum
+ * @param {Number} row row ID
+ * @param {String|Number} column column ID (Number)
+ * or title (String)
+ * @param {Number} value value to assign
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * table.setNum(1, "id", 1);
+ *
+ * print(table.getColumn(0));
+ * //["0", 1, "2"]
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ */
+p5.Table.prototype.setNum = function(row, column, value){
+ this.rows[row].setNum(column, value);
+};
+
+
+/**
+ * Stores a String value in the Table's specified row and column.
+ * The row is specified by its ID, while the column may be specified
+ * by either its ID or title.
+ *
+ * @method setString
+ * @param {Number} row row ID
+ * @param {String|Number} column column ID (Number)
+ * or title (String)
+ * @param {String} value value to assign
+ */
+p5.Table.prototype.setString = function(row, column, value){
+ this.rows[row].setString(column, value);
+};
+
+/**
+ * Retrieves a value from the Table's specified row and column.
+ * The row is specified by its ID, while the column may be specified by
+ * either its ID or title.
+ *
+ * @method get
+ * @param {Number} row row ID
+ * @param {String|Number} column columnName (string) or
+ * ID (number)
+ * @return {String|Number}
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * print(table.get(0, 1));
+ * //Capra hircus
+ * print(table.get(0, "species"));
+ * //Capra hircus
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.get = function(row, column) {
+ return this.rows[row].get(column);
+};
+
+/**
+ * Retrieves a Float value from the Table's specified row and column.
+ * The row is specified by its ID, while the column may be specified by
+ * either its ID or title.
+ *
+ * @method getNum
+ * @param {Number} row row ID
+ * @param {String|Number} column columnName (string) or
+ * ID (number)
+ * @return {Number}
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * print(table.getNum(1, 0) + 100);
+ * //id 1 + 100 = 101
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.getNum = function(row, column) {
+ return this.rows[row].getNum(column);
+};
+
+/**
+ * Retrieves a String value from the Table's specified row and column.
+ * The row is specified by its ID, while the column may be specified by
+ * either its ID or title.
+ *
+ * @method getString
+ * @param {Number} row row ID
+ * @param {String|Number} column columnName (string) or
+ * ID (number)
+ * @return {String}
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * var tableArray = table.getArray();
+ *
+ * //output each row as array
+ * for (var i = 0; i < tableArray.length; i++)
+ * print(tableArray[i]);
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.getString = function(row, column) {
+ return this.rows[row].getString(column);
+};
+
+/**
+ * Retrieves all table data and returns as an object. If a column name is
+ * passed in, each row object will be stored with that attribute as its
+ * title.
+ *
+ * @method getObject
+ * @param {String} headerColumn Name of the column which should be used to
+ * title each row object (optional)
+ * @return {Object}
+ *
+ * @example
+ *
+ *
+ * // Given the CSV file "mammals.csv"
+ * // in the project's "assets" folder:
+ * //
+ * // id,species,name
+ * // 0,Capra hircus,Goat
+ * // 1,Panthera pardus,Leopard
+ * // 2,Equus zebra,Zebra
+ *
+ * var table;
+ *
+ * function preload() {
+ * //my table is comma separated value "csv"
+ * //and has a header specifying the columns labels
+ * table = loadTable("assets/mammals.csv", "csv", "header");
+ * }
+ *
+ * function setup() {
+ * var tableObject = table.getObject();
+ *
+ * print(tableObject);
+ * //outputs an object
+ * }
+ *
+ *
+ *
+ *@alt
+ * no image displayed
+ *
+ */
+p5.Table.prototype.getObject = function (headerColumn) {
+ var tableObject = {};
+ var obj, cPos, index;
+
+ for(var i = 0; i < this.rows.length; i++) {
+ obj = this.rows[i].obj;
+
+ if (typeof(headerColumn) === 'string'){
+ cPos = this.columns.indexOf(headerColumn); // index of columnID
+ if (cPos >= 0) {
+ index = obj[headerColumn];
+ tableObject[index] = obj;
+ } else {
+ throw 'This table has no column named "' + headerColumn +'"';
+ }
+ } else {
+ tableObject[i] = this.rows[i].obj;
+ }
+ }
+ return tableObject;
+};
+
+/**
+ * Retrieves all table data and returns it as a multidimensional array.
+ *
+ * @method getArray
+ * @return {Array}
+ */
+p5.Table.prototype.getArray = function () {
+ var tableArray = [];
+ for(var i = 0; i < this.rows.length; i++) {
+ tableArray.push(this.rows[i].arr);
+ }
+ return tableArray;
+};
+
+module.exports = p5.Table;
+
+},{"../core/core":42}],66:[function(_dereq_,module,exports){
+/**
+ * @module IO
+ * @submodule Table
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * A TableRow object represents a single row of data values,
+ * stored in columns, from a table.
+ *
+ * A Table Row contains both an ordered array, and an unordered
+ * JSON object.
+ *
+ * @class p5.TableRow
+ * @constructor
+ * @param {String} [str] optional: populate the row with a
+ * string of values, separated by the
+ * separator
+ * @param {String} [separator] comma separated values (csv) by default
+ */
+p5.TableRow = function (str, separator) {
+ var arr = [];
+ var obj = {};
+ if (str){
+ separator = separator || ',';
+ arr = str.split(separator);
+ }
+ for (var i = 0; i < arr.length; i++){
+ var key = i;
+ var val = arr[i];
+ obj[key] = val;
+ }
+ this.arr = arr;
+ this.obj = obj;
+ this.table = null;
+};
+
+/**
+ * Stores a value in the TableRow's specified column.
+ * The column may be specified by either its ID or title.
+ *
+ * @method set
+ * @param {String|Number} column Column ID (Number)
+ * or Title (String)
+ * @param {String|Number} value The value to be stored
+ */
+p5.TableRow.prototype.set = function(column, value) {
+ // if typeof column is string, use .obj
+ if (typeof(column) === 'string'){
+ var cPos = this.table.columns.indexOf(column); // index of columnID
+ if (cPos >= 0) {
+ this.obj[column] = value;
+ this.arr[cPos] = value;
+ }
+ else {
+ throw 'This table has no column named "' + column +'"';
+ }
+ }
+
+ // if typeof column is number, use .arr
+ else {
+ if (column < this.table.columns.length) {
+ this.arr[column] = value;
+ var cTitle = this.table.columns[column];
+ this.obj[cTitle] = value;
+ }
+ else {
+ throw 'Column #' + column + ' is out of the range of this table';
+ }
+ }
+};
+
+
+/**
+ * Stores a Float value in the TableRow's specified column.
+ * The column may be specified by either its ID or title.
+ *
+ * @method setNum
+ * @param {String|Number} column Column ID (Number)
+ * or Title (String)
+ * @param {Number} value The value to be stored
+ * as a Float
+ */
+p5.TableRow.prototype.setNum = function(column, value){
+ var floatVal = parseFloat(value, 10);
+ this.set(column, floatVal);
+};
+
+
+/**
+ * Stores a String value in the TableRow's specified column.
+ * The column may be specified by either its ID or title.
+ *
+ * @method setString
+ * @param {String|Number} column Column ID (Number)
+ * or Title (String)
+ * @param {String} value The value to be stored
+ * as a String
+ */
+p5.TableRow.prototype.setString = function(column, value){
+ var stringVal = value.toString();
+ this.set(column, stringVal);
+};
+
+/**
+ * Retrieves a value from the TableRow's specified column.
+ * The column may be specified by either its ID or title.
+ *
+ * @method get
+ * @param {String|Number} column columnName (string) or
+ * ID (number)
+ * @return {String|Number}
+ */
+p5.TableRow.prototype.get = function(column) {
+ if (typeof(column) === 'string'){
+ return this.obj[column];
+ } else {
+ return this.arr[column];
+ }
+};
+
+/**
+ * Retrieves a Float value from the TableRow's specified
+ * column. The column may be specified by either its ID or
+ * title.
+ *
+ * @method getNum
+ * @param {String|Number} column columnName (string) or
+ * ID (number)
+ * @return {Number} Float Floating point number
+ */
+p5.TableRow.prototype.getNum = function(column) {
+ var ret;
+ if (typeof(column) === 'string'){
+ ret = parseFloat(this.obj[column], 10);
+ } else {
+ ret = parseFloat(this.arr[column], 10);
+ }
+
+ if (ret.toString() === 'NaN') {
+ throw 'Error: ' + this.obj[column]+ ' is NaN (Not a Number)';
+ }
+ return ret;
+};
+
+/**
+ * Retrieves an String value from the TableRow's specified
+ * column. The column may be specified by either its ID or
+ * title.
+ *
+ * @method getString
+ * @param {String|Number} column columnName (string) or
+ * ID (number)
+ * @return {String} String
+ */
+p5.TableRow.prototype.getString = function(column) {
+ if (typeof(column) === 'string'){
+ return this.obj[column].toString();
+ } else {
+ return this.arr[column].toString();
+ }
+};
+
+module.exports = p5.TableRow;
+
+},{"../core/core":42}],67:[function(_dereq_,module,exports){
+/**
+ * @module IO
+ * @submodule XML
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * XML is a representation of an XML object, able to parse XML code. Use
+ * loadXML() to load external XML files and create XML objects.
+ *
+ * @class p5.XML
+ * @constructor
+ * @return {p5.XML} p5.XML object generated
+ * @example
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var children = xml.getChildren("animal");
+ *
+ * for (var i = 0; i < children.length; i++) {
+ * var id = children[i].getNumber("id");
+ * var coloring = children[i].getString("species");
+ * var name = children[i].getContent();
+ * print(id + ", " + coloring + ", " + name);
+ * }
+ * }
+ *
+ * // Sketch prints:
+ * // 0, Capra hircus, Goat
+ * // 1, Panthera pardus, Leopard
+ * // 2, Equus zebra, Zebra
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.XML = function () {
+ this.name = null; //done
+ this.attributes = {}; //done
+ this.children = [];
+ this.parent = null;
+ this.content = null; //done
+};
+
+
+/**
+ * Gets a copy of the element's parent. Returns the parent as another
+ * p5.XML object.
+ *
+ * @method getParent
+ * @return {Object} element parent
+ * @example
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var children = xml.getChildren("animal");
+ * var parent = children[1].getParent();
+ * print(parent.getName());
+ * }
+ *
+ * // Sketch prints:
+ * // mammals
+ *
+ */
+p5.XML.prototype.getParent = function() {
+ return this.parent;
+};
+
+/**
+ * Gets the element's full name, which is returned as a String.
+ *
+ * @method getName
+ * @return {String} the name of the node
+ * @example<animal
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * print(xml.getName());
+ * }
+ *
+ * // Sketch prints:
+ * // mammals
+ *
+ */
+p5.XML.prototype.getName = function() {
+ return this.name;
+};
+
+/**
+ * Sets the element's name, which is specified as a String.
+ *
+ * @method setName
+ * @param {String} the new name of the node
+ * @example<animal
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * print(xml.getName());
+ * xml.setName("fish");
+ * print(xml.getName());
+ * }
+ *
+ * // Sketch prints:
+ * // mammals
+ * // fish
+ *
+ */
+p5.XML.prototype.setName = function(name) {
+ this.name = name;
+};
+
+/**
+ * Checks whether or not the element has any children, and returns the result
+ * as a boolean.
+ *
+ * @method hasChildren
+ * @return {boolean}
+ * @example<animal
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * print(xml.hasChildren());
+ * }
+ *
+ * // Sketch prints:
+ * // true
+ *
+ */
+p5.XML.prototype.hasChildren = function() {
+ return this.children.length > 0;
+};
+
+/**
+ * Get the names of all of the element's children, and returns the names as an
+ * array of Strings. This is the same as looping through and calling getName()
+ * on each child element individually.
+ *
+ * @method listChildren
+ * @return {Array} names of the children of the element
+ * @example<animal
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * print(xml.listChildren());
+ * }
+ *
+ * // Sketch prints:
+ * // ["animal", "animal", "animal"]
+ *
+ */
+p5.XML.prototype.listChildren = function() {
+ return this.children.map(function(c) { return c.name; });
+};
+
+/**
+ * Returns all of the element's children as an array of p5.XML objects. When
+ * the name parameter is specified, then it will return all children that match
+ * that name.
+ *
+ * @method getChildren
+ * @param {String} [name] element name
+ * @return {Array} children of the element
+ * @example<animal
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var animals = xml.getChildren("animal");
+ *
+ * for (var i = 0; i < animals.length; i++) {
+ * print(animals[i].getContent());
+ * }
+ * }
+ *
+ * // Sketch prints:
+ * // "Goat"
+ * // "Leopard"
+ * // "Zebra"
+ *
+ */
+p5.XML.prototype.getChildren = function(param) {
+ if (param) {
+ return this.children.filter(function(c) { return c.name === param; });
+ }
+ else {
+ return this.children;
+ }
+};
+
+/**
+ * Returns the first of the element's children that matches the name parameter
+ * or the child of the given index.It returns undefined if no matching
+ * child is found.
+ *
+ * @method getChild
+ * @param {String|Number} name element name or index
+ * @return {p5.XML}
+ * @example<animal
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var firstChild = xml.getChild("animal");
+ * print(firstChild.getContent());
+ * }
+ *
+ * // Sketch prints:
+ * // "Goat"
+ *
+ */
+p5.XML.prototype.getChild = function(param) {
+ if(typeof param === 'string') {
+ return this.children.find(function(c) {
+ return c.name === param;
+ });
+ }
+ else {
+ return this.children[param];
+ }
+};
+
+/**
+ * Appends a new child to the element. The child can be specified with
+ * either a String, which will be used as the new tag's name, or as a
+ * reference to an existing p5.XML object.
+ * A reference to the newly created child is returned as an p5.XML object.
+ *
+ * @method addChild
+ * @param {Object} a p5.XML Object which will be the child to be added
+ */
+p5.XML.prototype.addChild = function(node) {
+ if (node instanceof p5.XML) {
+ this.children.push(node);
+ } else {
+ // PEND
+ }
+};
+
+/**
+ * Removes the element specified by name or index.
+ *
+ * @method removeChild
+ * @param {String|Number} name element name or index
+ * @example
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * xml.removeChild("animal");
+ * var children = xml.getChildren();
+ * for (var i=0; i
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * xml.removeChild(1);
+ * var children = xml.getChildren();
+ * for (var i=0; i
+ */
+p5.XML.prototype.removeChild = function(param) {
+ var ind = -1;
+ if(typeof param === 'string') {
+ for (var i=0; i
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var firstChild = xml.getChild("animal");
+ * print(firstChild.getAttributeCount());
+ * }
+ *
+ * // Sketch prints:
+ * // 2
+ *
+ */
+p5.XML.prototype.getAttributeCount = function() {
+ return Object.keys(this.attributes).length;
+};
+
+/**
+ * Gets all of the specified element's attributes, and returns them as an
+ * array of Strings.
+ *
+ * @method listAttributes
+ * @return {Array} an array of strings containing the names of attributes
+ * @example
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var firstChild = xml.getChild("animal");
+ * print(firstChild.listAttributes());
+ * }
+ *
+ * // Sketch prints:
+ * // ["id", "species"]
+ *
+ */
+p5.XML.prototype.listAttributes = function() {
+ return Object.keys(this.attributes);
+};
+
+/**
+ * Checks whether or not an element has the specified attribute.
+ *
+ * @method hasAttribute
+ * @param {String} the attribute to be checked
+ * @return {boolean} true if attribute found else false
+ * @example
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var firstChild = xml.getChild("animal");
+ * print(firstChild.hasAttribute("species"));
+ * print(firstChild.hasAttribute("color"));
+ * }
+ *
+ * // Sketch prints:
+ * // true
+ * // false
+ *
+ */
+p5.XML.prototype.hasAttribute = function(name) {
+ return this.attributes[name] ? true : false;
+};
+
+/**
+ * Returns an attribute value of the element as an Number. If the defaultValue
+ * parameter is specified and the attribute doesn't exist, then defaultValue
+ * is returned. If no defaultValue is specified and the attribute doesn't
+ * exist, the value 0 is returned.
+ *
+ * @method getNumber
+ * @param {String} name the non-null full name of the attribute
+ * @param {Number} [defaultValue] the default value of the attribute
+ * @return {Number}
+ * @example
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var firstChild = xml.getChild("animal");
+ * print(firstChild.getNumber("id"));
+ * }
+ *
+ * // Sketch prints:
+ * // 0
+ *
+ */
+p5.XML.prototype.getNumber = function(name, defaultValue) {
+ return Number(this.attributes[name]) || defaultValue || 0;
+};
+
+/**
+ * Returns an attribute value of the element as an String. If the defaultValue
+ * parameter is specified and the attribute doesn't exist, then defaultValue
+ * is returned. If no defaultValue is specified and the attribute doesn't
+ * exist, null is returned.
+ *
+ * @method getString
+ * @param {String} name the non-null full name of the attribute
+ * @param {Number} [defaultValue] the default value of the attribute
+ * @return {Number}
+ * @example
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var firstChild = xml.getChild("animal");
+ * print(firstChild.getString("species"));
+ * }
+ *
+ * // Sketch prints:
+ * // "Capra hircus"
+ *
+ */
+p5.XML.prototype.getString = function(name, defaultValue) {
+ return String(this.attributes[name]) || defaultValue || null;
+};
+
+/**
+ * Sets the content of an element's attribute. The first parameter specifies
+ * the attribute name, while the second specifies the new content.
+ *
+ * @method setAttribute
+ * @param {String} name the full name of the attribute
+ * @param {Number} value the value of the attribute
+ * @example
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var firstChild = xml.getChild("animal");
+ * print(firstChild.getString("species"));
+ * firstChild.setAttribute("species", "Jamides zebra");
+ * print(firstChild.getString("species"));
+ * }
+ *
+ * // Sketch prints:
+ * // "Capra hircus"
+ * // "Jamides zebra"
+ *
+ */
+p5.XML.prototype.setAttribute = function(name, value) {
+ if (this.attributes[name]) {
+ this.attributes[name] = value;
+ }
+};
+
+/**
+ * Returns the content of an element. If there is no such content,
+ * defaultValue is returned if specified, otherwise null is returned.
+ *
+ * @method getContent
+ * @param {String} [defaultValue] value returned if no content is found
+ * @return {String}
+ * @example
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var firstChild = xml.getChild("animal");
+ * print(firstChild.getContent());
+ * }
+ *
+ * // Sketch prints:
+ * // "Goat"
+ *
+ * // The following short XML file called "mammals.xml" is parsed
+ * // in the code below.
+ * //
+ * //
+ * // <mammals>
+ * // <animal id="0" species="Capra hircus">Goat</animal>
+ * // <animal id="1" species="Panthera pardus">Leopard</animal>
+ * // <animal id="2" species="Equus zebra">Zebra</animal>
+ * // </mammals>
+ *
+ * var xml;
+ *
+ * function preload() {
+ * xml = loadXML("assets/mammals.xml");
+ * }
+ *
+ * function setup() {
+ * var firstChild = xml.getChild("animal");
+ * print(firstChild.getContent());
+ * firstChild.setContent("Mountain Goat");
+ * print(firstChild.getContent());
+ * }
+ *
+ * // Sketch prints:
+ * // "Goat"
+ * // "Mountain Goat"
+ *
+ */
+p5.XML.prototype.setContent = function( content ) {
+ if(!this.children.length) {
+ this.content = content;
+ }
+};
+
+/* HELPERS */
+/**
+ * This method is called while the parsing of XML (when loadXML() is
+ * called). The difference between this method and the setContent()
+ * method defined later is that this one is used to set the content
+ * when the node in question has more nodes under it and so on and
+ * not directly text content. While in the other one is used when
+ * the node in question directly has text inside it.
+ *
+ */
+p5.XML.prototype._setCont = function(content) {
+ var str;
+ str = content;
+ str = str.replace(/\s\s+/g, ',');
+ //str = str.split(',');
+ this.content = str;
+};
+
+/**
+ * This method is called while the parsing of XML (when loadXML() is
+ * called). The XML node is passed and its attributes are stored in the
+ * p5.XML's attribute Object.
+ *
+ */
+p5.XML.prototype._setAttributes = function(node) {
+ var i, att = {};
+ for( i = 0; i < node.attributes.length; i++) {
+ att[node.attributes[i].nodeName] = node.attributes[i].nodeValue;
+ }
+ this.attributes = att;
+};
+
+module.exports = p5.XML;
+},{"../core/core":42}],68:[function(_dereq_,module,exports){
+/**
+ * @module Math
+ * @submodule Calculation
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * Calculates the absolute value (magnitude) of a number. Maps to Math.abs().
+ * The absolute value of a number is always positive.
+ *
+ * @method abs
+ * @param {Number} n number to compute
+ * @return {Number} absolute value of given number
+ * @example
+ *
+ * function setup() {
+ * var x = -3;
+ * var y = abs(x);
+ *
+ * print(x); // -3
+ * print(y); // 3
+ * }
+ *
+ *
+ * @alt
+ * no image displayed
+ *
+ */
+p5.prototype.abs = Math.abs;
+
+/**
+ * Calculates the closest int value that is greater than or equal to the
+ * value of the parameter. Maps to Math.ceil(). For example, ceil(9.03)
+ * returns the value 10.
+ *
+ * @method ceil
+ * @param {Number} n number to round up
+ * @return {Number} rounded up number
+ * @example
+ *
+ * function draw() {
+ * background(200);
+ * // map, mouseX between 0 and 5.
+ * var ax = map(mouseX, 0, 100, 0, 5);
+ * var ay = 66;
+ *
+ * //Get the ceiling of the mapped number.
+ * var bx = ceil(map(mouseX, 0, 100, 0,5));
+ * var by = 33;
+ *
+ * // Multiply the mapped numbers by 20 to more easily
+ * // see the changes.
+ * stroke(0);
+ * fill(0);
+ * line(0, ay, ax * 20, ay);
+ * line(0, by, bx * 20, by);
+ *
+ * // Reformat the float returned by map and draw it.
+ * noStroke();
+ * text(nfc(ax, 2,2), ax, ay - 5);
+ * text(nfc(bx,1,1), bx, by - 5);
+ * }
+ *
+ *
+ * @alt
+ * 2 horizontal lines & number sets. increase with mouse x. bottom to 2 decimals
+ *
+ */
+p5.prototype.ceil = Math.ceil;
+
+/**
+ * Constrains a value between a minimum and maximum value.
+ *
+ * @method constrain
+ * @param {Number} n number to constrain
+ * @param {Number} low minimum limit
+ * @param {Number} high maximum limit
+ * @return {Number} constrained number
+ * @example
+ *
+ * function draw() {
+ * background(200);
+ *
+ * var leftWall = 25;
+ * var rightWall = 75;
+ *
+ * // xm is just the mouseX, while
+ * // xc is the mouseX, but constrained
+ * // between the leftWall and rightWall!
+ * var xm = mouseX;
+ * var xc = constrain(mouseX, leftWall, rightWall);
+ *
+ * // Draw the walls.
+ * stroke(150);
+ * line(leftWall, 0, leftWall, height);
+ * line(rightWall, 0, rightWall, height);
+ *
+ * // Draw xm and xc as circles.
+ * noStroke();
+ * fill(150);
+ * ellipse(xm, 33, 9,9); // Not Constrained
+ * fill(0);
+ * ellipse(xc, 66, 9,9); // Constrained
+ * }
+ *
+ *
+ * @alt
+ * 2 vertical lines. 2 ellipses move with mouse X 1 does not move passed lines
+ *
+ */
+p5.prototype.constrain = function(n, low, high) {
+ return Math.max(Math.min(n, high), low);
+};
+
+/**
+ * Calculates the distance between two points.
+ *
+ * @method dist
+ * @param {Number} x1 x-coordinate of the first point
+ * @param {Number} y1 y-coordinate of the first point
+ * @param {Number} [z1] z-coordinate of the first point
+ * @param {Number} x2 x-coordinate of the second point
+ * @param {Number} y2 y-coordinate of the second point
+ * @param {Number} [z2] z-coordinate of the second point
+ * @return {Number} distance between the two points
+ * @example
+ *
+ * // Move your mouse inside the canvas to see the
+ * // change in distance between two points!
+ * function draw() {
+ * background(200);
+ * fill(0);
+ *
+ * var x1 = 10;
+ * var y1 = 90;
+ * var x2 = mouseX;
+ * var y2 = mouseY;
+ *
+ * line(x1, y1, x2, y2);
+ * ellipse(x1, y1, 7, 7);
+ * ellipse(x2, y2, 7, 7);
+ *
+ * // d is the length of the line
+ * // the distance from point 1 to point 2.
+ * var d = int(dist(x1, y1, x2, y2));
+ *
+ * // Let's write d along the line we are drawing!
+ * push();
+ * translate( (x1+x2)/2, (y1+y2)/2 );
+ * rotate( atan2(y2-y1,x2-x1) );
+ * text(nfc(d,1,1), 0, -5);
+ * pop();
+ * // Fancy!
+ * }
+ *
+ *
+ * @alt
+ * 2 ellipses joined by line. 1 ellipse moves with mouse X&Y. Distance displayed.
+ *
+ */
+p5.prototype.dist = function(x1, y1, z1, x2, y2, z2) {
+ if (arguments.length === 4) {
+ // In the case of 2d: z1 means x2 and x2 means y2
+ return hypot(z1-x1, x2-y1);
+ } else if (arguments.length === 6) {
+ return hypot(x2-x1, y2-y1, z2-z1);
+ }
+};
+
+/**
+ * Returns Euler's number e (2.71828...) raised to the power of the n
+ * parameter. Maps to Math.exp().
+ *
+ * @method exp
+ * @param {Number} n exponent to raise
+ * @return {Number} e^n
+ * @example
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Compute the exp() function with a value between 0 and 2
+ * var xValue = map(mouseX, 0, width, 0, 2);
+ * var yValue = exp(xValue);
+ *
+ * var y = map(yValue, 0, 8, height, 0);
+ *
+ * var legend = "exp (" + nfc(xValue, 3) +")\n= " + nf(yValue, 1, 4);
+ * stroke(150);
+ * line(mouseX, y, mouseX, height);
+ * fill(0);
+ * text(legend, 5, 15);
+ * noStroke();
+ * ellipse (mouseX,y, 7, 7);
+ *
+ * // Draw the exp(x) curve,
+ * // over the domain of x from 0 to 2
+ * noFill();
+ * stroke(0);
+ * beginShape();
+ * for (var x = 0; x < width; x++) {
+ * xValue = map(x, 0, width, 0, 2);
+ * yValue = exp(xValue);
+ * y = map(yValue, 0, 8, height, 0);
+ * vertex(x, y);
+ * }
+ *
+ * endShape();
+ * line(0, 0, 0, height);
+ * line(0, height-1, width, height-1);
+ * }
+ *
+ *
+ * @alt
+ * ellipse moves along a curve with mouse x. e^n displayed.
+ *
+ */
+p5.prototype.exp = Math.exp;
+
+/**
+ * Calculates the closest int value that is less than or equal to the
+ * value of the parameter. Maps to Math.floor().
+ *
+ * @method floor
+ * @param {Number} n number to round down
+ * @return {Number} rounded down number
+ * @example
+ *
+ * function draw() {
+ * background(200);
+ * //map, mouseX between 0 and 5.
+ * var ax = map(mouseX, 0, 100, 0, 5);
+ * var ay = 66;
+ *
+ * //Get the floor of the mapped number.
+ * var bx = floor(map(mouseX, 0, 100, 0,5));
+ * var by = 33;
+ *
+ * // Multiply the mapped numbers by 20 to more easily
+ * // see the changes.
+ * stroke(0);
+ * fill(0);
+ * line(0, ay, ax * 20, ay);
+ * line(0, by, bx * 20, by);
+ *
+ * // Reformat the float returned by map and draw it.
+ * noStroke();
+ * text(nfc(ax, 2,2), ax, ay - 5);
+ * text(nfc(bx,1,1), bx, by - 5);
+ * }
+ *
+ *
+ * @alt
+ * 2 horizontal lines & number sets. increase with mouse x. bottom to 2 decimals
+ *
+ */
+p5.prototype.floor = Math.floor;
+
+/**
+ * Calculates a number between two numbers at a specific increment. The amt
+ * parameter is the amount to interpolate between the two values where 0.0
+ * equal to the first point, 0.1 is very near the first point, 0.5 is
+ * half-way in between, etc. The lerp function is convenient for creating
+ * motion along a straight path and for drawing dotted lines.
+ *
+ * @method lerp
+ * @param {Number} start first value
+ * @param {Number} stop second value
+ * @param {Number} amt number between 0.0 and 1.0
+ * @return {Number} lerped value
+ * @example
+ *
+ * function setup() {
+ * background(200);
+ * var a = 20;
+ * var b = 80;
+ * var c = lerp(a,b, .2);
+ * var d = lerp(a,b, .5);
+ * var e = lerp(a,b, .8);
+ *
+ * var y = 50
+ *
+ * strokeWeight(5);
+ * stroke(0); // Draw the original points in black
+ * point(a, y);
+ * point(b, y);
+ *
+ * stroke(100); // Draw the lerp points in gray
+ * point(c, y);
+ * point(d, y);
+ * point(e, y);
+ * }
+ *
+ *
+ * @alt
+ * 5 points horizontally staggered mid-canvas. mid 3 are grey, outer black
+ *
+ */
+p5.prototype.lerp = function(start, stop, amt) {
+ return amt*(stop-start)+start;
+};
+
+/**
+ * Calculates the natural logarithm (the base-e logarithm) of a number. This
+ * function expects the n parameter to be a value greater than 0.0. Maps to
+ * Math.log().
+ *
+ * @method log
+ * @param {Number} n number greater than 0
+ * @return {Number} natural logarithm of n
+ * @example
+ *
+ * function draw() {
+ * background(200);
+ * var maxX = 2.8;
+ * var maxY = 1.5;
+ *
+ * // Compute the natural log of a value between 0 and maxX
+ * var xValue = map(mouseX, 0, width, 0, maxX);
+ * if (xValue > 0) { // Cannot take the log of a negative number.
+ * var yValue = log(xValue);
+ * var y = map(yValue, -maxY, maxY, height, 0);
+ *
+ * // Display the calculation occurring.
+ * var legend = "log(" + nf(xValue, 1, 2) + ")\n= " + nf(yValue, 1, 3);
+ * stroke(150);
+ * line(mouseX, y, mouseX, height);
+ * fill(0);
+ * text (legend, 5, 15);
+ * noStroke();
+ * ellipse (mouseX, y, 7, 7);
+ * }
+ *
+ * // Draw the log(x) curve,
+ * // over the domain of x from 0 to maxX
+ * noFill();
+ * stroke(0);
+ * beginShape();
+ * for(var x=0; x < width; x++) {
+ * xValue = map(x, 0, width, 0, maxX);
+ * yValue = log(xValue);
+ * y = map(yValue, -maxY, maxY, height, 0);
+ * vertex(x, y);
+ * }
+ * endShape();
+ * line(0,0,0,height);
+ * line(0,height/2,width, height/2);
+ * }
+ *
+ *
+ * @alt
+ * ellipse moves along a curve with mouse x. natural logarithm of n displayed.
+ *
+ */
+p5.prototype.log = Math.log;
+
+/**
+ * Calculates the magnitude (or length) of a vector. A vector is a direction
+ * in space commonly used in computer graphics and linear algebra. Because it
+ * has no "start" position, the magnitude of a vector can be thought of as
+ * the distance from the coordinate 0,0 to its x,y value. Therefore, mag() is
+ * a shortcut for writing dist(0, 0, x, y).
+ *
+ * @method mag
+ * @param {Number} a first value
+ * @param {Number} b second value
+ * @return {Number} magnitude of vector from (0,0) to (a,b)
+ * @example
+ *
+ * function setup() {
+ * var x1 = 20;
+ * var x2 = 80;
+ * var y1 = 30;
+ * var y2 = 70;
+ *
+ * line(0, 0, x1, y1);
+ * print(mag(x1, y1)); // Prints "36.05551275463989"
+ * line(0, 0, x2, y1);
+ * print(mag(x2, y1)); // Prints "85.44003745317531"
+ * line(0, 0, x1, y2);
+ * print(mag(x1, y2)); // Prints "72.80109889280519"
+ * line(0, 0, x2, y2);
+ * print(mag(x2, y2)); // Prints "106.3014581273465"
+ * }
+ *
+ *
+ * @alt
+ * 4 lines of different length radiate from top left of canvas.
+ *
+ */
+p5.prototype.mag = function(x, y) {
+ return hypot(x, y);
+};
+
+/**
+ * Re-maps a number from one range to another.
+ *
+ * In the first example above, the number 25 is converted from a value in the
+ * range of 0 to 100 into a value that ranges from the left edge of the
+ * window (0) to the right edge (width).
+ *
+ * @method map
+ * @param {Number} value the incoming value to be converted
+ * @param {Number} start1 lower bound of the value's current range
+ * @param {Number} stop1 upper bound of the value's current range
+ * @param {Number} start2 lower bound of the value's target range
+ * @param {Number} stop2 upper bound of the value's target range
+ * @return {Number} remapped number
+ * @example
+ *
+ * var value = 25;
+ * var m = map(value, 0, 100, 0, width);
+ * ellipse(m, 50, 10, 10);
+ *
+ *
+ * @alt
+ * 10 by 10 white ellipse with in mid left canvas
+ * 2 25 by 25 white ellipses move with mouse x. Bottom has more range from X
+ *
+ */
+p5.prototype.map = function(n, start1, stop1, start2, stop2) {
+ return ((n-start1)/(stop1-start1))*(stop2-start2)+start2;
+};
+
+/**
+ * Determines the largest value in a sequence of numbers, and then returns
+ * that value. max() accepts any number of Number parameters, or an Array
+ * of any length.
+ *
+ * @method max
+ * @param {Number|Array} n0 Numbers to compare
+ * @return {Number} maximum Number
+ * @example
+ *
+ * function setup() {
+ * // Change the elements in the array and run the sketch
+ * // to show how max() works!
+ * numArray = new Array(2,1,5,4,8,9);
+ * fill(0);
+ * noStroke();
+ * text("Array Elements", 0, 10);
+ * // Draw all numbers in the array
+ * var spacing = 15;
+ * var elemsY = 25;
+ * for(var i = 0; i < numArray.length; i++) {
+ * text(numArray[i], i * spacing, elemsY);
+ * }
+ * maxX = 33;
+ * maxY = 80;
+ * // Draw the Maximum value in the array.
+ * textSize(32);
+ * text(max(numArray), maxX, maxY);
+ * }
+ *
+ *
+ * @alt
+ * Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 9
+ *
+ */
+p5.prototype.max = function() {
+ if (arguments[0] instanceof Array) {
+ return Math.max.apply(null,arguments[0]);
+ } else {
+ return Math.max.apply(null,arguments);
+ }
+};
+
+/**
+ * Determines the smallest value in a sequence of numbers, and then returns
+ * that value. min() accepts any number of Number parameters, or an Array
+ * of any length.
+ *
+ * @method min
+ * @param {Number|Array} n0 Numbers to compare
+ * @return {Number} minimum Number
+ * @example
+ *
+ * function setup() {
+ * // Change the elements in the array and run the sketch
+ * // to show how min() works!
+ * numArray = new Array(2,1,5,4,8,9);
+ * fill(0);
+ * noStroke();
+ * text("Array Elements", 0, 10);
+ * // Draw all numbers in the array
+ * var spacing = 15;
+ * var elemsY = 25;
+ * for(var i = 0; i < numArray.length; i++) {
+ * text(numArray[i], i * spacing, elemsY);
+ * }
+ * maxX = 33;
+ * maxY = 80;
+ * // Draw the Minimum value in the array.
+ * textSize(32);
+ * text(min(numArray), maxX, maxY);
+ * }
+ *
+ *
+ * @alt
+ * Small text at top reads: Array Elements 2 1 5 4 8 9. Large text at center: 1
+ *
+ */
+p5.prototype.min = function() {
+ if (arguments[0] instanceof Array) {
+ return Math.min.apply(null,arguments[0]);
+ } else {
+ return Math.min.apply(null,arguments);
+ }
+};
+
+/**
+ * Normalizes a number from another range into a value between 0 and 1.
+ * Identical to map(value, low, high, 0, 1).
+ * Numbers outside of the range are not clamped to 0 and 1, because
+ * out-of-range values are often intentional and useful. (See the second
+ * example above.)
+ *
+ * @method norm
+ * @param {Number} value incoming value to be normalized
+ * @param {Number} start lower bound of the value's current range
+ * @param {Number} stop upper bound of the value's current range
+ * @return {Number} normalized number
+ * @example
+ *
+ *
+ * @alt
+ * ellipse moves with mouse. 0 shown left & 100 right and updating values center
+ *
+ */
+p5.prototype.norm = function(n, start, stop) {
+ return this.map(n, start, stop, 0, 1);
+};
+
+/**
+ * Facilitates exponential expressions. The pow() function is an efficient
+ * way of multiplying numbers by themselves (or their reciprocals) in large
+ * quantities. For example, pow(3, 5) is equivalent to the expression
+ * 3*3*3*3*3 and pow(3, -5) is equivalent to 1 / 3*3*3*3*3. Maps to
+ * Math.pow().
+ *
+ * @method pow
+ * @param {Number} n base of the exponential expression
+ * @param {Number} e power by which to raise the base
+ * @return {Number} n^e
+ * @example
+ *
+ *
+ * @alt
+ * small to large ellipses radiating from top left of canvas
+ *
+ */
+p5.prototype.pow = Math.pow;
+
+/**
+ * Calculates the integer closest to the n parameter. For example,
+ * round(133.8) returns the value 134. Maps to Math.round().
+ *
+ * @method round
+ * @param {Number} n number to round
+ * @return {Number} rounded number
+ * @example
+ *
+ * function draw() {
+ * background(200);
+ * //map, mouseX between 0 and 5.
+ * var ax = map(mouseX, 0, 100, 0, 5);
+ * var ay = 66;
+ *
+ * // Round the mapped number.
+ * var bx = round(map(mouseX, 0, 100, 0,5));
+ * var by = 33;
+ *
+ * // Multiply the mapped numbers by 20 to more easily
+ * // see the changes.
+ * stroke(0);
+ * fill(0);
+ * line(0, ay, ax * 20, ay);
+ * line(0, by, bx * 20, by);
+ *
+ * // Reformat the float returned by map and draw it.
+ * noStroke();
+ * text(nfc(ax, 2,2), ax, ay - 5);
+ * text(nfc(bx,1,1), bx, by - 5);
+ * }
+ *
+ *
+ * @alt
+ * horizontal center line squared values displayed on top and regular on bottom.
+ *
+ */
+p5.prototype.round = Math.round;
+
+/**
+ * Squares a number (multiplies a number by itself). The result is always a
+ * positive number, as multiplying two negative numbers always yields a
+ * positive result. For example, -1 * -1 = 1.
+ *
+ * @method sq
+ * @param {Number} n number to square
+ * @return {Number} squared number
+ * @example
+ *
+ *
+ * @alt
+ * horizontal center line squared values displayed on top and regular on bottom.
+ *
+ */
+p5.prototype.sq = function(n) { return n*n; };
+
+/**
+ * Calculates the square root of a number. The square root of a number is
+ * always positive, even though there may be a valid negative root. The
+ * square root s of number a is such that s*s = a. It is the opposite of
+ * squaring. Maps to Math.sqrt().
+ *
+ * @method sqrt
+ * @param {Number} n non-negative number to square root
+ * @return {Number} square root of number
+ * @example
+ *
+ *
+ * @alt
+ * horizontal center line squareroot values displayed on top and regular on bottom.
+ *
+ */
+p5.prototype.sqrt = Math.sqrt;
+
+// Calculate the length of the hypotenuse of a right triangle
+// This won't under- or overflow in intermediate steps
+// https://en.wikipedia.org/wiki/Hypot
+function hypot(x, y, z) {
+ // Use the native implementation if it's available
+ if (typeof Math.hypot === 'function') {
+ return Math.hypot.apply(null, arguments);
+ }
+
+ // Otherwise use the V8 implementation
+ // https://github.com/v8/v8/blob/8cd3cf297287e581a49e487067f5cbd991b27123/src/js/math.js#L217
+ var length = arguments.length;
+ var args = [];
+ var max = 0;
+ for (var i = 0; i < length; i++) {
+ var n = arguments[i];
+ n = +n;
+ if (n === Infinity || n === -Infinity) {
+ return Infinity;
+ }
+ n = Math.abs(n);
+ if (n > max) {
+ max = n;
+ }
+ args[i] = n;
+ }
+
+ if (max === 0) {
+ max = 1;
+ }
+ var sum = 0;
+ var compensation = 0;
+ for (var j = 0; j < length; j++) {
+ var m = args[j] / max;
+ var summand = m * m - compensation;
+ var preliminary = sum + summand;
+ compensation = (preliminary - sum) - summand;
+ sum = preliminary;
+ }
+ return Math.sqrt(sum) * max;
+}
+
+module.exports = p5;
+
+},{"../core/core":42}],69:[function(_dereq_,module,exports){
+/**
+ * @module Math
+ * @submodule Math
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+
+/**
+ * Creates a new p5.Vector (the datatype for storing vectors). This provides a
+ * two or three dimensional vector, specifically a Euclidean (also known as
+ * geometric) vector. A vector is an entity that has both magnitude and
+ * direction.
+ *
+ * @method createVector
+ * @param {Number} [x] x component of the vector
+ * @param {Number} [y] y component of the vector
+ * @param {Number} [z] z component of the vector
+ */
+p5.prototype.createVector = function (x, y, z) {
+ if (this instanceof p5) {
+ return new p5.Vector(this, arguments);
+ } else {
+ return new p5.Vector(x, y, z);
+ }
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],70:[function(_dereq_,module,exports){
+//////////////////////////////////////////////////////////////
+
+// http://mrl.nyu.edu/~perlin/noise/
+// Adapting from PApplet.java
+// which was adapted from toxi
+// which was adapted from the german demo group farbrausch
+// as used in their demo "art": http://www.farb-rausch.de/fr010src.zip
+
+// someday we might consider using "improved noise"
+// http://mrl.nyu.edu/~perlin/paper445.pdf
+// See: https://github.com/shiffman/The-Nature-of-Code-Examples-p5.js/
+// blob/master/introduction/Noise1D/noise.js
+
+/**
+ * @module Math
+ * @submodule Noise
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+var PERLIN_YWRAPB = 4;
+var PERLIN_YWRAP = 1<random() function.
+ * It was invented by Ken Perlin in the 1980s and been used since in
+ * graphical applications to produce procedural textures, natural motion,
+ * shapes, terrains etc.
The main difference to the
+ * random() function is that Perlin noise is defined in an infinite
+ * n-dimensional space where each pair of coordinates corresponds to a
+ * fixed semi-random value (fixed only for the lifespan of the program; see
+ * the noiseSeed() function). p5.js can compute 1D, 2D and 3D noise,
+ * depending on the number of coordinates given. The resulting value will
+ * always be between 0.0 and 1.0. The noise value can be animated by moving
+ * through the noise space as demonstrated in the example above. The 2nd
+ * and 3rd dimension can also be interpreted as time.
The actual
+ * noise is structured similar to an audio signal, in respect to the
+ * function's use of frequencies. Similar to the concept of harmonics in
+ * physics, perlin noise is computed over several octaves which are added
+ * together for the final result.
Another way to adjust the
+ * character of the resulting sequence is the scale of the input
+ * coordinates. As the function works within an infinite space the value of
+ * the coordinates doesn't matter as such, only the distance between
+ * successive coordinates does (eg. when using noise() within a
+ * loop). As a general rule the smaller the difference between coordinates,
+ * the smoother the resulting noise sequence will be. Steps of 0.005-0.03
+ * work best for most applications, but this will differ depending on use.
+ *
+ *
+ * @method noise
+ * @param {Number} x x-coordinate in noise space
+ * @param {Number} y y-coordinate in noise space
+ * @param {Number} z z-coordinate in noise space
+ * @return {Number} Perlin noise value (between 0 and 1) at specified
+ * coordinates
+ * @example
+ *
+ * var xoff = 0.0;
+ *
+ * function draw() {
+ * background(204);
+ * xoff = xoff + .01;
+ * var n = noise(xoff) * width;
+ * line(n, 0, n, height);
+ * }
+ *
+ *
+ *
+ * var noiseScale=0.02;
+ *
+ * function draw() {
+ * background(0);
+ * for (var x=0; x < width; x++) {
+ * var noiseVal = noise((mouseX+x)*noiseScale, mouseY*noiseScale);
+ * stroke(noiseVal*255);
+ * line(x, mouseY+noiseVal*80, x, height);
+ * }
+ * }
+ *
+ *
+ *
+ * @alt
+ * vertical line moves left to right with updating noise values.
+ * horizontal wave pattern effected by mouse x-position & updating noise values.
+ *
+ */
+
+p5.prototype.noise = function(x,y,z) {
+ y = y || 0;
+ z = z || 0;
+
+ if (perlin == null) {
+ perlin = new Array(PERLIN_SIZE + 1);
+ for (var i = 0; i < PERLIN_SIZE + 1; i++) {
+ perlin[i] = Math.random();
+ }
+ }
+
+ if (x<0) { x=-x; }
+ if (y<0) { y=-y; }
+ if (z<0) { z=-z; }
+
+ var xi=Math.floor(x), yi=Math.floor(y), zi=Math.floor(z);
+ var xf = x - xi;
+ var yf = y - yi;
+ var zf = z - zi;
+ var rxf, ryf;
+
+ var r=0;
+ var ampl=0.5;
+
+ var n1,n2,n3;
+
+ for (var o=0; o=1.0) { xi++; xf--; }
+ if (yf>=1.0) { yi++; yf--; }
+ if (zf>=1.0) { zi++; zf--; }
+ }
+ return r;
+};
+
+
+/**
+ *
+ * Adjusts the character and level of detail produced by the Perlin noise
+ * function. Similar to harmonics in physics, noise is computed over
+ * several octaves. Lower octaves contribute more to the output signal and
+ * as such define the overall intensity of the noise, whereas higher octaves
+ * create finer grained details in the noise sequence.
+ *
+ * By default, noise is computed over 4 octaves with each octave contributing
+ * exactly half than its predecessor, starting at 50% strength for the 1st
+ * octave. This falloff amount can be changed by adding an additional function
+ * parameter. Eg. a falloff factor of 0.75 means each octave will now have
+ * 75% impact (25% less) of the previous lower octave. Any value between
+ * 0.0 and 1.0 is valid, however note that values greater than 0.5 might
+ * result in greater than 1.0 values returned by noise().
+ *
+ * By changing these parameters, the signal created by the noise()
+ * function can be adapted to fit very specific needs and characteristics.
+ *
+ * @method noiseDetail
+ * @param {Number} lod number of octaves to be used by the noise
+ * @param {Number} falloff falloff factor for each octave
+ * @example
+ *
+ *
+ * @alt
+ * 2 vertical grey smokey patterns affected my mouse x-position and noise.
+ *
+ */
+p5.prototype.noiseDetail = function(lod, falloff) {
+ if (lod>0) { perlin_octaves=lod; }
+ if (falloff>0) { perlin_amp_falloff=falloff; }
+};
+
+/**
+ * Sets the seed value for noise(). By default, noise()
+ * produces different results each time the program is run. Set the
+ * value parameter to a constant to return the same pseudo-random
+ * numbers each time the software is run.
+ *
+ * @method noiseSeed
+ * @param {Number} seed the seed value
+ * @example
+ *
+ * var xoff = 0.0;
+ *
+ * function setup() {
+ * noiseSeed(99);
+ * stroke(0, 10);
+ * }
+ *
+ * function draw() {
+ * xoff = xoff + .01;
+ * var n = noise(xoff) * width;
+ * line(n, 0, n, height);
+ * }
+ *
+ *
+ *
+ * @alt
+ * vertical grey lines drawing in pattern affected by noise.
+ *
+ */
+p5.prototype.noiseSeed = function(seed) {
+ // Linear Congruential Generator
+ // Variant of a Lehman Generator
+ var lcg = (function() {
+ // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes
+ // m is basically chosen to be large (as it is the max period)
+ // and for its relationships to a and c
+ var m = 4294967296,
+ // a - 1 should be divisible by m's prime factors
+ a = 1664525,
+ // c and m should be co-prime
+ c = 1013904223,
+ seed, z;
+ return {
+ setSeed : function(val) {
+ // pick a random seed if val is undefined or null
+ // the >>> 0 casts the seed to an unsigned 32-bit integer
+ z = seed = (val == null ? Math.random() * m : val) >>> 0;
+ },
+ getSeed : function() {
+ return seed;
+ },
+ rand : function() {
+ // define the recurrence relationship
+ z = (a * z + c) % m;
+ // return a float in [0, 1)
+ // if z = m then z / m = 0 therefore (z % m) / m < 1 always
+ return z / m;
+ }
+ };
+ }());
+
+ lcg.setSeed(seed);
+ perlin = new Array(PERLIN_SIZE + 1);
+ for (var i = 0; i < PERLIN_SIZE + 1; i++) {
+ perlin[i] = lcg.rand();
+ }
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],71:[function(_dereq_,module,exports){
+/**
+ * @module Math
+ * @submodule Math
+ * @requires constants
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+var polarGeometry = _dereq_('./polargeometry');
+var constants = _dereq_('../core/constants');
+
+/**
+ * A class to describe a two or three dimensional vector, specifically
+ * a Euclidean (also known as geometric) vector. A vector is an entity
+ * that has both magnitude and direction. The datatype, however, stores
+ * the components of the vector (x, y for 2D, and x, y, z for 3D). The magnitude
+ * and direction can be accessed via the methods mag() and heading().
+ *
+ * In many of the p5.js examples, you will see p5.Vector used to describe a
+ * position, velocity, or acceleration. For example, if you consider a rectangle
+ * moving across the screen, at any given instant it has a position (a vector
+ * that points from the origin to its location), a velocity (the rate at which
+ * the object's position changes per time unit, expressed as a vector), and
+ * acceleration (the rate at which the object's velocity changes per time
+ * unit, expressed as a vector).
+ *
+ * Since vectors represent groupings of values, we cannot simply use
+ * traditional addition/multiplication/etc. Instead, we'll need to do some
+ * "vector" math, which is made easy by the methods inside the p5.Vector class.
+ *
+ * @class p5.Vector
+ * @constructor
+ * @param {Number} [x] x component of the vector
+ * @param {Number} [y] y component of the vector
+ * @param {Number} [z] z component of the vector
+ * @example
+ *
+ *
+ * @alt
+ * 2 white ellipses. One center-left the other bottom right and off canvas
+ *
+ */
+p5.Vector = function() {
+ var x,y,z;
+ // This is how it comes in with createVector()
+ if(arguments[0] instanceof p5) {
+ // save reference to p5 if passed in
+ this.p5 = arguments[0];
+ x = arguments[1][0] || 0;
+ y = arguments[1][1] || 0;
+ z = arguments[1][2] || 0;
+ // This is what we'll get with new p5.Vector()
+ } else {
+ x = arguments[0] || 0;
+ y = arguments[1] || 0;
+ z = arguments[2] || 0;
+ }
+ /**
+ * The x component of the vector
+ * @property x
+ * @type {Number}
+ */
+ this.x = x;
+ /**
+ * The y component of the vector
+ * @property y
+ * @type {Number}
+ */
+ this.y = y;
+ /**
+ * The z component of the vector
+ * @property z
+ * @type {Number}
+ */
+ this.z = z;
+};
+
+/**
+ * Returns a string representation of a vector v by calling String(v)
+ * or v.toString(). This method is useful for logging vectors in the
+ * console.
+ * @method toString
+ * @example
+ *
+ * function setup() {
+ * var v = createVector(20,30);
+ * print(String(v)); // prints "p5.Vector Object : [20, 30, 0]"
+ * }
+ *
+ *
+ */
+p5.Vector.prototype.toString = function p5VectorToString() {
+ return 'p5.Vector Object : ['+ this.x +', '+ this.y +', '+ this.z + ']';
+};
+
+/**
+ * Sets the x, y, and z component of the vector using two or three separate
+ * variables, the data from a p5.Vector, or the values from a float array.
+ * @method set
+ *
+ * @param {Number|p5.Vector|Array} [x] the x component of the vector or a
+ * p5.Vector or an Array
+ * @param {Number} [y] the y component of the vector
+ * @param {Number} [z] the z component of the vector
+ * @example
+ *
+ *
+ * function setup() {
+ * var v = createVector(1, 2, 3);
+ * v.set(4,5,6); // Sets vector to [4, 5, 6]
+ *
+ * var v1 = createVector(0, 0, 0);
+ * var arr = [1, 2, 3];
+ * v1.set(arr); // Sets vector to [1, 2, 3]
+ * }
+ *
+ *
+ */
+p5.Vector.prototype.set = function (x, y, z) {
+ if (x instanceof p5.Vector) {
+ this.x = x.x || 0;
+ this.y = x.y || 0;
+ this.z = x.z || 0;
+ return this;
+ }
+ if (x instanceof Array) {
+ this.x = x[0] || 0;
+ this.y = x[1] || 0;
+ this.z = x[2] || 0;
+ return this;
+ }
+ this.x = x || 0;
+ this.y = y || 0;
+ this.z = z || 0;
+ return this;
+};
+
+/**
+ * Gets a copy of the vector, returns a p5.Vector object.
+ *
+ * @method copy
+ * @return {p5.Vector} the copy of the p5.Vector object
+ * @example
+ *
+ */
+p5.Vector.prototype.copy = function () {
+ if (this.p5) {
+ return new p5.Vector(this.p5,[this.x, this.y, this.z]);
+ } else {
+ return new p5.Vector(this.x,this.y,this.z);
+ }
+};
+
+/**
+ * Adds x, y, and z components to a vector, adds one vector to another, or
+ * adds two independent vectors together. The version of the method that adds
+ * two vectors together is a static method and returns a p5.Vector, the others
+ * acts directly on the vector. See the examples for more context.
+ *
+ * @method add
+ * @chainable
+ * @param {Number|p5.Vector|Array} x the x component of the vector to be
+ * added or a p5.Vector or an Array
+ * @param {Number} [y] the y component of the vector to be
+ * added
+ * @param {Number} [z] the z component of the vector to be
+ * added
+ * @return {p5.Vector} the p5.Vector object.
+ * @example
+ *
+ *
+ * var v = createVector(1, 2, 3);
+ * v.add(4,5,6);
+ * // v's components are set to [5, 7, 9]
+ *
+ *
+ */
+p5.Vector.prototype.add = function (x, y, z) {
+ if (x instanceof p5.Vector) {
+ this.x += x.x || 0;
+ this.y += x.y || 0;
+ this.z += x.z || 0;
+ return this;
+ }
+ if (x instanceof Array) {
+ this.x += x[0] || 0;
+ this.y += x[1] || 0;
+ this.z += x[2] || 0;
+ return this;
+ }
+ this.x += x || 0;
+ this.y += y || 0;
+ this.z += z || 0;
+ return this;
+};
+
+/**
+ * Subtracts x, y, and z components from a vector, subtracts one vector from
+ * another, or subtracts two independent vectors. The version of the method
+ * that subtracts two vectors is a static method and returns a p5.Vector, the
+ * other acts directly on the vector. See the examples for more context.
+ *
+ * @method sub
+ * @chainable
+ * @param {Number|p5.Vector|Array} x the x component of the vector or a
+ * p5.Vector or an Array
+ * @param {Number} [y] the y component of the vector
+ * @param {Number} [z] the z component of the vector
+ * @return {p5.Vector} p5.Vector object.
+ * @example
+ *
+ *
+ * var v = createVector(4, 5, 6);
+ * v.sub(1, 1, 1);
+ * // v's components are set to [3, 4, 5]
+ *
+ *
+ */
+p5.Vector.prototype.sub = function (x, y, z) {
+ if (x instanceof p5.Vector) {
+ this.x -= x.x || 0;
+ this.y -= x.y || 0;
+ this.z -= x.z || 0;
+ return this;
+ }
+ if (x instanceof Array) {
+ this.x -= x[0] || 0;
+ this.y -= x[1] || 0;
+ this.z -= x[2] || 0;
+ return this;
+ }
+ this.x -= x || 0;
+ this.y -= y || 0;
+ this.z -= z || 0;
+ return this;
+};
+
+/**
+ * Multiply the vector by a scalar. The static version of this method
+ * creates a new p5.Vector while the non static version acts on the vector
+ * directly. See the examples for more context.
+ *
+ * @method mult
+ * @chainable
+ * @param {Number} n the number to multiply with the vector
+ * @return {p5.Vector} a reference to the p5.Vector object (allow chaining)
+ * @example
+ *
+ *
+ * var v = createVector(1, 2, 3);
+ * v.mult(2);
+ * // v's components are set to [2, 4, 6]
+ *
+ *
+ */
+p5.Vector.prototype.mult = function (n) {
+ this.x *= n || 0;
+ this.y *= n || 0;
+ this.z *= n || 0;
+ return this;
+};
+
+/**
+ * Divide the vector by a scalar. The static version of this method creates a
+ * new p5.Vector while the non static version acts on the vector directly.
+ * See the examples for more context.
+ *
+ * @method div
+ * @chainable
+ * @param {number} n the number to divide the vector by
+ * @return {p5.Vector} a reference to the p5.Vector object (allow chaining)
+ * @example
+ *
+ *
+ * var v = createVector(6, 4, 2);
+ * v.div(2); //v's components are set to [3, 2, 1]
+ *
+ *
+ */
+p5.Vector.prototype.div = function (n) {
+ this.x /= n;
+ this.y /= n;
+ this.z /= n;
+ return this;
+};
+
+/**
+ * Calculates the magnitude (length) of the vector and returns the result as
+ * a float (this is simply the equation sqrt(x*x + y*y + z*z).)
+ *
+ * @method mag
+ * @return {Number} magnitude of the vector
+ * @example
+ *
+ *
+ * var v = createVector(20.0, 30.0, 40.0);
+ * var m = v.mag();
+ * print(m); // Prints "53.85164807134504"
+ *
+ *
+ */
+p5.Vector.prototype.mag = function () {
+ return Math.sqrt(this.magSq());
+};
+
+/**
+ * Calculates the squared magnitude of the vector and returns the result
+ * as a float (this is simply the equation (x*x + y*y + z*z).)
+ * Faster if the real length is not required in the
+ * case of comparing vectors, etc.
+ *
+ * @method magSq
+ * @return {number} squared magnitude of the vector
+ * @example
+ *
+ */
+p5.Vector.prototype.magSq = function () {
+ var x = this.x, y = this.y, z = this.z;
+ return (x * x + y * y + z * z);
+};
+
+/**
+ * Calculates the dot product of two vectors. The version of the method
+ * that computes the dot product of two independent vectors is a static
+ * method. See the examples for more context.
+ *
+ *
+ * @method dot
+ * @param {Number|p5.Vector} x x component of the vector or a p5.Vector
+ * @param {Number} [y] y component of the vector
+ * @param {Number} [z] z component of the vector
+ * @return {Number} the dot product
+ *
+ * @example
+ *
+ *
+ * var v1 = createVector(1, 2, 3);
+ * var v2 = createVector(2, 3, 4);
+ *
+ * print(v1.dot(v2)); // Prints "20"
+ *
+ *
+ */
+p5.Vector.prototype.dot = function (x, y, z) {
+ if (x instanceof p5.Vector) {
+ return this.dot(x.x, x.y, x.z);
+ }
+ return this.x * (x || 0) +
+ this.y * (y || 0) +
+ this.z * (z || 0);
+};
+
+/**
+ * Calculates and returns a vector composed of the cross product between
+ * two vectors. Both the static and non static methods return a new p5.Vector.
+ * See the examples for more context.
+ *
+ * @method cross
+ * @param {p5.Vector} v p5.Vector to be crossed
+ * @return {p5.Vector} p5.Vector composed of cross product
+ * @example
+ *
+ */
+p5.Vector.prototype.cross = function (v) {
+ var x = this.y * v.z - this.z * v.y;
+ var y = this.z * v.x - this.x * v.z;
+ var z = this.x * v.y - this.y * v.x;
+ if (this.p5) {
+ return new p5.Vector(this.p5,[x,y,z]);
+ } else {
+ return new p5.Vector(x,y,z);
+ }
+};
+
+/**
+ * Calculates the Euclidean distance between two points (considering a
+ * point as a vector object).
+ *
+ * @method dist
+ * @param {p5.Vector} v the x, y, and z coordinates of a p5.Vector
+ * @return {Number} the distance
+ * @example
+ *
+ *
+ * var v1 = createVector(1, 0, 0);
+ * var v2 = createVector(0, 1, 0);
+ *
+ * var distance = v1.dist(v2); // distance is 1.4142...
+ *
+ *
+ */
+p5.Vector.prototype.dist = function (v) {
+ var d = v.copy().sub(this);
+ return d.mag();
+};
+
+/**
+ * Normalize the vector to length 1 (make it a unit vector).
+ *
+ * @method normalize
+ * @return {p5.Vector} normalized p5.Vector
+ * @example
+ *
+ *
+ * var v = createVector(10, 20, 2);
+ * // v has components [10.0, 20.0, 2.0]
+ * v.normalize();
+ * // v's components are set to
+ * // [0.4454354, 0.8908708, 0.089087084]
+ *
+ *
+ *
+ */
+p5.Vector.prototype.normalize = function () {
+ return this.mag() === 0 ? this : this.div(this.mag());
+};
+
+/**
+ * Limit the magnitude of this vector to the value used for the max
+ * parameter.
+ *
+ * @method limit
+ * @param {Number} max the maximum magnitude for the vector
+ * @return {p5.Vector} the modified p5.Vector
+ * @example
+ *
+ *
+ * var v = createVector(10, 20, 2);
+ * // v has components [10.0, 20.0, 2.0]
+ * v.limit(5);
+ * // v's components are set to
+ * // [2.2271771, 4.4543543, 0.4454354]
+ *
+ *
+ */
+p5.Vector.prototype.limit = function (max) {
+ var mSq = this.magSq();
+ if(mSq > max*max) {
+ this.div(Math.sqrt(mSq)); //normalize it
+ this.mult(max);
+ }
+ return this;
+};
+
+/**
+ * Set the magnitude of this vector to the value used for the len
+ * parameter.
+ *
+ * @method setMag
+ * @param {number} len the new length for this vector
+ * @return {p5.Vector} the modified p5.Vector
+ * @example
+ *
+ *
+ * var v = createVector(10, 20, 2);
+ * // v has components [10.0, 20.0, 2.0]
+ * v.setMag(10);
+ * // v's components are set to [6.0, 8.0, 0.0]
+ *
+ *
+ */
+p5.Vector.prototype.setMag = function (n) {
+ return this.normalize().mult(n);
+};
+
+/**
+ * Calculate the angle of rotation for this vector (only 2D vectors)
+ *
+ * @method heading
+ * @return {Number} the angle of rotation
+ * @example
+ *
+ */
+p5.Vector.prototype.heading = function () {
+ var h = Math.atan2(this.y, this.x);
+ if (this.p5) {
+ if (this.p5._angleMode === constants.RADIANS) {
+ return h;
+ } else {
+ return polarGeometry.radiansToDegrees(h);
+ }
+ } else {
+ return h;
+ }
+};
+
+/**
+ * Rotate the vector by an angle (only 2D vectors), magnitude remains the
+ * same
+ *
+ * @method rotate
+ * @param {number} angle the angle of rotation
+ * @return {p5.Vector} the modified p5.Vector
+ * @example
+ *
+ *
+ * var v = createVector(10.0, 20.0);
+ * // v has components [10.0, 20.0, 0.0]
+ * v.rotate(HALF_PI);
+ * // v's components are set to [-20.0, 9.999999, 0.0]
+ *
+ *
+ */
+p5.Vector.prototype.rotate = function (a) {
+ var newHeading = this.heading() + a;
+ if (this.p5) {
+ if (this.p5._angleMode === constants.DEGREES) {
+ newHeading = polarGeometry.degreesToRadians(newHeading);
+ }
+ }
+ var mag = this.mag();
+ this.x = Math.cos(newHeading) * mag;
+ this.y = Math.sin(newHeading) * mag;
+ return this;
+};
+
+/**
+ * Linear interpolate the vector to another vector
+ *
+ * @method lerp
+ * @param {p5.Vector} x the x component or the p5.Vector to lerp to
+ * @param {p5.Vector} [y] y the y component
+ * @param {p5.Vector} [z] z the z component
+ * @param {Number} amt the amount of interpolation; some value between 0.0
+ * (old vector) and 1.0 (new vector). 0.1 is very near
+ * the new vector. 0.5 is halfway in between.
+ * @return {p5.Vector} the modified p5.Vector
+ * @example
+ *
+ *
+ * var v = createVector(1, 1, 0);
+ *
+ * v.lerp(3, 3, 0, 0.5); // v now has components [2,2,0]
+ *
+ *
+ *
+ *
+ *
+ * var v1 = createVector(0, 0, 0);
+ * var v2 = createVector(100, 100, 0);
+ *
+ * var v3 = p5.Vector.lerp(v1, v2, 0.5);
+ * // v3 has components [50,50,0]
+ *
+ *
+ */
+p5.Vector.prototype.lerp = function (x, y, z, amt) {
+ if (x instanceof p5.Vector) {
+ return this.lerp(x.x, x.y, x.z, y);
+ }
+ this.x += (x - this.x) * amt || 0;
+ this.y += (y - this.y) * amt || 0;
+ this.z += (z - this.z) * amt || 0;
+ return this;
+};
+
+/**
+ * Return a representation of this vector as a float array. This is only
+ * for temporary use. If used in any other fashion, the contents should be
+ * copied by using the p5.Vector.copy() method to copy into your own
+ * array.
+ *
+ * @method array
+ * @return {Array} an Array with the 3 values
+ * @example
+ *
+ * function setup() {
+ * var v = createVector(20,30);
+ * print(v.array()); // Prints : Array [20, 30, 0]
+ * }
+ *
+ *
+ *
+ * var v = createVector(10.0, 20.0, 30.0);
+ * var f = v.array();
+ * print(f[0]); // Prints "10.0"
+ * print(f[1]); // Prints "20.0"
+ * print(f[2]); // Prints "30.0"
+ *
+ *
+ */
+p5.Vector.prototype.array = function () {
+ return [this.x || 0, this.y || 0, this.z || 0];
+};
+
+/**
+ * Equality check against a p5.Vector
+ *
+ * @method equals
+ * @param {Number|p5.Vector|Array} [x] the x component of the vector or a
+ * p5.Vector or an Array
+ * @param {Number} [y] the y component of the vector
+ * @param {Number} [z] the z component of the vector
+ * @return {Boolean} whether the vectors are equals
+ * @example
+ *
+ */
+p5.Vector.prototype.equals = function (x, y, z) {
+ var a, b, c;
+ if (x instanceof p5.Vector) {
+ a = x.x || 0;
+ b = x.y || 0;
+ c = x.z || 0;
+ } else if (x instanceof Array) {
+ a = x[0] || 0;
+ b = x[1] || 0;
+ c = x[2] || 0;
+ } else {
+ a = x || 0;
+ b = y || 0;
+ c = z || 0;
+ }
+ return this.x === a && this.y === b && this.z === c;
+};
+
+
+// Static Methods
+
+
+/**
+ * Make a new 2D unit vector from an angle
+ *
+ * @method fromAngle
+ * @static
+ * @param {Number} angle the desired angle
+ * @return {p5.Vector} the new p5.Vector object
+ * @example
+ *
+ *
+ * function draw() {
+ * background (200);
+ *
+ * // Create a variable, proportional to the mouseX,
+ * // varying from 0-360, to represent an angle in degrees.
+ * angleMode(DEGREES);
+ * var myDegrees = map(mouseX, 0,width, 0,360);
+ *
+ * // Display that variable in an onscreen text.
+ * // (Note the nfc() function to truncate additional decimal places,
+ * // and the "\xB0" character for the degree symbol.)
+ * var readout = "angle = " + nfc(myDegrees,1,1) + "\xB0"
+ * noStroke();
+ * fill (0);
+ * text (readout, 5, 15);
+ *
+ * // Create a p5.Vector using the fromAngle function,
+ * // and extract its x and y components.
+ * var v = p5.Vector.fromAngle(radians(myDegrees));
+ * var vx = v.x;
+ * var vy = v.y;
+ *
+ * push();
+ * translate (width/2, height/2);
+ * noFill();
+ * stroke (150);
+ * line (0,0, 30,0);
+ * stroke (0);
+ * line (0,0, 30*vx, 30*vy);
+ * pop()
+ * }
+ *
+ *
+ */
+p5.Vector.fromAngle = function(angle) {
+ if (this.p5) {
+ if (this.p5._angleMode === constants.DEGREES) {
+ angle = polarGeometry.degreesToRadians(angle);
+ }
+ }
+ if (this.p5) {
+ return new p5.Vector(this.p5,[Math.cos(angle),Math.sin(angle),0]);
+ } else {
+ return new p5.Vector(Math.cos(angle),Math.sin(angle),0);
+ }
+};
+
+/**
+ * Make a new 2D unit vector from a random angle
+ *
+ * @method random2D
+ * @static
+ * @return {p5.Vector} the new p5.Vector object
+ * @example
+ *
+ *
+ * var v = p5.Vector.random2D();
+ * // May make v's attributes something like:
+ * // [0.61554617, -0.51195765, 0.0] or
+ * // [-0.4695841, -0.14366731, 0.0] or
+ * // [0.6091097, -0.22805278, 0.0]
+ *
+ *
+ */
+p5.Vector.random2D = function () {
+ var angle;
+ // A lot of nonsense to determine if we know about a
+ // p5 sketch and whether we should make a random angle in degrees or radians
+ if (this.p5) {
+ if (this.p5._angleMode === constants.DEGREES) {
+ angle = this.p5.random(360);
+ } else {
+ angle = this.p5.random(constants.TWO_PI);
+ }
+ } else {
+ angle = Math.random()*Math.PI*2;
+ }
+ return this.fromAngle(angle);
+};
+
+/**
+ * Make a new random 3D unit vector.
+ *
+ * @method random3D
+ * @static
+ * @return {p5.Vector} the new p5.Vector object
+ * @example
+ *
+ *
+ * var v = p5.Vector.random3D();
+ * // May make v's attributes something like:
+ * // [0.61554617, -0.51195765, 0.599168] or
+ * // [-0.4695841, -0.14366731, -0.8711202] or
+ * // [0.6091097, -0.22805278, -0.7595902]
+ *
+ *
+ */
+p5.Vector.random3D = function () {
+ var angle,vz;
+ // If we know about p5
+ if (this.p5) {
+ angle = this.p5.random(0,constants.TWO_PI);
+ vz = this.p5.random(-1,1);
+ } else {
+ angle = Math.random()*Math.PI*2;
+ vz = Math.random()*2-1;
+ }
+ var vx = Math.sqrt(1-vz*vz)*Math.cos(angle);
+ var vy = Math.sqrt(1-vz*vz)*Math.sin(angle);
+ if (this.p5) {
+ return new p5.Vector(this.p5,[vx,vy,vz]);
+ } else {
+ return new p5.Vector(vx,vy,vz);
+ }
+};
+
+
+/**
+ * Adds two vectors together and returns a new one.
+ *
+ * @static
+ * @param {p5.Vector} v1 a p5.Vector to add
+ * @param {p5.Vector} v2 a p5.Vector to add
+ * @param {p5.Vector} target if undefined a new vector will be created
+ * @return {p5.Vector} the resulting p5.Vector
+ *
+ */
+
+p5.Vector.add = function (v1, v2, target) {
+ if (!target) {
+ target = v1.copy();
+ } else {
+ target.set(v1);
+ }
+ target.add(v2);
+ return target;
+};
+
+/**
+ * Subtracts one p5.Vector from another and returns a new one. The second
+ * vector (v2) is subtracted from the first (v1), resulting in v1-v2.
+ *
+ * @static
+ * @param {p5.Vector} v1 a p5.Vector to subtract from
+ * @param {p5.Vector} v2 a p5.Vector to subtract
+ * @param {p5.Vector} target if undefined a new vector will be created
+ * @return {p5.Vector} the resulting p5.Vector
+ */
+
+p5.Vector.sub = function (v1, v2, target) {
+ if (!target) {
+ target = v1.copy();
+ } else {
+ target.set(v1);
+ }
+ target.sub(v2);
+ return target;
+};
+
+
+/**
+ * Multiplies a vector by a scalar and returns a new vector.
+ *
+ * @static
+ * @param {p5.Vector} v the p5.Vector to multiply
+ * @param {Number} n the scalar
+ * @param {p5.Vector} target if undefined a new vector will be created
+ * @return {p5.Vector} the resulting new p5.Vector
+ */
+p5.Vector.mult = function (v, n, target) {
+ if (!target) {
+ target = v.copy();
+ } else {
+ target.set(v);
+ }
+ target.mult(n);
+ return target;
+};
+
+/**
+ * Divides a vector by a scalar and returns a new vector.
+ *
+ * @static
+ * @param {p5.Vector} v the p5.Vector to divide
+ * @param {Number} n the scalar
+ * @param {p5.Vector} target if undefined a new vector will be created
+ * @return {p5.Vector} the resulting new p5.Vector
+ */
+p5.Vector.div = function (v, n, target) {
+ if (!target) {
+ target = v.copy();
+ } else {
+ target.set(v);
+ }
+ target.div(n);
+ return target;
+};
+
+
+/**
+ * Calculates the dot product of two vectors.
+ *
+ * @static
+ * @param {p5.Vector} v1 the first p5.Vector
+ * @param {p5.Vector} v2 the second p5.Vector
+ * @return {Number} the dot product
+ */
+p5.Vector.dot = function (v1, v2) {
+ return v1.dot(v2);
+};
+
+/**
+ * Calculates the cross product of two vectors.
+ *
+ * @static
+ * @param {p5.Vector} v1 the first p5.Vector
+ * @param {p5.Vector} v2 the second p5.Vector
+ * @return {Number} the cross product
+ */
+p5.Vector.cross = function (v1, v2) {
+ return v1.cross(v2);
+};
+
+/**
+ * Calculates the Euclidean distance between two points (considering a
+ * point as a vector object).
+ *
+ * @static
+ * @param {p5.Vector} v1 the first p5.Vector
+ * @param {p5.Vector} v2 the second p5.Vector
+ * @return {Number} the distance
+ */
+p5.Vector.dist = function (v1,v2) {
+ return v1.dist(v2);
+};
+
+/**
+ * Linear interpolate a vector to another vector and return the result as a
+ * new vector.
+ *
+ * @static
+ * @param {p5.Vector} v1 a starting p5.Vector
+ * @param {p5.Vector} v2 the p5.Vector to lerp to
+ * @param {Number} the amount of interpolation; some value between 0.0
+ * (old vector) and 1.0 (new vector). 0.1 is very near
+ * the new vector. 0.5 is halfway in between.
+ */
+p5.Vector.lerp = function (v1, v2, amt, target) {
+ if (!target) {
+ target = v1.copy();
+ } else {
+ target.set(v1);
+ }
+ target.lerp(v2, amt);
+ return target;
+};
+
+/**
+ * Calculates and returns the angle (in radians) between two vectors.
+ * @method angleBetween
+ * @static
+ * @param {p5.Vector} v1 the x, y, and z components of a p5.Vector
+ * @param {p5.Vector} v2 the x, y, and z components of a p5.Vector
+ * @return {Number} the angle between (in radians)
+ * @example
+ *
+ *
+ * var v1 = createVector(1, 0, 0);
+ * var v2 = createVector(0, 1, 0);
+ *
+ * var angle = p5.Vector.angleBetween(v1, v2);
+ * // angle is PI/2
+ *
+ *
+ */
+p5.Vector.angleBetween = function (v1, v2) {
+ var angle = Math.acos(v1.dot(v2) / (v1.mag() * v2.mag()));
+ if (this.p5) {
+ if (this.p5._angleMode === constants.DEGREES) {
+ angle = polarGeometry.radiansToDegrees(angle);
+ }
+ }
+ return angle;
+};
+
+/**
+ * @static
+ */
+p5.Vector.mag = function (vecT){
+ var x = vecT.x,
+ y = vecT.y,
+ z = vecT.z;
+ var magSq = x * x + y * y + z * z;
+ return Math.sqrt(magSq);
+};
+
+module.exports = p5.Vector;
+
+},{"../core/constants":41,"../core/core":42,"./polargeometry":72}],72:[function(_dereq_,module,exports){
+
+module.exports = {
+
+ degreesToRadians: function(x) {
+ return 2 * Math.PI * x / 360;
+ },
+
+ radiansToDegrees: function(x) {
+ return 360 * x / (2 * Math.PI);
+ }
+
+};
+
+},{}],73:[function(_dereq_,module,exports){
+/**
+ * @module Math
+ * @submodule Random
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+var seeded = false;
+var previous = false;
+var y2 = 0;
+
+// Linear Congruential Generator
+// Variant of a Lehman Generator
+var lcg = (function() {
+ // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes
+ // m is basically chosen to be large (as it is the max period)
+ // and for its relationships to a and c
+ var m = 4294967296,
+ // a - 1 should be divisible by m's prime factors
+ a = 1664525,
+ // c and m should be co-prime
+ c = 1013904223,
+ seed, z;
+ return {
+ setSeed : function(val) {
+ // pick a random seed if val is undefined or null
+ // the >>> 0 casts the seed to an unsigned 32-bit integer
+ z = seed = (val == null ? Math.random() * m : val) >>> 0;
+ },
+ getSeed : function() {
+ return seed;
+ },
+ rand : function() {
+ // define the recurrence relationship
+ z = (a * z + c) % m;
+ // return a float in [0, 1)
+ // if z = m then z / m = 0 therefore (z % m) / m < 1 always
+ return z / m;
+ }
+ };
+}());
+
+/**
+ * Sets the seed value for random().
+ *
+ * By default, random() produces different results each time the program
+ * is run. Set the seed parameter to a constant to return the same
+ * pseudo-random numbers each time the software is run.
+ *
+ * @method randomSeed
+ * @param {Number} seed the seed value
+ * @example
+ *
+ *
+ * randomSeed(99);
+ * for (var i=0; i < 100; i++) {
+ * var r = random(0, 255);
+ * stroke(r);
+ * line(i, 0, i, 100);
+ * }
+ *
+ *
+ *
+ * @alt
+ * many vertical lines drawn in white, black or grey.
+ *
+ */
+p5.prototype.randomSeed = function(seed) {
+ lcg.setSeed(seed);
+ seeded = true;
+ previous = false;
+};
+
+/**
+ * Return a random floating-point number.
+ *
+ * Takes either 0, 1 or 2 arguments.
+ *
+ * If no argument is given, returns a random number from 0
+ * up to (but not including) 1.
+ *
+ * If one argument is given and it is a number, returns a random number from 0
+ * up to (but not including) the number.
+ *
+ * If one argument is given and it is an array, returns a random element from
+ * that array.
+ *
+ * If two arguments are given, returns a random number from the
+ * first argument up to (but not including) the second argument.
+ *
+ * @method random
+ * @param {Number} [min] the lower bound (inclusive)
+ * @param {Number} [max] the upper bound (exclusive)
+ * @return {Number} the random number
+ * @example
+ *
+ *
+ * for (var i = 0; i < 100; i++) {
+ * var r = random(50);
+ * stroke(r*5);
+ * line(50, i, 50+r, i);
+ * }
+ *
+ *
+ *
+ *
+ * for (var i = 0; i < 100; i++) {
+ * var r = random(-50, 50);
+ * line(50,i,50+r,i);
+ * }
+ *
+ *
+ *
+ *
+ * // Get a random element from an array using the random(Array) syntax
+ * var words = [ "apple", "bear", "cat", "dog" ];
+ * var word = random(words); // select random word
+ * text(word,10,50); // draw the word
+ *
+ *
+ *
+ * @alt
+ * 100 horizontal lines from center canvas to right. size+fill change each time
+ * 100 horizontal lines from center of canvas. height & side change each render
+ * word displayed at random. Either apple, bear, cat, or dog
+ *
+ */
+/**
+ * @method random
+ * @param {Array} choices the array to choose from
+ * @return {*} the random element from the array
+ * @example
+ */
+p5.prototype.random = function (min, max) {
+
+ var rand;
+
+ if (seeded) {
+ rand = lcg.rand();
+ } else {
+ rand = Math.random();
+ }
+ if (typeof min === 'undefined') {
+ return rand;
+ } else
+ if (typeof max === 'undefined') {
+ if (min instanceof Array) {
+ return min[Math.floor(rand * min.length)];
+ } else {
+ return rand * min;
+ }
+ } else {
+ if (min > max) {
+ var tmp = min;
+ min = max;
+ max = tmp;
+ }
+
+ return rand * (max-min) + min;
+ }
+};
+
+
+/**
+ *
+ * Returns a random number fitting a Gaussian, or
+ * normal, distribution. There is theoretically no minimum or maximum
+ * value that randomGaussian() might return. Rather, there is
+ * just a very low probability that values far from the mean will be
+ * returned; and a higher probability that numbers near the mean will
+ * be returned.
+ *
+ * Takes either 0, 1 or 2 arguments.
+ * If no args, returns a mean of 0 and standard deviation of 1.
+ * If one arg, that arg is the mean (standard deviation is 1).
+ * If two args, first is mean, second is standard deviation.
+ *
+ * @method randomGaussian
+ * @param {Number} mean the mean
+ * @param {Number} sd the standard deviation
+ * @return {Number} the random number
+ * @example
+ *
+ * for (var y = 0; y < 100; y++) {
+ * var x = randomGaussian(50,15);
+ * line(50, y, x, y);
+ *}
+ *
+ *
+ * @alt
+ * 100 horizontal lines from center of canvas. height & side change each render
+ * black lines radiate from center of canvas. size determined each render
+ */
+p5.prototype.randomGaussian = function(mean, sd) {
+ var y1,x1,x2,w;
+ if (previous) {
+ y1 = y2;
+ previous = false;
+ } else {
+ do {
+ x1 = this.random(2) - 1;
+ x2 = this.random(2) - 1;
+ w = x1 * x1 + x2 * x2;
+ } while (w >= 1);
+ w = Math.sqrt((-2 * Math.log(w))/w);
+ y1 = x1 * w;
+ y2 = x2 * w;
+ previous = true;
+ }
+
+ var m = mean || 0;
+ var s = sd || 1;
+ return y1*s + m;
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],74:[function(_dereq_,module,exports){
+/**
+ * @module Math
+ * @submodule Trigonometry
+ * @for p5
+ * @requires core
+ * @requires polargeometry
+ * @requires constants
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+var polarGeometry = _dereq_('./polargeometry');
+var constants = _dereq_('../core/constants');
+
+p5.prototype._angleMode = constants.RADIANS;
+
+/**
+ * The inverse of cos(), returns the arc cosine of a value. This function
+ * expects the values in the range of -1 to 1 and values are returned in
+ * the range 0 to PI (3.1415927).
+ *
+ * @method acos
+ * @param {Number} value the value whose arc cosine is to be returned
+ * @return {Number} the arc cosine of the given value
+ *
+ * @example
+ *
+ *
+ * var a = PI;
+ * var c = cos(a);
+ * var ac = acos(c);
+ * // Prints: "3.1415927 : -1.0 : 3.1415927"
+ * print(a + " : " + c + " : " + ac);
+ *
+ *
+ *
+ *
+ *
+ * var a = PI + PI/4.0;
+ * var c = cos(a);
+ * var ac = acos(c);
+ * // Prints: "3.926991 : -0.70710665 : 2.3561943"
+ * print(a + " : " + c + " : " + ac);
+ *
+ *
+ */
+p5.prototype.acos = function(ratio) {
+ if (this._angleMode === constants.RADIANS) {
+ return Math.acos(ratio);
+ } else {
+ return polarGeometry.radiansToDegrees(Math.acos(ratio));
+ }
+};
+
+/**
+ * The inverse of sin(), returns the arc sine of a value. This function
+ * expects the values in the range of -1 to 1 and values are returned
+ * in the range -PI/2 to PI/2.
+ *
+ * @method asin
+ * @param {Number} value the value whose arc sine is to be returned
+ * @return {Number} the arc sine of the given value
+ *
+ * @example
+ *
+ *
+ * var a = PI + PI/3;
+ * var s = sin(a);
+ * var as = asin(s);
+ * // Prints: "1.0471976 : 0.86602545 : 1.0471976"
+ * print(a + " : " + s + " : " + as);
+ *
+ *
+ *
+ *
+ *
+ * var a = PI + PI/3.0;
+ * var s = sin(a);
+ * var as = asin(s);
+ * // Prints: "4.1887903 : -0.86602545 : -1.0471976"
+ * print(a + " : " + s + " : " + as);
+ *
+ *
+ *
+ */
+p5.prototype.asin = function(ratio) {
+ if (this._angleMode === constants.RADIANS) {
+ return Math.asin(ratio);
+ } else {
+ return polarGeometry.radiansToDegrees(Math.asin(ratio));
+ }
+};
+
+/**
+ * The inverse of tan(), returns the arc tangent of a value. This function
+ * expects the values in the range of -Infinity to Infinity (exclusive) and
+ * values are returned in the range -PI/2 to PI/2.
+ *
+ * @method atan
+ * @param {Number} value the value whose arc tangent is to be returned
+ * @return {Number} the arc tangent of the given value
+ *
+ * @example
+ *
+ *
+ * var a = PI + PI/3;
+ * var t = tan(a);
+ * var at = atan(t);
+ * // Prints: "1.0471976 : 1.7320509 : 1.0471976"
+ * print(a + " : " + t + " : " + at);
+ *
+ *
+ *
+ *
+ *
+ * var a = PI + PI/3.0;
+ * var t = tan(a);
+ * var at = atan(t);
+ * // Prints: "4.1887903 : 1.7320513 : 1.0471977"
+ * print(a + " : " + t + " : " + at);
+ *
+ *
+ *
+ */
+p5.prototype.atan = function(ratio) {
+ if (this._angleMode === constants.RADIANS) {
+ return Math.atan(ratio);
+ } else {
+ return polarGeometry.radiansToDegrees(Math.atan(ratio));
+ }
+};
+
+/**
+ * Calculates the angle (in radians) from a specified point to the coordinate
+ * origin as measured from the positive x-axis. Values are returned as a
+ * float in the range from PI to -PI. The atan2() function is most often used
+ * for orienting geometry to the position of the cursor.
+ *
+ * Note: The y-coordinate of the point is the first parameter, and the
+ * x-coordinate is the second parameter, due the the structure of calculating
+ * the tangent.
+ *
+ * @method atan2
+ * @param {Number} y y-coordinate of the point
+ * @param {Number} x x-coordinate of the point
+ * @return {Number} the arc tangent of the given point
+ *
+ * @example
+ *
+ *
+ * @alt
+ * 60 by 10 rect at center of canvas rotates with mouse movements
+ *
+ */
+p5.prototype.atan2 = function (y, x) {
+ if (this._angleMode === constants.RADIANS) {
+ return Math.atan2(y, x);
+ } else {
+ return polarGeometry.radiansToDegrees(Math.atan2(y, x));
+ }
+};
+
+/**
+ * Calculates the cosine of an angle. This function takes into account the
+ * current angleMode. Values are returned in the range -1 to 1.
+ *
+ * @method cos
+ * @param {Number} angle the angle
+ * @return {Number} the cosine of the angle
+ *
+ * @example
+ *
+ *
+ * var a = 0.0;
+ * var inc = TWO_PI/25.0;
+ * for (var i = 0; i < 25; i++) {
+ * line(i*4, 50, i*4, 50+cos(a)*40.0);
+ * a = a + inc;
+ * }
+ *
+ *
+ *
+ * @alt
+ * vertical black lines form wave patterns, extend-down on left and right side
+ *
+ */
+p5.prototype.cos = function(angle) {
+ if (this._angleMode === constants.RADIANS) {
+ return Math.cos(angle);
+ } else {
+ return Math.cos(this.radians(angle));
+ }
+};
+
+/**
+ * Calculates the sine of an angle. This function takes into account the
+ * current angleMode. Values are returned in the range -1 to 1.
+ *
+ * @method sin
+ * @param {Number} angle the angle
+ * @return {Number} the sine of the angle
+ *
+ * @example
+ *
+ *
+ * var a = 0.0;
+ * var inc = TWO_PI/25.0;
+ * for (var i = 0; i < 25; i++) {
+ * line(i*4, 50, i*4, 50+sin(a)*40.0);
+ * a = a + inc;
+ * }
+ *
+ *
+ *
+ * @alt
+ * vertical black lines extend down and up from center to form wave pattern
+ *
+ */
+p5.prototype.sin = function(angle) {
+ if (this._angleMode === constants.RADIANS) {
+ return Math.sin(angle);
+ } else {
+ return Math.sin(this.radians(angle));
+ }
+};
+
+/**
+ * Calculates the tangent of an angle. This function takes into account
+ * the current angleMode. Values are returned in the range -1 to 1.
+ *
+ * @method tan
+ * @param {Number} angle the angle
+ * @return {Number} the tangent of the angle
+ *
+ * @example
+ *
+ *
+ * var a = 0.0;
+ * var inc = TWO_PI/50.0;
+ * for (var i = 0; i < 100; i = i+2) {
+ * line(i, 50, i, 50+tan(a)*2.0);
+ * a = a + inc;
+ * }
+ *
+ *
+ *
+ * @alt
+ * vertical black lines end down and up from center to form spike pattern
+ *
+ */
+p5.prototype.tan = function(angle) {
+ if (this._angleMode === constants.RADIANS) {
+ return Math.tan(angle);
+ } else {
+ return Math.tan(this.radians(angle));
+ }
+};
+
+/**
+ * Converts a radian measurement to its corresponding value in degrees.
+ * Radians and degrees are two ways of measuring the same thing. There are
+ * 360 degrees in a circle and 2*PI radians in a circle. For example,
+ * 90° = PI/2 = 1.5707964.
+ *
+ * @method degrees
+ * @param {Number} radians the radians value to convert to degrees
+ * @return {Number} the converted angle
+ *
+ *
+ * @example
+ *
+ *
+ * var rad = PI/4;
+ * var deg = degrees(rad);
+ * print(rad + " radians is " + deg + " degrees");
+ * // Prints: 0.7853981633974483 radians is 45 degrees
+ *
+ *
+ *
+ */
+p5.prototype.degrees = function(angle) {
+ return polarGeometry.radiansToDegrees(angle);
+};
+
+/**
+ * Converts a degree measurement to its corresponding value in radians.
+ * Radians and degrees are two ways of measuring the same thing. There are
+ * 360 degrees in a circle and 2*PI radians in a circle. For example,
+ * 90° = PI/2 = 1.5707964.
+ *
+ * @method radians
+ * @param {Number} degrees the degree value to convert to radians
+ * @return {Number} the converted angle
+ *
+ * @example
+ *
+ *
+ * var deg = 45.0;
+ * var rad = radians(deg);
+ * print(deg + " degrees is " + rad + " radians");
+ * // Prints: 45 degrees is 0.7853981633974483 radians
+ *
+ *
+ */
+p5.prototype.radians = function(angle) {
+ return polarGeometry.degreesToRadians(angle);
+};
+
+/**
+ * Sets the current mode of p5 to given mode. Default mode is RADIANS.
+ *
+ * @method angleMode
+ * @param {Constant} mode either RADIANS or DEGREES
+ *
+ * @example
+ *
+ *
+ * function draw(){
+ * background(204);
+ * angleMode(DEGREES); // Change the mode to DEGREES
+ * var a = atan2(mouseY-height/2, mouseX-width/2);
+ * translate(width/2, height/2);
+ * push();
+ * rotate(a);
+ * rect(-20, -5, 40, 10); // Larger rectangle is rotating in degrees
+ * pop();
+ * angleMode(RADIANS); // Change the mode to RADIANS
+ * rotate(a); // var a stays the same
+ * rect(-40, -5, 20, 10); // Smaller rectangle is rotating in radians
+ * }
+ *
+ *
+ *
+ * @alt
+ * 40 by 10 rect in center rotates with mouse moves. 20 by 10 rect moves faster.
+ *
+ *
+ */
+p5.prototype.angleMode = function(mode) {
+ if (mode === constants.DEGREES || mode === constants.RADIANS) {
+ this._angleMode = mode;
+ }
+};
+
+module.exports = p5;
+
+},{"../core/constants":41,"../core/core":42,"./polargeometry":72}],75:[function(_dereq_,module,exports){
+/**
+ * @module Typography
+ * @submodule Attributes
+ * @for p5
+ * @requires core
+ * @requires constants
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * Sets the current alignment for drawing text. Accepts two
+ * arguments: horizAlign (LEFT, CENTER, or RIGHT) and
+ * vertAlign (TOP, BOTTOM, CENTER, or BASELINE).
+ *
+ * The horizAlign parameter is in reference to the x value
+ * of the text() function, while the vertAlign parameter is
+ * in reference to the y value.
+ *
+ * So if you write textAlign(LEFT), you are aligning the left
+ * edge of your text to the x value you give in text(). If you
+ * write textAlign(RIGHT, TOP), you are aligning the right edge
+ * of your text to the x value and the top of edge of the text
+ * to the y value.
+ *
+ * @method textAlign
+ * @param {Constant} horizAlign horizontal alignment, either LEFT,
+ * CENTER, or RIGHT
+ * @param {Constant} vertAlign vertical alignment, either TOP,
+ * BOTTOM, CENTER, or BASELINE
+ * @return {Number}
+ * @example
+ *
+ *
+ * @alt
+ *Letters ABCD displayed at top right, EFGH at center and IJKL at bottom left.
+ *
+ */
+p5.prototype.textAlign = function(horizAlign, vertAlign) {
+ return this._renderer.textAlign.apply(this._renderer, arguments);
+};
+
+/**
+ * Sets/gets the spacing, in pixels, between lines of text. This
+ * setting will be used in all subsequent calls to the text() function.
+ *
+ * @method textLeading
+ * @param {Number} leading the size in pixels for spacing between lines
+ * @return {Object|Number}
+ * @example
+ *
+ *
+ * // Text to display. The "\n" is a "new line" character
+ * lines = "L1\nL2\nL3";
+ * textSize(12);
+ *
+ * textLeading(10); // Set leading to 10
+ * text(lines, 10, 25);
+ *
+ * textLeading(20); // Set leading to 20
+ * text(lines, 40, 25);
+ *
+ * textLeading(30); // Set leading to 30
+ * text(lines, 70, 25);
+ *
+ *
+ *
+ * @alt
+ *set L1 L2 & L3 displayed vertically 3 times. spacing increases for each set
+ *
+ */
+p5.prototype.textLeading = function(theLeading) {
+ return this._renderer.textLeading.apply(this._renderer, arguments);
+};
+
+/**
+ * Sets/gets the current font size. This size will be used in all subsequent
+ * calls to the text() function. Font size is measured in pixels.
+ *
+ * @method textSize
+ * @param {Number} theSize the size of the letters in units of pixels
+ * @return {Object|Number}
+ * @example
+ *
+ *
+ * @alt
+ *Font Size 12 displayed small, Font Size 14 medium & Font Size 16 large
+ *
+ */
+p5.prototype.textSize = function(theSize) {
+ return this._renderer.textSize.apply(this._renderer, arguments);
+};
+
+/**
+ * Sets/gets the style of the text for system fonts to NORMAL, ITALIC, or BOLD.
+ * Note: this may be is overridden by CSS styling. For non-system fonts
+ * (opentype, truetype, etc.) please load styled fonts instead.
+ *
+ * @method textStyle
+ * @param {Number|Constant} theStyle styling for text, either NORMAL,
+ * ITALIC, or BOLD
+ * @return {Object|String}
+ * @example
+ *
+ *
+ * @alt
+ *words Font Style Normal displayed normally, Italic in italic and bold in bold
+ *
+ */
+p5.prototype.textStyle = function(theStyle) {
+ return this._renderer.textStyle.apply(this._renderer, arguments);
+};
+
+/**
+ * Calculates and returns the width of any character or text string.
+ *
+ * @method textWidth
+ * @param {String} theText the String of characters to measure
+ * @return {Number}
+ * @example
+ *
+ *
+ * @alt
+ *Letter P and p5.js are displayed with vertical lines at end. P is wide
+ *
+ */
+p5.prototype.textWidth = function(theText) {
+ if (theText.length === 0) {
+ return 0;
+ }
+ return this._renderer.textWidth.apply(this._renderer, arguments);
+};
+
+/**
+ * Returns the ascent of the current font at its current size. The ascent
+ * represents the distance, in pixels, of the tallest character above
+ * the baseline.
+ *
+ * @return {Number}
+ * @example
+ *
+ *
+ * var base = height * 0.75;
+ * var scalar = 0.8; // Different for each font
+ *
+ * textSize(32); // Set initial text size
+ * var asc = textAscent() * scalar; // Calc ascent
+ * line(0, base - asc, width, base - asc);
+ * text("dp", 0, base); // Draw text on baseline
+ *
+ * textSize(64); // Increase text size
+ * asc = textAscent() * scalar; // Recalc ascent
+ * line(40, base - asc, width, base - asc);
+ * text("dp", 40, base); // Draw text on baseline
+ *
+ *
+ */
+p5.prototype.textAscent = function() {
+ return this._renderer.textAscent();
+};
+
+/**
+ * Returns the descent of the current font at its current size. The descent
+ * represents the distance, in pixels, of the character with the longest
+ * descender below the baseline.
+ *
+ * @return {Number}
+ * @example
+ *
+ *
+ * var base = height * 0.75;
+ * var scalar = 0.8; // Different for each font
+ *
+ * textSize(32); // Set initial text size
+ * var desc = textDescent() * scalar; // Calc ascent
+ * line(0, base+desc, width, base+desc);
+ * text("dp", 0, base); // Draw text on baseline
+ *
+ * textSize(64); // Increase text size
+ * desc = textDescent() * scalar; // Recalc ascent
+ * line(40, base + desc, width, base + desc);
+ * text("dp", 40, base); // Draw text on baseline
+ *
+ *
+ */
+p5.prototype.textDescent = function() {
+ return this._renderer.textDescent();
+};
+
+/**
+ * Helper function to measure ascent and descent.
+ */
+p5.prototype._updateTextMetrics = function() {
+ return this._renderer._updateTextMetrics();
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],76:[function(_dereq_,module,exports){
+/**
+ * @module Typography
+ * @submodule Loading & Displaying
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+var constants = _dereq_('../core/constants');
+
+_dereq_('../core/error_helpers');
+
+
+/**
+ * Draws text to the screen. Displays the information specified in the first
+ * parameter on the screen in the position specified by the additional
+ * parameters. A default font will be used unless a font is set with the
+ * textFont() function and a default size will be used unless a font is set
+ * with textSize(). Change the color of the text with the fill() function.
+ * Change the outline of the text with the stroke() and strokeWeight()
+ * functions.
+ *
+ * The text displays in relation to the textAlign() function, which gives the
+ * option to draw to the left, right, and center of the coordinates.
+ *
+ * The x2 and y2 parameters define a rectangular area to display within and
+ * may only be used with string data. When these parameters are specified,
+ * they are interpreted based on the current rectMode() setting. Text that
+ * does not fit completely within the rectangle specified will not be drawn
+ * to the screen.
+ *
+ * @method text
+ * @param {String} str the alphanumeric symbols to be displayed
+ * @param {Number} x x-coordinate of text
+ * @param {Number} y y-coordinate of text
+ * @param {Number} x2 by default, the width of the text box,
+ * see rectMode() for more info
+ * @param {Number} y2 by default, the height of the text box,
+ * see rectMode() for more info
+ * @return {Object} this
+ * @example
+ *
+ *
+ * s = "The quick brown fox jumped over the lazy dog.";
+ * fill(50);
+ * text(s, 10, 10, 70, 80); // Text wraps within text box
+ *
+ *
+ *
+ * @alt
+ *'word' displayed 3 times going from black, blue to translucent blue
+ * The quick brown fox jumped over the lazy dog.
+ *
+ */
+p5.prototype.text = function(str, x, y, maxWidth, maxHeight) {
+ return (!(this._renderer._doFill || this._renderer._doStroke)) ? this :
+ this._renderer.text.apply(this._renderer, arguments);
+};
+
+/**
+ * Sets the current font that will be drawn with the text() function.
+ *
+ * @method textFont
+ * @param {Object|String} f a font loaded via loadFont(), or a String
+ * representing a web safe font (a font
+ * that is generally available across all systems).
+ * @return {Object} this
+ * @example
+ *
+ */
+p5.prototype.append = function(array, value) {
+ array.push(value);
+ return array;
+};
+
+/**
+ * Copies an array (or part of an array) to another array. The src array is
+ * copied to the dst array, beginning at the position specified by
+ * srcPosition and into the position specified by dstPosition. The number of
+ * elements to copy is determined by length. Note that copying values
+ * overwrites existing values in the destination array. To append values
+ * instead of overwriting them, use concat().
+ *
+ * The simplified version with only two arguments, arrayCopy(src, dst),
+ * copies an entire array to another of the same size. It is equivalent to
+ * arrayCopy(src, 0, dst, 0, src.length).
+ *
+ * Using this function is far more efficient for copying array data than
+ * iterating through a for() loop and copying each element individually.
+ *
+ * @method arrayCopy
+ * @param {Array} src the source Array
+ * @param {Number} [srcPosition] starting position in the source Array
+ * @param {Array} dst the destination Array
+ * @param {Number} [dstPosition] starting position in the destination Array
+ * @param {Number} [length] number of Array elements to be copied
+ *
+ * @example
+ *
+ */
+p5.prototype.arrayCopy = function(
+ src,
+ srcPosition,
+ dst,
+ dstPosition,
+ length) {
+
+ // the index to begin splicing from dst array
+ var start,
+ end;
+
+ if (typeof length !== 'undefined') {
+
+ end = Math.min(length, src.length);
+ start = dstPosition;
+ src = src.slice(srcPosition, end + srcPosition);
+
+ } else {
+
+ if (typeof dst !== 'undefined') { // src, dst, length
+ // rename so we don't get confused
+ end = dst;
+ end = Math.min(end, src.length);
+ } else { // src, dst
+ end = src.length;
+ }
+
+ start = 0;
+ // rename so we don't get confused
+ dst = srcPosition;
+ src = src.slice(0, end);
+ }
+
+ // Since we are not returning the array and JavaScript is pass by reference
+ // we must modify the actual values of the array
+ // instead of reassigning arrays
+ Array.prototype.splice.apply(dst, [start, end].concat(src));
+
+};
+
+/**
+ * Concatenates two arrays, maps to Array.concat(). Does not modify the
+ * input arrays.
+ *
+ * @method concat
+ * @param {Array} a first Array to concatenate
+ * @param {Array} b second Array to concatenate
+ * @return {Array} concatenated array
+ *
+ * @example
+ *
+ */
+p5.prototype.shorten = function(list) {
+ list.pop();
+ return list;
+};
+
+/**
+ * Randomizes the order of the elements of an array. Implements
+ *
+ * Fisher-Yates Shuffle Algorithm.
+ *
+ * @method shuffle
+ * @param {Array} array Array to shuffle
+ * @param {Boolean} [bool] modify passed array
+ * @return {Array} shuffled Array
+ * @example
+ *
+ * function setup() {
+ * var regularArr = ['ABC', 'def', createVector(), TAU, Math.E];
+ * print(regularArr);
+ * shuffle(regularArr, true); // force modifications to passed array
+ * print(regularArr);
+ *
+ * // By default shuffle() returns a shuffled cloned array:
+ * var newArr = shuffle(regularArr);
+ * print(regularArr);
+ * print(newArr);
+ * }
+ *
+ */
+p5.prototype.shuffle = function(arr, bool) {
+ var isView = ArrayBuffer && ArrayBuffer.isView && ArrayBuffer.isView(arr);
+ arr = bool || isView ? arr : arr.slice();
+
+ var rnd, tmp, idx = arr.length;
+ while (idx > 1) {
+ rnd = Math.random()*idx | 0;
+
+ tmp = arr[--idx];
+ arr[idx] = arr[rnd];
+ arr[rnd] = tmp;
+ }
+
+ return arr;
+};
+
+/**
+ * Sorts an array of numbers from smallest to largest, or puts an array of
+ * words in alphabetical order. The original array is not modified; a
+ * re-ordered array is returned. The count parameter states the number of
+ * elements to sort. For example, if there are 12 elements in an array and
+ * count is set to 5, only the first 5 elements in the array will be sorted.
+ *
+ * @method sort
+ * @param {Array} list Array to sort
+ * @param {Number} [count] number of elements to sort, starting from 0
+ *
+ * @example
+ *
+ * function setup() {
+ * var words = new Array("banana", "apple", "pear","lime");
+ * print(words); // ["banana", "apple", "pear", "lime"]
+ * var count = 4; // length of array
+ *
+ * words = sort(words, count);
+ * print(words); // ["apple", "banana", "lime", "pear"]
+ * }
+ *
+ *
+ * function setup() {
+ * var numbers = new Array(2,6,1,5,14,9,8,12);
+ * print(numbers); // [2,6,1,5,14,9,8,12]
+ * var count = 5; // Less than the length of the array
+ *
+ * numbers = sort(numbers, count);
+ * print(numbers); // [1,2,5,6,14,9,8,12]
+ * }
+ *
+ */
+p5.prototype.sort = function(list, count) {
+ var arr = count ? list.slice(0, Math.min(count, list.length)) : list;
+ var rest = count ? list.slice(Math.min(count, list.length)) : [];
+ if (typeof arr[0] === 'string') {
+ arr = arr.sort();
+ } else {
+ arr = arr.sort(function(a,b){return a-b;});
+ }
+ return arr.concat(rest);
+};
+
+/**
+ * Inserts a value or an array of values into an existing array. The first
+ * parameter specifies the initial array to be modified, and the second
+ * parameter defines the data to be inserted. The third parameter is an index
+ * value which specifies the array position from which to insert data.
+ * (Remember that array index numbering starts at zero, so the first position
+ * is 0, the second position is 1, and so on.)
+ *
+ * @method splice
+ * @param {Array} list Array to splice into
+ * @param {any} value value to be spliced in
+ * @param {Number} position in the array from which to insert data
+ *
+ * @example
+ *
+ * function setup() {
+ * var myArray = new Array(0,1,2,3,4);
+ * var insArray = new Array("A","B","C");
+ * print(myArray); // [0,1,2,3,4]
+ * print(insArray); // ["A","B","C"]
+ *
+ * splice(myArray, insArray, 3);
+ * print(myArray); // [0,1,2,"A","B","C",3,4]
+ * }
+ *
+ */
+p5.prototype.splice = function(list, value, index) {
+
+ // note that splice returns spliced elements and not an array
+ Array.prototype.splice.apply(list, [index, 0].concat(value));
+
+ return list;
+};
+
+/**
+ * Extracts an array of elements from an existing array. The list parameter
+ * defines the array from which the elements will be copied, and the start
+ * and count parameters specify which elements to extract. If no count is
+ * given, elements will be extracted from the start to the end of the array.
+ * When specifying the start, remember that the first array element is 0.
+ * This function does not change the source array.
+ *
+ * @method subset
+ * @param {Array} list Array to extract from
+ * @param {Number} start position to begin
+ * @param {Number} [count] number of values to extract
+ * @return {Array} Array of extracted elements
+ *
+ * @example
+ *
+ * function setup() {
+ * var myArray = new Array(1,2,3,4,5);
+ * print(myArray); // [1,2,3,4,5]
+ *
+ * var sub1 = subset(myArray, 0, 3);
+ * var sub2 = subset(myArray, 2, 2);
+ * print(sub1); // [1,2,3]
+ * print(sub2); // [3,4]
+ * }
+ *
+ */
+p5.prototype.subset = function(list, start, count) {
+ if (typeof count !== 'undefined') {
+ return list.slice(start, start + count);
+ } else {
+ return list.slice(start, list.length);
+ }
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],79:[function(_dereq_,module,exports){
+/**
+ * @module Data
+ * @submodule Conversion
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * Converts a string to its floating point representation. The contents of a
+ * string must resemble a number, or NaN (not a number) will be returned.
+ * For example, float("1234.56") evaluates to 1234.56, but float("giraffe")
+ * will return NaN.
+ *
+ * When an array of values is passed in, then an array of floats of the same
+ * length is returned.
+ *
+ * @method float
+ * @param {String} str float string to parse
+ * @return {Number} floating point representation of string
+ * @example
+ *
+ * var str = '20';
+ * var diameter = float(str);
+ * ellipse(width/2, height/2, diameter, diameter);
+ *
+ *
+ * @alt
+ * 20 by 20 white ellipse in the center of the canvas
+ *
+ */
+p5.prototype.float = function(str) {
+ if (str instanceof Array) {
+ return str.map(parseFloat);
+ }
+ return parseFloat(str);
+};
+
+/**
+ * Converts a boolean, string, or float to its integer representation.
+ * When an array of values is passed in, then an int array of the same length
+ * is returned.
+ *
+ * @method int
+ * @param {String|Boolean|Number|Array} n value to parse
+ * @return {Number} integer representation of value
+ * @example
+ *
+ */
+p5.prototype.int = function(n, radix) {
+ radix = radix || 10;
+ if (typeof n === 'string') {
+ return parseInt(n, radix);
+ } else if (typeof n === 'number') {
+ return n | 0;
+ } else if (typeof n === 'boolean') {
+ return n ? 1 : 0;
+ } else if (n instanceof Array) {
+ return n.map(function(n) { return p5.prototype.int(n, radix); });
+ }
+};
+
+/**
+ * Converts a boolean, string or number to its string representation.
+ * When an array of values is passed in, then an array of strings of the same
+ * length is returned.
+ *
+ * @method str
+ * @param {String|Boolean|Number|Array} n value to parse
+ * @return {String} string representation of value
+ * @example
+ *
+ */
+p5.prototype.str = function(n) {
+ if (n instanceof Array) {
+ return n.map(p5.prototype.str);
+ } else {
+ return String(n);
+ }
+};
+
+/**
+ * Converts a number or string to its boolean representation.
+ * For a number, any non-zero value (positive or negative) evaluates to true,
+ * while zero evaluates to false. For a string, the value "true" evaluates to
+ * true, while any other value evaluates to false. When an array of number or
+ * string values is passed in, then a array of booleans of the same length is
+ * returned.
+ *
+ * @method boolean
+ * @param {String|Boolean|Number|Array} n value to parse
+ * @return {Boolean} boolean representation of value
+ * @example
+ *
+ */
+p5.prototype.boolean = function(n) {
+ if (typeof n === 'number') {
+ return n !== 0;
+ } else if (typeof n === 'string') {
+ return n.toLowerCase() === 'true';
+ } else if (typeof n === 'boolean') {
+ return n;
+ } else if (n instanceof Array) {
+ return n.map(p5.prototype.boolean);
+ }
+};
+
+/**
+ * Converts a number, string or boolean to its byte representation.
+ * A byte can be only a whole number between -128 and 127, so when a value
+ * outside of this range is converted, it wraps around to the corresponding
+ * byte representation. When an array of number, string or boolean values is
+ * passed in, then an array of bytes the same length is returned.
+ *
+ * @method byte
+ * @param {String|Boolean|Number|Array} n value to parse
+ * @return {Number} byte representation of value
+ * @example
+ *
+ */
+p5.prototype.byte = function(n) {
+ var nn = p5.prototype.int(n, 10);
+ if (typeof nn === 'number') {
+ return ((nn + 128) % 256) - 128;
+ } else if (nn instanceof Array) {
+ return nn.map(p5.prototype.byte);
+ }
+};
+
+/**
+ * Converts a number or string to its corresponding single-character
+ * string representation. If a string parameter is provided, it is first
+ * parsed as an integer and then translated into a single-character string.
+ * When an array of number or string values is passed in, then an array of
+ * single-character strings of the same length is returned.
+ *
+ * @method char
+ * @param {String|Number|Array} n value to parse
+ * @return {String} string representation of value
+ * @example
+ *
+ */
+p5.prototype.char = function(n) {
+ if (typeof n === 'number' && !isNaN(n)) {
+ return String.fromCharCode(n);
+ } else if (n instanceof Array) {
+ return n.map(p5.prototype.char);
+ } else if (typeof n === 'string') {
+ return p5.prototype.char(parseInt(n, 10));
+ }
+};
+
+/**
+ * Converts a single-character string to its corresponding integer
+ * representation. When an array of single-character string values is passed
+ * in, then an array of integers of the same length is returned.
+ *
+ * @method unchar
+ * @param {String|Array} n value to parse
+ * @return {Number} integer representation of value
+ * @example
+ *
+ */
+p5.prototype.unchar = function(n) {
+ if (typeof n === 'string' && n.length === 1) {
+ return n.charCodeAt(0);
+ } else if (n instanceof Array) {
+ return n.map(p5.prototype.unchar);
+ }
+};
+
+/**
+ * Converts a number to a string in its equivalent hexadecimal notation. If a
+ * second parameter is passed, it is used to set the number of characters to
+ * generate in the hexadecimal notation. When an array is passed in, an
+ * array of strings in hexadecimal notation of the same length is returned.
+ *
+ * @method hex
+ * @param {Number|Array} n value to parse
+ * @return {String} hexadecimal string representation of value
+ * @example
+ *
+ */
+p5.prototype.unhex = function(n) {
+ if (n instanceof Array) {
+ return n.map(p5.prototype.unhex);
+ } else {
+ return parseInt('0x' + n, 16);
+ }
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],80:[function(_dereq_,module,exports){
+/**
+ * @module Data
+ * @submodule String Functions
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+//return p5; //LM is this a mistake?
+
+/**
+ * Combines an array of Strings into one String, each separated by the
+ * character(s) used for the separator parameter. To join arrays of ints or
+ * floats, it's necessary to first convert them to Strings using nf() or
+ * nfs().
+ *
+ * @method join
+ * @param {Array} list array of Strings to be joined
+ * @param {String} separator String to be placed between each item
+ * @return {String} joined String
+ * @example
+ *
+ *
+ * @alt
+ * "hello world!" displayed middle left of canvas.
+ *
+ */
+p5.prototype.join = function(list, separator) {
+ return list.join(separator);
+};
+
+/**
+ * This function is used to apply a regular expression to a piece of text,
+ * and return matching groups (elements found inside parentheses) as a
+ * String array. If there are no matches, a null value will be returned.
+ * If no groups are specified in the regular expression, but the sequence
+ * matches, an array of length 1 (with the matched text as the first element
+ * of the array) will be returned.
+ *
+ * To use the function, first check to see if the result is null. If the
+ * result is null, then the sequence did not match at all. If the sequence
+ * did match, an array is returned.
+ *
+ * If there are groups (specified by sets of parentheses) in the regular
+ * expression, then the contents of each will be returned in the array.
+ * Element [0] of a regular expression match returns the entire matching
+ * string, and the match groups start at element [1] (the first group is [1],
+ * the second [2], and so on).
+ *
+ * @method match
+ * @param {String} str the String to be searched
+ * @param {String} regexp the regexp to be used for matching
+ * @return {Array} Array of Strings found
+ * @example
+ *
+ *
+ * var string = "Hello p5js*!"
+ * var regexp = "p5js\\*"
+ * var match = match(string, regexp);
+ * text(match, 5, 50);
+ *
+ *
+ *
+ * @alt
+ * "p5js*" displayed middle left of canvas.
+ *
+ */
+p5.prototype.match = function(str, reg) {
+ return str.match(reg);
+};
+
+/**
+ * This function is used to apply a regular expression to a piece of text,
+ * and return a list of matching groups (elements found inside parentheses)
+ * as a two-dimensional String array. If there are no matches, a null value
+ * will be returned. If no groups are specified in the regular expression,
+ * but the sequence matches, a two dimensional array is still returned, but
+ * the second dimension is only of length one.
+ *
+ * To use the function, first check to see if the result is null. If the
+ * result is null, then the sequence did not match at all. If the sequence
+ * did match, a 2D array is returned.
+ *
+ * If there are groups (specified by sets of parentheses) in the regular
+ * expression, then the contents of each will be returned in the array.
+ * Assuming a loop with counter variable i, element [i][0] of a regular
+ * expression match returns the entire matching string, and the match groups
+ * start at element [i][1] (the first group is [i][1], the second [i][2],
+ * and so on).
+ *
+ * @method matchAll
+ * @param {String} str the String to be searched
+ * @param {String} regexp the regexp to be used for matching
+ * @return {Array} 2d Array of Strings found
+ * @example
+ *
+
+ */
+p5.prototype.matchAll = function(str, reg) {
+ var re = new RegExp(reg, 'g');
+ var match = re.exec(str);
+ var matches = [];
+ while (match !== null) {
+ matches.push(match);
+ // matched text: match[0]
+ // match start: match.index
+ // capturing group n: match[n]
+ match = re.exec(str);
+ }
+ return matches;
+};
+
+/**
+ * Utility function for formatting numbers into strings. There are two
+ * versions: one for formatting floats, and one for formatting ints.
+ * The values for the digits, left, and right parameters should always
+ * be positive integers.
+ *
+ * @method nf
+ * @param {Number|Array} num the Number to format
+ * @param {Number} [left] number of digits to the left of the
+ * decimal point
+ * @param {Number} [right] number of digits to the right of the
+ * decimal point
+ * @return {String|Array} formatted String
+ * @example
+ *
+ *
+ * @alt
+ * "11,253,106.115" top middle and "1.00,1.00,2.00" displayed bottom mid
+ *
+ */
+p5.prototype.nfc = function () {
+ if (arguments[0] instanceof Array) {
+ var a = arguments[1];
+ return arguments[0].map(function (x) {
+ return doNfc(x, a);
+ });
+ } else {
+ return doNfc.apply(this, arguments);
+ }
+};
+function doNfc() {
+ var num = arguments[0].toString();
+ var dec = num.indexOf('.');
+ var rem = dec !== -1 ? num.substring(dec) : '';
+ var n = dec !== -1 ? num.substring(0, dec) : num;
+ n = n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+ if (arguments[1] === 0) {
+ rem = '';
+ }
+ else if(arguments[1] !== undefined){
+ if(arguments[1] > rem.length){
+ rem+= dec === -1 ? '.' : '';
+ var len = arguments[1] - rem.length + 1;
+ for(var i =0; i< len; i++){
+ rem += '0';
+ }
+ }
+ else{
+ rem = rem.substring(0, arguments[1] + 1);
+ }
+ }
+ return n + rem;
+}
+
+/**
+ * Utility function for formatting numbers into strings. Similar to nf() but
+ * puts a "+" in front of positive numbers and a "-" in front of negative
+ * numbers. There are two versions: one for formatting floats, and one for
+ * formatting ints. The values for left, and right parameters
+ * should always be positive integers.
+ *
+ * @method nfp
+ * @param {Number|Array} num the Number to format
+ * @param {Number} [left] number of digits to the left of the decimal
+ * point
+ * @param {Number} [right] number of digits to the right of the
+ * decimal point
+ * @return {String|Array} formatted String
+ * @example
+ *
+ *
+ * @alt
+ * "+11253106.11" top middle and "-11253106.11" displayed bottom middle
+ *
+ */
+p5.prototype.nfp = function() {
+ var nfRes = this.nf.apply(this, arguments);
+ if (nfRes instanceof Array) {
+ return nfRes.map(addNfp);
+ } else {
+ return addNfp(nfRes);
+ }
+};
+
+function addNfp() {
+ return (
+ parseFloat(arguments[0]) > 0) ?
+ '+'+arguments[0].toString() :
+ arguments[0].toString();
+}
+
+/**
+ * Utility function for formatting numbers into strings. Similar to nf() but
+ * puts a " " (space) in front of positive numbers and a "-" in front of
+ * negative numbers. There are two versions: one for formatting floats, and
+ * one for formatting ints. The values for the digits, left, and right
+ * parameters should always be positive integers.
+ *
+ * @method nfs
+ * @param {Number|Array} num the Number to format
+ * @param {Number} [left] number of digits to the left of the decimal
+ * point
+ * @param {Number} [right] number of digits to the right of the
+ * decimal point
+ * @return {String|Array} formatted String
+ * @example
+ *
+ *
+ * @alt
+ * "11253106.11" top middle and "-11253106.11" displayed bottom middle
+ *
+ */
+p5.prototype.nfs = function() {
+ var nfRes = this.nf.apply(this, arguments);
+ if (nfRes instanceof Array) {
+ return nfRes.map(addNfs);
+ } else {
+ return addNfs(nfRes);
+ }
+};
+
+function addNfs() {
+ return (
+ parseFloat(arguments[0]) > 0) ?
+ ' '+arguments[0].toString() :
+ arguments[0].toString();
+}
+
+/**
+ * The split() function maps to String.split(), it breaks a String into
+ * pieces using a character or string as the delimiter. The delim parameter
+ * specifies the character or characters that mark the boundaries between
+ * each piece. A String[] array is returned that contains each of the pieces.
+ *
+ * The splitTokens() function works in a similar fashion, except that it
+ * splits using a range of characters instead of a specific character or
+ * sequence.
+ *
+ * @method split
+ * @param {String} value the String to be split
+ * @param {String} delim the String used to separate the data
+ * @return {Array} Array of Strings
+ * @example
+ *
+ *
+ * @alt
+ * "pat" top left, "Xio" mid left and "Alex" displayed bottom left
+ *
+ */
+p5.prototype.split = function(str, delim) {
+ return str.split(delim);
+};
+
+/**
+ * The splitTokens() function splits a String at one or many character
+ * delimiters or "tokens." The delim parameter specifies the character or
+ * characters to be used as a boundary.
+ *
+ * If no delim characters are specified, any whitespace character is used to
+ * split. Whitespace characters include tab (\t), line feed (\n), carriage
+ * return (\r), form feed (\f), and space.
+ *
+ * @method splitTokens
+ * @param {String} value the String to be split
+ * @param {String} [delim] list of individual Strings that will be used as
+ * separators
+ * @return {Array} Array of Strings
+ * @example
+ *
+ *
+ * function setup() {
+ * var myStr = "Mango, Banana, Lime";
+ * var myStrArr = splitTokens(myStr, ",");
+ *
+ * print(myStrArr); // prints : ["Mango"," Banana"," Lime"]
+ * }
+ *
+ *
+ */
+p5.prototype.splitTokens = function() {
+ var d,sqo,sqc,str;
+ str = arguments[1];
+ if (arguments.length > 1) {
+ sqc = /\]/g.exec(str);
+ sqo = /\[/g.exec(str);
+ if ( sqo && sqc ) {
+ str = str.slice(0, sqc.index) + str.slice(sqc.index+1);
+ sqo = /\[/g.exec(str);
+ str = str.slice(0, sqo.index) + str.slice(sqo.index+1);
+ d = new RegExp('[\\['+str+'\\]]','g');
+ } else if ( sqc ) {
+ str = str.slice(0, sqc.index) + str.slice(sqc.index+1);
+ d = new RegExp('[' + str + '\\]]', 'g');
+ } else if(sqo) {
+ str = str.slice(0, sqo.index) + str.slice(sqo.index+1);
+ d = new RegExp('[' + str + '\\[]', 'g');
+ } else {
+ d = new RegExp('[' + str + ']', 'g');
+ }
+ } else {
+ d = /\s/g;
+ }
+ return arguments[0].split(d).filter(function(n){return n;});
+};
+
+/**
+ * Removes whitespace characters from the beginning and end of a String. In
+ * addition to standard whitespace characters such as space, carriage return,
+ * and tab, this function also removes the Unicode "nbsp" character.
+ *
+ * @method trim
+ * @param {String|Array} str a String or Array of Strings to be trimmed
+ * @return {String|Array} a trimmed String or Array of Strings
+ * @example
+ *
+ *
+ * var string = trim(" No new lines\n ");
+ * text(string +" here", 2, 50);
+ *
+ *
+ *
+ * @alt
+ * "No new lines here" displayed center canvas
+ *
+ */
+p5.prototype.trim = function(str) {
+ if (str instanceof Array) {
+ return str.map(this.trim);
+ } else {
+ return str.trim();
+ }
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],81:[function(_dereq_,module,exports){
+/**
+ * @module IO
+ * @submodule Time & Date
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * p5.js communicates with the clock on your computer. The day() function
+ * returns the current day as a value from 1 - 31.
+ *
+ * @method day
+ * @return {Number} the current day
+ * @example
+ *
+ *
+ * @alt
+ * Current day is displayed
+ *
+ */
+p5.prototype.day = function() {
+ return new Date().getDate();
+};
+
+/**
+ * p5.js communicates with the clock on your computer. The hour() function
+ * returns the current hour as a value from 0 - 23.
+ *
+ * @method hour
+ * @return {Number} the current hour
+ * @example
+ *
+ *
+ * var h = hour();
+ * text("Current hour:\n" + h, 5, 50);
+ *
+ *
+ *
+ * @alt
+ * Current hour is displayed
+ *
+ */
+p5.prototype.hour = function() {
+ return new Date().getHours();
+};
+
+/**
+ * p5.js communicates with the clock on your computer. The minute() function
+ * returns the current minute as a value from 0 - 59.
+ *
+ * @method minute
+ * @return {Number} the current minute
+ * @example
+ *
+ *
+ * var m = minute();
+ * text("Current minute: \n" + m, 5, 50);
+ *
+ *
+ *
+ * @alt
+ * Current minute is displayed
+ *
+ */
+p5.prototype.minute = function() {
+ return new Date().getMinutes();
+};
+
+/**
+ * Returns the number of milliseconds (thousandths of a second) since
+ * starting the program. This information is often used for timing events and
+ * animation sequences.
+ *
+ * @method millis
+ * @return {Number} the number of milliseconds since starting the program
+ * @example
+ *
+ *
+ * @alt
+ * number of milliseconds since program has started displayed
+ *
+ */
+p5.prototype.millis = function() {
+ return window.performance.now();
+};
+
+/**
+ * p5.js communicates with the clock on your computer. The month() function
+ * returns the current month as a value from 1 - 12.
+ *
+ * @method month
+ * @return {Number} the current month
+ * @example
+ *
+ *
+ * var m = month();
+ * text("Current month: \n" + m, 5, 50);
+ *
+ *
+ *
+ * @alt
+ * Current month is displayed
+ *
+ */
+p5.prototype.month = function() {
+ return new Date().getMonth() + 1; //January is 0!
+};
+
+/**
+ * p5.js communicates with the clock on your computer. The second() function
+ * returns the current second as a value from 0 - 59.
+ *
+ * @method second
+ * @return {Number} the current second
+ * @example
+ *
+ *
+ * @alt
+ * Current second is displayed
+ *
+ */
+p5.prototype.second = function() {
+ return new Date().getSeconds();
+};
+
+/**
+ * p5.js communicates with the clock on your computer. The year() function
+ * returns the current year as an integer (2014, 2015, 2016, etc).
+ *
+ * @method year
+ * @return {Number} the current year
+ * @example
+ *
+ *
+ * var y = year();
+ * text("Current year: \n" + y, 5, 50);
+ *
+ *
+ *
+ * @alt
+ * Current year is displayed
+ *
+ */
+p5.prototype.year = function() {
+ return new Date().getFullYear();
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],82:[function(_dereq_,module,exports){
+/**
+ * @module Lights, Camera
+ * @submodule Camera
+ * @for p5
+ * @requires core
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+
+/**
+ * Sets camera position
+ * @method camera
+ * @param {Number} x camera position value on x axis
+ * @param {Number} y camera position value on y axis
+ * @param {Number} z camera position value on z axis
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * function setup(){
+ * createCanvas(100, 100, WEBGL);
+ * }
+ * function draw(){
+ * //move the camera away from the plane by a sin wave
+ * camera(0, 0, sin(frameCount * 0.01) * 100);
+ * plane(120, 120);
+ * }
+ *
+ *
+ *
+ * @alt
+ * blue square shrinks in size grows to fill canvas. disappears then loops.
+ *
+ */
+p5.prototype.camera = function(x, y, z){
+ //what it manipulates is the model view matrix
+ this._renderer.translate(-x, -y, -z);
+};
+
+/**
+ * Sets perspective camera
+ * @method perspective
+ * @param {Number} fovy camera frustum vertical field of view,
+ * from bottom to top of view, in degrees
+ * @param {Number} aspect camera frustum aspect ratio
+ * @param {Number} near frustum near plane length
+ * @param {Number} far frustum far plane length
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * spot light on canvas changes position with mouse
+ *
+ */
+p5.prototype.pointLight = function(v1, v2, v3, a, x, y, z) {
+ var gl = this._renderer.GL;
+ var shaderProgram = this._renderer._getShader(
+ 'lightVert', 'lightTextureFrag');
+
+ gl.useProgram(shaderProgram);
+ shaderProgram.uPointLightColor = gl.getUniformLocation(
+ shaderProgram,
+ 'uPointLightColor[' + this._renderer.pointLightCount + ']');
+
+ //@TODO: check parameters number
+ var color = this._renderer._pInst.color.apply(
+ this._renderer._pInst, [v1, v2, v3]);
+ var colors = color._array;
+
+ gl.uniform3f( shaderProgram.uPointLightColor,
+ colors[0], colors[1], colors[2]);
+
+ var _x, _y, _z;
+
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ if(typeof args[args.length-1] === 'number'){
+ _x = args[args.length-3];
+ _y = args[args.length-2];
+ _z = args[args.length-1];
+
+ }else{
+ try{
+ _x = args[args.length-1].x;
+ _y = args[args.length-1].y;
+ _z = args[args.length-1].z;
+ }
+ catch(error){
+ throw error;
+ }
+ }
+
+ shaderProgram.uPointLightLocation = gl.getUniformLocation(
+ shaderProgram,
+ 'uPointLightLocation[' + this._renderer.pointLightCount + ']');
+ gl.uniform3f( shaderProgram.uPointLightLocation, _x, _y, _z);
+
+ //in case there's no material color for the geometry
+ shaderProgram.uMaterialColor = gl.getUniformLocation(
+ shaderProgram, 'uMaterialColor' );
+ gl.uniform4f( shaderProgram.uMaterialColor, 1, 1, 1, 1);
+
+ this._renderer.pointLightCount ++;
+ shaderProgram.uPointLightCount =
+ gl.getUniformLocation(shaderProgram, 'uPointLightCount');
+ gl.uniform1i(shaderProgram.uPointLightCount,
+ this._renderer.pointLightCount);
+
+ return this;
+};
+
+module.exports = p5;
+
+},{"../core/core":42}],85:[function(_dereq_,module,exports){
+/**
+ * @module Shape
+ * @submodule 3D Models
+ * @for p5
+ * @requires core
+ * @requires p5.Geometry3D
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+_dereq_('./p5.Geometry');
+
+/**
+ * Load a 3d model from an OBJ file.
+ *
+ * One of the limitations of the OBJ format is that it doesn't have a built-in
+ * sense of scale. This means that models exported from different programs might
+ * be very different sizes. If your model isn't displaying, try calling
+ * loadModel() with the normalized parameter set to true. This will resize the
+ * model to a scale appropriate for p5. You can also make additional changes to
+ * the final size of your model with the scale() function.
+ *
+ * @method loadModel
+ * @param {String} path Path of the model to be loaded
+ * @param {Boolean} [normalize] If true, scale the model to a
+ * standardized size when loading
+ * @param {Function(p5.Geometry3D)} [successCallback] Function to be called
+ * once the model is loaded. Will be passed
+ * the 3D model object.
+ * @param {Function(Event)} [failureCallback] called with event error if
+ * the image fails to load.
+ * @return {p5.Geometry} the p5.Geometry3D object
+ * @example
+ *
+ *
+ * @alt
+ * Vertically rotating 3-d teapot with red, green and blue gradient.
+ *
+ */
+p5.prototype.loadModel = function () {
+ var path = arguments[0];
+ var normalize;
+ var successCallback;
+ var failureCallback;
+ if(typeof arguments[1] === 'boolean') {
+ normalize = arguments[1];
+ successCallback = arguments[2];
+ failureCallback = arguments[3];
+ } else {
+ normalize = false;
+ successCallback = arguments[1];
+ failureCallback = arguments[2];
+ }
+
+ var model = new p5.Geometry();
+ model.gid = path + '|' + normalize;
+ this.loadStrings(path, function(strings) {
+ parseObj(model, strings);
+
+ if (normalize) {
+ model.normalize();
+ }
+
+ if (typeof successCallback === 'function') {
+ successCallback(model);
+ }
+ }.bind(this), failureCallback);
+
+ return model;
+};
+
+/**
+ * Parse OBJ lines into model. For reference, this is what a simple model of a
+ * square might look like:
+ *
+ * v -0.5 -0.5 0.5
+ * v -0.5 -0.5 -0.5
+ * v -0.5 0.5 -0.5
+ * v -0.5 0.5 0.5
+ *
+ * f 4 3 2 1
+ */
+function parseObj( model, lines ) {
+ // OBJ allows a face to specify an index for a vertex (in the above example),
+ // but it also allows you to specify a custom combination of vertex, UV
+ // coordinate, and vertex normal. So, "3/4/3" would mean, "use vertex 3 with
+ // UV coordinate 4 and vertex normal 3". In WebGL, every vertex with different
+ // parameters must be a different vertex, so loadedVerts is used to
+ // temporarily store the parsed vertices, normals, etc., and indexedVerts is
+ // used to map a specific combination (keyed on, for example, the string
+ // "3/4/3"), to the actual index of the newly created vertex in the final
+ // object.
+ var loadedVerts = {'v' : [],
+ 'vt' : [],
+ 'vn' : []};
+ var indexedVerts = {};
+
+ for (var line = 0; line < lines.length; ++line) {
+ // Each line is a separate object (vertex, face, vertex normal, etc)
+ // For each line, split it into tokens on whitespace. The first token
+ // describes the type.
+ var tokens = lines[line].trim().split(/\b\s+/);
+
+ if (tokens.length > 0) {
+ if (tokens[0] === 'v' || tokens[0] === 'vn') {
+ // Check if this line describes a vertex or vertex normal.
+ // It will have three numeric parameters.
+ var vertex = new p5.Vector(parseFloat(tokens[1]),
+ parseFloat(tokens[2]),
+ parseFloat(tokens[3]));
+ loadedVerts[tokens[0]].push(vertex);
+ } else if (tokens[0] === 'vt') {
+ // Check if this line describes a texture coordinate.
+ // It will have two numeric parameters.
+ var texVertex = [parseFloat(tokens[1]), parseFloat(tokens[2])];
+ loadedVerts[tokens[0]].push(texVertex);
+ } else if (tokens[0] === 'f') {
+ // Check if this line describes a face.
+ // OBJ faces can have more than three points. Triangulate points.
+ for (var tri = 3; tri < tokens.length; ++tri) {
+ var face = [];
+
+ var vertexTokens = [1, tri - 1, tri];
+
+ for (var tokenInd = 0; tokenInd < vertexTokens.length; ++tokenInd) {
+ // Now, convert the given token into an index
+ var vertString = tokens[vertexTokens[tokenInd]];
+ var vertIndex = 0;
+
+ // TODO: Faces can technically use negative numbers to refer to the
+ // previous nth vertex. I haven't seen this used in practice, but
+ // it might be good to implement this in the future.
+
+ if (indexedVerts[vertString] !== undefined) {
+ vertIndex = indexedVerts[vertString];
+ } else {
+ var vertParts = vertString.split('/');
+ for (var i = 0; i < vertParts.length; i++) {
+ vertParts[i] = parseInt(vertParts[i]) - 1;
+ }
+
+ vertIndex = indexedVerts[vertString] = model.vertices.length;
+ model.vertices.push(loadedVerts.v[vertParts[0]].copy());
+ if (loadedVerts.vt[vertParts[1]]) {
+ model.uvs.push(loadedVerts.vt[vertParts[1]].slice());
+ } else {
+ model.uvs.push([0, 0]);
+ }
+
+ if (loadedVerts.vn[vertParts[2]]) {
+ model.vertexNormals.push(loadedVerts.vn[vertParts[2]].copy());
+ }
+ }
+
+ face.push(vertIndex);
+ }
+
+ model.faces.push(face);
+ }
+ }
+ }
+ }
+
+ // If the model doesn't have normals, compute the normals
+ if(model.vertexNormals.length === 0) {
+ model.computeNormals();
+ }
+
+ return model;
+}
+
+/**
+ * Render a 3d model to the screen.
+ *
+ * @method model
+ * @param {p5.Geometry} model Loaded 3d model to be rendered
+ * @example
+ *
+ *
+ * @alt
+ * radiating light source from top right of canvas
+ *
+ */
+p5.prototype.ambientMaterial = function(v1, v2, v3, a) {
+ var gl = this._renderer.GL;
+ var shaderProgram =
+ this._renderer._getShader('lightVert', 'lightTextureFrag');
+
+ gl.useProgram(shaderProgram);
+ shaderProgram.uMaterialColor = gl.getUniformLocation(
+ shaderProgram, 'uMaterialColor' );
+ var colors = this._renderer._applyColorBlend.apply(this._renderer, arguments);
+
+ gl.uniform4f(shaderProgram.uMaterialColor,
+ colors[0], colors[1], colors[2], colors[3]);
+
+ shaderProgram.uSpecular = gl.getUniformLocation(
+ shaderProgram, 'uSpecular' );
+ gl.uniform1i(shaderProgram.uSpecular, false);
+
+ gl.uniform1i(gl.getUniformLocation(shaderProgram, 'isTexture'), false);
+
+ return this;
+};
+
+/**
+ * Specular material for geometry with a given color. You can view all
+ * possible materials in this
+ * example.
+ * @method specularMaterial
+ * @param {Number|Array|String|p5.Color} v1 gray value,
+ * red or hue value (depending on the current color mode),
+ * or color Array, or CSS color string
+ * @param {Number} [v2] optional: green or saturation value
+ * @param {Number} [v3] optional: blue or brightness value
+ * @param {Number} [a] optional: opacity
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * @alt
+ * red canvas
+ *
+ */
+p5.RendererGL.prototype.fill = function(v1, v2, v3, a) {
+ var gl = this.GL;
+ var shaderProgram;
+ //see material.js for more info on color blending in webgl
+ var colors = this._applyColorBlend.apply(this, arguments);
+ this.curFillColor = colors;
+ this.drawMode = 'fill';
+ if(this.isImmediateDrawing){
+ shaderProgram =
+ this._getShader('immediateVert','vertexColorFrag');
+ gl.useProgram(shaderProgram);
+ } else {
+ shaderProgram =
+ this._getShader('normalVert', 'basicFrag');
+ gl.useProgram(shaderProgram);
+ //RetainedMode uses a webgl uniform to pass color vals
+ //in ImmediateMode, we want access to each vertex so therefore
+ //we cannot use a uniform.
+ shaderProgram.uMaterialColor = gl.getUniformLocation(
+ shaderProgram, 'uMaterialColor' );
+ gl.uniform4f( shaderProgram.uMaterialColor,
+ colors[0],
+ colors[1],
+ colors[2],
+ colors[3]);
+ }
+ return this;
+};
+p5.RendererGL.prototype.stroke = function(r, g, b, a) {
+ var color = this._pInst.color.apply(this._pInst, arguments);
+ var colorNormalized = color._array;
+ this.curStrokeColor = colorNormalized;
+ this.drawMode = 'stroke';
+ return this;
+};
+
+//@TODO
+p5.RendererGL.prototype._strokeCheck = function(){
+ if(this.drawMode === 'stroke'){
+ throw new Error(
+ 'stroke for shapes in 3D not yet implemented, use fill for now :('
+ );
+ }
+};
+
+/**
+ * [strokeWeight description]
+ * @param {Number} pointSize stroke point size
+ * @return {[type]} [description]
+ * @todo strokeWeight currently works on points only.
+ * implement on all wireframes and strokes.
+ */
+p5.RendererGL.prototype.strokeWeight = function(pointSize) {
+ this.pointSize = pointSize;
+ return this;
+};
+//////////////////////////////////////////////
+// HASH | for material and geometry
+//////////////////////////////////////////////
+
+p5.RendererGL.prototype.geometryInHash = function(gId){
+ return this.gHash[gId] !== undefined;
+};
+
+p5.RendererGL.prototype.materialInHash = function(mId){
+ return this.mHash[mId] !== undefined;
+};
+
+/**
+ * [resize description]
+ * @param {[type]} w [description]
+ * @param {[tyoe]} h [description]
+ * @return {[type]} [description]
+ */
+p5.RendererGL.prototype.resize = function(w,h) {
+ var gl = this.GL;
+ p5.Renderer.prototype.resize.call(this, w, h);
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ // If we're using the default camera, update the aspect ratio
+ if(this._curCamera === 'default') {
+ this._curCamera = null;
+ this._setDefaultCamera();
+ }
+};
+
+/**
+ * clears color and depth buffers
+ * with r,g,b,a
+ * @param {Number} r normalized red val.
+ * @param {Number} g normalized green val.
+ * @param {Number} b normalized blue val.
+ * @param {Number} a normalized alpha val.
+ */
+p5.RendererGL.prototype.clear = function() {
+ var gl = this.GL;
+ gl.clearColor(arguments[0],
+ arguments[1],
+ arguments[2],
+ arguments[3]);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+};
+
+/**
+ * [translate description]
+ * @param {[type]} x [description]
+ * @param {[type]} y [description]
+ * @param {[type]} z [description]
+ * @return {[type]} [description]
+ * @todo implement handle for components or vector as args
+ */
+p5.RendererGL.prototype.translate = function(x, y, z) {
+ this.uMVMatrix.translate([x,-y,z]);
+ return this;
+};
+
+/**
+ * Scales the Model View Matrix by a vector
+ * @param {Number | p5.Vector | Array} x [description]
+ * @param {Number} [y] y-axis scalar
+ * @param {Number} [z] z-axis scalar
+ * @return {this} [description]
+ */
+p5.RendererGL.prototype.scale = function(x,y,z) {
+ this.uMVMatrix.scale([x,y,z]);
+ return this;
+};
+
+p5.RendererGL.prototype.rotate = function(rad, axis){
+ this.uMVMatrix.rotate(rad, axis);
+ return this;
+};
+
+p5.RendererGL.prototype.rotateX = function(rad) {
+ this.rotate(rad, [1,0,0]);
+ return this;
+};
+
+p5.RendererGL.prototype.rotateY = function(rad) {
+ this.rotate(rad, [0,1,0]);
+ return this;
+};
+
+p5.RendererGL.prototype.rotateZ = function(rad) {
+ this.rotate(rad, [0,0,1]);
+ return this;
+};
+
+/**
+ * pushes a copy of the model view matrix onto the
+ * MV Matrix stack.
+ */
+p5.RendererGL.prototype.push = function() {
+ uMVMatrixStack.push(this.uMVMatrix.copy());
+};
+
+/**
+ * [pop description]
+ * @return {[type]} [description]
+ */
+p5.RendererGL.prototype.pop = function() {
+ if (uMVMatrixStack.length === 0) {
+ throw new Error('Invalid popMatrix!');
+ }
+ this.uMVMatrix = uMVMatrixStack.pop();
+};
+
+p5.RendererGL.prototype.resetMatrix = function() {
+ this.uMVMatrix = p5.Matrix.identity();
+ this.translate(0, 0, -800);
+ return this;
+};
+
+// Text/Typography
+// @TODO:
+p5.RendererGL.prototype._applyTextProperties = function() {
+ //@TODO finish implementation
+ console.error('text commands not yet implemented in webgl');
+};
+module.exports = p5.RendererGL;
+
+},{"../core/core":42,"../core/p5.Renderer":48,"./p5.Matrix":88,"./shader":93}],92:[function(_dereq_,module,exports){
+/**
+ * @module Shape
+ * @submodule 3D Primitives
+ * @for p5
+ * @requires core
+ * @requires p5.Geometry
+ */
+
+'use strict';
+
+var p5 = _dereq_('../core/core');
+_dereq_('./p5.Geometry');
+/**
+ * Draw a plane with given a width and height
+ * @method plane
+ * @param {Number} width width of the plane
+ * @param {Number} height height of the plane
+ * @param {Number} [detailX] Optional number of triangle
+ * subdivisions in x-dimension
+ * @param {Number} [detailY] Optional number of triangle
+ * subdivisions in y-dimension
+ * @return {p5} the p5 object
+ * @example
+ *
+ *
+ * //draw a plane with width 200 and height 200
+ * function setup(){
+ * createCanvas(100, 100, WEBGL);
+ * }
+ *
+ * function draw(){
+ * background(200);
+ * plane(50, 50);
+ * }
+ *
+ *
+ *
+ * @alt
+ * Nothing displayed on canvas
+ * Rotating interior view of a box with sides that change color.
+ * 3d red and green gradient.
+ * Rotating interior view of a cylinder with sides that change color.
+ * Rotating view of a cylinder with sides that change color.
+ * 3d red and green gradient.
+ * rotating view of a multi-colored cylinder with concave sides.
+ */
+p5.prototype.plane = function(){
+ var args = new Array(arguments.length);
+ for (var i = 0; i < args.length; ++i) {
+ args[i] = arguments[i];
+ }
+ var width = args[0] || 50;
+ var height = args[1] || width;
+ var detailX = typeof args[2] === 'number' ? args[2] : 1;
+ var detailY = typeof args[3] === 'number' ? args[3] : 1;
+
+ var gId = 'plane|'+width+'|'+height+'|'+detailX+'|'+detailY;
+
+ if(!this._renderer.geometryInHash(gId)){
+ var _plane = function(){
+ var u,v,p;
+ for (var i = 0; i <= this.detailY; i++){
+ v = i / this.detailY;
+ for (var j = 0; j <= this.detailX; j++){
+ u = j / this.detailX;
+ p = new p5.Vector(width * u - width/2,
+ height * v - height/2,
+ 0);
+ this.vertices.push(p);
+ this.uvs.push([u,v]);
+ }
+ }
+ };
+ var planeGeom =
+ new p5.Geometry(detailX, detailY, _plane);
+ planeGeom
+ .computeFaces()
+ .computeNormals();
+ this._renderer.createBuffers(gId, planeGeom);
+ }
+
+ this._renderer.drawBuffers(gId);
+
+};
+
+/**
+ * Draw a box with given width, height and depth
+ * @method box
+ * @param {Number} width width of the box
+ * @param {Number} Height height of the box
+ * @param {Number} depth depth of the box
+ * @param {Number} [detailX] Optional number of triangle
+ * subdivisions in x-dimension
+ * @param {Number} [detailY] Optional number of triangle
+ * subdivisions in y-dimension
+ * @return {p5} the p5 object
+ * @example
+ *