Update Path Drawing Component to Match Wall Drawing Component Behavior

This commit is contained in:
2025-08-25 15:25:48 +05:30
parent d090b976b0
commit fe95ea8d0b
5 changed files with 590 additions and 755 deletions

View File

@@ -0,0 +1,186 @@
import { DragControls, Line } from "@react-three/drei";
import React, { useMemo, useState } from "react";
import { useActiveSubTool, useToolMode } from "../../../../store/builder/store";
import { useThree } from "@react-three/fiber";
import { LineCurve3, Plane, Vector3 } from "three";
import { getPathsByPointId, setPathPosition } from "./function/getPaths";
import { handleCanvasCursors } from "../../../../utils/mouseUtils/handleCanvasCursors";
type PointData = {
pointId: string;
position: [number, number, number];
isCurved?: boolean;
handleA?: [number, number, number] | null;
handleB?: [number, number, number] | null;
};
interface PathDataInterface {
pathId: string;
isActive?: boolean;
isCurved?: boolean;
pathPoints: [PointData, PointData];
}
type PathData = PathDataInterface[];
type PathHandlerProps = {
selectedPath: PathDataInterface;
points: [PointData, PointData];
paths: PathData;
setPaths: React.Dispatch<React.SetStateAction<PathData>>;
setHoveredLine: React.Dispatch<
React.SetStateAction<PathDataInterface | null>
>;
hoveredLine: PathDataInterface | null;
hoveredPoint: PointData | null;
};
export default function PathHandler({
selectedPath,
setPaths,
points,
paths,
setHoveredLine,
hoveredLine,
hoveredPoint,
}: PathHandlerProps) {
const { toolMode } = useToolMode();
const { scene, raycaster } = useThree();
const [dragOffset, setDragOffset] = useState<Vector3 | null>(null);
const [initialPositions, setInitialPositions] = useState<{
paths?: any;
}>({});
const [isHovered, setIsHovered] = useState(false);
const { activeSubTool } = useActiveSubTool();
const plane = useMemo(() => new Plane(new Vector3(0, 1, 0), 0), []);
const path = useMemo(() => {
const [start, end] = points.map((p) => new Vector3(...p.position));
return new LineCurve3(start, end);
}, [points]);
const removePath = (pathId: string) => {
setPaths((prevPaths) => prevPaths.filter((p) => p.pathId !== pathId));
};
const handlePathClick = (pointId: string) => {
if (toolMode === "3D-Delete") {
removePath(pointId);
}
};
const handleDragStart = (points: [PointData, PointData]) => {
if (activeSubTool !== "free-hand") return;
const intersectionPoint = new Vector3();
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit) {
const start = new Vector3(...points[0].position);
const end = new Vector3(...points[1].position);
const midPoint = new Vector3().addVectors(start, end).multiplyScalar(0.5);
const offset = new Vector3().subVectors(midPoint, hit);
setDragOffset(offset);
const pathSet = getPathsByPointId(points[0].pointId, paths);
setInitialPositions({ paths: pathSet });
}
};
// const handleDrag = (points: [PointData, PointData]) => {
// if (isHovered && dragOffset) {
// const intersectionPoint = new Vector3();
// const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
// if (hit) {
// handleCanvasCursors("grabbing");
// const positionWithOffset = new Vector3().addVectors(hit, dragOffset);
// const start = new Vector3(...points[0].position);
// const end = new Vector3(...points[1].position);
// const midPoint = new Vector3()
// .addVectors(start, end)
// .multiplyScalar(0.5);
// const delta = new Vector3().subVectors(positionWithOffset, midPoint);
// const newStart = new Vector3().addVectors(start, delta);
// const newEnd = new Vector3().addVectors(end, delta);
// setPathPosition(
// points[0].pointId,
// [newStart.x, newStart.y, newStart.z],
// setPaths
// );
// setPathPosition(
// points[1].pointId,
// [newEnd.x, newEnd.y, newEnd.z],
// setPaths
// );
// }
// }
// };
const handleDrag = (points: [PointData, PointData]) => {
if (isHovered && dragOffset) {
const intersectionPoint = new Vector3();
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit) {
handleCanvasCursors("grabbing");
const positionWithOffset = new Vector3().addVectors(hit, dragOffset);
const start = new Vector3(...points[0].position);
const end = new Vector3(...points[1].position);
const midPoint = new Vector3()
.addVectors(start, end)
.multiplyScalar(0.5);
const delta = new Vector3().subVectors(positionWithOffset, midPoint);
const newStart: [number, number, number] = [
start.x + delta.x,
start.y + delta.y,
start.z + delta.z,
];
const newEnd: [number, number, number] = [
end.x + delta.x,
end.y + delta.y,
end.z + delta.z,
];
// ✅ Move both points separately (wont overwrite other updates)
setPathPosition(points[0].pointId, newStart, setPaths);
setPathPosition(points[1].pointId, newEnd, setPaths);
}
}
};
const handleDragEnd = (points: [PointData, PointData]) => {};
return (
<>
<DragControls
axisLock="y"
autoTransform={false}
onDragStart={() => handleDragStart(points)}
onDrag={() => handleDrag(points)}
onDragEnd={() => handleDragEnd(points)}
>
<Line
name="Path-Line"
key={selectedPath.pathId}
points={[points[0].position, points[1].position]}
color="purple"
lineWidth={5}
userData={selectedPath}
onClick={(e) => {
e.stopPropagation();
handlePathClick(selectedPath.pathId);
}}
onPointerOver={(e) => {
if (e.buttons === 0 && !e.ctrlKey) {
setHoveredLine(selectedPath);
setIsHovered(true);
if (!hoveredPoint) {
// handleCanvasCursors("grab");
}
}
}}
onPointerOut={() => {
if (isHovered && hoveredLine) {
setHoveredLine(null);
if (!hoveredPoint) {
// handleCanvasCursors("default");
}
}
setIsHovered(false);
}}
/>
</DragControls>
</>
);
}