Clue Mediator

Draggable Rectangle on Canvas using React

📅July 12, 2020

Today we’ll show you how to create a draggable rectangle on canvas using React. In the previous article we have explained you, how to draw a rectangle on canvas using React.

You can also find the more article related to the Canvas in ReactJS.

Step to create draggable rectangle on Canvas

  1. Create a react application
  2. Draw a rectangle on canvas
  3. Add functionality to manage draggable rectangle
  4. Output

1. Create a react application

Let’s create a react application using `create-react-app`. Refer to this link for more information. Run the following command to set up a react app.

npx create-react-app draggable-rectangle-canvas-react

2. Draw a rectangle on canvas

In the next step, we have to write a logic to draw a rectangle on canvas using React. Check out the below article for more information.

Draw a rectangle on Canvas using React

3. Add functionality to manage draggable rectangle

  • First, we have to define a few variables to manage the click, drag element and position of the drag element.
  • Create a separate method `draw()` to draw an element. Here we have to clear the canvas context before we draw an element.
  • Create a new method `hitBox` to identify the click event in the rectangle.
  • Handle the several mouse events such as `onMouseDown`, `onMouseMove`, `onMouseUp` and `onMouseOut` to manage drag functionality.

Check out the following code.

App.js

import React, { useRef, useEffect } from 'react';

function App() {
  const canvas = useRef();
  let ctx = null;
  const boxes = [
    { x: 200, y: 220, w: 100, h: 50 },
    { x: 100, y: 120, w: 100, h: 50 }
  ]
  let isDown = false;
  let dragTarget = null;
  let startX = null;
  let startY = null;

  // initialize the canvas context
  useEffect(() => {
    // dynamically assign the width and height to canvas
    const canvasEle = canvas.current;
    canvasEle.width = canvasEle.clientWidth;
    canvasEle.height = canvasEle.clientHeight;

    // get context of the canvas
    ctx = canvasEle.getContext("2d");
  }, []);

  useEffect(() => {
    draw();
  }, []);

  // draw rectangle
  const draw = () => {
    ctx.clearRect(0, 0, canvas.current.clientWidth, canvas.current.clientHeight);
    boxes.map(info => drawFillRect(info));
  }

  // draw rectangle with background
  const drawFillRect = (info, style = {}) => {
    const { x, y, w, h } = info;
    const { backgroundColor = 'black' } = style;

    ctx.beginPath();
    ctx.fillStyle = backgroundColor;
    ctx.fillRect(x, y, w, h);
  }

  // identify the click event in the rectangle
  const hitBox = (x, y) => {
    let isTarget = null;
    for (let i = 0; i < boxes.length; i++) {
      const box = boxes[i];
      if (x >= box.x && x <= box.x + box.w && y >= box.y && y <= box.y + box.h) {
        dragTarget = box;
        isTarget = true;
        break;
      }
    }
    return isTarget;
  }

  const handleMouseDown = e => {
    startX = parseInt(e.nativeEvent.offsetX - canvas.current.clientLeft);
    startY = parseInt(e.nativeEvent.offsetY - canvas.current.clientTop);
    isDown = hitBox(startX, startY);
  }
  const handleMouseMove = e => {
    if (!isDown) return;

    const mouseX = parseInt(e.nativeEvent.offsetX - canvas.current.clientLeft);
    const mouseY = parseInt(e.nativeEvent.offsetY - canvas.current.clientTop);
    const dx = mouseX - startX;
    const dy = mouseY - startY;
    startX = mouseX;
    startY = mouseY;
    dragTarget.x += dx;
    dragTarget.y += dy;
    draw();
  }
  const handleMouseUp = e => {
    dragTarget = null;
    isDown = false;
  }
  const handleMouseOut = e => {
    handleMouseUp(e);
  }

  return (
    <div class="App">
      <h3>Draggable Rectangle on Canvas - <a href="http://www.cluemediator.com" target="_blank" rel="noopener noreferrer">Clue Mediator</a></h3>
      <canvas onmousedown={handleMouseDown} onmousemove={handleMouseMove} onmouseup={handleMouseUp} onmouseout={handleMouseOut} ref={canvas}></canvas>
    </div>
  );
}

export default App;

4. Output

Run the application and check the output in the browser.

Output - Draggable Rectangle on Canvas using React - Clue Mediator

Output - Draggable Rectangle on Canvas using React - Clue Mediator

That’s it for today.
Thank you for reading. Happy Coding..!!

Demo & Source Code

Github Repository StackBlitz Project