Pause and Reset buttons in p5.js sketches
Pretty cool right? Here's how you do it:
0. Starting out with a simple script
Lets begin with the following very simple p5 sketch.
It's the example above
but without the pause and reset buttons, all it does is:
- move a circle across the screen,
- move it up and down according to a sine wave,
- and draw the background with 10 alpha, so a slight trace of the circle remains
If you add this script to a html page, you get something like this.
You would have minimal control over where your script is in your document, and you can't really pause the sketch or reset it (without reloading the entire page).
So how do you fix this?
// A simple p5.js script // Just a ball moving across the canvas let ballX = 0; let ballSpeed = 1; functionsetup () { // put setup code herecreateCanvas (240, 120);background (51); } functiondraw () { // put drawing code herebackground (51,10);stroke (255);strokeWeight (10);translate (0,height /2); let ang = 2*PI *(ballX/width ); let ballY =sin (ang) *height /2.5;circle (ballX, ballY, 10); ballX = (ballX + ballSpeed) %width ; }
The sketch simple_script.js
1. Namespacing your script
// A namespaced p5.js script function ballMovingSketch(p){ let ballX = 0; let ballSpeed = 1; p.setup = function() { // put setup code here p.createCanvas (240, 120); p.background (51); } p.draw = function() { // put drawing code here p.background (51,10); ...
The sketch, now namespaced! Find it here: namespaced_simple_script.js
To namespace our sketch, we want to wrap everything in a function, with an argument of a p5Canvas object p
.
We won't need to run this function, p5.js will handle that for us, we just need to worry about the namespacing.
If you notice in the code above in Chapter 0 , keywords and functions from p5.js were highlighted as such:
These terms are all linked to the canvas, so when we want to namespace according to the p5Canvas object p
,
we will need to namespace all of these terms by simply adding a p.<term>
for each term, so the example above will be
p.
ballMovingSketch(p)
,
we need to actually add the sketch to the page. All we need is the following line after writing the function:let mysketch = newp5 (ballMovingSketch, 'sketchDiv');
This will add a p5Cavas (mysketch
) running the sketch from the function ballMovingSketch
to the element with the id sketchDiv
.
I prefer to place sketches in divs but they can be placed wherever.
With such namespacing, you can achieve pages that give you control over how the sketch is displayed in your document, and even how many times it's displayed,
like this very basic example.
If your sketch doesn't need interactivity, something like generative art in the background,
or a sketch without a draw function that only uses dom elements, you only really needs this modular function wrapping to achieve your goals.
But if we want to pause and reset the sketch, we're gonna need to add a few more things.
2. Adding a Reset button
Resetting a sketch can mean many different things, like simply blanking the canvas by splashing it with its background colour,
or setting the sketch as though the entire page was just refreshed, or somewhere in between.
Dan Shiffman of the Coding Train has a great video on
implementing a simple reset button for a p5 sketch.
It's a great tutorial if your page is just a standalone p5 sketch, however our implementation shall be slightly different,
since we don't necessarily want the button to be attatched to the sketch itself, and we want to use our function namespacing for greater control of our sketch.
Here's how we do that.
Let's call that method
p.initialiseSketch
, importantly with the namespacing, since we
will want to call this externally when we reset the sketch.Then our entire
setup
function should just be creating the canvas, and then calling this initialising method.If there are additional dom elements declared in the sketch in
setup
, those declaraions should stay in setup
, since calling it
during a reset would duplicate those elements. That is also why we shouldn't call setup
or p.createCanvas
in our reset method, since that would call p.createCanvas
again, which could be unsafe.
// The sketch is wrapped in a function function ballMovingSketch(p){ // Sketch variables, uninitalised let ballX; let ballSpeed; // This defines the initial state of the sketch, // like variable initalisation and canvas actions p.initialiseSketch = function(){ ballX = 0; ballSpeed = 1; p.background (51); } // We only need to create the canvas here, // everything else goes in initaliseSketch p.setup = function() { // put setup code here p.createCanvas (240, 120); p.initialiseSketch(); }
onclick
event, but this can be any event.
<!-- within index.html --> <button id="resetButton" onclick="mysketch.initialiseSketch();" style="width: 75px; font-size:12px"> Reset </button>
And bam we have a reset button!
3. Adding a Pause button
We're gonna take the main ideas from our reset button implementation to create our pause button, with a few extra bits thrown in.
// Flag to pause the sketch let paused = false; // Function to read the pause flag externally p.isPaused = function(){ return paused } // This simply toggles the pause flag // used to control the sketch's pause state p.pauseToggle = function(){ paused = !paused; }
p.draw = function() { // If pause flag is true, do nothing in draw if(paused){ return; } // put drawing code here ...
Within our ballMovingSketch
function, we add a flag paused
, initially set to false
since we want the sketch to start unpaused (there are many cases where a sketch would instead be paused from the start).
We want to limit external control over the value of this flag, so we create two functions, a getter p.isPaused
,
which simply returns the flag, and a toggle p.pauseToggle
, which switches the flag between true
and false
for our p5Canvas object p
.
This will allow the flag to be controlled from outside the sketch function, in a controlled way.
In the draw
method, if the pause
flag is set to true
, do not proceed with the method.
There are many ways this can be implemented, our method has draw
continuously being called even when paused. There may be a way to
have the draw
method only be called while the sketch is not paused, but for the most part this is fine as is.
// This pauses a given sketch from a button press let pauseButtonToggle = function(button, sketch){ if(sketch.isPaused()){ button.innerText = "Pause"; }else{ button.innerText = "Play"; } sketch.pauseToggle(); }
<button id="pauseButton" onclick="pauseButtonToggle(this, mysketch)" style="width: 75px; font-size:12px"> Pause </button>
Outside of the sketch's function, we add a method to pause via buttons pauseButtonToggle(button, sketch)
, which,
given the button pressed and the sketch to (un)pause, relabels the button and toggles the pause
flag in the sketch.
We can then assign this to a button's onclick
event, with the argument for the button being this
to refer
to the button itself, and we're done!
A more simple type of button could also have onclick="mysketch.pauseToggle()"
.
This wouldn't change the looks of the button, but it would function the same otherwise.
And that's it! You're done!