Public
Edited
Oct 21, 2022
3 forks
5 stars
Insert cell
Insert cell
// p8g can currently only initialize a WebGL2 canvas once.
// That means it can easily conflict with Observable's reactivity.
// To avoid that, use `createCanvas` to create a p8g canvas and pass it
// the draw and (optionally) setup functions.
// You can also optionally pass a css string to style the canvas
// (if no option is present, the canvas will be transparent)
createCanvas(512, 512, draw, setup, {css: "background: #000"})
Insert cell
// setup and draw are both passed a `p8g` object.
// This means you can use destructuring assignment
// in the parameters to avoid having to write
// `p8g.fill`, `p8g.rect`, etc.
//
// Note that unlike P5, `fill`, `stroke` and other
// settings are not kept between draw calls,
// so initializing those once in setup won't work!
// The reason for this is that p8g does not have
// its own `setup` function, just the `draw` loop.
function setup(p8g) {
// initiate background as bright blue
p8g.background(0x82, 0xb4, 0xed);
}
Insert cell
function draw({
strokeWeight,
rect,
width,
height,
ellipse,
mouseX,
mouseY
}){

// fill defaults to white, stroke defaults to black.
// All we need is to initiate the stroke size.
strokeWeight(2);

// draw a rectangle in the middle
rect(width/2 - 100, height/2 - 100, 200, 200);

// draw ellipse at mouse
ellipse(mouseX, mouseY, 50, 50)
}
Insert cell
Insert cell
// The normal p8g approach would be to assign a draw function to
// the p8g object, but because it's imported through skypack
// at runtime the p8g module is read-only. So instead we use
// this workaround.

createCanvas = {
const p8g = await import('https://cdn.skypack.dev/p8g.js@0.8.1?min');

let canvas = null;
let _draw = () => {};
let _setup = () => {};
let request = null;
let state = null;
return async function createCanvas(width, height, draw = _draw, setup = _setup, opts = {}) {

const {
css
} = opts
// cancel previous loop
if (request) cancelAnimationFrame(request);

if(typeof _setup !== "function") throw new Error("setup is not a function!");
if(typeof _draw !== "function") throw new Error("draw is not a function!")

_setup = setup;
_draw = draw;

if (!canvas) {
canvas = await html`${p8g.createCanvas(width, height)}`;
}
if (typeof css === "string") canvas.style = css;

state = setup(p8g);

// Draw Loop
request = requestAnimationFrame(function tick() {
draw(p8g, state);
request = requestAnimationFrame(tick);
});

invalidation.then(() => cancelAnimationFrame(request));

return canvas;
}
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more