Upload Image to Canvas p5js - javascript

I am a beginner at p5js, and I was learning how to upload an image. This is my code:
PImage img;
function setup() {
size(1400, 1400)
img = loadImage("india-map.gif");
}
function draw() {
background(0)
image(img, 100, 100);
}
When I run it, it says that there is a problem with line 1. The error message reads:
SyntaxError: Expected ;but found img.
I don't know what this means and what I should do. Can anyone help me?
Edit:
I changed the code to
var image1;
function preload(){
image1= loadImage("india-map.jpg");
}
function setup(){
creatCanvas(1350,600)
}
function draw(){
image(image1, 100, 100);
}
My page just says ...loading without loading any image.

In addition to kemicofa great answer, I think it is also important to note the loadImage is asynchronous. This means that when we call loadImage it will take some time for the method to retrieve and load the image data into memory. As a result of this, loadImage doesn't happen instantly like the rest of your code.
Thus, while your image is being loaded, the rest of your code is still able to run, including the draw method. This means that if your draw method only runs once (you can make it run only once by using noLoop(), your image will not be displayed because it hasn't yet been loaded in.
There are a couple of solutions to this issue such as using a callback. However, p5js offers another method which runs before setup called preload. In this function, you can load your image to make sure that it is ready for setup and draw to use.
Using all these ideas you will end up with code which looks somewhat like:
let img;
function preload() {
img = loadImage('india-map.gif'); // load media and other data
}
function setup() { // only executed once preload is has finished loading data
createCanvas(400, 400);
}
function draw() { // only executed once preload is has finished loading data
image(img, 0, 0, width, height);
noLoop(); // stop draw from looping (to show img has been loaded)
}
You can find a working example here

Explanation:
PImage is a type coming from the Processing3 library.
In javascript, when declaring a variable use const, let or var.
Additionally, the size method comes from Processing3 as well. Instead use createCanvas method and pass the size as a parameter.
Go over the documentation and make sure the methods you wish to use exist.
Solution:
let img;
function setup() {
createCanvas(100, 50);
img = loadImage("india-map.gif");
}
function draw() {
background(0);
image(img, 100, 100);
}

Related

How can I re-load images in p5.js once they've changed since runtime?

I have a python file outputting a .png file to a local directory once a second, and this p5.js Javascript file is being hosted from this directory on a server. My issue is in trying to use the loadImage() function to load this local .png -- if I do so, it'll only refer to the initial value of it, and not its new changed value. Even when using a callback function inside draw(), it is very buggy, and does not change. Here's the file:
let splot;
//...
//irrelevant classes
//...
function draw() {
background(245);
solOnePane.display();
s1plot = loadImage("plot.png", imageLoaded);
}
function imageLoaded()
{
console.log("Debug");
image(s1plot,200,200);
}
The result is a super buggy and unchanging image file that only reflects the image file at the state of loading the site. Upon a refresh, the file is updated. So, how can I write code with loadImage() to load an image at the current moment?
Thanks so much.
If the image is saved at a set internal externally, let's say every second, you could use setInterval() every 1100ms for example to reload the image:
var s1plot;
function setup(){
//...init your things here
//reload the image every 1.1s
setInterval(loadImage, 1100, "plot.png", imageLoaded, imageLoadFailed);
}
function imageLoaded(loadedImage)
{
s1plot = loadedImage;
console.log("image loaded", s1plot);
}
function imageLoadFailed(event){
console.warn("image load failed", event);
}
function draw() {
background(245);
if(s1plot){// try to display the image only when it's available
image(s1plot, 200, 200);
}
}
You could use draw() as well and change the frameRate() to so a new frame is rendered every second or so. Here's a modified version of the above using frameRate():
var s1plot;
function setup(){
//...init your things here
//set frameRate to 1 frame every 1.1s
frameRate(1000 / 1100);
}
function imageLoaded(loadedImage)
{
s1plot = loadedImage;
console.log("image loaded", s1plot);
}
function imageLoadFailed(event){
console.warn("image load failed", event);
}
function draw() {
background(245);
if(s1plot){// try to display the image only when it's available
image(s1plot, 200, 200);
}
// reload the image
loadImage("plot.png", imageLoaded, imageLoadFailed);
}
This may be simpler (sometimes setInterval's scope can get hairy), but it also means you're limited to slow render updates. You may want this if the p5 sketch if simply displaying an image, but not if for example you want to handle reactive user interaction as well.
The code above isn't tested, but hopefully illustrates the idea.
It's worth double checking loadImage() reference when in doubt.
For example, these details are important:
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.
In your case the second option (supplying a callback function) applies, however you've forgotten to add the image argument to the image load callback.
This assumes there are no issues writing plot.png to disk with no errors and the timing is a bit of a hack.
In an ideal world you would have the first system which writes plot.png send a message to p5 when the image has been successuflly been written and is ready to be loaded. (If plot.png is for example generated by a python script using matplotlib or something similar you could use a server sent event or websocket library to which p5 can connect to and listen for the message to load the image)

Cursor as PNG image?

I am trying to make my cursor be a PNG image that I have already preloaded in an art game I am designing on P5.js.
I have tried so many things, but it still won't work!
Can someone please let me know where to put the cursor function as well as what to put inside the parentheses? Thanks so much!
function preload() {
uImg = loadImage('assets/ufo.png');
rImg = loadImage('assets/asteroid.png');
bImg3 = loadImage('assets/bimg3.jpg');
}
function setup() {
createCanvas(1200, 600);
mode = 3; //level 3 in game
noCursor();
}
// END OF SET UP
function draw() {
levelThree();
}
// END OF DRAW
function levelThree() {
clear();
if (mode == 3) {
lost = false;
score = 0;
background(bImg3);
cursor(uImg,mouseX,mouseY);
}
}
I think simply using image() instead of cursor() will do what you want. I don't know why, but I think that when using cursor() you can't input a p5.Image, you have to put a string of a URL to an image that exists on the internet.
Also, when using cursor(), the other two parameters should be between 0 and 31. They describe where the "active point" of the cursor is, relative to where the actual mouse point is.
You could just do something like this:
let img
function preload(){
img = loadImage('cursor.png')
}
function setup() {
createCanvas(400, 400);
imageMode(CENTER)
noCursor()
}
function draw() {
background(20);
image(img,mouseX,mouseY)
}
And you should put the option stuff in setup() so the imageMode() and fill() and idk rectMode()... in setup, though what ever you're going to draw multiple times in draw() and you should load images in preload, cause javascript doesn't reallly care if images are loaded in or not and callback functions are meh, preload is good in my opinion. I also don't think that you really need the assets in assets/image.png
And also why exactly do you have mouseX and mouseY in the cursor() at the end of your code snippet???
hope this is actually answering the right question...

Accessing a loaded Table in drop()

I am trying to load a simple CSV file in my sketch through the drop() function in p5. I can successfully 'get' the file and call loadTable(), however I would like to do something with the loaded table automatically, and for some reason it seems like I have to let the drop() function completely finish before being able to access the table.
My little test sketch 'gets' a file that is dragged onto the canvas, loads it into a table, and attempts to print out the getRowCount() immediately after loading. This returns 0.... so I also set up a function to run getRowCount() when the mouse is clicked, and this works as expected.
My test CSV file: https://drive.google.com/open?id=1NOluhKiqMxZy10s3dAFLsHLLjoAtV6GT
I only partially understand why this is happening, and I definitely don't know how to get around it. I've been teaching myself Javascript and p5, so I don't know the terms that I need to search to understand what is happening here...
var myTable;
function setup() {
var canvas = createCanvas(400, 400);
canvas.drop(getFile);
}
function draw() {
background(220);
}
function getFile(file) {
myTable = loadTable(file.data);
// Do something with the table *when* I drop it...
console.log("In getFile function: " + myTable.getRowCount());
// Doesn't work either...
extra(myTable);
}
function mouseClicked() {
console.log("On mouse click " + myTable.getRowCount());
}
function extra(table_) {
console.log("In extra function: " + table_.getRowCount());
}
I'd recommend always looking in the reference when you have questions about how P5.js works.
Here is the reference for the loadTable() function. It says:
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:
Syntax
loadTable(filename, options, [callback], [errorCallback])
loadTable(filename, [callback], [errorCallback])
You would need to provide a callback function that is triggered when the loadTable() function is finished asynchronously loading the table.

Random Ball Speed in P5.js

I have the following code:
var posX1 = 0, posY1 = 100;
var speedX1 = random(1,3), speedY1 = random(1,3);
var posX2 = 0, posY2 = 200;
var speedX2 = 2, speedY2 = 0;
function setup()
{
createCanvas(640, 480);
}
function draw()
{
// redraw the background so you blank the screen
background(255);
if(posX1 > width)
{
speedX1 = -speedX1;
}
// update the position based on the speed
posX1 += speedX1;
posY1 += speedY1;
// draw a ball
strokeWeight(20);
point(posX1, posY1);
//
posX2 += speedX2;
posY2 += speedY2;
//draw a ball
strokeWeight(20);
point(posX2, posY2);
}
Its in P5. I basically want the two circles to race each other at random speeds between 1 and 3 but instead they dont even appear on the screen. Can anyone point out where I'm going wrong?
You can't use P5.js functions before setup() is called.
If you run this code and look at the JavaScript console (which should always be your first step) you'll see that you're getting an error saying that random() is not defined. If you then Google that error, you'll get a ton of results explaining what's going on.
From the P5.js FAQ:
Why can't I assign variables using p5 functions and variables before setup()?
The explanation for this is a little complicated, but it has to do
with the way the library is setup in order to support both global and
instance mode. To understand what's happening, let's first look at the
order things happen when a page with p5 is loaded (in global mode).
Scripts in <head> are loaded.
<body> of HTML page loads (when this is complete, the onload event fires, which then triggers step 3).
p5 is started, all functions are added to the global namespace.
So the issue is that the scripts are loaded and evaluated before p5 is
started, when it's not yet aware of the p5 variables. If we try to
call them here, they will cause an error. However, when we use p5
function calls inside setup() and draw() this is ok, because the
browser doesn't look inside functions when the scripts are first
loaded. This is because the setup() and draw() functions are not
called in the user code, they are only defined, so the stuff inside of
them isn't run or evaluated yet.
It's not until p5 is started up that the setup() function is actually
run (p5 calls it for you), and at this point, the p5 functions exist
in the global namespace.
In other words, you have to define your variables at the top of your sketch, but only assign them inside the setup() function:
var speedX1;
var speedY1;
function setup()
{
createCanvas(640, 480);
speedX1 = random(1,3);
speedY1 = random(1,3);
}

How to access processing.js 'width' and 'height' outside processing.js functions

I've recently made the leap from using Khan Academy's processing.js environment to the real deal and am getting a little confused.
I have a simple processing.js program that basically draws a circle, and I want the size of this circle to be determined by the width of the canvas.
If I print the width within a processing.js function, like setup, I'm shown the correct 500px width. Unfortunately, whenever I try to access the width property outside of a processing.js function, it shows the default 100px size, even though the canvas itself is 500px wide.
I think I might be using a fairly ugly mix of processing and javascript, which could be the root of my problems. Your help would be much appreciated!
Processing.js
///* PROCESSING.JS SETUP *///
void setup() {
size(500, 500);
println(width); // WORKS! :)
}
println(width); // DOESN'T WORK... :(
///* GLOBAL VARIABLES *///
var moleculeQuantity = 1;
///* OBJECT CONSTUCTORS *///
var Molecule = function(x, y) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
};
Molecule.prototype.draw = function() {
noStroke();
fill(88, 91, 183);
ellipse(this.x, this.y, 70, 70);
fill(225, 227, 228);
ellipse(this.x, this.y, 40, 40);
};
// Fill array with molecule objects
var molecules = [];
for (var i = 0; i < moleculeQuantity; i++) {
molecules[i] = new Molecule(200, 100);
}
///* DRAW FUNCTION *///
void draw() {
background(225, 227, 228);
molecules[0].draw();
}
Your problem has nothing to do with mixing Processing and JavaScript, and it has nothing to do with asynchronous execution. It's much simpler than that.
Think of the order your code executes in. Anything outside of a method will execute before your setup() function is called. In your case, that means you're accessing the width variable before you've changed it by calling the size() function.
You have to change your code so that your code is triggered after setup() is called. The simplest way to do that is to just move your code to the end of your setup() function, or into a function that's called after setup(), such as the draw() or event methods.
You might think that because your function call is below the setup() function in your code that the setup() call happens first, but it doesn't. You've simply defined the setup() function- it hasn't been called (by Processing) yet! Try moving any code that's outside of a function to the top of your sketch to make it more obvious:
println(width); // this happens first, so width is still 100
void setup() {
size(500, 500);
println(width); //now that size() has been called, the width is 500
}
Edit: I'll try to explain the order of events. Here is what happens when you load a page that contains a Processing.js sketch:
The page is loaded.
Processing.js itself is loaded.
Processing.js compiles your Processing code into JavaScript code.
Your code (which is now JavaScript code) is loaded. Functions like setup() and draw() are defined at this step, but not called yet. Code outside of your functions is called. This is when you see 100 being printed out.
Processing.js calls the setup() function that was defined in step 4. This is when the width is set.
Processing.js starts calling the draw() function 60 times per second.
As for where you should place your variables and functions, that completely depends on what you want to do with them. But you might place a variable's declaration at the top of your sketch and its initialization inside the setup() function. That way you can access its value anywhere, but you know it won't be set until setup() has run. Something like this:
float middleX;
void setup(){
size(500, 500);
middleX = width/2;
}
void draw(){
background(0);
ellipse(middleX, mouseY, 10, 10);
}

Categories

Resources