Sujeet Raman

Sujeet Raman

  • 773
  • 927
  • 341.8k

Connecting Lines Between Selected Boxes in React Component Not Display

Jun 8 2024 5:50 AM

I'm working on a React component where I have two sets of boxes on the left and right sides of the screen. The user can select one box from each side and click a "Connect" button to draw a line between the selected boxes. The line should connect the selected boxes, but I'm facing an issue. When I select the first box from the left side and the first box from the right side, the line is drawn between the second boxes on both sides instead of the selected ones. Similarly, when I select the second set of boxes, the line is drawn between the third set. I'm new to this, and my calculations and positioning are not working as expected.

 

import React, { useState, useEffect, useRef } from 'react';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Radio from '@mui/material/Radio';
import FormControlLabel from '@mui/material/FormControlLabel';
import RadioGroup from '@mui/material/RadioGroup';
import Button from '@mui/material/Button';

const UI_OPTIONS_LEFT = [ 'A', 'B', 'C', 'D' ];
const UI_OPTIONS_RIGHT = [ '1', '2', '3', '4' ];

export default function Flowchart() {
	const [ leftSelected, setLeftSelected ] = useState('');
	const [ rightSelected, setRightSelected ] = useState('');
	const [ isConnectEnabled, setIsConnectEnabled ] = useState(false);
	const [ showConnector, setShowConnector ] = useState(false);
	const [ connectorPosition, setConnectorPosition ] = useState({ x1: 0, y1: 0, x2: 0, y2: 0 });
	const connectorRef = useRef(null);

	useEffect(
		() => {
			setIsConnectEnabled(!!leftSelected && !!rightSelected);
		},
		[ leftSelected, rightSelected ]
	);

	const handleLeftChange = (event) => {
		setLeftSelected(event.target.value);
	};

	const handleRightChange = (event) => {
		setRightSelected(event.target.value);
	};

	const handleConnectClick = () => {
		if (isConnectEnabled) {
			const leftIndex = UI_OPTIONS_LEFT.indexOf(leftSelected);
			const rightIndex = UI_OPTIONS_RIGHT.indexOf(rightSelected);

			const leftBox = document.querySelector(`#left-${leftIndex}`);
			const rightBox = document.querySelector(`#right-${rightIndex}`);

			if (leftBox && rightBox) {
				const leftBoxRect = leftBox.getBoundingClientRect();
				const rightBoxRect = rightBox.getBoundingClientRect();

				const x1 = leftBoxRect.left + leftBoxRect.width / 2;
				const y1 = leftBoxRect.top + leftBoxRect.height / 2;
				// Adjust x2 to touch the left side edge of the right box
				const x2 = rightBoxRect.left;
				const y2 = rightBoxRect.top + rightBoxRect.height / 2;

				setConnectorPosition({ x1, y1, x2, y2 });
				setShowConnector(true);
			}
		}
	};

	return (
		<Box display="flex" flexDirection="column" alignItems="center" width="100%" position="relative">
			<Typography variant="h5" mb={4}>
				Select UI Flow
			</Typography>
			<Box display="flex" flex={1} mb={4} position="relative">
				<OptionsBox
					options={UI_OPTIONS_LEFT}
					selected={leftSelected}
					onChange={handleLeftChange}
					idPrefix="left-"
				/>
				<OptionsBox
					options={UI_OPTIONS_RIGHT}
					selected={rightSelected}
					onChange={handleRightChange}
					idPrefix="right-"
				/>
				{showConnector && (
					<ConnectorLine
						ref={connectorRef}
						x1={connectorPosition.x1}
						y1={connectorPosition.y1}
						x2={connectorPosition.x2}
						y2={connectorPosition.y2}
					/>
				)}
			</Box>
			<Button variant="contained" color="primary" onClick={handleConnectClick} disabled={!isConnectEnabled}>
				Connect
			</Button>
		</Box>
	);
}

function OptionsBox({ options, selected, onChange, idPrefix }) {
	return (
		<Box display="flex" flexDirection="column" gap={4} flex={1} mr={8}>
			<RadioGroup value={selected} onChange={onChange}>
				{options.map((name, index) => (
					<Box key={name} display="flex" alignItems="center" mb={2}>
						<FormControlLabel
							value={name}
							control={<Radio />}
							label=""
							id={`${idPrefix}${index}`}
							sx={{ marginRight: 2 }}
						/>
						<Box
							height={50}
							width={50}
							display="flex"
							alignItems="center"
							justifyContent="center"
							p={2}
							sx={{ border: '2px solid grey' }}
						>
							{name}
						</Box>
					</Box>
				))}
			</RadioGroup>
		</Box>
	);
}

const ConnectorLine = React.forwardRef(({ x1, y1, x2, y2 }, ref) => {
	return (
		<svg style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }}>
			<line ref={ref} x1={x1} y1={y1} x2={x2} y2={y2} style={{ stroke: 'black', strokeWidth: 2 }} />
		</svg>
	);
});

 


Answers (2)