vue, p5.js

Experiment with p5.js and Vue

Background

This post is a note from my research on drawing p5.js using the Vue framework. The p5.js is a library derived from Processing, and is useful for visual expression. There is an open editor environment called OpenProcessing, so you can write visuals as soon as you write a program. Galleries other users created is also helpful. Visitor can appreciate many kinds of art and design works on that site. This time, I examined how to display the code written by p5.js with Vue framework.

Import library

After creating a Vue project(I created it with a Nuxt, but I think the same result will be got by vue-cli.), install the p5.js library with this command.

npm install --save p5

Now you can use p5.js immediately. But the only concerned point is that functions and properties prepared in p5.js will be expanded into global field. So it can not be handled well. Therefore, the object of p5 should be created by instance mode in order to prevent conflicts with the global property. Get more information about instance mode here. The code creating the p5 object is as follows. The practical implementation code of p5.js is written in the callback function passed from initialization of P5 class.

mounted() {   
 const script = function (p5) {    
  var speed = 2;    
  var posX = 0;
  
  // NOTE: Set up is here   
  p5.setup = _ => {      
   p5.createCanvas(500, 500);      
   p5.ellipse(p5.width / 2, p5.height / 2, 500, 500);    
  }     
  // NOTE: Draw is here
  p5.draw = _ => {      
   p5.background(0);
   const degree = p5.frameCount * 3;      
   const y = p5.sin(p5.radians(degree)) * 50;
    
   p5.push();
    p5.translate(0, p5.height / 2);
    p5.ellipse(posX, y, 50, 50);
   p5.pop();
   posX += speed;
      
   if (posX > p5.width || posX < 0) {    
    speed *= -1;      
   }
  }  
 }   
 // NOTE: Use p5 as an instance mode
 const P5 = require('p5');
 new P5(script)
}
The result of above code

Display p5 canvas on optional position

The canvas is displayed at the left corner in the default unless override the position. If you want to set it on an original container, prepare one with specific id at first.

<template>
  <div class="container border">
    <div class="d-flex justify-content-center" id="p5Canvas"></div>
  </div>
</template>

I pre-installed bootstrap to layout the specific container to center. Then set the container as the root of the default p5 canvas. You can customize the position of p5 canvas by changing css properties of the container.

// p5.createCanvas(500, 500);
var canvas = p5.createCanvas(500, 500)
canvas.parent("p5Canvas");

External file

I extructed the p5 code from the vue file, then put it on the new js file. It is a bit better for clean code because the logic of the visualizing is only written by JavaScript. This may be somewhat putting the cart before horse. But it is easier to implement p5 code because I can focus to write the only p5 code in that file.

At first I created a visual which you must have seen at the top of this page, then prepared file called Radar.js. It is read in the vue file to draw the visual on any situation and timing.

// in mounted ...
var radar = require('@/js/Radar.js')
const P5 = require('p5')
new P5(radar.main)
// NOTE: Radar.js
let p5; 
export function main(_p5) {
  p5 = _p5
 ... Same code for setup and draw before 
}

You can access p5 object in the external JavaScript file by exporting main function in advance. This main function is passed when the p5 object is created.

new P5(radar.main)

Get callback

Change above sample so as to be more effective for Vue framework, which means using two-way reactive binding property.

Add data and methods

// NOTE: Add data
data() {
  return {
    message: ""
  }
},
// NOTE: Add callback method
methods: {
  callbackOnP5: function(timeStr) {
    this.message = timeStr;
  }
},

Display the property in real-time changing.

<div class="message d-flex justify-content-center">
  {{ message }}
</div>

Set callback function to get a new value.

radar.setDelegate(this.callbackOnP5);

At the Radar.js, send a new value to Vue by the callback function every time the seconds advance.

let delegate;
let p5;
export function main(_p5) {
 p5 = _p5
 p5.draw = _ => {
   notifyCurrentTime();
 }
}

export function setDelegate(_delegate) {
  delegate = _delegate;
}

function notifyCurrentTime() {
  if (delegate !== undefined) {
    const message = p5.hour() + ":" + p5.minute() + ":" + p5.second();

    delegate(message);
  }
}

Please back to the top image again and look at carefully what the value is changing in real-time.

Conclusion

This is all about how to use p5.js with Vue. If you use p5.js to draw some visualization, you will find it more easier to write it than native code for canvas. Let’s try to code on a playground or have a look at great art work with p5.js on OpenProcessing.

My demonstration code is on GitHub as well as OpenProcessing.