diff --git a/src/core/structure.js b/src/core/structure.js index 539a9c1192..309f4380c5 100644 --- a/src/core/structure.js +++ b/src/core/structure.js @@ -7,119 +7,210 @@ import p5 from './main'; /** - * 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 saveFrames() - * 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. - * - * Use isLooping() to check the current state of loop(). + * Stops the code in draw() from running repeatedly. + * + * By default, draw() tries to run 60 times per + * second. Calling `noLoop()` stops draw() from + * repeating. The draw loop can be restarted by calling + * loop(). draw() can be run + * once by calling redraw(). + * + * The isLooping() function can be used to check + * whether a sketch is looping, as in `isLooping() === true`. * * @method noLoop + * * @example *
* function setup() {
* createCanvas(100, 100);
- * background(200);
+ *
+ * // Turn off the draw loop.
* noLoop();
+ *
+ * describe('A white half-circle on the left edge of a gray square.');
* }
-
+ *
* function draw() {
- * line(10, 10, 90, 90);
+ * background(200);
+ *
+ * // Calculate the circle's x-coordinate.
+ * let x = frameCount;
+ *
+ * // Draw the circle.
+ * // Normally, the circle would move from left to right.
+ * circle(x, 50, 20);
* }
*
*
- * let x = 0;
+ * // Double-click to stop the draw loop.
+ *
* function setup() {
* createCanvas(100, 100);
+ *
+ * // Slow the frame rate.
+ * frameRate(5);
+ *
+ * describe('A white circle moves randomly on a gray background. It stops moving when the user double-clicks.');
* }
*
* function draw() {
- * background(204);
- * x = x + 0.1;
- * if (x > width) {
- * x = 0;
- * }
- * line(x, 0, x, height);
+ * background(200);
+ *
+ * // Calculate the circle's coordinates.
+ * let x = random(0, 100);
+ * let y = random(0, 100);
+ *
+ * // Draw the circle.
+ * // Normally, the circle would move from left to right.
+ * circle(x, y, 20);
* }
*
- * function mousePressed() {
+ * // Stop the draw loop when the user double-clicks.
+ * function doubleClicked() {
* noLoop();
* }
+ *
+ *
+ * let startButton;
+ * let stopButton;
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * // Create the button elements and place them
+ * // beneath the canvas.
+ * startButton = createButton('▶');
+ * startButton.position(0, 100);
+ * startButton.size(50, 20);
+ * stopButton = createButton('◾');
+ * stopButton.position(50, 100);
+ * stopButton.size(50, 20);
+ *
+ * // Set functions to call when the buttons are pressed.
+ * startButton.mousePressed(loop);
+ * stopButton.mousePressed(noLoop);
+ *
+ * // Slow the frame rate.
+ * frameRate(5);
+ *
+ * describe(
+ * 'A white circle moves randomly on a gray background. Play and stop buttons are shown beneath the canvas. The circle stops or starts moving when the user presses a button.'
+ * );
+ * }
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Calculate the circle's coordinates.
+ * let x = random(0, 100);
+ * let y = random(0, 100);
+ *
+ * // Draw the circle.
+ * // Normally, the circle would move from left to right.
+ * circle(x, y, 20);
* }
*
*
- * let x = 0;
* function setup() {
* createCanvas(100, 100);
+ *
+ * // Turn off the draw loop.
* noLoop();
+ *
+ * describe(
+ * 'A white half-circle on the left edge of a gray square. The circle starts moving to the right when the user double-clicks.'
+ * );
* }
*
* function draw() {
- * background(204);
- * x = x + 0.1;
- * if (x > width) {
- * x = 0;
- * }
- * line(x, 0, x, height);
+ * background(200);
+ *
+ * // Calculate the circle's x-coordinate.
+ * let x = frameCount;
+ *
+ * // Draw the circle.
+ * circle(x, 50, 20);
* }
*
- * function mousePressed() {
+ * // Resume the draw loop when the user double-clicks.
+ * function doubleClicked() {
* loop();
* }
+ *
+ *
+ * let startButton;
+ * let stopButton;
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * // Create the button elements and place them
+ * // beneath the canvas.
+ * startButton = createButton('▶');
+ * startButton.position(0, 100);
+ * startButton.size(50, 20);
+ * stopButton = createButton('◾');
+ * stopButton.position(50, 100);
+ * stopButton.size(50, 20);
+ *
+ * // Set functions to call when the buttons are pressed.
+ * startButton.mousePressed(loop);
+ * stopButton.mousePressed(noLoop);
+ *
+ * // Slow the frame rate.
+ * frameRate(5);
+ *
+ * describe(
+ * 'A white circle moves randomly on a gray background. Play and stop buttons are shown beneath the canvas. The circle stops or starts moving when the user presses a button.'
+ * );
+ * }
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Calculate the circle's coordinates.
+ * let x = random(0, 100);
+ * let y = random(0, 100);
+ *
+ * // Draw the circle.
+ * // Normally, the circle would move from left to right.
+ * circle(x, y, 20);
* }
*
*
- * let checkbox, button, colBG, colFill;
- *
* function setup() {
* createCanvas(100, 100);
*
- * button = createButton('Colorize if loop()');
- * button.position(0, 120);
- * button.mousePressed(changeBG);
- *
- * checkbox = createCheckbox('loop()', true);
- * checkbox.changed(checkLoop);
- *
- * colBG = color(0);
- * colFill = color(255);
+ * describe('A white circle drawn against a gray background. When the user double-clicks, the circle stops or resumes following the mouse.');
* }
*
- * function changeBG() {
- * if (isLooping()) {
- * colBG = color(random(255), random(255), random(255));
- * colFill = color(random(255), random(255), random(255));
- * }
+ * function draw() {
+ * background(200);
+ *
+ * // Draw the circle at the mouse's position.
+ * circle(mouseX, mouseY, 20);
* }
*
- * function checkLoop() {
- * if (this.checked()) {
- * loop();
- * } else {
+ * // Toggle the draw loop when the user double-clicks.
+ * function doubleClicked() {
+ * if (isLooping() === true) {
* noLoop();
+ * } else {
+ * loop();
* }
* }
- *
- * function draw() {
- * background(colBG);
- * fill(colFill);
- * ellipse(frameCount % width, height / 2, 50);
- * }
*
*
- * ellipse(0, 50, 33, 33); // Left circle
+ * function setup() {
+ * createCanvas(100, 100);
*
- * 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
+ * background(200);
+ *
+ * // Draw the left circle.
+ * circle(25, 50, 20);
+ *
+ * // Begin the drawing group.
+ * push();
+ *
+ * // Translate the origin to the center.
+ * translate(50, 50);
+ *
+ * // Style the circle.
+ * strokeWeight(5);
+ * stroke('royalblue');
+ * fill('orange');
+ *
+ * // Draw the circle.
+ * circle(0, 0, 20);
+ *
+ * // End the drawing group.
+ * pop();
*
- * ellipse(100, 50, 33, 33); // Right circle
+ * // Draw the right circle.
+ * circle(75, 50, 20);
+ *
+ * describe(
+ * 'Three circles drawn in a row on a gray background. The left and right circles are white with thin, black borders. The middle circle is orange with a thick, blue border.'
+ * );
+ * }
*
*
- * ellipse(0, 50, 33, 33); // Left circle
+ * function setup() {
+ * createCanvas(100, 100);
*
- * push(); // Start a new drawing state
- * strokeWeight(10);
- * fill(204, 153, 0);
- * ellipse(33, 50, 33, 33); // Left-middle circle
+ * // Slow the frame rate.
+ * frameRate(24);
*
- * push(); // Start another new drawing state
- * stroke(0, 102, 153);
- * ellipse(66, 50, 33, 33); // Right-middle circle
- * pop(); // Restore previous state
+ * describe('A mosquito buzzes in front of a green frog. The frog follows the mouse as the user moves.');
+ * }
*
- * pop(); // Restore original state
+ * function draw() {
+ * background(200);
*
- * ellipse(100, 50, 33, 33); // Right circle
+ * // Begin the drawing group.
+ * push();
+ *
+ * // Translate the origin to the mouse's position.
+ * translate(mouseX, mouseY);
+ *
+ * // Style the face.
+ * noStroke();
+ * fill('green');
+ *
+ * // Draw a face.
+ * circle(0, 0, 60);
+ *
+ * // Style the eyes.
+ * fill('white');
+ *
+ * // Draw the left eye.
+ * push();
+ * translate(-20, -20);
+ * ellipse(0, 0, 30, 20);
+ * fill('black');
+ * circle(0, 0, 8);
+ * pop();
+ *
+ * // Draw the right eye.
+ * push();
+ * translate(20, -20);
+ * ellipse(0, 0, 30, 20);
+ * fill('black');
+ * circle(0, 0, 8);
+ * pop();
+ *
+ * // End the drawing group.
+ * pop();
+ *
+ * // Draw a bug.
+ * let x = random(0, 100);
+ * let y = random(0, 100);
+ * text('🦟', x, y);
+ * }
*
*
+ * // Click and drag the mouse to view the scene from different angles.
+ *
+ * function setup() {
+ * createCanvas(100, 100, WEBGL);
+ *
+ * describe(
+ * 'Two spheres drawn on a gray background. The sphere on the left is red and lit from the front. The sphere on the right is a blue wireframe.'
+ * );
+ * }
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Enable orbiting with the mouse.
+ * orbitControl();
+ *
+ * // Draw the red sphere.
+ * push();
+ * translate(-25, 0, 0);
+ * noStroke();
+ * directionalLight(255, 0, 0, 0, 0, -1);
+ * sphere(20);
+ * pop();
+ *
+ * // Draw the blue sphere.
+ * push();
+ * translate(25, 0, 0);
+ * strokeWeight(0.3);
+ * stroke(0, 0, 255);
+ * noFill();
+ * sphere(20);
+ * pop();
+ * }
+ *
+ *
- * ellipse(0, 50, 33, 33); // Left circle
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * background(200);
*
- * 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
+ * // Draw the left circle.
+ * circle(25, 50, 20);
*
- * ellipse(100, 50, 33, 33); // Right circle
+ * // Begin the drawing group.
+ * push();
+ *
+ * // Translate the origin to the center.
+ * translate(50, 50);
+ *
+ * // Style the circle.
+ * strokeWeight(5);
+ * stroke('royalblue');
+ * fill('orange');
+ *
+ * // Draw the circle.
+ * circle(0, 0, 20);
+ *
+ * // End the drawing group.
+ * pop();
+ *
+ * // Draw the right circle.
+ * circle(75, 50, 20);
+ *
+ * describe(
+ * 'Three circles drawn in a row on a gray background. The left and right circles are white with thin, black borders. The middle circle is orange with a thick, blue border.'
+ * );
+ * }
*
*
- * ellipse(0, 50, 33, 33); // Left circle
+ * function setup() {
+ * createCanvas(100, 100);
*
- * push(); // Start a new drawing state
- * strokeWeight(10);
- * fill(204, 153, 0);
- * ellipse(33, 50, 33, 33); // Left-middle circle
+ * // Slow the frame rate.
+ * frameRate(24);
*
- * push(); // Start another new drawing state
- * stroke(0, 102, 153);
- * ellipse(66, 50, 33, 33); // Right-middle circle
- * pop(); // Restore previous state
+ * describe('A mosquito buzzes in front of a green frog. The frog follows the mouse as the user moves.');
+ * }
*
- * pop(); // Restore original state
+ * function draw() {
+ * background(200);
*
- * ellipse(100, 50, 33, 33); // Right circle
+ * // Begin the drawing group.
+ * push();
+ *
+ * // Translate the origin to the mouse's position.
+ * translate(mouseX, mouseY);
+ *
+ * // Style the face.
+ * noStroke();
+ * fill('green');
+ *
+ * // Draw a face.
+ * circle(0, 0, 60);
+ *
+ * // Style the eyes.
+ * fill('white');
+ *
+ * // Draw the left eye.
+ * push();
+ * translate(-20, -20);
+ * ellipse(0, 0, 30, 20);
+ * fill('black');
+ * circle(0, 0, 8);
+ * pop();
+ *
+ * // Draw the right eye.
+ * push();
+ * translate(20, -20);
+ * ellipse(0, 0, 30, 20);
+ * fill('black');
+ * circle(0, 0, 8);
+ * pop();
+ *
+ * // End the drawing group.
+ * pop();
+ *
+ * // Draw a bug.
+ * let x = random(0, 100);
+ * let y = random(0, 100);
+ * text('🦟', x, y);
+ * }
*
*
+ * // Click and drag the mouse to view the scene from different angles.
+ *
+ * function setup() {
+ * createCanvas(100, 100, WEBGL);
+ *
+ * describe(
+ * 'Two spheres drawn on a gray background. The sphere on the left is red and lit from the front. The sphere on the right is a blue wireframe.'
+ * );
+ * }
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Enable orbiting with the mouse.
+ * orbitControl();
+ *
+ * // Draw the red sphere.
+ * push();
+ * translate(-25, 0, 0);
+ * noStroke();
+ * directionalLight(255, 0, 0, 0, 0, -1);
+ * sphere(20);
+ * pop();
+ *
+ * // Draw the blue sphere.
+ * push();
+ * translate(25, 0, 0);
+ * strokeWeight(0.3);
+ * stroke(0, 0, 255);
+ * noFill();
+ * sphere(20);
+ * pop();
+ * }
+ *
+ *
+ *
+ *
+ * // Double-click the canvas to move the circle.
+ *
* let x = 0;
*
* function setup() {
* createCanvas(100, 100);
+ *
+ * // Turn off the draw loop.
* noLoop();
+ *
+ * describe(
+ * 'A white half-circle on the left edge of a gray square. The circle moves a little to the right when the user double-clicks.'
+ * );
* }
*
* function draw() {
- * background(204);
- * line(x, 0, x, height);
+ * background(200);
+ *
+ * // Draw the circle.
+ * circle(x, 50, 20);
+ *
+ * // Increment x.
+ * x += 5;
* }
*
- * function mousePressed() {
- * x += 1;
+ * // Run the draw loop when the user double-clicks.
+ * function doubleClicked() {
* redraw();
* }
*
*
*
- *
+ *
*
+ * // Double-click the canvas to move the circle.
+ *
* let x = 0;
*
* function setup() {
* createCanvas(100, 100);
+ *
+ * // Turn off the draw loop.
* noLoop();
+ *
+ * describe(
+ * 'A white half-circle on the left edge of a gray square. The circle hops to the right when the user double-clicks.'
+ * );
* }
*
* function draw() {
- * background(204);
- * x += 1;
- * line(x, 0, x, height);
+ * background(200);
+ *
+ * // Draw the circle.
+ * circle(x, 50, 20);
+ *
+ * // Increment x.
+ * x += 5;
* }
*
- * function mousePressed() {
- * redraw(5);
+ * // Run the draw loop three times when the user double-clicks.
+ * function doubleClicked() {
+ * redraw(3);
* }
*
*
- *
- * @alt
- * black line on far left of canvas
- * black line on far left of canvas
*/
p5.prototype.redraw = function(n) {
if (this._inUserDraw || !this._setupDone) {
@@ -492,53 +957,193 @@ p5.prototype.redraw = function(n) {
};
/**
- * The `p5()` constructor enables you to activate "instance mode" instead of normal
- * "global mode". This is an advanced topic. A short description and example is
- * included below. Please see
- *
- * Dan Shiffman's Coding Train video tutorial or this
- * tutorial page
- * for more info.
- *
- * By default, all p5.js functions are in the global namespace (i.e. bound to the window
- * object), meaning you can call them simply `ellipse()`, `fill()`, etc. However, this
- * might be inconvenient if you are mixing with other JS libraries (synchronously or
- * asynchronously) or writing long programs of your own. p5.js currently supports a
- * way around this problem called "instance mode". In instance mode, all p5 functions
- * are bound up in a single variable instead of polluting your global namespace.
- *
- * Optionally, you can specify a default container for the canvas and any other elements
- * to append to with a second argument. You can give the ID of an element in your html,
- * or an html node itself.
- *
- * Note that creating instances like this also allows you to have more than one p5 sketch on
- * a single web page, as they will each be wrapped up with their own set up variables. Of
- * course, you could also use iframes to have multiple sketches in global mode.
+ * Creates a new sketch in "instance" mode.
+ *
+ * All p5.js sketches are instances of the `p5` class. Put another way, all
+ * p5.js sketches are objects with methods including `pInst.setup()`,
+ * `pInst.draw()`, `pInst.circle()`, and `pInst.fill()`. By default, sketches
+ * run in "global mode" to hide some of this complexity.
+ *
+ * In global mode, a default instance of the `p5` class is created
+ * automatically. The default `p5` instance searches the web page's source
+ * code for declarations of system functions such as `setup()`, `draw()`,
+ * and `mousePressed()`, then attaches those functions to itself as methods.
+ * Calling a function such as `circle()` in global mode actually calls the
+ * default `p5` object's `pInst.circle()` method.
+ *
+ * It's often helpful to isolate the code within sketches from the rest of the
+ * code on a web page. Two common use cases are web pages that use other
+ * JavaScript libraries and web pages with multiple sketches. "Instance mode"
+ * makes it easy to support both of these scenarios.
+ *
+ * Instance mode sketches support the same API as global mode sketches. They
+ * use a function to bundle, or encapsulate, an entire sketch. The function
+ * containing the sketch is then passed to the `p5()` constructor.
+ *
+ * The first parameter, `sketch`, is a function that contains the sketch. For
+ * example, the statement `new p5(mySketch)` would create a new instance mode
+ * sketch from a function named `mySketch`. The function should have one
+ * parameter, `p`, that's a `p5` object.
+ *
+ * The second parameter, `node`, is optional. If a string is passed, as in
+ * `new p5(mySketch, 'sketch-one')` the new instance mode sketch will become a
+ * child of the HTML element with the id `sketch-one`. If an HTML element is
+ * passed, as in `new p5(mySketch, myElement)`, then the new instance mode
+ * sketch will become a child of the `Element` object called `myElement`.
*
* @method p5
- * @param {Object} sketch a function containing a p5.js sketch
- * @param {String|Object} node ID or pointer to HTML DOM node to contain sketch in
+ * @param {Object} sketch function containing the sketch.
+ * @param {String|HTMLElement} node ID or reference to the HTML element that will contain the sketch.
+ *
* @example
- *
- * const s = p => {
- * let x = 100;
- * let y = 100;
+ *
+ *
+ * // Declare the function containing the sketch.
+ * function sketch(p) {
+ *
+ * // Declare the setup() method.
+ * p.setup = function () {
+ * p.createCanvas(100, 100);
*
- * p.setup = function() {
- * p.createCanvas(700, 410);
+ * p.describe('A white circle drawn on a gray background.');
* };
*
- * p.draw = function() {
- * p.background(0);
- * p.fill(255);
- * p.rect(x, y, 50, 50);
+ * // Declare the draw() method.
+ * p.draw = function () {
+ * p.background(200);
+ *
+ * // Draw the circle.
+ * p.circle(50, 50, 20);
* };
- * };
+ * }
+ *
+ * // Initialize the sketch.
+ * new p5(sketch);
+ *
+ *
+ *
+ *
+ *
+ * // Declare the function containing the sketch.
+ * function sketch(p) {
+ * // Create the sketch's variables within its scope.
+ * let x = 50;
+ * let y = 50;
+ *
+ * // Declare the setup() method.
+ * p.setup = function () {
+ * p.createCanvas(100, 100);
+ *
+ * p.describe('A white circle moves randomly on a gray background.');
+ * };
+ *
+ * // Declare the draw() method.
+ * p.draw = function () {
+ * p.background(200);
+ *
+ * // Update x and y.
+ * x += p.random(-1, 1);
+ * y += p.random(-1, 1);
+ *
+ * // Draw the circle.
+ * p.circle(x, y, 20);
+ * };
+ * }
+ *
+ * // Initialize the sketch.
+ * new p5(sketch);
+ *
+ *
+ *
+ *
+ *
+ * // Declare the function containing the sketch.
+ * function sketch(p) {
+ *
+ * // Declare the setup() method.
+ * p.setup = function () {
+ * p.createCanvas(100, 100);
+ *
+ * p.describe('A white circle drawn on a gray background.');
+ * };
+ *
+ * // Declare the draw() method.
+ * p.draw = function () {
+ * p.background(200);
+ *
+ * // Draw the circle.
+ * p.circle(50, 50, 20);
+ * };
+ * }
+ *
+ * // Select the web page's body element.
+ * let body = document.querySelector('body');
*
- * new p5(s); // invoke p5
- *
+ * // Initialize the sketch and attach it to the web page's body.
+ * new p5(sketch, body);
+ *
+ *
+ *
+ *
+ *
+ * // Declare the function containing the sketch.
+ * function sketch(p) {
+ *
+ * // Declare the setup() method.
+ * p.setup = function () {
+ * p.createCanvas(100, 100);
+ *
+ * p.describe(
+ * 'A white circle drawn on a gray background. The circle follows the mouse as the user moves.'
+ * );
+ * };
+ *
+ * // Declare the draw() method.
+ * p.draw = function () {
+ * p.background(200);
+ *
+ * // Draw the circle.
+ * p.circle(p.mouseX, p.mouseY, 20);
+ * };
+ * }
+ *
+ * // Initialize the sketch.
+ * new p5(sketch);
+ *
+ *
*
- * @alt
- * white rectangle on black background
+ *
+ *
+ * // Declare the function containing the sketch.
+ * function sketch(p) {
+ *
+ * // Declare the setup() method.
+ * p.setup = function () {
+ * p.createCanvas(100, 100);
+ *
+ * p.describe(
+ * 'A white circle drawn on a gray background. The circle follows the mouse as the user moves. The circle becomes black when the user double-clicks.'
+ * );
+ * };
+ *
+ * // Declare the draw() method.
+ * p.draw = function () {
+ * p.background(200);
+ *
+ * // Draw the circle.
+ * p.circle(p.mouseX, p.mouseY, 20);
+ * };
+ *
+ * // Declare the doubleClicked() method.
+ * p.doubleClicked = function () {
+ * // Change the fill color when the user double-clicks.
+ * p.fill(0);
+ * };
+ * }
+ *
+ * // Initialize the sketch.
+ * new p5(sketch);
+ *
+ *
*/
export default p5;