Connect two rectangles with a line on canvas using React
In this article, we will show you how to connect two rectangles with a line on canvas using React. In previous articles, we have explained the drawing of rectangles, lines, and writing a text on canvas using React.
Check out the following articles related to the Canvas.
- Draw a rounded Rectangle on Canvas using React
- Draw a line on Canvas using React
- Write text on Canvas using React
Demo Application
Output - Connect two rectangles with a line on canvas using React - Clue Mediator
Steps to connect two rectangles with a line on canvas
- Create a react application
- Draw draggable rectangles on canvas
- Draw a line between two rectangles
- Output
1. Create a react application
Let’s create a react application using the `create-react-app` package. Run the following command.
npx create-react-app connect-rectangles-with-line-react
2. Draw draggable rectangles on canvas
Before drawing a line between two rectangles, we will draw draggable rectangles on canvas. Refer the following article to draw draggable rectangles.
Draggable Rectangle on Canvas using React
In this article, we will draw four rectangles for the demonstration.
3. Draw a line between two rectangles
To draw a line between two rectangles, we will use the list of the connectors where we can store the index of the start box and the end box as below.
const boxes = [
{ x: 200, y: 220, w: 80, h: 40 },
{ x: 100, y: 120, w: 70, h: 50 },
{ x: 20, y: 20, w: 60, h: 40 },
{ x: 250, y: 80, w: 55, h: 50 }
];
const connectors = [
{ startBoxIndex: 0, endBoxIndex: 1 },
{ startBoxIndex: 2, endBoxIndex: 3 }
];
Same as the boxes, we will draw the connectors based on the start box index and the end box index. Here we are fetching the center point of the start box and end box to draw the line using the `moveTo` and `lineTo` methods.
// draw rectangles and connectors
const draw = () => {
ctx.clearRect(0, 0, canvas.current.clientWidth, canvas.current.clientHeight);
boxes.map(info => drawFillRect(info));
connectors.map(connector => drawConnector(connector));
}
// draw connector line between two rectangles
const drawConnector = (connector) => {
var startBoxIndex = boxes[connector.startBoxIndex];
var endBoxIndex = boxes[connector.endBoxIndex];
ctx.beginPath();
ctx.moveTo(startBoxIndex.x + startBoxIndex.w / 2, startBoxIndex.y + startBoxIndex.h / 2);
ctx.lineTo(endBoxIndex.x + endBoxIndex.w / 2, endBoxIndex.y + endBoxIndex.h / 2);
ctx.stroke();
}
You can also set the color and width of the line. Refer the following article for more information.
Draw a line on Canvas using React
Let’s combine all code together and see how it looks.
App.js
import React, { useRef, useEffect } from 'react';
function App() {
const canvas = useRef();
let ctx = null;
const boxes = [
{ x: 200, y: 220, w: 80, h: 40 },
{ x: 100, y: 120, w: 70, h: 50 },
{ x: 20, y: 20, w: 60, h: 40 },
{ x: 250, y: 80, w: 55, h: 50 }
];
let isDown = false;
let dragTarget = null;
let startX = null;
let startY = null;
const connectors = [
{ startBoxIndex: 0, endBoxIndex: 1 },
{ startBoxIndex: 2, endBoxIndex: 3 }
];
// 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 rectangles and connectors
const draw = () => {
ctx.clearRect(0, 0, canvas.current.clientWidth, canvas.current.clientHeight);
boxes.map(info => drawFillRect(info));
connectors.map(connector => drawConnector(connector));
}
// draw connector line between two rectangles
const drawConnector = (connector) => {
var startBoxIndex = boxes[connector.startBoxIndex];
var endBoxIndex = boxes[connector.endBoxIndex];
ctx.beginPath();
ctx.moveTo(startBoxIndex.x + startBoxIndex.w / 2, startBoxIndex.y + startBoxIndex.h / 2);
ctx.lineTo(endBoxIndex.x + endBoxIndex.w / 2, endBoxIndex.y + endBoxIndex.h / 2);
ctx.stroke();
}
// 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>Connect two rectangles<br>with a line 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 react application and check the output in the browser.
That’s it for today.
Thank you for reading. Happy Coding..!! 🙂