I would like to paint ellipses over an image when clicking the mouse, and when I press the keyboard, hide and show the underneath image alternatively, without cleaning the ellipses.
I'm using createGraphics() to store the image data, and remove() so when the keyboard is pressed I spect the image disappear but it doesn't work
Here is a sketch of what I trying to do:
let isMouseBeeingPressed = false;
let img;
let isShow = true
let bufferImg;
function preload() {
img = loadImage(
"https://images.pexels.com/photos/20787/pexels-photo.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500"
);
}
function setup() {
createCanvas(500, 500);
background(255);
loadImageBuffer();
}
function loadImageBuffer() {
bufferImg = createGraphics(400, 400);
bufferImg.image(img, 0, 0);
image(bufferImg, 0, 0);
}
function draw() {
if(isMouseBeeingPressed) {
stroke(0, 0, 0, 50);
fill(255);
ellipse(mouseX, mouseY, 20);
}
}
function keyPressed() {
if(isShow) {
bufferImg.remove();
} else {
image(bufferImg, 0, 0);
}
console.log('isShow:', isShow);
return isShow = !isShow;
}
function mousePressed() {
isMouseBeeingPressed = true;
}
function mouseReleased() {
isMouseBeeingPressed = false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
Any idea of how to achieve this?
The best approach is probably to draw the ellipses to a separate buffer (p5.Graphics
), and then draw that on top of the image or blank background as needed. An alternative approach would be to record the position of each ellipse in an array so that they can be redrawn. However, the latter approach will use more memory and switching the image on and off will have a noticeable delay after many ellipses have been drawn.
p5.Graphics
)let img;
let graphics;
let isShow = true;
function preload() {
img = loadImage(
"https://images.pexels.com/photos/20787/pexels-photo.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500"
);
}
function setup() {
createCanvas(500, 500);
background(255);
image(img, 0, 0);
graphics = createGraphics(width, height);
}
function draw() {
if (mouseIsPressed) {
graphics.stroke(0, 0, 0, 50);
graphics.fill(255);
graphics.ellipse(mouseX, mouseY, 20);
background(255);
if (isShow) {
image(img, 0, 0);
}
image(graphics, 0, 0);
}
}
function keyPressed(e) {
isShow = !isShow;
background(255);
if (isShow) {
image(img, 0, 0);
}
image(graphics, 0, 0);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
Update: one thing to note about this approach is that whenever the mouse is pressed, the entire scene must be redrawn (white background, image if applicable, and foreground). The reason for this is antialiasing and transparency. When you draw an ellipse on the graphics
buffer the edges will have some partially transparent pixels due to antialiasing. If you repeatedly draw the buffer as an overlay without redrawing what is behind it then the partially transparent pixels will become less and less transparent until they are sold black. This will cause your ellipses to have a slightly thicker and more pixelated outer edge.
let img;
let isShow = true
let positions = [];
function preload() {
img = loadImage(
"https://images.pexels.com/photos/20787/pexels-photo.jpg?auto=compress&cs=tinysrgb&dpr=1&w=500"
);
}
function setup() {
createCanvas(500, 500);
background(255);
image(img, 0, 0);
}
function draw() {
if (mouseIsPressed) {
stroke(0, 0, 0, 50);
fill(255);
ellipse(mouseX, mouseY, 20);
positions.push([mouseX, mouseY]);
}
}
function keyPressed() {
isShow = !isShow;
background(255);
if (isShow) {
image(img, 0, 0);
}
stroke(0, 0, 0, 50);
fill(255);
for (const [x, y] of positions) {
ellipse(x, y, 20);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>