How to implement ctrl+Z to undo in a custom p5.js drawing program?

Hi I need help with the question…

Welcome to the forum.

Your question is clear but the scope is too wide. What you want undo? Your question indicates there is some user interaction to create something on the screen

One way to do a processing apps is to first clear everything in draw()-cycle and then add elements one by one to screen. Something like this

void draw() {
background(0);
for(graphicItem item : itemsList) {
  drawItem(item);
}

So if you are adding whatever user interaction is creating to a list or similar data structure then is pretty straight forwards to remove the most recent item from the list.

If you are drawing straight to the canvas then you need to store pixels that were under the drawn shape and put them back to undo. Other option is to store the whole canvas before last addition and return to it with undo.

Processing is really good at adding stuff to canvas(screen), but removing stuff is hard. You need to have some sort of history to return to previous state.

2 Likes

Hi Gustavo. Welcome to the forum.
Will this help?

let fillVal = 255;

function draw() {
  fill(fillVal);
  if (keyIsDown(CONTROL) && keyIsDown(90)) fillVal = 0;
  rect(25, 25, 50, 50);
}
1 Like

Hi every one , i dont know very well if my english is correct but…

My code is in p5.js and yes, the proyect is for draw serial lines starting from a center with the mouseIsPressed function ( i dont share my code in this case for a security issue), but in essence that is the idea. I need a typical “undo” that is used in any program, when you draw something and then press CONTROL+Z I need the last thing drawn to undo. Can you show me an example were this principle is fulfilled?

Thanks.

But isn’t my code exactly doing this?
If you write backgroun(255); instead of fillVal = 0;
it will "undo’ the rectangle drawing

Noel,

Yes but that apply for all the canvas. How I can undo the last drawing and not all the drawing in the all canvas?

thanks

SomeOne,
how i can store the pixels in p5.js?
thanks

https://p5js.org/reference/#/p5/createGraphics
draw into a buffer, store the result in a second one.
draw something else -> if undo replace the buffer with the stored one.

probably for more than 1 undo you need the appropriate number of buffers…

Here is the result of mi code https://editor.p5js.org/gquevedoe/present/XaEuf_NSF

Is it supposed to work with CONTROL + Z to undo ?

@noel Is what i try to do…

do you mean setBuffer() or reverseBuffer()?

It doesn’t undo anything on my PC, but I use a virtual keyboard. Maybe that’s why,

@noel I still can’t program it

Hello, here is a short example:

Obviously it only can do 1 Undo by pressing ‘z’. If you want more undos, you will have to make as many PGraphics layers and organize them so one, or more get cleared with undo.

The advantage is, that you do not have to care what is actually drawn (a circle, a rect, or whatever.
The disadvantage probably that you need many PGraphics…

The other option would be to store the history of objects being drawn somewhere to “redraw” everything or remove drawing steps that have been stored.

let pgFinal; // the Pgraphics that holds all previous things
let pgNew; // the PGraphics that ONLY holds the last object

function setup() {
  createCanvas(710, 400);
  pgFinal = createGraphics(400, 250);
  pgFinal.noFill();
  pgFinal.stroke(255);

  pgNewest = createGraphics(400, 250);
  pgNewest.noFill();
  pgNewest.stroke(255);
  fill(0);
}

function draw() {
  background(0);  
  //Draw the offscreen buffer to the screen with image()
  noTint(); 
  image(pgFinal, 150, 75);
  
  tint(255,0,0); // just to show its the new circle inside pgNewest 
  image(pgNewest,150,75);
}

// if a new circle is drawn, the content of pgNewest is added to pgFinal
// pgNewest is cleared and only the new circle is drawin into it
function mouseClicked() { 
  pgFinal.image(pgNewest,0,0);
  pgNewest.clear();
  pgNewest.ellipse(mouseX-150, mouseY-75, 60, 60); 
}

function keyTyped() {
  if (key === 'z') {
    pgNewest.clear();
    print("pressed");
  } 
}

So all these methods work, but I think the best way is to create a list of strokes, and inside those elements of that list, have the positions list of each pixel of the stroke, as well as the color.

1 Like

This answer at stackoverflow gives a broad view of the methods usually used to undo/redo

2 Likes