Merge pull request 'simulation' (#50) from simulation into main
Reviewed-on: http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev/pulls/50
This commit is contained in:
commit
daa507e464
|
@ -22,6 +22,8 @@ import GlobalProperties from "./properties/GlobalProperties";
|
|||
import AsstePropertiies from "./properties/AssetProperties";
|
||||
import ZoneProperties from "./properties/ZoneProperties";
|
||||
import VehicleMechanics from "./mechanics/VehicleMechanics";
|
||||
import StaticMachineMechanics from "./mechanics/StaticMachineMechanics";
|
||||
import ArmBotMechanics from "./mechanics/ArmBotMechanics";
|
||||
|
||||
const SideBarRight: React.FC = () => {
|
||||
const { activeModule } = useModuleStore();
|
||||
|
@ -42,9 +44,8 @@ const SideBarRight: React.FC = () => {
|
|||
<div className="sidebar-actions-container">
|
||||
{/* {activeModule === "builder" && ( */}
|
||||
<div
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "properties" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("properties")}
|
||||
>
|
||||
<PropertiesIcon isActive={subModule === "properties"} />
|
||||
|
@ -53,25 +54,22 @@ const SideBarRight: React.FC = () => {
|
|||
{activeModule === "simulation" && (
|
||||
<>
|
||||
<div
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("mechanics")}
|
||||
>
|
||||
<MechanicsIcon isActive={subModule === "mechanics"} />
|
||||
</div>
|
||||
<div
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "simulations" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("simulations")}
|
||||
>
|
||||
<SimulationIcon isActive={subModule === "simulations"} />
|
||||
</div>
|
||||
<div
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "analysis" ? "active" : ""
|
||||
}`}
|
||||
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSubModule("analysis")}
|
||||
>
|
||||
<AnalysisIcon isActive={subModule === "analysis"} />
|
||||
|
@ -132,10 +130,28 @@ const SideBarRight: React.FC = () => {
|
|||
</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 && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<ConveyorMechanics />
|
||||
<ConveyorMechanics /> {/* default */}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -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);
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
|
@ -28,9 +28,12 @@ const ZoneProperties: React.FC = () => {
|
|||
};
|
||||
|
||||
let response = await zoneCameraUpdate(zonesdata, organization);
|
||||
console.log('response: ', response);
|
||||
if (response.message === "updated successfully") {
|
||||
setEdit(false);
|
||||
} else {
|
||||
console.log("Not updated Camera Position and Target");
|
||||
}
|
||||
|
||||
setEdit(false);
|
||||
} catch (error) {
|
||||
console.error("Error in handleSetView:", error);
|
||||
}
|
||||
|
|
|
@ -42,16 +42,19 @@ const Design = () => {
|
|||
const [elementColor, setElementColor] = useState("#6f42c1");
|
||||
const [showColorPicker, setShowColorPicker] = useState(false);
|
||||
const [chartElements, setChartElements] = useState<ChartElement[]>([]);
|
||||
const [selectedElementToStyle, setSelectedElementToStyle] = useState<string | null>(null);
|
||||
const [selectedElementToStyle, setSelectedElementToStyle] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const [nameInput, setNameInput] = useState("");
|
||||
const chartRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { selectedChartId, setSelectedChartId, widgets, setWidgets } = useWidgetStore();
|
||||
const { selectedChartId, setSelectedChartId, widgets, setWidgets } =
|
||||
useWidgetStore();
|
||||
|
||||
// Initialize name input and extract elements when selectedChartId changes
|
||||
useEffect(() => {
|
||||
setNameInput(selectedChartId?.header || selectedChartId?.title || "");
|
||||
|
||||
|
||||
if (!chartRef.current) return;
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
|
@ -65,13 +68,16 @@ const Design = () => {
|
|||
})
|
||||
.map((el, index) => {
|
||||
const tagName = el.tagName.toLowerCase();
|
||||
const className = typeof el.className === "string" ? el.className : "";
|
||||
const className =
|
||||
typeof el.className === "string" ? el.className : "";
|
||||
const textContent = el.textContent?.trim() || "";
|
||||
|
||||
let selector = tagName;
|
||||
|
||||
if (className && typeof className === "string") {
|
||||
const classList = className.split(/\s+/).filter((c) => c.length > 0);
|
||||
const classList = className
|
||||
.split(/\s+/)
|
||||
.filter((c) => c.length > 0);
|
||||
if (classList.length > 0) {
|
||||
selector += "." + classList.join(".");
|
||||
}
|
||||
|
@ -126,7 +132,13 @@ const Design = () => {
|
|||
|
||||
useEffect(() => {
|
||||
applyStyles();
|
||||
}, [selectedFont, selectedSize, selectedWeight, elementColor, selectedElementToStyle]);
|
||||
}, [
|
||||
selectedFont,
|
||||
selectedSize,
|
||||
selectedWeight,
|
||||
elementColor,
|
||||
selectedElementToStyle,
|
||||
]);
|
||||
|
||||
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
|
||||
if (!selectedChartId) return;
|
||||
|
@ -138,7 +150,9 @@ const Design = () => {
|
|||
setSelectedChartId(updatedChartId);
|
||||
|
||||
const updatedWidgets = widgets.map((widget) =>
|
||||
widget.id === selectedChartId.id ? { ...widget, ...updatedProperties } : widget
|
||||
widget.id === selectedChartId.id
|
||||
? { ...widget, ...updatedProperties }
|
||||
: widget
|
||||
);
|
||||
setWidgets(updatedWidgets);
|
||||
};
|
||||
|
@ -146,7 +160,7 @@ const Design = () => {
|
|||
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newName = e.target.value;
|
||||
setNameInput(newName);
|
||||
|
||||
|
||||
if (selectedChartId?.title) {
|
||||
handleUpdateWidget({ title: newName });
|
||||
} else if (selectedChartId?.header) {
|
||||
|
@ -155,12 +169,12 @@ const Design = () => {
|
|||
};
|
||||
|
||||
const defaultChartData = {
|
||||
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [
|
||||
{
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
backgroundColor: elementColor,
|
||||
borderColor: "#ffffff",
|
||||
backgroundColor: "#6f42c1",
|
||||
borderColor: "#b392f0",
|
||||
borderWidth: 1,
|
||||
},
|
||||
],
|
||||
|
@ -311,4 +325,4 @@ const Design = () => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Design;
|
||||
export default Design;
|
||||
|
|
|
@ -59,13 +59,14 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
setHiddenPanels,
|
||||
hiddenPanels,
|
||||
}) => {
|
||||
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
|
||||
// Local state to track hidden panels
|
||||
|
||||
// Function to toggle lock/unlock a panel
|
||||
const toggleLockPanel = (side: Side) => {
|
||||
console.log('side: ', side);
|
||||
//add api
|
||||
const newLockedPanels = selectedZone.lockedPanels.includes(side)
|
||||
? selectedZone.lockedPanels.filter((panel) => panel !== side)
|
||||
: [...selectedZone.lockedPanels, side];
|
||||
|
@ -93,6 +94,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
|
||||
// Function to clean all widgets from a panel
|
||||
const cleanPanel = (side: Side) => {
|
||||
//add api
|
||||
console.log('side: ', side);
|
||||
const cleanedWidgets = selectedZone.widgets.filter(
|
||||
(widget) => widget.panel !== side
|
||||
);
|
||||
|
@ -101,7 +104,6 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
...selectedZone,
|
||||
widgets: cleanedWidgets,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
};
|
||||
|
@ -129,25 +131,27 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
let deletePanel = {
|
||||
organization: organization,
|
||||
panelName: side,
|
||||
zoneId: selectedZone.zoneId
|
||||
}
|
||||
zoneId: selectedZone.zoneId,
|
||||
};
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-panel:delete", deletePanel)
|
||||
visualizationSocket.emit("v2:viz-panel:delete", deletePanel);
|
||||
}
|
||||
setSelectedZone(updatedZone);
|
||||
|
||||
// API call to delete the panel
|
||||
// try {
|
||||
// const response = await deletePanelApi(selectedZone.zoneId, side, organization);
|
||||
//
|
||||
//
|
||||
// if (response.message === "Panel deleted successfully") {
|
||||
// } else {
|
||||
//
|
||||
//
|
||||
// }
|
||||
// } catch (error) {
|
||||
//
|
||||
//
|
||||
// }
|
||||
} else {
|
||||
setHiddenPanels(hiddenPanels.filter((panel) => panel !== side));
|
||||
|
||||
// Panel does not exist: Create panel
|
||||
try {
|
||||
// Get email and organization safely with a default fallback
|
||||
|
@ -167,27 +171,24 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
let addPanel = {
|
||||
organization: organization,
|
||||
zoneId: selectedZone.zoneId,
|
||||
panelOrder: newActiveSides
|
||||
}
|
||||
panelOrder: newActiveSides,
|
||||
};
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-panel:add", addPanel)
|
||||
visualizationSocket.emit("v2:viz-panel:add", addPanel);
|
||||
}
|
||||
setSelectedZone(updatedZone);
|
||||
// API call to create panels
|
||||
// const response = await panelData(organization, selectedZone.zoneId, newActiveSides);
|
||||
//
|
||||
//
|
||||
|
||||
// if (response.message === "Panels created successfully") {
|
||||
// } else {
|
||||
//
|
||||
//
|
||||
// }
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
|
@ -195,8 +196,9 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
<div key={side} className={`side-button-container ${side}`}>
|
||||
{/* "+" Button */}
|
||||
<button
|
||||
className={`side-button ${side}${selectedZone.activeSides.includes(side) ? " active" : ""
|
||||
}`}
|
||||
className={`side-button ${side}${
|
||||
selectedZone.activeSides.includes(side) ? " active" : ""
|
||||
}`}
|
||||
onClick={() => handlePlusButtonClick(side)}
|
||||
title={
|
||||
selectedZone.activeSides.includes(side)
|
||||
|
@ -214,15 +216,20 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
<div className="extra-Bs">
|
||||
{/* Hide Panel */}
|
||||
<div
|
||||
className={`icon ${hiddenPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
className={`icon ${
|
||||
hiddenPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
|
||||
}
|
||||
onClick={() => toggleVisibility(side)}
|
||||
>
|
||||
<EyeIcon
|
||||
fill={hiddenPanels.includes(side) ? "var(--primary-color)" : "var(--text-color)"}
|
||||
fill={
|
||||
hiddenPanels.includes(side)
|
||||
? "var(--primary-color)"
|
||||
: "var(--text-color)"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -237,8 +244,9 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
|
||||
{/* Lock/Unlock Panel */}
|
||||
<div
|
||||
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
className={`icon ${
|
||||
selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
selectedZone.lockedPanels.includes(side)
|
||||
? "Unlock Panel"
|
||||
|
|
|
@ -96,16 +96,16 @@ export const DraggableWidget = ({
|
|||
let deleteWidget = {
|
||||
zoneId: selectedZone.zoneId,
|
||||
widgetID: widget.id,
|
||||
organization: organization
|
||||
}
|
||||
console.log('deleteWidget: ', deleteWidget);
|
||||
organization: organization,
|
||||
};
|
||||
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-widget:delete", deleteWidget)
|
||||
visualizationSocket.emit("v2:viz-widget:delete", deleteWidget);
|
||||
}
|
||||
const updatedWidgets = selectedZone.widgets.filter(
|
||||
(w: Widget) => w.id !== widget.id
|
||||
);
|
||||
console.log('updatedWidgets: ', updatedWidgets);
|
||||
|
||||
setSelectedZone((prevZone: any) => ({
|
||||
...prevZone,
|
||||
widgets: updatedWidgets,
|
||||
|
@ -168,10 +168,10 @@ export const DraggableWidget = ({
|
|||
let duplicateWidget = {
|
||||
organization: organization,
|
||||
zoneId: selectedZone.zoneId,
|
||||
widget: duplicatedWidget
|
||||
}
|
||||
widget: duplicatedWidget,
|
||||
};
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-widget:add", duplicateWidget)
|
||||
visualizationSocket.emit("v2:viz-widget:add", duplicateWidget);
|
||||
}
|
||||
setSelectedZone((prevZone: any) => ({
|
||||
...prevZone,
|
||||
|
@ -245,21 +245,64 @@ export const DraggableWidget = ({
|
|||
// });
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
||||
|
||||
const [canvasDimensions, setCanvasDimensions] = useState({
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
// Track canvas dimensions
|
||||
|
||||
|
||||
|
||||
// Current: Two identical useEffect hooks for canvas dimensions
|
||||
// Remove the duplicate and keep only one
|
||||
useEffect(() => {
|
||||
const canvas = document.getElementById("real-time-vis-canvas");
|
||||
if (!canvas) return;
|
||||
|
||||
const updateCanvasDimensions = () => {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
setCanvasDimensions({
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
});
|
||||
};
|
||||
|
||||
updateCanvasDimensions();
|
||||
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
|
||||
resizeObserver.observe(canvas);
|
||||
|
||||
return () => resizeObserver.unobserve(canvas);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>
|
||||
{`
|
||||
:root {
|
||||
--realTimeViz-container-width: ${canvasDimensions.width * 0.25}px;
|
||||
--realTimeViz-container-height: ${canvasDimensions.height}px;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
<div
|
||||
draggable
|
||||
key={widget.id}
|
||||
className={`chart-container ${(selectedChartId?.id === widget.id) && !isPlaying && "activeChart"
|
||||
}`}
|
||||
className={`chart-container ${
|
||||
selectedChartId?.id === widget.id && !isPlaying && "activeChart"
|
||||
}`}
|
||||
onPointerDown={handlePointerDown}
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragOver={handleDragOver}
|
||||
onDrop={handleDrop}
|
||||
style={{
|
||||
pointerEvents: isPanelHidden ? "none" : "auto",
|
||||
// Apply styles based on panel position
|
||||
width: ["top", "bottom"].includes(widget.panel)
|
||||
? `calc(${canvasDimensions.width * 0.16}px - 2px)` // For top/bottom panels, set width
|
||||
: undefined, // Don't set width if it's left or right
|
||||
height: ["left", "right"].includes(widget.panel)
|
||||
? `calc(${canvasDimensions.height * 0.25}px - 2px)` // For left/right panels, set height
|
||||
: undefined, // Don't set height if it's top or bottom
|
||||
}}
|
||||
ref={chartWidget}
|
||||
onClick={() => setSelectedChartId(widget)}
|
||||
|
@ -273,8 +316,9 @@ export const DraggableWidget = ({
|
|||
{openKebabId === widget.id && (
|
||||
<div className="kebab-options" ref={widgetRef}>
|
||||
<div
|
||||
className={`edit btn ${isPanelFull(widget.panel) ? "btn-blur" : ""
|
||||
}`}
|
||||
className={`edit btn ${
|
||||
isPanelFull(widget.panel) ? "btn-blur" : ""
|
||||
}`}
|
||||
onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget}
|
||||
>
|
||||
<div className="icon">
|
||||
|
@ -348,3 +392,5 @@ export const DraggableWidget = ({
|
|||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// while resize calculate --realTimeViz-container-height pprperly
|
|
@ -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 verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move
|
||||
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 mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||
|
||||
|
@ -60,7 +58,7 @@ export default function Dropped3dWidgets() {
|
|||
|
||||
async function get3dWidgetData() {
|
||||
const result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
|
||||
console.log('result: ', result);
|
||||
|
||||
setWidgets3D(result);
|
||||
|
||||
const formattedWidgets = result.map((widget: WidgetData) => ({
|
||||
|
@ -84,8 +82,31 @@ export default function Dropped3dWidgets() {
|
|||
|
||||
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) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
canvasElement.style.cursor = ""; // Reset cursor
|
||||
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
@ -93,6 +114,12 @@ export default function Dropped3dWidgets() {
|
|||
const group1 = scene.getObjectByName("itemsGroup");
|
||||
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(
|
||||
(intersect) =>
|
||||
!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);
|
||||
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] || [];
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -161,7 +197,7 @@ export default function Dropped3dWidgets() {
|
|||
visualizationSocket.emit("v2:viz-3D-widget:add", adding3dWidget);
|
||||
}
|
||||
// let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget)
|
||||
// console.log('response: ', response);
|
||||
//
|
||||
|
||||
addWidget(selectedZone.zoneId, newWidget);
|
||||
setRightSelect(null);
|
||||
|
@ -179,7 +215,7 @@ export default function Dropped3dWidgets() {
|
|||
zoneId: selectedZone.zoneId,
|
||||
};
|
||||
|
||||
console.log('deleteWidget: ', deleteWidget);
|
||||
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget);
|
||||
}
|
||||
|
@ -190,7 +226,7 @@ export default function Dropped3dWidgets() {
|
|||
activeZoneWidgets.filter((w: WidgetData) => w.id !== rightClickSelected)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error deleting widget:", error);
|
||||
|
||||
} finally {
|
||||
setRightClickSelected(null);
|
||||
setRightSelect(null);
|
||||
|
@ -304,20 +340,15 @@ export default function Dropped3dWidgets() {
|
|||
|
||||
const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected);
|
||||
if (!selectedWidget) return;
|
||||
|
||||
|
||||
|
||||
// Format values to 2 decimal places
|
||||
const formatValues = (vals: number[]) => vals.map(val => parseFloat(val.toFixed(2)));
|
||||
|
||||
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];
|
||||
// (async () => {
|
||||
// let response = await update3dWidget(selectedZone, organization, rightClickSelected, lastPosition);
|
||||
// console.log('response: ', response);
|
||||
//
|
||||
// if (response) {
|
||||
// console.log("Widget position updated in API:", response);
|
||||
//
|
||||
// }
|
||||
// })();
|
||||
let updatingPosition = {
|
||||
|
@ -333,13 +364,13 @@ export default function Dropped3dWidgets() {
|
|||
}
|
||||
else if (rightSelect.includes("Rotate")) {
|
||||
const rotation = selectedWidget.rotation || [0, 0, 0];
|
||||
console.log(`${rightSelect} Completed - Full Rotation:`, formatValues(rotation));
|
||||
|
||||
let lastRotation = formatValues(rotation) as [number, number, number];
|
||||
// (async () => {
|
||||
// let response = await update3dWidgetRotation(selectedZone, organization, rightClickSelected, lastRotation);
|
||||
// console.log('response: ', response);
|
||||
//
|
||||
// if (response) {
|
||||
// console.log("Widget position updated in API:", response);
|
||||
//
|
||||
// }
|
||||
// })();
|
||||
let updatingRotation = {
|
||||
|
@ -388,49 +419,13 @@ export default function Dropped3dWidgets() {
|
|||
|
||||
switch (type) {
|
||||
case "ui-Widget 1":
|
||||
return (
|
||||
<ProductionCapacity
|
||||
key={id}
|
||||
id={id}
|
||||
type={type}
|
||||
position={position}
|
||||
rotation={rotation}
|
||||
onContextMenu={(e) => handleRightClick(e, id)}
|
||||
/>
|
||||
);
|
||||
return (<ProductionCapacity key={id} id={id} type={type} position={position} rotation={rotation} onContextMenu={(e) => handleRightClick(e, id)} />);
|
||||
case "ui-Widget 2":
|
||||
return (
|
||||
<ReturnOfInvestment
|
||||
key={id}
|
||||
id={id}
|
||||
type={type}
|
||||
position={position}
|
||||
rotation={rotation}
|
||||
onContextMenu={(e) => handleRightClick(e, id)}
|
||||
/>
|
||||
);
|
||||
return (<ReturnOfInvestment key={id} id={id} type={type} position={position} rotation={rotation} onContextMenu={(e) => handleRightClick(e, id)} />);
|
||||
case "ui-Widget 3":
|
||||
return (
|
||||
<StateWorking
|
||||
key={id}
|
||||
id={id}
|
||||
type={type}
|
||||
position={position}
|
||||
rotation={rotation}
|
||||
onContextMenu={(e) => handleRightClick(e, id)}
|
||||
/>
|
||||
);
|
||||
return (<StateWorking key={id} id={id} type={type} position={position} rotation={rotation} onContextMenu={(e) => handleRightClick(e, id)} />);
|
||||
case "ui-Widget 4":
|
||||
return (
|
||||
<Throughput
|
||||
key={id}
|
||||
id={id}
|
||||
type={type}
|
||||
position={position}
|
||||
rotation={rotation}
|
||||
onContextMenu={(e) => handleRightClick(e, id)}
|
||||
/>
|
||||
);
|
||||
return (<Throughput key={id} id={id} type={type} position={position} rotation={rotation} onContextMenu={(e) => handleRightClick(e, id)} />);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ const DroppedObjects: React.FC = () => {
|
|||
);
|
||||
const [offset, setOffset] = useState<[number, number] | null>(null);
|
||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||
|
||||
const [activeEdges, setActiveEdges] = useState<{
|
||||
vertical: "top" | "bottom";
|
||||
horizontal: "left" | "right";
|
||||
|
@ -84,7 +85,6 @@ const DroppedObjects: React.FC = () => {
|
|||
// });
|
||||
const kebabRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
||||
// Clean up animation frame on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
@ -95,7 +95,10 @@ const DroppedObjects: React.FC = () => {
|
|||
}, []);
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (kebabRef.current && !kebabRef.current.contains(event.target as Node)) {
|
||||
if (
|
||||
kebabRef.current &&
|
||||
!kebabRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setOpenKebabId(null);
|
||||
}
|
||||
};
|
||||
|
@ -113,7 +116,6 @@ const DroppedObjects: React.FC = () => {
|
|||
if (zoneEntries.length === 0) return null;
|
||||
const [zoneName, zone] = zoneEntries[0];
|
||||
|
||||
|
||||
function handleDuplicate(zoneName: string, index: number) {
|
||||
setOpenKebabId(null);
|
||||
duplicateObject(zoneName, index); // Call the duplicateObject method from the store
|
||||
|
@ -132,7 +134,7 @@ const DroppedObjects: React.FC = () => {
|
|||
}
|
||||
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget)
|
||||
visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget);
|
||||
}
|
||||
deleteObject(zoneName, id);
|
||||
|
||||
|
@ -148,7 +150,10 @@ const DroppedObjects: React.FC = () => {
|
|||
}
|
||||
|
||||
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
||||
if ((event.target as HTMLElement).closest(".kebab-options") || (event.target as HTMLElement).closest(".kebab")) {
|
||||
if (
|
||||
(event.target as HTMLElement).closest(".kebab-options") ||
|
||||
(event.target as HTMLElement).closest(".kebab")
|
||||
) {
|
||||
return; // Prevent dragging when clicking on the kebab menu or its options
|
||||
}
|
||||
const obj = zone.objects[index];
|
||||
|
@ -449,7 +454,6 @@ const DroppedObjects: React.FC = () => {
|
|||
// position: boundedPosition,
|
||||
// });
|
||||
|
||||
|
||||
let updateFloatingWidget = {
|
||||
organization: organization,
|
||||
widget: {
|
||||
|
@ -460,7 +464,7 @@ const DroppedObjects: React.FC = () => {
|
|||
zoneId: zone.zoneId
|
||||
}
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget)
|
||||
visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget);
|
||||
}
|
||||
|
||||
// if (response.message === "Widget updated successfully") {
|
||||
|
@ -479,7 +483,6 @@ const DroppedObjects: React.FC = () => {
|
|||
// animationRef.current = null;
|
||||
// }
|
||||
} catch (error) {
|
||||
|
||||
} finally {
|
||||
// Clean up regardless of success or failure
|
||||
setDraggingIndex(null);
|
||||
|
@ -565,26 +568,32 @@ const DroppedObjects: React.FC = () => {
|
|||
ref={kebabRef}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleKebabClick(obj.id, event)
|
||||
handleKebabClick(obj.id, event);
|
||||
}}
|
||||
>
|
||||
<KebabIcon />
|
||||
</div>
|
||||
{openKebabId === obj.id && (
|
||||
<div className="kebab-options" ref={kebabRef}>
|
||||
<div className="dublicate btn" onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleDuplicate(zoneName, index); // Call the duplicate handler
|
||||
}}>
|
||||
<div
|
||||
className="dublicate btn"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleDuplicate(zoneName, index); // Call the duplicate handler
|
||||
}}
|
||||
>
|
||||
<div className="icon">
|
||||
<DublicateIcon />
|
||||
</div>
|
||||
<div className="label">Duplicate</div>
|
||||
</div>
|
||||
<div className="edit btn" onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleDelete(zoneName, obj.id); // Call the delete handler
|
||||
}}>
|
||||
<div
|
||||
className="edit btn"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleDelete(zoneName, obj.id); // Call the delete handler
|
||||
}}
|
||||
>
|
||||
<div className="icon">
|
||||
<DeleteIcon />
|
||||
</div>
|
||||
|
@ -592,7 +601,6 @@ const DroppedObjects: React.FC = () => {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
))}
|
||||
|
||||
|
@ -630,5 +638,3 @@ const DroppedObjects: React.FC = () => {
|
|||
};
|
||||
|
||||
export default DroppedObjects;
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ interface PanelProps {
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -64,6 +63,59 @@ const Panel: React.FC<PanelProps> = ({
|
|||
const { isPlaying } = usePlayButtonStore();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
|
||||
const [canvasDimensions, setCanvasDimensions] = useState({
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
// Track canvas dimensions
|
||||
useEffect(() => {
|
||||
const canvas = document.getElementById("real-time-vis-canvas");
|
||||
if (!canvas) return;
|
||||
|
||||
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);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = document.getElementById("real-time-vis-canvas");
|
||||
if (!canvas) return;
|
||||
|
||||
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);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const getPanelStyle = useMemo(
|
||||
() => (side: Side) => {
|
||||
const currentIndex = selectedZone.panelOrder.indexOf(side);
|
||||
|
@ -72,36 +124,50 @@ const Panel: React.FC<PanelProps> = ({
|
|||
const rightActive = previousPanels.includes("right");
|
||||
const topActive = previousPanels.includes("top");
|
||||
const bottomActive = previousPanels.includes("bottom");
|
||||
const panelSize = isPlaying ? 300 : 210;
|
||||
|
||||
// Dynamic panel sizes based on canvas width
|
||||
const panelSizeWidth = isPlaying ? Math.max(canvasDimensions.width * 0.14, 200) : Math.max(canvasDimensions.width * 0.165, 200); // Ensure minimum width of 200px
|
||||
const panelSizeHeight = isPlaying ? Math.max(canvasDimensions.width * 0.13, 200) : Math.max(canvasDimensions.width * 0.13, 200); // Ensure minimum height of 200px
|
||||
|
||||
switch (side) {
|
||||
case "top":
|
||||
case "bottom":
|
||||
return {
|
||||
width: `calc(100% - ${
|
||||
(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
|
||||
}px)`,
|
||||
height: `${panelSize - 2}px`,
|
||||
left: leftActive ? `${panelSize}px` : "0",
|
||||
right: rightActive ? `${panelSize}px` : "0",
|
||||
// minWidth: "200px", // Minimum width constraint
|
||||
width: `calc(100% - ${(leftActive ? panelSizeWidth : 0) +
|
||||
(rightActive ? panelSizeWidth : 0)
|
||||
}px)`,
|
||||
minHeight: "200px", // Minimum height constraint
|
||||
height: `${panelSizeHeight - 2}px`, // Subtracting for border or margin
|
||||
left: leftActive ? `${panelSizeWidth}px` : "0",
|
||||
right: rightActive ? `${panelSizeWidth}px` : "0",
|
||||
[side]: "0",
|
||||
};
|
||||
|
||||
case "left":
|
||||
case "right":
|
||||
return {
|
||||
width: `${panelSize - 2}px`,
|
||||
height: `calc(100% - ${
|
||||
(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
|
||||
}px)`,
|
||||
top: topActive ? `${panelSize}px` : "0",
|
||||
bottom: bottomActive ? `${panelSize}px` : "0",
|
||||
minWidth: "200px", // Minimum width constraint
|
||||
width: `${panelSizeWidth - 2}px`, // Subtracting for border or margin
|
||||
// minHeight: "200px", // Minimum height constraint
|
||||
height: `calc(100% - ${(topActive ? panelSizeHeight : 0) +
|
||||
(bottomActive ? panelSizeHeight : 0)
|
||||
}px)`,
|
||||
top: topActive ? `${panelSizeHeight}px` : "0",
|
||||
bottom: bottomActive ? `${panelSizeHeight}px` : "0",
|
||||
[side]: "0",
|
||||
};
|
||||
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
},
|
||||
[selectedZone.panelOrder, isPlaying]
|
||||
[
|
||||
selectedZone.panelOrder,
|
||||
isPlaying,
|
||||
canvasDimensions.width,
|
||||
canvasDimensions.height,
|
||||
]
|
||||
);
|
||||
|
||||
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
||||
|
@ -153,10 +219,10 @@ const Panel: React.FC<PanelProps> = ({
|
|||
let addWidget = {
|
||||
organization: organization,
|
||||
zoneId: selectedZone.zoneId,
|
||||
widget: newWidget
|
||||
}
|
||||
widget: newWidget,
|
||||
};
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-widget:add", addWidget)
|
||||
visualizationSocket.emit("v2:viz-widget:add", addWidget);
|
||||
}
|
||||
setSelectedZone((prev) => ({
|
||||
...prev,
|
||||
|
@ -165,7 +231,6 @@ const Panel: React.FC<PanelProps> = ({
|
|||
|
||||
try {
|
||||
// let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
|
||||
|
||||
// if (response.message === "Widget created successfully") {
|
||||
// setSelectedZone((prev) => ({
|
||||
// ...prev,
|
||||
|
@ -175,7 +240,6 @@ const Panel: React.FC<PanelProps> = ({
|
|||
} catch (error) {
|
||||
console.error("Error adding widget:", error);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -233,9 +297,8 @@ const Panel: React.FC<PanelProps> = ({
|
|||
{selectedZone.activeSides.map((side) => (
|
||||
<div
|
||||
key={side}
|
||||
className={`panel ${side}-panel absolute ${isPlaying ? "" : ""} ${
|
||||
hiddenPanels.includes(side) ? "hidePanel" : ""
|
||||
}`}
|
||||
className={`panel ${side}-panel absolute ${isPlaying ? "" : ""} ${hiddenPanels.includes(side) ? "hidePanel" : ""
|
||||
}`}
|
||||
style={getPanelStyle(side)}
|
||||
onDrop={(e) => handleDrop(e, side)}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
|
@ -281,3 +344,5 @@ const Panel: React.FC<PanelProps> = ({
|
|||
};
|
||||
|
||||
export default Panel;
|
||||
|
||||
// canvasDimensions.width as percent
|
||||
|
|
|
@ -23,8 +23,11 @@ import RenderOverlay from "../../templates/Overlay";
|
|||
import ConfirmationPopup from "../../layout/confirmationPopup/ConfirmationPopup";
|
||||
import DroppedObjects from "./DroppedFloatingWidgets";
|
||||
import EditWidgetOption from "../menu/EditWidgetOption";
|
||||
import { useEditWidgetOptionsStore, useRightClickSelected, useRightSelected } from "../../../store/useZone3DWidgetStore";
|
||||
|
||||
import {
|
||||
useEditWidgetOptionsStore,
|
||||
useRightClickSelected,
|
||||
useRightSelected,
|
||||
} from "../../../store/useZone3DWidgetStore";
|
||||
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
|
@ -58,15 +61,13 @@ const RealTimeVisulization: React.FC = () => {
|
|||
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
|
||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||
|
||||
|
||||
const { rightSelect, setRightSelect } = useRightSelected()
|
||||
const { editWidgetOptions, setEditWidgetOptions } = useEditWidgetOptionsStore()
|
||||
const { rightClickSelected, setRightClickSelected } = useRightClickSelected()
|
||||
const { rightSelect, setRightSelect } = useRightSelected();
|
||||
const { editWidgetOptions, setEditWidgetOptions } =
|
||||
useEditWidgetOptionsStore();
|
||||
const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
|
||||
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
|
||||
|
||||
const [floatingWidgets, setFloatingWidgets] = useState<
|
||||
Record<string, { zoneName: string; zoneId: string; objects: any[] }>
|
||||
>({});
|
||||
const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({});
|
||||
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
|
@ -78,7 +79,6 @@ const RealTimeVisulization: React.FC = () => {
|
|||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
try {
|
||||
const response = await getZone2dData(organization);
|
||||
// console.log('response: ', response);
|
||||
|
||||
if (!Array.isArray(response)) {
|
||||
return;
|
||||
|
@ -241,84 +241,90 @@ const RealTimeVisulization: React.FC = () => {
|
|||
}, [setRightClickSelected]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
id="real-time-vis-canvas"
|
||||
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
|
||||
style={{
|
||||
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
|
||||
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
||||
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
||||
}}
|
||||
>
|
||||
{openConfirmationPopup && (
|
||||
<RenderOverlay>
|
||||
<ConfirmationPopup
|
||||
message={"Are you sure want to delete?"}
|
||||
onConfirm={() => console.log("confirm")}
|
||||
onCancel={() => setOpenConfirmationPopup(false)}
|
||||
/>
|
||||
</RenderOverlay>
|
||||
)}
|
||||
<>
|
||||
|
||||
|
||||
<div
|
||||
className="scene-container"
|
||||
ref={containerRef}
|
||||
id="real-time-vis-canvas"
|
||||
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
|
||||
style={{
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
borderRadius:
|
||||
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
||||
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
|
||||
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
||||
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
||||
}}
|
||||
onDrop={(event) => handleDrop(event)}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
>
|
||||
<Scene />
|
||||
</div>
|
||||
{activeModule === "visualization" && selectedZone.zoneName !== "" && (
|
||||
<DroppedObjects />
|
||||
)}
|
||||
{activeModule === "visualization" && <SocketRealTimeViz />}
|
||||
|
||||
{activeModule === "visualization" &&
|
||||
editWidgetOptions &&
|
||||
rightClickSelected && (
|
||||
<EditWidgetOption
|
||||
options={[
|
||||
"Duplicate",
|
||||
"Vertical Move",
|
||||
"Horizontal Move",
|
||||
"RotateX",
|
||||
"RotateY",
|
||||
"Delete",
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
{activeModule === "visualization" && (
|
||||
<>
|
||||
<DisplayZone
|
||||
zonesData={zonesData}
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
/>
|
||||
|
||||
{!isPlaying && selectedZone?.zoneName !== "" && (
|
||||
<AddButtons
|
||||
hiddenPanels={hiddenPanels}
|
||||
setHiddenPanels={setHiddenPanels}
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
/>
|
||||
<div className="realTime-viz-wrapper">
|
||||
{openConfirmationPopup && (
|
||||
<RenderOverlay>
|
||||
<ConfirmationPopup
|
||||
message={"Are you sure want to delete?"}
|
||||
onConfirm={() => console.log("confirm")}
|
||||
onCancel={() => setOpenConfirmationPopup(false)}
|
||||
/>
|
||||
</RenderOverlay>
|
||||
)}
|
||||
<div
|
||||
className="scene-container"
|
||||
style={{
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
borderRadius:
|
||||
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
||||
}}
|
||||
onDrop={(event) => handleDrop(event)}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
>
|
||||
<Scene />
|
||||
</div>
|
||||
{activeModule === "visualization" && selectedZone.zoneName !== "" && (
|
||||
<DroppedObjects />
|
||||
)}
|
||||
{activeModule === "visualization" && <SocketRealTimeViz />}
|
||||
|
||||
<Panel
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
hiddenPanels={hiddenPanels}
|
||||
setZonesData={setZonesData}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{activeModule === "visualization" &&
|
||||
editWidgetOptions &&
|
||||
rightClickSelected && (
|
||||
<EditWidgetOption
|
||||
options={[
|
||||
"Duplicate",
|
||||
"Vertical Move",
|
||||
"Horizontal Move",
|
||||
"RotateX",
|
||||
"RotateY",
|
||||
"Delete",
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
{activeModule === "visualization" && (
|
||||
<>
|
||||
<DisplayZone
|
||||
zonesData={zonesData}
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
/>
|
||||
|
||||
{!isPlaying && selectedZone?.zoneName !== "" && (
|
||||
<AddButtons
|
||||
hiddenPanels={hiddenPanels}
|
||||
setHiddenPanels={setHiddenPanels}
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Panel
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
hiddenPanels={hiddenPanels}
|
||||
setZonesData={setZonesData}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -47,80 +47,83 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
|||
const [zoneDataList, setZoneDataList] = useState<
|
||||
{ id: string; name: string; assets: Asset[] }[]
|
||||
>([]);
|
||||
const [zonePoints3D, setZonePoints3D] = useState<[]>([]);
|
||||
|
||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||
|
||||
useEffect(() => {
|
||||
// console.log(zones);
|
||||
// setZoneDataList([
|
||||
// { id: "2e996073-546c-470c-8323-55bd3700c6aa", name: "zone1" },
|
||||
// { id: "3f473bf0-197c-471c-a71f-943fc9ca2b47", name: "zone2" },
|
||||
// { id: "905e8fb6-9e18-469b-9474-e0478fb9601b", name: "zone3" },
|
||||
// { id: "9d9efcbe-8e96-47eb-bfad-128a9e4c532e", name: "zone4" },
|
||||
// { id: "884f3d29-eb5a-49a5-abe9-d11971c08e85", name: "zone5" },
|
||||
// { id: "70fa55cd-b5c9-4f80-a8c4-6319af3bfb4e", name: "zone6" },
|
||||
// ])
|
||||
// const value = (zones || []).map(
|
||||
// (val: { zoneId: string; zoneName: string }) => ({
|
||||
// id: val.zoneId,
|
||||
// name: val.zoneName,
|
||||
// })
|
||||
// );
|
||||
// console.log('zones: ', zones);
|
||||
const value = (zones || []).map((val: { zoneId: string; zoneName: string }) => ({
|
||||
id: val.zoneId,
|
||||
name: val.zoneName
|
||||
}));
|
||||
setZoneDataList(prev => (JSON.stringify(prev) !== JSON.stringify(value) ? value : prev));
|
||||
const allPoints = zones.flatMap((zone: any) => zone.points);
|
||||
setZonePoints3D(allPoints);
|
||||
// setZoneDataList([
|
||||
// {
|
||||
// id: "zone1",
|
||||
// name: "Zone 1",
|
||||
// assets: [
|
||||
// {
|
||||
// id: "asset1",
|
||||
// name: "Asset 1",
|
||||
// },
|
||||
// {
|
||||
// id: "asset2",
|
||||
// name: "Asset 2",
|
||||
// },
|
||||
// {
|
||||
// id: "asset3",
|
||||
// name: "Asset 3",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// id: "zone2",
|
||||
// name: "Zone 2",
|
||||
// assets: [
|
||||
// {
|
||||
// id: "asset4",
|
||||
// name: "Asset 4",
|
||||
// },
|
||||
// {
|
||||
// id: "asset5",
|
||||
// name: "Asset 5",
|
||||
// },
|
||||
// {
|
||||
// id: "asset6",
|
||||
// name: "Asset 6",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// id: "zone3",
|
||||
// name: "Zone 3",
|
||||
// assets: [
|
||||
// {
|
||||
// id: "asset7",
|
||||
// name: "Asset 7",
|
||||
// },
|
||||
// {
|
||||
// id: "asset8",
|
||||
// name: "Asset 8",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ]);
|
||||
|
||||
const value = (zones || []).map(
|
||||
(val: { zoneId: string; zoneName: string }) => ({
|
||||
id: val.zoneId,
|
||||
name: val.zoneName,
|
||||
})
|
||||
);
|
||||
setZoneDataList([
|
||||
{
|
||||
id: "zone1",
|
||||
name: "Zone 1",
|
||||
assets: [
|
||||
{
|
||||
id: "asset1",
|
||||
name: "Asset 1",
|
||||
},
|
||||
{
|
||||
id: "asset2",
|
||||
name: "Asset 2",
|
||||
},
|
||||
{
|
||||
id: "asset3",
|
||||
name: "Asset 3",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "zone2",
|
||||
name: "Zone 2",
|
||||
assets: [
|
||||
{
|
||||
id: "asset4",
|
||||
name: "Asset 4",
|
||||
},
|
||||
{
|
||||
id: "asset5",
|
||||
name: "Asset 5",
|
||||
},
|
||||
{
|
||||
id: "asset6",
|
||||
name: "Asset 6",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "zone3",
|
||||
name: "Zone 3",
|
||||
assets: [
|
||||
{
|
||||
id: "asset7",
|
||||
name: "Asset 7",
|
||||
},
|
||||
{
|
||||
id: "asset8",
|
||||
name: "Asset 8",
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
}, [zones]);
|
||||
useEffect(() => {
|
||||
|
||||
// console.log('zonePoints3D: ', zonePoints3D);
|
||||
}, [zonePoints3D])
|
||||
|
||||
return (
|
||||
<div className="dropdown-list-container">
|
||||
|
|
|
@ -29,12 +29,15 @@ export default function PathNavigator({
|
|||
const [dropPickupPath, setDropPickupPath] = useState<[number, number, number][]>([]);
|
||||
const [initialPosition, setInitialPosition] = useState<THREE.Vector3 | 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 totalDistanceRef = useRef(0);
|
||||
const progressRef = useRef(0);
|
||||
const isWaiting = useRef(false);
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const pathTransitionProgress = useRef(0);
|
||||
|
||||
const { scene } = useThree();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
@ -44,6 +47,9 @@ export default function PathNavigator({
|
|||
if (object) {
|
||||
setInitialPosition(object.position.clone());
|
||||
setInitialRotation(object.rotation.clone());
|
||||
smoothPosition.copy(object.position.clone());
|
||||
targetPosition.copy(object.position.clone());
|
||||
targetQuaternion.setFromEuler(object.rotation.clone());
|
||||
}
|
||||
}, [scene, id]);
|
||||
|
||||
|
@ -65,22 +71,23 @@ export default function PathNavigator({
|
|||
|
||||
setPath([]);
|
||||
setCurrentPhase('initial');
|
||||
setPickupDropPath([]);
|
||||
setDropPickupPath([]);
|
||||
distancesRef.current = [];
|
||||
totalDistanceRef.current = 0;
|
||||
progressRef.current = 0;
|
||||
isWaiting.current = false;
|
||||
pathTransitionProgress.current = 0;
|
||||
|
||||
if (initialPosition && initialRotation) {
|
||||
const object = scene.getObjectByProperty("uuid", id);
|
||||
if (object) {
|
||||
object.position.copy(initialPosition);
|
||||
object.rotation.copy(initialRotation);
|
||||
}
|
||||
const object = scene.getObjectByProperty("uuid", id);
|
||||
if (object && initialPosition && initialRotation) {
|
||||
object.position.copy(initialPosition);
|
||||
object.rotation.copy(initialRotation);
|
||||
smoothPosition.copy(initialPosition);
|
||||
targetPosition.copy(initialPosition);
|
||||
targetQuaternion.setFromEuler(initialRotation);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPlaying) {
|
||||
resetState();
|
||||
|
@ -171,16 +178,16 @@ export default function PathNavigator({
|
|||
const end = new THREE.Vector3(...path[index + 1]);
|
||||
const dist = distancesRef.current[index];
|
||||
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 targetRotationY = Math.atan2(direction.x, direction.z);
|
||||
|
||||
let angleDifference = targetRotationY - object.rotation.y;
|
||||
angleDifference = ((angleDifference + Math.PI) % (Math.PI * 2)) - Math.PI;
|
||||
object.rotation.y += angleDifference * 0.1;
|
||||
targetQuaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), targetRotationY);
|
||||
object.quaternion.slerp(targetQuaternion, 0.1);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -53,7 +53,7 @@ export default function addFloorToScene(
|
|||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.receiveShadow = true;
|
||||
mesh.position.y = layer;
|
||||
mesh.position.y = (layer) * CONSTANTS.wallConfig.height;
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.name = `Floor_Layer_${layer}`;
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ function loadOnlyFloors(
|
|||
mesh.castShadow = 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.name = `Only_Floor_Line_${floor[0][0][2]}`;
|
||||
|
||||
|
|
|
@ -1,26 +1,11 @@
|
|||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import {
|
||||
useActiveTool,
|
||||
useAsset3dWidget,
|
||||
useCamMode,
|
||||
useDeletableFloorItem,
|
||||
useDeleteModels,
|
||||
useFloorItems,
|
||||
useLoadingProgress,
|
||||
useRenderDistance,
|
||||
useselectedFloorItem,
|
||||
useSelectedItem,
|
||||
useSimulationStates,
|
||||
useSocketStore,
|
||||
useToggleView,
|
||||
useTransformMode,
|
||||
} from "../../../store/store";
|
||||
import { useActiveTool, useAsset3dWidget, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useLoadingProgress, useRenderDistance, useselectedFloorItem, useSelectedItem, useSimulationStates, useSocketStore, useToggleView, useTransformMode, } from "../../../store/store";
|
||||
import assetVisibility from "../geomentries/assets/assetVisibility";
|
||||
import { useEffect } from "react";
|
||||
import * as THREE from "three";
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import assetManager, {
|
||||
cancelOngoingTasks,
|
||||
cancelOngoingTasks,
|
||||
} from "../geomentries/assets/assetManager";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
|
@ -31,413 +16,313 @@ import addAssetModel from "../geomentries/assets/addAssetModel";
|
|||
import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
||||
const assetManagerWorker = new Worker(
|
||||
new URL(
|
||||
"../../../services/factoryBuilder/webWorkers/assetManagerWorker.js",
|
||||
import.meta.url
|
||||
)
|
||||
);
|
||||
const gltfLoaderWorker = new Worker(
|
||||
new URL(
|
||||
"../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js",
|
||||
import.meta.url
|
||||
)
|
||||
);
|
||||
const assetManagerWorker = new Worker(new 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 = ({
|
||||
itemsGroup,
|
||||
hoveredDeletableFloorItem,
|
||||
AttachedObject,
|
||||
floorGroup,
|
||||
tempLoader,
|
||||
isTempLoader,
|
||||
plane,
|
||||
}: any) => {
|
||||
const state: Types.ThreeState = useThree();
|
||||
const { raycaster, controls }: any = state;
|
||||
const { renderDistance } = useRenderDistance();
|
||||
const { toggleView } = useToggleView();
|
||||
const { floorItems, setFloorItems } = useFloorItems();
|
||||
const { camMode } = useCamMode();
|
||||
const { deleteModels } = useDeleteModels();
|
||||
const { setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { transformMode } = useTransformMode();
|
||||
const { setselectedFloorItem } = useselectedFloorItem();
|
||||
const { activeTool } = useActiveTool();
|
||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { socket } = useSocketStore();
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => {
|
||||
const state: Types.ThreeState = useThree();
|
||||
const { raycaster, controls }: any = state;
|
||||
const { renderDistance } = useRenderDistance();
|
||||
const { toggleView } = useToggleView();
|
||||
const { floorItems, setFloorItems } = useFloorItems();
|
||||
const { camMode } = useCamMode();
|
||||
const { deleteModels } = useDeleteModels();
|
||||
const { setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { transformMode } = useTransformMode();
|
||||
const { setselectedFloorItem } = useselectedFloorItem();
|
||||
const { activeTool } = useActiveTool();
|
||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { socket } = useSocketStore();
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
dracoLoader.setDecoderPath(
|
||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
||||
);
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/");
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
let totalAssets = 0;
|
||||
let loadedAssets = 0;
|
||||
let totalAssets = 0;
|
||||
let loadedAssets = 0;
|
||||
|
||||
const updateLoadingProgress = (progress: number) => {
|
||||
if (progress < 100) {
|
||||
setLoadingProgress(progress);
|
||||
} else if (progress === 100) {
|
||||
setTimeout(() => {
|
||||
setLoadingProgress(100);
|
||||
setTimeout(() => {
|
||||
setLoadingProgress(0);
|
||||
}, 1500);
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
const updateLoadingProgress = (progress: number) => {
|
||||
if (progress < 100) {
|
||||
setLoadingProgress(progress);
|
||||
} else if (progress === 100) {
|
||||
setTimeout(() => {
|
||||
setLoadingProgress(100);
|
||||
setTimeout(() => {
|
||||
setLoadingProgress(0);
|
||||
}, 1500);
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
getFloorAssets(organization).then((data) => {
|
||||
if (data.length > 0) {
|
||||
const uniqueItems = (data as Types.FloorItems).filter(
|
||||
(item, index, self) =>
|
||||
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
|
||||
);
|
||||
totalAssets = uniqueItems.length;
|
||||
if (totalAssets === 0) {
|
||||
updateLoadingProgress(100);
|
||||
return;
|
||||
}
|
||||
gltfLoaderWorker.postMessage({ floorItems: data });
|
||||
} else {
|
||||
gltfLoaderWorker.postMessage({ floorItems: [] });
|
||||
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
|
||||
updateLoadingProgress(100);
|
||||
}
|
||||
});
|
||||
|
||||
gltfLoaderWorker.onmessage = async (event) => {
|
||||
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
||||
const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
||||
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(event.data.modelID, gltf);
|
||||
|
||||
loadedAssets++;
|
||||
const progress = Math.round((loadedAssets / totalAssets) * 100);
|
||||
updateLoadingProgress(progress);
|
||||
|
||||
if (loadedAssets === totalAssets) {
|
||||
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
|
||||
updateLoadingProgress(100);
|
||||
}
|
||||
getFloorAssets(organization).then((data) => {
|
||||
if (data.length > 0) {
|
||||
const uniqueItems = (data as Types.FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.modelfileID === item.modelfileID));
|
||||
totalAssets = uniqueItems.length;
|
||||
if (totalAssets === 0) {
|
||||
updateLoadingProgress(100);
|
||||
return;
|
||||
}
|
||||
gltfLoaderWorker.postMessage({ floorItems: data });
|
||||
} else {
|
||||
gltfLoaderWorker.postMessage({ floorItems: [] });
|
||||
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
|
||||
updateLoadingProgress(100);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
assetManagerWorker.onmessage = async (event) => {
|
||||
cancelOngoingTasks(); // Cancel the ongoing process
|
||||
await assetManager(event.data, itemsGroup, loader);
|
||||
};
|
||||
}, [assetManagerWorker]);
|
||||
gltfLoaderWorker.onmessage = async (event) => {
|
||||
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
||||
const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
||||
|
||||
useEffect(() => {
|
||||
if (toggleView) return;
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(event.data.modelID, gltf);
|
||||
|
||||
const uuids: string[] = [];
|
||||
itemsGroup.current?.children.forEach((child: any) => {
|
||||
uuids.push(child.uuid);
|
||||
});
|
||||
const cameraPosition = state.camera.position;
|
||||
loadedAssets++;
|
||||
const progress = Math.round((loadedAssets / totalAssets) * 100);
|
||||
updateLoadingProgress(progress);
|
||||
|
||||
assetManagerWorker.postMessage({
|
||||
floorItems,
|
||||
cameraPosition,
|
||||
uuids,
|
||||
renderDistance,
|
||||
});
|
||||
}, [camMode, renderDistance]);
|
||||
if (loadedAssets === totalAssets) {
|
||||
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
|
||||
updateLoadingProgress(100);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const controls: any = state.controls;
|
||||
const camera: any = state.camera;
|
||||
useEffect(() => {
|
||||
assetManagerWorker.onmessage = async (event) => {
|
||||
cancelOngoingTasks(); // Cancel the ongoing process
|
||||
await assetManager(event.data, itemsGroup, loader);
|
||||
};
|
||||
}, [assetManagerWorker]);
|
||||
|
||||
if (controls) {
|
||||
let intervalId: NodeJS.Timeout | null = null;
|
||||
|
||||
const handleChange = () => {
|
||||
useEffect(() => {
|
||||
if (toggleView) return;
|
||||
|
||||
const uuids: string[] = [];
|
||||
itemsGroup.current?.children.forEach((child: any) => {
|
||||
uuids.push(child.uuid);
|
||||
});
|
||||
const cameraPosition = camera.position;
|
||||
itemsGroup.current?.children.forEach((child: any) => { uuids.push(child.uuid); });
|
||||
const cameraPosition = state.camera.position;
|
||||
|
||||
assetManagerWorker.postMessage({
|
||||
floorItems,
|
||||
cameraPosition,
|
||||
uuids,
|
||||
renderDistance,
|
||||
});
|
||||
};
|
||||
assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance, });
|
||||
}, [camMode, renderDistance]);
|
||||
|
||||
const startInterval = () => {
|
||||
if (!intervalId) {
|
||||
intervalId = setInterval(handleChange, 50);
|
||||
useEffect(() => {
|
||||
const controls: any = state.controls;
|
||||
const camera: any = state.camera;
|
||||
|
||||
if (controls) {
|
||||
let intervalId: NodeJS.Timeout | null = null;
|
||||
|
||||
const handleChange = () => {
|
||||
if (toggleView) return;
|
||||
|
||||
const uuids: string[] = [];
|
||||
itemsGroup.current?.children.forEach((child: any) => { uuids.push(child.uuid); });
|
||||
const cameraPosition = camera.position;
|
||||
|
||||
assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance, });
|
||||
};
|
||||
|
||||
const startInterval = () => {
|
||||
if (!intervalId) {
|
||||
intervalId = setInterval(handleChange, 50);
|
||||
}
|
||||
};
|
||||
|
||||
const stopInterval = () => {
|
||||
handleChange();
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
intervalId = null;
|
||||
}
|
||||
};
|
||||
|
||||
controls.addEventListener("rest", handleChange);
|
||||
controls.addEventListener("rest", stopInterval);
|
||||
controls.addEventListener("control", startInterval);
|
||||
controls.addEventListener("controlend", stopInterval);
|
||||
|
||||
return () => {
|
||||
controls.removeEventListener("rest", handleChange);
|
||||
controls.removeEventListener("rest", stopInterval);
|
||||
controls.removeEventListener("control", startInterval);
|
||||
controls.removeEventListener("controlend", stopInterval);
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}, [state.controls, floorItems, toggleView, renderDistance]);
|
||||
|
||||
const stopInterval = () => {
|
||||
handleChange();
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
intervalId = null;
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
const canvasElement = state.gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
controls.addEventListener("rest", handleChange);
|
||||
controls.addEventListener("rest", stopInterval);
|
||||
controls.addEventListener("control", startInterval);
|
||||
controls.addEventListener("controlend", stopInterval);
|
||||
|
||||
return () => {
|
||||
controls.removeEventListener("rest", handleChange);
|
||||
controls.removeEventListener("rest", stopInterval);
|
||||
controls.removeEventListener("control", startInterval);
|
||||
controls.removeEventListener("controlend", stopInterval);
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
};
|
||||
}
|
||||
}, [state.controls, floorItems, toggleView, renderDistance]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = state.gl.domElement;
|
||||
let drag = false;
|
||||
let isLeftMouseDown = false;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = async (evt: any) => {
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (drag) return;
|
||||
|
||||
if (deleteModels) {
|
||||
DeleteFloorItems(
|
||||
itemsGroup,
|
||||
hoveredDeletableFloorItem,
|
||||
setFloorItems,
|
||||
setSimulationStates,
|
||||
socket
|
||||
);
|
||||
}
|
||||
const Mode = transformMode;
|
||||
|
||||
if (Mode !== null || activeTool === "cursor") {
|
||||
if (!itemsGroup.current) return;
|
||||
let intersects = raycaster.intersectObjects(
|
||||
itemsGroup.current.children,
|
||||
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;
|
||||
// while (currentObject) {
|
||||
// if (currentObject.name === "Scene") {
|
||||
// break;
|
||||
// }
|
||||
// currentObject = currentObject.parent as THREE.Object3D;
|
||||
// }
|
||||
// if (currentObject) {
|
||||
// AttachedObject.current = currentObject as any;
|
||||
// setselectedFloorItem(AttachedObject.current!);
|
||||
// }
|
||||
} else {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
await controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onDblClick = async (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (drag) return;
|
||||
|
||||
const Mode = transformMode;
|
||||
|
||||
if (Mode !== null || activeTool === "cursor") {
|
||||
if (!itemsGroup.current) return;
|
||||
let intersects = raycaster.intersectObjects(
|
||||
itemsGroup.current.children,
|
||||
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;
|
||||
|
||||
while (currentObject) {
|
||||
if (currentObject.name === "Scene") {
|
||||
break;
|
||||
}
|
||||
currentObject = currentObject.parent as THREE.Object3D;
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = true;
|
||||
drag = false;
|
||||
}
|
||||
if (currentObject) {
|
||||
AttachedObject.current = currentObject as any;
|
||||
// controls.fitToSphere(AttachedObject.current!, true);
|
||||
};
|
||||
|
||||
const bbox = new THREE.Box3().setFromObject(
|
||||
AttachedObject.current
|
||||
);
|
||||
const size = bbox.getSize(new THREE.Vector3());
|
||||
const center = bbox.getCenter(new THREE.Vector3());
|
||||
|
||||
const front = new THREE.Vector3(0, 0, 1);
|
||||
AttachedObject.current.localToWorld(front);
|
||||
front.sub(AttachedObject.current.position).normalize();
|
||||
|
||||
const distance = Math.max(size.x, size.y, size.z) * 2;
|
||||
const newPosition = center
|
||||
.clone()
|
||||
.addScaledVector(front, distance);
|
||||
|
||||
controls.setPosition(
|
||||
newPosition.x,
|
||||
newPosition.y,
|
||||
newPosition.z,
|
||||
true
|
||||
);
|
||||
controls.setTarget(center.x, center.y, center.z, true);
|
||||
controls.fitToBox(AttachedObject.current!, true, {
|
||||
cover: true,
|
||||
paddingTop: 5,
|
||||
paddingLeft: 5,
|
||||
paddingBottom: 5,
|
||||
paddingRight: 5,
|
||||
});
|
||||
|
||||
setselectedFloorItem(AttachedObject.current!);
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = async (evt: any) => {
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (drag) return;
|
||||
|
||||
if (deleteModels) {
|
||||
DeleteFloorItems(itemsGroup, hoveredDeletableFloorItem, setFloorItems, setSimulationStates, socket);
|
||||
}
|
||||
const Mode = transformMode;
|
||||
|
||||
if (Mode !== null || activeTool === "cursor") {
|
||||
if (!itemsGroup.current) return;
|
||||
let intersects = raycaster.intersectObjects(
|
||||
itemsGroup.current.children,
|
||||
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;
|
||||
// while (currentObject) {
|
||||
// if (currentObject.name === "Scene") {
|
||||
// break;
|
||||
// }
|
||||
// currentObject = currentObject.parent as THREE.Object3D;
|
||||
// }
|
||||
// if (currentObject) {
|
||||
// AttachedObject.current = currentObject as any;
|
||||
// setselectedFloorItem(AttachedObject.current!);
|
||||
// }
|
||||
} else {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
await controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onDblClick = async (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (drag) return;
|
||||
|
||||
const Mode = transformMode;
|
||||
|
||||
if (Mode !== null || activeTool === "cursor") {
|
||||
if (!itemsGroup.current) return;
|
||||
let intersects = raycaster.intersectObjects(itemsGroup.current.children, 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;
|
||||
|
||||
while (currentObject) {
|
||||
if (currentObject.name === "Scene") {
|
||||
break;
|
||||
}
|
||||
currentObject = currentObject.parent as THREE.Object3D;
|
||||
}
|
||||
if (currentObject) {
|
||||
AttachedObject.current = currentObject as any;
|
||||
// controls.fitToSphere(AttachedObject.current!, true);
|
||||
|
||||
const bbox = new THREE.Box3().setFromObject(AttachedObject.current);
|
||||
const size = bbox.getSize(new THREE.Vector3());
|
||||
const center = bbox.getCenter(new THREE.Vector3());
|
||||
|
||||
const front = new THREE.Vector3(0, 0, 1);
|
||||
AttachedObject.current.localToWorld(front);
|
||||
front.sub(AttachedObject.current.position).normalize();
|
||||
|
||||
const distance = Math.max(size.x, size.y, size.z) * 2;
|
||||
const newPosition = center.clone().addScaledVector(front, distance);
|
||||
|
||||
controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true);
|
||||
controls.setTarget(center.x, center.y, center.z, true);
|
||||
controls.fitToBox(AttachedObject.current!, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, });
|
||||
|
||||
setselectedFloorItem(AttachedObject.current!);
|
||||
}
|
||||
} else {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
await controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onDrop = (event: any) => {
|
||||
if (!event.dataTransfer?.files[0]) return;
|
||||
|
||||
if (selectedItem.id !== "" && event.dataTransfer?.files[0]) {
|
||||
addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, setSimulationStates, plane);
|
||||
}
|
||||
};
|
||||
|
||||
const onDragOver = (event: any) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
if (activeModule === "builder") {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("dblclick", onDblClick);
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
canvasElement.addEventListener("dragover", onDragOver);
|
||||
} else {
|
||||
if (controls) {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
} else {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
await controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onDrop = (event: any) => {
|
||||
if (!event.dataTransfer?.files[0]) return;
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("dblclick", onDblClick);
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
canvasElement.removeEventListener("dragover", onDragOver);
|
||||
};
|
||||
}, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule,]);
|
||||
|
||||
if (selectedItem.id !== "" && event.dataTransfer?.files[0]) {
|
||||
addAssetModel(
|
||||
raycaster,
|
||||
state.camera,
|
||||
state.pointer,
|
||||
floorGroup,
|
||||
setFloorItems,
|
||||
itemsGroup,
|
||||
isTempLoader,
|
||||
tempLoader,
|
||||
socket,
|
||||
selectedItem,
|
||||
setSelectedItem,
|
||||
setSimulationStates,
|
||||
plane
|
||||
);
|
||||
}
|
||||
};
|
||||
useFrame(() => {
|
||||
if (controls)
|
||||
assetVisibility(itemsGroup, state.camera.position, renderDistance);
|
||||
if (deleteModels && activeModule === "builder") {
|
||||
DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem);
|
||||
} else if (!deleteModels) {
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
hoveredDeletableFloorItem.current = undefined;
|
||||
setDeletableFloorItem(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const onDragOver = (event: any) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
if (activeModule === "builder") {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("dblclick", onDblClick);
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
canvasElement.addEventListener("dragover", onDragOver);
|
||||
} else {
|
||||
if (controls) {
|
||||
const target = controls.getTarget(new THREE.Vector3());
|
||||
controls.setTarget(target.x, 0, target.z, true);
|
||||
setselectedFloorItem(null);
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("dblclick", onDblClick);
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
canvasElement.removeEventListener("dragover", onDragOver);
|
||||
};
|
||||
}, [
|
||||
deleteModels,
|
||||
transformMode,
|
||||
controls,
|
||||
selectedItem,
|
||||
state.camera,
|
||||
state.pointer,
|
||||
activeTool,
|
||||
activeModule,
|
||||
]);
|
||||
|
||||
|
||||
useFrame(() => {
|
||||
if (controls)
|
||||
assetVisibility(itemsGroup, state.camera.position, renderDistance);
|
||||
if (deleteModels) {
|
||||
DeletableHoveredFloorItems(
|
||||
state,
|
||||
itemsGroup,
|
||||
hoveredDeletableFloorItem,
|
||||
setDeletableFloorItem
|
||||
);
|
||||
} else if (!deleteModels) {
|
||||
if (hoveredDeletableFloorItem.current) {
|
||||
hoveredDeletableFloorItem.current = undefined;
|
||||
setDeletableFloorItem(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return <group ref={itemsGroup} name="itemsGroup"></group>;
|
||||
return <group ref={itemsGroup} name="itemsGroup"></group>;
|
||||
};
|
||||
|
||||
export default FloorItemsGroup;
|
||||
|
|
|
@ -9,9 +9,13 @@ import handleMeshMissed from "../eventFunctions/handleMeshMissed";
|
|||
import DeleteWallItems from "../geomentries/walls/deleteWallItems";
|
||||
import loadInitialWallItems from "../../scene/IntialLoad/loadInitialWallItems";
|
||||
import AddWallItems from "../geomentries/walls/addWallItems";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
|
||||
|
||||
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 { wallItems, setWallItems } = useWallItems();
|
||||
const { objectPosition, setObjectPosition } = useObjectPosition();
|
||||
|
@ -19,10 +23,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
|
|||
const { objectRotation, setObjectRotation } = useObjectRotation();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||
const { socket } = useSocketStore();
|
||||
const state = useThree();
|
||||
const { pointer, camera, raycaster } = state;
|
||||
|
||||
const { activeModule } = useModuleStore();
|
||||
|
||||
useEffect(() => {
|
||||
// Load Wall Items from the backend
|
||||
|
@ -209,7 +210,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
|
|||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown = false;
|
||||
if (!drag && deleteModels) {
|
||||
if (!drag && deleteModels && activeModule === "builder") {
|
||||
DeleteWallItems(hoveredDeletableWallItem, setWallItems, wallItems, socket);
|
||||
}
|
||||
}
|
||||
|
@ -224,7 +225,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
|
|||
const onDrop = (event: any) => {
|
||||
|
||||
if (!event.dataTransfer?.files[0]) return
|
||||
|
||||
|
||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
|
@ -259,7 +260,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
|
|||
}, [deleteModels, wallItems])
|
||||
|
||||
useEffect(() => {
|
||||
if (deleteModels) {
|
||||
if (deleteModels && activeModule === "builder") {
|
||||
handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
|
|
|
@ -192,7 +192,7 @@ function processLoadedModel(
|
|||
},
|
||||
]);
|
||||
|
||||
if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') {
|
||||
if (item.eventData || item.modelfileID === '67e3db5ac2e8f37134526f40' || item.modelfileID === '67eb7904c2e8f37134527eae') {
|
||||
processEventData(item, setSimulationStates);
|
||||
}
|
||||
|
||||
|
@ -227,10 +227,10 @@ function processEventData(item: Types.EventData, setSimulationStates: any) {
|
|||
data as Types.VehicleEventsSchema
|
||||
]);
|
||||
|
||||
} else if (item.modelfileID === '67e3db95c2e8f37134526fb2') {
|
||||
} else if (item.modelfileID === '67e3db5ac2e8f37134526f40') {
|
||||
|
||||
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 = {
|
||||
modeluuid: item.modeluuid,
|
||||
|
@ -243,13 +243,39 @@ function processEventData(item: Types.EventData, setSimulationStates: any) {
|
|||
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
|
||||
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)[]) => [
|
||||
...(prevEvents || []),
|
||||
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
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
|||
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 organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||
|
@ -234,7 +234,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
|||
newEventData.position = newFloorItem.position;
|
||||
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 || []),
|
||||
newEventData as Types.ConveyorEventsSchema
|
||||
]);
|
||||
|
@ -313,13 +313,44 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
|||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
|
||||
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
newEventData as Types.VehicleEventsSchema
|
||||
]);
|
||||
|
||||
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 {
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
|||
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 organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||
|
@ -216,7 +216,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
|||
newEventData.position = newFloorItem.position;
|
||||
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 || []),
|
||||
newEventData as Types.ConveyorEventsSchema
|
||||
]);
|
||||
|
@ -295,13 +295,44 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
|||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
|
||||
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
|
||||
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
newEventData as Types.VehicleEventsSchema
|
||||
]);
|
||||
|
||||
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 {
|
||||
|
||||
|
|
|
@ -180,12 +180,12 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
|||
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 organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||
|
||||
if (eventData && eventData.type !== 'StaticMachine') {
|
||||
if (eventData) {
|
||||
if (eventData.type === 'Conveyor' && eventData) {
|
||||
|
||||
const backendEventData = {
|
||||
|
@ -229,7 +229,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
|||
newEventData.position = newFloorItem.position;
|
||||
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 =>
|
||||
event.modeluuid === newFloorItem.modeluuid
|
||||
? { ...event, ...newEventData }
|
||||
|
@ -280,7 +280,113 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
|||
newEventData.modelName = newFloorItem.modelname;
|
||||
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 =>
|
||||
event.modeluuid === newFloorItem.modeluuid
|
||||
? { ...event, ...newEventData }
|
||||
|
|
|
@ -184,13 +184,12 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
|||
return updatedItems;
|
||||
});
|
||||
|
||||
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
|
||||
console.log('eventData: ', eventData);
|
||||
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 organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||
|
||||
if (eventData && eventData.type !== 'StaticMachine') {
|
||||
if (eventData) {
|
||||
if (eventData.type === 'Conveyor' && eventData) {
|
||||
|
||||
const backendEventData = {
|
||||
|
@ -233,9 +232,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
|||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
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 =>
|
||||
event.modeluuid === newFloorItem.modeluuid
|
||||
? { ...event, ...newEventData }
|
||||
|
@ -287,7 +285,113 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
|||
newEventData.modelName = newFloorItem.modelname;
|
||||
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 =>
|
||||
event.modeluuid === newFloorItem.modeluuid
|
||||
? { ...event, ...newEventData }
|
||||
|
|
|
@ -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);
|
||||
return updatedEvents;
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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 Types from '../../../types/world/worldTypes';
|
||||
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 { usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
||||
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> }) {
|
||||
const { activeModule } = useModuleStore();
|
||||
const { gl, raycaster, scene, pointer, camera } = useThree();
|
||||
const { renderDistance } = useRenderDistance();
|
||||
const { setIsConnecting } = useIsConnecting();
|
||||
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { socket } = useSocketStore();
|
||||
const groupRefs = useRef<{ [key: string]: any }>({});
|
||||
|
||||
const [firstSelected, setFirstSelected] = useState<{
|
||||
modelUUID: string;
|
||||
sphereUUID: string;
|
||||
position: THREE.Vector3;
|
||||
isCorner: boolean;
|
||||
} | null>(null);
|
||||
const [firstSelected, setFirstSelected] = useState<{ 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 [helperlineColor, setHelperLineColor] = useState<string>('red');
|
||||
|
||||
const updatePathConnections = (
|
||||
fromModelUUID: string,
|
||||
fromPointUUID: string,
|
||||
toModelUUID: string,
|
||||
toPointUUID: string
|
||||
) => {
|
||||
const updatePathConnections = (fromModelUUID: string, fromPointUUID: string, toModelUUID: string, toPointUUID: string) => {
|
||||
const updatedPaths = simulationStates.map(path => {
|
||||
if (path.type === 'Conveyor') {
|
||||
// Handle outgoing connections from Conveyor
|
||||
if (path.modeluuid === fromModelUUID) {
|
||||
return {
|
||||
...path,
|
||||
|
@ -61,6 +54,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
})
|
||||
};
|
||||
}
|
||||
// Handle incoming connections to Conveyor
|
||||
else if (path.modeluuid === toModelUUID) {
|
||||
return {
|
||||
...path,
|
||||
|
@ -167,82 +161,170 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
}
|
||||
return path;
|
||||
}
|
||||
// else if (path.type === 'StaticMachine') {
|
||||
// if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
|
||||
// const newTarget = {
|
||||
// modelUUID: toModelUUID,
|
||||
// pointUUID: toPointUUID
|
||||
// };
|
||||
// const existingTargets = path.points.connections.targets || [];
|
||||
else if (path.type === 'StaticMachine') {
|
||||
// Handle outgoing connections from StaticMachine
|
||||
if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
|
||||
const newTarget = {
|
||||
modelUUID: toModelUUID,
|
||||
pointUUID: toPointUUID
|
||||
};
|
||||
|
||||
// // Check if target is an ArmBot
|
||||
// const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
|
||||
// if (toPath?.type !== 'ArmBot') {
|
||||
// console.log("StaticMachine can only connect to ArmBot");
|
||||
// return path;
|
||||
// }
|
||||
// Ensure target is an ArmBot
|
||||
const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
|
||||
if (toPath?.type !== 'ArmBot') {
|
||||
console.log("StaticMachine can only connect to ArmBot");
|
||||
return path;
|
||||
}
|
||||
|
||||
// // Check if already has a connection
|
||||
// if (existingTargets.length >= 1) {
|
||||
// console.log("StaticMachine can have only one connection");
|
||||
// return path;
|
||||
// }
|
||||
const existingTargets = path.points.connections.targets || [];
|
||||
|
||||
// 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 StaticMachine
|
||||
// else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
|
||||
// const reverseTarget = {
|
||||
// modelUUID: fromModelUUID,
|
||||
// pointUUID: fromPointUUID
|
||||
// };
|
||||
// const existingTargets = path.points.connections.targets || [];
|
||||
// Allow only one connection
|
||||
if (existingTargets.length >= 1) {
|
||||
console.log("StaticMachine can only have one connection");
|
||||
return path;
|
||||
}
|
||||
|
||||
// // Check if source is an ArmBot
|
||||
// const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
|
||||
// if (fromPath?.type !== 'ArmBot') {
|
||||
// console.log("StaticMachine can only connect to ArmBot");
|
||||
// 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]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// // Check if already has a connection
|
||||
// if (existingTargets.length >= 1) {
|
||||
// console.log("StaticMachine can have only one connection");
|
||||
// return path;
|
||||
// }
|
||||
// Handle incoming connections to StaticMachine
|
||||
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?.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;
|
||||
});
|
||||
|
||||
|
@ -252,10 +334,10 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
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;
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||
|
@ -437,6 +519,69 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
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
|
||||
if (!firstSelected.isCorner && !isStartOrEnd) {
|
||||
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]);
|
||||
|
||||
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(() => {
|
||||
if (firstSelected) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
|
@ -574,12 +728,50 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
(firstPath?.type === 'Vehicle' && secondPath?.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 (
|
||||
!isDuplicateConnection &&
|
||||
!isVehicleToVehicle &&
|
||||
!isNonVehicleAlreadyConnected &&
|
||||
!isVehicleAtMaxConnections &&
|
||||
!isVehicleConnectingToNonConveyor &&
|
||||
!isStaticMachineToNonArmBot &&
|
||||
!isStaticMachineAtMaxConnections &&
|
||||
!isArmBotToArmBot &&
|
||||
!isArmBotToInvalidType &&
|
||||
!isArmBotAlreadyConnectedToStatic &&
|
||||
firstSelected.sphereUUID !== sphereUUID &&
|
||||
firstSelected.modelUUID !== modelUUID &&
|
||||
(firstSelected.isCorner || isConnectable) &&
|
||||
|
@ -596,6 +788,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
} else {
|
||||
isInvalidConnection = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (snappedSphere) {
|
||||
|
@ -633,7 +826,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
});
|
||||
|
||||
return (
|
||||
<group name='simulationConnectionGroup' visible={!isPlaying} >
|
||||
<group name='simulationConnectionGroup' visible={!isPlaying}>
|
||||
{simulationStates.flatMap(path => {
|
||||
if (path.type === 'Conveyor') {
|
||||
return path.points.flatMap(point =>
|
||||
|
@ -652,7 +845,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
|
||||
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,
|
||||
|
@ -662,6 +854,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
return (
|
||||
<QuadraticBezierLine
|
||||
key={`${point.uuid}-${target.pointUUID}-${index}`}
|
||||
ref={(el) => (groupRefs.current[`${point.uuid}-${target.pointUUID}-${index}`] = el!)}
|
||||
start={fromWorldPosition.toArray()}
|
||||
end={toWorldPosition.toArray()}
|
||||
mid={midPoint.toArray()}
|
||||
|
@ -676,7 +869,9 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
return null;
|
||||
})
|
||||
);
|
||||
} else if (path.type === 'Vehicle') {
|
||||
}
|
||||
|
||||
if (path.type === 'Vehicle') {
|
||||
return path.points.connections.targets.map((target, index) => {
|
||||
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid);
|
||||
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
||||
|
@ -689,7 +884,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
|
||||
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,
|
||||
|
@ -699,6 +893,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
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()}
|
||||
|
@ -713,6 +908,48 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
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 [];
|
||||
})}
|
||||
|
||||
|
@ -730,6 +967,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
)}
|
||||
</group>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default PathConnector;
|
|
@ -206,6 +206,7 @@ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObjec
|
|||
return (
|
||||
<group
|
||||
name={`${path.modeluuid}-${path.type}-path`}
|
||||
uuid={path.modeluuid}
|
||||
key={path.modeluuid}
|
||||
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
|
||||
position={path.position}
|
||||
|
@ -271,10 +272,11 @@ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObjec
|
|||
})}
|
||||
</group>
|
||||
);
|
||||
} else if (path.type === "Vehicle" || path.type === "StaticMachine") {
|
||||
} else if (path.type === "Vehicle") {
|
||||
return (
|
||||
<group
|
||||
name={`${path.modeluuid}-${path.type}-path`}
|
||||
uuid={path.modeluuid}
|
||||
key={path.modeluuid}
|
||||
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
|
||||
position={path.position}
|
||||
|
@ -323,6 +325,114 @@ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObjec
|
|||
</Sphere>
|
||||
</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;
|
||||
})}
|
||||
|
|
|
@ -15,7 +15,7 @@ export const deleteZonesApi = async (userId: string, organization: string, zoneI
|
|||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log('result: ', result);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
|
|
|
@ -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`;
|
||||
|
||||
export const getZoneData = async (zoneId: string, organization: string) => {
|
||||
console.log("organization: ", organization);
|
||||
console.log("zoneId: ", zoneId);
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${url_Backend_dwinzo}/api/v2/A_zone/${zoneId}/${organization}`,
|
||||
|
|
|
@ -347,12 +347,12 @@ export const useSelectedPath = create<any>((set: any) => ({
|
|||
}));
|
||||
|
||||
interface SimulationPathsStore {
|
||||
simulationStates: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[];
|
||||
simulationStates: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[];
|
||||
setSimulationStates: (
|
||||
paths:
|
||||
| (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]
|
||||
| ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]
|
||||
) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[])
|
||||
| (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]
|
||||
| ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]
|
||||
) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[])
|
||||
) => void;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
.tools-container {
|
||||
@include flex-center;
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
bottom: 32px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
padding: 8px;
|
||||
|
|
|
@ -472,6 +472,15 @@
|
|||
font-size: var(--font-weight-regular);
|
||||
color: #4a4a4a;
|
||||
|
||||
.reviewChart {
|
||||
width: 100%;
|
||||
|
||||
.floating {
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.selectedWidget {
|
||||
padding: 6px 12px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
border-radius: 20px;
|
||||
box-shadow: $box-shadow-medium;
|
||||
width: calc(100% - (320px + 270px + 90px));
|
||||
height: calc(100% - (200px + 80px));
|
||||
height: calc(100% - (250px));
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: calc(270px + 45px);
|
||||
|
@ -16,6 +16,13 @@
|
|||
transition: all 0.2s;
|
||||
z-index: #{$z-index-default};
|
||||
|
||||
.realTime-viz-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.floating {
|
||||
width: 100%;
|
||||
max-width: 250px;
|
||||
|
@ -62,6 +69,7 @@
|
|||
max-width: 80%;
|
||||
overflow: auto;
|
||||
max-width: calc(100% - 500px);
|
||||
z-index: 3;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
|
@ -108,7 +116,8 @@
|
|||
}
|
||||
|
||||
.zone-wrapper.bottom {
|
||||
bottom: 210px;
|
||||
bottom: calc(var(--realTimeViz-container-height) * 0.27);
|
||||
bottom: 200px;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
|
@ -173,12 +182,15 @@
|
|||
overflow: auto;
|
||||
z-index: $z-index-tools;
|
||||
overflow: auto;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -191,7 +203,6 @@
|
|||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 25% !important;
|
||||
min-height: 150px;
|
||||
max-height: 100%;
|
||||
// border: 1px dashed var(--background-color-gray);
|
||||
|
@ -200,6 +211,7 @@
|
|||
padding: 6px 0;
|
||||
background-color: var(--background-color);
|
||||
position: relative;
|
||||
padding: 0 10px;
|
||||
|
||||
.kebab {
|
||||
width: 30px;
|
||||
|
@ -284,16 +296,17 @@
|
|||
&.bottom-panel {
|
||||
left: 0;
|
||||
right: 0;
|
||||
min-height: 150px;
|
||||
|
||||
.panel-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-height: 150px;
|
||||
|
||||
.chart-container {
|
||||
height: 100% !important;
|
||||
width: 20%;
|
||||
min-width: 150px;
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -310,29 +323,47 @@
|
|||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
}
|
||||
}
|
||||
|
||||
&.right-panel {
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
&.left-panel,
|
||||
&.right-panel {
|
||||
min-width: 150px;
|
||||
|
||||
.panel-content {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
gap: 6px;
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
min-height: 160px;
|
||||
max-height: 100%;
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--box-shadow-medium);
|
||||
padding: 6px 0;
|
||||
background-color: var(--background-color);
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panel.hidePanel {
|
||||
opacity: 0;
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
.playingFlase {
|
||||
.zone-wrapper.bottom {
|
||||
bottom: 300px;
|
||||
bottom: calc(var(--realTimeViz-container-height) * 0.25);
|
||||
// bottom: 210px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -621,9 +652,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -719,14 +747,13 @@
|
|||
}
|
||||
|
||||
.connectionSuccess {
|
||||
outline-color: #43C06D;
|
||||
outline-color: #43c06d;
|
||||
}
|
||||
|
||||
.connectionFails {
|
||||
outline-color: #ffe3e0;
|
||||
}
|
||||
|
||||
|
||||
.editWidgetOptions {
|
||||
position: absolute;
|
||||
// top: 50%;
|
||||
|
@ -739,7 +766,8 @@
|
|||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
|
||||
min-width: 150px;
|
||||
min-width: 150px;
|
||||
|
||||
.option {
|
||||
padding: 8px 10px;
|
||||
color: var(--text-color);
|
||||
|
@ -758,4 +786,4 @@ min-width: 150px;
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -329,6 +329,7 @@ interface StaticMachineEventsSchema {
|
|||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||
};
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
}
|
||||
|
||||
interface ArmBotEventsSchema {
|
||||
|
@ -343,6 +344,7 @@ interface ArmBotEventsSchema {
|
|||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||
};
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
}
|
||||
|
||||
export type EventData = {
|
||||
|
|
Loading…
Reference in New Issue