updated visualization panel ui and added outer click

This commit is contained in:
Nalvazhuthi 2025-04-08 18:34:21 +05:30
commit ed6edef24e
39 changed files with 2604 additions and 1877 deletions

View File

@ -3,13 +3,10 @@ import { useDroppedObjectsStore } from "../../../../store/useDroppedObjectsStore
import useTemplateStore from "../../../../store/useTemplateStore"; import useTemplateStore from "../../../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../../../store/useZoneStore"; import { useSelectedZoneStore } from "../../../../store/useZoneStore";
import { getTemplateData } from "../../../../services/realTimeVisulization/zoneData/getTemplate"; import { getTemplateData } from "../../../../services/realTimeVisulization/zoneData/getTemplate";
import { deleteTemplateApi } from "../../../../services/realTimeVisulization/zoneData/deleteTemplate";
import { loadTempleteApi } from "../../../../services/realTimeVisulization/zoneData/loadTemplate";
import { useSocketStore } from "../../../../store/store"; import { useSocketStore } from "../../../../store/store";
const Templates = () => { const Templates = () => {
const { templates, removeTemplate } = useTemplateStore(); const { templates, removeTemplate, setTemplates } = useTemplateStore();
const { setTemplates } = useTemplateStore();
const { setSelectedZone, selectedZone } = useSelectedZoneStore(); const { setSelectedZone, selectedZone } = useSelectedZoneStore();
const { visualizationSocket } = useSocketStore(); const { visualizationSocket } = useSocketStore();
@ -35,15 +32,11 @@ const Templates = () => {
let deleteTemplate = { let deleteTemplate = {
organization: organization, organization: organization,
templateID: id, templateID: id,
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-template:deleteTemplate", deleteTemplate) visualizationSocket.emit("v2:viz-template:deleteTemplate", deleteTemplate);
} }
removeTemplate(id); removeTemplate(id);
// let response = await deleteTemplateApi(id, organization);
// if (response.message === "Template deleted successfully") {
// }
} catch (error) { } catch (error) {
console.error("Error deleting template:", error); console.error("Error deleting template:", error);
} }
@ -60,16 +53,12 @@ const Templates = () => {
organization: organization, organization: organization,
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
templateID: template.id, templateID: template.id,
} };
console.log('template: ', template);
console.log('loadingTemplate: ', loadingTemplate);
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-template:addToZone", loadingTemplate) visualizationSocket.emit("v2:viz-template:addToZone", loadingTemplate);
} }
// let response = await loadTempleteApi(template.id, selectedZone.zoneId, organization);
// if (response.message === "Template placed in Zone") {
setSelectedZone({ setSelectedZone({
panelOrder: template.panelOrder, panelOrder: template.panelOrder,
activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides` activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides`
@ -83,91 +72,35 @@ const Templates = () => {
useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val); useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val);
}); });
} }
// }
} catch (error) { } catch (error) {
console.error("Error loading template:", error); console.error("Error loading template:", error);
} }
}; };
return ( return (
<div <div className="template-list">
className="template-list"
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))",
gap: "1rem",
padding: "1rem",
}}
>
{templates.map((template) => ( {templates.map((template) => (
<div <div key={template.id} className="template-item">
key={template.id}
className="template-item"
style={{
border: "1px solid #e0e0e0",
borderRadius: "8px",
padding: "1rem",
transition: "box-shadow 0.3s ease",
}}
>
{template?.snapshot && ( {template?.snapshot && (
<div style={{ position: "relative", paddingBottom: "56.25%" }}> <div className="template-image-container">
{" "}
{/* 16:9 aspect ratio */}
<img <img
src={template.snapshot} // Corrected from template.image to template.snapshot src={template.snapshot}
alt={`${template.name} preview`} alt={`${template.name} preview`}
style={{ className="template-image"
position: "absolute",
width: "100%",
height: "100%",
objectFit: "contain",
borderRadius: "4px",
cursor: "pointer",
transition: "transform 0.3s ease",
// ':hover': {
// transform: 'scale(1.05)'
// }
}}
onClick={() => handleLoadTemplate(template)} onClick={() => handleLoadTemplate(template)}
/> />
</div> </div>
)} )}
<div <div className="template-details">
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginTop: "0.5rem",
}}
>
<div <div
onClick={() => handleLoadTemplate(template)} onClick={() => handleLoadTemplate(template)}
style={{ className="template-name"
cursor: "pointer",
fontWeight: "500",
// ':hover': {
// textDecoration: 'underline'
// }
}}
> >
{template.name} {template.name}
</div> </div>
<button <button
onClick={() => handleDeleteTemplate(template.id)} onClick={() => handleDeleteTemplate(template.id)}
style={{ className="delete-button"
padding: "0.25rem 0.5rem",
background: "#ff4444",
color: "white",
border: "none",
borderRadius: "4px",
cursor: "pointer",
transition: "opacity 0.3s ease",
// ':hover': {
// opacity: 0.8
// }
}}
aria-label="Delete template" aria-label="Delete template"
> >
Delete Delete
@ -176,14 +109,7 @@ const Templates = () => {
</div> </div>
))} ))}
{templates.length === 0 && ( {templates.length === 0 && (
<div <div className="no-templates">
style={{
textAlign: "center",
color: "#666",
padding: "2rem",
gridColumn: "1 / -1",
}}
>
No saved templates yet. Create one in the visualization view! No saved templates yet. Create one in the visualization view!
</div> </div>
)} )}
@ -192,4 +118,3 @@ const Templates = () => {
}; };
export default Templates; export default Templates;

View File

@ -46,7 +46,7 @@ const WidgetsFloating = () => {
))} */} ))} */}
{/* Floating 1 */} {/* Floating 1 */}
<SimpleCard <SimpleCard
header={"Todays Money"} header={"Todays Earnings"}
icon={WalletIcon} icon={WalletIcon}
value={"$53,000"} value={"$53,000"}
per={"+55%"} per={"+55%"}

View File

@ -22,6 +22,8 @@ import GlobalProperties from "./properties/GlobalProperties";
import AsstePropertiies from "./properties/AssetProperties"; import AsstePropertiies from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties"; import ZoneProperties from "./properties/ZoneProperties";
import VehicleMechanics from "./mechanics/VehicleMechanics"; import VehicleMechanics from "./mechanics/VehicleMechanics";
import StaticMachineMechanics from "./mechanics/StaticMachineMechanics";
import ArmBotMechanics from "./mechanics/ArmBotMechanics";
const SideBarRight: React.FC = () => { const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
@ -42,8 +44,7 @@ const SideBarRight: React.FC = () => {
<div className="sidebar-actions-container"> <div className="sidebar-actions-container">
{/* {activeModule === "builder" && ( */} {/* {activeModule === "builder" && ( */}
<div <div
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
subModule === "properties" ? "active" : ""
}`} }`}
onClick={() => setSubModule("properties")} onClick={() => setSubModule("properties")}
> >
@ -53,24 +54,21 @@ const SideBarRight: React.FC = () => {
{activeModule === "simulation" && ( {activeModule === "simulation" && (
<> <>
<div <div
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
subModule === "mechanics" ? "active" : ""
}`} }`}
onClick={() => setSubModule("mechanics")} onClick={() => setSubModule("mechanics")}
> >
<MechanicsIcon isActive={subModule === "mechanics"} /> <MechanicsIcon isActive={subModule === "mechanics"} />
</div> </div>
<div <div
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
subModule === "simulations" ? "active" : ""
}`} }`}
onClick={() => setSubModule("simulations")} onClick={() => setSubModule("simulations")}
> >
<SimulationIcon isActive={subModule === "simulations"} /> <SimulationIcon isActive={subModule === "simulations"} />
</div> </div>
<div <div
className={`sidebar-action-list ${ className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
subModule === "analysis" ? "active" : ""
}`} }`}
onClick={() => setSubModule("analysis")} onClick={() => setSubModule("analysis")}
> >
@ -132,10 +130,28 @@ const SideBarRight: React.FC = () => {
</div> </div>
</div> </div>
)} )}
{subModule === "mechanics" &&
selectedActionSphere &&
selectedActionSphere.path.type === "StaticMachine" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<StaticMachineMechanics />
</div>
</div>
)}
{subModule === "mechanics" &&
selectedActionSphere &&
selectedActionSphere.path.type === "ArmBot" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
<ArmBotMechanics />
</div>
</div>
)}
{subModule === "mechanics" && !selectedActionSphere && ( {subModule === "mechanics" && !selectedActionSphere && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
<ConveyorMechanics /> <ConveyorMechanics /> {/* default */}
</div> </div>
</div> </div>
)} )}

View File

@ -0,0 +1,90 @@
import React, { useRef, useMemo } from "react";
import { InfoIcon } from "../../../icons/ExportCommonIcons";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store";
import * as Types from '../../../../types/world/worldTypes';
import PositionInput from "../customInput/PositionInputs";
import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
const ArmBotMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere();
const { simulationStates, setSimulationStates } = useSimulationStates();
const { socket } = useSocketStore();
const propertiesContainerRef = useRef<HTMLDivElement>(null);
const { selectedPoint, connectedPointUuids } = useMemo(() => {
if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
const vehiclePaths = simulationStates.filter(
(path): path is Types.ArmBotEventsSchema => path.type === "ArmBot"
);
const points = vehiclePaths.find(
(path) => path.points.uuid === selectedActionSphere.points.uuid
)?.points;
if (!points) return { selectedPoint: null, connectedPointUuids: [] };
const connectedUuids: string[] = [];
if (points.connections?.targets) {
points.connections.targets.forEach(target => {
connectedUuids.push(target.pointUUID);
});
}
return {
selectedPoint: points,
connectedPointUuids: connectedUuids
};
}, [selectedActionSphere, simulationStates]);
const updateBackend = async (updatedPath: Types.ArmBotEventsSchema | undefined) => {
if (!updatedPath) return;
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "";
// await setEventApi(
// organization,
// updatedPath.modeluuid,
// { type: "ArmBot", points: updatedPath.points }
// );
const data = {
organization: organization,
modeluuid: updatedPath.modeluuid,
eventData: { type: "ArmBot", points: updatedPath.points }
}
socket.emit('v2:model-asset:updateEventData', data);
}
return (
<div className="machine-mechanics-container" key={selectedPoint?.uuid}>
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "ArmBot point not found"}
</div>
<div className="machine-mechanics-content-container">
<div className="selected-properties-container" ref={propertiesContainerRef}>
<div className="properties-header">ArmBot Properties</div>
{selectedPoint && (
<>
</>
)}
</div>
<div className="footer">
<InfoIcon />
Configure armbot properties.
</div>
</div>
</div>
);
};
export default React.memo(ArmBotMechanics);

View File

@ -332,9 +332,7 @@ const ConveyorMechanics: React.FC = () => {
const updatedPath = updatedPaths.find( const updatedPath = updatedPaths.find(
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.modeluuid === selectedPath.path.modeluuid
(point) => point.uuid === selectedActionSphere.points.uuid
)
); );
updateBackend(updatedPath); updateBackend(updatedPath);

View File

@ -0,0 +1,90 @@
import React, { useRef, useMemo } from "react";
import { InfoIcon } from "../../../icons/ExportCommonIcons";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store";
import * as Types from '../../../../types/world/worldTypes';
import PositionInput from "../customInput/PositionInputs";
import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
const StaticMachineMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere();
const { simulationStates, setSimulationStates } = useSimulationStates();
const { socket } = useSocketStore();
const propertiesContainerRef = useRef<HTMLDivElement>(null);
const { selectedPoint, connectedPointUuids } = useMemo(() => {
if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
const vehiclePaths = simulationStates.filter(
(path): path is Types.StaticMachineEventsSchema => path.type === "StaticMachine"
);
const points = vehiclePaths.find(
(path) => path.points.uuid === selectedActionSphere.points.uuid
)?.points;
if (!points) return { selectedPoint: null, connectedPointUuids: [] };
const connectedUuids: string[] = [];
if (points.connections?.targets) {
points.connections.targets.forEach(target => {
connectedUuids.push(target.pointUUID);
});
}
return {
selectedPoint: points,
connectedPointUuids: connectedUuids
};
}, [selectedActionSphere, simulationStates]);
const updateBackend = async (updatedPath: Types.StaticMachineEventsSchema | undefined) => {
if (!updatedPath) return;
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "";
// await setEventApi(
// organization,
// updatedPath.modeluuid,
// { type: "StaticMachine", points: updatedPath.points }
// );
const data = {
organization: organization,
modeluuid: updatedPath.modeluuid,
eventData: { type: "StaticMachine", points: updatedPath.points }
}
socket.emit('v2:model-asset:updateEventData', data);
}
return (
<div className="machine-mechanics-container" key={selectedPoint?.uuid}>
<div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "Machine point not found"}
</div>
<div className="machine-mechanics-content-container">
<div className="selected-properties-container" ref={propertiesContainerRef}>
<div className="properties-header">Machine Properties</div>
{selectedPoint && (
<>
</>
)}
</div>
<div className="footer">
<InfoIcon />
Configure machine properties.
</div>
</div>
</div>
);
};
export default React.memo(StaticMachineMechanics);

View File

@ -28,9 +28,12 @@ const ZoneProperties: React.FC = () => {
}; };
let response = await zoneCameraUpdate(zonesdata, organization); let response = await zoneCameraUpdate(zonesdata, organization);
console.log('response: ', response); if (response.message === "updated successfully") {
setEdit(false); setEdit(false);
} else {
console.log("Not updated Camera Position and Target");
}
} catch (error) { } catch (error) {
console.error("Error in handleSetView:", error); console.error("Error in handleSetView:", error);
} }

View File

@ -35,6 +35,7 @@ import {
import useToggleStore from "../../store/useUIToggleStore"; import useToggleStore from "../../store/useUIToggleStore";
import { import {
use3DWidget, use3DWidget,
useDroppedObjectsStore,
useFloatingWidget, useFloatingWidget,
} from "../../store/useDroppedObjectsStore"; } from "../../store/useDroppedObjectsStore";
@ -52,8 +53,12 @@ const Tools: React.FC = () => {
const { addTemplate } = useTemplateStore(); const { addTemplate } = useTemplateStore();
const { selectedZone } = useSelectedZoneStore(); const { selectedZone } = useSelectedZoneStore();
const { floatingWidget } = useFloatingWidget(); const { floatingWidget } = useFloatingWidget();
const { widgets3D } = use3DWidget(); const { widgets3D } = use3DWidget();
const zones = useDroppedObjectsStore((state) => state.zones);
// wall options // wall options
const { toggleView, setToggleView } = useToggleView(); const { toggleView, setToggleView } = useToggleView();
const { setDeleteModels } = useDeleteModels(); const { setDeleteModels } = useDeleteModels();
@ -409,10 +414,9 @@ const Tools: React.FC = () => {
widgets3D, widgets3D,
selectedZone, selectedZone,
templates, templates,
visualizationSocket visualizationSocket,
}) });
} }}
}
> >
<SaveTemplateIcon isActive={false} /> <SaveTemplateIcon isActive={false} />
</div> </div>

View File

@ -65,6 +65,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
// Function to toggle lock/unlock a panel // Function to toggle lock/unlock a panel
const toggleLockPanel = (side: Side) => { const toggleLockPanel = (side: Side) => {
console.log('side: ', side);
//add api
const newLockedPanels = selectedZone.lockedPanels.includes(side) const newLockedPanels = selectedZone.lockedPanels.includes(side)
? selectedZone.lockedPanels.filter((panel) => panel !== side) ? selectedZone.lockedPanels.filter((panel) => panel !== side)
: [...selectedZone.lockedPanels, side]; : [...selectedZone.lockedPanels, side];
@ -92,6 +94,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
// Function to clean all widgets from a panel // Function to clean all widgets from a panel
const cleanPanel = (side: Side) => { const cleanPanel = (side: Side) => {
//add api
console.log('side: ', side);
const cleanedWidgets = selectedZone.widgets.filter( const cleanedWidgets = selectedZone.widgets.filter(
(widget) => widget.panel !== side (widget) => widget.panel !== side
); );
@ -100,7 +104,6 @@ const AddButtons: React.FC<ButtonsProps> = ({
...selectedZone, ...selectedZone,
widgets: cleanedWidgets, widgets: cleanedWidgets,
}; };
// Update the selectedZone state // Update the selectedZone state
setSelectedZone(updatedZone); setSelectedZone(updatedZone);
}; };

View File

@ -74,6 +74,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
const [showLeftArrow, setShowLeftArrow] = useState(false); const [showLeftArrow, setShowLeftArrow] = useState(false);
const [showRightArrow, setShowRightArrow] = useState(false); const [showRightArrow, setShowRightArrow] = useState(false);
const { floatingWidget, setFloatingWidget } = useFloatingWidget() const { floatingWidget, setFloatingWidget } = useFloatingWidget()
const{setSelectedChartId}=useWidgetStore() const{setSelectedChartId}=useWidgetStore()
// Function to calculate overflow state // Function to calculate overflow state
@ -178,7 +179,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
zoneViewPortPosition: response.viewPortposition || {}, zoneViewPortPosition: response.viewPortposition || {},
}); });
} catch (error) { } catch (error) {
console.error(error);
} }
} }

View File

@ -18,6 +18,7 @@ import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData
import { useClickOutside } from "./functions/handleWidgetsOuterClick"; import { useClickOutside } from "./functions/handleWidgetsOuterClick";
import { useSocketStore } from "../../../store/store"; import { useSocketStore } from "../../../store/store";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import OuterClick from "../../../utils/outerClick";
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
@ -89,6 +90,11 @@ export const DraggableWidget = ({
const isPanelHidden = hiddenPanels.includes(widget.panel); const isPanelHidden = hiddenPanels.includes(widget.panel);
OuterClick({
contextClassName: ["chart-container", "floating", "sidebar-right-wrapper"],
setMenuVisible: () => setSelectedChartId(null),
});
const deleteSelectedChart = async () => { const deleteSelectedChart = async () => {
try { try {
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
@ -251,11 +257,9 @@ export const DraggableWidget = ({
}); });
// Track canvas dimensions // Track canvas dimensions
// Current: Two identical useEffect hooks for canvas dimensions
// Remove the duplicate and keep only one
// Current: Two identical useEffect hooks for canvas dimensions useEffect(() => {
// Remove the duplicate and keep only one
useEffect(() => {
const canvas = document.getElementById("real-time-vis-canvas"); const canvas = document.getElementById("real-time-vis-canvas");
if (!canvas) return; if (!canvas) return;
@ -272,15 +276,16 @@ useEffect(() => {
resizeObserver.observe(canvas); resizeObserver.observe(canvas);
return () => resizeObserver.unobserve(canvas); return () => resizeObserver.unobserve(canvas);
}, []); }, []);
return ( return (
<> <>
<style> <style>
{` {`
:root { :root {
--realTimeViz-container-width: ${canvasDimensions.width * 0.25}px; --realTimeViz-container-width: ${canvasDimensions.width}px;
--realTimeViz-container-height: ${canvasDimensions.height}px; --realTimeViz-container-height: ${canvasDimensions.height}px;
} }
`} `}
</style> </style>
@ -296,13 +301,12 @@ useEffect(() => {
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDrop={handleDrop} onDrop={handleDrop}
style={{ style={{
// Apply styles based on panel position
width: ["top", "bottom"].includes(widget.panel) width: ["top", "bottom"].includes(widget.panel)
? `calc(${canvasDimensions.width * 0.16}px - 2px)` // For top/bottom panels, set width ? `calc(${canvasDimensions.width}px / 6)`
: undefined, // Don't set width if it's left or right : undefined,
height: ["left", "right"].includes(widget.panel) height: ["left", "right"].includes(widget.panel)
? `calc(${canvasDimensions.height * 0.25}px - 2px)` // For left/right panels, set height ? `calc(${canvasDimensions.height - 10}px / 4)`
: undefined, // Don't set height if it's top or bottom : undefined,
}} }}
ref={chartWidget} ref={chartWidget}
onClick={() => setSelectedChartId(widget)} onClick={() => setSelectedChartId(widget)}
@ -393,4 +397,4 @@ useEffect(() => {
); );
}; };
// while resize calculate --realTimeViz-container-height pprperly

View File

@ -44,9 +44,7 @@ export default function Dropped3dWidgets() {
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Floor plane for horizontal move const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Floor plane for horizontal move
const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move
const planeIntersect = useRef(new THREE.Vector3()); const planeIntersect = useRef(new THREE.Vector3());
// const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
// const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
// const planeIntersect = useRef(new THREE.Vector3());
const rotationStartRef = useRef<[number, number, number]>([0, 0, 0]); const rotationStartRef = useRef<[number, number, number]>([0, 0, 0]);
const mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); const mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
@ -60,7 +58,7 @@ export default function Dropped3dWidgets() {
async function get3dWidgetData() { async function get3dWidgetData() {
const result = await get3dWidgetZoneData(selectedZone.zoneId, organization); const result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
console.log('result: ', result);
setWidgets3D(result); setWidgets3D(result);
const formattedWidgets = result.map((widget: WidgetData) => ({ const formattedWidgets = result.map((widget: WidgetData) => ({
@ -84,8 +82,31 @@ export default function Dropped3dWidgets() {
const canvasElement = gl.domElement; const canvasElement = gl.domElement;
const handleDragEnter = (event: DragEvent) => {
event.preventDefault();
event.stopPropagation();
console.log("Drag enter");
};
const handleDragOver = (event: DragEvent) => {
event.preventDefault();
event.stopPropagation();
};
const handleDragLeave = (event: DragEvent) => {
event.preventDefault();
event.stopPropagation();
console.log("Drag leave");
// Remove visual feedback
canvasElement.style.cursor = "";
};
const onDrop = async (event: DragEvent) => { const onDrop = async (event: DragEvent) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation();
canvasElement.style.cursor = ""; // Reset cursor
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]; const organization = email?.split("@")[1]?.split(".")[0];
@ -93,6 +114,12 @@ export default function Dropped3dWidgets() {
const group1 = scene.getObjectByName("itemsGroup"); const group1 = scene.getObjectByName("itemsGroup");
if (!group1) return; if (!group1) return;
// Update raycaster with current mouse position
const rect = canvasElement.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true).filter( const intersects = raycaster.intersectObjects(scene.children, true).filter(
(intersect) => (intersect) =>
!intersect.object.name.includes("Roof") && !intersect.object.name.includes("Roof") &&
@ -125,12 +152,21 @@ export default function Dropped3dWidgets() {
} }
}; };
// Add all event listeners
// canvasElement.addEventListener("dragenter", handleDragEnter);
// canvasElement.addEventListener("dragover", handleDragOver);
// canvasElement.addEventListener("dragleave", handleDragLeave);
canvasElement.addEventListener("drop", onDrop); canvasElement.addEventListener("drop", onDrop);
return () => {
canvasElement.removeEventListener("drop", onDrop);
};
}, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]);
return () => {
// // Clean up all event listeners
// canvasElement.removeEventListener("dragenter", handleDragEnter);
// canvasElement.removeEventListener("dragover", handleDragOver);
// canvasElement.removeEventListener("dragleave", handleDragLeave);
canvasElement.removeEventListener("drop", onDrop);
canvasElement.style.cursor = ""; // Ensure cursor is reset
};
}, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption, gl.domElement, scene, raycaster, camera]);
const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || [];
useEffect(() => { useEffect(() => {
@ -161,7 +197,7 @@ export default function Dropped3dWidgets() {
visualizationSocket.emit("v2:viz-3D-widget:add", adding3dWidget); visualizationSocket.emit("v2:viz-3D-widget:add", adding3dWidget);
} }
// let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget) // let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget)
// console.log('response: ', response); //
addWidget(selectedZone.zoneId, newWidget); addWidget(selectedZone.zoneId, newWidget);
setRightSelect(null); setRightSelect(null);
@ -179,7 +215,7 @@ export default function Dropped3dWidgets() {
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
}; };
console.log('deleteWidget: ', deleteWidget);
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget); visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget);
} }
@ -190,7 +226,7 @@ export default function Dropped3dWidgets() {
activeZoneWidgets.filter((w: WidgetData) => w.id !== rightClickSelected) activeZoneWidgets.filter((w: WidgetData) => w.id !== rightClickSelected)
); );
} catch (error) { } catch (error) {
console.error("Error deleting widget:", error);
} finally { } finally {
setRightClickSelected(null); setRightClickSelected(null);
setRightSelect(null); setRightSelect(null);
@ -304,20 +340,15 @@ export default function Dropped3dWidgets() {
const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected); const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected);
if (!selectedWidget) return; if (!selectedWidget) return;
// Format values to 2 decimal places // Format values to 2 decimal places
const formatValues = (vals: number[]) => vals.map(val => parseFloat(val.toFixed(2))); const formatValues = (vals: number[]) => vals.map(val => parseFloat(val.toFixed(2)));
if (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move") { if (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move") {
console.log(`${rightSelect} Completed - Full Position:`, formatValues(selectedWidget.position));
let lastPosition = formatValues(selectedWidget.position) as [number, number, number]; let lastPosition = formatValues(selectedWidget.position) as [number, number, number];
// (async () => { // (async () => {
// let response = await update3dWidget(selectedZone, organization, rightClickSelected, lastPosition); // let response = await update3dWidget(selectedZone, organization, rightClickSelected, lastPosition);
// console.log('response: ', response); //
// if (response) { // if (response) {
// console.log("Widget position updated in API:", response); //
// } // }
// })(); // })();
let updatingPosition = { let updatingPosition = {
@ -333,13 +364,13 @@ export default function Dropped3dWidgets() {
} }
else if (rightSelect.includes("Rotate")) { else if (rightSelect.includes("Rotate")) {
const rotation = selectedWidget.rotation || [0, 0, 0]; const rotation = selectedWidget.rotation || [0, 0, 0];
console.log(`${rightSelect} Completed - Full Rotation:`, formatValues(rotation));
let lastRotation = formatValues(rotation) as [number, number, number]; let lastRotation = formatValues(rotation) as [number, number, number];
// (async () => { // (async () => {
// let response = await update3dWidgetRotation(selectedZone, organization, rightClickSelected, lastRotation); // let response = await update3dWidgetRotation(selectedZone, organization, rightClickSelected, lastRotation);
// console.log('response: ', response); //
// if (response) { // if (response) {
// console.log("Widget position updated in API:", response); //
// } // }
// })(); // })();
let updatingRotation = { let updatingRotation = {
@ -388,49 +419,13 @@ export default function Dropped3dWidgets() {
switch (type) { switch (type) {
case "ui-Widget 1": case "ui-Widget 1":
return ( return (<ProductionCapacity key={id} id={id} type={type} position={position} rotation={rotation} onContextMenu={(e) => handleRightClick(e, id)} />);
<ProductionCapacity
key={id}
id={id}
type={type}
position={position}
rotation={rotation}
onContextMenu={(e) => handleRightClick(e, id)}
/>
);
case "ui-Widget 2": case "ui-Widget 2":
return ( return (<ReturnOfInvestment key={id} id={id} type={type} position={position} rotation={rotation} onContextMenu={(e) => handleRightClick(e, id)} />);
<ReturnOfInvestment
key={id}
id={id}
type={type}
position={position}
rotation={rotation}
onContextMenu={(e) => handleRightClick(e, id)}
/>
);
case "ui-Widget 3": case "ui-Widget 3":
return ( return (<StateWorking key={id} id={id} type={type} position={position} rotation={rotation} onContextMenu={(e) => handleRightClick(e, id)} />);
<StateWorking
key={id}
id={id}
type={type}
position={position}
rotation={rotation}
onContextMenu={(e) => handleRightClick(e, id)}
/>
);
case "ui-Widget 4": case "ui-Widget 4":
return ( return (<Throughput key={id} id={id} type={type} position={position} rotation={rotation} onContextMenu={(e) => handleRightClick(e, id)} />);
<Throughput
key={id}
id={id}
type={type}
position={position}
rotation={rotation}
onContextMenu={(e) => handleRightClick(e, id)}
/>
);
default: default:
return null; return null;
} }

View File

@ -126,12 +126,11 @@ const DroppedObjects: React.FC = () => {
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]; const organization = email?.split("@")[1]?.split(".")[0];
let deleteFloatingWidget = { let deleteFloatingWidget = {
floatWidgetID: id, floatWidgetID: id,
organization: organization, organization: organization,
zoneId: zone.zoneId zoneId: zone.zoneId,
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget); visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget);
@ -144,9 +143,7 @@ const DroppedObjects: React.FC = () => {
// if (res.message === "FloatingWidget deleted successfully") { // if (res.message === "FloatingWidget deleted successfully") {
// deleteObject(zoneName, id, index); // Call the deleteObject method from the store // deleteObject(zoneName, id, index); // Call the deleteObject method from the store
// } // }
} catch (error) { } catch (error) {}
}
} }
const handlePointerDown = (event: React.PointerEvent, index: number) => { const handlePointerDown = (event: React.PointerEvent, index: number) => {
@ -461,15 +458,14 @@ const DroppedObjects: React.FC = () => {
position: boundedPosition, position: boundedPosition,
}, },
index: draggingIndex.index, index: draggingIndex.index,
zoneId: zone.zoneId zoneId: zone.zoneId,
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget); visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget);
} }
// if (response.message === "Widget updated successfully") { // if (response.message === "Widget updated successfully") {
console.log('boundedPosition: ', boundedPosition);
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
// } // }
@ -503,47 +499,74 @@ const DroppedObjects: React.FC = () => {
setOpenKebabId((prevId) => (prevId === id ? null : id)); setOpenKebabId((prevId) => (prevId === id ? null : id));
}; };
const containerHeight = getComputedStyle(
document.documentElement
).getPropertyValue("--realTimeViz-container-height");
const containerWidth = getComputedStyle(
document.documentElement
).getPropertyValue("--realTimeViz-container-width");
const heightMultiplier = parseFloat(containerHeight) * 0.14;
const widthMultiplier = parseFloat(containerWidth) * 0.13;
console.log("zone.objects: ", zone.objects);
return ( return (
<div <div
onPointerMove={handlePointerMove} onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp} onPointerUp={handlePointerUp}
className="floating-wrapper" className="floating-wrapper"
> >
{zone.objects.map((obj, index) => ( {zone.objects.map((obj, index) => {
const topPosition =
typeof obj.position.top === "number"
? `calc(${obj.position.top}px + ${
isPlaying && selectedZone.activeSides.includes("top")
? `${heightMultiplier - 55}px`
: "0px"
})`
: "auto";
const leftPosition =
typeof obj.position.left === "number"
? `calc(${obj.position.left}px + ${
isPlaying && selectedZone.activeSides.includes("left")
? `${widthMultiplier - 100}px`
: "0px"
})`
: "auto";
const rightPosition =
typeof obj.position.right === "number"
? `calc(${obj.position.right}px + ${
isPlaying && selectedZone.activeSides.includes("right")
? `${widthMultiplier - 100}px`
: "0px"
})`
: "auto";
const bottomPosition =
typeof obj.position.bottom === "number"
? `calc(${obj.position.bottom}px + ${
isPlaying && selectedZone.activeSides.includes("bottom")
? `${heightMultiplier - 55}px`
: "0px"
})`
: "auto";
return (
<div <div
key={`${zoneName}-${index}`} key={`${zoneName}-${index}`}
className={`${obj.className} ${selectedChartId?.id === obj.id && "activeChart"}`} className={`${obj.className} ${
selectedChartId?.id === obj.id && "activeChart"
}`}
ref={chartWidget} ref={chartWidget}
style={{ style={{
position: "absolute", position: "absolute",
top: top: topPosition,
typeof obj.position.top === "number" left: leftPosition,
? `calc(${obj.position.top}px + ${isPlaying && selectedZone.activeSides.includes("top") right: rightPosition,
? 90 bottom: bottomPosition,
: 0
}px)`
: "auto",
left:
typeof obj.position.left === "number"
? `calc(${obj.position.left}px + ${isPlaying && selectedZone.activeSides.includes("left")
? 90
: 0
}px)`
: "auto",
right:
typeof obj.position.right === "number"
? `calc(${obj.position.right}px + ${isPlaying && selectedZone.activeSides.includes("right")
? 90
: 0
}px)`
: "auto",
bottom:
typeof obj.position.bottom === "number"
? `calc(${obj.position.bottom}px + ${isPlaying && selectedZone.activeSides.includes("bottom")
? 90
: 0
}px)`
: "auto",
}} }}
onPointerDown={(event) => { onPointerDown={(event) => {
setSelectedChartId(obj); setSelectedChartId(obj);
@ -551,18 +574,13 @@ const DroppedObjects: React.FC = () => {
}} }}
> >
{obj.className === "floating total-card" ? ( {obj.className === "floating total-card" ? (
<>
<TotalCardComponent object={obj} /> <TotalCardComponent object={obj} />
</>
) : obj.className === "warehouseThroughput floating" ? ( ) : obj.className === "warehouseThroughput floating" ? (
<>
<WarehouseThroughputComponent object={obj} /> <WarehouseThroughputComponent object={obj} />
</>
) : obj.className === "fleetEfficiency floating" ? ( ) : obj.className === "fleetEfficiency floating" ? (
<>
<FleetEfficiencyComponent object={obj} /> <FleetEfficiencyComponent object={obj} />
</>
) : null} ) : null}
<div <div
className="icon kebab" className="icon kebab"
ref={kebabRef} ref={kebabRef}
@ -573,6 +591,7 @@ const DroppedObjects: React.FC = () => {
> >
<KebabIcon /> <KebabIcon />
</div> </div>
{openKebabId === obj.id && ( {openKebabId === obj.id && (
<div className="kebab-options" ref={kebabRef}> <div className="kebab-options" ref={kebabRef}>
<div <div
@ -602,7 +621,8 @@ const DroppedObjects: React.FC = () => {
</div> </div>
)} )}
</div> </div>
))} );
})}
{/* Render DistanceLines component during drag */} {/* Render DistanceLines component during drag */}
{isPlaying === false && {isPlaying === false &&

View File

@ -21,7 +21,6 @@ interface PanelProps {
zoneName: string; zoneName: string;
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string; zoneId: string;
zoneViewPortTarget: number[]; zoneViewPortTarget: number[];
@ -33,7 +32,6 @@ interface PanelProps {
zoneName: string; zoneName: string;
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string; zoneId: string;
zoneViewPortTarget: number[]; zoneViewPortTarget: number[];
@ -42,7 +40,7 @@ interface PanelProps {
}> }>
>; >;
hiddenPanels: string[]; hiddenPanels: string[];
setZonesData: React.Dispatch<React.SetStateAction<any>>; // Add this line setZonesData: React.Dispatch<React.SetStateAction<any>>;
} }
const generateUniqueId = () => const generateUniqueId = () =>
@ -60,14 +58,13 @@ const Panel: React.FC<PanelProps> = ({
[side in Side]?: { width: number; height: number }; [side in Side]?: { width: number; height: number };
}>({}); }>({});
const [openKebabId, setOpenKebabId] = useState<string | null>(null); const [openKebabId, setOpenKebabId] = useState<string | null>(null);
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { visualizationSocket } = useSocketStore(); const { visualizationSocket } = useSocketStore();
const [canvasDimensions, setCanvasDimensions] = useState({ const [canvasDimensions, setCanvasDimensions] = useState({
width: 0, width: 0,
height: 0, height: 0,
}); });
// Track canvas dimensions // Track canvas dimensions
useEffect(() => { useEffect(() => {
const canvas = document.getElementById("real-time-vis-canvas"); const canvas = document.getElementById("real-time-vis-canvas");
@ -81,42 +78,20 @@ const Panel: React.FC<PanelProps> = ({
}); });
}; };
// Initial measurement
updateCanvasDimensions(); updateCanvasDimensions();
// Set up ResizeObserver to track changes
const resizeObserver = new ResizeObserver(updateCanvasDimensions); const resizeObserver = new ResizeObserver(updateCanvasDimensions);
resizeObserver.observe(canvas); resizeObserver.observe(canvas);
return () => { return () => resizeObserver.unobserve(canvas);
resizeObserver.unobserve(canvas);
};
}, []); }, []);
useEffect(() => { // Calculate panel size
const canvas = document.getElementById("real-time-vis-canvas"); const panelSize = Math.max(
if (!canvas) return; Math.min(canvasDimensions.width * 0.25, canvasDimensions.height * 0.25),
170 // Min 170px
const updateCanvasDimensions = () => { );
const rect = canvas.getBoundingClientRect();
setCanvasDimensions({
width: rect.width,
height: rect.height,
});
};
// Initial measurement
updateCanvasDimensions();
// Set up ResizeObserver to track changes
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
resizeObserver.observe(canvas);
return () => {
resizeObserver.unobserve(canvas);
};
}, []);
// Define getPanelStyle
const getPanelStyle = useMemo( const getPanelStyle = useMemo(
() => (side: Side) => { () => (side: Side) => {
const currentIndex = selectedZone.panelOrder.indexOf(side); const currentIndex = selectedZone.panelOrder.indexOf(side);
@ -126,125 +101,105 @@ const Panel: React.FC<PanelProps> = ({
const topActive = previousPanels.includes("top"); const topActive = previousPanels.includes("top");
const bottomActive = previousPanels.includes("bottom"); const bottomActive = previousPanels.includes("bottom");
// Dynamic panel sizes based on canvas width
const panelSizeWidth = Math.max(canvasDimensions.width * 0.165, 200); // Ensure minimum width of 200px
const panelSizeHeight = Math.max(canvasDimensions.width * 0.13, 200); // Ensure minimum height of 200px
switch (side) { switch (side) {
case "top": case "top":
case "bottom": case "bottom":
return { return {
// minWidth: "200px", // Minimum width constraint minWidth: "170px",
width: `calc(100% - ${ width: `calc(100% - ${
(leftActive ? panelSizeWidth : 0) + (leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
(rightActive ? panelSizeWidth : 0)
}px)`, }px)`,
minHeight: "150px", // Minimum height constraint minHeight: "170px",
height: `${panelSizeHeight - 2}px`, // Subtracting for border or margin height: `${panelSize}px`,
left: leftActive ? `${panelSizeWidth}px` : "0", left: leftActive ? `${panelSize}px` : "0",
right: rightActive ? `${panelSizeWidth}px` : "0", right: rightActive ? `${panelSize}px` : "0",
[side]: "0", [side]: "0",
}; };
case "left": case "left":
case "right": case "right":
return { return {
minWidth: "150px", // Minimum width constraint minWidth: "170px",
width: `${panelSizeWidth - 2}px`, // Subtracting for border or margin width: `${panelSize}px`,
// minHeight: "200px", // Minimum height constraint minHeight: "170px",
height: `calc(100% - ${ height: `calc(100% - ${
(topActive ? panelSizeHeight : 0) + (topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
(bottomActive ? panelSizeHeight : 0)
}px)`, }px)`,
top: topActive ? `${panelSizeHeight}px` : "0", top: topActive ? `${panelSize}px` : "0",
bottom: bottomActive ? `${panelSizeHeight}px` : "0", bottom: bottomActive ? `${panelSize}px` : "0",
[side]: "0", [side]: "0",
}; };
default: default:
return {}; return {};
} }
}, },
[ [selectedZone.panelOrder, panelSize]
selectedZone.panelOrder,
isPlaying,
canvasDimensions.width,
canvasDimensions.height,
]
); );
// Handle drop event
const handleDrop = (e: React.DragEvent, panel: Side) => { const handleDrop = (e: React.DragEvent, panel: Side) => {
e.preventDefault(); e.preventDefault();
const { draggedAsset } = useWidgetStore.getState(); const { draggedAsset } = useWidgetStore.getState();
if (!draggedAsset) return; if (!draggedAsset || isPanelLocked(panel)) return;
if (isPanelLocked(panel)) return;
const currentWidgetsCount = getCurrentWidgetCount(panel); const currentWidgetsCount = getCurrentWidgetCount(panel);
const maxCapacity = calculatePanelCapacity(panel); const maxCapacity = calculatePanelCapacity(panel);
if (currentWidgetsCount >= maxCapacity) return; if (currentWidgetsCount < maxCapacity) {
addWidgetToPanel(draggedAsset, panel); addWidgetToPanel(draggedAsset, panel);
}
}; };
// Check if panel is locked
const isPanelLocked = (panel: Side) => const isPanelLocked = (panel: Side) =>
selectedZone.lockedPanels.includes(panel); selectedZone.lockedPanels.includes(panel);
// Get current widget count in a panel
const getCurrentWidgetCount = (panel: Side) => const getCurrentWidgetCount = (panel: Side) =>
selectedZone.widgets.filter((w) => w.panel === panel).length; selectedZone.widgets.filter((w) => w.panel === panel).length;
// Calculate panel capacity
const calculatePanelCapacity = (panel: Side) => { const calculatePanelCapacity = (panel: Side) => {
const CHART_WIDTH = 170; const CHART_WIDTH = panelSize;
const CHART_HEIGHT = 170; const CHART_HEIGHT = panelSize;
const FALLBACK_HORIZONTAL_CAPACITY = 5;
const FALLBACK_VERTICAL_CAPACITY = 3;
const dimensions = panelDimensions[panel]; const dimensions = panelDimensions[panel];
if (!dimensions) { if (!dimensions) {
return panel === "top" || panel === "bottom" return panel === "top" || panel === "bottom" ? 5 : 3; // Fallback capacities
? FALLBACK_HORIZONTAL_CAPACITY
: FALLBACK_VERTICAL_CAPACITY;
} }
return panel === "top" || panel === "bottom" return panel === "top" || panel === "bottom"
? Math.floor(dimensions.width / CHART_WIDTH) ? Math.max(1, Math.floor(dimensions.width / CHART_WIDTH))
: Math.floor(dimensions.height / CHART_HEIGHT); : Math.max(1, Math.floor(dimensions.height / CHART_HEIGHT));
}; };
// while dublicate check this and add // Add widget to panel
const addWidgetToPanel = async (asset: any, panel: Side) => { const addWidgetToPanel = async (asset: any, panel: Side) => {
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]; const organization = email?.split("@")[1]?.split(".")[0];
const newWidget = { const newWidget = {
...asset, ...asset,
id: generateUniqueId(), id: generateUniqueId(),
panel, panel,
}; };
let addWidget = { let addWidget = {
organization: organization, organization: organization,
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
widget: newWidget, widget: newWidget,
}; };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-widget:add", addWidget); visualizationSocket.emit("v2:viz-widget:add", addWidget);
} }
setSelectedZone((prev) => ({ setSelectedZone((prev) => ({
...prev, ...prev,
widgets: [...prev.widgets, newWidget], widgets: [...prev.widgets, newWidget],
})); }));
try {
// let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
// if (response.message === "Widget created successfully") {
// setSelectedZone((prev) => ({
// ...prev,
// widgets: [...prev.widgets, newWidget],
// }));
// }
} catch (error) {
console.error("Error adding widget:", error);
}
}; };
// Observe panel dimensions
useEffect(() => { useEffect(() => {
const observers: ResizeObserver[] = []; const observers: ResizeObserver[] = [];
const currentPanelRefs = panelRefs.current; const currentPanelRefs = panelRefs.current;
@ -261,6 +216,7 @@ const Panel: React.FC<PanelProps> = ({
})); }));
} }
}); });
observer.observe(element); observer.observe(element);
observers.push(observer); observers.push(observer);
} }
@ -271,22 +227,15 @@ const Panel: React.FC<PanelProps> = ({
}; };
}, [selectedZone.activeSides]); }, [selectedZone.activeSides]);
// Handle widget reordering
const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => { const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => {
if (!selectedZone) return; // Ensure selectedZone is not null
setSelectedZone((prev) => { setSelectedZone((prev) => {
if (!prev) return prev; // Ensure prev is not null
// Filter widgets for the specified panel
const widgetsInPanel = prev.widgets.filter((w) => w.panel === panel); const widgetsInPanel = prev.widgets.filter((w) => w.panel === panel);
// Reorder widgets within the same panel
const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex); const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex);
// Merge the reordered widgets back into the full list while preserving the order
const updatedWidgets = prev.widgets const updatedWidgets = prev.widgets
.filter((widget) => widget.panel !== panel) // Keep widgets from other panels .filter((widget) => widget.panel !== panel)
.concat(reorderedWidgets); // Add the reordered widgets for the specified panel .concat(reorderedWidgets);
return { return {
...prev, ...prev,
@ -295,12 +244,40 @@ const Panel: React.FC<PanelProps> = ({
}); });
}; };
// Calculate capacities and dimensions
const topWidth = getPanelStyle("top").width;
const bottomWidth = getPanelStyle("bottom").width;
const leftHeight = getPanelStyle("left").height;
const rightHeight = getPanelStyle("right").height;
const topCapacity = calculatePanelCapacity("top");
const bottomCapacity = calculatePanelCapacity("bottom");
const leftCapacity = calculatePanelCapacity("left");
const rightCapacity = calculatePanelCapacity("right");
return ( return (
<> <>
<style>
{`
:root {
--topWidth: ${topWidth};
--bottomWidth: ${bottomWidth};
--leftHeight: ${leftHeight};
--rightHeight: ${rightHeight};
--topCapacity: ${topCapacity};
--bottomCapacity: ${bottomCapacity};
--leftCapacity: ${leftCapacity};
--rightCapacity: ${rightCapacity};
}
`}
</style>
{selectedZone.activeSides.map((side) => ( {selectedZone.activeSides.map((side) => (
<div <div
key={side} key={side}
className={`panel ${side}-panel absolute ${isPlaying ? "" : ""} ${ id="panel-wrapper"
className={`panel ${side}-panel absolute ${
hiddenPanels.includes(side) ? "hidePanel" : "" hiddenPanels.includes(side) ? "hidePanel" : ""
}`} }`}
style={getPanelStyle(side)} style={getPanelStyle(side)}
@ -348,5 +325,3 @@ const Panel: React.FC<PanelProps> = ({
}; };
export default Panel; export default Panel;
// canvasDimensions.width as percent

View File

@ -67,9 +67,7 @@ const RealTimeVisulization: React.FC = () => {
const { rightClickSelected, setRightClickSelected } = useRightClickSelected(); const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false); const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
const [floatingWidgets, setFloatingWidgets] = useState< const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({});
Record<string, { zoneName: string; zoneId: string; objects: any[] }>
>({});
const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
const { visualizationSocket } = useSocketStore(); const { visualizationSocket } = useSocketStore();
@ -81,7 +79,6 @@ const RealTimeVisulization: React.FC = () => {
const organization = email?.split("@")[1]?.split(".")[0]; const organization = email?.split("@")[1]?.split(".")[0];
try { try {
const response = await getZone2dData(organization); const response = await getZone2dData(organization);
// console.log('response: ', response);
if (!Array.isArray(response)) { if (!Array.isArray(response)) {
return; return;
@ -102,7 +99,7 @@ const RealTimeVisulization: React.FC = () => {
{} {}
); );
setZonesData(formattedData); setZonesData(formattedData);
} catch (error) {} } catch (error) { }
} }
GetZoneData(); GetZoneData();
@ -200,7 +197,7 @@ const RealTimeVisulization: React.FC = () => {
], ],
}, },
})); }));
} catch (error) {} } catch (error) { }
}; };
useEffect(() => { useEffect(() => {
const handleClickOutside = (event: MouseEvent) => { const handleClickOutside = (event: MouseEvent) => {
@ -267,7 +264,7 @@ const RealTimeVisulization: React.FC = () => {
/> />
</RenderOverlay> </RenderOverlay>
)} )}
{/* <div <div
className="scene-container" className="scene-container"
style={{ style={{
height: "100%", height: "100%",
@ -279,7 +276,7 @@ const RealTimeVisulization: React.FC = () => {
onDragOver={(event) => event.preventDefault()} onDragOver={(event) => event.preventDefault()}
> >
<Scene /> <Scene />
</div> */} </div>
{activeModule === "visualization" && selectedZone.zoneName !== "" && ( {activeModule === "visualization" && selectedZone.zoneName !== "" && (
<DroppedObjects /> <DroppedObjects />
)} )}

View File

@ -47,80 +47,83 @@ const DropDownList: React.FC<DropDownListProps> = ({
const [zoneDataList, setZoneDataList] = useState< const [zoneDataList, setZoneDataList] = useState<
{ id: string; name: string; assets: Asset[] }[] { id: string; name: string; assets: Asset[] }[]
>([]); >([]);
const [zonePoints3D, setZonePoints3D] = useState<[]>([]);
const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore();
useEffect(() => { useEffect(() => {
// console.log(zones); // const value = (zones || []).map(
// setZoneDataList([ // (val: { zoneId: string; zoneName: string }) => ({
// { id: "2e996073-546c-470c-8323-55bd3700c6aa", name: "zone1" }, // id: val.zoneId,
// { id: "3f473bf0-197c-471c-a71f-943fc9ca2b47", name: "zone2" }, // name: val.zoneName,
// { id: "905e8fb6-9e18-469b-9474-e0478fb9601b", name: "zone3" }, // })
// { id: "9d9efcbe-8e96-47eb-bfad-128a9e4c532e", name: "zone4" }, // );
// { id: "884f3d29-eb5a-49a5-abe9-d11971c08e85", name: "zone5" }, // console.log('zones: ', zones);
// { id: "70fa55cd-b5c9-4f80-a8c4-6319af3bfb4e", name: "zone6" }, const value = (zones || []).map((val: { zoneId: string; zoneName: string }) => ({
// ])
const value = (zones || []).map(
(val: { zoneId: string; zoneName: string }) => ({
id: val.zoneId, id: val.zoneId,
name: val.zoneName, name: val.zoneName
}) }));
); setZoneDataList(prev => (JSON.stringify(prev) !== JSON.stringify(value) ? value : prev));
setZoneDataList([ const allPoints = zones.flatMap((zone: any) => zone.points);
{ setZonePoints3D(allPoints);
id: "zone1", // setZoneDataList([
name: "Zone 1", // {
assets: [ // id: "zone1",
{ // name: "Zone 1",
id: "asset1", // assets: [
name: "Asset 1", // {
}, // id: "asset1",
{ // name: "Asset 1",
id: "asset2", // },
name: "Asset 2", // {
}, // id: "asset2",
{ // name: "Asset 2",
id: "asset3", // },
name: "Asset 3", // {
}, // id: "asset3",
], // name: "Asset 3",
}, // },
{ // ],
id: "zone2", // },
name: "Zone 2", // {
assets: [ // id: "zone2",
{ // name: "Zone 2",
id: "asset4", // assets: [
name: "Asset 4", // {
}, // id: "asset4",
{ // name: "Asset 4",
id: "asset5", // },
name: "Asset 5", // {
}, // id: "asset5",
{ // name: "Asset 5",
id: "asset6", // },
name: "Asset 6", // {
}, // id: "asset6",
], // name: "Asset 6",
}, // },
{ // ],
id: "zone3", // },
name: "Zone 3", // {
assets: [ // id: "zone3",
{ // name: "Zone 3",
id: "asset7", // assets: [
name: "Asset 7", // {
}, // id: "asset7",
{ // name: "Asset 7",
id: "asset8", // },
name: "Asset 8", // {
}, // id: "asset8",
], // name: "Asset 8",
}, // },
]); // ],
// },
// ]);
}, [zones]); }, [zones]);
useEffect(() => {
// console.log('zonePoints3D: ', zonePoints3D);
}, [zonePoints3D])
return ( return (
<div className="dropdown-list-container"> <div className="dropdown-list-container">

View File

@ -5,7 +5,7 @@ interface SimpleCardProps {
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>; // React component for SVG icon icon: React.ComponentType<React.SVGProps<SVGSVGElement>>; // React component for SVG icon
value: string; value: string;
per: string; // Percentage change per: string; // Percentage change
position?: [number, number] position?: [number, number];
} }
const SimpleCard: React.FC<SimpleCardProps> = ({ const SimpleCard: React.FC<SimpleCardProps> = ({
@ -15,7 +15,6 @@ const SimpleCard: React.FC<SimpleCardProps> = ({
per, per,
position = [0, 0], position = [0, 0],
}) => { }) => {
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => { const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
const rect = event.currentTarget.getBoundingClientRect(); // Get position const rect = event.currentTarget.getBoundingClientRect(); // Get position
const cardData = JSON.stringify({ const cardData = JSON.stringify({

View File

@ -29,12 +29,15 @@ export default function PathNavigator({
const [dropPickupPath, setDropPickupPath] = useState<[number, number, number][]>([]); const [dropPickupPath, setDropPickupPath] = useState<[number, number, number][]>([]);
const [initialPosition, setInitialPosition] = useState<THREE.Vector3 | null>(null); const [initialPosition, setInitialPosition] = useState<THREE.Vector3 | null>(null);
const [initialRotation, setInitialRotation] = useState<THREE.Euler | null>(null); const [initialRotation, setInitialRotation] = useState<THREE.Euler | null>(null);
const [targetPosition] = useState(new THREE.Vector3());
const [smoothPosition] = useState(new THREE.Vector3());
const [targetQuaternion] = useState(new THREE.Quaternion());
const distancesRef = useRef<number[]>([]); const distancesRef = useRef<number[]>([]);
const totalDistanceRef = useRef(0); const totalDistanceRef = useRef(0);
const progressRef = useRef(0); const progressRef = useRef(0);
const isWaiting = useRef(false); const isWaiting = useRef(false);
const timeoutRef = useRef<NodeJS.Timeout | null>(null); const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const pathTransitionProgress = useRef(0);
const { scene } = useThree(); const { scene } = useThree();
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
@ -44,6 +47,9 @@ export default function PathNavigator({
if (object) { if (object) {
setInitialPosition(object.position.clone()); setInitialPosition(object.position.clone());
setInitialRotation(object.rotation.clone()); setInitialRotation(object.rotation.clone());
smoothPosition.copy(object.position.clone());
targetPosition.copy(object.position.clone());
targetQuaternion.setFromEuler(object.rotation.clone());
} }
}, [scene, id]); }, [scene, id]);
@ -65,22 +71,23 @@ export default function PathNavigator({
setPath([]); setPath([]);
setCurrentPhase('initial'); setCurrentPhase('initial');
setPickupDropPath([]);
setDropPickupPath([]);
distancesRef.current = []; distancesRef.current = [];
totalDistanceRef.current = 0; totalDistanceRef.current = 0;
progressRef.current = 0; progressRef.current = 0;
isWaiting.current = false; isWaiting.current = false;
pathTransitionProgress.current = 0;
if (initialPosition && initialRotation) {
const object = scene.getObjectByProperty("uuid", id); const object = scene.getObjectByProperty("uuid", id);
if (object) { if (object && initialPosition && initialRotation) {
object.position.copy(initialPosition); object.position.copy(initialPosition);
object.rotation.copy(initialRotation); object.rotation.copy(initialRotation);
} smoothPosition.copy(initialPosition);
targetPosition.copy(initialPosition);
targetQuaternion.setFromEuler(initialRotation);
} }
}; };
useEffect(() => { useEffect(() => {
if (!isPlaying) { if (!isPlaying) {
resetState(); resetState();
@ -171,16 +178,16 @@ export default function PathNavigator({
const end = new THREE.Vector3(...path[index + 1]); const end = new THREE.Vector3(...path[index + 1]);
const dist = distancesRef.current[index]; const dist = distancesRef.current[index];
const t = THREE.MathUtils.clamp((covered - accumulated) / dist, 0, 1); const t = THREE.MathUtils.clamp((covered - accumulated) / dist, 0, 1);
const position = start.clone().lerp(end, t);
object.position.copy(position); targetPosition.copy(start).lerp(end, t);
smoothPosition.lerp(targetPosition, 0.1);
object.position.copy(smoothPosition);
const direction = new THREE.Vector3().subVectors(end, start).normalize(); const direction = new THREE.Vector3().subVectors(end, start).normalize();
const targetRotationY = Math.atan2(direction.x, direction.z); const targetRotationY = Math.atan2(direction.x, direction.z);
targetQuaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), targetRotationY);
let angleDifference = targetRotationY - object.rotation.y; object.quaternion.slerp(targetQuaternion, 0.1);
angleDifference = ((angleDifference + Math.PI) % (Math.PI * 2)) - Math.PI;
object.rotation.y += angleDifference * 0.1;
}); });
useEffect(() => { useEffect(() => {

View File

@ -53,7 +53,7 @@ export default function addFloorToScene(
const mesh = new THREE.Mesh(geometry, material); const mesh = new THREE.Mesh(geometry, material);
mesh.receiveShadow = true; mesh.receiveShadow = true;
mesh.position.y = layer; mesh.position.y = (layer) * CONSTANTS.wallConfig.height;
mesh.rotateX(Math.PI / 2); mesh.rotateX(Math.PI / 2);
mesh.name = `Floor_Layer_${layer}`; mesh.name = `Floor_Layer_${layer}`;

View File

@ -171,7 +171,7 @@ function loadOnlyFloors(
mesh.castShadow = true; mesh.castShadow = true;
mesh.receiveShadow = true; mesh.receiveShadow = true;
mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height + 0.03; mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height;
mesh.rotateX(Math.PI / 2); mesh.rotateX(Math.PI / 2);
mesh.name = `Only_Floor_Line_${floor[0][0][2]}`; mesh.name = `Only_Floor_Line_${floor[0][0][2]}`;

View File

@ -1,20 +1,5 @@
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { import { useActiveTool, useAsset3dWidget, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useLoadingProgress, useRenderDistance, useselectedFloorItem, useSelectedItem, useSimulationStates, useSocketStore, useToggleView, useTransformMode, } from "../../../store/store";
useActiveTool,
useAsset3dWidget,
useCamMode,
useDeletableFloorItem,
useDeleteModels,
useFloorItems,
useLoadingProgress,
useRenderDistance,
useselectedFloorItem,
useSelectedItem,
useSimulationStates,
useSocketStore,
useToggleView,
useTransformMode,
} from "../../../store/store";
import assetVisibility from "../geomentries/assets/assetVisibility"; import assetVisibility from "../geomentries/assets/assetVisibility";
import { useEffect } from "react"; import { useEffect } from "react";
import * as THREE from "three"; import * as THREE from "three";
@ -31,28 +16,10 @@ import addAssetModel from "../geomentries/assets/addAssetModel";
import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
import useModuleStore from "../../../store/useModuleStore"; import useModuleStore from "../../../store/useModuleStore";
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils"; // import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
const assetManagerWorker = new Worker( const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url));
new URL( const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url));
"../../../services/factoryBuilder/webWorkers/assetManagerWorker.js",
import.meta.url
)
);
const gltfLoaderWorker = new Worker(
new URL(
"../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js",
import.meta.url
)
);
const FloorItemsGroup = ({ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => {
itemsGroup,
hoveredDeletableFloorItem,
AttachedObject,
floorGroup,
tempLoader,
isTempLoader,
plane,
}: any) => {
const state: Types.ThreeState = useThree(); const state: Types.ThreeState = useThree();
const { raycaster, controls }: any = state; const { raycaster, controls }: any = state;
const { renderDistance } = useRenderDistance(); const { renderDistance } = useRenderDistance();
@ -72,9 +39,7 @@ const FloorItemsGroup = ({
const loader = new GLTFLoader(); const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader(); const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath( dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/");
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
);
loader.setDRACOLoader(dracoLoader); loader.setDRACOLoader(dracoLoader);
useEffect(() => { useEffect(() => {
@ -99,10 +64,7 @@ const FloorItemsGroup = ({
getFloorAssets(organization).then((data) => { getFloorAssets(organization).then((data) => {
if (data.length > 0) { if (data.length > 0) {
const uniqueItems = (data as Types.FloorItems).filter( const uniqueItems = (data as Types.FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.modelfileID === item.modelfileID));
(item, index, self) =>
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
);
totalAssets = uniqueItems.length; totalAssets = uniqueItems.length;
if (totalAssets === 0) { if (totalAssets === 0) {
updateLoadingProgress(100); updateLoadingProgress(100);
@ -149,17 +111,10 @@ const FloorItemsGroup = ({
if (toggleView) return; if (toggleView) return;
const uuids: string[] = []; const uuids: string[] = [];
itemsGroup.current?.children.forEach((child: any) => { itemsGroup.current?.children.forEach((child: any) => { uuids.push(child.uuid); });
uuids.push(child.uuid);
});
const cameraPosition = state.camera.position; const cameraPosition = state.camera.position;
assetManagerWorker.postMessage({ assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance, });
floorItems,
cameraPosition,
uuids,
renderDistance,
});
}, [camMode, renderDistance]); }, [camMode, renderDistance]);
useEffect(() => { useEffect(() => {
@ -173,17 +128,10 @@ const FloorItemsGroup = ({
if (toggleView) return; if (toggleView) return;
const uuids: string[] = []; const uuids: string[] = [];
itemsGroup.current?.children.forEach((child: any) => { itemsGroup.current?.children.forEach((child: any) => { uuids.push(child.uuid); });
uuids.push(child.uuid);
});
const cameraPosition = camera.position; const cameraPosition = camera.position;
assetManagerWorker.postMessage({ assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance, });
floorItems,
cameraPosition,
uuids,
renderDistance,
});
}; };
const startInterval = () => { const startInterval = () => {
@ -244,13 +192,7 @@ const FloorItemsGroup = ({
if (drag) return; if (drag) return;
if (deleteModels) { if (deleteModels) {
DeleteFloorItems( DeleteFloorItems(itemsGroup, hoveredDeletableFloorItem, setFloorItems, setSimulationStates, socket);
itemsGroup,
hoveredDeletableFloorItem,
setFloorItems,
setSimulationStates,
socket
);
} }
const Mode = transformMode; const Mode = transformMode;
@ -260,12 +202,7 @@ const FloorItemsGroup = ({
itemsGroup.current.children, itemsGroup.current.children,
true true
); );
if ( if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
intersects.length > 0 &&
intersects[0]?.object?.parent?.parent?.position &&
intersects[0]?.object?.parent?.parent?.scale &&
intersects[0]?.object?.parent?.parent?.rotation
) {
// let currentObject = intersects[0].object; // let currentObject = intersects[0].object;
// while (currentObject) { // while (currentObject) {
// if (currentObject.name === "Scene") { // if (currentObject.name === "Scene") {
@ -295,16 +232,8 @@ const FloorItemsGroup = ({
if (Mode !== null || activeTool === "cursor") { if (Mode !== null || activeTool === "cursor") {
if (!itemsGroup.current) return; if (!itemsGroup.current) return;
let intersects = raycaster.intersectObjects( let intersects = raycaster.intersectObjects(itemsGroup.current.children, true);
itemsGroup.current.children, if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
true
);
if (
intersects.length > 0 &&
intersects[0]?.object?.parent?.parent?.position &&
intersects[0]?.object?.parent?.parent?.scale &&
intersects[0]?.object?.parent?.parent?.rotation
) {
let currentObject = intersects[0].object; let currentObject = intersects[0].object;
while (currentObject) { while (currentObject) {
@ -317,9 +246,7 @@ const FloorItemsGroup = ({
AttachedObject.current = currentObject as any; AttachedObject.current = currentObject as any;
// controls.fitToSphere(AttachedObject.current!, true); // controls.fitToSphere(AttachedObject.current!, true);
const bbox = new THREE.Box3().setFromObject( const bbox = new THREE.Box3().setFromObject(AttachedObject.current);
AttachedObject.current
);
const size = bbox.getSize(new THREE.Vector3()); const size = bbox.getSize(new THREE.Vector3());
const center = bbox.getCenter(new THREE.Vector3()); const center = bbox.getCenter(new THREE.Vector3());
@ -328,24 +255,11 @@ const FloorItemsGroup = ({
front.sub(AttachedObject.current.position).normalize(); front.sub(AttachedObject.current.position).normalize();
const distance = Math.max(size.x, size.y, size.z) * 2; const distance = Math.max(size.x, size.y, size.z) * 2;
const newPosition = center const newPosition = center.clone().addScaledVector(front, distance);
.clone()
.addScaledVector(front, distance);
controls.setPosition( controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true);
newPosition.x,
newPosition.y,
newPosition.z,
true
);
controls.setTarget(center.x, center.y, center.z, true); controls.setTarget(center.x, center.y, center.z, true);
controls.fitToBox(AttachedObject.current!, true, { controls.fitToBox(AttachedObject.current!, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, });
cover: true,
paddingTop: 5,
paddingLeft: 5,
paddingBottom: 5,
paddingRight: 5,
});
setselectedFloorItem(AttachedObject.current!); setselectedFloorItem(AttachedObject.current!);
} }
@ -362,21 +276,7 @@ const FloorItemsGroup = ({
if (!event.dataTransfer?.files[0]) return; if (!event.dataTransfer?.files[0]) return;
if (selectedItem.id !== "" && event.dataTransfer?.files[0]) { if (selectedItem.id !== "" && event.dataTransfer?.files[0]) {
addAssetModel( addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, setSimulationStates, plane);
raycaster,
state.camera,
state.pointer,
floorGroup,
setFloorItems,
itemsGroup,
isTempLoader,
tempLoader,
socket,
selectedItem,
setSelectedItem,
setSimulationStates,
plane
);
} }
}; };
@ -407,28 +307,13 @@ const FloorItemsGroup = ({
canvasElement.removeEventListener("drop", onDrop); canvasElement.removeEventListener("drop", onDrop);
canvasElement.removeEventListener("dragover", onDragOver); canvasElement.removeEventListener("dragover", onDragOver);
}; };
}, [ }, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule,]);
deleteModels,
transformMode,
controls,
selectedItem,
state.camera,
state.pointer,
activeTool,
activeModule,
]);
useFrame(() => { useFrame(() => {
if (controls) if (controls)
assetVisibility(itemsGroup, state.camera.position, renderDistance); assetVisibility(itemsGroup, state.camera.position, renderDistance);
if (deleteModels) { if (deleteModels && activeModule === "builder") {
DeletableHoveredFloorItems( DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem);
state,
itemsGroup,
hoveredDeletableFloorItem,
setDeletableFloorItem
);
} else if (!deleteModels) { } else if (!deleteModels) {
if (hoveredDeletableFloorItem.current) { if (hoveredDeletableFloorItem.current) {
hoveredDeletableFloorItem.current = undefined; hoveredDeletableFloorItem.current = undefined;

View File

@ -9,9 +9,13 @@ import handleMeshMissed from "../eventFunctions/handleMeshMissed";
import DeleteWallItems from "../geomentries/walls/deleteWallItems"; import DeleteWallItems from "../geomentries/walls/deleteWallItems";
import loadInitialWallItems from "../../scene/IntialLoad/loadInitialWallItems"; import loadInitialWallItems from "../../scene/IntialLoad/loadInitialWallItems";
import AddWallItems from "../geomentries/walls/addWallItems"; import AddWallItems from "../geomentries/walls/addWallItems";
import useModuleStore from "../../../store/useModuleStore";
const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletableWallItem, selectedItemsIndex, setSelectedItemsIndex, CSGGroup }: any) => { const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletableWallItem, selectedItemsIndex, setSelectedItemsIndex, CSGGroup }: any) => {
const state = useThree();
const { socket } = useSocketStore();
const { pointer, camera, raycaster } = state;
const { deleteModels, setDeleteModels } = useDeleteModels(); const { deleteModels, setDeleteModels } = useDeleteModels();
const { wallItems, setWallItems } = useWallItems(); const { wallItems, setWallItems } = useWallItems();
const { objectPosition, setObjectPosition } = useObjectPosition(); const { objectPosition, setObjectPosition } = useObjectPosition();
@ -19,10 +23,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
const { objectRotation, setObjectRotation } = useObjectRotation(); const { objectRotation, setObjectRotation } = useObjectRotation();
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
const { socket } = useSocketStore(); const { activeModule } = useModuleStore();
const state = useThree();
const { pointer, camera, raycaster } = state;
useEffect(() => { useEffect(() => {
// Load Wall Items from the backend // Load Wall Items from the backend
@ -209,7 +210,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
const onMouseUp = (evt: any) => { const onMouseUp = (evt: any) => {
if (evt.button === 0) { if (evt.button === 0) {
isLeftMouseDown = false; isLeftMouseDown = false;
if (!drag && deleteModels) { if (!drag && deleteModels && activeModule === "builder") {
DeleteWallItems(hoveredDeletableWallItem, setWallItems, wallItems, socket); DeleteWallItems(hoveredDeletableWallItem, setWallItems, wallItems, socket);
} }
} }
@ -259,7 +260,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
}, [deleteModels, wallItems]) }, [deleteModels, wallItems])
useEffect(() => { useEffect(() => {
if (deleteModels) { if (deleteModels && activeModule === "builder") {
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex); handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
setSelectedWallItem(null); setSelectedWallItem(null);
setSelectedItemsIndex(null); setSelectedItemsIndex(null);

View File

@ -192,7 +192,7 @@ function processLoadedModel(
}, },
]); ]);
if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') { if (item.eventData || item.modelfileID === '67e3db5ac2e8f37134526f40' || item.modelfileID === '67eb7904c2e8f37134527eae') {
processEventData(item, setSimulationStates); processEventData(item, setSimulationStates);
} }
@ -227,10 +227,10 @@ function processEventData(item: Types.EventData, setSimulationStates: any) {
data as Types.VehicleEventsSchema data as Types.VehicleEventsSchema
]); ]);
} else if (item.modelfileID === '67e3db95c2e8f37134526fb2') { } else if (item.modelfileID === '67e3db5ac2e8f37134526f40') {
const pointUUID = THREE.MathUtils.generateUUID(); const pointUUID = THREE.MathUtils.generateUUID();
const pointPosition = new THREE.Vector3(0, 1.75, 0); const pointPosition = new THREE.Vector3(0, 1.5, -0.5);
const staticMachine: Types.StaticMachineEventsSchema = { const staticMachine: Types.StaticMachineEventsSchema = {
modeluuid: item.modeluuid, modeluuid: item.modeluuid,
@ -243,13 +243,39 @@ function processEventData(item: Types.EventData, setSimulationStates: any) {
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] }, connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
}, },
position: item.position position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
}; };
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
staticMachine as Types.StaticMachineEventsSchema staticMachine as Types.StaticMachineEventsSchema
]); ]);
} else if (item.modelfileID === '67eb7904c2e8f37134527eae') {
const pointUUID = THREE.MathUtils.generateUUID();
const pointPosition = new THREE.Vector3(0, 2.75, -0.5);
const armBot: Types.ArmBotEventsSchema = {
modeluuid: item.modeluuid,
modelName: item.modelname,
type: "ArmBot",
points: {
uuid: pointUUID,
position: [pointPosition.x, pointPosition.y, pointPosition.z],
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', speed: 1, processes: [] },
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
},
position: item.position,
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
}
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []),
armBot as Types.ArmBotEventsSchema
]);
} }
} }

View File

@ -151,7 +151,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
return updatedItems; return updatedItems;
}); });
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default"; const organization = email ? email.split("@")[1].split(".")[0] : "default";
@ -234,7 +234,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
newEventData as Types.ConveyorEventsSchema newEventData as Types.ConveyorEventsSchema
]); ]);
@ -313,13 +313,44 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
newEventData.modelName = newFloorItem.modelname; newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
newEventData as Types.VehicleEventsSchema newEventData as Types.VehicleEventsSchema
]); ]);
socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
} else {
//REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
//SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id,
};
socket.emit("v2:model-asset:add", data);
} }
} else { } else {

View File

@ -132,7 +132,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
return updatedItems; return updatedItems;
}); });
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default"; const organization = email ? email.split("@")[1].split(".")[0] : "default";
@ -216,7 +216,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
newEventData as Types.ConveyorEventsSchema newEventData as Types.ConveyorEventsSchema
]); ]);
@ -295,13 +295,44 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
newEventData.modelName = newFloorItem.modelname; newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
newEventData as Types.VehicleEventsSchema newEventData as Types.VehicleEventsSchema
]); ]);
socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
} else {
//REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false,
// true,
// );
//SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false,
isVisible: true,
socketId: socket.id,
};
socket.emit("v2:model-asset:add", data);
} }
} else { } else {

View File

@ -180,12 +180,12 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
return updatedItems; return updatedItems;
}); });
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default"; const organization = email ? email.split("@")[1].split(".")[0] : "default";
if (eventData && eventData.type !== 'StaticMachine') { if (eventData) {
if (eventData.type === 'Conveyor' && eventData) { if (eventData.type === 'Conveyor' && eventData) {
const backendEventData = { const backendEventData = {
@ -229,7 +229,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event => const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData } ? { ...event, ...newEventData }
@ -280,7 +280,113 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
newEventData.modelName = newFloorItem.modelname; newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData }
: event
);
return updatedEvents;
});
socket.emit("v2:model-asset:add", data);
} else if (eventData.type === 'StaticMachine' && eventData) {
const backendEventData = {
type: 'StaticMachine',
points: eventData.points,
};
// REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// obj.userData.modelId,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// false,
// true,
// { type: backendEventData.type, points: backendEventData.points }
// );
//SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false,
isVisible: true,
// eventData: { type: backendEventData.type, points: backendEventData.points },
socketId: socket.id,
};
const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
newEventData.modeluuid = newFloorItem.modeluuid;
newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData }
: event
);
return updatedEvents;
});
socket.emit("v2:model-asset:add", data);
} else if (eventData.type === 'ArmBot' && eventData) {
const backendEventData = {
type: 'ArmBot',
points: eventData.points,
};
// REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// obj.userData.modelId,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// false,
// true,
// { type: backendEventData.type, points: backendEventData.points }
// );
//SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false,
isVisible: true,
// eventData: { type: backendEventData.type, points: backendEventData.points },
socketId: socket.id,
};
const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
newEventData.modeluuid = newFloorItem.modeluuid;
newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event => const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData } ? { ...event, ...newEventData }

View File

@ -184,13 +184,12 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
return updatedItems; return updatedItems;
}); });
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
console.log('eventData: ', eventData);
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default"; const organization = email ? email.split("@")[1].split(".")[0] : "default";
if (eventData && eventData.type !== 'StaticMachine') { if (eventData) {
if (eventData.type === 'Conveyor' && eventData) { if (eventData.type === 'Conveyor' && eventData) {
const backendEventData = { const backendEventData = {
@ -233,9 +232,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
newEventData.modelName = newFloorItem.modelname; newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
console.log('newEventData: ', newEventData);
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event => const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData } ? { ...event, ...newEventData }
@ -287,7 +285,113 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
newEventData.modelName = newFloorItem.modelname; newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData }
: event
);
return updatedEvents;
});
socket.emit("v2:model-asset:add", data);
} else if (eventData.type === 'StaticMachine' && eventData) {
const backendEventData = {
type: 'StaticMachine',
points: eventData.points,
};
// REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// obj.userData.modelId,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// false,
// true,
// { type: backendEventData.type, points: backendEventData.points }
// );
//SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false,
isVisible: true,
// eventData: { type: backendEventData.type, points: backendEventData.points },
socketId: socket.id,
};
const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
newEventData.modeluuid = newFloorItem.modeluuid;
newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData }
: event
);
return updatedEvents;
});
socket.emit("v2:model-asset:add", data);
} else if (eventData.type === 'ArmBot' && eventData) {
const backendEventData = {
type: 'ArmBot',
points: eventData.points,
};
// REST
// await setFloorItemApi(
// organization,
// obj.uuid,
// obj.userData.name,
// obj.userData.modelId,
// [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// false,
// true,
// { type: backendEventData.type, points: backendEventData.points }
// );
//SOCKET
const data = {
organization,
modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position,
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false,
isVisible: true,
// eventData: { type: backendEventData.type, points: backendEventData.points },
socketId: socket.id,
};
const newEventData: any = { type: backendEventData.type, points: backendEventData.points };
newEventData.modeluuid = newFloorItem.modeluuid;
newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event => const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData } ? { ...event, ...newEventData }

View File

@ -240,7 +240,7 @@ const SelectionControls: React.FC = () => {
} }
}); });
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid); const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid);
return updatedEvents; return updatedEvents;
}); });

View File

@ -1,9 +1,9 @@
import { useFrame, useThree } from '@react-three/fiber'; import { useFrame, useThree } from '@react-three/fiber';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from '../../../types/world/worldTypes'; import * as Types from '../../../types/world/worldTypes';
import { QuadraticBezierLine } from '@react-three/drei'; import { QuadraticBezierLine } from '@react-three/drei';
import { useIsConnecting, useSimulationStates, useSocketStore } from '../../../store/store'; import { useIsConnecting, useRenderDistance, useSimulationStates, useSocketStore } from '../../../store/store';
import useModuleStore from '../../../store/useModuleStore'; import useModuleStore from '../../../store/useModuleStore';
import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
import { setEventApi } from '../../../services/factoryBuilder/assest/floorAsset/setEventsApt'; import { setEventApi } from '../../../services/factoryBuilder/assest/floorAsset/setEventsApt';
@ -11,28 +11,21 @@ import { setEventApi } from '../../../services/factoryBuilder/assest/floorAsset/
function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) { function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const { gl, raycaster, scene, pointer, camera } = useThree(); const { gl, raycaster, scene, pointer, camera } = useThree();
const { renderDistance } = useRenderDistance();
const { setIsConnecting } = useIsConnecting(); const { setIsConnecting } = useIsConnecting();
const { simulationStates, setSimulationStates } = useSimulationStates(); const { simulationStates, setSimulationStates } = useSimulationStates();
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { socket } = useSocketStore(); const { socket } = useSocketStore();
const groupRefs = useRef<{ [key: string]: any }>({});
const [firstSelected, setFirstSelected] = useState<{ const [firstSelected, setFirstSelected] = useState<{ modelUUID: string; sphereUUID: string; position: THREE.Vector3; isCorner: boolean; } | null>(null);
modelUUID: string;
sphereUUID: string;
position: THREE.Vector3;
isCorner: boolean;
} | null>(null);
const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3, end: THREE.Vector3, mid: THREE.Vector3 } | null>(null); const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3, end: THREE.Vector3, mid: THREE.Vector3 } | null>(null);
const [helperlineColor, setHelperLineColor] = useState<string>('red'); const [helperlineColor, setHelperLineColor] = useState<string>('red');
const updatePathConnections = ( const updatePathConnections = (fromModelUUID: string, fromPointUUID: string, toModelUUID: string, toPointUUID: string) => {
fromModelUUID: string,
fromPointUUID: string,
toModelUUID: string,
toPointUUID: string
) => {
const updatedPaths = simulationStates.map(path => { const updatedPaths = simulationStates.map(path => {
if (path.type === 'Conveyor') { if (path.type === 'Conveyor') {
// Handle outgoing connections from Conveyor
if (path.modeluuid === fromModelUUID) { if (path.modeluuid === fromModelUUID) {
return { return {
...path, ...path,
@ -61,6 +54,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
}) })
}; };
} }
// Handle incoming connections to Conveyor
else if (path.modeluuid === toModelUUID) { else if (path.modeluuid === toModelUUID) {
return { return {
...path, ...path,
@ -167,82 +161,170 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
return path; return path;
} }
// else if (path.type === 'StaticMachine') { else if (path.type === 'StaticMachine') {
// if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) { // Handle outgoing connections from StaticMachine
// const newTarget = { if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
// modelUUID: toModelUUID, const newTarget = {
// pointUUID: toPointUUID modelUUID: toModelUUID,
// }; pointUUID: toPointUUID
// const existingTargets = path.points.connections.targets || []; };
// // Check if target is an ArmBot // Ensure target is an ArmBot
// const toPath = simulationStates.find(p => p.modeluuid === toModelUUID); const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
// if (toPath?.type !== 'ArmBot') { if (toPath?.type !== 'ArmBot') {
// console.log("StaticMachine can only connect to ArmBot"); console.log("StaticMachine can only connect to ArmBot");
// return path; return path;
// } }
// // Check if already has a connection const existingTargets = path.points.connections.targets || [];
// if (existingTargets.length >= 1) {
// console.log("StaticMachine can have only one connection");
// return path;
// }
// if (!existingTargets.some(target => // Allow only one connection
// target.modelUUID === newTarget.modelUUID && if (existingTargets.length >= 1) {
// target.pointUUID === newTarget.pointUUID console.log("StaticMachine can only have one connection");
// )) { return path;
// return { }
// ...path,
// points: {
// ...path.points,
// connections: {
// ...path.points.connections,
// targets: [...existingTargets, newTarget]
// }
// }
// };
// }
// }
// // Handle incoming connections to StaticMachine
// else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
// const reverseTarget = {
// modelUUID: fromModelUUID,
// pointUUID: fromPointUUID
// };
// const existingTargets = path.points.connections.targets || [];
// // Check if source is an ArmBot if (!existingTargets.some(target =>
// const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID); target.modelUUID === newTarget.modelUUID &&
// if (fromPath?.type !== 'ArmBot') { target.pointUUID === newTarget.pointUUID
// console.log("StaticMachine can only connect to ArmBot"); )) {
// return path; return {
// } ...path,
points: {
...path.points,
connections: {
...path.points.connections,
targets: [...existingTargets, newTarget]
}
}
};
}
}
// // Check if already has a connection // Handle incoming connections to StaticMachine
// if (existingTargets.length >= 1) { else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
// console.log("StaticMachine can have only one connection"); const reverseTarget = {
// return path; modelUUID: fromModelUUID,
// } pointUUID: fromPointUUID
};
const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
if (fromPath?.type !== 'ArmBot') {
console.log("StaticMachine can only be connected from ArmBot");
return path;
}
const existingTargets = path.points.connections.targets || [];
if (existingTargets.length >= 1) {
console.log("StaticMachine can only have one connection");
return path;
}
if (!existingTargets.some(target =>
target.modelUUID === reverseTarget.modelUUID &&
target.pointUUID === reverseTarget.pointUUID
)) {
return {
...path,
points: {
...path.points,
connections: {
...path.points.connections,
targets: [...existingTargets, reverseTarget]
}
}
};
}
}
return path;
}
else if (path.type === 'ArmBot') {
// Handle outgoing connections from ArmBot
if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
const newTarget = {
modelUUID: toModelUUID,
pointUUID: toPointUUID
};
const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
if (!toPath) return path;
const existingTargets = path.points.connections.targets || [];
// Check if connecting to a StaticMachine and already connected to one
const alreadyConnectedToStatic = existingTargets.some(target => {
const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
return targetPath?.type === 'StaticMachine';
});
if (toPath.type === 'StaticMachine') {
if (alreadyConnectedToStatic) {
console.log("ArmBot can only connect to one StaticMachine");
return path;
}
}
if (!existingTargets.some(target =>
target.modelUUID === newTarget.modelUUID &&
target.pointUUID === newTarget.pointUUID
)) {
return {
...path,
points: {
...path.points,
connections: {
...path.points.connections,
targets: [...existingTargets, newTarget]
}
}
};
}
}
// Handle incoming connections to ArmBot
else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
const reverseTarget = {
modelUUID: fromModelUUID,
pointUUID: fromPointUUID
};
const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
if (!fromPath) return path;
const existingTargets = path.points.connections.targets || [];
const alreadyConnectedFromStatic = existingTargets.some(target => {
const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
return targetPath?.type === 'StaticMachine';
});
if (fromPath.type === 'StaticMachine') {
if (alreadyConnectedFromStatic) {
console.log("ArmBot can only be connected from one StaticMachine");
return path;
}
}
if (!existingTargets.some(target =>
target.modelUUID === reverseTarget.modelUUID &&
target.pointUUID === reverseTarget.pointUUID
)) {
return {
...path,
points: {
...path.points,
connections: {
...path.points.connections,
targets: [...existingTargets, reverseTarget]
}
}
};
}
}
return path;
}
// if (!existingTargets.some(target =>
// target.modelUUID === reverseTarget.modelUUID &&
// target.pointUUID === reverseTarget.pointUUID
// )) {
// return {
// ...path,
// points: {
// ...path.points,
// connections: {
// ...path.points.connections,
// targets: [...existingTargets, reverseTarget]
// }
// }
// };
// }
// }
// return path;
// }
return path; return path;
}); });
@ -252,10 +334,10 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
path.modeluuid === fromModelUUID || path.modeluuid === toModelUUID path.modeluuid === fromModelUUID || path.modeluuid === toModelUUID
); );
updateBackend(updatedPathDetails); // updateBackend(updatedPathDetails);
}; };
const updateBackend = async (updatedPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { const updateBackend = async (updatedPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
if (updatedPaths.length === 0) return; if (updatedPaths.length === 0) return;
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : ""; const organization = email ? email.split("@")[1].split(".")[0] : "";
@ -437,6 +519,69 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
return; return;
} }
// Check if StaticMachine is involved in the connection
if ((firstPath?.type === 'StaticMachine' && secondPath?.type !== 'ArmBot') ||
(secondPath?.type === 'StaticMachine' && firstPath?.type !== 'ArmBot')) {
console.log("StaticMachine can only connect to ArmBot");
return;
}
// Check if StaticMachine already has a connection
if (firstPath?.type === 'StaticMachine') {
const staticConnections = firstPath.points.connections.targets.length;
if (staticConnections >= 1) {
console.log("StaticMachine can only have one connection");
return;
}
}
if (secondPath?.type === 'StaticMachine') {
const staticConnections = secondPath.points.connections.targets.length;
if (staticConnections >= 1) {
console.log("StaticMachine can only have one connection");
return;
}
}
// Check if ArmBot is involved
if ((firstPath?.type === 'ArmBot' && secondPath?.type === 'StaticMachine') ||
(secondPath?.type === 'ArmBot' && firstPath?.type === 'StaticMachine')) {
const armBotPath = firstPath?.type === 'ArmBot' ? firstPath : secondPath;
const staticPath = firstPath?.type === 'StaticMachine' ? firstPath : secondPath;
const armBotConnections = armBotPath.points.connections.targets || [];
const alreadyConnectedToStatic = armBotConnections.some(target => {
const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
return targetPath?.type === 'StaticMachine';
});
if (alreadyConnectedToStatic) {
console.log("ArmBot can only connect to one StaticMachine");
return;
}
const staticConnections = staticPath.points.connections.targets.length;
if (staticConnections >= 1) {
console.log("StaticMachine can only have one connection");
return;
}
}
// Prevent ArmBot ↔ ArmBot
if (firstPath?.type === 'ArmBot' && secondPath?.type === 'ArmBot') {
console.log("Cannot connect two ArmBots together");
return;
}
// If one is ArmBot, ensure the other is StaticMachine or Conveyor
if (firstPath?.type === 'ArmBot' || secondPath?.type === 'ArmBot') {
const otherType = firstPath?.type === 'ArmBot' ? secondPath?.type : firstPath?.type;
if (otherType !== 'StaticMachine' && otherType !== 'Conveyor') {
console.log("ArmBot can only connect to Conveyors or one StaticMachine");
return;
}
}
// At least one must be start/end point // At least one must be start/end point
if (!firstSelected.isCorner && !isStartOrEnd) { if (!firstSelected.isCorner && !isStartOrEnd) {
console.log("At least one of the selected spheres must be a start or end point."); console.log("At least one of the selected spheres must be a start or end point.");
@ -489,6 +634,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
}; };
}, [camera, scene, raycaster, firstSelected, simulationStates]); }, [camera, scene, raycaster, firstSelected, simulationStates]);
useFrame(() => {
Object.values(groupRefs.current).forEach((group) => {
if (group) {
const distance = new THREE.Vector3(...group.position.toArray()).distanceTo(camera.position);
group.visible = ((distance <= renderDistance) && !isPlaying);
}
});
});
useFrame(() => { useFrame(() => {
if (firstSelected) { if (firstSelected) {
raycaster.setFromCamera(pointer, camera); raycaster.setFromCamera(pointer, camera);
@ -574,12 +728,50 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
(firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') || (firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
(secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor'); (secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor');
// Check if StaticMachine is connecting to non-ArmBot
const isStaticMachineToNonArmBot =
(firstPath?.type === 'StaticMachine' && secondPath?.type !== 'ArmBot') ||
(secondPath?.type === 'StaticMachine' && firstPath?.type !== 'ArmBot');
// Check if StaticMachine already has a connection
const isStaticMachineAtMaxConnections =
(firstPath?.type === 'StaticMachine' && firstPath.points.connections.targets.length >= 1) ||
(secondPath?.type === 'StaticMachine' && secondPath.points.connections.targets.length >= 1);
// Check if ArmBot is connecting to StaticMachine
const isArmBotToStaticMachine =
(firstPath?.type === 'ArmBot' && secondPath?.type === 'StaticMachine') ||
(secondPath?.type === 'ArmBot' && firstPath?.type === 'StaticMachine');
// Prevent multiple StaticMachine connections to ArmBot
let isArmBotAlreadyConnectedToStatic = false;
if (isArmBotToStaticMachine) {
const armBotPath = firstPath?.type === 'ArmBot' ? firstPath : secondPath;
isArmBotAlreadyConnectedToStatic = armBotPath.points.connections.targets.some(target => {
const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
return targetPath?.type === 'StaticMachine';
});
}
// Prevent ArmBot to ArmBot
const isArmBotToArmBot = firstPath?.type === 'ArmBot' && secondPath?.type === 'ArmBot';
// If ArmBot is involved, other must be Conveyor or StaticMachine
const isArmBotToInvalidType = (firstPath?.type === 'ArmBot' || secondPath?.type === 'ArmBot') &&
!(firstPath?.type === 'Conveyor' || firstPath?.type === 'StaticMachine' ||
secondPath?.type === 'Conveyor' || secondPath?.type === 'StaticMachine');
if ( if (
!isDuplicateConnection && !isDuplicateConnection &&
!isVehicleToVehicle && !isVehicleToVehicle &&
!isNonVehicleAlreadyConnected && !isNonVehicleAlreadyConnected &&
!isVehicleAtMaxConnections && !isVehicleAtMaxConnections &&
!isVehicleConnectingToNonConveyor && !isVehicleConnectingToNonConveyor &&
!isStaticMachineToNonArmBot &&
!isStaticMachineAtMaxConnections &&
!isArmBotToArmBot &&
!isArmBotToInvalidType &&
!isArmBotAlreadyConnectedToStatic &&
firstSelected.sphereUUID !== sphereUUID && firstSelected.sphereUUID !== sphereUUID &&
firstSelected.modelUUID !== modelUUID && firstSelected.modelUUID !== modelUUID &&
(firstSelected.isCorner || isConnectable) && (firstSelected.isCorner || isConnectable) &&
@ -596,6 +788,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} else { } else {
isInvalidConnection = true; isInvalidConnection = true;
} }
} }
if (snappedSphere) { if (snappedSphere) {
@ -633,7 +826,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
}); });
return ( return (
<group name='simulationConnectionGroup' visible={!isPlaying} > <group name='simulationConnectionGroup' visible={!isPlaying}>
{simulationStates.flatMap(path => { {simulationStates.flatMap(path => {
if (path.type === 'Conveyor') { if (path.type === 'Conveyor') {
return path.points.flatMap(point => return path.points.flatMap(point =>
@ -652,7 +845,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const distance = fromWorldPosition.distanceTo(toWorldPosition); const distance = fromWorldPosition.distanceTo(toWorldPosition);
const heightFactor = Math.max(0.5, distance * 0.2); const heightFactor = Math.max(0.5, distance * 0.2);
const midPoint = new THREE.Vector3( const midPoint = new THREE.Vector3(
(fromWorldPosition.x + toWorldPosition.x) / 2, (fromWorldPosition.x + toWorldPosition.x) / 2,
Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor, Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
@ -662,6 +854,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
return ( return (
<QuadraticBezierLine <QuadraticBezierLine
key={`${point.uuid}-${target.pointUUID}-${index}`} key={`${point.uuid}-${target.pointUUID}-${index}`}
ref={(el) => (groupRefs.current[`${point.uuid}-${target.pointUUID}-${index}`] = el!)}
start={fromWorldPosition.toArray()} start={fromWorldPosition.toArray()}
end={toWorldPosition.toArray()} end={toWorldPosition.toArray()}
mid={midPoint.toArray()} mid={midPoint.toArray()}
@ -676,7 +869,9 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
return null; return null;
}) })
); );
} else if (path.type === 'Vehicle') { }
if (path.type === 'Vehicle') {
return path.points.connections.targets.map((target, index) => { return path.points.connections.targets.map((target, index) => {
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid); const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid);
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID); const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
@ -689,7 +884,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const distance = fromWorldPosition.distanceTo(toWorldPosition); const distance = fromWorldPosition.distanceTo(toWorldPosition);
const heightFactor = Math.max(0.5, distance * 0.2); const heightFactor = Math.max(0.5, distance * 0.2);
const midPoint = new THREE.Vector3( const midPoint = new THREE.Vector3(
(fromWorldPosition.x + toWorldPosition.x) / 2, (fromWorldPosition.x + toWorldPosition.x) / 2,
Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor, Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
@ -699,6 +893,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
return ( return (
<QuadraticBezierLine <QuadraticBezierLine
key={`${path.points.uuid}-${target.pointUUID}-${index}`} key={`${path.points.uuid}-${target.pointUUID}-${index}`}
ref={(el) => (groupRefs.current[`${path.points.uuid}-${target.pointUUID}-${index}`] = el!)}
start={fromWorldPosition.toArray()} start={fromWorldPosition.toArray()}
end={toWorldPosition.toArray()} end={toWorldPosition.toArray()}
mid={midPoint.toArray()} mid={midPoint.toArray()}
@ -713,6 +908,48 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
return null; return null;
}); });
} }
if (path.type === 'StaticMachine') {
return path.points.connections.targets.map((target, index) => {
const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
if (targetPath?.type !== 'ArmBot') return null;
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid);
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
if (fromSphere && toSphere) {
const fromWorldPosition = new THREE.Vector3();
const toWorldPosition = new THREE.Vector3();
fromSphere.getWorldPosition(fromWorldPosition);
toSphere.getWorldPosition(toWorldPosition);
const distance = fromWorldPosition.distanceTo(toWorldPosition);
const heightFactor = Math.max(0.5, distance * 0.2);
const midPoint = new THREE.Vector3(
(fromWorldPosition.x + toWorldPosition.x) / 2,
Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
(fromWorldPosition.z + toWorldPosition.z) / 2
);
return (
<QuadraticBezierLine
key={`${path.points.uuid}-${target.pointUUID}-${index}`}
ref={(el) => (groupRefs.current[`${path.points.uuid}-${target.pointUUID}-${index}`] = el!)}
start={fromWorldPosition.toArray()}
end={toWorldPosition.toArray()}
mid={midPoint.toArray()}
color="#42a5f5"
lineWidth={4}
dashed
dashSize={0.75}
dashScale={20}
/>
);
}
return null;
});
}
return []; return [];
})} })}
@ -730,6 +967,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
)} )}
</group> </group>
); );
} }
export default PathConnector; export default PathConnector;

View File

@ -206,6 +206,7 @@ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObjec
return ( return (
<group <group
name={`${path.modeluuid}-${path.type}-path`} name={`${path.modeluuid}-${path.type}-path`}
uuid={path.modeluuid}
key={path.modeluuid} key={path.modeluuid}
ref={(el) => (groupRefs.current[path.modeluuid] = el!)} ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
position={path.position} position={path.position}
@ -271,10 +272,11 @@ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObjec
})} })}
</group> </group>
); );
} else if (path.type === "Vehicle" || path.type === "StaticMachine") { } else if (path.type === "Vehicle") {
return ( return (
<group <group
name={`${path.modeluuid}-${path.type}-path`} name={`${path.modeluuid}-${path.type}-path`}
uuid={path.modeluuid}
key={path.modeluuid} key={path.modeluuid}
ref={(el) => (groupRefs.current[path.modeluuid] = el!)} ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
position={path.position} position={path.position}
@ -323,6 +325,114 @@ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObjec
</Sphere> </Sphere>
</group> </group>
); );
} else if (path.type === "StaticMachine") {
return (
<group
name={`${path.modeluuid}-${path.type}-path`}
uuid={path.modeluuid}
key={path.modeluuid}
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
position={path.position}
rotation={path.rotation}
onClick={(e) => {
if (isConnecting || eyeDropMode) return;
e.stopPropagation();
setSelectedPath({
path,
group: groupRefs.current[path.modeluuid],
});
setSelectedActionSphere(null);
setTransformMode(null);
setSubModule("mechanics");
}}
onPointerMissed={() => {
if (eyeDropMode) return;
setSelectedPath(null);
setSubModule("properties");
}}
>
<Sphere
key={path.points.uuid}
uuid={path.points.uuid}
position={path.points.position}
args={[0.15, 32, 32]}
name="events-sphere"
ref={(el) => (sphereRefs.current[path.points.uuid] = el!)}
onClick={(e) => {
if (isConnecting || eyeDropMode) return;
e.stopPropagation();
setSelectedActionSphere({
path,
points: sphereRefs.current[path.points.uuid],
});
setSubModule("mechanics");
setSelectedPath(null);
}}
userData={{ points: path.points, path }}
onPointerMissed={() => {
if (eyeDropMode) return;
setSubModule("properties");
setSelectedActionSphere(null);
}}
>
<meshStandardMaterial color="yellow" />
</Sphere>
</group>
);
} else if (path.type === "ArmBot") {
return (
<group
name={`${path.modeluuid}-${path.type}-path`}
uuid={path.modeluuid}
key={path.modeluuid}
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
position={path.position}
rotation={path.rotation}
onClick={(e) => {
if (isConnecting || eyeDropMode) return;
e.stopPropagation();
setSelectedPath({
path,
group: groupRefs.current[path.modeluuid],
});
setSelectedActionSphere(null);
setTransformMode(null);
setSubModule("mechanics");
}}
onPointerMissed={() => {
if (eyeDropMode) return;
setSelectedPath(null);
setSubModule("properties");
}}
>
<Sphere
key={path.points.uuid}
uuid={path.points.uuid}
position={path.points.position}
args={[0.15, 32, 32]}
name="events-sphere"
ref={(el) => (sphereRefs.current[path.points.uuid] = el!)}
onClick={(e) => {
if (isConnecting || eyeDropMode) return;
e.stopPropagation();
setSelectedActionSphere({
path,
points: sphereRefs.current[path.points.uuid],
});
setSubModule("mechanics");
setSelectedPath(null);
}}
userData={{ points: path.points, path }}
onPointerMissed={() => {
if (eyeDropMode) return;
setSubModule("properties");
setSelectedActionSphere(null);
}}
>
<meshStandardMaterial color="pink" />
</Sphere>
</group>
);
} }
return null; return null;
})} })}

View File

@ -65,6 +65,7 @@ export const handleSaveTemplate = async ({
widgets3D, widgets3D,
}; };
console.log('newTemplate: ', newTemplate);
// Extract organization from email // Extract organization from email
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
const organization = email.includes("@") const organization = email.includes("@")

View File

@ -56,7 +56,7 @@ const Project: React.FC = () => {
return ( return (
<div className="project-main"> <div className="project-main">
{/* {loadingProgress && <LoadingPage progress={loadingProgress} />} */} {loadingProgress && <LoadingPage progress={loadingProgress} />}
{!isPlaying && ( {!isPlaying && (
<> <>
{toggleThreeD && <ModuleToggle />} {toggleThreeD && <ModuleToggle />}

View File

@ -15,7 +15,7 @@ export const deleteZonesApi = async (userId: string, organization: string, zoneI
} }
const result = await response.json(); const result = await response.json();
console.log('result: ', result);
return result; return result;
} catch (error) { } catch (error) {
if (error instanceof Error) { if (error instanceof Error) {

View File

@ -2,8 +2,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR
// let url_Backend_dwinzo = `http://192.168.0.102:5000`; // let url_Backend_dwinzo = `http://192.168.0.102:5000`;
export const getZoneData = async (zoneId: string, organization: string) => { export const getZoneData = async (zoneId: string, organization: string) => {
console.log("organization: ", organization);
console.log("zoneId: ", zoneId);
try { try {
const response = await fetch( const response = await fetch(
`${url_Backend_dwinzo}/api/v2/A_zone/${zoneId}/${organization}`, `${url_Backend_dwinzo}/api/v2/A_zone/${zoneId}/${organization}`,

View File

@ -347,12 +347,12 @@ export const useSelectedPath = create<any>((set: any) => ({
})); }));
interface SimulationPathsStore { interface SimulationPathsStore {
simulationStates: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]; simulationStates: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[];
setSimulationStates: ( setSimulationStates: (
paths: paths:
| (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[] | (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]
| ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[] | ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]
) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) ) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[])
) => void; ) => void;
} }

View File

@ -70,6 +70,67 @@
position: relative; position: relative;
overflow: auto; overflow: auto;
.template-list {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
min-height: 50vh;
max-height: 60vh;
}
.template-item {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 1rem;
transition: box-shadow 0.3s ease;
}
.template-image-container {
position: relative;
padding-bottom: 56.25%; // 16:9 aspect ratio
}
.template-image {
position: absolute;
width: 100%;
height: 100%;
object-fit: contain;
border-radius: 4px;
cursor: pointer;
transition: transform 0.3s ease;
}
.template-details {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 0.5rem;
}
.template-name {
cursor: pointer;
font-weight: 500;
}
.delete-button {
padding: 0.25rem 0.5rem;
background: #ff4444;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: opacity 0.3s ease;
}
.no-templates {
text-align: center;
color: #666;
padding: 2rem;
grid-column: 1 / -1;
}
.widget-left-sideBar { .widget-left-sideBar {
min-height: 50vh; min-height: 50vh;
max-height: 60vh; max-height: 60vh;

View File

@ -24,9 +24,17 @@
} }
.floating { .floating {
width: 100%;
max-width: 250px;
min-height: 83px; width: calc(var(--realTimeViz-container-width) * 0.2);
height: calc(var(--realTimeViz-container-width) * 0.05);
min-width: 250px;
max-width: 300px;
min-height: 83px !important;
// max-height: 100px !important;
background: var(--background-color); background: var(--background-color);
border: 1.23px solid var(--border-color); border: 1.23px solid var(--border-color);
box-shadow: 0px 4.91px 4.91px 0px #0000001c; box-shadow: 0px 4.91px 4.91px 0px #0000001c;
@ -60,9 +68,8 @@
display: flex; display: flex;
background-color: var(--background-color); background-color: var(--background-color);
position: absolute; position: absolute;
bottom: 10px; // bottom: 10px;
left: 50%; left: 50%;
transform: translate(-50%, 0);
gap: 6px; gap: 6px;
border-radius: 8px; border-radius: 8px;
@ -70,6 +77,7 @@
overflow: auto; overflow: auto;
max-width: calc(100% - 500px); max-width: calc(100% - 500px);
z-index: 3; z-index: 3;
transform: translate(-50%, -100%);
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;
@ -116,8 +124,8 @@
} }
.zone-wrapper.bottom { .zone-wrapper.bottom {
bottom: calc(var(--realTimeViz-container-height) * 0.27); top: var(--bottomWidth);
bottom: 200px; // bottom: 200px;
} }
.content-container { .content-container {
@ -138,7 +146,7 @@
display: flex; display: flex;
background-color: rgba(224, 223, 255, 0.5); background-color: rgba(224, 223, 255, 0.5);
position: absolute; position: absolute;
bottom: 10px; // bottom: 10px;
left: 50%; left: 50%;
transform: translate(-50%, 0); transform: translate(-50%, 0);
gap: 6px; gap: 6px;
@ -203,9 +211,9 @@
.chart-container { .chart-container {
width: 100%; width: 100%;
min-height: 150px;
max-height: 100%; max-height: 100%;
// border: 1px dashed var(--background-color-gray); border: 1px dashed var(--background-color-gray);
border-radius: 8px; border-radius: 8px;
box-shadow: var(--box-shadow-medium); box-shadow: var(--box-shadow-medium);
padding: 6px 0; padding: 6px 0;
@ -306,7 +314,6 @@
min-height: 150px; min-height: 150px;
.chart-container { .chart-container {
min-width: 160px; min-width: 160px;
} }
} }
@ -324,14 +331,12 @@
left: 0; left: 0;
top: 0; top: 0;
bottom: 0; bottom: 0;
} }
&.right-panel { &.right-panel {
right: 0; right: 0;
top: 0; top: 0;
bottom: 0 bottom: 0;
} }
&.left-panel, &.left-panel,
@ -342,12 +347,11 @@
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
gap: 6px; gap: 6px;
.chart-container { .chart-container {
width: 100%; width: 100%;
min-height: 160px; min-height: 150px;
max-height: 100%; max-height: 100%;
border-radius: 8px; border-radius: 8px;
box-shadow: var(--box-shadow-medium); box-shadow: var(--box-shadow-medium);
@ -355,8 +359,6 @@
background-color: var(--background-color); background-color: var(--background-color);
position: relative; position: relative;
} }
} }
} }
} }
@ -368,8 +370,8 @@
.playingFlase { .playingFlase {
.zone-wrapper.bottom { .zone-wrapper.bottom {
bottom: calc(var(--realTimeViz-container-height) * 0.3); top: var(--bottomWidth);
bottom: 210px; // bottom: 210px;
} }
} }
@ -658,9 +660,6 @@
} }
} }
} }
} }
} }
@ -756,14 +755,13 @@
} }
.connectionSuccess { .connectionSuccess {
outline-color: #43C06D; outline-color: #43c06d;
} }
.connectionFails { .connectionFails {
outline-color: #ffe3e0; outline-color: #ffe3e0;
} }
.editWidgetOptions { .editWidgetOptions {
position: absolute; position: absolute;
// top: 50%; // top: 50%;

View File

@ -329,6 +329,7 @@ interface StaticMachineEventsSchema {
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
}; };
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number];
} }
interface ArmBotEventsSchema { interface ArmBotEventsSchema {
@ -343,6 +344,7 @@ interface ArmBotEventsSchema {
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
}; };
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number];
} }
export type EventData = { export type EventData = {

View File

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
interface OuterClickProps { interface OuterClickProps {
contextClassName: string; contextClassName: string[]; // Make sure this is an array of strings
setMenuVisible: React.Dispatch<React.SetStateAction<boolean>>; setMenuVisible: React.Dispatch<React.SetStateAction<boolean>>;
} }
@ -11,8 +11,12 @@ export default function OuterClick({
}: OuterClickProps) { }: OuterClickProps) {
const handleClick = (event: MouseEvent) => { const handleClick = (event: MouseEvent) => {
const targets = event.target as HTMLElement; const targets = event.target as HTMLElement;
// Check if the click is outside the selectable-dropdown-wrapper // Check if the click is outside of any of the provided class names
if (!targets.closest(`.${contextClassName}`)) { const isOutside = contextClassName.every(
(className) => !targets.closest(`.${className}`)
);
if (isOutside) {
setMenuVisible(false); // Close the menu by updating the state setMenuVisible(false); // Close the menu by updating the state
} }
}; };
@ -23,7 +27,7 @@ export default function OuterClick({
return () => { return () => {
document.removeEventListener("click", handleClick); document.removeEventListener("click", handleClick);
}; };
}, []); }, [contextClassName]); // Add contextClassName to dependency array to handle any changes
return null; // This component doesn't render anything return null; // This component doesn't render anything
} }