Accessing a variable from setup() in (draw) in p5.js - 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.

Related

How do I create a line that recedes as you draw more in p5.js?

Currently working on a site that features some line drawing while hovering. How can I make the line recede naturally as you draw more? Right now I've figured out how to draw a continual line.
var canvas;
var button;
function windowResized() {
console.log('resized');
resizeCanvas(windowWidth, windowHeight);
}
function setup () {
canvas = createCanvas(windowWidth, windowHeight);
canvas.position(0,0);
canvas.style('z-index', '-1')
background(175);
// button = createButton("Start Your Walk");
}
function draw () {
strokeWeight(4);
console.log('button')
line(pmouseX, pmouseY, mouseX, mouseY)
}
You may store the values of your mouse position in an array and then draw the points of the array in order. When the array is updated, if it is full, you will have to erase the last point of the array, move all the points one position backwards and add the new point. The following would be an example code. I recomend you to consult this page for documentation and also the p5 reference.
var mousePositions = [];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
v = createVector(mouseX, mouseY);
mousePositions.push(v);
noFill();
beginShape();
for(var i = 0; i < mousePositions.length; i++){
vertex(mousePositions[i].x, mousePositions[i].y);
}
endShape();
if(mousePositions.length > 25){
mousePositions.shift();
}
}

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();
}

p5 resize window without clearing the background

The following code makes use of the p5dom add-on to position the canvas in the centre of the window. To dynamically resize the canvas I'm using the windowResized() function. I want to keep the background function in setup. How do I prevent the background colour from clearing when I resize the window? Many thanks.
var cnv;
function centerCanvas() {
var x = (windowWidth - width) / 2;
var y = (windowHeight - height) / 2;
cnv.position(x, y);
}
function setup() {
cnv = createCanvas(windowWidth,windowHeight);
centerCanvas();
background(255, 0, 200);
}
function draw(){
}
function windowResized() {
centerCanvas();
resizeCanvas(windowWidth,windowHeight)
}
One thing you might do is draw everything to a buffer instead of directly to the screen. The createGraphics() function is your friend here. From the P5.js 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);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.js"></script>
You would want to draw everything to a buffer, and then when the screen is resized, redraw that buffer.
Simply by adding the background function to the draw one too.
Try this:
var cnv;
function centerCanvas() {
var x = (windowWidth - width) / 2;
var y = (windowHeight - height) / 2;
cnv.position(x, y);
}
function setup() {
cnv = createCanvas(windowWidth,windowHeight);
centerCanvas();
background(255, 0, 200);
}
function draw(){
//HERE:
background(255, 0, 200);
}
function windowResized() {
//(you can add it here too...)
centerCanvas();
resizeCanvas(windowWidth,windowHeight);
}
I would simply set the background in the windowResized function.
function windowResized() {
centerCanvas();
resizeCanvas(windowWidth,windowHeight)
background(255, 0, 200);
}
For an alternative method, you could use CSS to edit the dimensions using something similar to the following:
<style>
canvas {
width: 100%;
height: 100%;
}
</style>

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

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)
}
}

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