Accessing a loaded Table in drop() - javascript

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.

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)

Creating a sprite inside of setInterval

Using the setInterval function, I'm trying to create a sprite once every second on code.org using javascript, so my first version of the code looks like
setInterval( function() {
createSprite(200,200,20,20)
}, 1000)
My problem is that putting setInterval inside of the Draw function causes it to not work properly and a sprite is created every tick after one second has passed, and when the setInterval is not put into function Draw it does not draw the sprite like I want it too.
One solution I have tried is putting the Draw function inside of setInterval but it is not recognized and gives the error message "Draw is defined, but it is not called in your program".
Is there a different version of setInterval that works inside of Draw function, a way to put Draw inside of setInterval successfully, a way to make the sprite show up even though it is outside Draw, or a different way to solve this problem?
Specifically what I'm looking for is to create a sprite once every second, have it show up on screen, be able to choose different velocities for each sprite each time a new one is spawned, and being able to put this function inside of an if function and still have it work as intended.
a piece of code showing something that partially works is shown here:
https://studio.code.org/projects/gamelab/ApXezLpMzV3TfEfHx1CrhFyuteYDSKWe_6Hx0NdJgnc
It works in the regards that it spawns a sprite every second, but if I try to assign one of the sprites that got spawned a velocity, It only works for the first one, as shown here:
https://studio.code.org/projects/gamelab/ApXezLpMzV3TfEfHx1CrhFyuteYDSKWe_6Hx0NdJgnc
the only way I think a solution could be made would be by declaring a class, and then creating a sprite of this class inside the setInterval function, but I do not know exactly how to do this.
So i think that your problem is that the sprite generates only after a second, right?
If so, please try this:
createSprite(200,200,20,20);
setInterval( function(){ createSprite(200,200,20,20)},1000);
See comments:
// just a helper function to generate random velocities
function random_in_range(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min }
var monster = createSprite(200,200,20,20);
monster.velocityX = 5;
setInterval(function() {
// as you needed to set velocity for a newly created sprite
// you need to have this sprite as a variable
var fireball = createSprite(monster.x,monster.y,4,4);
// now you can set it's velocity
fireball.velocityX = random_in_range(1,6);
// basically that's it.
// as you don't do anything else with a "fireball"
// you can just forget about it, and you don't need to save it anywhere
}, 1000);
function draw() {
background("white");
createEdgeSprites();
monster.bounceOff(edges);
drawSprites();
}
The link with the working code
Looking at your original code and your question I think that you may have some basic misconseptions about JS (sorry if I misjudged). Explained them in the comments to your code. I also added some lines to illustrate my points:
var spawner = createSprite(200,200,20,20);
var remember_spawner = spawner // ADDED
// After a new sprite created it does't change 'spawner' variable
createSprite(150,200,15,15).velocityY = 3; // ADDED
console.log(remember_spawner === spawner) // ADDED // you see it's the same
// you need to assign the newly created sprite to a variable
// you can think of this as:
// I need give them different names so that they can understand to whom am I taking to
// and if you don't name them they won't listen to you at all
var spawner2 = createSprite(100,200,10,10); // ADDED
spawner2.velocityY = 1 // ADDED // now you cat change velocity of another sprite
console.log(spawner !== spawner2) // ADDED // and it is another sprite
// var thing_to_be_spawned = createSprite(spawner.x,spawner.y,4,4);
// You probably don't need this. And you don't use the variable anyway.
// This sprite created at the same time as the spawner.
// But if you need it, and you want it to move - change it's velocity (thing_to_be_spawned.velocityX = something) not the velocity of spawner
// And it would be better if you'll name the function passed to setInterval
// and call it instead of repeating it. Like so:
// function fire() { ... } // define the function
// fire() // call the function
// setInterval(fire, 1000) // call the function every second
setInterval(function(){
console.log("This function executed every second") // ADDED
console.log("Fire!") // ADDED
createSprite(spawner.x,spawner.y,4,4);
console.log("Done") // ADDED
},1000);
console.log("Next line executed only once") // ADDED
spawner.velocityX=5;
// The fact that it's placed after setInterval() does mean that
// it will be executed after call to setInterval()
// but it doesn't mean that it will be executed after the function passed to setInterval(). Let's call it fire(), shall we?
// Actually, the fire() function will be called only after all the code in this file
// And setInterval() is also called only once, only the fire() passed to it called every second
function draw() { // Here you don't call draw() you only define it, so that code.org can call it whenever it wants
// looking at the code draw function we can't tell when or how often it's called
// it depends on the implementation details of code.org.
// We can add console.log to find out
console.log("Draw called") // ADDED
background("white");
createEdgeSprites();
spawner.bounceOff(edges);
drawSprites();
}
console.log("'fire()' not called yet") // ADDED
Console logs can be seeing in Debug Console of studio.code.org. It opens with a click on Debug Commands. Use it! I mean console.log(). I could also say "use Debug Commands!" but debug is poorly implemented in studio.code.org and can be misleading... You should definitely give it a try, but your trust you should put in console.log().

Upload Image to Canvas p5js

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

Why does my function not get Called inside click event of google maps?

I am not sure what is the concept behind this problem, may be its a closure or something other. I have no clue as to why this function can't execute. Looks to me it executes but my browser just turns blank. Not sure whats happening.
google.maps.event.addListener(map,'click', function searchComplete() {
function outside() {
google.load('search', '1');
var newsSearch;
function onLoad() {
// Create a News Search instance.
newsSearch = new google.search.NewsSearch();
// Set searchComplete as the callback function when a search is
// complete. The newsSearch object will have results in it.
newsSearch.setSearchCompleteCallback(this, searchComplete, null);
// Specify search quer(ies)
newsSearch.execute('Obama');
// Include the required Google branding
google.search.Search.getBranding('branding');
}
// Set a callback to call your code when the page loads
google.setOnLoadCallback(onLoad);
}
outside();
});
I have also set up a JSFIDDLE:
http://jsfiddle.net/L9MDu/3/
Am I correct in assuming that onload() is not being called?
From what I can gather, setOnLoadCallback functions similar to a DOMReady ready state, and not a callback for a library loaded dynamically via google.load().
I tried the following, which caused the entire thing to loop and alert indefinitely. Perhaps this is desired?
google.load('search', '1', {
callback: function() {
onLoad();
}
});

Javascript Image.onload callback to object function

This is driving me nuts - I have been round and round in circles, and this no joy. I am loading multiple dynamic images, and have a simple Javascript object which I instantiate for each image, and which has a callback to render the image once it has loaded asynchronously.
I have verified that the callback code works just fine on a stand-alone basis (ie. I can call the callback 'manually' after the image has loaded, and the image is rendered correctly), and I have verified that the image itself is successfully loaded (by switching the object's callback for a simple one line logging function), but when I try to tie it all together, the callback apparently never gets invoked.
I'm relatively new to JS and I suspect that I am missing something fundamental about the way functions within objects are defined, but despite a lot of Googling, can't work out what.
Please can someone show me the error of my ways?
function ImageHolder(aX,aY,aW,aH, anImageURL) {
this.posx=aX;
this.posy=aY;
this.posw=aW;
this.posh=aH;
this.url=anImageURL;
this.myImage = new Image();
this.myImage.onload=this.onload;
this.myImage.src=anImageURL;
this.onload=function() {
try {
var d=document.getElementById("d");
var mycanvas=d.getContext('2d');
mycanvas.drawImage(this.myImage, this.posx, this.posy, this.posw, this.posh);
} catch(err) {
console.log('Onload: could not draw image '+this.url);
console.log(err);
}
};
}
You have two problems: first, this.onload is not defined at the point at which you assign it to the image. You can fix this by missing out the stage of storing the onload handler function as a property of this. The second problem is that when the onload handler function is called, this is not set to what you think it is (in fact, it's a reference to the Image object that has just loaded). You need to store a reference to the current ImageHolder object and use it instead of this within the event handler function.
New code:
var that = this;
this.myImage = new Image();
this.myImage.onload=function() {
try {
var d=document.getElementById("d");
var mycanvas=d.getContext('2d');
mycanvas.drawImage(that.myImage, that.posx, that.posy, that.posw, that.posh);
} catch(err) {
console.log('Onload: could not draw image '+that.url);
console.log(err);
}
};
this.myImage.src = anImageURL;

Categories

Resources