Search code examples
javascriptfunctiondrawingp5.js

Why can't I draw when background is located in the draw() function? p5.js


I am making a basic drawing application on p5.js.

I have placed my background under the draw function as I have inserted sliders to change the rgb of the background.

Once I do this, I cannot draw however. I have a mousePressed function, which works when I move the background to setup().

Any ideas of why this may be?

let brushSize;
let white;
let redB;
let yellowB;
let blueB;
let blackB;
let greenB;
let pinkB;
let brownB;
let brushColor;


let rSlide, gSlide, bSlide;
let r, g, b;
let imgLego;
let imgBrush;
let fontHead;
let fontMid;
let x;

function preload() {
  imgLego = loadImage("images/lego.png");
  imgBrush = loadImage("images/paint_brush.png");
  fontHead = loadFont("fonts/shizuru.ttf");
  fontMid = loadFont("fonts/concertOne.ttf");
  
}// close preload function

function setup() {
  x = 10;
  createCanvas(1000, 600);
  noStroke();

  // create the slider for the brush size
  brushSize = createSlider(1, 100, 20);

  // create the sliders for red, gree, blue values
  rSlide = createSlider(0, 255, 255);
  gSlide = createSlider(0, 255, 255);
  bSlide = createSlider(0, 255, 255);

  // position the sliders
  rSlide.position(x, x * 20);
  gSlide.position(x, x * 22);
  bSlide.position(x, x * 24);
  brushSize.position(x, x * 26);

  // variables to hold the colour (background)
  r = 255;
  g = 255;
  b = 255;
  
  // color variables for brush
  redB = color(255);
  whiteB = color(255,0,0);
  yellowB = color(246, 236, 54);
  blueB = color(0,0,255);
  blackB = color(0);
  greenB = color(0,170,35);
  pinkB = color(255,53,184);
  brownB = color(155,103,60);
  brushColor = redB;
}

function draw() {
  
 
  background(r, g, b);
  noStroke();
  
  // poisition the text & value of slider
  textAlign(LEFT, TOP);
  fill(120, 120, 255);
  textFont(fontMid);
  textSize(15);
  text("red : " + rSlide.value(), x*2 + rSlide.width, x*20);
  text("green : " + gSlide.value(), x*2 + gSlide.width, x*22);
  text("blue : " + bSlide.value(), x*2 + bSlide.width, x*24);
  text("brush : ", x*2 + bSlide.width, x*26);

  // read the value of the slider and store it in a variable
  r = rSlide.value();
  g = gSlide.value();
  b = bSlide.value();

  // create & position the default brush to follow the mouse
  //ellipse(mouseX, mouseY, brushSize.value(), brushSize.value());
  
  // customise "background" text
  fill(0);
  textSize(20);
  text("BACKGROUND", 20, 180);
  
  // red "navbar"
  fill(255,0,0)
  rect(0,0,1000,120,0,0,50,0);
  
  // customse "sketch" text
  fill(255)
  textFont(fontHead);
  textSize(40);
  text("SKETCH", 180, 10)
  
  // images
  image(imgBrush, 930, 40, 40, 40);
  image(imgLego, 20, 15, 160, 90);
  
  //**lego block top right corner**//
  stroke(0);
  strokeWeight(3)
  // yellow block
  fill(246, 236, 54);
  rect(748,18,164,84,5)
  
  // paint buttons
  ellipseMode(CENTER);
  // white button
  fill(whiteB);
  ellipse(770,40,30);
  // red button
  fill(redB);
  ellipse(810,40,30);
  // yellow button
  fill(yellowB);
  ellipse(850,40,30);
  // blue button
  fill(blueB);
  ellipse(890,40,30);
  // black button
  fill(blackB);
  ellipse(770,80,30);
  // green button
  fill(greenB);
  ellipse(810,80,30);
  // pink button
  fill(pinkB);
  ellipse(850,80,30);
  // brown button
  fill(brownB);
  ellipse(890,80,30);
}


// create function to allow the mosue to draw the relevant colours from the lego bloack colour paletter - top right corner

function mouseDragged() {
  stroke(brushColor);
  strokeWeight(5);
  line(mouseX,mouseY,pmouseX,pmouseY);
}

Solution

  • Note that the draw function is continuously executed.

    This is what's happening:

    • mouseDragged draws a line
    • draw function runs in the next frame and whatever's inside this function gets re-drawn on top

    So if there's a background() call inside the draw function, it will re-draw the background on top of whatever was previously drawn. Hence the order of operation is so important in processing.

    In your sketch, instead of drawing the line in mouseDragged, you can to draw it inside the draw loop after background() is called. For example:

    // Globally accessed variable, declared at the top
    // Stores the metadata for all the lines drawn in mouseDragged
    let drawnLines = []
    
    function mouseDragged() {
      drawnLines.push({
        mouseX: mouseX,
        mouseY: mouseY,
        pmouseX: pmouseX,
        pmouseY: pmouseY,
      });
    }
    
    function draw() {
      // Draw the background
      background(255, 255, 255);
    
      // Draw the lines drawn by the user
      stroke(brushColor);
      strokeWeight(5);
      drawnLines.forEach(drawnLine => {
        line(
          drawnLine.mouseX,
          drawnLine.mouseY,
          drawnLine.pmouseX,
          drawnLine.pmouseY);
      });
    }