Browser controls

by Allison Parrish

The p5.js framework makes it easy to add HTML5 interface elements to the page that contains your sketch. You can then use these interface elements to allow the user to control your sketch! This tutorial shows you how.

p5.js and the browser

Every p5.js sketch is actually just a “canvas element” in a web page. Up until this point in the class, that web page has only ever contained just the sketch and nothing else. You can actually include anything else you want in that web page, and if you know HTML, you can take the index.html file that p5.js exports and modify it however you please.

But we can use the browser-nature of our p5.js sketches for more than just decoration. Building interface elements like buttons, input boxes, and sliders has traditionally been one of the most difficult parts of making interactive software. Because every p5.js sketch lives inside a web browser, we can take advantage of the browser’s built-in interface elements, so we don’t have to build them ourselves. It’s a convenient time saver!

For any of the examples in this tutorial to work, you’ll need a copy of the p5.dom library, which is what enables interaction between your sketch and the web page that contains it. (This should be included by default when you make a sketch in the p5 app, but you’ll have to include it separately if you’re working on bare HTML/JS files.)

Adding a button

Adding a button to the sketch is as easy as calling the createButton() function. Here’s a simple example:

► run sketch ◼ stop sketch
var button;
function setup() {
  createCanvas(400, 300);
  button = createButton("Hello");
  background(50);
}
function draw() {
}

Hey, nice, a button! But clicking the button doesn’t do anything. To attach a particular behavior to an interface element, we need to define a function that contains the code that we want to run when the user clicks the button, and then attach an “event listener” to the object, to tell p5.js to call that particular function when the user takes a particular action.

The following code uses the .mousePressed() method of the button object to call a function when the user clicks a button.

► run sketch ◼ stop sketch
var button;
function setup() {
  createCanvas(400, 300);
  button = createButton("Click me!");
  button.mousePressed(randomRectangle);
  background(50);
  noStroke();
}
function draw() {
}
function randomRectangle() {
    fill(random(255));
    rect(random()*width, random()*height,
      random(400), random(400));
}

Pretty neat!

The createButton() function returns a button object (actually a kind of p5.Element object). This object, and similar objects returned from the other create functions that we’ll look at below, support a method called .mousePressed(). The parameter you pass to this function should be the name of a function you want p5.js to call when the user clicks the button.

You’re not limited to one button. Here’s a different version of the sketch that adds a second button, with a second function to handle mousePressed events:

► run sketch ◼ stop sketch
var button1;
var button2;
function setup() {
  createCanvas(400, 300);
  button1 = createButton("Click me!");
  button1.mousePressed(randomRectangle);
  button2 = createButton("Clear");
  button2.mousePressed(clearEverything);
  background(50);
  noStroke();
}
function draw() {
}
function randomRectangle() {
    fill(random(255));
    rect(random()*width, random()*height,
      random(400), random(400));
}
function clearEverything() {
  background(50);
}

Sliders

Another helpful interface element is the slider. It allows the user to specify one value among a range of values with visual feedback. You can add a slider to your sketch’s page using the createSlider() function. Here’s an example:

► run sketch ◼ stop sketch
var slider;
function setup() {
  createCanvas(400, 300);
  slider = createSlider(0, width, width/2);
}
function draw() {
  background(50);
  fill(255);
  noStroke();
  ellipse(slider.value(), height/2, 50, 50);
}

The .value() method of the slider object returns the current value of the slider, which we’re using in the above example to control the X position of an ellipse. The createSlider() function creates the slider, and takes three parameters: the minimum value of the slider, the maximum value, and the initial value.

Here’s another example that adds a second slider that controls the ellipse’s size:

► run sketch ◼ stop sketch
var positionSlider;
var sizeSlider;
function setup() {
  createCanvas(400, 300);
  positionSlider = createSlider(0, width, width/2);
  sizeSlider = createSlider(0, 255, 0);
}
function draw() {
  background(50);
  fill(255);
  noStroke();
  ellipse(positionSlider.value(), height/2,
    sizeSlider.value(), 50);
}

Sliders aren’t just read-only; you can also use them as a way to display data, by calling the .value() method with a parameter. Here’s an example that moves the slider in a sinusoidal pattern:

► run sketch ◼ stop sketch
var slider;
function setup() {
  createCanvas(400, 300);
  slider = createSlider(-100, 100, 0);
}
function draw() {
  background(50);
  fill(255);
  noStroke();
  var sinVal = sin(frameCount * 0.05);
  ellipse(width/2, height/2,
    (1+sinVal)*100, (1+sinVal)*100);
  slider.value(sinVal*100);
}

Creating text input fields

Text input is one of the most difficult problems in interface design. Let’s leverage your browser’s built-in text input interface element so we don’t have to write our own from scratch.

To do this, call the createInput() function, which will create a new text input element on the page. The value you pass to createInput() sets the initial value of the field, and just as with a slider, you can use the field’s .value() method to get whatever the user has typed into the field.

► run sketch ◼ stop sketch
var field;
function setup() {
  createCanvas(400, 300);
  field = createInput("type something here");
}
function draw() {
  background(50);
  fill(255);
  noStroke();
  textSize(24);
  text(field.value(), 10, 10, width-20, height-20);
}

Here’s a more advanced example that combines a text input field and a button to create an “exploding text” effect with the user’s input:

► run sketch ◼ stop sketch
var field;
var button;
var letters = [];
function setup() {
  createCanvas(400, 300);
  field = createInput("your text");
  button = createButton("Explode!!");
  button.mousePressed(explodeText);
}
function draw() {
  background(50);
  fill(255);
  noStroke();
  textSize(24);
  for (var i = 0; i < letters.length; i++) {
    text(letters[i].letter, letters[i].xpos, 
      letters[i].ypos);
    letters[i].xpos += letters[i].xdir;
    letters[i].ypos += letters[i].ydir;
  }
}
function explodeText() {
  textSize(24);
  var text = field.value();
  var currentPos = random(width/2);
  for (var i = 0; i < text.length; i++) {
    var letterObj = {
      letter: text.charAt(i),
      ypos: 50,
      xpos: currentPos,
      xdir: random(-1, 1),
      ydir: random(-0.5, 2)
    };
    letters.push(letterObj);
    currentPos += textWidth(text.charAt(i));
  }
}

More examples TK!

Further resources