How to execute a function when using the createGraphics function in P5js? - html5-canvas

I want to use the createGraphics function to draw something on another screen... and then paste that into my main sketch..
in the docu, the example they give is doing something like:
var vignette;
function setup(){
createCanvas(710, 400);
vignette = createGraphics(400, 250);
}
function draw(){
ellipse(mouseX, mouseY, 60, 60);
pg.background(51);
pg.noFill();
pg.stroke(255);
pg.ellipse(mouseX-150, mouseY-75, 60, 60);
//Draw the offscreen buffer to the screen with image()
image(pg, 150, 75);
}
But what i want to do is more complex than pg.background(51)
I want to run this function which creates a radial gradient:
function drawGradient() {
for (let r = canvasX; r > 0; --r) {
let lightnes = map(r,0,canvasX,360,0)
fill(360, 360, lightnes)
ellipse(0, 0, r, r)
}
}
But if i do vignette.drawGradient() i get the error: vignette.drawGradient is not a function...
So how can i then execute things like whats inside the drawgradient function inside the createGraphics function?
Here is the codepen: https://codepen.io/giorgiomartini/pen/ZJjWbw?editors=0010

You wouldn't put anything "inside" the createGraphics() function. The createGraphics() function returns an instance of p5.Renderer. You then call functions on that instance.
You were going in the right direction by trying to call vignette.drawGradient(), but like you've discovered, p5.Renderer does not contain a drawGradient() function. Only your sketch contains that function, because it's something you created.
p5.Renderer contains the drawing functions: stuff like background(), fill(), rect(), and ellipse(). So if you want to draw your gradient to your vignette renderer, you have to call the functions that actually draw things on your vignette variable. Like this:
function drawGradient() {
for (let r = canvasX; r > 0; --r) {
let lightnes = map(r,0,canvasX,360,0)
vignette.fill(360, 360, lightnes)
vignette.ellipse(0, 0, r, r)
}
}

Related

Accessing a variable from setup() in (draw) in p5.js

I am drawing a scatterplot with p5.js and want to access the x and y points from inside the setup() function for use with mouseovers in the draw() function. How can I make the x and y point variables globally accessible? I'm afraid I don't understand scoping well enough yet. Do they need to be initialized as arrays...?
function setup() {
//create canvas
createCanvas(windowWidth, windowHeight);
//loop through the videoDatatwo array of objects and get xpoints and ypoints
for (var i = 0; i < videoDatatwo.length; i++) {
videoDatatwo[i].xpoint = map(videoDatatwo[i].Reach, 0, 47674, 150, width - 400);
videoDatatwo[i].ypoint = map(videoDatatwo[i].Views, 0, 9248, height - 150, 150);
}
}
If you want a variable to be available in both the setup() and draw() functions, then you need to declare it outside of those functions. Here's an example:
var message;
function setup() {
createCanvas(500, 500);
message = 'hello world';
}
function draw() {
text(message, 100, 100);
}
This code declares the message variable at the top of the sketch, then it initializes it in the setup() function, and finally it references it in the draw() function.
The same concept would apply to arrays.

How do I save a p5.js canvas as a very large PNG?

I know how to save the canvas using p5.js. However I want to save the canvas as a very large png (for example 8000x8000) so that I can use it in Photoshop and scale down the image to the appropriate size. Is there a simple way of doing this besides creating a new canvas behind the scenes that is too large for the browser window?
You could use the createGraphics() function to create an off-screen buffer. Then you can draw it to the screen using the image() function, or you can call its save() function to store it as a file. Here's an example:
let pg;
function setup() {
createCanvas(400, 400);
pg = createGraphics(4000, 4000);
pg.background(32);
}
function draw() {
pg.ellipse(random(pg.width), random(pg.height), 100, 100);
image(pg, 0, 0, width, height);
}
function mousePressed(){
pg.save("pg.png");
}
Draw everything into a pGraphics object.
Normally you draw this "output" just as an image to the canvas.
But if you want to export a high-res version of it, you scale it up first.
let scaleOutput = 1;
let output;
let canvas;
// setup
function setup() {
// other stuff...
output = createGraphics(1000, 640);
canvas = createCanvas(1000, 640);
}
// the draw loop
function draw() {
// Clear Canvas
background(255);
output.clear();
// Set scale
output.push();
output.scale(scaleOutput);
// Draw to your output here...
output.pop();
// Show on canvas
image(output, 0, 0);
}
// Scale up graphics before exporting
function exportHighRes() {
// HighRes Export
scaleOutput = 5;
output = createGraphics(scaleOutput * 1000, scaleOutput * 640);
draw();
save(output, "filename", 'png');
// Reset Default
scaleOutput = 1;
output = createGraphics(1000, 640);
draw();
}
// Export when key is pressed
function keyReleased() {
if (key == 'e' || key == 'E') exportHighRes();
}

how to have steps of actions in p5.js

This is the pseudocode I hope to realize in p5.js:
The shape keeps rotating throughout the process.
The shape moves to point A.
The shape stay at point A rotating for 2 seconds.
The shape moves to point B.
The shape stay at point B rotating for 2 seconds.
The shape moves to point C.
The shape stay at point C rotating for 2 seconds.
This is what I have already attempted which didn't work:
var angle=0.0
var x=[20,40,60,320]
var y=[50,70,90,280]
function setup() {
createCanvas(400, 400);
background(220);
}
function draw() {
for (i=0; i<x.length; i++) {
translate(x[i], y[i]);
setTimeout(rotate(angle), 1000);
ellipse(0,0,10,100);
angle+=0.1
pop()}
}
You shouldn't really use the setTimeout() function for logic like this.
Instead, use the timing mechanisms built into P5.js, such as the frameCount variable, the millis() function, and the lerp() function.
Here's a simple example that moves a circle after 2 seconds:
var y = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
ellipse(width/2, y, 20, 20);
if(millis() > 2000){
y++;
}
}

How do I resize a p5.Graphic object?

In p5.js resizeCanvas(x, y) is a function for p5 objects but if I made a p5.Graphics object, can I resize it with a similar function?
Interestingly, p5.Graphics objects can run resizeGraphics() but nothing happens (including no error) and the height and width remain the same in the console.
g = createGraphics(50, 50); //creates p5.Graphics
g.resizeCanvas(100, 100); //fails: silently without error
g.resize(100, 100); //fails: resize has not been defined
Is there another function or would I need to actually extract the cooresponding graphics canvas and call a native javascript function instead?
Thanks!
If you want to resize a P5.Graphics, you can just create a new one, then draw the old one to the new one.
Here is an example:
var pg;
function setup() {
createCanvas(1000, 1000);
pg = createGraphics(100, 100);
pg.background(100);
pg.noStroke();
pg.ellipse(pg.width/2, pg.height/2, pg.width, pg.height);
}
function draw() {
background(200);
image(pg, 0, 0);
}
function mouseClicked(){
var newPG = createGraphics(mouseX, mouseY);
newPG.image(pg, 0, 0, newPG.width, newPG.height);
pg = newPG;
}
Using resizeCanvas on a graphics object created with "createGraphics" seems to stretch the graphics rather than resize the buffer.
Right now the best way to resize a graphics object is to simply set the width and height properties directly.
// Some graphics object
let graphics = createGraphics(w,h);
// Now simply resize like this
graphics.width = gWidth;
graphics.height = gHeight;
As suggested here:
https://github.com/processing/p5.js/issues/2064#issuecomment-315503533

Moving an objects while others stay static in a click controlled sketch

So I'm trying to build an animation that I can step through with mouse clicks. Adding individual objects click by click is easy. Sequence I want is as follows:
One object(a) drawn initially.
First mouse click adds an object(b).
Second mouse click adds an object(c).
Third mouse click, object(c) should move across the screen and disappear.
I'm having a problem on the last part of the sequence. I can't figure out how to make the object move and still maintain the static part of the sketch. The normal way of doing movement is to change the coordinates of the object with each loop through the draw() function, and use the background to cover up the previous objects. Can't do that in this case because I need object(a) and object(b) to be persistent.
Code below. Thanks for your help!
var count = 0;
function setup() {
createCanvas(200, 200);
a = new Object1(20, 40);
b = new Object1(20, 85);
c = new Object1(20, 130);
}
function draw() {
background(200);
a.display();
if (count == 1) {
b.display();
}
if (count == 2) {
b.display();
c.display();
}
if (count == 3) { //this is where I have a problem
}
if (count > 3) {
count = 0;
}
}
function Object1(ix, iy, itext) {
this.x = ix;
this.y = iy;
this.text = itext;
this.display = function() {
fill(160);
rect(this.x, this.y, 40, 40);
}
}
function mousePressed() {
count++;
}
Generally how you'd do this is by drawing the static part of your scene to an off-screen buffer, which you can create using the createGraphics() function. From the reference:
var pg;
function setup() {
createCanvas(100, 100);
pg = createGraphics(100, 100);
}
function draw() {
background(200);
pg.background(100);
pg.noStroke();
pg.ellipse(pg.width/2, pg.height/2, 50, 50);
image(pg, 50, 50);
image(pg, 0, 0, 50, 50);
}
You'd draw the static part to the buffer, then draw the buffer to the screen, then draw the dynamic stuff on top of it each frame.
This has been discussed before, so I'd recommend doing a search for stuff like "processing pgraphics" and "p5.js buffer" to find a bunch more information.

Resources