Moro Owusu Afriyie
Moro Owusu Afriyie

Reputation: 475

How to show a rectangle while drawing it on mousemove html canvas

I'm trying to let users draw rectangles on a canvas using the mouse and i've been able to get it to work to some extent.The users can draw the rectangles using the mouse but it only shows after the mouseup event but i also want the users to also see the rectangles while drawing it on mousemove event. How can i achieve this and at the same time let users draw multiple rectangles which currently works but i want them to see it while drawing the rectangles.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <style>
    #container {
      /*background-color: lime;*/
      width: 150px;
      height: 150px;
      cursor: pointer;
    }
    
    .close {
      color: #aaa;
      float: right;
      font-size: 28px;
      font-weight: bold;
    }
    
    .close:hover,
    .close:focus {
      color: black;
      text-decoration: none;
      cursor: pointer;
    }
    
    #heatmapContainer {
      border: 1px solid red;
    }
  </style>
</head>

<body>
  <div class="heatmapWrapper">
    <div id="heatmapContainer" style="height: 4205px; width: 1278px">
      <div id="heatmap1" class="heatmapTile" style="height: 4205px; position: relative">
        <canvas id="myCanvas" class="heatmap-canvas" width="1278" height="4205" style="position: absolute; left: 0px; top: 0px"></canvas>
      </div>
    </div>
  </div>
  <script>
    var canvas = document.getElementById('myCanvas'),
      elemLeft = canvas.offsetLeft,
      elemTop = canvas.offsetTop,
      context = canvas.getContext('2d');

    let start = {};
    var mouseDown = false;

    function getMousePos(canvas, evt) {
      var rect = canvas.getBoundingClientRect(),
        scaleX = canvas.width / rect.width,
        scaleY = canvas.height / rect.height;

      return {
        x: (evt.clientX - rect.left) * scaleX,
        y: (evt.clientY - rect.top) * scaleY,
      };
    }

    function startRect(e) {
      start = getMousePos(canvas, e);
      mouseDown = true;
    }

    window.addEventListener('mousedown', startRect);

    function endRect(e) {
      let {
        x,
        y
      } = getMousePos(canvas, e);
      context.strokeStyle = 'blue';
      context.strokeRect(start.x, start.y, x - start.x, y - start.y);
      mouseDown = false;
    }

    function drawSquare(e) {
      if (!mouseDown) return;
      // creating a square
      var width = Math.abs(start.x - canvas.getBoundingClientRect().offsetLeft);
      var height = Math.abs(start.y - canvas.getBoundingClientRect().offsetLeft);

      context.beginPath();
      context.rect(start.x, start.y, width, height);
      context.strokeStyle = 'blue';

      context.stroke();
    }

    window.addEventListener('mouseup', endRect);

    window.addEventListener('mousemove', drawSquare);
    /**End Drawing a rectangle on the canvas **/
  </script>
</body>

</html>

Upvotes: 2

Views: 1385

Answers (1)

Helder Sepulveda
Helder Sepulveda

Reputation: 17584

We need to make something different, instead of drawing on the fly we need to add the rectangles to an array, then clean the canvas and draw them on demand, that way we can also draw additional elements, on the sample below I draw a red rectangle while moving and blue ones once we release the mouse

var canvas = document.getElementById('myCanvas')
var context = canvas.getContext('2d')

let start = {}
let rects = [{x: 9, y: 9, width: 50, height: 30}]

function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect()
  return {
    x: (evt.clientX - rect.left) * canvas.width / rect.width,
    y: (evt.clientY - rect.top) * canvas.height / rect.height,
  };
}

function startRect(e) {
  start = getMousePos(canvas, e);
}

function endRect(e) {
  let { x, y } = getMousePos(canvas, e)
  rects.push({x: start.x, y: start.y, width: x - start.x, height: y - start.y})
  start = {}
  draw()
}

function draw() {
  context.clearRect(0, 0, canvas.width, canvas.height)
  rects.forEach(rect => {
    context.beginPath();
    context.rect(rect.x, rect.y, rect.width, rect.height);
    context.strokeStyle = 'blue';
    context.stroke();
  }); 
}

function drawMove(e) {
  if (start.x) {
    draw()
    let { x, y } = getMousePos(canvas, e)
    context.beginPath();
    context.rect(start.x, start.y, x - start.x, y - start.y);
    context.strokeStyle = 'red';
    context.stroke();
    context.beginPath();
    context.arc(start.x, start.y, 5, 0, 2 * Math.PI);
    context.fill();
    context.beginPath();
    context.arc(x, y, 5, 0, 2 * Math.PI);
    context.fill();
  }
}
draw()

window.addEventListener('mouseup', endRect)
window.addEventListener('mousedown', startRect)
window.addEventListener('mousemove', drawMove)
canvas { border: solid }
<canvas id="myCanvas" width="400" height="400"></canvas>

Upvotes: 5

Related Questions