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
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.
1 | 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.
1 2 3 4 5 6 7 8 9 10 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | 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 className="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..!! 🙂