Interacting with the DOM

Resources

Shiffman - 8.3: Manipulating DOM Elements with html() and position()
Shiffman - 8.4: Handling DOM Events with Callbacks
Shiffman - 8.5: Interacting with the DOM using Sliders, Buttons and Text Inputs
Shiffman - 8.6: Other Events and Inputs

p5 - Beyond the Canvas
p5 - DOM Library Reference

The Canvas

The examples on this page will show you how to access and interact with resources beyond the canvas, ranging from HTML elements on the page to the user's webcam. In order to follow along with these examples, you'll need to run a local server. You'll also need to include the p5 DOM library. Here's an index.html file that you can use for these examples (assuming you have a sketch.js in the same folder):


<!DOCTYPE html>
<html>
  <head>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.dom.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.sound.min.js"></script>
   <script src="sketch.js"></script>
  </head>
  <body>
   
  </body>
</html>
 

As we've seen before, we can control the position of the canvas by placing it inside of a <div> section with a specific id (assuming somewhere in your index.html file is <div id="sketch-holder"> </div> :


function setup() {
  let cnv = createCanvas(600,400);
  cnv.parent('sketch-holder');
}

The .parent property nests the canvas element within another HTML element. As we'll see later, this doesn't just work for the canvas element, but for any other element as well!

Instance Mode

If we want to place multiple sketches on the same page, we should use "instance mode" to make sure that variables and functions are confined to the scope of one canvas. So code might like this in "global mode":


let x = 100, y = 100;

function setup() {   
  createCanvas(200,200);
}

function draw() {
  background(0);
  fill(255);
  ellipse(x,y,50,50);
}

But the same code in "instance mode" would look like:


let sketch = function(p) {
  let x = 100, y = 100;

  p.setup = function() {
    p.createCanvas(700, 410);
  };

  p.draw = function() {
    p.background(0);
    p.fill(255);
    p.rect(x,y,50,50);
  };
};

let myp5 = new p5(sketch);

Sketch as Background

The canvas can be made to automatically fill the window by using the built-in variables windowWidth and windowHeight:


function setup() {
  createCanvas(windowWidth, windowHeight);
  background(255, 0, 200);
}

If you want the canvas to automatically resize to fill the window whenever the window is resized, you can define the windowResized function in your sketch:


function setup() {
  createCanvas(windowWidth, windowHeight);
  background(255, 0, 200);
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

Beyond the Canvas

Now for our sketch.js file, let's look at some more of the functions that allow us to add additional HTML elements. In addition to createCanvas(), there are also a bunch of other functions (partial list below). By default, new elements will be added in order to the end of the <body> section.

We can use createElement() to make any generic HTML element:


function setup() {
  createElement('h3', 'This is a Heading');
}

Additional elements will be added to the end of the HTML document.


function setup() {
  createElement('h3', 'This is a Heading');
  createP('This is a paragraph.');
}

We can add new elements on the fly:


function mousePressed() {
  createP('This is another paragraph');
}

Elements can be stored as variables. Their properties can then be accessed and edited. For example, the .position property sets the position of the element in relation to the (0,0) or top left corner of the browser window. This allows us to position elements on top of each other.


function setup() {
  let canvas = createCanvas(200, 200);
  canvas.position(200, 200);
  let h3 = createElement('h3', 'This is a Heading');
  h3.position(200, 200);
}

The .html property changes the inner HTML of an element.


let canvas, h3; 

function setup() {
  canvas = createCanvas(200, 200);
  canvas.position(200, 200);
  h3 = createElement('h3', 'This is a Heading');
  h3.position(200, 200);
}

function mousePressed() {
  h3.html('The mouse was pressed.');
}

We can create global variables for x and y, and use them to control coordinates relative to the canvas as well as coordinates relative to the browser window.


let canvas, h3, x = 100, y = 100;

function setup() {
  canvas = createCanvas(200, 200);
  canvas.position(200, 200);
  h3 = createElement('h3', 'This is a Header');  
}

function draw() {
  background(0);
  fill(255, 0, 255);
  rect(x, y, 50, 50); // position on the canvas
  h3.position(x, y);  // position in the window
  x = x + random(-2, 2);
}

Callback Functions

We previously discussed how callback functions can be used for asynchronous data loading. We can also attach callback functions to HTML elements. For example, we can tell a function to run once a button is clicked. Compare this to using just a mousePressed() function. Try repositioning this button at the top left corner of the canvas.


let button;

function setup() {
  createCanvas(200, 200);
  button = createButton('change');
  button.mousePressed(changeColor);
}

function changeColor() {
  background(color(random(255))); 
}

User Input

In addition to buttons, there a many other ways we can get input from a user. The slider element is great for retreiving numerical data. We can make one using the createSlider() function. The syntax is createSlider(min,max,[value],[step]) where value is a default value, and step allows for fixed increments. We can retrieve the current value of the slider with the .value() method.


let slider;
function setup() {
  slider = createSlider(0, 255, 100);
}

function draw() {
  let val = slider.value();
  background(val);
}

Another useful function is createInput(), which allows us to ask the user to enter text into a text box. The syntax is createInput([default text]). We can retrieve the current text with the .value() method.


let inp;

function setup() {
  inp = createInput();
}

function draw(){
  background(255);
  text(inp.value(), 50, 10);
}

Element Styling

We can also set style (CSS) properties using .style, where the syntax is style(property,[value],[value2],[value3]).


function setup() {
  let myDiv = createDiv('I like pandas.');
  myDiv.style('font-size', '18px');
  myDiv.style('color', '#ff0000');
}

We can create custom buttons, which can be positioned on or off the canvas.


function setup() {
  let col = color(25, 23, 200, 50);
  let button = createButton('Click Me');
  button.style('background-color', col);
  button.position(10, 10);
}

Finally, we can dynamically change properties from the draw() function.


let myDiv;
function setup() {
  background(200);
  myDiv = createDiv('A question of scale');
  myDiv.position(20, 20);
}

function draw() {
  myDiv.style('font-size', mouseX + 'px');
}

We've only just begun to scratch the surface with all of the things you can do using p5 to control HTML elements. For more information, check out the p5 tutorial Beyond the Canvas.