updated realTimeViz panel style

This commit is contained in:
Nalvazhuthi 2025-04-07 17:55:14 +05:30
commit 4a05bb8cdf
74 changed files with 3243 additions and 3138 deletions

View File

@ -11,7 +11,7 @@ REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000
REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011
# Base URL for the asset library server, used for asset library images and model blob id. # Base URL for the asset library server, used for asset library images and model blob id.
REACT_APP_SERVER_ASSET_LIBRARY_URL=192.168.0.111:3501 REACT_APP_SERVER_ASSET_LIBRARY_URL=185.100.212.76:50011
# base url for IoT socket server # base url for IoT socket server
REACT_APP_IOT_SOCKET_SERVER_URL =185.100.212.76:5010 REACT_APP_IOT_SOCKET_SERVER_URL =185.100.212.76:5010

Binary file not shown.

View File

@ -30,14 +30,13 @@ interface ProductionCapacityProps {
id: string; id: string;
type: string; type: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number];
onContextMenu?: (event: React.MouseEvent) => void; onContextMenu?: (event: React.MouseEvent) => void;
// onPointerDown:any // onPointerDown:any
} }
const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ id, type, position, onContextMenu }) => { const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ id, type, position, rotation, onContextMenu }) => {
const { selectedChartId, setSelectedChartId } = useWidgetStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({}); const [measurements, setmeasurements] = useState<any>({});
const [duration, setDuration] = useState("1h") const [duration, setDuration] = useState("1h")
@ -158,10 +157,10 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ id, type, posit
setDuration(response.data.Data.duration) setDuration(response.data.Data.duration)
setName(response.data.widgetName) setName(response.data.widgetName)
} else { } else {
console.log("Unexpected response:", response);
} }
} catch (error) { } catch (error) {
console.error("There was an error!", error);
} }
} }
} }
@ -177,15 +176,42 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ id, type, posit
} }
, [chartMeasurements, chartDuration, widgetName]) , [chartMeasurements, chartDuration, widgetName])
useEffect(() => {
}, [rotation])
const rotationDegrees = {
x: (rotation[0] * 180) / Math.PI,
y: (rotation[1] * 180) / Math.PI,
z: (rotation[2] * 180) / Math.PI,
};
const transformStyle = {
transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`,
};
return ( return (
<Html position={[position[0], position[1], position[2]]} <Html position={position}
scale={[0.5, 0.5, 0.5]} scale={[0.5, 0.5, 0.5]}
zIndexRange={[1, 0]}
transform transform
sprite> sprite
zIndexRange={[1,0]}
// center
// distanceFactor={10} // Adjusted for visual balance
style={{
transform: transformStyle.transform,
transformStyle: 'preserve-3d',
transition: 'transform 0.1s ease-out'
}}>
<div className="productionCapacity-wrapper card" <div className="productionCapacity-wrapper card"
onClick={() => setSelectedChartId({ id: id, type: type })} onClick={() => setSelectedChartId({ id: id, type: type })}
onContextMenu={onContextMenu} onContextMenu={onContextMenu}
style={{
width: '300px', // Original width
height: '300px', // Original height
transform: transformStyle.transform,
transformStyle: 'preserve-3d'
}}
> >
<div className="headeproductionCapacityr-wrapper"> <div className="headeproductionCapacityr-wrapper">
<div className="header">Production Capacity</div> <div className="header">Production Capacity</div>

View File

@ -43,9 +43,10 @@ interface ReturnOfInvestmentProps {
id: string; id: string;
type: string; type: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number];
onContextMenu?: (event: React.MouseEvent) => void; onContextMenu?: (event: React.MouseEvent) => void;
} }
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, position, onContextMenu }) => { const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, position, rotation, onContextMenu }) => {
const { selectedChartId, setSelectedChartId } = useWidgetStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
@ -203,13 +204,29 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
} }
} }
, [chartMeasurements, chartDuration, widgetName]) , [chartMeasurements, chartDuration, widgetName])
const rotationDegrees = {
x: (rotation[0] * 180) / Math.PI,
y: (rotation[1] * 180) / Math.PI,
z: (rotation[2] * 180) / Math.PI,
};
const transformStyle = {
transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`,
};
return ( return (
<Html position={[position[0], position[1], position[2]]} <Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]} scale={[0.5, 0.5, 0.5]}
transform transform
zIndexRange={[1, 0]} zIndexRange={[1, 0]}
sprite> sprite
style={{
transform: transformStyle.transform,
transformStyle: 'preserve-3d',
transition: 'transform 0.1s ease-out'
}}
>
<div className="returnOfInvestment card" <div className="returnOfInvestment card"
onClick={() => setSelectedChartId({ id: id, type: type })} onClick={() => setSelectedChartId({ id: id, type: type })}
onContextMenu={onContextMenu} onContextMenu={onContextMenu}

View File

@ -10,9 +10,10 @@ interface StateWorkingProps {
id: string; id: string;
type: string; type: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number];
onContextMenu?: (event: React.MouseEvent) => void; onContextMenu?: (event: React.MouseEvent) => void;
} }
const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, onContextMenu }) => { const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotation, onContextMenu }) => {
const { selectedChartId, setSelectedChartId } = useWidgetStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState<any>({}); const [measurements, setmeasurements] = useState<any>({});
@ -45,7 +46,7 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, onConte
socket.on("connect", startStream); socket.on("connect", startStream);
socket.on("lastOutput", (response) => { socket.on("lastOutput", (response) => {
const responseData = response; const responseData = response;
console.log("responceeeeeeeeeee", response);
setDatas(responseData); setDatas(responseData);
}); });
@ -75,7 +76,7 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, onConte
} }
} }
console.log("dataaaaa", datas);
useEffect(() => { useEffect(() => {
@ -89,13 +90,28 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, onConte
} }
, [chartMeasurements, chartDuration, widgetName]) , [chartMeasurements, chartDuration, widgetName])
const rotationDegrees = {
x: (rotation[0] * 180) / Math.PI,
y: (rotation[1] * 180) / Math.PI,
z: (rotation[2] * 180) / Math.PI,
};
const transformStyle = {
transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`,
};
return ( return (
<Html position={[position[0], position[1], position[2]]} <Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]} scale={[0.5, 0.5, 0.5]}
transform transform
zIndexRange={[1, 0]} zIndexRange={[1, 0]}
sprite> sprite
style={{
transform: transformStyle.transform,
transformStyle: 'preserve-3d',
transition: 'transform 0.1s ease-out'
}}
>
<div className="stateWorking-wrapper card" <div className="stateWorking-wrapper card"
onClick={() => setSelectedChartId({ id: id, type: type })} onClick={() => setSelectedChartId({ id: id, type: type })}
onContextMenu={onContextMenu} onContextMenu={onContextMenu}

View File

@ -45,10 +45,11 @@ interface ThroughputProps {
id: string; id: string;
type: string; type: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number];
onContextMenu?: (event: React.MouseEvent) => void; onContextMenu?: (event: React.MouseEvent) => void;
} }
const Throughput: React.FC<ThroughputProps> = ({ id, type, position, onContextMenu }) => { const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, onContextMenu }) => {
const { selectedChartId, setSelectedChartId } = useWidgetStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore();
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
@ -183,13 +184,29 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, onContextMe
} }
} }
, [chartMeasurements, chartDuration, widgetName]) , [chartMeasurements, chartDuration, widgetName])
const rotationDegrees = {
x: (rotation[0] * 180) / Math.PI,
y: (rotation[1] * 180) / Math.PI,
z: (rotation[2] * 180) / Math.PI,
};
const transformStyle = {
transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`,
};
return ( return (
<Html position={[position[0], position[1], position[2]]} <Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]} scale={[0.5, 0.5, 0.5]}
transform transform
zIndexRange={[1, 0]} zIndexRange={[1, 0]}
sprite> sprite
style={{
transform: transformStyle.transform,
transformStyle: 'preserve-3d',
transition: 'transform 0.1s ease-out'
}}
>
<div className="throughput-wrapper" <div className="throughput-wrapper"
onClick={() => setSelectedChartId({ id: id, type: type })} onClick={() => setSelectedChartId({ id: id, type: type })}
onContextMenu={onContextMenu} onContextMenu={onContextMenu}

View File

@ -13,7 +13,8 @@ import {
useFloorItems, useFloorItems,
useSelectedActionSphere, useSelectedActionSphere,
useSelectedPath, useSelectedPath,
useSimulationPaths, useSimulationStates,
useSocketStore,
} from "../../../../store/store"; } from "../../../../store/store";
import * as THREE from "three"; import * as THREE from "three";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
@ -24,44 +25,53 @@ import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAss
const ConveyorMechanics: React.FC = () => { const ConveyorMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere(); const { selectedActionSphere } = useSelectedActionSphere();
const { selectedPath, setSelectedPath } = useSelectedPath(); const { selectedPath, setSelectedPath } = useSelectedPath();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationStates, setSimulationStates } = useSimulationStates();
const { floorItems, setFloorItems } = useFloorItems(); const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore();
const actionsContainerRef = useRef<HTMLDivElement>(null); const actionsContainerRef = useRef<HTMLDivElement>(null);
const triggersContainerRef = useRef<HTMLDivElement>(null); const triggersContainerRef = useRef<HTMLDivElement>(null);
const selectedPoint = useMemo(() => { const selectedPoint = useMemo(() => {
if (!selectedActionSphere) return null; if (!selectedActionSphere) return null;
return simulationPaths return simulationStates
.filter( .filter(
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor" (path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
) )
.flatMap((path) => path.points) .flatMap((path) => path.points)
.find((point) => point.uuid === selectedActionSphere.point.uuid); .find((point) => point.uuid === selectedActionSphere.points.uuid);
}, [selectedActionSphere, simulationPaths]); }, [selectedActionSphere, simulationStates]);
const updateBackend = async (updatedPath: Types.ConveyorEventsSchema | undefined) => { const updateBackend = async (updatedPath: Types.ConveyorEventsSchema | undefined) => {
if (!updatedPath) return; if (!updatedPath) return;
// const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
// const organization = email ? email.split("@")[1].split(".")[0] : ""; const organization = email ? email.split("@")[1].split(".")[0] : "";
// console.log('updatedPath: ', updatedPath);
// const a = await setEventApi( // await setEventApi(
// organization, // organization,
// updatedPath.modeluuid, // updatedPath.modeluuid,
// updatedPath.points // { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
// ); // );
// console.log('a: ', a);
const data = {
organization: organization,
modeluuid: updatedPath.modeluuid,
eventData: { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
}
socket.emit('v2:model-asset:updateEventData', data);
} }
const handleAddAction = () => { const handleAddAction = () => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => { const updatedPaths = simulationStates.map((path) => {
if (path.type === "Conveyor") { if (path.type === "Conveyor") {
return { return {
...path, ...path,
points: path.points.map((point) => { points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) { if (point.uuid === selectedActionSphere.points.uuid) {
const actionIndex = point.actions.length; const actionIndex = point.actions.length;
const newAction = { const newAction = {
uuid: THREE.MathUtils.generateUUID(), uuid: THREE.MathUtils.generateUUID(),
@ -86,23 +96,23 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
}; };
const handleDeleteAction = (uuid: string) => { const handleDeleteAction = (uuid: string) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
actions: point.actions.filter( actions: point.actions.filter(
@ -119,23 +129,23 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
}; };
const handleActionSelect = (uuid: string, actionType: string) => { const handleActionSelect = (uuid: string, actionType: string) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
actions: point.actions.map((action) => actions: point.actions.map((action) =>
@ -167,12 +177,12 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
// Update the selected item to reflect changes // Update the selected item to reflect changes
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
@ -181,7 +191,7 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => path.type === "Conveyor" (path): path is Types.ConveyorEventsSchema => path.type === "Conveyor"
) )
.flatMap((path) => path.points) .flatMap((path) => path.points)
.find((p) => p.uuid === selectedActionSphere.point.uuid) .find((p) => p.uuid === selectedActionSphere.points.uuid)
?.actions.find((a) => a.uuid === uuid); ?.actions.find((a) => a.uuid === uuid);
if (updatedAction) { if (updatedAction) {
@ -197,12 +207,12 @@ const ConveyorMechanics: React.FC = () => {
const handleMaterialSelect = (uuid: string, material: string) => { const handleMaterialSelect = (uuid: string, material: string) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
actions: point.actions.map((action) => actions: point.actions.map((action) =>
@ -222,12 +232,12 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
// Update selected item if it's the current action // Update selected item if it's the current action
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
@ -244,12 +254,12 @@ const ConveyorMechanics: React.FC = () => {
const handleDelayChange = (uuid: string, delay: number | string) => { const handleDelayChange = (uuid: string, delay: number | string) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
actions: point.actions.map((action) => actions: point.actions.map((action) =>
@ -266,12 +276,12 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
}; };
const handleSpawnIntervalChange = ( const handleSpawnIntervalChange = (
@ -280,12 +290,12 @@ const ConveyorMechanics: React.FC = () => {
) => { ) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
actions: point.actions.map((action) => actions: point.actions.map((action) =>
@ -304,18 +314,18 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
}; };
const handleSpeedChange = (speed: number | string) => { const handleSpeedChange = (speed: number | string) => {
if (!selectedPath) return; if (!selectedPath) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
); );
@ -323,24 +333,24 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } }); setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
}; };
const handleAddTrigger = () => { const handleAddTrigger = () => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => { points: path.points.map((point) => {
if (point.uuid === selectedActionSphere.point.uuid) { if (point.uuid === selectedActionSphere.points.uuid) {
const triggerIndex = point.triggers.length; const triggerIndex = point.triggers.length;
const newTrigger = { const newTrigger = {
uuid: THREE.MathUtils.generateUUID(), uuid: THREE.MathUtils.generateUUID(),
@ -362,23 +372,23 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
}; };
const handleDeleteTrigger = (uuid: string) => { const handleDeleteTrigger = (uuid: string) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
triggers: point.triggers.filter( triggers: point.triggers.filter(
@ -395,23 +405,23 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
}; };
const handleTriggerSelect = (uuid: string, triggerType: string) => { const handleTriggerSelect = (uuid: string, triggerType: string) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
triggers: point.triggers.map((trigger) => triggers: point.triggers.map((trigger) =>
@ -430,12 +440,12 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
// Ensure the selectedItem is updated immediately // Ensure the selectedItem is updated immediately
const updatedTrigger = updatedPaths const updatedTrigger = updatedPaths
@ -451,12 +461,12 @@ const ConveyorMechanics: React.FC = () => {
// Update the toggle handlers to immediately update the selected item // Update the toggle handlers to immediately update the selected item
const handleActionToggle = (uuid: string) => { const handleActionToggle = (uuid: string) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
actions: point.actions.map((action) => ({ actions: point.actions.map((action) => ({
@ -474,12 +484,12 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
// Immediately update the selected item if it's the one being toggled // Immediately update the selected item if it's the one being toggled
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
@ -497,12 +507,12 @@ const ConveyorMechanics: React.FC = () => {
const handleTriggerToggle = (uuid: string) => { const handleTriggerToggle = (uuid: string) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
triggers: point.triggers.map((trigger) => ({ triggers: point.triggers.map((trigger) => ({
@ -520,12 +530,12 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
// Immediately update the selected item if it's the one being toggled // Immediately update the selected item if it's the one being toggled
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) { if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
@ -542,12 +552,12 @@ const ConveyorMechanics: React.FC = () => {
const handleTriggerBufferTimeChange = (uuid: string, bufferTime: number) => { const handleTriggerBufferTimeChange = (uuid: string, bufferTime: number) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.type === "Conveyor" path.type === "Conveyor"
? { ? {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
triggers: point.triggers.map((trigger) => triggers: point.triggers.map((trigger) =>
@ -566,12 +576,12 @@ const ConveyorMechanics: React.FC = () => {
(path): path is Types.ConveyorEventsSchema => (path): path is Types.ConveyorEventsSchema =>
path.type === "Conveyor" && path.type === "Conveyor" &&
path.points.some( path.points.some(
(point) => point.uuid === selectedActionSphere.point.uuid (point) => point.uuid === selectedActionSphere.points.uuid
) )
); );
updateBackend(updatedPath); updateBackend(updatedPath);
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
// Immediately update selectedItem if it's the currently selected trigger // Immediately update selectedItem if it's the currently selected trigger
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) { if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {

View File

@ -1,56 +1,79 @@
import React, { useRef, useMemo } from "react"; import React, { useRef, useMemo } from "react";
import { InfoIcon } from "../../../icons/ExportCommonIcons"; import { InfoIcon } from "../../../icons/ExportCommonIcons";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationPaths } from "../../../../store/store"; import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store";
import * as Types from '../../../../types/world/worldTypes'; import * as Types from '../../../../types/world/worldTypes';
import PositionInput from "../customInput/PositionInputs"; import PositionInput from "../customInput/PositionInputs";
import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
const VehicleMechanics: React.FC = () => { const VehicleMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere(); const { selectedActionSphere } = useSelectedActionSphere();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationStates, setSimulationStates } = useSimulationStates();
const { eyeDropMode, setEyeDropMode } = useEyeDropMode(); const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
const { editingPoint, setEditingPoint } = useEditingPoint(); const { editingPoint, setEditingPoint } = useEditingPoint();
const { previewPosition, setPreviewPosition } = usePreviewPosition(); const { previewPosition, setPreviewPosition } = usePreviewPosition();
const { socket } = useSocketStore();
const propertiesContainerRef = useRef<HTMLDivElement>(null); const propertiesContainerRef = useRef<HTMLDivElement>(null);
const { selectedPoint, connectedPointUuids } = useMemo(() => { const { selectedPoint, connectedPointUuids } = useMemo(() => {
if (!selectedActionSphere?.point?.uuid) return { selectedPoint: null, connectedPointUuids: [] }; if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
const vehiclePaths = simulationPaths.filter( const vehiclePaths = simulationStates.filter(
(path): path is Types.VehicleEventsSchema => path.type === "Vehicle" (path): path is Types.VehicleEventsSchema => path.type === "Vehicle"
); );
const point = vehiclePaths.find( const points = vehiclePaths.find(
(path) => path.point.uuid === selectedActionSphere.point.uuid (path) => path.points.uuid === selectedActionSphere.points.uuid
)?.point; )?.points;
if (!point) return { selectedPoint: null, connectedPointUuids: [] }; if (!points) return { selectedPoint: null, connectedPointUuids: [] };
const connectedUuids: string[] = []; const connectedUuids: string[] = [];
if (point.connections?.targets) { if (points.connections?.targets) {
point.connections.targets.forEach(target => { points.connections.targets.forEach(target => {
connectedUuids.push(target.pointUUID); connectedUuids.push(target.pointUUID);
}); });
} }
return { return {
selectedPoint: point, selectedPoint: points,
connectedPointUuids: connectedUuids connectedPointUuids: connectedUuids
}; };
}, [selectedActionSphere, simulationPaths]); }, [selectedActionSphere, simulationStates]);
const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['point']['actions']>) => { const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => {
if (!selectedActionSphere?.point?.uuid) return; if (!updatedPath) return;
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "";
const updatedPaths = simulationPaths.map((path) => { // await setEventApi(
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) { // organization,
// updatedPath.modeluuid,
// { type: "Vehicle", points: updatedPath.points }
// );
const data = {
organization: organization,
modeluuid: updatedPath.modeluuid,
eventData: { type: "Vehicle", points: updatedPath.points }
}
socket.emit('v2:model-asset:updateEventData', data);
}
const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['points']['actions']>) => {
if (!selectedActionSphere?.points?.uuid) return;
const updatedPaths = simulationStates.map((path) => {
if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
return { return {
...path, ...path,
point: { points: {
...path.point, ...path.points,
actions: { actions: {
...path.point.actions, ...path.points.actions,
...updatedAction ...updatedAction
} }
} }
@ -59,14 +82,15 @@ const VehicleMechanics: React.FC = () => {
return path; return path;
}); });
setSimulationPaths(updatedPaths); const updatedPath = updatedPaths.find(
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]); (path): path is Types.VehicleEventsSchema =>
path.type === "Vehicle" &&
path.points.uuid === selectedActionSphere.points.uuid
);
updateBackend(updatedPath);
const handleStartPointChange = React.useCallback((position: { x: number, y: number }) => { setSimulationStates(updatedPaths);
}, [handleActionUpdate]); }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
const handleEndPointChange = React.useCallback((position: { x: number, y: number }) => {
}, [handleActionUpdate]);
const handleHitCountChange = React.useCallback((hitCount: number) => { const handleHitCountChange = React.useCallback((hitCount: number) => {
handleActionUpdate({ hitCount }); handleActionUpdate({ hitCount });
@ -77,14 +101,14 @@ const VehicleMechanics: React.FC = () => {
}, [handleActionUpdate]); }, [handleActionUpdate]);
const handleSpeedChange = React.useCallback((speed: number) => { const handleSpeedChange = React.useCallback((speed: number) => {
if (!selectedActionSphere?.point?.uuid) return; if (!selectedActionSphere?.points?.uuid) return;
const updatedPaths = simulationPaths.map((path) => { const updatedPaths = simulationStates.map((path) => {
if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) { if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
return { return {
...path, ...path,
point: { points: {
...path.point, ...path.points,
speed: speed speed: speed
} }
}; };
@ -92,8 +116,15 @@ const VehicleMechanics: React.FC = () => {
return path; return path;
}); });
setSimulationPaths(updatedPaths); const updatedPath = updatedPaths.find(
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]); (path): path is Types.VehicleEventsSchema =>
path.type === "Vehicle" &&
path.points.uuid === selectedActionSphere.points.uuid
);
updateBackend(updatedPath);
setSimulationStates(updatedPaths);
}, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
const handleStartEyeDropClick = () => { const handleStartEyeDropClick = () => {
setEditingPoint('start'); setEditingPoint('start');

View File

@ -33,7 +33,7 @@ const GlobalProperties: React.FC = () => {
const { setPlaneValue, setGridValue, planeValue, gridValue } = const { setPlaneValue, setGridValue, planeValue, gridValue } =
useTileDistance(); useTileDistance();
useEffect(() => { useEffect(() => {
// console.log(gridValue, planeValue, "values");
}, [gridValue, planeValue]); }, [gridValue, planeValue]);
const { socket } = useSocketStore(); const { socket } = useSocketStore();
const { limitDistance, setLimitDistance } = useLimitDistance(); const { limitDistance, setLimitDistance } = useLimitDistance();

View File

@ -45,7 +45,7 @@ const FleetEfficiencyInputComponent = (props: Props) => {
try { try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`); const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
if (response.status === 200) { if (response.status === 200) {
console.log(response.data);
setSelections(response.data.Data.measurements) setSelections(response.data.Data.measurements)
setDuration(response.data.Data.duration) setDuration(response.data.Data.duration)

View File

@ -45,7 +45,7 @@ const FlotingWidgetInput = (props: Props) => {
try { try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`); const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
if (response.status === 200) { if (response.status === 200) {
console.log(response.data);
setSelections(response.data.Data.measurements) setSelections(response.data.Data.measurements)
setDuration(response.data.Data.duration) setDuration(response.data.Data.duration)

View File

@ -45,7 +45,7 @@ const WarehouseThroughputInputComponent = (props: Props) => {
try { try {
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`); const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
if (response.status === 200) { if (response.status === 200) {
console.log(response.data);
setSelections(response.data.Data.measurements) setSelections(response.data.Data.measurements)
setDuration(response.data.Data.duration) setDuration(response.data.Data.duration)

View File

@ -42,16 +42,19 @@ const Design = () => {
const [elementColor, setElementColor] = useState("#6f42c1"); const [elementColor, setElementColor] = useState("#6f42c1");
const [showColorPicker, setShowColorPicker] = useState(false); const [showColorPicker, setShowColorPicker] = useState(false);
const [chartElements, setChartElements] = useState<ChartElement[]>([]); const [chartElements, setChartElements] = useState<ChartElement[]>([]);
const [selectedElementToStyle, setSelectedElementToStyle] = useState<string | null>(null); const [selectedElementToStyle, setSelectedElementToStyle] = useState<
string | null
>(null);
const [nameInput, setNameInput] = useState(""); const [nameInput, setNameInput] = useState("");
const chartRef = useRef<HTMLDivElement>(null); 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 // Initialize name input and extract elements when selectedChartId changes
useEffect(() => { useEffect(() => {
setNameInput(selectedChartId?.header || selectedChartId?.title || ""); setNameInput(selectedChartId?.header || selectedChartId?.title || "");
if (!chartRef.current) return; if (!chartRef.current) return;
const timer = setTimeout(() => { const timer = setTimeout(() => {
@ -65,13 +68,16 @@ const Design = () => {
}) })
.map((el, index) => { .map((el, index) => {
const tagName = el.tagName.toLowerCase(); 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() || ""; const textContent = el.textContent?.trim() || "";
let selector = tagName; let selector = tagName;
if (className && typeof className === "string") { 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) { if (classList.length > 0) {
selector += "." + classList.join("."); selector += "." + classList.join(".");
} }
@ -126,7 +132,13 @@ const Design = () => {
useEffect(() => { useEffect(() => {
applyStyles(); applyStyles();
}, [selectedFont, selectedSize, selectedWeight, elementColor, selectedElementToStyle]); }, [
selectedFont,
selectedSize,
selectedWeight,
elementColor,
selectedElementToStyle,
]);
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => { const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
if (!selectedChartId) return; if (!selectedChartId) return;
@ -138,7 +150,9 @@ const Design = () => {
setSelectedChartId(updatedChartId); setSelectedChartId(updatedChartId);
const updatedWidgets = widgets.map((widget) => const updatedWidgets = widgets.map((widget) =>
widget.id === selectedChartId.id ? { ...widget, ...updatedProperties } : widget widget.id === selectedChartId.id
? { ...widget, ...updatedProperties }
: widget
); );
setWidgets(updatedWidgets); setWidgets(updatedWidgets);
}; };
@ -146,7 +160,7 @@ const Design = () => {
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newName = e.target.value; const newName = e.target.value;
setNameInput(newName); setNameInput(newName);
if (selectedChartId?.title) { if (selectedChartId?.title) {
handleUpdateWidget({ title: newName }); handleUpdateWidget({ title: newName });
} else if (selectedChartId?.header) { } else if (selectedChartId?.header) {
@ -155,12 +169,12 @@ const Design = () => {
}; };
const defaultChartData = { const defaultChartData = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"], labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [ datasets: [
{ {
data: [65, 59, 80, 81, 56, 55, 40], data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: elementColor, backgroundColor: "#6f42c1",
borderColor: "#ffffff", borderColor: "#b392f0",
borderWidth: 1, borderWidth: 1,
}, },
], ],
@ -311,4 +325,4 @@ const Design = () => {
); );
}; };
export default Design; export default Design;

View File

@ -438,7 +438,6 @@ const Tools: React.FC = () => {
}`} }`}
onClick={() => { onClick={() => {
setIsPlaying(!isPlaying); setIsPlaying(!isPlaying);
setActiveTool("play");
}} }}
> >
<PlayIcon isActive={activeTool === "play"} /> <PlayIcon isActive={activeTool === "play"} />

View File

@ -96,16 +96,16 @@ export const DraggableWidget = ({
let deleteWidget = { let deleteWidget = {
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
widgetID: widget.id, widgetID: widget.id,
organization: organization organization: organization,
} };
console.log('deleteWidget: ', deleteWidget); console.log("deleteWidget: ", deleteWidget);
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-widget:delete", deleteWidget) visualizationSocket.emit("v2:viz-widget:delete", deleteWidget);
} }
const updatedWidgets = selectedZone.widgets.filter( const updatedWidgets = selectedZone.widgets.filter(
(w: Widget) => w.id !== widget.id (w: Widget) => w.id !== widget.id
); );
console.log('updatedWidgets: ', updatedWidgets); console.log("updatedWidgets: ", updatedWidgets);
setSelectedZone((prevZone: any) => ({ setSelectedZone((prevZone: any) => ({
...prevZone, ...prevZone,
widgets: updatedWidgets, widgets: updatedWidgets,
@ -168,10 +168,10 @@ export const DraggableWidget = ({
let duplicateWidget = { let duplicateWidget = {
organization: organization, organization: organization,
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
widget: duplicatedWidget widget: duplicatedWidget,
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-widget:add", duplicateWidget) visualizationSocket.emit("v2:viz-widget:add", duplicateWidget);
} }
setSelectedZone((prevZone: any) => ({ setSelectedZone((prevZone: any) => ({
...prevZone, ...prevZone,
@ -239,29 +239,95 @@ export const DraggableWidget = ({
onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop
} }
}; };
console.log("widget.type", widget.type);
// useClickOutside(chartWidget, () => { // useClickOutside(chartWidget, () => {
// setSelectedChartId(null); // setSelectedChartId(null);
// }); // });
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
console.log('isPanelHidden: ', isPanelHidden); 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);
};
}, []);
console.log("selectedChartId: ", widget);
return ( return (
<> <>
<style>
{`
:root {
--realTimeViz-container-width: ${canvasDimensions.width * 0.25}px;
--realTimeViz-container-height: ${canvasDimensions.height}px;
}
`}
</style>
<div <div
draggable draggable
key={widget.id} key={widget.id}
className={`chart-container ${(selectedChartId?.id === widget.id) && !isPlaying && "activeChart" className={`chart-container ${
}`} selectedChartId?.id === widget.id && !isPlaying && "activeChart"
}`}
onPointerDown={handlePointerDown} onPointerDown={handlePointerDown}
onDragStart={handleDragStart} onDragStart={handleDragStart}
onDragEnter={handleDragEnter} onDragEnter={handleDragEnter}
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDrop={handleDrop} onDrop={handleDrop}
style={{ style={{
// pointerEvents: isPanelHidden ? "none" : "auto", // Apply styles based on panel position
// opacity: isPanelHidden ? "0.1" : "0", 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.3}px - 2px)` // For left/right panels, set height
: undefined, // Don't set height if it's top or bottom
}} }}
ref={chartWidget} ref={chartWidget}
onClick={() => setSelectedChartId(widget)} onClick={() => setSelectedChartId(widget)}
@ -275,8 +341,9 @@ export const DraggableWidget = ({
{openKebabId === widget.id && ( {openKebabId === widget.id && (
<div className="kebab-options" ref={widgetRef}> <div className="kebab-options" ref={widgetRef}>
<div <div
className={`edit btn ${isPanelFull(widget.panel) ? "btn-blur" : "" className={`edit btn ${
}`} isPanelFull(widget.panel) ? "btn-blur" : ""
}`}
onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget} onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget}
> >
<div className="icon"> <div className="icon">
@ -350,3 +417,5 @@ export const DraggableWidget = ({
</> </>
); );
}; };
// in style if widget .panel is top or bottom set width if left or right set height

View File

@ -1,5 +1,5 @@
import { useThree } from "@react-three/fiber"; import { useThree } from "@react-three/fiber";
import React, { useState, useEffect, useRef } from "react"; import React, { useEffect, useRef } from "react";
import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../store/store"; import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../store/store";
import useModuleStore from "../../../store/useModuleStore"; import useModuleStore from "../../../store/useModuleStore";
import { ThreeState } from "../../../types/world/worldTypes"; import { ThreeState } from "../../../types/world/worldTypes";
@ -13,9 +13,19 @@ import { generateUniqueId } from "../../../functions/generateUniqueId";
import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget"; import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget";
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData"; import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
import { use3DWidget } from "../../../store/useDroppedObjectsStore"; import { use3DWidget } from "../../../store/useDroppedObjectsStore";
import { useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../store/useZone3DWidgetStore"; import { useEditWidgetOptionsStore, useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../store/useZone3DWidgetStore";
import { useWidgetStore } from "../../../store/useWidgetStore"; import { useWidgetStore } from "../../../store/useWidgetStore";
import EditWidgetOption from "../menu/EditWidgetOption"; import EditWidgetOption from "../menu/EditWidgetOption";
import { delete3dWidgetApi } from "../../../services/realTimeVisulization/zoneData/delete3dWidget";
import { update3dWidget, update3dWidgetRotation } from "../../../services/realTimeVisulization/zoneData/update3dWidget";
type WidgetData = {
id: string;
type: string;
position: [number, number, number];
rotation?: [number, number, number];
tempPosition?: [number, number, number];
};
export default function Dropped3dWidgets() { export default function Dropped3dWidgets() {
const { widgetSelect } = useAsset3dWidget(); const { widgetSelect } = useAsset3dWidget();
@ -23,22 +33,23 @@ export default function Dropped3dWidgets() {
const { raycaster, gl, scene, mouse, camera }: ThreeState = useThree(); const { raycaster, gl, scene, mouse, camera }: ThreeState = useThree();
const { widgetSubOption } = useWidgetSubOption(); const { widgetSubOption } = useWidgetSubOption();
const { selectedZone } = useSelectedZoneStore(); const { selectedZone } = useSelectedZoneStore();
const { top, setTop } = useTopData() const { top, setTop } = useTopData();
const { left, setLeft } = useLeftData() const { left, setLeft } = useLeftData();
const { rightSelect, setRightSelect } = useRightSelected() const { rightSelect, setRightSelect } = useRightSelected();
const { editWidgetOptions, setEditWidgetOptions } = useEditWidgetOptionsStore()
// ✅ Use Zustand Store instead of useState const { zoneWidgetData, setZoneWidgetData, addWidget, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore();
const { zoneWidgetData, setZoneWidgetData, addWidget, updateWidgetPosition } = useZoneWidgetStore();
const { setWidgets3D } = use3DWidget(); const { setWidgets3D } = use3DWidget();
const { visualizationSocket } = useSocketStore(); const { visualizationSocket } = useSocketStore();
const { rightClickSelected, setRightClickSelected } = useRightClickSelected() const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Floor plane for horizontal move const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Floor plane for horizontal move
const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move
const planeIntersect = useRef(new THREE.Vector3()); const planeIntersect = useRef(new THREE.Vector3());
// let [verticalPlane, setFloorPlanesVertical] = useState( // const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
// new THREE.Plane(new THREE.Vector3(0, 1, 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 });
useEffect(() => { useEffect(() => {
if (activeModule !== "visualization") return; if (activeModule !== "visualization") return;
@ -48,16 +59,18 @@ export default function Dropped3dWidgets() {
const organization = email?.split("@")[1]?.split(".")[0]; const organization = email?.split("@")[1]?.split(".")[0];
async function get3dWidgetData() { async function get3dWidgetData() {
let result = await get3dWidgetZoneData(selectedZone.zoneId, organization); const result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
console.log('result: ', result);
setWidgets3D(result); setWidgets3D(result);
const formattedWidgets = result.map((widget: any) => ({ const formattedWidgets = result.map((widget: WidgetData) => ({
id: widget.id, id: widget.id,
type: widget.type, type: widget.type,
position: widget.position, position: widget.position,
rotation: widget.rotation || [0, 0, 0],
})); }));
setZoneWidgetData(selectedZone.zoneId, formattedWidgets); setZoneWidgetData(selectedZone.zoneId, formattedWidgets);
} }
@ -91,28 +104,24 @@ export default function Dropped3dWidgets() {
if (intersects.length > 0) { if (intersects.length > 0) {
const { x, y, z } = intersects[0].point; const { x, y, z } = intersects[0].point;
const newWidget = { const newWidget: WidgetData = {
id: generateUniqueId(), id: generateUniqueId(),
type: widgetSelect, type: widgetSelect,
position: [x, y, z] as [number, number, number], position: [x, y, z],
rotation: [0, 0, 0],
}; };
let add3dWidget = { const add3dWidget = {
organization: organization, organization: organization,
widget: newWidget, widget: newWidget,
zoneId: selectedZone.zoneId zoneId: selectedZone.zoneId
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget) visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget);
} }
// let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget);
//
// if (response.message === "Widget created successfully") {
addWidget(selectedZone.zoneId, newWidget); addWidget(selectedZone.zoneId, newWidget);
// }
} }
}; };
@ -128,63 +137,101 @@ export default function Dropped3dWidgets() {
if (!rightClickSelected) return; if (!rightClickSelected) return;
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]; const organization = email?.split("@")[1]?.split(".")[0];
if (rightSelect === "Duplicate") { if (rightSelect === "Duplicate") {
const widgetToDuplicate = activeZoneWidgets.find(w => w.id === rightClickSelected); async function duplicateWidget() {
if (!widgetToDuplicate) return; const widgetToDuplicate = activeZoneWidgets.find((w: WidgetData) => w.id === rightClickSelected);
const newWidget = { if (!widgetToDuplicate) return;
id: generateUniqueId(), const newWidget: WidgetData = {
type: widgetToDuplicate.type, id: generateUniqueId(),
position: [ type: widgetToDuplicate.type,
widgetToDuplicate.position[0] + 0.5, // Slightly shift position position: [
widgetToDuplicate.position[1], widgetToDuplicate.position[0] + 0.5,
widgetToDuplicate.position[2] + 0.5, widgetToDuplicate.position[1],
] as [number, number, number], widgetToDuplicate.position[2] + 0.5,
}; ],
let add3dWidget = { rotation: widgetToDuplicate.rotation || [0, 0, 0],
organization, };
widget: newWidget, const adding3dWidget = {
zoneId: selectedZone.zoneId organization: organization,
}; widget: newWidget,
// if (visualizationSocket) { zoneId: selectedZone.zoneId
// visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget); };
// } if (visualizationSocket) {
addWidget(selectedZone.zoneId, newWidget); visualizationSocket.emit("v2:viz-3D-widget:add", adding3dWidget);
setRightSelect(null); }
setRightClickSelected(null); // let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget)
// console.log('response: ', response);
addWidget(selectedZone.zoneId, newWidget);
setRightSelect(null);
setRightClickSelected(null);
}
duplicateWidget()
} }
if (rightSelect === "Delete") { if (rightSelect === "Delete") {
let deleteWidget = { const deleteWidgetApi = async () => {
organization, try {
widgetId: rightClickSelected, const deleteWidget = {
zoneId: selectedZone.zoneId organization,
id: rightClickSelected,
zoneId: selectedZone.zoneId,
};
console.log('deleteWidget: ', deleteWidget);
if (visualizationSocket) {
visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget);
}
// Call the API to delete the widget
// const response = await delete3dWidgetApi(selectedZone.zoneId, organization, rightClickSelected);
setZoneWidgetData(
selectedZone.zoneId,
activeZoneWidgets.filter((w: WidgetData) => w.id !== rightClickSelected)
);
} catch (error) {
console.error("Error deleting widget:", error);
} finally {
setRightClickSelected(null);
setRightSelect(null);
}
}; };
// if (visualizationSocket) {
// visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget);
// }
setZoneWidgetData(selectedZone.zoneId, activeZoneWidgets.filter(w => w.id !== rightClickSelected));
setRightClickSelected(null);
setRightSelect(null);
}
if (rightSelect === "Horizontal Move") {
deleteWidgetApi();
} }
if (rightSelect === "Vertical Move") {
}
}, [rightSelect, rightClickSelected]); }, [rightSelect, rightClickSelected]);
useEffect(() => { useEffect(() => {
const handleMouseMove = (event: MouseEvent) => {
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const handleMouseDown = (event: MouseEvent) => {
if (!rightClickSelected || !rightSelect) return; if (!rightClickSelected || !rightSelect) return;
if (rightSelect === "RotateX" || rightSelect === "RotateY") {
mouseStartRef.current = { x: event.clientX, y: event.clientY };
const selectedZone = Object.keys(zoneWidgetData).find(zoneId => const selectedZone = Object.keys(zoneWidgetData).find((zoneId: string) =>
zoneWidgetData[zoneId].some(widget => widget.id === rightClickSelected) zoneWidgetData[zoneId].some((widget: WidgetData) => widget.id === rightClickSelected)
);
if (!selectedZone) return;
const selectedWidget = zoneWidgetData[selectedZone].find((widget: WidgetData) => widget.id === rightClickSelected);
if (selectedWidget) {
rotationStartRef.current = selectedWidget.rotation || [0, 0, 0];
}
}
};
const handleMouseMove = (event: MouseEvent) => {
if (!rightClickSelected || !rightSelect) return;
const selectedZone = Object.keys(zoneWidgetData).find((zoneId: string) =>
zoneWidgetData[zoneId].some((widget: WidgetData) => widget.id === rightClickSelected)
); );
if (!selectedZone) return; if (!selectedZone) return;
const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected); const selectedWidget = zoneWidgetData[selectedZone].find((widget: WidgetData) => widget.id === rightClickSelected);
if (!selectedWidget) return; if (!selectedWidget) return;
const rect = gl.domElement.getBoundingClientRect(); const rect = gl.domElement.getBoundingClientRect();
@ -194,72 +241,200 @@ export default function Dropped3dWidgets() {
raycaster.setFromCamera(mouse, camera); raycaster.setFromCamera(mouse, camera);
if (rightSelect === "Horizontal Move" && raycaster.ray.intersectPlane(plane.current, planeIntersect.current)) { if (rightSelect === "Horizontal Move" && raycaster.ray.intersectPlane(plane.current, planeIntersect.current)) {
const newPosition: [number, number, number] = [
updateWidgetPosition(selectedZone, rightClickSelected, [
planeIntersect.current.x, planeIntersect.current.x,
selectedWidget.position[1], selectedWidget.position[1],
planeIntersect.current.z planeIntersect.current.z
]); ];
updateWidgetPosition(selectedZone, rightClickSelected, newPosition);
} }
if (rightSelect === "Vertical Move") { if (rightSelect === "Vertical Move") {
if (raycaster.ray.intersectPlane(verticalPlane.current, planeIntersect.current)) { if (raycaster.ray.intersectPlane(verticalPlane.current, planeIntersect.current)) {
updateWidgetPosition(selectedZone, rightClickSelected, [ updateWidgetPosition(selectedZone, rightClickSelected, [
selectedWidget.position[0], selectedWidget.position[0],
planeIntersect.current.y, // Ensure Y value updates correctly planeIntersect.current.y,
selectedWidget.position[2] selectedWidget.position[2]
]); ]);
} else {
console.log("No Intersection with Vertical Plane");
} }
} }
if (rightSelect === "RotateX") {
const deltaX = event.clientX - mouseStartRef.current.x;
const rotationSpeed = 0.03;
const newRotation: [number, number, number] = [
rotationStartRef.current[0] + deltaX * rotationSpeed,
rotationStartRef.current[1],
rotationStartRef.current[2]
];
updateWidgetRotation(selectedZone, rightClickSelected, newRotation);
}
if (rightSelect === "RotateY") {
const deltaY = event.clientY - mouseStartRef.current.y;
const rotationSpeed = 0.03;
const newRotation: [number, number, number] = [
rotationStartRef.current[0],
rotationStartRef.current[1] + deltaY * rotationSpeed,
rotationStartRef.current[2]
];
updateWidgetRotation(selectedZone, rightClickSelected, newRotation);
}
if (rightSelect === "RotateZ") {
const deltaX = event.movementX;
const rotationSpeed = 0.03;
const currentRotation = selectedWidget.rotation || [0, 0, 0];
const newRotation: [number, number, number] = [
currentRotation[0],
currentRotation[1],
currentRotation[2] + deltaX * rotationSpeed
];
updateWidgetRotation(selectedZone, rightClickSelected, newRotation);
}
}; };
const handleMouseUp = () => { const handleMouseUp = () => {
if (!rightClickSelected || !rightSelect) return;
const selectedZone = Object.keys(zoneWidgetData).find(zoneId =>
zoneWidgetData[zoneId].some(widget => widget.id === rightClickSelected)
);
if (!selectedZone) return;
if (rightClickSelected && (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move")) { 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 = {
organization: organization,
zoneId: selectedZone,
id: rightClickSelected,
position: lastPosition,
}
if (visualizationSocket) {
visualizationSocket.emit("v2:viz-3D-widget:modifyPositionRotation", updatingPosition);
}
setTimeout(() => {
setRightClickSelected(null);
setRightSelect(null);
}, 50);
} }
}; 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 = {
organization: organization,
zoneId: selectedZone,
id: rightClickSelected,
rotation: lastRotation,
}
if (visualizationSocket) {
visualizationSocket.emit("v2:viz-3D-widget:modifyPositionRotation", updatingRotation);
}
}
// Attach events to window instead of gl.domElement // Reset selection
setTimeout(() => {
setRightClickSelected(null);
setRightSelect(null);
}, 50);
};
window.addEventListener("mousedown", handleMouseDown);
window.addEventListener("mousemove", handleMouseMove); window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp); window.addEventListener("mouseup", handleMouseUp);
return () => { return () => {
window.removeEventListener("mousedown", handleMouseDown);
window.removeEventListener("mousemove", handleMouseMove); window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp); window.removeEventListener("mouseup", handleMouseUp);
}; };
}, [rightClickSelected, rightSelect, zoneWidgetData, gl]); }, [rightClickSelected, rightSelect, zoneWidgetData, gl]);
return ( return (
<> <>
{activeZoneWidgets.map(({ id, type, position }) => { {activeZoneWidgets.map(({ id, type, position, rotation = [0, 0, 0] }: WidgetData) => {
const handleRightClick = (event: React.MouseEvent) => { const handleRightClick = (event: React.MouseEvent, id: string) => {
event.preventDefault(); event.preventDefault();
setRightClickSelected(id) const canvasElement = document.getElementById("real-time-vis-canvas");
if (!canvasElement) throw new Error("Canvas element not found");
const canvasRect = canvasElement.getBoundingClientRect();
const relativeX = event.clientX - canvasRect.left;
const relativeY = event.clientY - canvasRect.top;
setEditWidgetOptions(true);
setRightClickSelected(id);
setTop(relativeY);
setLeft(relativeX);
}; };
switch (type) { switch (type) {
case "ui-Widget 1": case "ui-Widget 1":
return <ProductionCapacity key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />; return (
<ProductionCapacity
key={id}
id={id}
type={type}
position={position}
rotation={rotation}
onContextMenu={(e) => handleRightClick(e, id)}
/>
);
case "ui-Widget 2": case "ui-Widget 2":
return <ReturnOfInvestment key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />; return (
<ReturnOfInvestment
key={id}
id={id}
type={type}
position={position}
rotation={rotation}
onContextMenu={(e) => handleRightClick(e, id)}
/>
);
case "ui-Widget 3": case "ui-Widget 3":
return <StateWorking key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />; return (
<StateWorking
key={id}
id={id}
type={type}
position={position}
rotation={rotation}
onContextMenu={(e) => handleRightClick(e, id)}
/>
);
case "ui-Widget 4": case "ui-Widget 4":
return <Throughput key={id} id={id} type={type} position={position} onContextMenu={handleRightClick} />; return (
<Throughput
key={id}
id={id}
type={type}
position={position}
rotation={rotation}
onContextMenu={(e) => handleRightClick(e, id)}
/>
);
default: default:
return null; return null;
} }
})} })}
</> </>
); );
} }

View File

@ -126,11 +126,12 @@ const DroppedObjects: React.FC = () => {
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]; const organization = email?.split("@")[1]?.split(".")[0];
let deleteFloatingWidget = { let deleteFloatingWidget = {
floatWidgetID: id, floatWidgetID: id,
organization: organization, organization: organization,
zoneId: zone.zoneId, zoneId: zone.zoneId
}; }
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget); visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget);
@ -143,7 +144,9 @@ const DroppedObjects: React.FC = () => {
// if (res.message === "FloatingWidget deleted successfully") { // if (res.message === "FloatingWidget deleted successfully") {
// deleteObject(zoneName, id, index); // Call the deleteObject method from the store // deleteObject(zoneName, id, index); // Call the deleteObject method from the store
// } // }
} catch (error) {} } catch (error) {
}
} }
const handlePointerDown = (event: React.PointerEvent, index: number) => { const handlePointerDown = (event: React.PointerEvent, index: number) => {
@ -458,15 +461,15 @@ const DroppedObjects: React.FC = () => {
position: boundedPosition, position: boundedPosition,
}, },
index: draggingIndex.index, index: draggingIndex.index,
zoneId: zone.zoneId, zoneId: zone.zoneId
}; }
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget); visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget);
} }
// if (response.message === "Widget updated successfully") { // if (response.message === "Widget updated successfully") {
console.log("boundedPosition: ", boundedPosition); console.log('boundedPosition: ', boundedPosition);
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
// } // }
@ -509,43 +512,37 @@ const DroppedObjects: React.FC = () => {
{zone.objects.map((obj, index) => ( {zone.objects.map((obj, index) => (
<div <div
key={`${zoneName}-${index}`} key={`${zoneName}-${index}`}
className={`${obj.className} ${ className={`${obj.className} ${selectedChartId?.id === obj.id && "activeChart"}`}
selectedChartId?.id === obj.id && !isPlaying && "activeChart"
}`}
ref={chartWidget} ref={chartWidget}
style={{ style={{
position: "absolute", position: "absolute",
top: top:
typeof obj.position.top === "number" typeof obj.position.top === "number"
? `calc(${obj.position.top}px + ${ ? `calc(${obj.position.top}px + ${isPlaying && selectedZone.activeSides.includes("top")
isPlaying && selectedZone.activeSides.includes("top") ? 90
? 90 : 0
: 0 }px)`
}px)`
: "auto", : "auto",
left: left:
typeof obj.position.left === "number" typeof obj.position.left === "number"
? `calc(${obj.position.left}px + ${ ? `calc(${obj.position.left}px + ${isPlaying && selectedZone.activeSides.includes("left")
isPlaying && selectedZone.activeSides.includes("left") ? 90
? 90 : 0
: 0 }px)`
}px)`
: "auto", : "auto",
right: right:
typeof obj.position.right === "number" typeof obj.position.right === "number"
? `calc(${obj.position.right}px + ${ ? `calc(${obj.position.right}px + ${isPlaying && selectedZone.activeSides.includes("right")
isPlaying && selectedZone.activeSides.includes("right") ? 90
? 90 : 0
: 0 }px)`
}px)`
: "auto", : "auto",
bottom: bottom:
typeof obj.position.bottom === "number" typeof obj.position.bottom === "number"
? `calc(${obj.position.bottom}px + ${ ? `calc(${obj.position.bottom}px + ${isPlaying && selectedZone.activeSides.includes("bottom")
isPlaying && selectedZone.activeSides.includes("bottom") ? 90
? 90 : 0
: 0 }px)`
}px)`
: "auto", : "auto",
}} }}
onPointerDown={(event) => { onPointerDown={(event) => {

View File

@ -64,6 +64,59 @@ const Panel: React.FC<PanelProps> = ({
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { visualizationSocket } = useSocketStore(); 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( const getPanelStyle = useMemo(
() => (side: Side) => { () => (side: Side) => {
const currentIndex = selectedZone.panelOrder.indexOf(side); const currentIndex = selectedZone.panelOrder.indexOf(side);
@ -72,36 +125,50 @@ const Panel: React.FC<PanelProps> = ({
const rightActive = previousPanels.includes("right"); const rightActive = previousPanels.includes("right");
const topActive = previousPanels.includes("top"); const topActive = previousPanels.includes("top");
const bottomActive = previousPanels.includes("bottom"); const bottomActive = previousPanels.includes("bottom");
const panelSize = isPlaying ? 300 : 210;
// Dynamic panel sizes based on canvas width
const panelSizeWidth = Math.max(canvasDimensions.width * 0.165, 200); // Ensure minimum width of 200px
const panelSizeHeight = Math.max(canvasDimensions.width * 0.13, 200); // Ensure minimum height of 200px
switch (side) { switch (side) {
case "top": case "top":
case "bottom": case "bottom":
return { return {
minWidth: "200px", // Minimum width constraint
width: `calc(100% - ${ width: `calc(100% - ${
(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0) (leftActive ? panelSizeWidth : 0) + (rightActive ? panelSizeWidth : 0)
}px)`, }px)`,
height: `${panelSize - 2}px`, minHeight: "200px", // Minimum height constraint
left: leftActive ? `${panelSize}px` : "0", height: `${panelSizeHeight - 2}px`, // Subtracting for border or margin
right: rightActive ? `${panelSize}px` : "0", left: leftActive ? `${panelSizeWidth}px` : "0",
right: rightActive ? `${panelSizeWidth}px` : "0",
[side]: "0", [side]: "0",
}; };
case "left": case "left":
case "right": case "right":
return { return {
width: `${panelSize - 2}px`, minWidth: "200px", // Minimum width constraint
width: `${panelSizeWidth - 2}px`, // Subtracting for border or margin
minHeight: "200px", // Minimum height constraint
height: `calc(100% - ${ height: `calc(100% - ${
(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0) (topActive ? panelSizeHeight : 0) + (bottomActive ? panelSizeHeight : 0)
}px)`, }px)`,
top: topActive ? `${panelSize}px` : "0", top: topActive ? `${panelSizeHeight}px` : "0",
bottom: bottomActive ? `${panelSize}px` : "0", bottom: bottomActive ? `${panelSizeHeight}px` : "0",
[side]: "0", [side]: "0",
}; };
default: default:
return {}; return {};
} }
}, },
[selectedZone.panelOrder, isPlaying] [
selectedZone.panelOrder,
isPlaying,
canvasDimensions.width,
canvasDimensions.height,
]
); );
const handleDrop = (e: React.DragEvent, panel: Side) => { const handleDrop = (e: React.DragEvent, panel: Side) => {
@ -153,10 +220,10 @@ const Panel: React.FC<PanelProps> = ({
let addWidget = { let addWidget = {
organization: organization, organization: organization,
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
widget: newWidget widget: newWidget,
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-widget:add", addWidget) visualizationSocket.emit("v2:viz-widget:add", addWidget);
} }
setSelectedZone((prev) => ({ setSelectedZone((prev) => ({
...prev, ...prev,
@ -165,7 +232,6 @@ const Panel: React.FC<PanelProps> = ({
try { try {
// let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); // let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
// if (response.message === "Widget created successfully") { // if (response.message === "Widget created successfully") {
// setSelectedZone((prev) => ({ // setSelectedZone((prev) => ({
// ...prev, // ...prev,
@ -175,7 +241,6 @@ const Panel: React.FC<PanelProps> = ({
} catch (error) { } catch (error) {
console.error("Error adding widget:", error); console.error("Error adding widget:", error);
} }
}; };
useEffect(() => { useEffect(() => {
@ -281,3 +346,5 @@ const Panel: React.FC<PanelProps> = ({
}; };
export default Panel; export default Panel;
// canvasDimensions.width as percent

View File

@ -7,7 +7,6 @@ import DisplayZone from "./DisplayZone";
import Scene from "../../../modules/scene/scene"; import Scene from "../../../modules/scene/scene";
import useModuleStore from "../../../store/useModuleStore"; import useModuleStore from "../../../store/useModuleStore";
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
import { import {
useAsset3dWidget, useAsset3dWidget,
@ -24,7 +23,11 @@ import RenderOverlay from "../../templates/Overlay";
import ConfirmationPopup from "../../layout/confirmationPopup/ConfirmationPopup"; import ConfirmationPopup from "../../layout/confirmationPopup/ConfirmationPopup";
import DroppedObjects from "./DroppedFloatingWidgets"; import DroppedObjects from "./DroppedFloatingWidgets";
import EditWidgetOption from "../menu/EditWidgetOption"; import EditWidgetOption from "../menu/EditWidgetOption";
import { useRightClickSelected } from "../../../store/useZone3DWidgetStore"; import {
useEditWidgetOptionsStore,
useRightClickSelected,
useRightSelected,
} from "../../../store/useZone3DWidgetStore";
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
@ -58,8 +61,10 @@ const RealTimeVisulization: React.FC = () => {
const [zonesData, setZonesData] = useState<FormattedZoneData>({}); const [zonesData, setZonesData] = useState<FormattedZoneData>({});
const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { rightSelect, setRightSelect } = useRightSelected();
const { rightClickSelected, setRightClickSelected } = useRightClickSelected() const { editWidgetOptions, setEditWidgetOptions } =
useEditWidgetOptionsStore();
const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false); const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
const [floatingWidgets, setFloatingWidgets] = useState< const [floatingWidgets, setFloatingWidgets] = useState<
@ -69,6 +74,7 @@ const RealTimeVisulization: React.FC = () => {
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
const { visualizationSocket } = useSocketStore(); const { visualizationSocket } = useSocketStore();
useEffect(() => { useEffect(() => {
async function GetZoneData() { async function GetZoneData() {
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
@ -96,7 +102,7 @@ const RealTimeVisulization: React.FC = () => {
{} {}
); );
setZonesData(formattedData); setZonesData(formattedData);
} catch (error) { } } catch (error) {}
} }
GetZoneData(); GetZoneData();
@ -142,8 +148,8 @@ const RealTimeVisulization: React.FC = () => {
const relativeX = event.clientX - canvasRect.left; const relativeX = event.clientX - canvasRect.left;
const relativeY = event.clientY - canvasRect.top; const relativeY = event.clientY - canvasRect.top;
const newPosition = determinePosition(canvasRect, relativeX, relativeY) const newPosition = determinePosition(canvasRect, relativeX, relativeY);
console.log('newPosition: ', newPosition); console.log("newPosition: ", newPosition);
const newObject = { const newObject = {
...droppedData, ...droppedData,
id: generateUniqueId(), id: generateUniqueId(),
@ -162,12 +168,12 @@ const RealTimeVisulization: React.FC = () => {
let addFloatingWidget = { let addFloatingWidget = {
organization: organization, organization: organization,
widget: newObject, widget: newObject,
zoneId: selectedZone.zoneId zoneId: selectedZone.zoneId,
} };
console.log('newObject: ', newObject); console.log("newObject: ", newObject);
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget) visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
} }
// let response = await addingFloatingWidgets( // let response = await addingFloatingWidgets(
@ -194,76 +200,134 @@ const RealTimeVisulization: React.FC = () => {
], ],
}, },
})); }));
} catch (error) { } } catch (error) {}
}; };
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
const editWidgetOptions = document.querySelector(
".editWidgetOptions-wrapper"
);
if (
editWidgetOptions &&
!editWidgetOptions.contains(event.target as Node)
) {
setRightClickSelected(null);
setRightSelect(null);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [setRightClickSelected]);
// Add this useEffect hook to your component
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
const editWidgetOptions = document.querySelector(
".editWidgetOptions-wrapper"
);
if (
editWidgetOptions &&
!editWidgetOptions.contains(event.target as Node)
) {
setRightClickSelected(null);
setRightSelect(null);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [setRightClickSelected]);
function handleRightClickSel(){}
return ( 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 <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%" : "",
}}
>
<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" className="scene-container"
style={{ style={{
height: "100%", height: "100%",
width: "100%", width: "100%",
borderRadius: borderRadius:
isPlaying || activeModule !== "visualization" ? "" : "6px", isPlaying || activeModule !== "visualization" ? "" : "6px",
}} }}
onDrop={(event) => handleDrop(event)} onDrop={(event) => handleDrop(event)}
onDragOver={(event) => event.preventDefault()} onDragOver={(event) => event.preventDefault()}
> >
<Scene /> <Scene />
</div> </div> */}
{activeModule === "visualization" && selectedZone.zoneName !== "" && <DroppedObjects />} {activeModule === "visualization" && selectedZone.zoneName !== "" && (
{activeModule === "visualization" && <SocketRealTimeViz />} <DroppedObjects />
{activeModule === "visualization" && widgetSubOption === "3D" && rightClickSelected && <EditWidgetOption
options={["Duplicate", "Vertical Move", "Horizontal Move", "Delete"]}
/>}
{activeModule === "visualization" && (
<>
<DisplayZone
zonesData={zonesData}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
{!isPlaying && selectedZone?.zoneName !== "" && (
<AddButtons
hiddenPanels={hiddenPanels}
setHiddenPanels={setHiddenPanels}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
)} )}
{activeModule === "visualization" && <SocketRealTimeViz />}
<Panel {activeModule === "visualization" &&
selectedZone={selectedZone} editWidgetOptions &&
setSelectedZone={setSelectedZone} rightClickSelected && (
hiddenPanels={hiddenPanels} <EditWidgetOption
setZonesData={setZonesData} options={[
/> "Duplicate",
</> "Vertical Move",
)} "Horizontal Move",
</div> "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>
</>
); );
}; };

View File

@ -31,7 +31,6 @@ interface ListProps {
} }
const List: React.FC<ListProps> = ({ items = [], remove }) => { const List: React.FC<ListProps> = ({ items = [], remove }) => {
console.log("items: ", items);
const { activeModule, setActiveModule } = useModuleStore(); const { activeModule, setActiveModule } = useModuleStore();
const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { setSubModule } = useSubModuleStore(); const { setSubModule } = useSubModuleStore();

View File

@ -1,26 +1,48 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useLeftData, useRightSelected, useTopData } from "../../../store/useZone3DWidgetStore"; import {
useEditWidgetOptionsStore,
useLeftData,
useRightClickSelected,
useRightSelected,
useTopData,
} from "../../../store/useZone3DWidgetStore";
interface EditWidgetOptionProps { interface EditWidgetOptionProps {
options: string[]; options: string[];
} }
const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({ options }) => { const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({
const { top, setTop } = useTopData() options,
const { left, setLeft } = useLeftData() }) => {
const { rightSelect, setRightSelect } = useRightSelected() const { top } = useTopData();
const { left } = useLeftData();
const { setRightSelect } = useRightSelected();
const { setEditWidgetOptions } = useEditWidgetOptionsStore();
useEffect(() => { useEffect(() => {
console.log('left: ', left); }, [top, left]);
console.log('top: ', top);
}, [top, left])
return ( return (
<div className="editWidgetOptions-wrapper" style={{ top: top + "px", left: left + "px" }}> <div
className="editWidgetOptions-wrapper"
style={{
position: "absolute",
top: `${top}px`,
left: `${left}px`,
zIndex: 10000,
}}
>
<div className="editWidgetOptions"> <div className="editWidgetOptions">
{options.map((option, index) => ( {options.map((option, index) => (
<div className="option" key={index} onClick={(e) => setRightSelect(option)}> <div
className="option"
key={index}
onClick={(e) => {
setRightSelect(option);
setEditWidgetOptions(false);
}}
>
{option} {option}
</div> </div>
))} ))}

View File

@ -238,7 +238,7 @@ const BarGraphComponent = ({
}; };
useEffect(() => { useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[]) },[])
// Memoize Theme Colors // Memoize Theme Colors

View File

@ -51,7 +51,7 @@ const DoughnutGraphComponent = ({
}; };
useEffect(() => { useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[]) },[])
// Memoize Theme Colors // Memoize Theme Colors

View File

@ -51,7 +51,7 @@ const LineGraphComponent = ({
}; };
useEffect(() => { useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[]) },[])
// Memoize Theme Colors // Memoize Theme Colors

View File

@ -237,7 +237,7 @@ const PieChartComponent = ({
}; };
useEffect(() => { useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[]) },[])
// Memoize Theme Colors // Memoize Theme Colors

View File

@ -51,7 +51,7 @@ const PolarAreaGraphComponent = ({
}; };
useEffect(() => { useEffect(() => {
console.log("titleeeeeeeeeeeeeeeeeee",title);
},[]) },[])
// Memoize Theme Colors // Memoize Theme Colors

View File

@ -1,24 +1,36 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons"; import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import { useActiveTool } from "../../../store/store";
import {
useAnimationPlaySpeed,
usePauseButtonStore,
usePlayButtonStore,
useResetButtonStore,
} from "../../../store/usePlayButtonStore";
const SimulationPlayer: React.FC = () => { const SimulationPlayer: React.FC = () => {
const [speed, setSpeed] = useState<number>(1); const { speed, setSpeed } = useAnimationPlaySpeed();
const [playSimulation, setPlaySimulation] = useState(false); const [playSimulation, setPlaySimulation] = useState(false);
const { setIsPlaying } = usePlayButtonStore(); const { setIsPlaying } = usePlayButtonStore();
const sliderRef = useRef<HTMLDivElement>(null); const sliderRef = useRef<HTMLDivElement>(null);
const isDragging = useRef(false); const isDragging = useRef(false);
const { setActiveTool } = useActiveTool();
const { isPaused, setIsPaused } = usePauseButtonStore();
const { isReset, setReset } = useResetButtonStore();
// Button functions // Button functions
const handleReset = () => { const handleReset = () => {
setReset(true);
setSpeed(1); setSpeed(1);
}; };
const handlePlayStop = () => { const handlePlayStop = () => {
setIsPaused(!isPaused);
setPlaySimulation(!playSimulation); setPlaySimulation(!playSimulation);
}; };
const handleExit = () => { const handleExit = () => {
setPlaySimulation(false); setPlaySimulation(false);
setIsPlaying(false); setIsPlaying(false);
setActiveTool("cursor")
}; };
// Slider functions starts // Slider functions starts
@ -27,7 +39,7 @@ const SimulationPlayer: React.FC = () => {
}; };
const calculateHandlePosition = () => { const calculateHandlePosition = () => {
return ((speed - 0.5) / (50 - 0.5)) * 100; return ((speed - 0.5) / (8 - 0.5)) * 100;
}; };
const handleMouseDown = () => { const handleMouseDown = () => {
@ -115,7 +127,7 @@ const SimulationPlayer: React.FC = () => {
<input <input
type="range" type="range"
min="0.5" min="0.5"
max="50" max="8"
step="0.1" step="0.1"
value={speed} value={speed}
onChange={handleSpeedChange} onChange={handleSpeedChange}
@ -123,7 +135,7 @@ const SimulationPlayer: React.FC = () => {
/> />
</div> </div>
</div> </div>
<div className="max-value">50x</div> <div className="max-value">8x</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,111 +1,68 @@
import PolygonGenerator from "./polygonGenerator"; import { useEffect, useState } from "react";
import { useThree } from "@react-three/fiber"; import { Line } from "@react-three/drei";
import { useEffect, useMemo, useRef, useState } from "react"; import { useNavMesh, useSimulationStates } from "../../../store/store";
import * as THREE from "three";
import * as Types from "../../../types/world/worldTypes";
import PathNavigator from "./pathNavigator"; import PathNavigator from "./pathNavigator";
import NavMeshDetails from "./navMeshDetails"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import {
useSelectedActionSphere,
useSimulationPaths,
} from "../../../store/store";
const Agv = ({ type PathPoints = {
lines, modelUuid: string;
plane, modelSpeed: number;
}: { bufferTime: number;
lines: Types.RefLines; points: { x: number; y: number; z: number }[];
plane: Types.RefMesh; hitCount: number;
}) => { };
const [pathPoints, setPathPoints] = useState<
{
uuid: string;
points: { x: number; y: number; z: number }[];
}[]
>([]);
const { simulationPaths } = useSimulationPaths();
const { selectedActionSphere } = useSelectedActionSphere();
useEffect(() => {
if (!Array.isArray(simulationPaths)) {
} else {
let agvModels = simulationPaths.filter(
(val: any) => val.modelName === "agv"
);
let findMesh = agvModels.filter( const Agv = () => {
(val: any) => const [pathPoints, setPathPoints] = useState<PathPoints[]>([]);
val.modeluuid === selectedActionSphere?.path?.modeluuid && const { simulationStates } = useSimulationStates();
val.type === "Vehicle" const { navMesh } = useNavMesh();
); const { isPlaying } = usePlayButtonStore();
const result = useEffect(() => {
findMesh.length > 0 && if (simulationStates.length > 0) {
findMesh[0].type === "Vehicle" &&
typeof findMesh[0].point?.actions.start === "object" &&
typeof findMesh[0].point?.actions.end === "object" &&
"x" in findMesh[0].point.actions.start &&
"y" in findMesh[0].point.actions.start &&
"x" in findMesh[0].point.actions.end &&
"y" in findMesh[0].point.actions.end
? [
{
uuid: findMesh[0].modeluuid, // Ensure it's a number
points: [ const agvModels = simulationStates.filter((val) => val.modelName === "agv" && val.type === "Vehicle");
{
x: findMesh[0].position[0],
y: findMesh[0].position[1],
z: findMesh[0].position[2],
},
{
x: findMesh[0].point.actions.start.x,
y: 0,
z: findMesh[0].point.actions.start.y,
},
{
x: findMesh[0].point.actions.end.x,
y: 0,
z: findMesh[0].point.actions.end.y,
},
],
},
]
: [];
if (result.length > 0) {
setPathPoints((prev) => {
const existingUUIDs = new Set(prev.map((item) => item.uuid));
const newItems = result.filter(
(item) => !existingUUIDs.has(item.uuid)
);
return [...prev, ...newItems];
});
}
}
}, [simulationPaths, selectedActionSphere]);
let groupRef = useRef() as Types.RefGroup; const newPathPoints = agvModels.filter((model: any) => model.points && model.points.actions && typeof model.points.actions.start === "object" && typeof model.points.actions.end === "object" && "x" in model.points.actions.start && "y" in model.points.actions.start && "x" in model.points.actions.end && "y" in model.points.actions.end)
const [navMesh, setNavMesh] = useState(); .map((model: any) => ({
modelUuid: model.modeluuid,
modelSpeed: model.points.speed,
bufferTime: model.points.actions.buffer,
hitCount: model.points.actions.hitCount,
points: [
{ x: model.position[0], y: model.position[1], z: model.position[2] },
{ x: model.points.actions.start.x, y: 0, z: model.points.actions.start.y },
{ x: model.points.actions.end.x, y: 0, z: model.points.actions.end.y },
],
}));
return ( setPathPoints(newPathPoints);
<> }
<PolygonGenerator groupRef={groupRef} lines={lines} plane={plane} /> }, [simulationStates]);
<NavMeshDetails
lines={lines} return (
setNavMesh={setNavMesh} <>
groupRef={groupRef} {pathPoints.map((pair, i) => (
plane={plane} <group key={i} visible={!isPlaying}>
/> <PathNavigator
{pathPoints.map((pair, i) => ( navMesh={navMesh}
<PathNavigator pathPoints={pair.points}
navMesh={navMesh} id={pair.modelUuid}
selectedPoints={pair.points} speed={pair.modelSpeed}
id={pair.uuid} bufferTime={pair.bufferTime}
key={i} hitCount={pair.hitCount}
/> />
))}
<group ref={groupRef} visible={false} name="Meshes"></group> {pair.points.slice(1).map((point, idx) => (
</> <mesh position={[point.x, point.y, point.z]} key={idx}>
); <sphereGeometry args={[0.3, 15, 15]} />
<meshStandardMaterial color="red" />
</mesh>
))}
</group>
))}
</>
);
}; };
export default Agv; export default Agv;

View File

@ -0,0 +1,31 @@
import { useRef } from "react";
import { useNavMesh } from "../../../store/store";
import PolygonGenerator from "./polygonGenerator";
import NavMeshDetails from "./navMeshDetails";
import * as CONSTANTS from "../../../types/world/worldConstants";
import * as Types from "../../../types/world/worldTypes";
type NavMeshCreatorProps = {
lines: Types.RefLines
};
function NavMeshCreator({ lines }: NavMeshCreatorProps) {
let groupRef = useRef() as Types.RefGroup;
const { setNavMesh } = useNavMesh();
return (
<>
<PolygonGenerator groupRef={groupRef} lines={lines} />
<NavMeshDetails lines={lines} setNavMesh={setNavMesh} groupRef={groupRef} />
<group ref={groupRef} visible={false} name="Meshes">
<mesh rotation-x={CONSTANTS.planeConfig.rotation} position={CONSTANTS.planeConfig.position3D} name="Plane" receiveShadow>
<planeGeometry args={[300, 300]} />
<meshBasicMaterial color={CONSTANTS.planeConfig.color} />
</mesh>
</group>
</>
)
}
export default NavMeshCreator

View File

@ -10,14 +10,12 @@ interface NavMeshDetailsProps {
setNavMesh: (navMesh: any) => void; setNavMesh: (navMesh: any) => void;
groupRef: React.MutableRefObject<THREE.Group | null>; groupRef: React.MutableRefObject<THREE.Group | null>;
lines: Types.RefLines; lines: Types.RefLines;
plane: Types.RefMesh;
} }
export default function NavMeshDetails({ export default function NavMeshDetails({
lines, lines,
setNavMesh, setNavMesh,
groupRef, groupRef,
plane,
}: NavMeshDetailsProps) { }: NavMeshDetailsProps) {
const { scene } = useThree(); const { scene } = useThree();
@ -34,14 +32,13 @@ export default function NavMeshDetails({
const [positions, indices] = getPositionsAndIndices(meshes); const [positions, indices] = getPositionsAndIndices(meshes);
const cs = 0.25; const cellSize = 0.35;
const ch = 0.69; const cellHeight = 0.7;
const walkableRadius = 0.5; const walkableRadius = 0.5;
const { success, navMesh } = generateSoloNavMesh(positions, indices, { const { success, navMesh } = generateSoloNavMesh(positions, indices, {
cs, cs: cellSize,
ch, ch: cellHeight,
walkableRadius: Math.round(walkableRadius / ch), walkableRadius: Math.round(walkableRadius / cellHeight),
}); });
if (!success || !navMesh) { if (!success || !navMesh) {
@ -50,10 +47,14 @@ export default function NavMeshDetails({
setNavMesh(navMesh); setNavMesh(navMesh);
scene.children
.filter((child) => child instanceof DebugDrawer)
.forEach((child) => scene.remove(child));
const debugDrawer = new DebugDrawer(); const debugDrawer = new DebugDrawer();
debugDrawer.drawNavMesh(navMesh); debugDrawer.drawNavMesh(navMesh);
// scene.add(debugDrawer); // scene.add(debugDrawer);
} catch (error) {} } catch (error) { }
}; };
initializeNavigation(); initializeNavigation();

View File

@ -3,147 +3,207 @@ import * as THREE from "three";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { NavMeshQuery } from "@recast-navigation/core"; import { NavMeshQuery } from "@recast-navigation/core";
import { Line } from "@react-three/drei"; import { Line } from "@react-three/drei";
import { useTh } from "leva/dist/declarations/src/styles"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import { useActiveTool } from "../../../store/store";
// Define interface for props
interface PathNavigatorProps { interface PathNavigatorProps {
navMesh: any; navMesh: any;
selectedPoints: any; pathPoints: any;
id: string; id: string;
speed: number;
bufferTime: number;
hitCount: number;
} }
export default function PathNavigator({ export default function PathNavigator({
navMesh, navMesh,
selectedPoints, pathPoints,
id, id,
speed,
bufferTime,
hitCount
}: PathNavigatorProps) { }: PathNavigatorProps) {
const [path, setPath] = useState<[number, number, number][]>([]); const [path, setPath] = useState<[number, number, number][]>([]);
const progressRef = useRef(0); const [currentPhase, setCurrentPhase] = useState<'initial' | 'loop'>('initial');
const distancesRef = useRef<number[]>([]); const [toPickupPath, setToPickupPath] = useState<[number, number, number][]>([]);
const totalDistanceRef = useRef(0); const [pickupDropPath, setPickupDropPath] = useState<[number, number, number][]>([]);
const currentSegmentIndex = useRef(0); const [dropPickupPath, setDropPickupPath] = useState<[number, number, number][]>([]);
const { scene } = useThree(); const [initialPosition, setInitialPosition] = useState<THREE.Vector3 | null>(null);
const { activeTool } = useActiveTool(); const [initialRotation, setInitialRotation] = useState<THREE.Euler | null>(null);
const [startPoint, setStartPoint] = useState(new THREE.Vector3());
const meshRef = useRef<THREE.Mesh | null>(null);
useEffect(() => {
if (!scene || !id || path.length < 2) return;
let totalDistance = 0; const distancesRef = useRef<number[]>([]);
const distances: number[] = []; const totalDistanceRef = useRef(0);
for (let i = 0; i < path.length - 1; i++) { const progressRef = useRef(0);
const start = new THREE.Vector3(...path[i]); const isWaiting = useRef(false);
const end = new THREE.Vector3(...path[i + 1]); const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const segmentDistance = start.distanceTo(end);
distances.push(segmentDistance);
totalDistance += segmentDistance;
}
distancesRef.current = distances; const { scene } = useThree();
totalDistanceRef.current = totalDistance; const { isPlaying } = usePlayButtonStore();
progressRef.current = 0; // Reset progress when the path changes
}, [path]);
useEffect(() => {
if (!navMesh || selectedPoints.length === 0) return;
// Flatten the selectedPoints array into a single list of points useEffect(() => {
const allPoints = selectedPoints.flat(); const object = scene.getObjectByProperty("uuid", id);
if (object) {
setInitialPosition(object.position.clone());
setInitialRotation(object.rotation.clone());
}
}, [scene, id]);
// Compute paths between consecutive points const computePath = (start: any, end: any) => {
const computedPath: [number, number, number][] = []; try {
for (let i = 0; i < allPoints.length - 1; i++) { const navMeshQuery = new NavMeshQuery(navMesh);
const start = allPoints[i]; const { path: segmentPath } = navMeshQuery.computePath(start, end);
setStartPoint( return segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || [];
new THREE.Vector3(allPoints[0].x, allPoints[0].y, allPoints[0].z) } catch {
); return [];
}
};
const end = allPoints[i + 1]; const resetState = () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
try { setPath([]);
const navMeshQuery = new NavMeshQuery(navMesh); setCurrentPhase('initial');
const { path: segmentPath } = navMeshQuery.computePath(start, end); setPickupDropPath([]);
setDropPickupPath([]);
distancesRef.current = [];
totalDistanceRef.current = 0;
progressRef.current = 0;
isWaiting.current = false;
if (segmentPath && segmentPath.length > 0) { if (initialPosition && initialRotation) {
computedPath.push( const object = scene.getObjectByProperty("uuid", id);
...segmentPath.map(({ x, y, z }): [number, number, number] => [ if (object) {
x, object.position.copy(initialPosition);
y + 0.1, object.rotation.copy(initialRotation);
z, }
]) }
); };
}
} catch (error) {}
}
// Set the full computed path useEffect(() => {
if (!isPlaying) {
resetState();
}
if (computedPath.length > 0) { if (!navMesh || pathPoints.length < 2) return;
setPath(computedPath);
currentSegmentIndex.current = 0; // Reset to the first segment
}
}, [selectedPoints, navMesh, path]);
useFrame((_, delta) => { const [pickup, drop] = pathPoints.slice(-2);
if (!scene || !id || path.length < 2) return; const object = scene.getObjectByProperty("uuid", id);
if (!object) return;
// Find the object in the scene const currentPosition = { x: object.position.x, y: object.position.y, z: object.position.z };
const findObject = scene.getObjectByProperty("uuid", id);
if (activeTool === "play") {
if (!findObject) return;
const speed = 5; const toPickupPath = computePath(currentPosition, pickup);
progressRef.current += delta * speed; const pickupToDropPath = computePath(pickup, drop);
const dropToPickupPath = computePath(drop, pickup);
let coveredDistance = progressRef.current; if (toPickupPath.length && pickupToDropPath.length && dropToPickupPath.length) {
let accumulatedDistance = 0; setPickupDropPath(pickupToDropPath);
let index = 0; setDropPickupPath(dropToPickupPath);
setToPickupPath(toPickupPath);
setPath(toPickupPath);
setCurrentPhase('initial');
}
}, [navMesh, pathPoints, hitCount, isPlaying]);
// Determine the current segment of the path useEffect(() => {
while ( if (path.length < 2) return;
index < distancesRef.current.length &&
coveredDistance > accumulatedDistance + distancesRef.current[index]
) {
accumulatedDistance += distancesRef.current[index];
index++;
}
// If the object has reached the end of the path, stop moving let total = 0;
if (index >= distancesRef.current.length) { const segmentDistances = path.slice(0, -1).map((point, i) => {
progressRef.current = totalDistanceRef.current; const dist = new THREE.Vector3(...point).distanceTo(new THREE.Vector3(...path[i + 1]));
return; total += dist;
} return dist;
});
// Interpolate position within the current segment distancesRef.current = segmentDistances;
const start = new THREE.Vector3(...path[index]); totalDistanceRef.current = total;
const end = new THREE.Vector3(...path[index + 1]); progressRef.current = 0;
const segmentDistance = distancesRef.current[index]; isWaiting.current = false;
}, [path]);
const t = (coveredDistance - accumulatedDistance) / segmentDistance; useFrame((_, delta) => {
const position = start.clone().lerp(end, t); if (!isPlaying || path.length < 2 || !scene || !id) return;
findObject.position.copy(position);
// Rotate the object to face the direction of movement const object = scene.getObjectByProperty("uuid", id);
const direction = new THREE.Vector3().subVectors(end, start).normalize(); if (!object) return;
const targetQuaternion = new THREE.Quaternion().setFromUnitVectors(
new THREE.Vector3(0, 0, 1), // Assuming forward direction is (0, 0, 1)
direction
);
findObject.quaternion.slerp(targetQuaternion, 0.1); // Smoothly interpolate rotation
} else if (activeTool === "cursor") {
findObject?.position.copy(startPoint);
}
});
return ( const speedFactor = speed;
<> progressRef.current += delta * speedFactor;
{path.length > 0 && <Line points={path} color="blue" lineWidth={3} />}
{/* {path.length > 0 && ( let covered = progressRef.current;
<mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}> let accumulated = 0;
<boxGeometry args={[1, 1, 1]} /> let index = 0;
<meshNormalMaterial />
</mesh> while (
)} */} index < distancesRef.current.length &&
</> covered > accumulated + distancesRef.current[index]
); ) {
} accumulated += distancesRef.current[index];
index++;
}
if (index >= distancesRef.current.length) {
progressRef.current = totalDistanceRef.current;
if (!isWaiting.current) {
isWaiting.current = true;
timeoutRef.current = setTimeout(() => {
if (currentPhase === 'initial') {
setPath(pickupDropPath);
setCurrentPhase('loop');
} else {
setPath(prevPath =>
prevPath === pickupDropPath ? dropPickupPath : pickupDropPath
);
}
progressRef.current = 0;
isWaiting.current = false;
}, bufferTime * 1000);
}
return;
}
const start = new THREE.Vector3(...path[index]);
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);
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;
});
useEffect(() => {
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, []);
return (
<group name="path-navigator-lines" visible={!isPlaying} >
{toPickupPath.length > 0 && (
<Line points={toPickupPath} color="blue" lineWidth={3} dashed dashSize={0.75} dashScale={2} />
)}
{pickupDropPath.length > 0 && (
<Line points={pickupDropPath} color="red" lineWidth={3} />
)}
{dropPickupPath.length > 0 && (
<Line points={dropPickupPath} color="red" lineWidth={3} />
)}
</group>
);
}

View File

@ -6,21 +6,12 @@ import arrayLinesToObject from "../geomentries/lines/lineConvertions/arrayLinesT
interface PolygonGeneratorProps { interface PolygonGeneratorProps {
groupRef: React.MutableRefObject<THREE.Group | null>; groupRef: React.MutableRefObject<THREE.Group | null>;
lines: Types.RefLines; lines: Types.RefLines;
plane: Types.RefMesh;
} }
export default function PolygonGenerator({ export default function PolygonGenerator({
groupRef, groupRef,
lines, lines,
plane,
}: PolygonGeneratorProps) { }: PolygonGeneratorProps) {
// const [rooms, setRooms] = useState<THREE.Vector3[][]>([]);
useEffect(() => {
if (groupRef.current && plane.current) {
groupRef.current.add(plane.current.clone());
}
}, [groupRef, plane]);
useEffect(() => { useEffect(() => {
let allLines = arrayLinesToObject(lines.current); let allLines = arrayLinesToObject(lines.current);
@ -37,13 +28,14 @@ export default function PolygonGenerator({
uuid: point.uuid, uuid: point.uuid,
})) }))
); );
if (!result || result.some((line) => !line)) { if (!result || result.some((line) => !line)) {
return; return;
} }
const lineFeatures = result?.map((line: any) => const lineFeatures = result?.map((line: any) =>
turf.lineString(line.map((p: any) => p?.position)) turf.lineString(line.map((p: any) => p?.position))
); );
const polygons = turf.polygonize(turf.featureCollection(lineFeatures)); const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
renderWallGeometry(wallPoints); renderWallGeometry(wallPoints);
@ -79,8 +71,8 @@ export default function PolygonGenerator({
groupRef.current?.add(mesh); groupRef.current?.add(mesh);
} }
}); });
} }
}, [lines.current]); }, [lines.current]);
const renderWallGeometry = (walls: THREE.Vector3[][]) => { const renderWallGeometry = (walls: THREE.Vector3[][]) => {

View File

@ -24,7 +24,7 @@ async function addAssetModel(
socket: Socket<any>, socket: Socket<any>,
selectedItem: any, selectedItem: any,
setSelectedItem: any, setSelectedItem: any,
setSimulationPaths: any, setSimulationStates: any,
plane: Types.RefMesh, plane: Types.RefMesh,
): Promise<void> { ): Promise<void> {
@ -65,7 +65,7 @@ async function addAssetModel(
const cachedModel = THREE.Cache.get(selectedItem.id); const cachedModel = THREE.Cache.get(selectedItem.id);
if (cachedModel) { if (cachedModel) {
// console.log(`[Cache] Fetching ${selectedItem.name}`); // console.log(`[Cache] Fetching ${selectedItem.name}`);
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket); handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket);
return; return;
} else { } else {
const cachedModelBlob = await retrieveGLTF(selectedItem.id); const cachedModelBlob = await retrieveGLTF(selectedItem.id);
@ -78,7 +78,7 @@ async function addAssetModel(
URL.revokeObjectURL(blobUrl); URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl); THREE.Cache.remove(blobUrl);
THREE.Cache.add(selectedItem.id, gltf); THREE.Cache.add(selectedItem.id, gltf);
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket); handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket);
}, },
() => { () => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
@ -90,7 +90,7 @@ async function addAssetModel(
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob()); const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
await storeGLTF(selectedItem.id, modelBlob); await storeGLTF(selectedItem.id, modelBlob);
THREE.Cache.add(selectedItem.id, gltf); THREE.Cache.add(selectedItem.id, gltf);
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket); await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket);
}, },
() => { () => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
@ -113,7 +113,7 @@ async function handleModelLoad(
tempLoader: Types.RefMesh, tempLoader: Types.RefMesh,
isTempLoader: Types.RefBoolean, isTempLoader: Types.RefBoolean,
setFloorItems: Types.setFloorItemSetState, setFloorItems: Types.setFloorItemSetState,
setSimulationPaths: any, setSimulationStates: any,
socket: Socket<any> socket: Socket<any>
) { ) {
const model = gltf.scene.clone(); const model = gltf.scene.clone();
@ -136,7 +136,7 @@ async function handleModelLoad(
tempLoader.current = undefined; tempLoader.current = undefined;
} }
const newFloorItem: Types.FloorItemType = { const newFloorItem: Types.EventData = {
modeluuid: model.uuid, modeluuid: model.uuid,
modelname: selectedItem.name, modelname: selectedItem.name,
modelfileID: selectedItem.id, modelfileID: selectedItem.id,
@ -154,7 +154,7 @@ async function handleModelLoad(
if (res.type === "Conveyor") { if (res.type === "Conveyor") {
const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID()); const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
const backendEventData: Extract<Types.FloorItemType['eventData'], { type: 'Conveyor' }> = { const backendEventData: Extract<Types.EventData['eventData'], { type: 'Conveyor' }> = {
type: 'Conveyor', type: 'Conveyor',
points: res.points.map((point: any, index: number) => ({ points: res.points.map((point: any, index: number) => ({
uuid: pointUUIDs[index], uuid: pointUUIDs[index],
@ -167,11 +167,11 @@ async function handleModelLoad(
material: 'Inherit', material: 'Inherit',
delay: 'Inherit', delay: 'Inherit',
spawnInterval: 'Inherit', spawnInterval: 'Inherit',
isUsed: false isUsed: true
}], }],
triggers: [], triggers: [],
connections: { connections: {
source: { pathUUID: model.uuid, pointUUID: pointUUIDs[index] }, source: { modelUUID: model.uuid, pointUUID: pointUUIDs[index] },
targets: [] targets: []
} }
})), })),
@ -189,7 +189,7 @@ async function handleModelLoad(
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, // { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
// false, // false,
// true, // true,
// newFloorItem.eventData // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
// ); // );
// SOCKET // SOCKET
@ -206,8 +206,7 @@ async function handleModelLoad(
eventData: backendEventData, eventData: backendEventData,
socketId: socket.id socketId: socket.id
}; };
console.log('data: ', data);
setFloorItems((prevItems) => { setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@ -220,9 +219,71 @@ async function handleModelLoad(
eventData.position = newFloorItem.position; eventData.position = newFloorItem.position;
eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z]; eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
eventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema eventData as Types.ConveyorEventsSchema
]);
socket.emit("v2:model-asset:add", data);
} else if (res.type === "Vehicle") {
const pointUUID = THREE.MathUtils.generateUUID();
const backendEventData: Extract<Types.EventData['eventData'], { type: 'Vehicle' }> = {
type: "Vehicle",
points: {
uuid: pointUUID,
position: res.points.position as [number, number, number],
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: '', start: {}, hitCount: 1, end: {}, buffer: 0 },
connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
speed: 2,
}
}
// API
// await setFloorItemApi(
// organization,
// newFloorItem.modeluuid,
// newFloorItem.modelname,
// newFloorItem.modelfileID,
// newFloorItem.position,
// { x: model.rotation.x, y: model.rotation.y, z: model.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: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false,
isVisible: true,
eventData: { type: backendEventData.type, points: backendEventData.points },
socketId: socket.id
};
const eventData: any = backendEventData;
eventData.modeluuid = newFloorItem.modeluuid;
eventData.modelName = newFloorItem.modelname;
eventData.position = newFloorItem.position;
setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems;
});
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []),
eventData as Types.VehicleEventsSchema
]); ]);
socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
@ -239,7 +300,7 @@ async function handleModelLoad(
// newFloorItem.position, // newFloorItem.position,
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, // { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
// false, // false,
// true // true,
// ); // );
// SOCKET // SOCKET
@ -255,7 +316,8 @@ async function handleModelLoad(
isVisible: true, isVisible: true,
socketId: socket.id socketId: socket.id
}; };
setFloorItems((prevItems) => { setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@ -263,7 +325,6 @@ async function handleModelLoad(
}); });
socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
} }
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });

View File

@ -10,7 +10,7 @@ async function DeleteFloorItems(
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
hoveredDeletableFloorItem: Types.RefMesh, hoveredDeletableFloorItem: Types.RefMesh,
setFloorItems: Types.setFloorItemSetState, setFloorItems: Types.setFloorItemSetState,
setSimulationPaths: any, setSimulationStates: any,
socket: Socket<any> socket: Socket<any>
): Promise<void> { ): Promise<void> {
@ -76,7 +76,7 @@ async function DeleteFloorItems(
} }
setFloorItems(updatedItems); setFloorItems(updatedItems);
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== removedItem.modeluuid); const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== removedItem.modeluuid);
return updatedEvents; return updatedEvents;
}); });

View File

@ -10,7 +10,7 @@ import {
useRenderDistance, useRenderDistance,
useselectedFloorItem, useselectedFloorItem,
useSelectedItem, useSelectedItem,
useSimulationPaths, useSimulationStates,
useSocketStore, useSocketStore,
useToggleView, useToggleView,
useTransformMode, useTransformMode,
@ -65,7 +65,7 @@ const FloorItemsGroup = ({
const { setselectedFloorItem } = useselectedFloorItem(); const { setselectedFloorItem } = useselectedFloorItem();
const { activeTool } = useActiveTool(); const { activeTool } = useActiveTool();
const { selectedItem, setSelectedItem } = useSelectedItem(); const { selectedItem, setSelectedItem } = useSelectedItem();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationStates, setSimulationStates } = useSimulationStates();
const { setLoadingProgress } = useLoadingProgress(); const { setLoadingProgress } = useLoadingProgress();
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const { socket } = useSocketStore(); const { socket } = useSocketStore();
@ -110,9 +110,8 @@ const FloorItemsGroup = ({
} }
gltfLoaderWorker.postMessage({ floorItems: data }); gltfLoaderWorker.postMessage({ floorItems: data });
} else { } else {
console.log('data: ', data);
gltfLoaderWorker.postMessage({ floorItems: [] }); gltfLoaderWorker.postMessage({ floorItems: [] });
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths); loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
updateLoadingProgress(100); updateLoadingProgress(100);
} }
}); });
@ -131,7 +130,7 @@ const FloorItemsGroup = ({
updateLoadingProgress(progress); updateLoadingProgress(progress);
if (loadedAssets === totalAssets) { if (loadedAssets === totalAssets) {
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths); loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates);
updateLoadingProgress(100); updateLoadingProgress(100);
} }
}); });
@ -249,7 +248,7 @@ const FloorItemsGroup = ({
itemsGroup, itemsGroup,
hoveredDeletableFloorItem, hoveredDeletableFloorItem,
setFloorItems, setFloorItems,
setSimulationPaths, setSimulationStates,
socket socket
); );
} }
@ -375,7 +374,7 @@ const FloorItemsGroup = ({
socket, socket,
selectedItem, selectedItem,
setSelectedItem, setSelectedItem,
setSimulationPaths, setSimulationStates,
plane plane
); );
} }

View File

@ -12,203 +12,189 @@ import CollabUserIcon from "./collabUserIcon";
import { getAvatarColor } from "./users/functions/getAvatarColor"; import { getAvatarColor } from "./users/functions/getAvatarColor";
const CamModelsGroup = () => { const CamModelsGroup = () => {
let navigate = useNavigate(); const navigate = useNavigate();
const groupRef = useRef<THREE.Group>(null); const groupRef = useRef<THREE.Group>(null);
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const { activeUsers, setActiveUsers } = useActiveUsers(); const { activeUsers, setActiveUsers } = useActiveUsers();
const { socket } = useSocketStore(); const { socket } = useSocketStore();
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
const [cams, setCams] = useState<any[]>([]);
const [models, setModels] = useState<Record<string, { targetPosition: THREE.Vector3; targetRotation: THREE.Euler }>>({});
dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/"); const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader); const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
loader.setDRACOLoader(dracoLoader);
useEffect(() => { const [cams, setCams] = useState<any[]>([]);
if (!email) { const [models, setModels] = useState<Record<string, { targetPosition: THREE.Vector3; targetRotation: THREE.Euler }>>({});
navigate("/");
}
if (!socket) return;
const organization = email!.split("@")[1].split(".")[0];
socket.on("userConnectResponse", (data: any) => { const dedupeCams = (cams: any[]) => {
if (!groupRef.current) return; const seen = new Set();
if (data.data.userData.email === email) return; return cams.filter((cam) => {
if (socket.id === data.socketId || organization !== data.organization) if (seen.has(cam.uuid)) return false;
return; seen.add(cam.uuid);
return true;
});
};
const model = groupRef.current.getObjectByProperty( const dedupeUsers = (users: any[]) => {
"uuid", const seen = new Set();
data.data.userData._id return users.filter((user) => {
); if (seen.has(user._id)) return false;
if (model) { seen.add(user._id);
groupRef.current.remove(model); return true;
} });
loader.load(camModel, (gltf) => { };
const newModel = gltf.scene.clone();
newModel.uuid = data.data.userData._id;
newModel.position.set(
data.data.position.x,
data.data.position.y,
data.data.position.z
);
newModel.rotation.set(
data.data.rotation.x,
data.data.rotation.y,
data.data.rotation.z
);
newModel.userData = data.data.userData;
setCams((prev) => [...prev, newModel]);
setActiveUsers([...activeUsers, data.data.userData]);
});
});
// socket.on("users:online", (data: any) => { useEffect(() => {
// console.log('users online: ', data); if (!email) navigate("/");
// })
socket.on("userDisConnectResponse", (data: any) => { if (!socket) return;
if (!groupRef.current) return; const organization = email!.split("@")[1].split(".")[0];
if (socket.id === data.socketId || organization !== data.organization)
return;
setCams((prev) => socket.on("userConnectResponse", (data: any) => {
prev.filter((cam) => cam.uuid !== data.data.userData._id) if (!groupRef.current) return;
); if (data.data.userData.email === email) return;
setActiveUsers( if (socket.id === data.socketId || organization !== data.organization) return;
activeUsers.filter((user: any) => user._id !== data.data.userData._id)
);
});
socket.on("cameraUpdateResponse", (data: any) => { const model = groupRef.current.getObjectByProperty("uuid", data.data.userData._id);
if ( if (model) {
!groupRef.current || groupRef.current.remove(model);
socket.id === data.socketId || }
organization !== data.organization
)
return;
setModels((prev) => ({ loader.load(camModel, (gltf) => {
...prev, const newModel = gltf.scene.clone();
[data.data.userId]: { newModel.uuid = data.data.userData._id;
targetPosition: new THREE.Vector3( newModel.position.set(
data.data.position.x, data.data.position.x,
data.data.position.y, data.data.position.y,
data.data.position.z data.data.position.z
), );
targetRotation: new THREE.Euler( newModel.rotation.set(
data.data.rotation.x, data.data.rotation.x,
data.data.rotation.y, data.data.rotation.y,
data.data.rotation.z data.data.rotation.z
), );
}, newModel.userData = data.data.userData;
}));
});
return () => { setCams((prev) => dedupeCams([...prev, newModel]));
socket.off("userConnectRespones"); setActiveUsers((prev: any) =>
socket.off("userDisConnectRespones"); dedupeUsers([...prev, data.data.userData])
socket.off("cameraUpdateResponse"); );
}; });
}, [socket, activeUsers]); });
socket.on("userDisConnectResponse", (data: any) => {
if (!groupRef.current) return;
if (socket.id === data.socketId || organization !== data.organization) return;
// useEffect(() => { setCams((prev) =>
// console.log(activeUsers); prev.filter((cam) => cam.uuid !== data.data.userData._id)
// }, [activeUsers]) );
setActiveUsers((prev: any) =>
prev.filter((user: any) => user._id !== data.data.userData._id)
);
});
// useEffect(() => { socket.on("cameraUpdateResponse", (data: any) => {
// console.log(models); if (
// }, [models]) !groupRef.current ||
socket.id === data.socketId ||
organization !== data.organization
)
return;
useFrame(() => { setModels((prev) => ({
if (!groupRef.current) return; ...prev,
Object.keys(models).forEach((uuid) => { [data.data.userId]: {
const model = groupRef.current!.getObjectByProperty("uuid", uuid); targetPosition: new THREE.Vector3(
if (!model) return; data.data.position.x,
data.data.position.y,
data.data.position.z
),
targetRotation: new THREE.Euler(
data.data.rotation.x,
data.data.rotation.y,
data.data.rotation.z
),
},
}));
});
const { targetPosition, targetRotation } = models[uuid]; return () => {
model.position.lerp(targetPosition, 0.1); socket.off("userConnectResponse");
model.rotation.x = THREE.MathUtils.lerp( socket.off("userDisConnectResponse");
model.rotation.x, socket.off("cameraUpdateResponse");
targetRotation.x, };
0.1 }, [socket]);
);
model.rotation.y = THREE.MathUtils.lerp(
model.rotation.y,
targetRotation.y,
0.1
);
model.rotation.z = THREE.MathUtils.lerp(
model.rotation.z,
targetRotation.z,
0.1
);
});
});
useEffect(() => { useFrame(() => {
if (!groupRef.current) return; if (!groupRef.current) return;
const organization = email!.split("@")[1].split(".")[0]; Object.keys(models).forEach((uuid) => {
getActiveUsersData(organization).then((data) => { const model = groupRef.current!.getObjectByProperty("uuid", uuid);
const filteredData = data.cameraDatas.filter( if (!model) return;
(camera: any) => camera.userData.email !== email
);
let a: any = [];
if (filteredData.length > 0) {
loader.load(camModel, (gltf) => {
const newCams = filteredData.map((cam: any) => {
const newModel = gltf.scene.clone();
newModel.uuid = cam.userData._id;
newModel.position.set(
cam.position.x,
cam.position.y,
cam.position.z
);
newModel.rotation.set(
cam.rotation.x,
cam.rotation.y,
cam.rotation.z
);
newModel.userData = cam.userData;
a.push(cam.userData);
return newModel;
});
setActiveUsers(a);
setCams((prev) => [...prev, ...newCams]);
});
}
});
}, []);
return ( const { targetPosition, targetRotation } = models[uuid];
<group ref={groupRef} name="Cam-Model-Group"> model.position.lerp(targetPosition, 0.1);
{cams.map((cam, index) => ( model.rotation.x = THREE.MathUtils.lerp(model.rotation.x, targetRotation.x, 0.1);
<primitive key={index} object={cam}> model.rotation.y = THREE.MathUtils.lerp(model.rotation.y, targetRotation.y, 0.1);
<Html model.rotation.z = THREE.MathUtils.lerp(model.rotation.z, targetRotation.z, 0.1);
as="div" });
center });
zIndexRange={[1, 0]}
sprite useEffect(() => {
style={{ if (!groupRef.current) return;
color: "white", const organization = email!.split("@")[1].split(".")[0];
textAlign: "center",
fontFamily: "Arial, sans-serif", getActiveUsersData(organization).then((data) => {
}} const filteredData = data.cameraDatas.filter(
position={[-0.015, 0, 0.7]} (camera: any) => camera.userData.email !== email
> );
<CollabUserIcon
userImage={""} if (filteredData.length > 0) {
userName={cam.userData.userName} loader.load(camModel, (gltf) => {
index={index} const newCams = filteredData.map((cam: any) => {
color={getAvatarColor(index)} const newModel = gltf.scene.clone();
/> newModel.uuid = cam.userData._id;
</Html> newModel.position.set(cam.position.x, cam.position.y, cam.position.z);
</primitive> newModel.rotation.set(cam.rotation.x, cam.rotation.y, cam.rotation.z);
))} newModel.userData = cam.userData;
</group> return newModel;
); });
const users = filteredData.map((cam: any) => cam.userData);
setActiveUsers((prev: any) => dedupeUsers([...prev, ...users]));
setCams((prev) => dedupeCams([...prev, ...newCams]));
});
}
});
}, []);
return (
<group ref={groupRef} name="Cam-Model-Group">
{cams.map((cam, index) => (
<primitive key={cam.uuid} object={cam}>
<Html
as="div"
center
zIndexRange={[1, 0]}
sprite
style={{
color: "white",
textAlign: "center",
fontFamily: "Arial, sans-serif",
}}
position={[-0.015, 0, 0.7]}
>
<CollabUserIcon
userImage={""}
userName={cam.userData.userName}
index={index}
color={getAvatarColor(index)}
/>
</Html>
</primitive>
))}
</group>
);
}; };
export default CamModelsGroup; export default CamModelsGroup;

View File

@ -20,7 +20,24 @@ const CollabUserIcon: React.FC<CollabUserIconProps> = ({
{userImage ? ( {userImage ? (
<img className="user-image" src={userImage} alt={userName} /> <img className="user-image" src={userImage} alt={userName} />
) : ( ) : (
<CustomAvatar name={userName} index={index} /> <CustomAvatar name={userName} index={index} color={color} />
// <div
// className="user-image"
// style={{
// lineHeight: "30px",
// textTransform: "uppercase",
// textAlign: "center",
// fontSize: "16px",
// borderRadius: "50%",
// backgroundColor: color,
// overflow: "hidden",
// backgroundSize: "cover",
// backgroundPosition: "center",
// color: "white",
// fontWeight: "bold",
// }}>
// {userName[0]}
// </div>
)} )}
</div> </div>
<div className="user-name" style={{ backgroundColor: color }}> <div className="user-name" style={{ backgroundColor: color }}>

View File

@ -143,10 +143,6 @@ export default function SocketResponses({
isVisible: data.data.isVisible, isVisible: data.data.isVisible,
}; };
if (data.data.eventData) {
newFloorItem.eventData = data.data.eventData;
}
setFloorItems((prevItems: any) => { setFloorItems((prevItems: any) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@ -221,10 +217,6 @@ export default function SocketResponses({
isVisible: data.data.isVisible, isVisible: data.data.isVisible,
}; };
if (data.data.eventData) {
newFloorItem.eventData = data.data.eventData;
}
setFloorItems((prevItems: any) => { setFloorItems((prevItems: any) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
@ -241,7 +233,7 @@ export default function SocketResponses({
} }
} else if (data.message === "Model updated successfully") { } else if (data.message === "Model updated successfully") {
itemsGroup.current.children.forEach((item: THREE.Group) => { itemsGroup.current?.children.forEach((item: THREE.Group) => {
if (item.uuid === data.data.modeluuid) { if (item.uuid === data.data.modeluuid) {
item.position.set(...data.data.position as [number, number, number]); item.position.set(...data.data.position as [number, number, number]);
item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); item.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);

View File

@ -7,6 +7,7 @@ interface AvatarProps {
size?: number; size?: number;
index?: number; index?: number;
textColor?: string; textColor?: string;
color?: string; // Optional color prop for future use
} }
const CustomAvatar: React.FC<AvatarProps> = ({ const CustomAvatar: React.FC<AvatarProps> = ({
@ -14,6 +15,7 @@ const CustomAvatar: React.FC<AvatarProps> = ({
size = 100, size = 100,
index = 0, index = 0,
textColor = "#ffffff", textColor = "#ffffff",
color, // Optional color prop for future use
}) => { }) => {
const [imageSrc, setImageSrc] = useState<string | null>(null); const [imageSrc, setImageSrc] = useState<string | null>(null);
@ -26,7 +28,7 @@ const CustomAvatar: React.FC<AvatarProps> = ({
const initials = getInitials(name); // Convert name to initials if needed const initials = getInitials(name); // Convert name to initials if needed
// Draw background // Draw background
ctx.fillStyle = getAvatarColor(index); ctx.fillStyle = color || getAvatarColor(index); // Use color prop or generate color based on index
ctx.fillRect(0, 0, size, size); ctx.fillRect(0, 0, size, size);
// Draw initials // Draw initials
@ -40,7 +42,7 @@ const CustomAvatar: React.FC<AvatarProps> = ({
const dataURL = canvas.toDataURL("image/png"); const dataURL = canvas.toDataURL("image/png");
setImageSrc(dataURL); setImageSrc(dataURL);
} }
}, [name, size, textColor]); }, [name, size, textColor, index]);
if (!imageSrc) { if (!imageSrc) {
return null; // Return null while the image is being generated return null; // Return null while the image is being generated
@ -53,6 +55,18 @@ const CustomAvatar: React.FC<AvatarProps> = ({
alt="User Avatar" alt="User Avatar"
style={{ width: "100%", height: "100%" }} style={{ width: "100%", height: "100%" }}
/> />
// <div
// className="user-image"
// style={{
// width: size,
// height: size,
// borderRadius: "50%",
// overflow: "hidden",
// backgroundSize: "cover",
// backgroundPosition: "center",
// }}>
// {name[0]}
// </div>
); );
}; };

View File

@ -12,7 +12,7 @@ import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAss
async function loadInitialFloorItems( async function loadInitialFloorItems(
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState, setFloorItems: Types.setFloorItemSetState,
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void
): Promise<void> { ): Promise<void> {
if (!itemsGroup.current) return; if (!itemsGroup.current) return;
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
@ -23,10 +23,10 @@ async function loadInitialFloorItems(
localStorage.setItem("FloorItems", JSON.stringify(items)); localStorage.setItem("FloorItems", JSON.stringify(items));
await initializeDB(); await initializeDB();
if (items.message === "floorItems not found") return; if (items.message === "floorItems not found") return;
if (items) { if (items) {
const storedFloorItems: Types.FloorItems = items; const storedFloorItems: Types.EventData[] = items;
const loader = new GLTFLoader(); const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader(); const dracoLoader = new DRACOLoader();
@ -53,7 +53,6 @@ async function loadInitialFloorItems(
}); });
for (const item of storedFloorItems) { for (const item of storedFloorItems) {
console.log('item: ', item);
if (!item.modelfileID) return; if (!item.modelfileID) return;
const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]); const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
let storedPosition; let storedPosition;
@ -72,7 +71,7 @@ async function loadInitialFloorItems(
const cachedModel = THREE.Cache.get(item.modelfileID!); const cachedModel = THREE.Cache.get(item.modelfileID!);
if (cachedModel) { if (cachedModel) {
// console.log(`[Cache] Fetching ${item.modelname}`); // console.log(`[Cache] Fetching ${item.modelname}`);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths); processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
modelsLoaded++; modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
return; return;
@ -89,7 +88,7 @@ async function loadInitialFloorItems(
URL.revokeObjectURL(blobUrl); URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl); THREE.Cache.remove(blobUrl);
THREE.Cache.add(item.modelfileID!, gltf); THREE.Cache.add(item.modelfileID!, gltf);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths); processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
modelsLoaded++; modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
}, },
@ -112,7 +111,7 @@ async function loadInitialFloorItems(
const modelBlob = await fetch(modelUrl).then((res) => res.blob()); const modelBlob = await fetch(modelUrl).then((res) => res.blob());
await storeGLTF(item.modelfileID!, modelBlob); await storeGLTF(item.modelfileID!, modelBlob);
THREE.Cache.add(item.modelfileID!, gltf); THREE.Cache.add(item.modelfileID!, gltf);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths); processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
modelsLoaded++; modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
}, },
@ -138,8 +137,8 @@ async function loadInitialFloorItems(
}, },
]); ]);
if (item.eventData) { if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') {
processEventData(item, setSimulationPaths); processEventData(item, setSimulationStates);
} }
modelsLoaded++; modelsLoaded++;
@ -155,10 +154,10 @@ async function loadInitialFloorItems(
function processLoadedModel( function processLoadedModel(
gltf: any, gltf: any,
item: Types.FloorItemType, item: Types.EventData,
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState, setFloorItems: Types.setFloorItemSetState,
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void
) { ) {
const model = gltf; const model = gltf;
model.uuid = item.modeluuid; model.uuid = item.modeluuid;
@ -193,15 +192,15 @@ function processLoadedModel(
}, },
]); ]);
if (item.eventData || item.modelfileID === '67e3da19c2e8f37134526e6a') { if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') {
processEventData(item, setSimulationPaths); processEventData(item, setSimulationStates);
} }
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' }); gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
} }
function processEventData(item: Types.FloorItemType, setSimulationPaths: any) { function processEventData(item: Types.EventData, setSimulationStates: any) {
if (item.eventData?.type === 'Conveyor') { if (item.eventData?.type === 'Conveyor') {
@ -211,32 +210,45 @@ function processEventData(item: Types.FloorItemType, setSimulationPaths: any) {
data.position = item.position; data.position = item.position;
data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z]; data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
data as Types.ConveyorEventsSchema data as Types.ConveyorEventsSchema
]); ]);
} else {
} else if (item.eventData?.type === 'Vehicle') {
const data: any = item.eventData;
data.modeluuid = item.modeluuid;
data.modelName = item.modelname;
data.position = item.position;
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []),
data as Types.VehicleEventsSchema
]);
} else if (item.modelfileID === '67e3db95c2e8f37134526fb2') {
const pointUUID = THREE.MathUtils.generateUUID(); const pointUUID = THREE.MathUtils.generateUUID();
const pointPosition = new THREE.Vector3(0, 1.3, 0); const pointPosition = new THREE.Vector3(0, 1.75, 0);
const newVehiclePath: Types.VehicleEventsSchema = { const staticMachine: Types.StaticMachineEventsSchema = {
modeluuid: item.modeluuid, modeluuid: item.modeluuid,
modelName: item.modelname, modelName: item.modelname,
type: 'Vehicle', type: "StaticMachine",
point: { points: {
uuid: pointUUID, uuid: pointUUID,
position: [pointPosition.x, pointPosition.y, pointPosition.z], position: [pointPosition.x, pointPosition.y, pointPosition.z],
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 }, actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', buffer: 'Inherit', material: 'Inherit', isUsed: false },
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] }, triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
speed: 2, connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
}, },
position: [...item.position], position: item.position
}; };
setSimulationPaths((prevEvents: (Types.VehicleEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
newVehiclePath as Types.VehicleEventsSchema staticMachine as Types.StaticMachineEventsSchema
]); ]);
} }
} }

View File

@ -1,7 +1,7 @@
import * as THREE from "three"; import * as THREE from "three";
import { useEffect, useMemo } from "react"; import { useEffect, useMemo } from "react";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
@ -10,7 +10,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { camera, controls, gl, scene, pointer, raycaster } = useThree();
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationStates, setSimulationStates } = useSimulationStates();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { floorItems, setFloorItems } = useFloorItems(); const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore() const { socket } = useSocketStore()
@ -151,7 +151,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
return updatedItems; return updatedItems;
}); });
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid); let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default"; const organization = email ? email.split("@")[1].split(".")[0] : "default";
@ -183,7 +183,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
: [defaultAction], : [defaultAction],
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers, triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
connections: { connections: {
source: { pathUUID: obj.uuid, pointUUID }, source: { modelUUID: obj.uuid, pointUUID },
targets: [] targets: []
} }
}; };
@ -224,22 +224,102 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false, isLocked: false,
isVisible: true, isVisible: true,
eventData: backendEventData, eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
socketId: socket.id, socketId: socket.id,
}; };
const newEventData: any = backendEventData; const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed };
newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modeluuid = newFloorItem.modeluuid;
newEventData.modelName = newFloorItem.modelname; newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema newEventData as Types.ConveyorEventsSchema
]); ]);
socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
} else if (eventData.type === 'Vehicle' && eventData) {
const createVehiclePoint = () => {
const pointUUID = THREE.MathUtils.generateUUID();
const vehiclePoint = (eventData as Types.VehicleEventsSchema)?.points;
const hasActions = vehiclePoint?.actions !== undefined;
const defaultAction = {
uuid: THREE.MathUtils.generateUUID(),
name: 'Action 1',
type: 'Inherit',
start: {},
hitCount: 0,
end: {},
buffer: 0
};
return {
uuid: pointUUID,
position: vehiclePoint?.position,
actions: hasActions
? {
...vehiclePoint.actions,
uuid: THREE.MathUtils.generateUUID()
}
: defaultAction,
connections: {
source: { modelUUID: obj.uuid, pointUUID },
targets: []
},
speed: vehiclePoint?.speed || 1
};
};
const backendEventData = {
type: 'Vehicle',
points: createVehiclePoint(),
};
// API
// 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;
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []),
newEventData as Types.VehicleEventsSchema
]);
socket.emit("v2:model-asset:add", data);
} }
} else { } else {

View File

@ -1,16 +1,17 @@
import * as THREE from "three"; import * as THREE from "three";
import { useEffect, useMemo } from "react"; import { useEffect, useMemo } from "react";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => { const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => {
const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { camera, controls, gl, scene, pointer, raycaster } = useThree();
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationStates, setSimulationStates } = useSimulationStates();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { floorItems, setFloorItems } = useFloorItems(); const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore(); const { socket } = useSocketStore();
@ -131,7 +132,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
return updatedItems; return updatedItems;
}); });
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid); let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default"; const organization = email ? email.split("@")[1].split(".")[0] : "default";
@ -164,7 +165,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
: [defaultAction], : [defaultAction],
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers, triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
connections: { connections: {
source: { pathUUID: obj.uuid, pointUUID }, source: { modelUUID: newFloorItem.modeluuid, pointUUID },
targets: [] targets: []
} }
}; };
@ -182,16 +183,16 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
//REST //REST
// await setFloorItemApi( // setFloorItemApi(
// organization, // organization,
// obj.uuid, // obj.uuid,
// obj.userData.name, // obj.userData.name,
// obj.userData.modelId,
// [worldPosition.x, worldPosition.y, worldPosition.z], // [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false, // false,
// true, // true,
// backendEventData // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
// ); // );
//SOCKET //SOCKET
@ -205,22 +206,102 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false, isLocked: false,
isVisible: true, isVisible: true,
eventData: backendEventData, eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
socketId: socket.id, socketId: socket.id,
}; };
const newEventData: any = backendEventData; const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed };
newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modeluuid = newFloorItem.modeluuid;
newEventData.modelName = newFloorItem.modelname; newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [ setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []), ...(prevEvents || []),
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema newEventData as Types.ConveyorEventsSchema
]); ]);
socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
} else if (eventData.type === 'Vehicle' && eventData) {
const createVehiclePoint = () => {
const pointUUID = THREE.MathUtils.generateUUID();
const vehiclePoint = (eventData as Types.VehicleEventsSchema)?.points;
const hasActions = vehiclePoint?.actions !== undefined;
const defaultAction = {
uuid: THREE.MathUtils.generateUUID(),
name: 'Action 1',
type: 'Inherit',
start: {},
hitCount: 0,
end: {},
buffer: 0
};
return {
uuid: pointUUID,
position: vehiclePoint?.position,
actions: hasActions
? {
...vehiclePoint.actions,
uuid: THREE.MathUtils.generateUUID()
}
: defaultAction,
connections: {
source: { modelUUID: obj.uuid, pointUUID },
targets: []
},
speed: vehiclePoint?.speed || 2
};
};
const backendEventData = {
type: 'Vehicle',
points: createVehiclePoint()
};
// API
// 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;
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [
...(prevEvents || []),
newEventData as Types.VehicleEventsSchema
]);
socket.emit("v2:model-asset:add", data);
} }
} else { } else {

View File

@ -1,7 +1,7 @@
import * as THREE from "three"; import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
@ -12,7 +12,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationStates, setSimulationStates } = useSimulationStates();
const { floorItems, setFloorItems } = useFloorItems(); const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore(); const { socket } = useSocketStore();
const itemsData = useRef<Types.FloorItems>([]); const itemsData = useRef<Types.FloorItems>([]);
@ -180,12 +180,12 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
return updatedItems; return updatedItems;
}); });
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid); let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default"; const organization = email ? email.split("@")[1].split(".")[0] : "default";
if (eventData) { if (eventData && eventData.type !== 'StaticMachine') {
if (eventData.type === 'Conveyor' && eventData) { if (eventData.type === 'Conveyor' && eventData) {
const backendEventData = { const backendEventData = {
@ -205,7 +205,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
// obj.userData.modelId, // obj.userData.modelId,
// false, // false,
// true, // true,
// backendEventData // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
// ); // );
//SOCKET //SOCKET
@ -219,17 +219,17 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false, isLocked: false,
isVisible: true, isVisible: true,
eventData: backendEventData, eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
socketId: socket.id, socketId: socket.id,
}; };
const newEventData: any = backendEventData; const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed };
newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modeluuid = newFloorItem.modeluuid;
newEventData.modelName = newFloorItem.modelname; newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event => const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData } ? { ...event, ...newEventData }
@ -238,7 +238,59 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
return updatedEvents; return updatedEvents;
}); });
// socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
} else if (eventData.type === 'Vehicle' && eventData) {
const backendEventData = {
type: 'Vehicle',
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;
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData }
: event
);
return updatedEvents;
});
socket.emit("v2:model-asset:add", data);
} }
} else { } else {

View File

@ -1,10 +1,11 @@
import * as THREE from "three"; import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) { function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMovedObjects, itemsGroupRef, copiedObjects, setCopiedObjects, pastedObjects, setpastedObjects, duplicatedObjects, setDuplicatedObjects, selectionGroup, boundingBoxRef }: any) {
const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { camera, controls, gl, scene, pointer, raycaster } = useThree();
@ -12,7 +13,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationStates, setSimulationStates } = useSimulationStates();
const { floorItems, setFloorItems } = useFloorItems(); const { floorItems, setFloorItems } = useFloorItems();
const { socket } = useSocketStore(); const { socket } = useSocketStore();
const itemsData = useRef<Types.FloorItems>([]); const itemsData = useRef<Types.FloorItems>([]);
@ -183,12 +184,12 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
return updatedItems; return updatedItems;
}); });
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid); let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid);
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default"; const organization = email ? email.split("@")[1].split(".")[0] : "default";
if (eventData) { if (eventData && eventData.type !== 'StaticMachine') {
if (eventData.type === 'Conveyor' && eventData) { if (eventData.type === 'Conveyor' && eventData) {
const backendEventData = { const backendEventData = {
@ -197,18 +198,18 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
speed: (eventData as Types.ConveyorEventsSchema)?.speed speed: (eventData as Types.ConveyorEventsSchema)?.speed
}; };
//REST // REST
// await setFloorItemApi( // await setFloorItemApi(
// organization, // organization,
// obj.uuid, // obj.uuid,
// obj.userData.name, // obj.userData.name,
// obj.userData.modelId,
// [worldPosition.x, worldPosition.y, worldPosition.z], // [worldPosition.x, worldPosition.y, worldPosition.z],
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
// obj.userData.modelId,
// false, // false,
// true, // true,
// backendEventData // { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed }
// ); // );
//SOCKET //SOCKET
@ -222,17 +223,17 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
isLocked: false, isLocked: false,
isVisible: true, isVisible: true,
eventData: backendEventData, eventData: { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed },
socketId: socket.id, socketId: socket.id,
}; };
const newEventData: any = backendEventData; const newEventData: any = { type: backendEventData.type, points: backendEventData.points, speed: backendEventData.speed };
newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modeluuid = newFloorItem.modeluuid;
newEventData.modelName = newFloorItem.modelname; newEventData.modelName = newFloorItem.modelname;
newEventData.position = newFloorItem.position; newEventData.position = newFloorItem.position;
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event => const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData } ? { ...event, ...newEventData }
@ -241,11 +242,63 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
return updatedEvents; return updatedEvents;
}); });
// socket.emit("v2:model-asset:add", data); socket.emit("v2:model-asset:add", data);
} else if (eventData.type === 'Vehicle' && eventData) {
const backendEventData = {
type: 'Vehicle',
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;
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).map(event =>
event.modeluuid === newFloorItem.modeluuid
? { ...event, ...newEventData }
: event
);
return updatedEvents;
});
socket.emit("v2:model-asset:add", data);
} }
} else { } else {
//REST //REST
// await setFloorItemApi( // await setFloorItemApi(

View File

@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox"; import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
import { SelectionHelper } from "./selectionHelper"; import { SelectionHelper } from "./selectionHelper";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store"; import { useFloorItems, useSelectedAssets, useSimulationStates, useSocketStore, useToggleView } from "../../../../store/store";
import BoundingBox from "./boundingBoxHelper"; import BoundingBox from "./boundingBoxHelper";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi'; // import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
@ -20,7 +20,7 @@ const SelectionControls: React.FC = () => {
const itemsGroupRef = useRef<THREE.Group | undefined>(undefined); const itemsGroupRef = useRef<THREE.Group | undefined>(undefined);
const selectionGroup = useRef() as Types.RefGroup; const selectionGroup = useRef() as Types.RefGroup;
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { setSimulationPaths } = useSimulationPaths(); const { setSimulationStates } = useSimulationStates();
const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]); const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
const [rotatedObjects, setRotatedObjects] = useState<THREE.Object3D[]>([]); const [rotatedObjects, setRotatedObjects] = useState<THREE.Object3D[]>([]);
@ -240,7 +240,7 @@ const SelectionControls: React.FC = () => {
} }
}); });
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => { setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid); const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid);
return updatedEvents; return updatedEvents;
}); });

View File

@ -91,7 +91,7 @@ export default function PostProcessing() {
)} )}
{selectedActionSphere && ( {selectedActionSphere && (
<Outline <Outline
selection={[selectedActionSphere.point]} selection={[selectedActionSphere.points]}
selectionLayer={10} selectionLayer={10}
width={1000} width={1000}
blendFunction={BlendFunction.ALPHA} blendFunction={BlendFunction.ALPHA}

View File

@ -53,8 +53,8 @@ import { findEnvironment } from "../../../services/factoryBuilder/environment/fi
import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility"; import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility";
import DrieHtmlTemp from "../mqttTemp/drieHtmlTemp"; import DrieHtmlTemp from "../mqttTemp/drieHtmlTemp";
import ZoneGroup from "../../builder/groups/zoneGroup"; import ZoneGroup from "../../builder/groups/zoneGroup";
import Agv from "../../builder/agv/agv";
import useModuleStore from "../../../store/useModuleStore"; import useModuleStore from "../../../store/useModuleStore";
import NavMeshCreator from "../../builder/agv/navMeshCreator";
export default function World() { export default function World() {
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
@ -367,7 +367,9 @@ export default function World() {
/> />
{/* <DrieHtmlTemp itemsGroup={itemsGroup} /> */} {/* <DrieHtmlTemp itemsGroup={itemsGroup} /> */}
{activeModule === "simulation" && <Agv lines={lines} plane={plane} />}
<NavMeshCreator lines={lines} />
</> </>
); );
} }

View File

@ -1,14 +1,14 @@
import { useFloorItems, useSimulationPaths } from '../../../store/store'; import { useFloorItems, useSimulationStates } from '../../../store/store';
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from '../../../types/world/worldTypes'; import * as Types from '../../../types/world/worldTypes';
import { useEffect } from 'react'; import { useEffect } from 'react';
function Behaviour() { function Behaviour() {
const { setSimulationPaths } = useSimulationPaths(); const { setSimulationStates } = useSimulationStates();
const { floorItems } = useFloorItems(); const { floorItems } = useFloorItems();
useEffect(() => { useEffect(() => {
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = []; const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[] = [];
// floorItems.forEach((item: Types.FloorItemType) => { // floorItems.forEach((item: Types.FloorItemType) => {
// if (item.modelfileID === "672a090f80d91ac979f4d0bd") { // if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
@ -31,7 +31,7 @@ function Behaviour() {
// rotation: [0, 0, 0], // rotation: [0, 0, 0],
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }], // actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
// triggers: [], // triggers: [],
// connections: { source: { pathUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] }, // connections: { source: { modelUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] },
// }, // },
// { // {
// uuid: middlePointUUID, // uuid: middlePointUUID,
@ -39,7 +39,7 @@ function Behaviour() {
// rotation: [0, 0, 0], // rotation: [0, 0, 0],
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }], // actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
// triggers: [], // triggers: [],
// connections: { source: { pathUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] }, // connections: { source: { modelUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] },
// }, // },
// { // {
// uuid: point2UUID, // uuid: point2UUID,
@ -47,7 +47,7 @@ function Behaviour() {
// rotation: [0, 0, 0], // rotation: [0, 0, 0],
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }], // actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
// triggers: [], // triggers: [],
// connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] }, // connections: { source: { modelUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
// }, // },
// ], // ],
// position: [...item.position], // position: [...item.position],
@ -68,7 +68,7 @@ function Behaviour() {
// uuid: pointUUID, // uuid: pointUUID,
// position: [pointPosition.x, pointPosition.y, pointPosition.z], // position: [pointPosition.x, pointPosition.y, pointPosition.z],
// actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 }, // actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
// connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] }, // connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
// speed: 2, // speed: 2,
// }, // },
// position: [...item.position], // position: [...item.position],
@ -78,7 +78,7 @@ function Behaviour() {
// } // }
// }); // });
// setSimulationPaths(newPaths); // setSimulationStates(newPaths);
// console.log('floorItems: ', floorItems); // console.log('floorItems: ', floorItems);
}, [floorItems]); }, [floorItems]);

View File

@ -3,17 +3,21 @@ import React, { useEffect, useState } from 'react';
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from '../../../types/world/worldTypes'; import * as Types from '../../../types/world/worldTypes';
import { QuadraticBezierLine } from '@react-three/drei'; import { QuadraticBezierLine } from '@react-three/drei';
import { useIsConnecting, useSimulationPaths } from '../../../store/store'; import { useIsConnecting, useSimulationStates, useSocketStore } from '../../../store/store';
import useModuleStore from '../../../store/useModuleStore'; import useModuleStore from '../../../store/useModuleStore';
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
import { setEventApi } from '../../../services/factoryBuilder/assest/floorAsset/setEventsApt';
function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) { function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const { gl, raycaster, scene, pointer, camera } = useThree(); const { gl, raycaster, scene, pointer, camera } = useThree();
const { setIsConnecting } = useIsConnecting(); const { setIsConnecting } = useIsConnecting();
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationStates, setSimulationStates } = useSimulationStates();
const { isPlaying } = usePlayButtonStore();
const { socket } = useSocketStore();
const [firstSelected, setFirstSelected] = useState<{ const [firstSelected, setFirstSelected] = useState<{
pathUUID: string; modelUUID: string;
sphereUUID: string; sphereUUID: string;
position: THREE.Vector3; position: THREE.Vector3;
isCorner: boolean; isCorner: boolean;
@ -22,26 +26,26 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const [helperlineColor, setHelperLineColor] = useState<string>('red'); const [helperlineColor, setHelperLineColor] = useState<string>('red');
const updatePathConnections = ( const updatePathConnections = (
fromPathUUID: string, fromModelUUID: string,
fromPointUUID: string, fromPointUUID: string,
toPathUUID: string, toModelUUID: string,
toPointUUID: string toPointUUID: string
) => { ) => {
const updatedPaths = simulationPaths.map(path => { const updatedPaths = simulationStates.map(path => {
if (path.type === 'Conveyor') { if (path.type === 'Conveyor') {
if (path.modeluuid === fromPathUUID) { if (path.modeluuid === fromModelUUID) {
return { return {
...path, ...path,
points: path.points.map(point => { points: path.points.map(point => {
if (point.uuid === fromPointUUID) { if (point.uuid === fromPointUUID) {
const newTarget = { const newTarget = {
pathUUID: toPathUUID, modelUUID: toModelUUID,
pointUUID: toPointUUID pointUUID: toPointUUID
}; };
const existingTargets = point.connections.targets || []; const existingTargets = point.connections.targets || [];
if (!existingTargets.some(target => if (!existingTargets.some(target =>
target.pathUUID === newTarget.pathUUID && target.modelUUID === newTarget.modelUUID &&
target.pointUUID === newTarget.pointUUID target.pointUUID === newTarget.pointUUID
)) { )) {
return { return {
@ -57,19 +61,19 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
}) })
}; };
} }
else if (path.modeluuid === toPathUUID) { else if (path.modeluuid === toModelUUID) {
return { return {
...path, ...path,
points: path.points.map(point => { points: path.points.map(point => {
if (point.uuid === toPointUUID) { if (point.uuid === toPointUUID) {
const reverseTarget = { const reverseTarget = {
pathUUID: fromPathUUID, modelUUID: fromModelUUID,
pointUUID: fromPointUUID pointUUID: fromPointUUID
}; };
const existingTargets = point.connections.targets || []; const existingTargets = point.connections.targets || [];
if (!existingTargets.some(target => if (!existingTargets.some(target =>
target.pathUUID === reverseTarget.pathUUID && target.modelUUID === reverseTarget.modelUUID &&
target.pointUUID === reverseTarget.pointUUID target.pointUUID === reverseTarget.pointUUID
)) { )) {
return { return {
@ -86,18 +90,17 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
}; };
} }
} }
// In the updatePathConnections function, modify the Vehicle handling section:
else if (path.type === 'Vehicle') { else if (path.type === 'Vehicle') {
// Handle outgoing connections from Vehicle // Handle outgoing connections from Vehicle
if (path.modeluuid === fromPathUUID && path.point.uuid === fromPointUUID) { if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
const newTarget = { const newTarget = {
pathUUID: toPathUUID, modelUUID: toModelUUID,
pointUUID: toPointUUID pointUUID: toPointUUID
}; };
const existingTargets = path.point.connections.targets || []; const existingTargets = path.points.connections.targets || [];
// Check if target is a Conveyor // Check if target is a Conveyor
const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID); const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
if (toPath?.type !== 'Conveyor') { if (toPath?.type !== 'Conveyor') {
console.log("Vehicle can only connect to Conveyors"); console.log("Vehicle can only connect to Conveyors");
return path; return path;
@ -110,15 +113,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
if (!existingTargets.some(target => if (!existingTargets.some(target =>
target.pathUUID === newTarget.pathUUID && target.modelUUID === newTarget.modelUUID &&
target.pointUUID === newTarget.pointUUID target.pointUUID === newTarget.pointUUID
)) { )) {
return { return {
...path, ...path,
point: { points: {
...path.point, ...path.points,
connections: { connections: {
...path.point.connections, ...path.points.connections,
targets: [...existingTargets, newTarget] targets: [...existingTargets, newTarget]
} }
} }
@ -126,15 +129,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
} }
// Handle incoming connections to Vehicle // Handle incoming connections to Vehicle
else if (path.modeluuid === toPathUUID && path.point.uuid === toPointUUID) { else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
const reverseTarget = { const reverseTarget = {
pathUUID: fromPathUUID, modelUUID: fromModelUUID,
pointUUID: fromPointUUID pointUUID: fromPointUUID
}; };
const existingTargets = path.point.connections.targets || []; const existingTargets = path.points.connections.targets || [];
// Check if source is a Conveyor // Check if source is a Conveyor
const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID); const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
if (fromPath?.type !== 'Conveyor') { if (fromPath?.type !== 'Conveyor') {
console.log("Vehicle can only connect to Conveyors"); console.log("Vehicle can only connect to Conveyors");
return path; return path;
@ -147,15 +150,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
if (!existingTargets.some(target => if (!existingTargets.some(target =>
target.pathUUID === reverseTarget.pathUUID && target.modelUUID === reverseTarget.modelUUID &&
target.pointUUID === reverseTarget.pointUUID target.pointUUID === reverseTarget.pointUUID
)) { )) {
return { return {
...path, ...path,
point: { points: {
...path.point, ...path.points,
connections: { connections: {
...path.point.connections, ...path.points.connections,
targets: [...existingTargets, reverseTarget] targets: [...existingTargets, reverseTarget]
} }
} }
@ -164,14 +167,139 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
return path; 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 || [];
// // 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;
// }
// // Check if already has a connection
// if (existingTargets.length >= 1) {
// console.log("StaticMachine can have only one connection");
// 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 StaticMachine
// else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
// const reverseTarget = {
// modelUUID: fromModelUUID,
// pointUUID: fromPointUUID
// };
// const existingTargets = path.points.connections.targets || [];
// // Check if source is an ArmBot
// const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
// if (fromPath?.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;
// }
// if (!existingTargets.some(target =>
// target.modelUUID === reverseTarget.modelUUID &&
// target.pointUUID === reverseTarget.pointUUID
// )) {
// return {
// ...path,
// points: {
// ...path.points,
// connections: {
// ...path.points.connections,
// targets: [...existingTargets, reverseTarget]
// }
// }
// };
// }
// }
// return path;
// }
return path; return path;
}); });
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
const updatedPathDetails = updatedPaths.filter(path =>
path.modeluuid === fromModelUUID || path.modeluuid === toModelUUID
);
updateBackend(updatedPathDetails);
}; };
const handleAddConnection = (fromPathUUID: string, fromUUID: string, toPathUUID: string, toUUID: string) => { const updateBackend = async (updatedPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => {
updatePathConnections(fromPathUUID, fromUUID, toPathUUID, toUUID); if (updatedPaths.length === 0) return;
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "";
updatedPaths.forEach(async (updatedPath) => {
if (updatedPath.type === 'Conveyor') {
// await setEventApi(
// organization,
// updatedPath.modeluuid,
// { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
// );
const data = {
organization: organization,
modeluuid: updatedPath.modeluuid,
eventData: { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
}
socket.emit('v2:model-asset:updateEventData', data);
} else if (updatedPath.type === 'Vehicle') {
// await setEventApi(
// organization,
// updatedPath.modeluuid,
// { type: "Vehicle", points: updatedPath.points }
// );
const data = {
organization: organization,
modeluuid: updatedPath.modeluuid,
eventData: { type: "Vehicle", points: updatedPath.points }
}
socket.emit('v2:model-asset:updateEventData', data);
}
})
}
const handleAddConnection = (fromModelUUID: string, fromUUID: string, toModelUUID: string, toUUID: string) => {
updatePathConnections(fromModelUUID, fromUUID, toModelUUID, toUUID);
setFirstSelected(null); setFirstSelected(null);
setCurrentLine(null); setCurrentLine(null);
setIsConnecting(false); setIsConnecting(false);
@ -208,25 +336,25 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const intersected = intersects[0].object; const intersected = intersects[0].object;
if (intersected.name.includes("events-sphere")) { if (intersected.name.includes("events-sphere")) {
const pathUUID = intersected.userData.path.modeluuid; const modelUUID = intersected.userData.path.modeluuid;
const sphereUUID = intersected.uuid; const sphereUUID = intersected.uuid;
const worldPosition = new THREE.Vector3(); const worldPosition = new THREE.Vector3();
intersected.getWorldPosition(worldPosition); intersected.getWorldPosition(worldPosition);
let isStartOrEnd = false; let isStartOrEnd = false;
if (intersected.userData.path.points) { if (intersected.userData.path.points && intersected.userData.path.points.length > 1) {
isStartOrEnd = intersected.userData.path.points.length > 0 && ( isStartOrEnd = intersected.userData.path.points.length > 0 && (
sphereUUID === intersected.userData.path.points[0].uuid || sphereUUID === intersected.userData.path.points[0].uuid ||
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
); );
} else if (intersected.userData.path.point) { } else if (intersected.userData.path.points) {
isStartOrEnd = sphereUUID === intersected.userData.path.point.uuid; isStartOrEnd = sphereUUID === intersected.userData.path.points.uuid;
} }
if (pathUUID) { if (modelUUID) {
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected?.pathUUID); const firstPath = simulationStates.find(p => p.modeluuid === firstSelected?.modelUUID);
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID); const secondPath = simulationStates.find(p => p.modeluuid === modelUUID);
// Prevent vehicle-to-vehicle connections // Prevent vehicle-to-vehicle connections
if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') { if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') {
@ -238,23 +366,23 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
if (firstPath && secondPath && if (firstPath && secondPath &&
firstPath.type === 'Conveyor' && firstPath.type === 'Conveyor' &&
secondPath.type === 'Conveyor' && secondPath.type === 'Conveyor' &&
!firstSelected?.isCorner) { (!firstSelected?.isCorner || !isStartOrEnd)) {
console.log("Conveyor middle points can only connect to non-conveyor paths"); console.log("Conveyor connections must be between start/end points");
return; return;
} }
// Check if this specific connection already exists // Check if this specific connection already exists
const isDuplicateConnection = firstSelected const isDuplicateConnection = firstSelected
? simulationPaths.some(path => { ? simulationStates.some(path => {
if (path.modeluuid === firstSelected.pathUUID) { if (path.modeluuid === firstSelected.modelUUID) {
if (path.type === 'Conveyor') { if (path.type === 'Conveyor') {
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID); const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
return point?.connections.targets.some(t => return point?.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID t.modelUUID === modelUUID && t.pointUUID === sphereUUID
); );
} else if (path.type === 'Vehicle') { } else if (path.type === 'Vehicle') {
return path.point.connections.targets.some(t => return path.points.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID t.modelUUID === modelUUID && t.pointUUID === sphereUUID
); );
} }
} }
@ -269,7 +397,8 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
// For Vehicles, check if they're already connected to anything // For Vehicles, check if they're already connected to anything
if (intersected.userData.path.type === 'Vehicle') { if (intersected.userData.path.type === 'Vehicle') {
const vehicleConnections = intersected.userData.path.point.connections.targets.length; console.log('intersected: ', intersected);
const vehicleConnections = intersected.userData.path.points.connections.targets.length;
if (vehicleConnections >= 1) { if (vehicleConnections >= 1) {
console.log("Vehicle can only have one connection"); console.log("Vehicle can only have one connection");
return; return;
@ -278,7 +407,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
// For non-Vehicle paths, check if already connected // For non-Vehicle paths, check if already connected
if (intersected.userData.path.type !== 'Vehicle') { if (intersected.userData.path.type !== 'Vehicle') {
const isAlreadyConnected = simulationPaths.some(path => { const isAlreadyConnected = simulationStates.some(path => {
if (path.type === 'Conveyor') { if (path.type === 'Conveyor') {
return path.points.some(point => return path.points.some(point =>
point.uuid === sphereUUID && point.uuid === sphereUUID &&
@ -303,7 +432,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
} }
// Prevent same-path connections // Prevent same-path connections
if (firstSelected.pathUUID === pathUUID) { if (firstSelected.modelUUID === modelUUID) {
console.log("Cannot connect spheres on the same path."); console.log("Cannot connect spheres on the same path.");
return; return;
} }
@ -316,15 +445,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
// All checks passed - make the connection // All checks passed - make the connection
handleAddConnection( handleAddConnection(
firstSelected.pathUUID, firstSelected.modelUUID,
firstSelected.sphereUUID, firstSelected.sphereUUID,
pathUUID, modelUUID,
sphereUUID sphereUUID
); );
} else { } else {
// First selection - just store it // First selection - just store it
setFirstSelected({ setFirstSelected({
pathUUID, modelUUID,
sphereUUID, sphereUUID,
position: worldPosition, position: worldPosition,
isCorner: isStartOrEnd isCorner: isStartOrEnd
@ -358,7 +487,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
canvasElement.removeEventListener("mousemove", onMouseMove); canvasElement.removeEventListener("mousemove", onMouseMove);
canvasElement.removeEventListener("contextmenu", onContextMenu); canvasElement.removeEventListener("contextmenu", onContextMenu);
}; };
}, [camera, scene, raycaster, firstSelected, simulationPaths]); }, [camera, scene, raycaster, firstSelected, simulationStates]);
useFrame(() => { useFrame(() => {
if (firstSelected) { if (firstSelected) {
@ -372,7 +501,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
); );
let point: THREE.Vector3 | null = null; let point: THREE.Vector3 | null = null;
let snappedSphere: { sphereUUID: string, position: THREE.Vector3, pathUUID: string, isCorner: boolean } | null = null; let snappedSphere: { sphereUUID: string, position: THREE.Vector3, modelUUID: string, isCorner: boolean } | null = null;
let isInvalidConnection = false; let isInvalidConnection = false;
if (intersects.length > 0) { if (intersects.length > 0) {
@ -392,10 +521,10 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const spherePosition = new THREE.Vector3(); const spherePosition = new THREE.Vector3();
sphere.getWorldPosition(spherePosition); sphere.getWorldPosition(spherePosition);
const pathData = sphere.userData.path; const pathData = sphere.userData.path;
const pathUUID = pathData.modeluuid; const modelUUID = pathData.modeluuid;
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected.pathUUID); const firstPath = simulationStates.find(p => p.modeluuid === firstSelected.modelUUID);
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID); const secondPath = simulationStates.find(p => p.modeluuid === modelUUID);
const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle'; const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle';
// Inside the useFrame hook, where we check for snapped spheres: // Inside the useFrame hook, where we check for snapped spheres:
@ -410,16 +539,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
!firstSelected.isCorner); !firstSelected.isCorner);
// Check for duplicate connection (regardless of path type) // Check for duplicate connection (regardless of path type)
const isDuplicateConnection = simulationPaths.some(path => { const isDuplicateConnection = simulationStates.some(path => {
if (path.modeluuid === firstSelected.pathUUID) { if (path.modeluuid === firstSelected.modelUUID) {
if (path.type === 'Conveyor') { if (path.type === 'Conveyor') {
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID); const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
return point?.connections.targets.some(t => return point?.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID t.modelUUID === modelUUID && t.pointUUID === sphereUUID
); );
} else if (path.type === 'Vehicle') { } else if (path.type === 'Vehicle') {
return path.point.connections.targets.some(t => return path.points.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID t.modelUUID === modelUUID && t.pointUUID === sphereUUID
); );
} }
} }
@ -428,7 +557,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
// For non-Vehicle paths, check if already connected // For non-Vehicle paths, check if already connected
const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' && const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' &&
simulationPaths.some(path => { simulationStates.some(path => {
if (path.type === 'Conveyor') { if (path.type === 'Conveyor') {
return path.points.some(point => return path.points.some(point =>
point.uuid === sphereUUID && point.uuid === sphereUUID &&
@ -440,7 +569,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
// Check vehicle connection rules // Check vehicle connection rules
const isVehicleAtMaxConnections = pathData.type === 'Vehicle' && const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
pathData.point.connections.targets.length >= 1; pathData.points.connections.targets.length >= 1;
const isVehicleConnectingToNonConveyor = const isVehicleConnectingToNonConveyor =
(firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') || (firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
(secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor'); (secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor');
@ -452,13 +581,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
!isVehicleAtMaxConnections && !isVehicleAtMaxConnections &&
!isVehicleConnectingToNonConveyor && !isVehicleConnectingToNonConveyor &&
firstSelected.sphereUUID !== sphereUUID && firstSelected.sphereUUID !== sphereUUID &&
firstSelected.pathUUID !== pathUUID && firstSelected.modelUUID !== modelUUID &&
(firstSelected.isCorner || isConnectable) (firstSelected.isCorner || isConnectable) &&
!(firstPath?.type === 'Conveyor' &&
pathData.type === 'Conveyor' &&
!(firstSelected.isCorner && isConnectable))
) { ) {
snappedSphere = { snappedSphere = {
sphereUUID, sphereUUID,
position: spherePosition, position: spherePosition,
pathUUID, modelUUID,
isCorner: isConnectable isCorner: isConnectable
}; };
} else { } else {
@ -501,12 +633,12 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
}); });
return ( return (
<> <group name='simulationConnectionGroup' visible={!isPlaying} >
{simulationPaths.flatMap(path => { {simulationStates.flatMap(path => {
if (path.type === 'Conveyor') { if (path.type === 'Conveyor') {
return path.points.flatMap(point => return path.points.flatMap(point =>
point.connections.targets.map((target, index) => { point.connections.targets.map((target, index) => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
if (targetPath?.type === 'Vehicle') return null; if (targetPath?.type === 'Vehicle') return null;
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid); const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
@ -545,8 +677,8 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
}) })
); );
} else if (path.type === 'Vehicle') { } else if (path.type === 'Vehicle') {
return path.point.connections.targets.map((target, index) => { return path.points.connections.targets.map((target, index) => {
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.point.uuid); const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid);
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID); const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
if (fromSphere && toSphere) { if (fromSphere && toSphere) {
@ -566,7 +698,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
return ( return (
<QuadraticBezierLine <QuadraticBezierLine
key={`${path.point.uuid}-${target.pointUUID}-${index}`} key={`${path.points.uuid}-${target.pointUUID}-${index}`}
start={fromWorldPosition.toArray()} start={fromWorldPosition.toArray()}
end={toWorldPosition.toArray()} end={toWorldPosition.toArray()}
mid={midPoint.toArray()} mid={midPoint.toArray()}
@ -596,7 +728,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
dashScale={20} dashScale={20}
/> />
)} )}
</> </group>
); );
} }

View File

@ -3,362 +3,340 @@ import * as Types from "../../../types/world/worldTypes";
import { useRef, useState, useEffect, useMemo } from "react"; import { useRef, useState, useEffect, useMemo } from "react";
import { Sphere, TransformControls } from "@react-three/drei"; import { Sphere, TransformControls } from "@react-three/drei";
import { import {
useEditingPoint, useEditingPoint,
useEyeDropMode, useEyeDropMode,
useIsConnecting, useIsConnecting,
usePreviewPosition, usePreviewPosition,
useRenderDistance, useRenderDistance,
useSelectedActionSphere, useSelectedActionSphere,
useSelectedPath, useSelectedPath,
useSimulationPaths, useSimulationStates,
} from "../../../store/store"; } from "../../../store/store";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { useSubModuleStore } from "../../../store/useModuleStore"; import { useSubModuleStore } from "../../../store/useModuleStore";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import { setEventApi } from "../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
function PathCreation({ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObject<THREE.Group>; }) {
pathsGroupRef, const { isPlaying } = usePlayButtonStore();
}: { const { renderDistance } = useRenderDistance();
pathsGroupRef: React.MutableRefObject<THREE.Group>; const { setSubModule } = useSubModuleStore();
}) { const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
const { isPlaying } = usePlayButtonStore(); const { eyeDropMode, setEyeDropMode } = useEyeDropMode();
const { renderDistance } = useRenderDistance(); const { editingPoint, setEditingPoint } = useEditingPoint();
const { setSubModule } = useSubModuleStore(); const { previewPosition, setPreviewPosition } = usePreviewPosition();
const { setSelectedActionSphere, selectedActionSphere } = const { raycaster, camera, pointer, gl } = useThree();
useSelectedActionSphere(); const { setSelectedPath } = useSelectedPath();
const { eyeDropMode, setEyeDropMode } = useEyeDropMode(); const { simulationStates, setSimulationStates } = useSimulationStates();
const { editingPoint, setEditingPoint } = useEditingPoint(); const { isConnecting } = useIsConnecting();
const { previewPosition, setPreviewPosition } = usePreviewPosition(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { raycaster, camera, pointer, gl } = useThree();
const plane = useMemo(
() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
[]
);
const { setSelectedPath } = useSelectedPath();
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
const { isConnecting } = useIsConnecting();
const groupRefs = useRef<{ [key: string]: THREE.Group }>({}); const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
const isMovingRef = useRef(false); const isMovingRef = useRef(false);
const transformRef = useRef<any>(null); const transformRef = useRef<any>(null);
const [transformMode, setTransformMode] = useState< const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
"translate" | "rotate" | null
>(null);
useEffect(() => { useEffect(() => {
setTransformMode(null); setTransformMode(null);
const handleKeyDown = (e: KeyboardEvent) => { const handleKeyDown = (e: KeyboardEvent) => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
if (e.key === "g") { if (e.key === "g") {
setTransformMode((prev) => (prev === "translate" ? null : "translate")); setTransformMode((prev) => (prev === "translate" ? null : "translate"));
} }
if (e.key === "r") { if (e.key === "r") {
setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
} }
}; };
window.addEventListener("keydown", handleKeyDown); window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown);
}, [selectedActionSphere]); }, [selectedActionSphere]);
useFrame(() => { useFrame(() => {
Object.values(groupRefs.current).forEach((group) => { Object.values(groupRefs.current).forEach((group) => {
if (group) { if (group) {
const distance = new THREE.Vector3( const distance = new THREE.Vector3(
...group.position.toArray() ...group.position.toArray()
).distanceTo(camera.position); ).distanceTo(camera.position);
group.visible = ((distance <= renderDistance) && !isPlaying); group.visible = ((distance <= renderDistance) && !isPlaying);
} }
}); });
}); });
const updateSimulationPaths = () => { const updateSimulationPaths = () => {
if (!selectedActionSphere) return; if (!selectedActionSphere) return;
const updatedPaths = simulationPaths.map((path) => { const updatedPaths = simulationStates.map((path) => {
if (path.type === "Conveyor") { if (path.type === "Conveyor") {
return { return {
...path, ...path,
points: path.points.map((point) => points: path.points.map((point) =>
point.uuid === selectedActionSphere.point.uuid point.uuid === selectedActionSphere.points.uuid
? { ? {
...point, ...point,
position: [ position: [
selectedActionSphere.point.position.x, selectedActionSphere.points.position.x,
selectedActionSphere.point.position.y, selectedActionSphere.points.position.y,
selectedActionSphere.point.position.z, selectedActionSphere.points.position.z,
], ],
rotation: [ rotation: [
selectedActionSphere.point.rotation.x, selectedActionSphere.points.rotation.x,
selectedActionSphere.point.rotation.y, selectedActionSphere.points.rotation.y,
selectedActionSphere.point.rotation.z, selectedActionSphere.points.rotation.z,
], ],
} }
: point : point
), ),
}; };
} } else {
return path; return path;
}) as Types.ConveyorEventsSchema[]; }
}) as Types.ConveyorEventsSchema[];
setSimulationPaths(updatedPaths); const updatedPath = updatedPaths.find(
}; (path) => path.type === "Conveyor" && path.points.some((point) => point.uuid === selectedActionSphere.points.uuid)
);
useFrame(() => { // console.log("Updated Path:", updatedPath);
if (eyeDropMode) {
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (point) { setSimulationStates(updatedPaths);
setPreviewPosition({ x: point.x, y: point.z }); };
}
} else {
setPreviewPosition(null);
}
});
useEffect(() => { useFrame(() => {
if (!camera) return; if (eyeDropMode) {
const canvasElement = gl.domElement; raycaster.setFromCamera(pointer, camera);
canvasElement.tabIndex = 0; const intersectionPoint = new THREE.Vector3();
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
const onPointerDown = () => { if (point) {
isMovingRef.current = false; setPreviewPosition({ x: point.x, y: point.z });
}; }
} else {
setPreviewPosition(null);
}
});
const onPointerMove = () => { useEffect(() => {
isMovingRef.current = true; if (!camera) return;
}; const canvasElement = gl.domElement;
canvasElement.tabIndex = 0;
const onPointerUp = (event: PointerEvent) => { const onPointerDown = () => {
if ( isMovingRef.current = false;
!isMovingRef.current && };
eyeDropMode &&
event.button === 0 &&
previewPosition
) {
event.preventDefault();
if (editingPoint) {
handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y);
setEditingPoint(null);
setEyeDropMode(false);
}
}
};
if (eyeDropMode) { const onPointerMove = () => {
canvasElement.addEventListener("pointerdown", onPointerDown); isMovingRef.current = true;
canvasElement.addEventListener("pointermove", onPointerMove); };
canvasElement.addEventListener("pointerup", onPointerUp);
}
return () => { const onPointerUp = (event: PointerEvent) => {
canvasElement.removeEventListener("pointerdown", onPointerDown); if (
canvasElement.removeEventListener("pointermove", onPointerMove); !isMovingRef.current &&
canvasElement.removeEventListener("pointerup", onPointerUp); eyeDropMode &&
}; event.button === 0 &&
}, [eyeDropMode, editingPoint, previewPosition]); previewPosition
) {
event.preventDefault();
if (editingPoint) {
handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y);
setEditingPoint(null);
setEyeDropMode(false);
}
}
};
const handlePointUpdate = ( if (eyeDropMode) {
pointType: "start" | "end", canvasElement.addEventListener("pointerdown", onPointerDown);
x: number, canvasElement.addEventListener("pointermove", onPointerMove);
z: number canvasElement.addEventListener("pointerup", onPointerUp);
) => { }
if (!selectedActionSphere?.point?.uuid) return;
const updatedPaths = simulationPaths.map((path) => { return () => {
if ( canvasElement.removeEventListener("pointerdown", onPointerDown);
path.type === "Vehicle" && canvasElement.removeEventListener("pointermove", onPointerMove);
path.point.uuid === selectedActionSphere.point.uuid canvasElement.removeEventListener("pointerup", onPointerUp);
) { };
return { }, [eyeDropMode, editingPoint, previewPosition]);
...path,
point: {
...path.point,
actions: {
...path.point.actions,
[pointType]: {
...path.point.actions[pointType],
x: x,
y: z,
},
},
},
};
}
return path;
});
setSimulationPaths(updatedPaths); const updateBackend = async (updatedPath: Types.VehicleEventsSchema | undefined) => {
}; if (!updatedPath) return;
const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "";
await setEventApi(
organization,
updatedPath.modeluuid,
{ type: "Vehicle", points: updatedPath.points }
);
}
return ( const handlePointUpdate = (pointType: "start" | "end", x: number, z: number) => {
<group visible={!isPlaying} name="simulation-simulationPaths-group" ref={pathsGroupRef}> if (!selectedActionSphere?.points?.uuid) return;
{simulationPaths.map((path) => { const updatedPaths = simulationStates.map((path) => {
if (path.type === "Conveyor") {
const points = path.points.map(
(point) => new THREE.Vector3(...point.position)
);
return ( if (path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid) {
<group return {
name={`${path.modeluuid}-event-path`} ...path,
key={path.modeluuid} points: {
ref={(el) => (groupRefs.current[path.modeluuid] = el!)} ...path.points,
position={path.position} actions: {
rotation={path.rotation} ...path.points.actions,
onClick={(e) => { [pointType]: { ...path.points.actions[pointType], x: x, y: z, },
if (isConnecting || eyeDropMode) return; },
e.stopPropagation(); },
setSelectedPath({ };
path, }
group: groupRefs.current[path.modeluuid], return path;
}); });
setSelectedActionSphere(null);
setTransformMode(null);
setSubModule("mechanics");
}}
onPointerMissed={() => {
if (eyeDropMode) return;
setSelectedPath(null);
setSubModule("properties");
}}
>
{path.points.map((point, index) => (
<Sphere
key={point.uuid}
uuid={point.uuid}
position={point.position}
args={[0.15, 32, 32]}
name="events-sphere"
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => {
if (isConnecting || eyeDropMode) return;
e.stopPropagation();
setSelectedActionSphere({
path,
point: sphereRefs.current[point.uuid],
});
setSubModule("mechanics");
setSelectedPath(null);
}}
userData={{ point, path }}
onPointerMissed={() => {
if (eyeDropMode) return;
setSubModule("properties");
setSelectedActionSphere(null);
}}
>
<meshStandardMaterial
color={
index === 0
? "orange"
: index === path.points.length - 1
? "blue"
: "green"
}
/>
</Sphere>
))}
{points.slice(0, -1).map((point, index) => { const updatedPath = updatedPaths.find((path): path is Types.VehicleEventsSchema => path.type === "Vehicle" && path.points.uuid === selectedActionSphere.points.uuid);
const nextPoint = points[index + 1]; updateBackend(updatedPath);
const segmentCurve = new THREE.CatmullRomCurve3([
point,
nextPoint,
]);
const tubeGeometry = new THREE.TubeGeometry(
segmentCurve,
20,
0.1,
16,
false
);
return ( setSimulationStates(updatedPaths);
<mesh };
name="event-connection-tube"
key={`tube-${index}`}
geometry={tubeGeometry}
>
<meshStandardMaterial
transparent
opacity={0.9}
color="red"
/>
</mesh>
);
})}
</group>
);
} else if (path.type === "Vehicle") {
return (
<group
name={`${path.modeluuid}-vehicle-path`}
key={path.modeluuid}
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
position={path.position}
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.point.uuid}
uuid={path.point.uuid}
position={path.point.position}
args={[0.15, 32, 32]}
name="events-sphere"
ref={(el) => (sphereRefs.current[path.point.uuid] = el!)}
onClick={(e) => {
if (isConnecting || eyeDropMode) return;
e.stopPropagation();
setSelectedActionSphere({
path,
point: sphereRefs.current[path.point.uuid],
});
setSubModule("mechanics");
setSelectedPath(null);
}}
userData={{ point: path.point, path }}
onPointerMissed={() => {
if (eyeDropMode) return;
setSubModule("properties");
setSelectedActionSphere(null);
}}
>
<meshStandardMaterial color="purple" />
</Sphere>
</group>
);
}
return null;
})}
{selectedActionSphere && transformMode && ( return (
<TransformControls <group visible={!isPlaying} name="simulation-simulationStates-group" ref={pathsGroupRef}>
ref={transformRef} {simulationStates.map((path) => {
object={selectedActionSphere.point} if (path.type === "Conveyor") {
mode={transformMode} const points = path.points.map(
onMouseUp={updateSimulationPaths} (point) => new THREE.Vector3(...point.position)
/> );
)}
</group> return (
); <group
name={`${path.modeluuid}-${path.type}-path`}
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");
}}
>
{path.points.map((point, index) => (
<Sphere
key={point.uuid}
uuid={point.uuid}
position={point.position}
args={[0.15, 32, 32]}
name="events-sphere"
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
onClick={(e) => {
if (isConnecting || eyeDropMode) return;
e.stopPropagation();
setSelectedActionSphere({
path,
points: sphereRefs.current[point.uuid],
});
setSubModule("mechanics");
setSelectedPath(null);
}}
userData={{ points, path }}
onPointerMissed={() => {
if (eyeDropMode) return;
setSubModule("properties");
setSelectedActionSphere(null);
}}
>
<meshStandardMaterial
color={index === 0 ? "orange" : index === path.points.length - 1 ? "blue" : "green"}
/>
</Sphere>
))}
{points.slice(0, -1).map((point, index) => {
const nextPoint = points[index + 1];
const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint,]);
const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false);
return (
<mesh name="event-connection-tube" key={`tube-${index}`} geometry={tubeGeometry}>
<meshStandardMaterial transparent opacity={0.9} color="red" />
</mesh>
);
})}
</group>
);
} else if (path.type === "Vehicle" || path.type === "StaticMachine") {
return (
<group
name={`${path.modeluuid}-${path.type}-path`}
key={path.modeluuid}
ref={(el) => (groupRefs.current[path.modeluuid] = el!)}
position={path.position}
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="purple" />
</Sphere>
</group>
);
}
return null;
})}
{selectedActionSphere && transformMode && (
<TransformControls
ref={transformRef}
object={selectedActionSphere.points}
mode={transformMode}
onMouseUp={updateSimulationPaths}
/>
)}
</group>
);
} }
export default PathCreation; export default PathCreation;

View File

@ -1,916 +0,0 @@
// // animation-worker.js
// // This web worker handles animation calculations off the main thread
// /* eslint-disable no-restricted-globals */
// // The above disables the ESLint rule for this file since 'self' is valid in web workers
// // Store process data, animation states, and objects
// let processes = [];
// let animationStates = {};
// let lastTimestamp = 0;
// // Message handler for communication with main thread
// self.onmessage = function (event) {
// const { type, data } = event.data;
// switch (type) {
// case "initialize":
// processes = data.processes;
// initializeAnimationStates();
// break;
// case "update":
// const { timestamp, isPlaying } = data;
// if (isPlaying) {
// const delta = (timestamp - lastTimestamp) / 1000; // Convert to seconds
// updateAnimations(delta, timestamp);
// }
// lastTimestamp = timestamp;
// break;
// case "reset":
// resetAnimations();
// break;
// case "togglePlay":
// // If resuming from pause, recalculate the time delta
// lastTimestamp = data.timestamp;
// break;
// }
// };
// // Initialize animation states for all processes
// function initializeAnimationStates() {
// animationStates = {};
// processes.forEach((process) => {
// animationStates[process.id] = {
// spawnedObjects: {},
// nextSpawnTime: 0,
// objectIdCounter: 0,
// };
// });
// // Send initial states back to main thread
// self.postMessage({
// type: "statesInitialized",
// data: { animationStates },
// });
// }
// // Reset all animations
// function resetAnimations() {
// initializeAnimationStates();
// }
// // Find spawn point in a process
// function findSpawnPoint(process) {
// for (const path of process.paths || []) {
// for (const point of path.points || []) {
// const spawnAction = point.actions?.find(
// (a) => a.isUsed && a.type === "Spawn"
// );
// if (spawnAction) {
// return { point, path };
// }
// }
// }
// return null;
// }
// // Create a new spawned object with proper initial position
// function createSpawnedObject(process, spawnPoint, currentTime, materialType) {
// // Extract spawn position from the actual spawn point
// const position = spawnPoint.point.position
// ? [...spawnPoint.point.position]
// : [0, 0, 0];
// // Get the path position and add it to the spawn point position
// const pathPosition = spawnPoint.path.pathPosition || [0, 0, 0];
// const absolutePosition = [
// position[0] + pathPosition[0],
// position[1] + pathPosition[1],
// position[2] + pathPosition[2],
// ];
// return {
// id: `obj-${process.id}-${animationStates[process.id].objectIdCounter}`,
// position: absolutePosition,
// state: {
// currentIndex: 0,
// progress: 0,
// isAnimating: true,
// speed: process.speed || 1,
// isDelaying: false,
// delayStartTime: 0,
// currentDelayDuration: 0,
// delayComplete: false,
// currentPathIndex: 0,
// // Store the spawn point index to start animation from correct path point
// spawnPointIndex: getPointIndexInProcess(process, spawnPoint.point),
// },
// visible: true,
// materialType: materialType || "Default",
// spawnTime: currentTime,
// };
// }
// // Get the index of a point within the process animation path
// function getPointIndexInProcess(process, point) {
// if (!process.paths) return 0;
// let cumulativePoints = 0;
// for (const path of process.paths) {
// for (let i = 0; i < (path.points?.length || 0); i++) {
// if (path.points[i].uuid === point.uuid) {
// return cumulativePoints + i;
// }
// }
// cumulativePoints += path.points?.length || 0;
// }
// return 0;
// }
// // Get point data for current animation index
// function getPointDataForAnimationIndex(process, index) {
// if (!process.paths) return null;
// let cumulativePoints = 0;
// for (const path of process.paths) {
// const pointCount = path.points?.length || 0;
// if (index < cumulativePoints + pointCount) {
// const pointIndex = index - cumulativePoints;
// return path.points?.[pointIndex] || null;
// }
// cumulativePoints += pointCount;
// }
// return null;
// }
// // Convert process paths to Vector3 format
// function getProcessPath(process) {
// return process.animationPath?.map((p) => ({ x: p.x, y: p.y, z: p.z })) || [];
// }
// // Handle material swap for an object
// function handleMaterialSwap(processId, objectId, materialType) {
// const processState = animationStates[processId];
// if (!processState || !processState.spawnedObjects[objectId]) return;
// processState.spawnedObjects[objectId].materialType = materialType;
// // Notify main thread about material change
// self.postMessage({
// type: "materialChanged",
// data: {
// processId,
// objectId,
// materialType,
// },
// });
// }
// // Handle point actions for an object
// function handlePointActions(processId, objectId, actions = [], currentTime) {
// let shouldStopAnimation = false;
// const processState = animationStates[processId];
// if (!processState || !processState.spawnedObjects[objectId]) return false;
// const objectState = processState.spawnedObjects[objectId];
// actions.forEach((action) => {
// if (!action.isUsed) return;
// switch (action.type) {
// case "Delay":
// if (objectState.state.isDelaying) return;
// const delayDuration =
// typeof action.delay === "number"
// ? action.delay
// : parseFloat(action.delay || "0");
// if (delayDuration > 0) {
// objectState.state.isDelaying = true;
// objectState.state.delayStartTime = currentTime;
// objectState.state.currentDelayDuration = delayDuration;
// objectState.state.delayComplete = false;
// shouldStopAnimation = true;
// }
// break;
// case "Despawn":
// delete processState.spawnedObjects[objectId];
// shouldStopAnimation = true;
// // Notify main thread about despawn
// self.postMessage({
// type: "objectDespawned",
// data: {
// processId,
// objectId,
// },
// });
// break;
// case "Swap":
// if (action.material) {
// handleMaterialSwap(processId, objectId, action.material);
// }
// break;
// default:
// break;
// }
// });
// return shouldStopAnimation;
// }
// // Check if point has non-inherit actions
// function hasNonInheritActions(actions = []) {
// return actions.some((action) => action.isUsed && action.type !== "Inherit");
// }
// // Calculate vector lerp (linear interpolation)
// function lerpVectors(v1, v2, alpha) {
// return {
// x: v1.x + (v2.x - v1.x) * alpha,
// y: v1.y + (v2.y - v1.y) * alpha,
// z: v1.z + (v2.z - v1.z) * alpha,
// };
// }
// // Calculate vector distance
// function distanceBetweenVectors(v1, v2) {
// const dx = v2.x - v1.x;
// const dy = v2.y - v1.y;
// const dz = v2.z - v1.z;
// return Math.sqrt(dx * dx + dy * dy + dz * dz);
// }
// // Process spawn logic
// function processSpawns(currentTime) {
// processes.forEach((process) => {
// const processState = animationStates[process.id];
// if (!processState) return;
// const spawnPointData = findSpawnPoint(process);
// if (!spawnPointData || !spawnPointData.point.actions) return;
// const spawnAction = spawnPointData.point.actions.find(
// (a) => a.isUsed && a.type === "Spawn"
// );
// if (!spawnAction) return;
// const spawnInterval =
// typeof spawnAction.spawnInterval === "number"
// ? spawnAction.spawnInterval
// : parseFloat(spawnAction.spawnInterval || "0");
// if (currentTime >= processState.nextSpawnTime) {
// const newObject = createSpawnedObject(
// process,
// spawnPointData,
// currentTime,
// spawnAction.material || "Default"
// );
// processState.spawnedObjects[newObject.id] = newObject;
// processState.objectIdCounter++;
// processState.nextSpawnTime = currentTime + spawnInterval;
// // Notify main thread about new object
// self.postMessage({
// type: "objectSpawned",
// data: {
// processId: process.id,
// object: newObject,
// },
// });
// }
// });
// }
// // Update all animations
// function updateAnimations(delta, currentTime) {
// // First handle spawning of new objects
// processSpawns(currentTime);
// // Then animate existing objects
// processes.forEach((process) => {
// const processState = animationStates[process.id];
// if (!processState) return;
// const path = getProcessPath(process);
// if (path.length < 2) return;
// const updatedObjects = {};
// let hasChanges = false;
// Object.entries(processState.spawnedObjects).forEach(([objectId, obj]) => {
// if (!obj.visible || !obj.state.isAnimating) return;
// const stateRef = obj.state;
// // Use the spawnPointIndex as starting point if it's the initial movement
// if (stateRef.currentIndex === 0 && stateRef.progress === 0) {
// stateRef.currentIndex = stateRef.spawnPointIndex || 0;
// }
// // Get current point data
// const currentPointData = getPointDataForAnimationIndex(
// process,
// stateRef.currentIndex
// );
// // Execute actions when arriving at a new point
// if (stateRef.progress === 0 && currentPointData?.actions) {
// const shouldStop = handlePointActions(
// process.id,
// objectId,
// currentPointData.actions,
// currentTime
// );
// if (shouldStop) return;
// }
// // Handle delays
// if (stateRef.isDelaying) {
// if (
// currentTime - stateRef.delayStartTime >=
// stateRef.currentDelayDuration
// ) {
// stateRef.isDelaying = false;
// stateRef.delayComplete = true;
// } else {
// updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
// return; // Keep waiting
// }
// }
// const nextPointIdx = stateRef.currentIndex + 1;
// const isLastPoint = nextPointIdx >= path.length;
// if (isLastPoint) {
// if (currentPointData?.actions) {
// const shouldStop = !hasNonInheritActions(currentPointData.actions);
// if (shouldStop) {
// // Reached the end of path with no more actions
// delete processState.spawnedObjects[objectId];
// // Notify main thread to remove the object
// self.postMessage({
// type: "objectCompleted",
// data: {
// processId: process.id,
// objectId,
// },
// });
// return;
// }
// }
// }
// if (!isLastPoint) {
// const currentPos = path[stateRef.currentIndex];
// const nextPos = path[nextPointIdx];
// const distance = distanceBetweenVectors(currentPos, nextPos);
// const movement = stateRef.speed * delta;
// // Update progress based on distance and speed
// const oldProgress = stateRef.progress;
// stateRef.progress += movement / distance;
// if (stateRef.progress >= 1) {
// // Reached next point
// stateRef.currentIndex = nextPointIdx;
// stateRef.progress = 0;
// stateRef.delayComplete = false;
// obj.position = [nextPos.x, nextPos.y, nextPos.z];
// } else {
// // Interpolate position
// const lerpedPos = lerpVectors(currentPos, nextPos, stateRef.progress);
// obj.position = [lerpedPos.x, lerpedPos.y, lerpedPos.z];
// }
// // Only send updates when there's meaningful movement
// if (Math.abs(oldProgress - stateRef.progress) > 0.01) {
// hasChanges = true;
// }
// }
// updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
// });
// // Update animation state with modified objects
// if (Object.keys(updatedObjects).length > 0) {
// processState.spawnedObjects = {
// ...processState.spawnedObjects,
// ...updatedObjects,
// };
// // Only send position updates when there are meaningful changes
// if (hasChanges) {
// self.postMessage({
// type: "positionsUpdated",
// data: {
// processId: process.id,
// objects: updatedObjects,
// },
// });
// }
// }
// });
// }
// animation-worker.js
// This web worker handles animation calculations off the main thread
/* eslint-disable no-restricted-globals */
// The above disables the ESLint rule for this file since 'self' is valid in web workers
// Store process data, animation states, and objects
let processes = [];
let animationStates = {};
let lastTimestamp = 0;
let debugMode = true;
// Logger function for debugging
function log(...args) {
if (debugMode) {
self.postMessage({
type: "debug",
data: { message: args.join(' ') }
});
}
}
// Message handler for communication with main thread
self.onmessage = function (event) {
const { type, data } = event.data;
log(`Worker received message: ${type}`);
switch (type) {
case "initialize":
processes = data.processes;
log(`Initialized with ${processes.length} processes`);
initializeAnimationStates();
break;
case "update":
const { timestamp, isPlaying } = data;
if (isPlaying) {
const delta = lastTimestamp === 0 ? 0.016 : (timestamp - lastTimestamp) / 1000; // Convert to seconds
updateAnimations(delta, timestamp);
}
lastTimestamp = timestamp;
break;
case "reset":
log("Resetting animations");
resetAnimations();
break;
case "togglePlay":
// If resuming from pause, recalculate the time delta
log(`Toggle play: ${data.isPlaying}`);
lastTimestamp = data.timestamp;
break;
case "setDebug":
debugMode = data.enabled;
log(`Debug mode: ${debugMode}`);
break;
}
};
// Initialize animation states for all processes
function initializeAnimationStates() {
animationStates = {};
processes.forEach((process) => {
if (!process || !process.id) {
log("Invalid process found:", process);
return;
}
animationStates[process.id] = {
spawnedObjects: {},
nextSpawnTime: 0,
objectIdCounter: 0,
};
});
// Send initial states back to main thread
self.postMessage({
type: "statesInitialized",
data: { animationStates },
});
}
// Reset all animations
function resetAnimations() {
initializeAnimationStates();
}
// Find spawn point in a process
function findSpawnPoint(process) {
if (!process || !process.paths) {
log(`No paths found for process ${process?.id}`);
return null;
}
for (const path of process.paths) {
if (!path || !path.points) continue;
for (const point of path.points) {
if (!point || !point.actions) continue;
const spawnAction = point.actions.find(
(a) => a && a.isUsed && a.type === "Spawn"
);
if (spawnAction) {
return { point, path };
}
}
}
log(`No spawn points found for process ${process.id}`);
return null;
}
// Create a new spawned object with proper initial position
function createSpawnedObject(process, spawnPoint, currentTime, materialType) {
// Extract spawn position from the actual spawn point
const position = spawnPoint.point.position
? [...spawnPoint.point.position]
: [0, 0, 0];
// Get the path position and add it to the spawn point position
const pathPosition = spawnPoint.path.pathPosition || [0, 0, 0];
const absolutePosition = [
position[0] + pathPosition[0],
position[1] + pathPosition[1],
position[2] + pathPosition[2],
];
return {
id: `obj-${process.id}-${animationStates[process.id].objectIdCounter}`,
position: absolutePosition,
state: {
currentIndex: 0,
progress: 0,
isAnimating: true,
speed: process.speed || 1,
isDelaying: false,
delayStartTime: 0,
currentDelayDuration: 0,
delayComplete: false,
currentPathIndex: 0,
// Store the spawn point index to start animation from correct path point
spawnPointIndex: getPointIndexInProcess(process, spawnPoint.point),
},
visible: true,
materialType: materialType || "Default",
spawnTime: currentTime,
};
}
// Get the index of a point within the process animation path
function getPointIndexInProcess(process, point) {
if (!process.paths) return 0;
let cumulativePoints = 0;
for (const path of process.paths) {
for (let i = 0; i < (path.points?.length || 0); i++) {
if (path.points[i].uuid === point.uuid) {
return cumulativePoints + i;
}
}
cumulativePoints += path.points?.length || 0;
}
return 0;
}
// Get point data for current animation index
function getPointDataForAnimationIndex(process, index) {
if (!process.paths) return null;
let cumulativePoints = 0;
for (const path of process.paths) {
const pointCount = path.points?.length || 0;
if (index < cumulativePoints + pointCount) {
const pointIndex = index - cumulativePoints;
return path.points?.[pointIndex] || null;
}
cumulativePoints += pointCount;
}
return null;
}
// Convert process paths to Vector3 format
function getProcessPath(process) {
if (!process.animationPath) {
log(`No animation path for process ${process.id}`);
return [];
}
return process.animationPath.map((p) => ({ x: p.x, y: p.y, z: p.z })) || [];
}
// Handle material swap for an object
function handleMaterialSwap(processId, objectId, materialType) {
const processState = animationStates[processId];
if (!processState || !processState.spawnedObjects[objectId]) return;
processState.spawnedObjects[objectId].materialType = materialType;
// Notify main thread about material change
self.postMessage({
type: "materialChanged",
data: {
processId,
objectId,
materialType,
},
});
}
// Handle point actions for an object
function handlePointActions(processId, objectId, actions = [], currentTime) {
let shouldStopAnimation = false;
const processState = animationStates[processId];
if (!processState || !processState.spawnedObjects[objectId]) return false;
const objectState = processState.spawnedObjects[objectId];
actions.forEach((action) => {
if (!action || !action.isUsed) return;
switch (action.type) {
case "Delay":
if (objectState.state.isDelaying) return;
const delayDuration =
typeof action.delay === "number"
? action.delay
: parseFloat(action.delay || "0");
if (delayDuration > 0) {
objectState.state.isDelaying = true;
objectState.state.delayStartTime = currentTime;
objectState.state.currentDelayDuration = delayDuration;
objectState.state.delayComplete = false;
shouldStopAnimation = true;
}
break;
case "Despawn":
delete processState.spawnedObjects[objectId];
shouldStopAnimation = true;
// Notify main thread about despawn
self.postMessage({
type: "objectDespawned",
data: {
processId,
objectId,
},
});
break;
case "Swap":
if (action.material) {
handleMaterialSwap(processId, objectId, action.material);
}
break;
default:
break;
}
});
return shouldStopAnimation;
}
// Check if point has non-inherit actions
function hasNonInheritActions(actions = []) {
return actions.some((action) => action && action.isUsed && action.type !== "Inherit");
}
// Calculate vector lerp (linear interpolation)
function lerpVectors(v1, v2, alpha) {
return {
x: v1.x + (v2.x - v1.x) * alpha,
y: v1.y + (v2.y - v1.y) * alpha,
z: v1.z + (v2.z - v1.z) * alpha,
};
}
// Calculate vector distance
function distanceBetweenVectors(v1, v2) {
const dx = v2.x - v1.x;
const dy = v2.y - v1.y;
const dz = v2.z - v1.z;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
// Process spawn logic
function processSpawns(currentTime) {
processes.forEach((process) => {
const processState = animationStates[process.id];
if (!processState) return;
const spawnPointData = findSpawnPoint(process);
if (!spawnPointData || !spawnPointData.point.actions) return;
const spawnAction = spawnPointData.point.actions.find(
(a) => a.isUsed && a.type === "Spawn"
);
if (!spawnAction) return;
const spawnInterval =
typeof spawnAction.spawnInterval === "number"
? spawnAction.spawnInterval
: parseFloat(spawnAction.spawnInterval || "2"); // Default to 2 seconds if not specified
if (currentTime >= processState.nextSpawnTime) {
const newObject = createSpawnedObject(
process,
spawnPointData,
currentTime,
spawnAction.material || "Default"
);
processState.spawnedObjects[newObject.id] = newObject;
processState.objectIdCounter++;
processState.nextSpawnTime = currentTime + spawnInterval;
log(`Spawned object ${newObject.id} for process ${process.id}`);
// Notify main thread about new object
self.postMessage({
type: "objectSpawned",
data: {
processId: process.id,
object: newObject,
},
});
}
});
}
// Update all animations
function updateAnimations(delta, currentTime) {
// First handle spawning of new objects
processSpawns(currentTime);
// Then animate existing objects
processes.forEach((process) => {
const processState = animationStates[process.id];
if (!processState) return;
const path = getProcessPath(process);
if (path.length < 2) {
log(`Path too short for process ${process.id}, length: ${path.length}`);
return;
}
const updatedObjects = {};
let hasChanges = false;
Object.entries(processState.spawnedObjects).forEach(([objectId, obj]) => {
if (!obj.visible || !obj.state.isAnimating) return;
const stateRef = obj.state;
// Use the spawnPointIndex as starting point if it's the initial movement
if (stateRef.currentIndex === 0 && stateRef.progress === 0) {
stateRef.currentIndex = stateRef.spawnPointIndex || 0;
}
// Get current point data
const currentPointData = getPointDataForAnimationIndex(
process,
stateRef.currentIndex
);
// Execute actions when arriving at a new point
if (stateRef.progress === 0 && currentPointData?.actions) {
const shouldStop = handlePointActions(
process.id,
objectId,
currentPointData.actions,
currentTime
);
if (shouldStop) return;
}
// Handle delays
if (stateRef.isDelaying) {
if (
currentTime - stateRef.delayStartTime >=
stateRef.currentDelayDuration
) {
stateRef.isDelaying = false;
stateRef.delayComplete = true;
} else {
updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
return; // Keep waiting
}
}
const nextPointIdx = stateRef.currentIndex + 1;
const isLastPoint = nextPointIdx >= path.length;
if (isLastPoint) {
if (currentPointData?.actions) {
const shouldStop = !hasNonInheritActions(currentPointData.actions);
if (shouldStop) {
// Reached the end of path with no more actions
delete processState.spawnedObjects[objectId];
log(`Object ${objectId} completed path`);
// Notify main thread to remove the object
self.postMessage({
type: "objectCompleted",
data: {
processId: process.id,
objectId,
},
});
return;
}
}
}
if (!isLastPoint) {
const currentPos = path[stateRef.currentIndex];
const nextPos = path[nextPointIdx];
const distance = distanceBetweenVectors(currentPos, nextPos);
// Ensure we don't divide by zero
if (distance > 0) {
const movement = stateRef.speed * delta;
// Update progress based on distance and speed
const oldProgress = stateRef.progress;
stateRef.progress += movement / distance;
if (stateRef.progress >= 1) {
// Reached next point
stateRef.currentIndex = nextPointIdx;
stateRef.progress = 0;
stateRef.delayComplete = false;
obj.position = [nextPos.x, nextPos.y, nextPos.z];
} else {
// Interpolate position
const lerpedPos = lerpVectors(currentPos, nextPos, stateRef.progress);
obj.position = [lerpedPos.x, lerpedPos.y, lerpedPos.z];
}
// Only send updates when there's meaningful movement
if (Math.abs(oldProgress - stateRef.progress) > 0.01) {
hasChanges = true;
}
} else {
// Skip to next point if distance is zero
stateRef.currentIndex = nextPointIdx;
stateRef.progress = 0;
obj.position = [nextPos.x, nextPos.y, nextPos.z];
hasChanges = true;
}
}
updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
});
// Update animation state with modified objects
if (Object.keys(updatedObjects).length > 0) {
processState.spawnedObjects = {
...processState.spawnedObjects,
...updatedObjects,
};
// Only send position updates when there are meaningful changes
if (hasChanges) {
self.postMessage({
type: "positionsUpdated",
data: {
processId: process.id,
objects: updatedObjects,
},
});
}
}
});
}

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
// useCallback, // useCallback,
// useRef, // useRef,
// } from "react"; // } from "react";
// import { useSimulationPaths } from "../../../store/store"; // import { useSimulationStates } from "../../../store/store";
// import * as THREE from "three"; // import * as THREE from "three";
// import { useThree } from "@react-three/fiber"; // import { useThree } from "@react-three/fiber";
// import { // import {
@ -29,7 +29,7 @@
// position: [number, number, number]; // position: [number, number, number];
// actions: PointAction[]; // actions: PointAction[];
// connections: { // connections: {
// targets: Array<{ pathUUID: string }>; // targets: Array<{ modelUUID: string }>;
// }; // };
// } // }
@ -72,7 +72,7 @@
// actions: point.actions.map(normalizeAction), // Preserve exact actions // actions: point.actions.map(normalizeAction), // Preserve exact actions
// connections: { // connections: {
// targets: point.connections.targets.map((target) => ({ // targets: point.connections.targets.map((target) => ({
// pathUUID: target.pathUUID, // modelUUID: target.modelUUID,
// })), // })),
// }, // },
// })), // })),
@ -94,7 +94,7 @@
// : [normalizeAction(path.point.actions)], // : [normalizeAction(path.point.actions)],
// connections: { // connections: {
// targets: path.point.connections.targets.map((target) => ({ // targets: path.point.connections.targets.map((target) => ({
// pathUUID: target.pathUUID, // modelUUID: target.modelUUID,
// })), // })),
// }, // },
// }, // },
@ -137,18 +137,18 @@
// // Check if current last connects to next last (requires reversal) // // Check if current last connects to next last (requires reversal)
// const connectsToLast = currentLastPoint.connections.targets.some( // const connectsToLast = currentLastPoint.connections.targets.some(
// (target) => // (target) =>
// target.pathUUID === nextPath.modeluuid && // target.modelUUID === nextPath.modeluuid &&
// nextLastPoint.connections.targets.some( // nextLastPoint.connections.targets.some(
// (t) => t.pathUUID === currentPath.modeluuid // (t) => t.modelUUID === currentPath.modeluuid
// ) // )
// ); // );
// // Check if current last connects to next first (no reversal needed) // // Check if current last connects to next first (no reversal needed)
// const connectsToFirst = currentLastPoint.connections.targets.some( // const connectsToFirst = currentLastPoint.connections.targets.some(
// (target) => // (target) =>
// target.pathUUID === nextPath.modeluuid && // target.modelUUID === nextPath.modeluuid &&
// nextFirstPoint.connections.targets.some( // nextFirstPoint.connections.targets.some(
// (t) => t.pathUUID === currentPath.modeluuid // (t) => t.modelUUID === currentPath.modeluuid
// ) // )
// ); // );
@ -249,10 +249,10 @@
// // Process outgoing connections // // Process outgoing connections
// for (const point of currentPath.points) { // for (const point of currentPath.points) {
// for (const target of point.connections.targets) { // for (const target of point.connections.targets) {
// if (!visited.has(target.pathUUID)) { // if (!visited.has(target.modelUUID)) {
// const targetPath = pathMap.get(target.pathUUID); // const targetPath = pathMap.get(target.modelUUID);
// if (targetPath) { // if (targetPath) {
// visited.add(target.pathUUID); // visited.add(target.modelUUID);
// queue.push(targetPath); // queue.push(targetPath);
// } // }
// } // }
@ -264,7 +264,7 @@
// if (!visited.has(uuid)) { // if (!visited.has(uuid)) {
// const hasConnectionToCurrent = path.points.some((point) => // const hasConnectionToCurrent = path.points.some((point) =>
// point.connections.targets.some( // point.connections.targets.some(
// (t) => t.pathUUID === currentPath.modeluuid // (t) => t.modelUUID === currentPath.modeluuid
// ) // )
// ); // );
// if (hasConnectionToCurrent) { // if (hasConnectionToCurrent) {
@ -312,19 +312,19 @@
// const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo( // const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
// ({ onProcessesCreated }) => { // ({ onProcessesCreated }) => {
// const { simulationPaths } = useSimulationPaths(); // const { simulationStates } = useSimulationStates();
// const { createProcessesFromPaths } = useProcessCreation(); // const { createProcessesFromPaths } = useProcessCreation();
// const prevPathsRef = useRef<SimulationPath[]>([]); // const prevPathsRef = useRef<SimulationPath[]>([]);
// const prevProcessesRef = useRef<Process[]>([]); // const prevProcessesRef = useRef<Process[]>([]);
// const convertedPaths = useMemo((): SimulationPath[] => { // const convertedPaths = useMemo((): SimulationPath[] => {
// if (!simulationPaths) return []; // if (!simulationStates) return [];
// return simulationPaths.map((path) => // return simulationStates.map((path) =>
// convertToSimulationPath( // convertToSimulationPath(
// path as ConveyorEventsSchema | VehicleEventsSchema // path as ConveyorEventsSchema | VehicleEventsSchema
// ) // )
// ); // );
// }, [simulationPaths]); // }, [simulationStates]);
// const pathsDependency = useMemo(() => { // const pathsDependency = useMemo(() => {
// if (!convertedPaths) return null; // if (!convertedPaths) return null;
@ -335,7 +335,7 @@
// ), // ),
// connections: path.points // connections: path.points
// .flatMap((p: PathPoint) => // .flatMap((p: PathPoint) =>
// p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID) // p.connections.targets.map((t: { modelUUID: string }) => t.modelUUID)
// ) // )
// .join(","), // .join(","),
// })); // }));
@ -404,7 +404,7 @@ import React, {
useCallback, useCallback,
useRef, useRef,
} from "react"; } from "react";
import { useSimulationPaths } from "../../../store/store"; import { useSimulationStates } from "../../../store/store";
import * as THREE from "three"; import * as THREE from "three";
import { useThree } from "@react-three/fiber"; import { useThree } from "@react-three/fiber";
import { import {
@ -428,11 +428,12 @@ export interface PathPoint {
position: [number, number, number]; position: [number, number, number];
actions: PointAction[]; actions: PointAction[];
connections: { connections: {
targets: Array<{ pathUUID: string }>; targets: Array<{ modelUUID: string }>;
}; };
} }
export interface SimulationPath { export interface SimulationPath {
type: string;
modeluuid: string; modeluuid: string;
points: PathPoint[]; points: PathPoint[];
pathPosition: [number, number, number]; pathPosition: [number, number, number];
@ -464,6 +465,7 @@ function convertToSimulationPath(
if (path.type === "Conveyor") { if (path.type === "Conveyor") {
return { return {
type: path.type,
modeluuid, modeluuid,
points: path.points.map((point) => ({ points: path.points.map((point) => ({
uuid: point.uuid, uuid: point.uuid,
@ -471,7 +473,7 @@ function convertToSimulationPath(
actions: point.actions.map(normalizeAction), // Preserve exact actions actions: point.actions.map(normalizeAction), // Preserve exact actions
connections: { connections: {
targets: point.connections.targets.map((target) => ({ targets: point.connections.targets.map((target) => ({
pathUUID: target.pathUUID, modelUUID: target.modelUUID,
})), })),
}, },
})), })),
@ -483,23 +485,24 @@ function convertToSimulationPath(
}; };
} else { } else {
return { return {
type: path.type,
modeluuid, modeluuid,
points: [ points: [
{ {
uuid: path.point.uuid, uuid: path.points.uuid,
position: path.point.position, position: path.points.position,
actions: Array.isArray(path.point.actions) actions: Array.isArray(path.points.actions)
? path.point.actions.map(normalizeAction) ? path.points.actions.map(normalizeAction)
: [normalizeAction(path.point.actions)], : [normalizeAction(path.points.actions)],
connections: { connections: {
targets: path.point.connections.targets.map((target) => ({ targets: path.points.connections.targets.map((target) => ({
pathUUID: target.pathUUID, modelUUID: target.modelUUID,
})), })),
}, },
}, },
], ],
pathPosition: path.position, pathPosition: path.position,
speed: path.point.speed || 1, speed: path.points.speed || 1,
}; };
} }
} }
@ -536,18 +539,18 @@ function shouldReverseNextPath(
// Check if current last connects to next last (requires reversal) // Check if current last connects to next last (requires reversal)
const connectsToLast = currentLastPoint.connections.targets.some( const connectsToLast = currentLastPoint.connections.targets.some(
(target) => (target) =>
target.pathUUID === nextPath.modeluuid && target.modelUUID === nextPath.modeluuid &&
nextLastPoint.connections.targets.some( nextLastPoint.connections.targets.some(
(t) => t.pathUUID === currentPath.modeluuid (t) => t.modelUUID === currentPath.modeluuid
) )
); );
// Check if current last connects to next first (no reversal needed) // Check if current last connects to next first (no reversal needed)
const connectsToFirst = currentLastPoint.connections.targets.some( const connectsToFirst = currentLastPoint.connections.targets.some(
(target) => (target) =>
target.pathUUID === nextPath.modeluuid && target.modelUUID === nextPath.modeluuid &&
nextFirstPoint.connections.targets.some( nextFirstPoint.connections.targets.some(
(t) => t.pathUUID === currentPath.modeluuid (t) => t.modelUUID === currentPath.modeluuid
) )
); );
@ -614,6 +617,7 @@ export function useProcessCreation() {
const [processes, setProcesses] = useState<Process[]>([]); const [processes, setProcesses] = useState<Process[]>([]);
const hasSpawnAction = useCallback((path: SimulationPath): boolean => { const hasSpawnAction = useCallback((path: SimulationPath): boolean => {
if (path.type !== "Conveyor") return false;
return path.points.some((point) => return path.points.some((point) =>
point.actions.some((action) => action.type.toLowerCase() === "spawn") point.actions.some((action) => action.type.toLowerCase() === "spawn")
); );
@ -674,10 +678,10 @@ export function useProcessCreation() {
// Process outgoing connections // Process outgoing connections
for (const point of currentPath.points) { for (const point of currentPath.points) {
for (const target of point.connections.targets) { for (const target of point.connections.targets) {
if (!visited.has(target.pathUUID)) { if (!visited.has(target.modelUUID)) {
const targetPath = pathMap.get(target.pathUUID); const targetPath = pathMap.get(target.modelUUID);
if (targetPath) { if (targetPath) {
visited.add(target.pathUUID); visited.add(target.modelUUID);
queue.push(targetPath); queue.push(targetPath);
} }
} }
@ -689,7 +693,7 @@ export function useProcessCreation() {
if (!visited.has(uuid)) { if (!visited.has(uuid)) {
const hasConnectionToCurrent = path.points.some((point) => const hasConnectionToCurrent = path.points.some((point) =>
point.connections.targets.some( point.connections.targets.some(
(t) => t.pathUUID === currentPath.modeluuid (t) => t.modelUUID === currentPath.modeluuid
) )
); );
if (hasConnectionToCurrent) { if (hasConnectionToCurrent) {
@ -737,19 +741,19 @@ export function useProcessCreation() {
const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo( const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
({ onProcessesCreated }) => { ({ onProcessesCreated }) => {
const { simulationPaths } = useSimulationPaths(); const { simulationStates } = useSimulationStates();
const { createProcessesFromPaths } = useProcessCreation(); const { createProcessesFromPaths } = useProcessCreation();
const prevPathsRef = useRef<SimulationPath[]>([]); const prevPathsRef = useRef<SimulationPath[]>([]);
const prevProcessesRef = useRef<Process[]>([]); const prevProcessesRef = useRef<Process[]>([]);
const convertedPaths = useMemo((): SimulationPath[] => { const convertedPaths = useMemo((): SimulationPath[] => {
if (!simulationPaths) return []; if (!simulationStates) return [];
return simulationPaths.map((path) => return simulationStates.map((path) =>
convertToSimulationPath( convertToSimulationPath(
path as ConveyorEventsSchema | VehicleEventsSchema path as ConveyorEventsSchema | VehicleEventsSchema
) )
); );
}, [simulationPaths]); }, [simulationStates]);
// Enhanced dependency tracking that includes action types // Enhanced dependency tracking that includes action types
const pathsDependency = useMemo(() => { const pathsDependency = useMemo(() => {
@ -764,7 +768,7 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
.join(","), .join(","),
connections: path.points connections: path.points
.flatMap((p: PathPoint) => .flatMap((p: PathPoint) =>
p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID) p.connections.targets.map((t: { modelUUID: string }) => t.modelUUID)
) )
.join(","), .join(","),
})); }));

View File

@ -0,0 +1,114 @@
import React, { useRef, useEffect } from "react";
import { useFrame } from "@react-three/fiber";
import * as THREE from "three";
import { GLTF } from "three-stdlib";
import { Box3Helper } from "three";
import { SpawnedObject, ProcessData } from "./types";
interface ProcessObjectRendererProps {
objectId: string;
object: SpawnedObject;
process: ProcessData;
gltf: GLTF;
showBoundingBox?: boolean;
}
export const ProcessObjectRenderer: React.FC<ProcessObjectRendererProps> = ({
objectId,
object,
process,
gltf,
showBoundingBox = false,
}) => {
const meshRef = useRef<THREE.Mesh>(null);
const boxHelperRef = useRef<THREE.Box3Helper | null>(null);
const boundingBoxRef = useRef<THREE.Box3>(new THREE.Box3());
// Issue 1: Can't assign to ref.current as it's read-only
useEffect(() => {
if (object.ref && meshRef.current) {
// Instead of direct assignment, we need to store the mesh reference another way
// Option 1: If you can modify the SpawnedObject interface, add a setMesh method
if (typeof (object as any).setMesh === 'function') {
(object as any).setMesh(meshRef.current);
}
// Option 2: Store the mesh in a property that isn't ref.current
// This requires modifying your SpawnedObject interface to include this property
(object as any).meshInstance = meshRef.current;
// Option 3: If you need to maintain compatibility, you could use Object.defineProperty
// But this is a hack and not recommended
// Object.defineProperty(object.ref, 'current', { value: meshRef.current, writable: true });
}
}, [object.ref]);
// Create a bounding box helper for visualization
useFrame(() => {
if (meshRef.current && showBoundingBox) {
// Update the bounding box to match the mesh position
if (!boxHelperRef.current) {
// Get the size of the mesh
const size = new THREE.Vector3(1, 1, 1);
// If the mesh has geometry, use its dimensions
if (meshRef.current.geometry) {
const box = new THREE.Box3().setFromObject(meshRef.current);
box.getSize(size);
}
// Create a new bounding box centered on the mesh
boundingBoxRef.current = new THREE.Box3().setFromCenterAndSize(
meshRef.current.position,
size
);
// Create a helper to visualize the box
boxHelperRef.current = new Box3Helper(
boundingBoxRef.current,
new THREE.Color(0xff0000)
);
// Add the helper to the scene
meshRef.current.parent?.add(boxHelperRef.current);
} else {
// Update the box position to match the mesh
boundingBoxRef.current.setFromCenterAndSize(
meshRef.current.position,
boundingBoxRef.current.getSize(new THREE.Vector3())
);
// Force the helper to update
boxHelperRef.current.updateMatrixWorld(true);
}
}
});
if (gltf?.scene) {
return (
<primitive
ref={meshRef}
object={gltf.scene.clone()}
position={[0, 0, 0]}
material={object.material}
/>
);
}
// Issue 2: Material color type problem
return (
<mesh ref={meshRef}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial
// Fix the color property access
color={
object.material && 'color' in object.material
? (object.material as THREE.MeshStandardMaterial).color
: "#00ff00"
}
metalness={0.5}
roughness={0.3}
/>
</mesh>
);
};

View File

@ -0,0 +1,79 @@
import * as THREE from "three";
import React from "react";
export interface ProcessPoint {
uuid: string;
position: number[];
actions?: PointAction[];
}
export interface PointAction {
type: string;
isUsed: boolean;
spawnInterval?: number | string;
material?: string;
delay?: number | string;
}
export interface ProcessData {
id: string;
name: string;
paths?: {
points?: ProcessPoint[];
}[];
animationPath?: { x: number; y: number; z: number }[];
speed?: number;
customMaterials?: Record<string, THREE.Material>;
}
export interface ProcessAnimationState {
spawnedObjects: Record<string, SpawnedObject | SpawnedObjectWithCollision>;
nextSpawnTime: number;
objectIdCounter: number;
isProcessDelaying: boolean;
processDelayStartTime: number;
processDelayDuration: number;
isCollisionPaused?: boolean;
}
export interface SpawnedObject {
ref: React.RefObject<THREE.Object3D>;
state: {
currentIndex: number;
progress: number;
isAnimating: boolean;
speed: number;
isDelaying: boolean;
delayStartTime: number;
currentDelayDuration: number;
delayComplete: boolean;
currentPathIndex: number;
};
visible: boolean;
material: THREE.Material;
currentMaterialType: string;
spawnTime: number;
position: THREE.Vector3;
collision?: {
boundingBox: THREE.Box3;
isColliding: boolean;
colliding: boolean; // Added this property
};
}
// For use in your processAnimator.tsx
// Update the CollisionState interface to include all required properties
interface CollisionState {
boundingBox: THREE.Box3;
isColliding: boolean;
colliding: boolean; // This was missing
collidingWith: string[];
}
export interface SpawnedObjectWithCollision extends SpawnedObject {
collision: {
boundingBox: THREE.Box3;
isColliding: boolean;
colliding: boolean;
collidingWith: string[];
};
}

View File

@ -2,7 +2,7 @@ import { useState, useEffect, useRef, useMemo } from "react";
import { import {
useSelectedActionSphere, useSelectedActionSphere,
useSelectedPath, useSelectedPath,
useSimulationPaths, useSimulationStates,
} from "../../store/store"; } from "../../store/store";
import * as THREE from "three"; import * as THREE from "three";
import Behaviour from "./behaviour/behaviour"; import Behaviour from "./behaviour/behaviour";
@ -15,12 +15,12 @@ import Agv from "../builder/agv/agv";
function Simulation() { function Simulation() {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const pathsGroupRef = useRef() as React.MutableRefObject<THREE.Group>; const pathsGroupRef = useRef() as React.MutableRefObject<THREE.Group>;
const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { simulationStates, setSimulationStates } = useSimulationStates();
const [processes, setProcesses] = useState([]); const [processes, setProcesses] = useState([]);
useEffect(() => { useEffect(() => {
console.log('simulationPaths: ', simulationPaths); // console.log('simulationStates: ', simulationStates);
}, [simulationPaths]); }, [simulationStates]);
// useEffect(() => { // useEffect(() => {
// if (selectedActionSphere) { // if (selectedActionSphere) {
@ -42,7 +42,7 @@ function Simulation() {
<PathCreation pathsGroupRef={pathsGroupRef} /> <PathCreation pathsGroupRef={pathsGroupRef} />
<PathConnector pathsGroupRef={pathsGroupRef} /> <PathConnector pathsGroupRef={pathsGroupRef} />
<ProcessContainer /> <ProcessContainer />
{/* <Agv /> */} <Agv />
</> </>
)} )}
</> </>

View File

@ -1,5 +1,5 @@
// import { useMemo, useState } from 'react'; // import { useMemo, useState } from 'react';
// import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store'; // import { useSelectedActionSphere, useToggleView, useSimulationStates, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store';
// import * as THREE from 'three'; // import * as THREE from 'three';
// import useModuleStore from '../../store/useModuleStore'; // import useModuleStore from '../../store/useModuleStore';
@ -9,17 +9,17 @@
// const { startSimulation, setStartSimulation } = useStartSimulation(); // const { startSimulation, setStartSimulation } = useStartSimulation();
// const { selectedActionSphere } = useSelectedActionSphere(); // const { selectedActionSphere } = useSelectedActionSphere();
// const { selectedPath, setSelectedPath } = useSelectedPath(); // const { selectedPath, setSelectedPath } = useSelectedPath();
// const { simulationPaths, setSimulationPaths } = useSimulationPaths(); // const { simulationStates, setSimulationStates } = useSimulationStates();
// const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath(); // const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath();
// const [activeButton, setActiveButton] = useState<string | null>(null); // const [activeButton, setActiveButton] = useState<string | null>(null);
// const handleAddAction = () => { // const handleAddAction = () => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => { // points: path.points.map((point) => {
// if (point.uuid === selectedActionSphere.point.uuid) { // if (point.uuid === selectedActionSphere.points.uuid) {
// const actionIndex = point.actions.length; // const actionIndex = point.actions.length;
// const newAction = { // const newAction = {
// uuid: THREE.MathUtils.generateUUID(), // uuid: THREE.MathUtils.generateUUID(),
@ -37,31 +37,31 @@
// }), // }),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleDeleteAction = (uuid: string) => { // const handleDeleteAction = (uuid: string) => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => // points: path.points.map((point) =>
// point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.points.uuid
// ? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) } // ? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
// : point // : point
// ), // ),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleActionSelect = (uuid: string, actionType: string) => { // const handleActionSelect = (uuid: string, actionType: string) => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => // points: path.points.map((point) =>
// point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.points.uuid
// ? { // ? {
// ...point, // ...point,
// actions: point.actions.map((action) => // actions: point.actions.map((action) =>
@ -72,16 +72,16 @@
// ), // ),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleMaterialSelect = (uuid: string, material: string) => { // const handleMaterialSelect = (uuid: string, material: string) => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => // points: path.points.map((point) =>
// point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.points.uuid
// ? { // ? {
// ...point, // ...point,
// actions: point.actions.map((action) => // actions: point.actions.map((action) =>
@ -92,16 +92,16 @@
// ), // ),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleDelayChange = (uuid: string, delay: number | string) => { // const handleDelayChange = (uuid: string, delay: number | string) => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => // points: path.points.map((point) =>
// point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.points.uuid
// ? { // ? {
// ...point, // ...point,
// actions: point.actions.map((action) => // actions: point.actions.map((action) =>
@ -112,16 +112,16 @@
// ), // ),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => { // const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => // points: path.points.map((point) =>
// point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.points.uuid
// ? { // ? {
// ...point, // ...point,
// actions: point.actions.map((action) => // actions: point.actions.map((action) =>
@ -132,27 +132,27 @@
// ), // ),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleSpeedChange = (speed: number) => { // const handleSpeedChange = (speed: number) => {
// if (!selectedPath) return; // if (!selectedPath) return;
// const updatedPaths = simulationPaths.map((path) => // const updatedPaths = simulationStates.map((path) =>
// path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path // path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
// ); // );
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } }); // setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
// }; // };
// const handleAddTrigger = () => { // const handleAddTrigger = () => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => { // points: path.points.map((point) => {
// if (point.uuid === selectedActionSphere.point.uuid) { // if (point.uuid === selectedActionSphere.points.uuid) {
// const triggerIndex = point.triggers.length; // const triggerIndex = point.triggers.length;
// const newTrigger = { // const newTrigger = {
// uuid: THREE.MathUtils.generateUUID(), // uuid: THREE.MathUtils.generateUUID(),
@ -167,31 +167,31 @@
// }), // }),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleDeleteTrigger = (uuid: string) => { // const handleDeleteTrigger = (uuid: string) => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => // points: path.points.map((point) =>
// point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.points.uuid
// ? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) } // ? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
// : point // : point
// ), // ),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleTriggerSelect = (uuid: string, triggerType: string) => { // const handleTriggerSelect = (uuid: string, triggerType: string) => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => // points: path.points.map((point) =>
// point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.points.uuid
// ? { // ? {
// ...point, // ...point,
// triggers: point.triggers.map((trigger) => // triggers: point.triggers.map((trigger) =>
@ -202,7 +202,7 @@
// ), // ),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleResetPath = () => { // const handleResetPath = () => {
@ -214,10 +214,10 @@
// const handleActionToggle = (uuid: string) => { // const handleActionToggle = (uuid: string) => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => // points: path.points.map((point) =>
// point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.points.uuid
// ? { // ? {
// ...point, // ...point,
// actions: point.actions.map((action) => ({ // actions: point.actions.map((action) => ({
@ -229,16 +229,16 @@
// ), // ),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const handleTriggerToggle = (uuid: string) => { // const handleTriggerToggle = (uuid: string) => {
// if (!selectedActionSphere) return; // if (!selectedActionSphere) return;
// const updatedPaths = simulationPaths.map((path) => ({ // const updatedPaths = simulationStates.map((path) => ({
// ...path, // ...path,
// points: path.points.map((point) => // points: path.points.map((point) =>
// point.uuid === selectedActionSphere.point.uuid // point.uuid === selectedActionSphere.points.uuid
// ? { // ? {
// ...point, // ...point,
// triggers: point.triggers.map((trigger) => ({ // triggers: point.triggers.map((trigger) => ({
@ -250,13 +250,13 @@
// ), // ),
// })); // }));
// setSimulationPaths(updatedPaths); // setSimulationStates(updatedPaths);
// }; // };
// const selectedPoint = useMemo(() => { // const selectedPoint = useMemo(() => {
// if (!selectedActionSphere) return null; // if (!selectedActionSphere) return null;
// return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid); // return simulationStates.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.points.uuid);
// }, [selectedActionSphere, simulationPaths]); // }, [selectedActionSphere, simulationStates]);
// const createPath = () => { // const createPath = () => {
// setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null); // setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);

View File

@ -11,13 +11,13 @@ type PathPoint = {
}; };
type PathCreatorProps = { type PathCreatorProps = {
simulationPaths: PathPoint[][]; simulationStates: PathPoint[][];
setSimulationPaths: React.Dispatch<React.SetStateAction<PathPoint[][]>>; setSimulationStates: React.Dispatch<React.SetStateAction<PathPoint[][]>>;
connections: { start: PathPoint; end: PathPoint }[]; connections: { start: PathPoint; end: PathPoint }[];
setConnections: React.Dispatch<React.SetStateAction<{ start: PathPoint; end: PathPoint }[]>> setConnections: React.Dispatch<React.SetStateAction<{ start: PathPoint; end: PathPoint }[]>>
}; };
const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConnections }: PathCreatorProps) => { const PathCreator = ({ simulationStates, setSimulationStates, connections, setConnections }: PathCreatorProps) => {
const { camera, scene, raycaster, pointer, gl } = useThree(); const { camera, scene, raycaster, pointer, gl } = useThree();
const { drawMaterialPath } = useDrawMaterialPath(); const { drawMaterialPath } = useDrawMaterialPath();
@ -71,7 +71,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
e.preventDefault(); e.preventDefault();
if (drag || e.button === 0) return; if (drag || e.button === 0) return;
if (currentPath.length > 1) { if (currentPath.length > 1) {
setSimulationPaths((prevPaths) => [...prevPaths, currentPath]); setSimulationStates((prevPaths) => [...prevPaths, currentPath]);
} }
setCurrentPath([]); setCurrentPath([]);
setTemporaryPoint(null); setTemporaryPoint(null);
@ -125,7 +125,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
canvasElement.addEventListener("contextmenu", onContextMenu); canvasElement.addEventListener("contextmenu", onContextMenu);
} else { } else {
if (currentPath.length > 1) { if (currentPath.length > 1) {
setSimulationPaths((prevPaths) => [...prevPaths, currentPath]); setSimulationStates((prevPaths) => [...prevPaths, currentPath]);
} }
setCurrentPath([]); setCurrentPath([]);
setTemporaryPoint(null); setTemporaryPoint(null);
@ -179,25 +179,25 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
if (selectedPoint) { if (selectedPoint) {
const updatedPosition = e.target.object.position.clone(); const updatedPosition = e.target.object.position.clone();
const updatedRotation = e.target.object.quaternion.clone(); const updatedRotation = e.target.object.quaternion.clone();
const updatedPaths = simulationPaths.map((path) => const updatedPaths = simulationStates.map((path) =>
path.map((p) => path.map((p) =>
p.uuid === selectedPoint.uuid ? { ...p, position: updatedPosition, rotation: updatedRotation } : p p.uuid === selectedPoint.uuid ? { ...p, position: updatedPosition, rotation: updatedRotation } : p
) )
); );
setSimulationPaths(updatedPaths); setSimulationStates(updatedPaths);
} }
}; };
const meshContext = (uuid: string) => { const meshContext = (uuid: string) => {
const pathIndex = simulationPaths.findIndex(path => path.some(point => point.uuid === uuid)); const pathIndex = simulationStates.findIndex(path => path.some(point => point.uuid === uuid));
if (pathIndex === -1) return; if (pathIndex === -1) return;
const clickedPoint = simulationPaths[pathIndex].find(point => point.uuid === uuid); const clickedPoint = simulationStates[pathIndex].find(point => point.uuid === uuid);
if (!clickedPoint) return; if (!clickedPoint) return;
const isStart = simulationPaths[pathIndex][0].uuid === uuid; const isStart = simulationStates[pathIndex][0].uuid === uuid;
const isEnd = simulationPaths[pathIndex][simulationPaths[pathIndex].length - 1].uuid === uuid; const isEnd = simulationStates[pathIndex][simulationStates[pathIndex].length - 1].uuid === uuid;
if (pathIndex === 0 && isStart) { if (pathIndex === 0 && isStart) {
console.log("The first-ever point is not connectable."); console.log("The first-ever point is not connectable.");
@ -285,8 +285,8 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
return ( return (
<> <>
<group name='pathObjects'> <group name='pathObjects'>
{/* Render finalized simulationPaths */} {/* Render finalized simulationStates */}
{simulationPaths.map((path, pathIndex) => ( {simulationStates.map((path, pathIndex) => (
<group key={`path-line-${pathIndex}`}> <group key={`path-line-${pathIndex}`}>
<Line <Line
name={`path-line-${pathIndex}`} name={`path-line-${pathIndex}`}
@ -299,7 +299,7 @@ const PathCreator = ({ simulationPaths, setSimulationPaths, connections, setConn
))} ))}
{/* Render finalized points */} {/* Render finalized points */}
{simulationPaths.map((path) => {simulationStates.map((path) =>
path.map((point) => ( path.map((point) => (
<mesh <mesh
key={`path-point-${point.uuid}`} key={`path-point-${point.uuid}`}

View File

@ -10,13 +10,13 @@ type PathPoint = {
}; };
function Simulation() { function Simulation() {
const [simulationPaths, setSimulationPaths] = useState<{ position: THREE.Vector3; rotation: THREE.Quaternion; uuid: string }[][]>([]); const [simulationStates, setSimulationStates] = useState<{ position: THREE.Vector3; rotation: THREE.Quaternion; uuid: string }[][]>([]);
const [connections, setConnections] = useState<{ start: PathPoint; end: PathPoint }[]>([]); const [connections, setConnections] = useState<{ start: PathPoint; end: PathPoint }[]>([]);
return ( return (
<> <>
<PathCreator simulationPaths={simulationPaths} setSimulationPaths={setSimulationPaths} connections={connections} setConnections={setConnections} /> <PathCreator simulationStates={simulationStates} setSimulationStates={setSimulationStates} connections={connections} setConnections={setConnections} />
{simulationPaths.map((path, index) => ( {simulationStates.map((path, index) => (
<PathFlow key={index} path={path} connections={connections} /> <PathFlow key={index} path={path} connections={connections} />
))} ))}
</> </>

View File

@ -5,6 +5,14 @@ import { useDroppedObjectsStore } from "../../store/useDroppedObjectsStore";
import { useZoneWidgetStore } from "../../store/useZone3DWidgetStore"; import { useZoneWidgetStore } from "../../store/useZone3DWidgetStore";
import useTemplateStore from "../../store/useTemplateStore"; import useTemplateStore from "../../store/useTemplateStore";
type WidgetData = {
id: string;
type: string;
position: [number, number, number];
rotation?: [number, number, number];
tempPosition?: [number, number, number];
};
export default function SocketRealTimeViz() { export default function SocketRealTimeViz() {
const { visualizationSocket } = useSocketStore(); const { visualizationSocket } = useSocketStore();
const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore();
@ -14,6 +22,7 @@ export default function SocketRealTimeViz() {
const { addWidget } = useZoneWidgetStore() const { addWidget } = useZoneWidgetStore()
const { templates, removeTemplate } = useTemplateStore(); const { templates, removeTemplate } = useTemplateStore();
const { setTemplates } = useTemplateStore(); const { setTemplates } = useTemplateStore();
const { zoneWidgetData, setZoneWidgetData, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore();
useEffect(() => { useEffect(() => {
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
@ -132,14 +141,36 @@ export default function SocketRealTimeViz() {
}); });
//add 3D Widget response //add 3D Widget response
visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => { visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => {
console.log('add3DWidget: ', add3DWidget);
console.log('add3DWidget: ', add3DWidget);
if (add3DWidget.success) { if (add3DWidget.success) {
console.log('add3DWidget: ', add3DWidget);
if (add3DWidget.message === "Widget created successfully") { if (add3DWidget.message === "Widget created successfully") {
addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget); addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget);
} }
} }
}); });
//delete 3D Widget response
visualizationSocket.on("viz-widget3D:response:delete", (delete3DWidget: any) => {
console.log('delete3DWidget: ', delete3DWidget);
// "3DWidget delete unsuccessfull"
if (delete3DWidget.success && delete3DWidget.message === "3DWidget delete successfull") {
const activeZoneWidgets = zoneWidgetData[delete3DWidget.data.zoneId] || [];
setZoneWidgetData(
delete3DWidget.data.zoneId,
activeZoneWidgets.filter((w: WidgetData) => w.id !== delete3DWidget.data.id)
);
}
});
//update3D widget response
visualizationSocket.on("viz-widget3D:response:modifyPositionRotation", (update3DWidget: any) => {
console.log('update3DWidget: ', update3DWidget);
if (update3DWidget.success && update3DWidget.message==="widget update successfully") {
updateWidgetPosition(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.position);
updateWidgetRotation(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.rotation);
}
});
// add Template response // add Template response
visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => { visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => {
console.log('addingTemplate: ', addingTemplate); console.log('addingTemplate: ', addingTemplate);

View File

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

View File

@ -1,8 +1,8 @@
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_ASSET_LIBRARY_URL}`; let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
export const getCategoryAsset = async (categoryName: any) => { export const getCategoryAsset = async (categoryName: any) => {
try { try {
const response = await fetch( const response = await fetch(
`${BackEnd_url}/api/v2/getCatagoryAssets/${categoryName}`, `${BackEnd_url}/api/v2/getCategoryAssets/${categoryName}`,
{ {
method: "GET", method: "GET",
headers: { headers: {

View File

@ -17,7 +17,7 @@ export const setEventApi = async (
}); });
if (!response.ok) { if (!response.ok) {
throw new Error("Failed to set or update Floor Item"); throw new Error("Failed to set or Update Event Data");
} }
const result = await response.json(); const result = await response.json();

View File

@ -26,7 +26,7 @@ export const findEnvironment = async (organization: string, userId: string) => {
false, false,
false, false,
false, false,
0, 40,
true true
); );
return userpos; return userpos;

View File

@ -5,9 +5,6 @@ export const adding3dWidgets = async (
organization: string, organization: string,
widget: {} widget: {}
) => { ) => {
console.log('widget: ', widget);
console.log('organization: ', organization);
console.log('zoneId: ', zoneId);
try { try {
const response = await fetch( const response = await fetch(
`${url_Backend_dwinzo}/api/v2/3dwidget/save`, `${url_Backend_dwinzo}/api/v2/3dwidget/save`,

View File

@ -0,0 +1,38 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
export const delete3dWidgetApi = async (
zoneId: string,
organization: string,
id: string
) => {
console.log("zoneId: ", zoneId);
console.log("organization: ", organization);
console.log("id: ", id);
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v2/widget3D/delete`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ organization, zoneId, id }),
}
);
if (!response.ok) {
throw new Error("Failed to delete floating widget in the zone");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -0,0 +1,81 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
export const update3dWidget = async (
zoneId: string,
organization: string,
id: string,
position?: [number, number, number]
) => {
console.log("organization: ", organization);
console.log("zoneId: ", zoneId);
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
organization,
zoneId,
id,
position,
}),
}
);
if (!response.ok) {
throw new Error("Failed to add 3dwidget in the zone");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};
export const update3dWidgetRotation = async (
zoneId: string,
organization: string,
id: string,
rotation?: [number, number, number]
) => {
console.log("organization: ", organization);
console.log("zoneId: ", zoneId);
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
organization,
zoneId,
id,
rotation,
}),
}
);
if (!response.ok) {
throw new Error("Failed to add 3dwidget in the zone");
}
const result = await response.json();
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
} else {
throw new Error("An unknown error occurred");
}
}
};

View File

@ -14,7 +14,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
const socket = io( const socket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`,
{ {
reconnection: false, reconnection: true,
auth: { email, organization }, auth: { email, organization },
} }
); );
@ -22,7 +22,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
const visualizationSocket = io( const visualizationSocket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`,
{ {
reconnection: false, reconnection: true,
auth: { email, organization }, auth: { email, organization },
} }
); );
@ -302,7 +302,13 @@ export const useDrieTemp = create<any>((set: any) => ({
export const useActiveUsers = create<any>((set: any) => ({ export const useActiveUsers = create<any>((set: any) => ({
activeUsers: [], activeUsers: [],
setActiveUsers: (x: any) => set({ activeUsers: x }), setActiveUsers: (callback: (prev: any[]) => any[] | any[]) =>
set((state: { activeUsers: any[] }) => ({
activeUsers:
typeof callback === "function"
? callback(state.activeUsers)
: callback,
})),
})); }));
export const useDrieUIValue = create<any>((set: any) => ({ export const useDrieUIValue = create<any>((set: any) => ({
@ -341,24 +347,29 @@ export const useSelectedPath = create<any>((set: any) => ({
})); }));
interface SimulationPathsStore { interface SimulationPathsStore {
simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]; simulationStates: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[];
setSimulationPaths: ( setSimulationStates: (
paths: paths:
| (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] | (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]
| ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] | ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]
) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) ) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[])
) => void; ) => void;
} }
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({ export const useSimulationStates = create<SimulationPathsStore>((set) => ({
simulationPaths: [], simulationStates: [],
setSimulationPaths: (paths) => setSimulationStates: (paths) =>
set((state) => ({ set((state) => ({
simulationPaths: simulationStates:
typeof paths === "function" ? paths(state.simulationPaths) : paths, typeof paths === "function" ? paths(state.simulationStates) : paths,
})), })),
})) }))
export const useNavMesh = create<any>((set: any) => ({
navMesh: null,
setNavMesh: (x: any) => set({ navMesh: x }),
}));
export const useIsConnecting = create<any>((set: any) => ({ export const useIsConnecting = create<any>((set: any) => ({
isConnecting: false, isConnecting: false,
setIsConnecting: (x: any) => set({ isConnecting: x }), setIsConnecting: (x: any) => set({ isConnecting: x }),

View File

@ -4,8 +4,32 @@ type PlayButtonStore = {
isPlaying: boolean; // Updated state name to reflect the play/pause status more clearly isPlaying: boolean; // Updated state name to reflect the play/pause status more clearly
setIsPlaying: (value: boolean) => void; // Updated setter function name for clarity setIsPlaying: (value: boolean) => void; // Updated setter function name for clarity
}; };
type PauseButtonStore = {
isPaused: boolean; // Updated state name to reflect the play/pause status more clearly
setIsPaused: (value: boolean) => void; // Updated setter function name for clarity
};
type ResetButtonStore = {
isReset: boolean; // Updated state name to reflect the play/pause status more clearly
setReset: (value: boolean) => void; // Updated setter function name for clarity
};
interface AnimationSpeedState {
speed: number;
setSpeed: (value: number) => void;
}
export const usePlayButtonStore = create<PlayButtonStore>((set) => ({ export const usePlayButtonStore = create<PlayButtonStore>((set) => ({
isPlaying: false, // Default state for play/pause isPlaying: false, // Default state for play/pause
setIsPlaying: (value) => set({ isPlaying: value }), // Update isPlaying state setIsPlaying: (value) => set({ isPlaying: value }), // Update isPlaying state
})); }));
export const useResetButtonStore = create<ResetButtonStore>((set) => ({
isReset: false, // Default state for play/pause
setReset: (value) => set({ isReset: value }), // Update isPlaying state
}));
export const usePauseButtonStore = create<PauseButtonStore>((set) => ({
isPaused: false, // Default state for play/pause
setIsPaused: (value) => set({ isPaused: value }), // Update isPlaying state
}));
export const useAnimationPlaySpeed = create<AnimationSpeedState>((set) => ({
speed: 1,
setSpeed: (value) => set({ speed: value }),
}));

View File

@ -1,10 +1,10 @@
import { create } from "zustand"; import { create } from "zustand";
type WidgetData = { type WidgetData = {
id: string; id: string;
type: string; type: string;
position: [number, number, number]; position: [number, number, number];
rotation?: [number, number, number];
tempPosition?: [number, number, number]; tempPosition?: [number, number, number];
}; };
@ -13,38 +13,59 @@ type ZoneWidgetStore = {
setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) => void; setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) => void;
addWidget: (zoneId: string, widget: WidgetData) => void; addWidget: (zoneId: string, widget: WidgetData) => void;
updateWidgetPosition: (zoneId: string, widgetId: string, newPosition: [number, number, number]) => void; updateWidgetPosition: (zoneId: string, widgetId: string, newPosition: [number, number, number]) => void;
updateWidgetRotation: (zoneId: string, widgetId: string, newRotation: [number, number, number]) => void;
}; };
export const useZoneWidgetStore = create<ZoneWidgetStore>((set) => ({ export const useZoneWidgetStore = create<ZoneWidgetStore>((set) => ({
zoneWidgetData: {}, zoneWidgetData: {},
setZoneWidgetData: (zoneId, widgets) => setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) =>
set((state) => ({ set((state: ZoneWidgetStore) => ({
zoneWidgetData: { ...state.zoneWidgetData, [zoneId]: widgets }, zoneWidgetData: { ...state.zoneWidgetData, [zoneId]: widgets },
})), })),
addWidget: (zoneId, widget) => addWidget: (zoneId: string, widget: WidgetData) =>
set((state) => ({ set((state: ZoneWidgetStore) => ({
zoneWidgetData: { zoneWidgetData: {
...state.zoneWidgetData, ...state.zoneWidgetData,
[zoneId]: [...(state.zoneWidgetData[zoneId] || []), widget], [zoneId]: [...(state.zoneWidgetData[zoneId] || []), { ...widget, rotation: widget.rotation || [0, 0, 0] }],
}, },
})), })),
updateWidgetPosition: (zoneId, widgetId, newPosition) => updateWidgetPosition: (zoneId: string, widgetId: string, newPosition: [number, number, number]) =>
set((state) => { set((state: ZoneWidgetStore) => {
const widgets = state.zoneWidgetData[zoneId] || []; const widgets = state.zoneWidgetData[zoneId] || [];
return { return {
zoneWidgetData: { zoneWidgetData: {
...state.zoneWidgetData, ...state.zoneWidgetData,
[zoneId]: widgets.map((widget) => [zoneId]: widgets.map((widget: WidgetData) =>
widget.id === widgetId ? { ...widget, position: newPosition } : widget widget.id === widgetId ? { ...widget, position: newPosition } : widget
), ),
}, },
}; };
}), }),
updateWidgetRotation: (zoneId: string, widgetId: string, newRotation: [number, number, number]) =>
set((state: ZoneWidgetStore) => {
const widgets = state.zoneWidgetData[zoneId] || [];
return {
zoneWidgetData: {
...state.zoneWidgetData,
[zoneId]: widgets.map((widget: WidgetData) =>
widget.id === widgetId ? { ...widget, rotation: newRotation } : widget
),
},
};
}),
})); }));
// export type WidgetData = {
// id: string;
// type: string;
// position: [number, number, number];
// rotation?: [number, number, number];
// tempPosition?: [number, number, number];
// };
interface RightClickStore { interface RightClickStore {
rightClickSelected: string | null; rightClickSelected: string | null;
@ -75,3 +96,13 @@ export const useRightSelected = create<RightSelectStore>((set) => ({
rightSelect: null, // Default state is null rightSelect: null, // Default state is null
setRightSelect: (x) => set({ rightSelect: x }), setRightSelect: (x) => set({ rightSelect: x }),
})); }));
interface EditWidgetOptionsStore {
editWidgetOptions: boolean;
setEditWidgetOptions: (value: boolean) => void;
}
export const useEditWidgetOptionsStore = create<EditWidgetOptionsStore>((set) => ({
editWidgetOptions: false, // Initial state
setEditWidgetOptions: (value: boolean) => set({ editWidgetOptions: value }),
}));

View File

@ -4,7 +4,7 @@
.tools-container { .tools-container {
@include flex-center; @include flex-center;
position: fixed; position: fixed;
bottom: 50px; bottom: 32px;
left: 50%; left: 50%;
transform: translate(-50%, 0); transform: translate(-50%, 0);
padding: 8px; padding: 8px;

View File

@ -472,6 +472,15 @@
font-size: var(--font-weight-regular); font-size: var(--font-weight-regular);
color: #4a4a4a; color: #4a4a4a;
.reviewChart {
width: 100%;
.floating {
width: 100%;
}
}
.selectedWidget { .selectedWidget {
padding: 6px 12px; padding: 6px 12px;
border-top: 1px solid var(--border-color); border-top: 1px solid var(--border-color);

View File

@ -7,7 +7,7 @@
border-radius: 20px; border-radius: 20px;
box-shadow: $box-shadow-medium; box-shadow: $box-shadow-medium;
width: calc(100% - (320px + 270px + 90px)); width: calc(100% - (320px + 270px + 90px));
height: calc(100% - (200px + 80px)); height: calc(100% - (250px));
position: absolute; position: absolute;
top: 50%; top: 50%;
left: calc(270px + 45px); left: calc(270px + 45px);
@ -16,6 +16,13 @@
transition: all 0.2s; transition: all 0.2s;
z-index: #{$z-index-default}; z-index: #{$z-index-default};
.realTime-viz-wrapper {
width: 100%;
height: 100%;
position: relative;
z-index: -1;
}
.floating { .floating {
width: 100%; width: 100%;
max-width: 250px; max-width: 250px;
@ -109,7 +116,7 @@
} }
.zone-wrapper.bottom { .zone-wrapper.bottom {
bottom: 210px; bottom: calc(var(--realTimeViz-container-height) * 0.27);
} }
.content-container { .content-container {
@ -182,6 +189,7 @@
.panel-content { .panel-content {
position: relative; position: relative;
height: 100%; height: 100%;
width: 100%;
padding: 10px; padding: 10px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -194,7 +202,6 @@
.chart-container { .chart-container {
width: 100%; width: 100%;
height: 25% !important;
min-height: 150px; min-height: 150px;
max-height: 100%; max-height: 100%;
// border: 1px dashed var(--background-color-gray); // border: 1px dashed var(--background-color-gray);
@ -203,6 +210,7 @@
padding: 6px 0; padding: 6px 0;
background-color: var(--background-color); background-color: var(--background-color);
position: relative; position: relative;
padding: 0 10px;
.kebab { .kebab {
width: 30px; width: 30px;
@ -287,15 +295,17 @@
&.bottom-panel { &.bottom-panel {
left: 0; left: 0;
right: 0; right: 0;
min-height: 150px;
.panel-content { .panel-content {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
height: 100%; height: 100%;
width: 100%;
min-height: 150px;
.chart-container { .chart-container {
height: 100% !important;
width: 20%;
min-width: 150px; min-width: 150px;
} }
} }
@ -314,17 +324,42 @@
top: 0; top: 0;
bottom: 0; bottom: 0;
.chart-container {
width: 100%;
height: 180px;
}
} }
&.right-panel { &.right-panel {
right: 0; right: 0;
top: 0; top: 0;
bottom: 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: 150px;
max-height: 100%;
// border: 1px dashed var(--background-color-gray);
border-radius: 8px;
box-shadow: var(--box-shadow-medium);
padding: 6px 0;
background-color: var(--background-color);
position: relative;
}
}
} }
} }
@ -335,7 +370,7 @@
.playingFlase { .playingFlase {
.zone-wrapper.bottom { .zone-wrapper.bottom {
bottom: 300px; bottom: calc(var(--realTimeViz-container-height) * 0.25);
} }
} }
@ -732,9 +767,9 @@
.editWidgetOptions { .editWidgetOptions {
position: absolute; position: absolute;
top: 50%; // top: 50%;
left: 50%; // left: 50%;
transform: translate(-50%, -50%); // transform: translate(-50%, -50%);
background-color: var(--background-color); background-color: var(--background-color);
z-index: 3; z-index: 3;
display: flex; display: flex;
@ -742,6 +777,8 @@
border-radius: 6px; border-radius: 6px;
overflow: hidden; overflow: hidden;
min-width: 150px;
.option { .option {
padding: 8px 10px; padding: 8px 10px;
color: var(--text-color); color: var(--text-color);

View File

@ -201,27 +201,6 @@ export type FloorItemType = {
modelfileID: string; modelfileID: string;
isLocked: boolean; isLocked: boolean;
isVisible: boolean; isVisible: boolean;
eventData?: {
type: 'Conveyor';
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
}[];
speed: number | string;
} | {
type: 'Vehicle';
point: {
uuid: string;
position: [number, number, number];
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
speed: number;
};
};
}; };
// Array of floor items for managing multiple objects on the floor // Array of floor items for managing multiple objects on the floor
@ -292,10 +271,10 @@ export type RefCSM = React.MutableRefObject<CSM>;
export type RefCSMHelper = React.MutableRefObject<CSMHelper>; export type RefCSMHelper = React.MutableRefObject<CSMHelper>;
interface PathConnection { interface PathConnection {
fromPathUUID: string; fromModelUUID: string;
fromUUID: string; fromUUID: string;
toConnections: { toConnections: {
toPathUUID: string; toModelUUID: string;
toUUID: string; toUUID: string;
}[]; }[];
} }
@ -317,7 +296,7 @@ interface ConveyorEventsSchema {
rotation: [number, number, number]; rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | []; actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | []; triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | [];
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
}[]; }[];
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number]; rotation: [number, number, number];
@ -328,12 +307,71 @@ interface VehicleEventsSchema {
modeluuid: string; modeluuid: string;
modelName: string; modelName: string;
type: 'Vehicle'; type: 'Vehicle';
point: { points: {
uuid: string; uuid: string;
position: [number, number, number]; position: [number, number, number];
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number }; actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
speed: number; speed: number;
}; };
position: [number, number, number]; position: [number, number, number];
} }
interface StaticMachineEventsSchema {
modeluuid: string;
modelName: string;
type: 'StaticMachine';
points: {
uuid: string;
position: [number, number, number];
actions: { uuid: string; name: string; buffer: number | string; material: string; isUsed: boolean };
triggers: { uuid: string; name: string; type: string };
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
};
position: [number, number, number];
}
interface ArmBotEventsSchema {
modeluuid: string;
modelName: string;
type: 'ArmBot';
points: {
uuid: string;
position: [number, number, number];
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] };
triggers: { uuid: string; name: string; type: string };
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
};
position: [number, number, number];
}
export type EventData = {
modeluuid: string;
modelname: string;
position: [number, number, number];
rotation: { x: number; y: number; z: number };
modelfileID: string;
isLocked: boolean;
isVisible: boolean;
eventData?: {
type: 'Conveyor';
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | [];
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
}[];
speed: number | string;
} | {
type: 'Vehicle';
points: {
uuid: string;
position: [number, number, number];
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
speed: number;
};
};
}