import React, { useState, useEffect } from "react";
import { Stage, Layer, Circle, Rect } from "react-konva";
import Konva from "konva";
import ColorPicker from "./ColorPicker";
interface Ball {
id: number;
x: number;
y: number;
radius: number;
color: string;
vx: number;
vy: number;
isDragging: boolean;
}
const BallCanvas: React.FC = () => {
const [balls, setBalls] = useState<Ball[]>([
{
id: 1,
x: 50,
y: 50,
radius: 20,
color: "#ffffff",
vx: 0,
vy: 0,
isDragging: true,
},
{
id: 2,
x: 150,
y: 100,
radius: 30,
color: "yellow",
vx: 0,
vy: 0,
isDragging: false,
},
{
id: 3,
x: 250,
y: 150,
radius: 40,
color: "black",
vx: 0,
vy: 0,
isDragging: false,
},
]);
const [color, setColor] = useState<{ background: string }>({
background: "#fff",
});
const [picker, setPicker] = useState(false);
const changePicker = () => {
setPicker((prevst) => !prevst);
};
useEffect(() => {
let animationFrame = requestAnimationFrame(animate);
function animate() {
const updatedBalls = balls.map((ball) => {
let newVx = ball.vx;
let newVy = ball.vy;
if (ball.x - ball.radius < 0 || ball.x + ball.radius > 500) {
newVx *= -0.8;
}
if (ball.y - ball.radius < 0 || ball.y + ball.radius > 300) {
newVy *= -0.8;
}
balls.forEach((otherBall) => {
if (ball.id !== otherBall.id) {
const dx = otherBall.x - ball.x;
const dy = otherBall.y - ball.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const minDist = ball.radius + otherBall.radius;
if (distance < minDist) {
const angle = Math.atan2(dy, dx);
const targetX = ball.x + Math.cos(angle) * minDist;
const targetY = ball.y + Math.sin(angle) * minDist;
const ax = (targetX - otherBall.x) * 0.05;
const ay = (targetY - otherBall.y) * 0.05;
newVx -= ax;
newVy -= ay;
}
}
});
ball.x += newVx;
ball.y += newVy;
return { ...ball, vx: newVx, vy: newVy };
});
setBalls(updatedBalls);
animationFrame = requestAnimationFrame(animate);
}
return () => cancelAnimationFrame(animationFrame);
}, [balls]);
const handleMouseMove = (evt: Konva.KonvaEventObject<MouseEvent>) => {
const stage = evt.target.getStage();
const mousePos = stage?.getPointerPosition();
const updatedBalls = balls.map((ball) =>
ball.isDragging ? { ...ball, x: mousePos!.x, y: mousePos!.y } : ball
);
setBalls(updatedBalls);
};
const handleChangeComplete = (color: any) => {
setColor({ background: color.hex });
const newArr = [...balls];
const newObj = { ...newArr[0], color: color.hex };
newArr[0] = newObj;
setBalls(newArr);
};
return (
<>
{/* {picker && <ColorPicker handle={handleChangeComplete} color={color}/>} */}
<Stage
width={window.innerWidth}
height={window.innerHeight}
onMouseMove={handleMouseMove}
onClick={changePicker}
>
<Layer>
<Rect
width={window.innerWidth}
height={window.innerHeight}
fill="green"
/>
{balls.map((ball) => (
<Circle
key={ball.id}
x={ball.x}
y={ball.y}
radius={ball.radius}
fill={ball.color}
/>
))}
</Layer>
</Stage>
</>
);
};
export default BallCanvas;
I tried to change window.height and window.width in the Stage component, but it didn't work; the animation doesn't appear when I am moving the mouse.
What should I change in my code? Or maybe it's a problem in my viewport.
It only works when I open the console using f12.
I created my app via Vite, and installed all packages: konva, react-konva.