We are about to switch to a new forum software. Until then we have removed the registration on this forum.
I am working on an online artwork generator using the flickr API. For the prototype I want a user to enter a string into an input box and then flickr returns images based on that string that are then overlayed etc to make a new image.
This is my code so far:
`
Type a word to generate a new image
<input type="text" id="subject" value="rainbow">
<button onclick="createNewImage()">Create New Image</button>
<script language="javascript" type="text/javascript">
//The problem occurs with the calling of this function, if I remove it it works but I have to call it after user input....
function createNewImage(){
var keyword = document.getElementById("subject").value;
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?",
{
tags: keyword,
tagmode: "any",
format: "json"
},
function(data) {
var image_1_index = Math.floor(Math.random() * data.items.length);
var image_2_index = Math.floor(Math.random() * data.items.length);
image1_src = data.items[image_1_index]['media']['m'].replace("_m", "_b");
image2_src = data.items[image_2_index]['media']['m'].replace("_m", "_b");
//$('body').css('background-image', "url('" + image_src + "')");
});
var blend_index;
var xa, yb, xc, yd, xe, yf, xg, yh, r, g, b;
function preload() {
img1 = loadImage(image1_src);
img2 = loadImage(image2_src);
imgs = [loadImage("assets/1.jpg"), loadImage("assets/2.jpg"), loadImage("assets/3.jpg"), loadImage("assets/4.jpg"), loadImage("assets/5.jpg"), loadImage("assets/0.jpg")];
}
function setup() {
frameRate(60);
createCanvas(windowWidth, windowHeight);
image_index = int(random(5));
}
function draw() {
blend_index = int(random(4));
switch (blend_index) {
case 0: blendMode(ADD);
break;
case 1: blendMode(DARKEST);
break;
case 2: blendMode(LIGHTEST);
break;
case 3: blendMode(DIFFERENCE);
break;
case 4: blendMode(EXCLUSION);
break;
default: blendMode(ADD);
}
image(img1, 0, 0, windowWidth, windowHeight);
image(img2, 0, 0, windowWidth, windowHeight);
noLoop();
}
} //end create new image function
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
</script>`
This all works fine until I try to call the 'createNewImage' function, what could cause this? Thank you in advance.
Answers
The problem is caused by the way p5 works by default: it expects to find setup and draw functions in the global scope when it is first run (i.e. when the script is loaded). By putting setup and draw in the scope of your creatImage function, you've hidden them from p5 and so nothing will happen...
The solution is to use instance mode. As per the example put the sketch code in a separate function; then in createImage run
var myp5 = new p5(sketch);
to run the sketch...Notice how any reference to p5 in the sketch must use the argument being passed (in this case
p
) to access p5 methods and properties. It's also worth mentioning that from a JS perspective protecting the global scope in this way is better practice.Another instance mode example:
https://forum.Processing.org/two/discussion/17841/using-createvector-on-a-class-error-what-should-the-right-order-be#Item_5
You can see it online in action going here: http://CodePen.io/anon/pen/wWNmVL?editors=1010
Thank you both for your replies,
I have updated my code and looked at both of the examples you linked and now the sketch works but the sketch() function is self invoking. I want the entire sketch to run only when the onClick event is fired so that the users input can be sent to the flickr api etc. I don't understand how the
var myp5 = new p5(sketch);
object works, why is it necessary to create this object and why does the entire sketch break when that line is removed?"index.html"
"index.js"
You've misunderstood my suggestion slightly. Try:
HTML
<button onclick="runSketch()">Create New Image</button>
JS
Must admit I don't know what will happen with multiple button clicks. If you need multiple sketch instances running you'll need to store these on an array and dispose of as and when necessary. One thing to watch out for will be the possible perfomance hit of invoking many p5 sketches: you may want to set a limit...
Ahhh yes It works!! I still don't understand how declaring an object makes a sketch run, this seems like a strange way of doing it. I'd expect it to be more like calling a function would cause the sketch to run? From the p5.js overview on github:
Either way it works now and I'm very thankful for your help, cheers!
@sai: it's fairly simple. When you create an object you can choose for it to run any actions you like, including running any additional functions. In fact in JS you used to define objects as functions (the latest version now supports class declaration directly) :
Anyway - when you instantiate a new p5 object it just runs methods against the passed sketch parameter - just as it looks for setup and draw functions in the global scope...
A shorter version: :ar!
new
upon constructor p5, a new object of datatype p5 is created.new p5(sketch);
.Ahhhh I get it, very well thought out. Awesome, thank you both for you help!!!