Skip to content

Javascript Canvas draw rectangles or circles

I’m searching for a way to “live” draw rectangles or circles on a canvas.

I found various ways with fillRect() to draw rectangles, but not live. What I mean is, to be able to mouseDown() on one point and move it to another point in the canvas, which defines the size of the canvas, just like for example in Microsoft Paint, OneNote and so on.

Can anybody help me out and give me an advice on how to get started? I might be thinking of a way on how to do it, without seeing the rectangle (or circle) size changing, something like:

 $("canvas").mousedown(function(event){
     var ctx = this.getContext("2d");
     ctx.clearRect(0,0,$(this).width(),$(this).height());
     var initialX = event.clientX - this.getBoundingClientRect().left;
     var initialY = event.clientY - this.getBoundingClientRect().top;

     $(this).mousemove(function(evt) {
         ctx.strokeRect(initialX, initialY, evt.clientX - event.clientX, evt.clientY - event.clientY);
     });
 });

But I want to see it live, so how the rectangles size changes when the user moves the mouse.

Answer

https://jsfiddle.net/zb66mxra/2/

To do it live you need to keep a constant image of your Canvas. This is accomplished easily by keeping an array of objects to be drawn over and over again by your JavaScript.

let drawArr = [];

An example object contains an x and y coordinate to begin drawing, a width, and a height:

 { x: 100,
  y: 100,
  w: 10,
  h: 10  }

when your mouse moves over the canvas you ONLY want it to change the array if the mouse is down. This means you need to set a flag to see if this case is either true or false:

  let mousedown = false;
  canvas.addEventListener('mousedown', function(e) {
    mousedown = true;
  ...
  });
  canvas.addEventListener('mouseup', function(e) {
    mousedown = false;
  });

When your mouse is down you want to add an item to draw to the array:

  canvas.addEventListener('mousedown', function(e) {
  mousedown = true;
  drawArr.push({
    x: e.pageX,
    y: e.pageY,
    w: 0,
    h: 0
  });
});

The height and width are initially set to 0. What we want to do now, if you can imagine, is create a height and width of the rectangle while we’re dragging the mouse over the canvas and the mouse is down. We want to adjust this on the fly so that when the screen is re-rendered it is seen as it’s being drawn.

It’s easy to manipulate the height and width because, as long as you’re only able to draw one at a time, it will ALWAYS be the most recent object added to the draw array.

  canvas.addEventListener('mousemove', function(e) {
  if (mousedown) {
    let i = drawArr.length -1;

    let {
      x,
      y
    } = drawArr[i];
    drawArr[i].w = e.pageX - x;
    drawArr[i].h = e.pageY - y;
  }
});

Finally we use requestAnimationFrame to constantly draw any object within the draw array. We do this by calling it when the page is loaded:

requestAnimationFrame(draw);

And then recursively within the draw function:

function draw() {
...
requestAnimationFrame(draw);
}

Then we simply need to clear the previous screen render and iterate over the draw array and draw everything to the screen again.

  function draw() {
    ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
    for (let obj of drawArr) {
    let {
      x,
      y,
      w,
      h
     } = obj;
      ctx.strokeRect(x, y, w, h);
    }
    requestAnimationFrame(draw);
  }

voila.