p5.js Session 16: Mouse Interaction

mouseX, mouseY and mousePressed(): sketches that answer back to where the pointer is and where it clicks.

In Session 14 the sketch listened to you once. You pressed a key, it saved a file, and that was the end of the conversation. This session leaves the line open: the sketch watches the mouse on every frame and answers immediately.

mouseX and mouseY

mouseX and mouseY hold the pointer’s position on the canvas, and p5.js refreshes them before every pass of draw(). Read them, and whatever you draw follows the mouse.

A ring of bars radiating from the centre. Move left and right to change how many there are, up and down to change how long they are.

The five colours are Vibrant Color Fiesta, another set from the trending palettes on Coolors.

let palette;

function setup() {
  createCanvas(600, 600);
  frameRate(30);
  angleMode(DEGREES);
  noStroke();
  palette = ['#FFBE0B', '#FB5607', '#FF006E', '#8338EC', '#3A86FF'];
}

function draw() {
  background(0);
  push();
  translate(300, 300);
  let count = floor(mouseX / 20) + 3;
  let barLength = mouseY / 3 + 80;
  let angle = 360 / count;
  for (let i = 0; i < count; i++) {
    rotate(angle);
    fill(palette[i % palette.length]);
    rect(0, -10, barLength, 20);
  }
  pop();
  fill(255);
  circle(mouseX, mouseY, 12);
}

function keyPressed() {
  if (key === 'g' || key === 'G') {
    saveGif('mouse-bars', 20);
  }
}

The dot is there because the pointer itself is not part of the canvas. Drawing a circle at mouseX, mouseY is the simplest possible proof that the two numbers really are where your hand is.

mousePressed()

Reading the mouse is one thing. Reacting to a click is another, and it needs a function p5.js calls for you, the same arrangement as keyPressed().

Every click drops a ring at that point, and every ring grows until it leaves the canvas.

let palette;
let clickX = [];
let clickY = [];
let ringSize = [];
let ringColour = [];
let clicks = 0;

function setup() {
  createCanvas(600, 600);
  frameRate(30);
  noFill();
  strokeWeight(6);
  palette = ['#FFBE0B', '#FB5607', '#FF006E', '#8338EC', '#3A86FF'];
}

function draw() {
  background(0);
  for (let i = 0; i < clicks; i++) {
    ringSize[i] = ringSize[i] + 4;
    stroke(ringColour[i]);
    circle(clickX[i], clickY[i], ringSize[i]);
  }
  push();
  noStroke();
  fill(255);
  circle(mouseX, mouseY, 12);
  pop();
}

function mousePressed() {
  clickX[clicks] = mouseX;
  clickY[clicks] = mouseY;
  ringSize[clicks] = 10;
  ringColour[clicks] = palette[floor(random(palette.length))];
  clicks = clicks + 1;
}

function keyPressed() {
  if (key === 'g' || key === 'G') {
    saveGif('click-rings', 20);
  }
}

One naming trap worth knowing about. JavaScript arrays have a push() method of their own, which would be the usual way to add to lists like these. This sketch uses a counter and direct indexing instead, because push() already means something else entirely in p5.js, saving the drawing state, and two unrelated things sharing a name is a trap rather than a lesson.

The scripts in this session were written for p5.js 2.3.2, the version the web editor runs by default.


Next session is the last of this series, and it looks back over all seventeen.