3d widget api added and template frontend and backend completed

This commit is contained in:
2025-03-31 19:20:03 +05:30
parent 9611ad69cf
commit 6b8ccc02c7
27 changed files with 790 additions and 129 deletions

View File

@@ -10,79 +10,139 @@ import ProductionCapacity from "../../layout/3D-cards/cards/ProductionCapacity";
import ReturnOfInvestment from "../../layout/3D-cards/cards/ReturnOfInvestment";
import StateWorking from "../../layout/3D-cards/cards/StateWorking";
import { useSelectedZoneStore } from "../../../store/useZoneStore";
import { generateUniqueId } from "../../../functions/generateUniqueId";
import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget";
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
import { use3DWidget } from "../../../store/useDroppedObjectsStore";
export default function Dropped3dWidgets() {
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
const { widgetSelect } = useAsset3dWidget();
const { activeModule } = useModuleStore();
const { raycaster, gl, scene }: ThreeState = useThree();
const { selectedZone } = useSelectedZoneStore(); // Get currently selected zone
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption()
// 🔥 Store widget positions per zone
const [zoneWidgets, setZoneWidgets] = useState<Record<
string, // Zone ID
Record<string, [number, number, number][]> // Widget type -> Positions array
>>({});
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
const { selectedZone } = useSelectedZoneStore(); // Get the currently active zone
// 🔥 Store widget data (id, type, position) based on the selected zone
const [zoneWidgetData, setZoneWidgetData] = useState<
Record<string, { id: string; type: string; position: [number, number, number] }[]>
>({});
const { setWidgets3D } = use3DWidget()
useEffect(() => {
if (widgetSubOption === "Floating") return
// if (activeModule !== "visualization") return;
const canvasElement = gl.domElement;
const onDrop = (event: DragEvent) => {
event.preventDefault(); // Prevent default browser behavior
if (widgetSubOption === "3D") {
if (selectedZone.zoneName === "") return
if (!widgetSelect?.startsWith("ui")) return;
const group1 = scene.getObjectByName("itemsGroup");
if (!group1) return;
const Assets = group1.children
.map((val) => scene.getObjectByProperty("uuid", val.uuid))
.filter(Boolean) as THREE.Object3D[];
const intersects = raycaster.intersectObjects(scene.children, true).filter(
(intersect) =>
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
!intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper")
);
if (intersects.length > 0) {
const { x, y, z } = intersects[0].point;
if (activeModule !== "visualization") return
if (selectedZone.zoneName === "") return;
setZoneWidgets((prev) => ({
...prev,
[selectedZone.zoneId]: {
...(prev[selectedZone.zoneId] || {}),
[widgetSelect]: [...(prev[selectedZone.zoneId]?.[widgetSelect] || []), [x, y, z]],
},
}));
}
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
async function get3dWidgetData() {
let result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
setWidgets3D(result)
// Ensure the extracted data has id, type, and position correctly mapped
const formattedWidgets = result.map((widget: any) => ({
id: widget.id,
type: widget.type,
position: widget.position,
}));
setZoneWidgetData((prev) => ({
...prev,
[selectedZone.zoneId]: formattedWidgets,
}));
}
get3dWidgetData();
}, [selectedZone.zoneId,activeModule]);
// useEffect(() => {
// // ✅ Set data only for the selected zone, keeping existing state structure
// setZoneWidgetData((prev) => ({
// ...prev,
// [selectedZone.zoneId]: [
// {
// "id": "1743322674626-50mucpb1c",
// "type": "ui-Widget 1",
// "position": [120.94655021768133, 4.142360029666558, 124.39283546121099]
// },
// {
// "id": "1743322682086-je2h9x33v",
// "type": "ui-Widget 2",
// "position": [131.28751045879255, 0.009999999999970264, 133.92059801984362]
// }
// ]
// }));
// }, [selectedZone.zoneId]); // ✅ Only update when the zone changes
useEffect(() => {
if (activeModule !== "visualization") return;
if (widgetSubOption === "Floating") return;
if (selectedZone.zoneName === "") return
const canvasElement = gl.domElement;
const onDrop = async (event: DragEvent) => {
event.preventDefault(); // Prevent default browser behavior
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
if (!widgetSelect.startsWith("ui")) return;
const group1 = scene.getObjectByName("itemsGroup");
if (!group1) return;
const intersects = raycaster.intersectObjects(scene.children, true).filter(
(intersect) =>
!intersect.object.name.includes("Roof") &&
!intersect.object.name.includes("agv-collider") &&
!intersect.object.name.includes("MeasurementReference") &&
!intersect.object.userData.isPathObject &&
!(intersect.object.type === "GridHelper")
);
if (intersects.length > 0) {
const { x, y, z } = intersects[0].point;
// ✅ Explicitly define position as a tuple
const newWidget: { id: string; type: string; position: [number, number, number] } = {
id: generateUniqueId(),
type: widgetSelect,
position: [x, y, z], // Ensures TypeScript recognizes it as a tuple
};
let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget)
// ✅ Store widgets uniquely for each zone
setZoneWidgetData((prev) => ({
...prev,
[selectedZone.zoneId]: [...(prev[selectedZone.zoneId] || []), newWidget],
}));
}
};
canvasElement.addEventListener("drop", onDrop);
return () => {
canvasElement.removeEventListener("drop", onDrop)
// setWidgetSelect()
canvasElement.removeEventListener("drop", onDrop);
};
}, [widgetSelect, activeModule, widgetSubOption]);
}, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]);
// Get widgets for the currently active zone
const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || [];
return (
<>
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 1"]?.map((pos, index) => (
<ProductionCapacity key={`Widget1-${index}`} position={pos} />
))}
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 2"]?.map((pos, index) => (
<ReturnOfInvestment key={`Widget2-${index}`} position={pos} />
))}
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 3"]?.map((pos, index) => (
<StateWorking key={`Widget3-${index}`} position={pos} />
))}
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 4"]?.map((pos, index) => (
<Throughput key={`Widget4-${index}`} position={pos} />
))}
{activeZoneWidgets.map(({ id, type, position }) => {
switch (type) {
case "ui-Widget 1":
return <ProductionCapacity key={id} position={position} />;
case "ui-Widget 2":
return <ReturnOfInvestment key={id} position={position} />;
case "ui-Widget 3":
return <StateWorking key={id} position={position} />;
case "ui-Widget 4":
return <Throughput key={id} position={position} />;
default:
return null;
}
})}
</>
);
}