I have a web page which encloses a few sketches, all written in P5.JS
Each sketch uses its own name space, so that it runs independently from the others.
I noticed that, for each sketch, the level of performance is lower than the one I get when it runs alone in a separate web page.
My question : what can I do to prevent all the sketches to run all at once ? Is it possible, for example, to activate a sketch only when the mouse hovers its canvas ? It would probably spare ressources.
Thank you for your help.
You can call noLoop()
and loop()
to stop and restart a sketch. There aren't any built in p5.js events to help you trigger noLoop()
when the mouse leaves the sketch or when the sketch is scrolled off screen, however there are a couple of ways you can do it which rely on using the underlying browser functionality:
mouseenter
and mouseleave
eventswinMouseX
and winMouseY
against the sketch canvas getBoundingClientRect()
in each call to draw()
function makeSketch(...colorArgs) {
return (p) => {
let bgColor;
let black;
let c;
p.setup = () => {
c = p.createCanvas(p.windowWidth, p.windowHeight / 3);
bgColor = p.color(...colorArgs);
black = p.color(0);
c.elt.addEventListener('mouseenter', () => {
p.loop();
});
c.elt.addEventListener('mouseleave', () => {
p.noLoop();
});
let bounds = c.elt.getBoundingClientRect();
// Just in case the mouse is already over the canvas when it is created.
// This is also how you would use getBoundingClientRect from the draw()
// and mouseMoved() functions instead of the mouseenter/mouseleave events.
if (p.winMouseX < bounds.left ||
p.winMouseX > bounds.right ||
p.minMouseY < bounds.top ||
p.winMouseY > bounds.bottom) {
p.noLoop();
}
};
p.draw = () => {
p.background(p.lerpColor(
bgColor,
black,
p.abs((p.frameCount % 240 - 120) / 120)
));
let bounds = c.elt.getBoundingClientRect();
p.fill('white');
p.noStroke();
p.text(`${p.winMouseX}, ${p.winMouseY} :: ${bounds.left}, ${bounds.top}, ${bounds.right}, ${bounds.bottom}`, 10, 10);
}
};
}
let sketch1 = new p5(makeSketch('red'));
let sketch2 = new p5(makeSketch(0, 255, 0));
let sketch3 = new p5(makeSketch('blue'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
You might also find that it is sufficient to pause sketches that are off screen:
function makeSketch(...colorArgs) {
return (p) => {
let bgColor;
let black;
let c;
let isLooping;
p.setup = () => {
c = p.createCanvas(p.windowWidth, p.windowHeight);
bgColor = p.color(...colorArgs);
black = p.color(0);
let bounds = c.elt.getBoundingClientRect();
isLooping = true;
if (bounds.bottom < 0 ||
bounds.top > p.windowHeight) {
p.noLoop();
isLooping = false;
}
// Might need to check this on resize as well.
document.addEventListener('scroll', () => {
let bounds = c.elt.getBoundingClientRect();
// Note this only checks verticle scrolling, but you could check horizontal as well
if (bounds.bottom > 0 &&
bounds.top <= p.windowHeight) {
if (!isLooping) {
isLooping = true;
console.log(`sketch ${colorArgs.join(',')}: loop`);
p.loop();
}
} else if (isLooping) {
isLooping = false;
console.log(`sketch ${colorArgs.join(',')}: noLoop`);
p.noLoop();
}
});
};
p.draw = () => {
p.background(p.lerpColor(
bgColor,
black,
p.abs((p.frameCount % 240 - 120) / 120)
));
p.fill('white');
p.noStroke();
p.text(`${p.frameCount}`, 10, 10);
}
};
}
let sketch1 = new p5(makeSketch('red'));
let sketch2 = new p5(makeSketch(0, 255, 0));
let sketch3 = new p5(makeSketch('blue'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>