diff --git a/src/core/p5.Graphics.js b/src/core/p5.Graphics.js index ee5fd1dd3e..4d8e848ff1 100644 --- a/src/core/p5.Graphics.js +++ b/src/core/p5.Graphics.js @@ -8,20 +8,90 @@ import p5 from './main'; import * as constants from './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. + * A class to describe a drawing surface that's separate from the main canvas. + * + * Each `p5.Graphics` object provides a dedicated drawing surface called a + * *graphics buffer*. Graphics buffers are helpful when drawing should happen + * offscreen. For example, separate scenes can be drawn offscreen and + * displayed only when needed. + * + * `p5.Graphics` objects have nearly all the drawing features of the main + * canvas. For example, calling the method `myGraphics.circle(50, 50, 20)` + * draws to the graphics buffer. The resulting image can be displayed on the + * main canvas by passing the `p5.Graphics` object to the + * image() function, as in `image(myGraphics, 0, 0)`. + * + * Note: createGraphics() is the recommended + * way to create an instance of this class. * * @class p5.Graphics * @constructor * @extends p5.Element - * @param {Number} w width - * @param {Number} h height - * @param {Constant} renderer the renderer to use, either P2D or WEBGL - * @param {p5} [pInst] pointer to p5 instance - * @param {HTMLCanvasElement} [canvas] existing html canvas element + * @param {Number} width width of the graphics buffer in pixels. + * @param {Number} height height of the graphics buffer in pixels. + * @param {Constant} renderer renderer to use, either P2D or WEBGL. + * @param {p5} [pInst] sketch instance. + * @param {HTMLCanvasElement} [canvas] existing `<canvas>` element to use. + * + * @example + *
+ * let pg;
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * // Create a p5.Graphics object.
+ * pg = createGraphics(50, 50);
+ *
+ * // Draw to the p5.Graphics object.
+ * pg.background(100);
+ * pg.circle(25, 25, 20);
+ *
+ * describe('A dark gray square with a white circle at its center drawn on a gray background.');
+ * }
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Display the p5.Graphics object.
+ * image(pg, 25, 25);
+ * }
+ *
+ *
+ * // Click the canvas to display the graphics buffer.
+ *
+ * let pg;
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * // Create a p5.Graphics object.
+ * pg = createGraphics(50, 50);
+ *
+ * describe('A square appears on a gray background when the user presses the mouse. The square cycles between white and black.');
+ * }
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Calculate the background color.
+ * let bg = frameCount % 255;
+ *
+ * // Draw to the p5.Graphics object.
+ * pg.background(bg);
+ *
+ * // Display the p5.Graphics object while
+ * // the user presses the mouse.
+ * if (mouseIsPressed === true) {
+ * image(pg, 25, 25);
+ * }
+ * }
+ *
+ *
+ * @example
+ *
+ *
* let pg;
+ *
* function setup() {
* createCanvas(100, 100);
- * background(0);
- * pg = createGraphics(50, 100);
- * pg.fill(0);
- * frameRate(5);
+ *
+ * // Create a p5.Graphics object.
+ * pg = createGraphics(60, 60);
+ *
+ * describe('A white circle moves downward slowly within a dark square. The circle resets at the top of the dark square when the user presses the mouse.');
* }
*
* function draw() {
- * image(pg, width / 2, 0);
- * pg.background(255);
- * // p5.Graphics object behave a bit differently in some cases
- * // The normal canvas on the left resets the translate
- * // with every loop through draw()
- * // the graphics object on the right doesn't automatically reset
- * // so translate() is additive and it moves down the screen
- * rect(0, 0, width / 2, 5);
- * pg.rect(0, 0, width / 2, 5);
- * translate(0, 5, 0);
- * pg.translate(0, 5, 0);
+ * background(200);
+ *
+ * // Translate the p5.Graphics object's coordinate system.
+ * // The translation accumulates; the white circle moves.
+ * pg.translate(0, 0.1);
+ *
+ * // Draw to the p5.Graphics object.
+ * pg.background(100);
+ * pg.circle(30, 0, 10);
+ *
+ * // Display the p5.Graphics object.
+ * image(pg, 20, 20);
+ *
+ * // Translate the main canvas' coordinate system.
+ * // The translation doesn't accumulate; the dark
+ * // square is always in the same place.
+ * translate(0, 0.1);
+ *
+ * // Reset the p5.Graphics object when the
+ * // user presses the mouse.
+ * if (mouseIsPressed === true) {
+ * pg.reset();
+ * }
+ * }
+ *
+ *
+ *
+ *
+ *
+ * let pg;
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * // Create a p5.Graphics object.
+ * pg = createGraphics(60, 60);
+ *
+ * describe('A white circle at the center of a dark gray square. The image is drawn on a light gray background.');
* }
- * function mouseClicked() {
- * // if you click you will see that
- * // reset() resets the translate back to the initial state
- * // of the Graphics object
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Translate the p5.Graphics object's coordinate system.
+ * pg.translate(30, 30);
+ *
+ * // Draw to the p5.Graphics object.
+ * pg.background(100);
+ * pg.circle(0, 0, 10);
+ *
+ * // Display the p5.Graphics object.
+ * image(pg, 20, 20);
+ *
+ * // Reset the p5.Graphics object automatically.
* pg.reset();
* }
- *
+ *
+ *
+ * let pg;
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * // Create a p5.Graphics object using WebGL mode.
+ * pg = createGraphics(100, 100, WEBGL);
+ *
+ * describe("A sphere lit from above with a red light. The sphere's surface becomes glossy while the user clicks and holds the mouse.");
+ * }
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Add a red point light from the top-right.
+ * pg.pointLight(255, 0, 0, 50, -100, 50);
+ *
+ * // Style the sphere.
+ * // It should appear glossy when the
+ * // lighting values are reset.
+ * pg.noStroke();
+ * pg.specularMaterial(255);
+ * pg.shininess(100);
+ *
+ * // Draw the sphere.
+ * pg.sphere(30);
+ *
+ * // Display the p5.Graphics object.
+ * image(pg, -50, -50);
+ *
+ * // Reset the p5.Graphics object when
+ * // the user presses the mouse.
+ * if (mouseIsPressed === true) {
+ * pg.reset();
+ * }
+ * }
+ *
+ *
+ * let pg;
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * // Create a p5.Graphics object using WebGL mode.
+ * pg = createGraphics(100, 100, WEBGL);
+ *
+ * describe('A sphere with a glossy surface is lit from the top-right by a red light.');
+ * }
+ *
+ * function draw() {
+ * background(200);
+ *
+ * // Add a red point light from the top-right.
+ * pg.pointLight(255, 0, 0, 50, -100, 50);
+ *
+ * // Style the sphere.
+ * pg.noStroke();
+ * pg.specularMaterial(255);
+ * pg.shininess(100);
+ *
+ * // Draw the sphere.
+ * pg.sphere(30);
*
- * @alt
- * A white line on a black background stays still on the top-left half.
- * A black line animates from top to bottom on a white background on the right half.
- * When clicked, the black line starts back over at the top.
+ * // Display the p5.Graphics object.
+ * image(pg, 0, 0);
+ *
+ * // Reset the p5.Graphics object automatically.
+ * pg.reset();
+ * }
+ *
+ *
- * let bg;
- * function setup() {
- * bg = createCanvas(100, 100);
- * bg.background(0);
- * image(bg, 0, 0);
- * bg.remove();
- * }
- *
+ * // Double-click to remove the p5.Graphics object.
+ *
+ * let pg;
*
- *
- * let bg;
* function setup() {
- * pixelDensity(1);
* createCanvas(100, 100);
- * stroke(255);
- * fill(0);
*
- * // create and draw the background image
- * bg = createGraphics(100, 100);
- * bg.background(200);
- * bg.ellipse(50, 50, 80, 80);
+ * // Create a p5.Graphics object.
+ * pg = createGraphics(60, 60);
+ *
+ * // Draw to the p5.Graphics object.
+ * pg.background(100);
+ * pg.circle(30, 30, 20);
+ *
+ * describe('A white circle at the center of a dark gray square disappears when the user double-clicks.');
* }
+ *
* function draw() {
- * let t = millis() / 1000;
- * // draw the background
- * if (bg) {
- * image(bg, frameCount % 100, 0);
- * image(bg, frameCount % 100 - 100, 0);
- * }
- * // draw the foreground
- * let p = p5.Vector.fromAngle(t, 35).add(50, 50);
- * ellipse(p.x, p.y, 30);
- * }
- * function mouseClicked() {
- * // remove the background
- * if (bg) {
- * bg.remove();
- * bg = null;
+ * background(200);
+ *
+ * // Display the p5.Graphics object if
+ * // it's available.
+ * if (pg) {
+ * image(pg, 20, 20);
* }
* }
- *
*
- * @alt
- * no image
- * a multi-colored circle moving back and forth over a scrolling background.
+ * // Remove the p5.Graphics object when the
+ * // the user double-clicks.
+ * function doubleClicked() {
+ * pg.remove();
+ * }
+ *
+ *
+ * // Click and hold a mouse button to change shapes.
+ *
+ * let pg;
+ * let torusLayer;
+ * let boxLayer;
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * // Create a p5.Graphics object using WebGL mode.
+ * pg = createGraphics(100, 100, WEBGL);
+ *
+ * // Create the p5.Framebuffer objects.
+ * torusLayer = pg.createFramebuffer();
+ * boxLayer = pg.createFramebuffer();
+ *
+ * describe('A grid of white toruses rotating against a dark gray background. The shapes become boxes while the user holds a mouse button.');
+ * }
+ *
+ * function draw() {
+ * // Update and draw the layers offscreen.
+ * drawTorus();
+ * drawBox();
+ *
+ * // Choose the layer to display.
+ * let layer;
+ * if (mouseIsPressed === true) {
+ * layer = boxLayer;
+ * } else {
+ * layer = torusLayer;
+ * }
+ *
+ * // Draw to the p5.Graphics object.
+ * pg.background(50);
+ *
+ * // Iterate from left to right.
+ * for (let x = -50; x < 50; x += 25) {
+ * // Iterate from top to bottom.
+ * for (let y = -50; y < 50; y += 25) {
+ * // Draw the layer to the p5.Graphics object
+ * pg.image(layer, x, y, 25, 25);
+ * }
+ * }
+ *
+ * // Display the p5.Graphics object.
+ * image(pg, 0, 0);
+ * }
+ *
+ * // Update and draw the torus layer offscreen.
+ * function drawTorus() {
+ * // Start drawing to the torus p5.Framebuffer.
+ * torusLayer.begin();
+ *
+ * // Clear the drawing surface.
+ * pg.clear();
+ *
+ * // Turn on the lights.
+ * pg.lights();
+ *
+ * // Rotate the coordinate system.
+ * pg.rotateX(frameCount * 0.01);
+ * pg.rotateY(frameCount * 0.01);
+ *
+ * // Style the torus.
+ * pg.noStroke();
+ *
+ * // Draw the torus.
+ * pg.torus(20);
+ *
+ * // Start drawing to the torus p5.Framebuffer.
+ * torusLayer.end();
+ * }
+ *
+ * // Update and draw the box layer offscreen.
+ * function drawBox() {
+ * // Start drawing to the box p5.Framebuffer.
+ * boxLayer.begin();
+ *
+ * // Clear the drawing surface.
+ * pg.clear();
+ *
+ * // Turn on the lights.
+ * pg.lights();
+ *
+ * // Rotate the coordinate system.
+ * pg.rotateX(frameCount * 0.01);
+ * pg.rotateY(frameCount * 0.01);
+ *
+ * // Style the box.
+ * pg.noStroke();
+ *
+ * // Draw the box.
+ * pg.box(30);
+ *
+ * // Start drawing to the box p5.Framebuffer.
+ * boxLayer.end();
+ * }
+ *
+ *
+ * // Click and hold a mouse button to change shapes.
+ *
+ * let pg;
+ * let torusLayer;
+ * let boxLayer;
+ *
+ * function setup() {
+ * createCanvas(100, 100);
+ *
+ * // Create an options object.
+ * let options = { width: 25, height: 25 };
+ *
+ * // Create a p5.Graphics object using WebGL mode.
+ * pg = createGraphics(100, 100, WEBGL);
+ *
+ * // Create the p5.Framebuffer objects.
+ * // Use options for configuration.
+ * torusLayer = pg.createFramebuffer(options);
+ * boxLayer = pg.createFramebuffer(options);
+ *
+ * describe('A grid of white toruses rotating against a dark gray background. The shapes become boxes while the user holds a mouse button.');
+ * }
+ *
+ * function draw() {
+ * // Update and draw the layers offscreen.
+ * drawTorus();
+ * drawBox();
+ *
+ * // Choose the layer to display.
+ * let layer;
+ * if (mouseIsPressed === true) {
+ * layer = boxLayer;
+ * } else {
+ * layer = torusLayer;
+ * }
+ *
+ * // Draw to the p5.Graphics object.
+ * pg.background(50);
+ *
+ * // Iterate from left to right.
+ * for (let x = -50; x < 50; x += 25) {
+ * // Iterate from top to bottom.
+ * for (let y = -50; y < 50; y += 25) {
+ * // Draw the layer to the p5.Graphics object
+ * pg.image(layer, x, y);
+ * }
+ * }
+ *
+ * // Display the p5.Graphics object.
+ * image(pg, 0, 0);
+ * }
+ *
+ * // Update and draw the torus layer offscreen.
+ * function drawTorus() {
+ * // Start drawing to the torus p5.Framebuffer.
+ * torusLayer.begin();
+ *
+ * // Clear the drawing surface.
+ * pg.clear();
+ *
+ * // Turn on the lights.
+ * pg.lights();
+ *
+ * // Rotate the coordinate system.
+ * pg.rotateX(frameCount * 0.01);
+ * pg.rotateY(frameCount * 0.01);
+ *
+ * // Style the torus.
+ * pg.noStroke();
+ *
+ * // Draw the torus.
+ * pg.torus(5, 2.5);
+ *
+ * // Start drawing to the torus p5.Framebuffer.
+ * torusLayer.end();
+ * }
+ *
+ * // Update and draw the box layer offscreen.
+ * function drawBox() {
+ * // Start drawing to the box p5.Framebuffer.
+ * boxLayer.begin();
+ *
+ * // Clear the drawing surface.
+ * pg.clear();
+ *
+ * // Turn on the lights.
+ * pg.lights();
+ *
+ * // Rotate the coordinate system.
+ * pg.rotateX(frameCount * 0.01);
+ * pg.rotateY(frameCount * 0.01);
+ *
+ * // Style the box.
+ * pg.noStroke();
+ *
+ * // Draw the box.
+ * pg.box(7.5);
+ *
+ * // Start drawing to the box p5.Framebuffer.
+ * boxLayer.end();
+ * }
+ *
+ *