The Interview Question
During a recent technical interview, I was given an interesting challenge:
"You need to build a React application where users can click anywhere on the screen to generate circles of random sizes. The circles should change color if they intersect with existing ones. Additionally, after every third click, the canvas should reset."
I had to quickly break down the problem and come up with an efficient way to handle circle positioning, intersection detection, and state management in React.
My Thought Process & Approach
When tackling this problem, I broke it down into the following key components:
Tracking Click Events - Each click should generate a new circle at the clicked position.
Generating Random Radius - The circle's radius should be randomly assigned between 20 and 200 pixels.
Detecting Circle Intersections - If the new circle overlaps with any existing ones, it should turn red; otherwise, it remains blue.
Managing State with React Hooks - Using
useState
to store and update the list of circles.Resetting After Three Clicks - The canvas should clear every third click to keep the UI fresh and test state management.
With these requirements in mind, I began implementing the solution.
The Solution
Here’s the final implementation of my solution:
import { useState, useEffect } from "react";
import "./App.css";
function App() {
const [circles, setCircles] = useState([]);
const [clickCount, setClickCount] = useState(0);
useEffect(() => {
console.log(circles);
}, [circles]);
// Function to check if a new circle overlaps any existing ones
const checkIntersection = (newCircle) => {
return circles.some((circle) => {
const dx = circle.x - newCircle.x;
const dy = circle.y - newCircle.y;
const distance = Math.sqrt(dx * dx + dy * dy);
return distance <= circle.radius + newCircle.radius;
});
};
const handleClick = (e) => {
if (clickCount === 2) {
setClickCount(0);
setCircles([]);
return;
}
const radius = Math.random() * (200 - 20) + 20;
const newCircle = {
x: e.clientX,
y: e.clientY,
radius: radius,
intersects: checkIntersection({ x: e.clientX, y: e.clientY, radius }),
};
setClickCount((count) => count + 1);
setCircles((prev) => [...prev, newCircle]);
};
return (
<div
onClick={handleClick}
style={{ width: "100vw", height: "100vh", backgroundColor: "#f0f0f0", position: "relative" }}
>
{circles.map((circle, idx) => (
<div
className="circle"
key={idx}
style={{
position: "absolute",
width: `${circle.radius}px`,
height: `${circle.radius}px`,
top: `${circle.y - circle.radius / 2}px`,
left: `${circle.x - circle.radius / 2}px`,
backgroundColor: circle.intersects ? "red" : "blue",
borderRadius: "50%",
pointerEvents: "none",
}}
></div>
))}
</div>
);
}
export default App;
Code Explanation
1. Tracking Click Events
The
handleClick
function is triggered when the user clicks anywhere on the screen.It captures the
x
andy
coordinates from the click event (e.clientX
ande.clientY
).
2. Generating Random Radius
The radius of the new circle is randomly generated using:
const radius = Math.random() * (200 - 20) + 20;
This ensures a range between 20px and 200px.
3. Detecting Circle Intersections
The
checkIntersection
function calculates the distance between the new circle and all existing ones:const dx = circle.x - newCircle.x; const dy = circle.y - newCircle.y; const distance = Math.sqrt(dx * dx + dy * dy); return distance <= circle.radius + newCircle.radius;
- If the distance is less than or equal to the sum of the radii, the circles intersect.
4. Managing State with useState
circles
state stores the list of circles created.clickCount
tracks how many clicks have occurred before resetting.The
setCircles([...prev, newCircle])
updates the list of circles after every click.
5. Resetting After Three Clicks
- Every third click (
clickCount === 2
) clears the screen:
if (clickCount === 2) {
setClickCount(0);
setCircles([]);
return;
}
- This ensures a fresh canvas every three clicks.
Challenges Faced
Handling Click Event Properly
- Initially, I had an issue where clearing the circles happened after adding a new one. Fixing the sequence of state updates resolved this.
Intersection Accuracy
- At first, I used
<=
but had rounding errors with floating points. I ensured calculations were precise withMath.sqrt(dx * dx + dy * dy)
.
- At first, I used
Preventing Circles from Blocking Clicks
- I used
pointerEvents: "none"
on circles so that clicks would still register properly.
- I used
Key Takeaways
✅ Breaking down the problem helped me focus on one feature at a time.
✅ Using React's useState
efficiently made it easy to track clicks and circles.
✅ Mathematical precision is important when handling geometric calculations.
✅ Handling state updates properly ensures smooth and expected UI behavior.
Final Thoughts
This question tested my ability to work with React state, event handling, mathematical calculations, and UI updates. I enjoyed the challenge, and solving it boosted my confidence in handling complex UI interactions.
Would you approach this problem differently? Let me know your thoughts! Also, I will be adding more question.