From 1ca5f001619ed691b5dff460f7f0f502ef8b89e6 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Thu, 8 May 2025 09:18:32 +0530 Subject: [PATCH 01/14] Add loading state and integrate simulation analysis components --- .../ui/analysis/ThroughputSummary.tsx | 2 +- .../analysis/simulationAnalysis.tsx | 12 + .../analysis/throughPut/throughPut.tsx | 31 +++ .../armInstance/roboticArmInstance.tsx | 216 +++++++++++++++++- app/src/modules/simulation/simulation.tsx | 3 + .../determineExecutionMachineSequences.ts | 101 ++++++++ 6 files changed, 360 insertions(+), 5 deletions(-) create mode 100644 app/src/modules/simulation/analysis/simulationAnalysis.tsx create mode 100644 app/src/modules/simulation/analysis/throughPut/throughPut.tsx create mode 100644 app/src/modules/simulation/simulator/functions/determineExecutionMachineSequences.ts diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index 6a0ad98..57eabd1 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -16,7 +16,7 @@ const ProductionCapacity = ({ const partialFillPercent = ((progressPercent / 100) * totalBars - barsToFill) * 100; - const isLoading = false; + const isLoading = true; return (
diff --git a/app/src/modules/simulation/analysis/simulationAnalysis.tsx b/app/src/modules/simulation/analysis/simulationAnalysis.tsx new file mode 100644 index 0000000..531c103 --- /dev/null +++ b/app/src/modules/simulation/analysis/simulationAnalysis.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import ThroughPut from './throughPut/throughPut' + +function SimulationAnalysis() { + return ( + <> + + + ) +} + +export default SimulationAnalysis diff --git a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx new file mode 100644 index 0000000..71e82f8 --- /dev/null +++ b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx @@ -0,0 +1,31 @@ +import React, { useEffect } from 'react' +import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import { useProductStore } from '../../../../store/simulation/useProductStore'; +import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; +export default function ThroughPut() { + const { selectedProduct } = useSelectedProduct(); + const { products,getProductById } = useProductStore() + + useEffect(() => { + let productData = getProductById(selectedProduct.productId) + if (productData) { + let productSequenceData = determineExecutionMachineSequences([productData]) + console.log('productSequenceData: ', productSequenceData); + if (productSequenceData?.length > 0) { + let totalItems = 0; // πŸ‘ˆ initialize total count + productSequenceData.map((sequence, index) => { + totalItems += sequence.length; + // sequence.map((item, idx) => {}); + }); + console.log(`Total items across all sequences: ${totalItems}`); // πŸ‘ˆ FINAL TOTAL βœ… + } else { + console.log('No productSequenceData found!'); + } + } + }, [products]) + + return ( + <> + + ) +} \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 7cd3634..a412714 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -1,12 +1,13 @@ import React, { useEffect, useRef, useState } from 'react' import IKInstance from '../ikInstance/ikInstance'; import RoboticArmAnimator from '../animator/roboticArmAnimator'; -import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; +import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_1.glb"; import { useThree } from "@react-three/fiber"; import * as THREE from "three"; import MaterialAnimator from '../animator/materialAnimator'; +import { clear } from 'console'; function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { @@ -20,12 +21,21 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { const groupRef = useRef(null); const pauseTimeRef = useRef(null); const isPausedRef = useRef(false); + const isSpeedRef = useRef(null); + const isIdleRef = useRef(false); let startTime: number; //zustand const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); const { isPlaying } = usePlayButtonStore(); const { isReset } = useResetButtonStore(); const { isPaused } = usePauseButtonStore(); + const { speed } = useAnimationPlaySpeed(); + + const activeSecondsElapsed = useRef(0); + const activeTimerId = useRef | null>(null); + + const idleSecondsElapsed = useRef(0); + const idleTimerId = useRef | null>(null); function firstFrame() { startTime = performance.now(); @@ -87,9 +97,15 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } useEffect(() => { + isPausedRef.current = isPaused; }, [isPaused]); + useEffect(() => { + + isSpeedRef.current = speed; + }, [speed]); + useEffect(() => { if (isReset || !isPlaying) { logStatus(armBot.modelUuid, "Simulation Play Reset Successfully") @@ -102,6 +118,12 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { isPausedRef.current = false pauseTimeRef.current = null startTime = 0 + clearInterval(activeTimerId.current!); + clearInterval(idleTimerId.current!); + activeTimerId.current = null; + activeSecondsElapsed.current = 0; + idleSecondsElapsed.current = 0; + idleTimerId.current = null; const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone ); if (targetBones && isPlaying) { @@ -114,6 +136,135 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } }, [isReset, isPlaying]) + useEffect(() => { + if (!isPlaying) return; + + const intervalMs = 1000 / isSpeedRef.current; + console.log('intervalMs: ', intervalMs); + + if (!armBot.isActive && armBot.state == "idle" && (currentPhase == "rest" || currentPhase == "init") && !isIdleRef.current) { + isIdleRef.current = true + + // Stop the timer + // 🚨 1. Clear Active Timer + if (activeTimerId.current) { + clearInterval(activeTimerId.current); + activeTimerId.current = null; + } + console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current} seconds`); + + // 🚨 2. Reset active timer seconds after logging + activeSecondsElapsed.current = 0; + + // 🚨 3. Start Idle Timer (clean old idle timer first) + if (idleTimerId.current) { + clearInterval(idleTimerId.current); + idleTimerId.current = null; + } + + idleSecondsElapsed.current = 0; + idleTimerId.current = setInterval(() => { + if (!isPausedRef.current) { + idleSecondsElapsed.current += 1; + console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current} seconds`); + } + }, intervalMs); + } else if (armBot.isActive && armBot.state != "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) { + isIdleRef.current = false + + if (armBot.currentAction) { + // 🚨 Clear Idle Timer + if (idleTimerId.current) { + clearInterval(idleTimerId.current); + idleTimerId.current = null; + } + console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`); + idleSecondsElapsed.current = 0; + + // 🚨 Start Active Timer + if (activeTimerId.current) { + clearInterval(activeTimerId.current); + } + activeSecondsElapsed.current = 0; + activeTimerId.current = setInterval(() => { + if (!isPausedRef.current) { + activeSecondsElapsed.current += 1 + console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current} seconds`); + } + }, intervalMs); + } + } + + }, [armBot, currentPhase, isPlaying]) + + + // useEffect(() => { + // if (!isPlaying) return; + // const now = () => performance.now(); + + + // const startActiveTimer = () => { + // let lastTime = now(); + + // const update = () => { + // if (!isPausedRef.current) { + // const currentTime = now(); + // const delta = currentTime - lastTime; + // activeSecondsElapsed.current += delta / 1000; + // console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current.toFixed(2)} seconds`); + // lastTime = currentTime; + // } else { + + // lastTime = now(); + // } + + // if (!isIdleRef.current) { + // requestAnimationFrame(update); + // } + // }; + + // activeSecondsElapsed.current = 0; + // update(); + // }; + + // const startIdleTimer = () => { + // let lastTime = now(); + + // const update = () => { + // if (!isPausedRef.current) { + // const currentTime = now(); + // const delta = currentTime - lastTime; + // idleSecondsElapsed.current += delta / 1000; + // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current.toFixed(2)} seconds`); + // lastTime = currentTime; + // } else { + // lastTime = now(); + // } + + // if (isIdleRef.current) { + // requestAnimationFrame(update); + // } + // }; + + // idleSecondsElapsed.current = 0; + // update(); + // }; + + // // State transition logic + // if (!armBot.isActive && armBot.state === "idle" && (currentPhase === "rest" || currentPhase === "init") && !isIdleRef.current) { + // isIdleRef.current = true; + // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current.toFixed(2)} seconds`); + // startIdleTimer(); + // } + // else if (armBot.isActive && armBot.state !== "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) { + // isIdleRef.current = false; + // console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current.toFixed(2)} seconds`); + // startActiveTimer(); + // } + + // }, [armBot, currentPhase, isPlaying, isIdleRef.current, isPausedRef.current]); + + useEffect(() => { const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); if (targetMesh) { @@ -136,6 +287,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } //Waiting for trigger. else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) { + logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction") const timeoutId = setTimeout(() => { addCurrentAction(armBot.modelUuid, armBot.point.actions[0].actionUuid, 'Material 2'); @@ -145,9 +297,30 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { //Moving to pickup point else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && armBot.currentAction) { if (armBot.currentAction) { + setArmBotActive(armBot.modelUuid, true); setArmBotState(armBot.modelUuid, "running"); setCurrentPhase("rest-to-start"); + // // 🚨 Clear Idle Timer + // if (idleTimerId.current) { + // clearInterval(idleTimerId.current); + // idleTimerId.current = null; + // } + // console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`); + // idleSecondsElapsed.current = 0; + + // // 🚨 Start Active Timer + // if (activeTimerId.current) { + // clearInterval(activeTimerId.current); + // } + // activeSecondsElapsed.current = 0; + // activeTimerId.current = setInterval(() => { + // if (!isPausedRef.current) { + // activeSecondsElapsed.current += 1; + // console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current} seconds`); + // } + // }, 1000); + const startPoint = armBot.point.actions[0].process.startPoint; if (startPoint) { let curve = createCurveBetweenTwoPoints(targetBones.position, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2])); @@ -177,6 +350,12 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { pauseTimeRef.current = null isPausedRef.current = false startTime = 0 + clearInterval(activeTimerId.current!); + clearInterval(idleTimerId.current!); + activeTimerId.current = null; + activeSecondsElapsed.current = 0; + idleSecondsElapsed.current = 0; + idleTimerId.current = null; removeCurrentAction(armBot.modelUuid) } @@ -215,10 +394,39 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } else if (armBot.isActive && armBot.state == "running" && currentPhase == "end-to-rest") { logStatus(armBot.modelUuid, "Callback triggered: rest, cycle completed."); + // Stop the timer + // 🚨 1. Clear Active Timer + // if (activeTimerId.current) { + // clearInterval(activeTimerId.current); + // activeTimerId.current = null; + // } + // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current} seconds`); + + // // 🚨 2. Reset active timer seconds after logging + // activeSecondsElapsed.current = 0; + + // // 🚨 3. Start Idle Timer (clean old idle timer first) + // if (idleTimerId.current) { + // clearInterval(idleTimerId.current); + // idleTimerId.current = null; + // } + + // idleSecondsElapsed.current = 0; + // idleTimerId.current = setInterval(() => { + // if (!isPausedRef.current) { + // idleSecondsElapsed.current += 1; + // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current} seconds`); + // } + // }, 1000); + + setArmBotActive(armBot.modelUuid, false) setArmBotState(armBot.modelUuid, "idle") setCurrentPhase("rest"); setPath([]) + + //end active calculation + removeCurrentAction(armBot.modelUuid) } } @@ -228,12 +436,12 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { return ( <> {!isReset && isPlaying && ( - <> + <> - - )} + + )} ) diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 7fe3c50..f918f56 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -12,6 +12,7 @@ import Simulator from './simulator/simulator'; import Products from './products/products'; import Trigger from './triggers/trigger'; import useModuleStore from '../../store/useModuleStore'; +import SimulationAnalysis from './analysis/simulationAnalysis'; function Simulation() { const { activeModule } = useModuleStore(); @@ -53,6 +54,8 @@ function Simulation() { + + } diff --git a/app/src/modules/simulation/simulator/functions/determineExecutionMachineSequences.ts b/app/src/modules/simulation/simulator/functions/determineExecutionMachineSequences.ts new file mode 100644 index 0000000..49e3cc6 --- /dev/null +++ b/app/src/modules/simulation/simulator/functions/determineExecutionMachineSequences.ts @@ -0,0 +1,101 @@ +import { extractTriggersFromPoint } from "./extractTriggersFromPoint"; + +export function determineExecutionMachineSequences(products: productsSchema): EventsSchema[][] { + const pointToEventMap = new Map(); + const allPoints: PointsScheme[] = []; + + // First pass: map points to their corresponding events + products.forEach(product => { + product.eventDatas.forEach(event => { + if (event.type === 'transfer') { + event.points.forEach(point => { + pointToEventMap.set(point.uuid, event); + allPoints.push(point); + }); + } else if ( + event.type === 'vehicle' || + event.type === 'machine' || + event.type === 'storageUnit' || + event.type === 'roboticArm' + ) { + pointToEventMap.set(event.point.uuid, event); + allPoints.push(event.point); + } + }); + }); + + // Build dependency graph + const dependencyGraph = new Map(); + const reverseDependencyGraph = new Map(); + const triggeredPoints = new Set(); + + allPoints.forEach(point => { + const triggers = extractTriggersFromPoint(point); + const dependencies: string[] = []; + + triggers.forEach(trigger => { + const targetUuid = trigger.triggeredAsset?.triggeredPoint?.pointUuid; + if (targetUuid && pointToEventMap.has(targetUuid)) { + dependencies.push(targetUuid); + triggeredPoints.add(targetUuid); + + if (!reverseDependencyGraph.has(targetUuid)) { + reverseDependencyGraph.set(targetUuid, []); + } + reverseDependencyGraph.get(targetUuid)!.push(point.uuid); + } + }); + + dependencyGraph.set(point.uuid, dependencies); + }); + + // Find root points (points that trigger others but are not triggered themselves) + const rootPoints = allPoints.filter(point => { + const hasOutgoingTriggers = extractTriggersFromPoint(point).some( + t => t.triggeredAsset?.triggeredPoint?.pointUuid + ); + return hasOutgoingTriggers && !triggeredPoints.has(point.uuid); + }); + + const executionSequences: EventsSchema[][] = []; + + function buildSequence(startUuid: string): EventsSchema[] { + const sequence: EventsSchema[] = []; + const visited = new Set(); + + function traverse(uuid: string) { + if (visited.has(uuid)) return; + visited.add(uuid); + + const event = pointToEventMap.get(uuid); + if (event && !sequence.includes(event)) { + sequence.push(event); + } + + const nextPoints = dependencyGraph.get(uuid) || []; + nextPoints.forEach(nextUuid => traverse(nextUuid)); + } + + traverse(startUuid); + return sequence; + } + + // Build sequences from root points + rootPoints.forEach(root => { + executionSequences.push(buildSequence(root.uuid)); + }); + + // Handle any isolated triggered points + const processedEvents = new Set( + executionSequences.flat().map(event => event) + ); + + allPoints.forEach(point => { + const event = pointToEventMap.get(point.uuid); + if (triggeredPoints.has(point.uuid) && event && !processedEvents.has(event)) { + executionSequences.push(buildSequence(point.uuid)); + } + }); + + return executionSequences; +} From cf66fbf20d4032de7d70781dc77bbc13bc5a06d7 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Fri, 9 May 2025 11:27:08 +0530 Subject: [PATCH 02/14] Implement machine count and uptime state management; refactor throughput calculations and logging in simulation components --- .../ui/analysis/ThroughputSummary.tsx | 14 +- .../analysis/throughPut/throughPut.tsx | 229 ++++++++++++++++-- .../armInstance/roboticArmInstance.tsx | 65 ++++- app/src/store/store.ts | 14 ++ 4 files changed, 299 insertions(+), 23 deletions(-) diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index 57eabd1..61e1282 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -1,3 +1,5 @@ +import { useEffect, useState } from "react"; +import { useMachineCount, useMachineUptime } from "../../../store/store"; import { ProductionCapacityIcon, ThroughputSummaryIcon, @@ -16,7 +18,15 @@ const ProductionCapacity = ({ const partialFillPercent = ((progressPercent / 100) * totalBars - barsToFill) * 100; - const isLoading = true; + const [isLoading, setIsLoading] = useState(false); + const { machineCount, setMachineCount } = useMachineCount() + const { machineActiveTime, setMachineActiveTime } = useMachineUptime() + useEffect(() => { + setIsLoading(true); + machineUtilization = machineActiveTime + console.log('machineActiveTime: ', machineActiveTime); + }, [machineActiveTime]) + return (
@@ -62,7 +72,7 @@ const ProductionCapacity = ({
Machine Utilization - {machineUtilization} + {machineActiveTime}
diff --git a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx index 71e82f8..385fb0b 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx @@ -1,31 +1,232 @@ -import React, { useEffect } from 'react' +// import React, { useEffect, useState } from 'react'; +// import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +// import { useProductStore } from '../../../../store/simulation/useProductStore'; +// import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; +// import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; +// import { useMachineCount, useMachineUptime, useMaterialCycle } from '../../../../store/store'; +// import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; +// import { useMachineStore } from '../../../../store/simulation/useMachineStore'; +// import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; +// import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'; +// import { useMaterialStore } from '../../../../store/simulation/useMaterialStore'; + +// export default function ThroughPut() { +// const { selectedProduct } = useSelectedProduct(); +// const { products, getProductById } = useProductStore(); +// const { armBots } = useArmBotStore(); +// const { vehicles } = useVehicleStore(); +// const { machines } = useMachineStore(); +// const { conveyors } = useConveyorStore(); +// const { storageUnits } = useStorageUnitStore(); +// const { materials } = useMaterialStore(); + +// const { machineCount, setMachineCount } = useMachineCount(); +// const { setMachineActiveTime } = useMachineUptime(); +// const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle(); + +// const [totalActiveTime, setTotalActiveTime] = useState(0); + +// // 1. Setting static active times and counting machines +// useEffect(() => { +// const productData = getProductById(selectedProduct.productId); +// if (productData) { +// const productSequenceData = determineExecutionMachineSequences([productData]); +// if (productSequenceData?.length > 0) { +// let totalItems = 0; + +// productSequenceData.forEach((sequence) => { +// totalItems += sequence.length; +// sequence.forEach((item) => { +// if (item.type === "roboticArm") { +// armBots.filter(arm => arm.modelUuid === item.modelUuid) +// .forEach(arm => { +// if (arm.activeTime >= 0) { +// console.log('armBot activeTime:', arm.activeTime); +// } +// }); +// } else if (item.type === "vehicle") { +// vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid) +// .forEach(vehicle => { +// if (vehicle.activeTime >= 0) { +// vehicle.activeTime = 10; // static +// } +// }); +// } else if (item.type === "machine") { +// machines.filter(machine => machine.modelUuid === item.modelUuid) +// .forEach(machine => { +// if (machine.activeTime >= 0) { +// machine.activeTime = 12; // static +// } +// }); +// } else if (item.type === "transfer") { +// conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid) +// .forEach(conveyor => { +// if (conveyor.activeTime >= 0) { +// conveyor.activeTime = 5; // static +// } +// }); +// } else if (item.type === "storageUnit") { +// storageUnits.filter(storage => storage.modelUuid === item.modelUuid) +// .forEach(storage => { +// if (storage.activeTime >= 0) { +// storage.activeTime = 8; // static +// } +// }); +// } +// }); +// }); + +// setMachineCount(totalItems); +// } +// } +// }, [products, selectedProduct, armBots, vehicles, machines, conveyors, storageUnits, getProductById, setMachineCount]); + +// // 2. Set material cycle time (static also) +// useEffect(() => { +// materials.forEach((material) => { +// material.startTime = 50; +// material.endTime = 100; +// const totalCycleTime = material.endTime - material.startTime; +// setMaterialCycleTime(totalCycleTime); +// }); +// }, [materials, setMaterialCycleTime]); + +// // 3. Sum of all activeTimes after static values are set +// useEffect(() => { +// let sum = 0; +// armBots.forEach(arm => { if (arm.activeTime > 0) sum += arm.activeTime; }); +// vehicles.forEach(vehicle => { if (vehicle.activeTime > 0) sum += vehicle.activeTime; }); +// machines.forEach(machine => { if (machine.activeTime > 0) sum += machine.activeTime; }); +// conveyors.forEach(conveyor => { if (conveyor.activeTime > 0) sum += conveyor.activeTime; }); +// storageUnits.forEach(storage => { if (storage.activeTime > 0) sum += storage.activeTime; }); + +// setTotalActiveTime(sum); +// setMachineActiveTime(sum); + +// }, [armBots, vehicles, machines, conveyors, storageUnits, setMachineActiveTime]); + +// // 4. Calculate throughput when activeTime and materialCycleTime are ready +// useEffect(() => { +// if (totalActiveTime > 0 && materialCycleTime > 0) { +// const avgProcessTime = (totalActiveTime / materialCycleTime) * 100; +// console.log('Throughput (%):', avgProcessTime.toFixed(2)); +// } +// }, [totalActiveTime, materialCycleTime]); + +// return ( +// <> +// +// ); +// } + + +import React, { useEffect, useState } from 'react'; import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useProductStore } from '../../../../store/simulation/useProductStore'; import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; +import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; +import { useMachineCount, useMachineUptime, useMaterialCycle } from '../../../../store/store'; +import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; +import { useMachineStore } from '../../../../store/simulation/useMachineStore'; +import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; +import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'; +import { useMaterialStore } from '../../../../store/simulation/useMaterialStore'; + export default function ThroughPut() { const { selectedProduct } = useSelectedProduct(); - const { products,getProductById } = useProductStore() + const { products, getProductById } = useProductStore(); + const { armBots } = useArmBotStore(); + const { vehicles } = useVehicleStore(); + const { machines } = useMachineStore(); + const { conveyors } = useConveyorStore(); + const { storageUnits } = useStorageUnitStore(); + const { materials } = useMaterialStore(); + const { setMachineCount } = useMachineCount(); + const { setMachineActiveTime } = useMachineUptime(); + const { setMaterialCycleTime } = useMaterialCycle(); + + const [totalActiveTime, setTotalActiveTime] = useState(0); + const [throughputData, setThroughputData] = useState(0); // <=== ADD THIS + + // Setting machine count useEffect(() => { - let productData = getProductById(selectedProduct.productId) + const productData = getProductById(selectedProduct.productId); if (productData) { - let productSequenceData = determineExecutionMachineSequences([productData]) - console.log('productSequenceData: ', productSequenceData); + const productSequenceData = determineExecutionMachineSequences([productData]); if (productSequenceData?.length > 0) { - let totalItems = 0; // πŸ‘ˆ initialize total count - productSequenceData.map((sequence, index) => { + let totalItems = 0; + productSequenceData.forEach((sequence) => { totalItems += sequence.length; - // sequence.map((item, idx) => {}); }); - console.log(`Total items across all sequences: ${totalItems}`); // πŸ‘ˆ FINAL TOTAL βœ… - } else { - console.log('No productSequenceData found!'); + setMachineCount(totalItems); } } - }, [products]) + }, [products, selectedProduct, getProductById, setMachineCount]); + + // Setting material cycle time + useEffect(() => { + materials.forEach(() => { + const staticStartTime = 50; + const staticEndTime = 100; + const totalCycleTime = staticEndTime - staticStartTime; + setMaterialCycleTime(totalCycleTime); + }); + }, [materials, setMaterialCycleTime]); + + // Calculate Sum, Machine Uptime and Throughput + useEffect(() => { + let sum = 0; + + console.log('armBots: ', armBots); + armBots.forEach(arm => { + console.log('arm.activeTime: ', arm.activeTime); + if (arm.activeTime > 0) sum += arm.activeTime; + }); + + vehicles.forEach(vehicle => { + if (vehicle.activeTime > 0) sum += 10; // static + }); + + machines.forEach(machine => { + if (machine.activeTime > 0) sum += 12; // static + }); + + conveyors.forEach(conveyor => { + if (conveyor.activeTime > 0) sum += 5; // static + }); + + storageUnits.forEach(storage => { + if (storage.activeTime > 0) sum += 8; // static + }); + + console.log('sum: ', sum); + + const avgProcessTime = 100 - 50; // static 50 + const machineUptime = (sum / avgProcessTime) * 100; + console.log('machineUptime: ', machineUptime.toFixed(2)); + + const machineCount = 3; // static + const throughput = (3600 / avgProcessTime) * machineCount * (machineUptime / 100); // **IMPORTANT divide by 100 for %** + console.log('throughPutData: ', throughput.toFixed(2)); + + setTotalActiveTime(sum); + setMachineActiveTime(sum); + setThroughputData(throughput); // Save it properly here + + }, [armBots, vehicles, machines, conveyors, storageUnits, setMachineActiveTime]); + + // Just display throughput when ready + useEffect(() => { + console.log('throughputData: ', throughputData); + if (throughputData > 0) { + console.log('Final Throughput (units/hour): ', throughputData.toFixed(2)); + } + }, [throughputData]); return ( <> - ) -} \ No newline at end of file + ); +} + diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 2107776..e2658f4 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -27,7 +27,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { const isIdleRef = useRef(false); let startTime: number; - const { setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); + const { setArmBotActive, setArmBotState, removeCurrentAction,incrementActiveTime,incrementIdleTime } = useArmBotStore(); const { setIsVisible } = useMaterialStore(); const { selectedProduct } = useSelectedProduct(); const { getActionByUuid } = useProductStore(); @@ -161,8 +161,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { useEffect(() => { if (!isPlaying) return; - const intervalMs = 1000 / isSpeedRef.current; - console.log('intervalMs: ', intervalMs); + const intervalMs = 1000 if (!armBot.isActive && armBot.state == "idle" && (currentPhase == "rest" || currentPhase == "init") && !isIdleRef.current) { isIdleRef.current = true @@ -173,7 +172,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { clearInterval(activeTimerId.current); activeTimerId.current = null; } - console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current} seconds`); + incrementActiveTime(armBot.modelUuid, activeSecondsElapsed.current) + // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current} seconds`); // 🚨 2. Reset active timer seconds after logging activeSecondsElapsed.current = 0; @@ -188,7 +188,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { idleTimerId.current = setInterval(() => { if (!isPausedRef.current) { idleSecondsElapsed.current += 1; - console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current} seconds`); + // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current} seconds`); } }, intervalMs); } else if (armBot.isActive && armBot.state != "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) { @@ -200,7 +200,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { clearInterval(idleTimerId.current); idleTimerId.current = null; } - console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`); + incrementIdleTime(armBot.modelUuid, idleSecondsElapsed.current) + // console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`); idleSecondsElapsed.current = 0; // 🚨 Start Active Timer @@ -211,7 +212,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { activeTimerId.current = setInterval(() => { if (!isPausedRef.current) { activeSecondsElapsed.current += 1 - console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current} seconds`); + // console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current} seconds`); } }, intervalMs); } @@ -287,6 +288,56 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { // }, [armBot, currentPhase, isPlaying, isIdleRef.current, isPausedRef.current]); + + // useEffect(() => { + // if (!isPlaying) return; + + // let frameId: number | null = null; + // let lastTime = performance.now(); + + // const tick = (currentTime: number) => { + // const delta = currentTime - lastTime; + // lastTime = currentTime; + + // const secondsToAdd = delta / 1000; // ⚑️REAL time passed (NO speed multiplication) + + // if (!isPausedRef.current) { + // // Update Timer + // if (isIdleRef.current) { + // idleSecondsElapsed.current += secondsToAdd; + // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current.toFixed(2)} seconds (Speed: ${isSpeedRef.current}x)`); + // } else { + // activeSecondsElapsed.current += secondsToAdd; + // console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current.toFixed(2)} seconds (Speed: ${isSpeedRef.current}x)`); + // } + // } + // frameId = requestAnimationFrame(tick); + // }; + // // Detect mode switch + // if (!armBot.isActive && armBot.state === "idle" && (currentPhase === "rest" || currentPhase === "init") && !isIdleRef.current) { + // isIdleRef.current = true; + + // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current.toFixed(2)} seconds`); + // activeSecondsElapsed.current = 0; + // idleSecondsElapsed.current = 0; + // } else if (armBot.isActive && armBot.state !== "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) { + // isIdleRef.current = false; + // console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current.toFixed(2)} seconds`); + // idleSecondsElapsed.current = 0; + // activeSecondsElapsed.current = 0; + // } + + // frameId = requestAnimationFrame(tick); + + // return () => { + // if (frameId !== null) { + // cancelAnimationFrame(frameId); + // } + // }; + // }, [armBot, currentPhase, isPlaying]); + + + useEffect(() => { const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); if (targetMesh) { diff --git a/app/src/store/store.ts b/app/src/store/store.ts index b16e1ff..e0157ff 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -430,3 +430,17 @@ export const useZoneAssetId = create((set) => ({ zoneAssetId: null, setZoneAssetId: (asset) => set({ zoneAssetId: asset }), })); + + +export const useMachineCount = create((set: any) => ({ + machineCount: 0, + setMachineCount: (x: any) => set({ activeLayer: x }), +})); +export const useMachineUptime = create((set: any) => ({ + machineActiveTime: 0, + setMachineActiveTime: (x: any) => set({ activeLayer: x }), +})); +export const useMaterialCycle = create((set: any) => ({ + materialCycleTime: 0, + setMaterialCycleTime: (x: any) => set({ activeLayer: x }), +})); \ No newline at end of file From 35c21c60b22e7c55c3de475821f072ad3987020c Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Fri, 9 May 2025 13:09:45 +0530 Subject: [PATCH 03/14] update state for throughput analysis --- .../ui/analysis/ProductionCapacity.tsx | 53 ++- .../ui/analysis/ThroughputSummary.tsx | 25 +- .../analysis/throughPut/throughPut.tsx | 29 +- .../widgets/3d/cards/Throughput.tsx | 17 +- app/src/store/store.ts | 449 +++++++++--------- 5 files changed, 302 insertions(+), 271 deletions(-) diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx index d6ebc58..3883ee3 100644 --- a/app/src/components/ui/analysis/ProductionCapacity.tsx +++ b/app/src/components/ui/analysis/ProductionCapacity.tsx @@ -9,6 +9,7 @@ import { } from "chart.js"; import { PowerIcon, ProductionCapacityIcon } from "../../icons/analysis"; import SkeletonUI from "../../templates/SkeletonUI"; +import { useMachineUptime } from "../../../store/store"; ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); @@ -19,12 +20,9 @@ const ThroughputSummary = () => { endTime: "09:00 AM", }; - const throughputData = { - labels: ["08:00", "08:10", "08:20", "08:30", "08:40", "08:50"], - data: [5, 10, 8, 10, 12, 10], - totalThroughput: 1240, - assetUsage: 85, - }; + const { machineActiveTime } = useMachineUptime(); + + const energyConsumption = { energyConsumed: 456, @@ -38,19 +36,7 @@ const ThroughputSummary = () => { { shift: 3, percentage: 30, color: "#7981F5" }, ]; - // Chart data configuration - const chartData = { - labels: throughputData.labels, - datasets: [ - { - label: "Units/hour", - data: throughputData.data, - borderColor: "#B392F0", - tension: 0.4, - pointRadius: 0, // Hide points - }, - ], - }; + const chartOptions = { responsive: true, @@ -73,6 +59,35 @@ const ThroughputSummary = () => { }, }; + const assetUsage = 85; + + // machineActiveTime => Throughput + // shiftUtilization.length => Shifts per day + // 8 => Shift length + // assetUsage => Yield rate + + const throughtputMachineData = machineActiveTime * shiftUtilization.length * 8 + + const throughputData = { + labels: ["08:00", "08:10", "08:20", "08:30", "08:40", "08:50"], + data: [5, 10, 8, 10, 12, 10], + totalThroughput: (throughtputMachineData) * assetUsage / 100, + assetUsage: assetUsage, + }; + + // Chart data configuration + const chartData = { + labels: throughputData.labels, + datasets: [ + { + label: "Units/hour", + data: throughputData.data, + borderColor: "#B392F0", + tension: 0.4, + pointRadius: 0, // Hide points + }, + ], + }; const isLoading = false; return ( diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index 61e1282..55da34f 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { useMachineCount, useMachineUptime } from "../../../store/store"; +import { useMachineCount, useMachineUptime, useMaterialCycle } from "../../../store/store"; import { ProductionCapacityIcon, ThroughputSummaryIcon, @@ -7,26 +7,34 @@ import { import SkeletonUI from "../../templates/SkeletonUI"; const ProductionCapacity = ({ - progressPercent = 50, avgProcessTime = "28.4 Secs/unit", machineUtilization = "78%", throughputValue = 128, timeRange = { startTime: "08:00 AM", endTime: "09:00 AM" }, }) => { + + + const { machineCount } = useMachineCount(); + const { machineActiveTime } = useMachineUptime(); + const { materialCycleTime } = useMaterialCycle(); + + const progressPercent = machineActiveTime; + + const totalBars = 6; const barsToFill = Math.floor((progressPercent / 100) * totalBars); const partialFillPercent = ((progressPercent / 100) * totalBars - barsToFill) * 100; const [isLoading, setIsLoading] = useState(false); - const { machineCount, setMachineCount } = useMachineCount() - const { machineActiveTime, setMachineActiveTime } = useMachineUptime() + // const { machineCount, setMachineCount } = useMachineCount() + // const { machineActiveTime, setMachineActiveTime } = useMachineUptime() useEffect(() => { setIsLoading(true); machineUtilization = machineActiveTime console.log('machineActiveTime: ', machineActiveTime); }, [machineActiveTime]) - + return (
@@ -45,7 +53,7 @@ const ProductionCapacity = ({ <>
- {throughputValue} Units/hour + {machineActiveTime} Units/hour
{/* Dynamic Progress Bar */} @@ -68,11 +76,12 @@ const ProductionCapacity = ({
Avg. Process Time - {avgProcessTime} + {materialCycleTime} secs/unit
Machine Utilization - {machineActiveTime} + 1 + {/* {machineActiveTime} */}
diff --git a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx index 385fb0b..8a9e331 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx @@ -41,7 +41,7 @@ // armBots.filter(arm => arm.modelUuid === item.modelUuid) // .forEach(arm => { // if (arm.activeTime >= 0) { -// console.log('armBot activeTime:', arm.activeTime); +// // } // }); // } else if (item.type === "vehicle") { @@ -109,7 +109,7 @@ // useEffect(() => { // if (totalActiveTime > 0 && materialCycleTime > 0) { // const avgProcessTime = (totalActiveTime / materialCycleTime) * 100; -// console.log('Throughput (%):', avgProcessTime.toFixed(2)); +// // } // }, [totalActiveTime, materialCycleTime]); @@ -143,7 +143,8 @@ export default function ThroughPut() { const { materials } = useMaterialStore(); const { setMachineCount } = useMachineCount(); - const { setMachineActiveTime } = useMachineUptime(); + const { machineActiveTime, setMachineActiveTime } = useMachineUptime(); + console.log('machineActiveTime: ', machineActiveTime); const { setMaterialCycleTime } = useMaterialCycle(); const [totalActiveTime, setTotalActiveTime] = useState(0); @@ -178,9 +179,9 @@ export default function ThroughPut() { useEffect(() => { let sum = 0; - console.log('armBots: ', armBots); + armBots.forEach(arm => { - console.log('arm.activeTime: ', arm.activeTime); + if (arm.activeTime > 0) sum += arm.activeTime; }); @@ -200,27 +201,33 @@ export default function ThroughPut() { if (storage.activeTime > 0) sum += 8; // static }); - console.log('sum: ', sum); + const avgProcessTime = 100 - 50; // static 50 + const machineUptime = (sum / avgProcessTime) * 100; - console.log('machineUptime: ', machineUptime.toFixed(2)); + console.log('machineUptime: ', machineUptime); + + const machineCount = 3; // static const throughput = (3600 / avgProcessTime) * machineCount * (machineUptime / 100); // **IMPORTANT divide by 100 for %** - console.log('throughPutData: ', throughput.toFixed(2)); + + setTotalActiveTime(sum); - setMachineActiveTime(sum); + setMachineActiveTime(machineUptime) + setMaterialCycleTime(throughput) + // setMachineActiveTime(sum); setThroughputData(throughput); // Save it properly here }, [armBots, vehicles, machines, conveyors, storageUnits, setMachineActiveTime]); // Just display throughput when ready useEffect(() => { - console.log('throughputData: ', throughputData); + if (throughputData > 0) { - console.log('Final Throughput (units/hour): ', throughputData.toFixed(2)); + } }, [throughputData]); diff --git a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx index 18edb61..1489c3d 100644 --- a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx @@ -83,6 +83,8 @@ const Throughput: React.FC = ({ const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; + + // Sample data for the line graph const graphData: ChartData<"line"> = { labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"], @@ -222,16 +224,15 @@ const Throughput: React.FC = ({ transform zIndexRange={[1, 0]} sprite={false} - // style={{ - // transform: transformStyle.transform, - // transformStyle: "preserve-3d", - // transition: "transform 0.1s ease-out", - // }} + // style={{ + // transform: transformStyle.transform, + // transformStyle: "preserve-3d", + // transition: "transform 0.1s ease-out", + // }} >
setSelectedChartId({ id: id, type: type })} onContextMenu={onContextMenu} > diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 45e8b31..13258c6 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -4,448 +4,447 @@ import { create } from "zustand"; import { io } from "socket.io-client"; export const useSocketStore = create((set: any, get: any) => ({ - socket: null, - initializeSocket: (email: string, organization: string) => { - const existingSocket = get().socket; - if (existingSocket) { - return; - } + socket: null, + initializeSocket: (email: string, organization: string) => { + const existingSocket = get().socket; + if (existingSocket) { + return; + } - const socket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, - { - reconnection: true, - auth: { email, organization }, - } - ); + const socket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, + { + reconnection: true, + auth: { email, organization }, + } + ); - const visualizationSocket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, - { - reconnection: true, - auth: { email, organization }, - } - ); + const visualizationSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, + { + reconnection: true, + auth: { email, organization }, + } + ); - set({ socket, visualizationSocket }); - }, - disconnectSocket: () => { - set((state: any) => { - state.socket?.disconnect(); - state.visualizationSocket?.disconnect(); - return { socket: null }; - }); - }, + set({ socket, visualizationSocket }); + }, + disconnectSocket: () => { + set((state: any) => { + state.socket?.disconnect(); + state.visualizationSocket?.disconnect(); + return { socket: null }; + }); + }, })); export const useLoadingProgress = create<{ - loadingProgress: number; - setLoadingProgress: (x: number) => void; + loadingProgress: number; + setLoadingProgress: (x: number) => void; }>((set) => ({ - loadingProgress: 1, - setLoadingProgress: (x: number) => set({ loadingProgress: x }), + loadingProgress: 1, + setLoadingProgress: (x: number) => set({ loadingProgress: x }), })); export const useOrganization = create((set: any) => ({ - organization: "", - setOrganization: (x: any) => set(() => ({ organization: x })), + organization: "", + setOrganization: (x: any) => set(() => ({ organization: x })), })); export const useToggleView = create((set: any) => ({ - toggleView: false, - setToggleView: (x: any) => set(() => ({ toggleView: x })), + toggleView: false, + setToggleView: (x: any) => set(() => ({ toggleView: x })), })); export const useUpdateScene = create((set: any) => ({ - updateScene: false, - setUpdateScene: (x: any) => set(() => ({ updateScene: x })), + updateScene: false, + setUpdateScene: (x: any) => set(() => ({ updateScene: x })), })); export const useWalls = create((set: any) => ({ - walls: [], - setWalls: (x: any) => set(() => ({ walls: x })), + walls: [], + setWalls: (x: any) => set(() => ({ walls: x })), })); export const useRoomsState = create((set: any) => ({ - roomsState: [], - setRoomsState: (x: any) => set(() => ({ walls: x })), + roomsState: [], + setRoomsState: (x: any) => set(() => ({ walls: x })), })); export const useZones = create((set: any) => ({ - zones: [], - setZones: (callback: any) => - set((state: any) => ({ - zones: typeof callback === "function" ? callback(state.zones) : callback, - })), + zones: [], + setZones: (callback: any) => + set((state: any) => ({ + zones: typeof callback === "function" ? callback(state.zones) : callback, + })), })); interface ZonePointsState { - zonePoints: THREE.Vector3[]; - setZonePoints: (points: THREE.Vector3[]) => void; + zonePoints: THREE.Vector3[]; + setZonePoints: (points: THREE.Vector3[]) => void; } export const useZonePoints = create((set) => ({ - zonePoints: [], - setZonePoints: (points) => set({ zonePoints: points }), + zonePoints: [], + setZonePoints: (points) => set({ zonePoints: points }), })); export const useSelectedItem = create((set: any) => ({ - selectedItem: { name: "", id: "", type: undefined }, - setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), + selectedItem: { name: "", id: "", type: undefined }, + setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), })); export const useNavMesh = create((set: any) => ({ - navMesh: null, - setNavMesh: (x: any) => set({ navMesh: x }), + navMesh: null, + setNavMesh: (x: any) => set({ navMesh: x }), })); export const useSelectedAssets = create((set: any) => ({ - selectedAssets: [], - setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })), + selectedAssets: [], + setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })), })); export const useLayers = create((set: any) => ({ - Layers: 1, - setLayers: (x: any) => set(() => ({ Layers: x })), + Layers: 1, + setLayers: (x: any) => set(() => ({ Layers: x })), })); export const useCamPosition = create((set: any) => ({ - camPosition: { x: undefined, y: undefined, z: undefined }, - setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }), + camPosition: { x: undefined, y: undefined, z: undefined }, + setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }), })); export const useMenuVisible = create((set: any) => ({ - menuVisible: false, - setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), + menuVisible: false, + setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), })); export const useDeleteTool = create((set: any) => ({ - deleteTool: false, - setDeleteTool: (x: any) => set(() => ({ deleteTool: x })), + deleteTool: false, + setDeleteTool: (x: any) => set(() => ({ deleteTool: x })), })); export const useToolMode = create((set: any) => ({ - toolMode: null, - setToolMode: (x: any) => set(() => ({ toolMode: x })), + toolMode: null, + setToolMode: (x: any) => set(() => ({ toolMode: x })), })); export const useNewLines = create((set: any) => ({ - newLines: [], - setNewLines: (x: any) => set(() => ({ newLines: x })), + newLines: [], + setNewLines: (x: any) => set(() => ({ newLines: x })), })); export const useDeletedLines = create((set: any) => ({ - deletedLines: [], - setDeletedLines: (x: any) => set(() => ({ deletedLines: x })), + deletedLines: [], + setDeletedLines: (x: any) => set(() => ({ deletedLines: x })), })); export const useMovePoint = create((set: any) => ({ - movePoint: false, - setMovePoint: (x: any) => set(() => ({ movePoint: x })), + movePoint: false, + setMovePoint: (x: any) => set(() => ({ movePoint: x })), })); export const useTransformMode = create((set: any) => ({ - transformMode: null, - setTransformMode: (x: any) => set(() => ({ transformMode: x })), + transformMode: null, + setTransformMode: (x: any) => set(() => ({ transformMode: x })), })); export const useDeletePointOrLine = create((set: any) => ({ - deletePointOrLine: false, - setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })), + deletePointOrLine: false, + setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })), })); export const useFloorItems = create((set: any) => ({ - floorItems: null, - setFloorItems: (callback: any) => - set((state: any) => ({ - floorItems: - typeof callback === "function" ? callback(state.floorItems) : callback, - })), + floorItems: null, + setFloorItems: (callback: any) => + set((state: any) => ({ + floorItems: + typeof callback === "function" ? callback(state.floorItems) : callback, + })), })); export const useWallItems = create((set: any) => ({ - wallItems: [], - setWallItems: (callback: any) => - set((state: any) => ({ - wallItems: - typeof callback === "function" ? callback(state.wallItems) : callback, - })), + wallItems: [], + setWallItems: (callback: any) => + set((state: any) => ({ + wallItems: + typeof callback === "function" ? callback(state.wallItems) : callback, + })), })); export const useSelectedWallItem = create((set: any) => ({ - selectedWallItem: null, - setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })), + selectedWallItem: null, + setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })), })); export const useSelectedFloorItem = create((set: any) => ({ - selectedFloorItem: null, - setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })), + selectedFloorItem: null, + setSelectedFloorItem: (x: any) => set(() => ({ selectedFloorItem: x })), })); export const useDeletableFloorItem = create((set: any) => ({ - deletableFloorItem: null, - setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })), + deletableFloorItem: null, + setDeletableFloorItem: (x: any) => set(() => ({ deletableFloorItem: x })), })); export const useSetScale = create((set: any) => ({ - scale: null, - setScale: (x: any) => set(() => ({ scale: x })), + scale: null, + setScale: (x: any) => set(() => ({ scale: x })), })); export const useRoofVisibility = create((set: any) => ({ - roofVisibility: false, - setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })), + roofVisibility: false, + setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })), })); export const useWallVisibility = create((set: any) => ({ - wallVisibility: false, - setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })), + wallVisibility: false, + setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })), })); export const useShadows = create((set: any) => ({ - shadows: false, - setShadows: (x: any) => set(() => ({ shadows: x })), + shadows: false, + setShadows: (x: any) => set(() => ({ shadows: x })), })); export const useSunPosition = create((set: any) => ({ - sunPosition: { x: undefined, y: undefined, z: undefined }, - setSunPosition: (newSuntPosition: any) => - set({ sunPosition: newSuntPosition }), + sunPosition: { x: undefined, y: undefined, z: undefined }, + setSunPosition: (newSuntPosition: any) => + set({ sunPosition: newSuntPosition }), })); export const useRemoveLayer = create((set: any) => ({ - removeLayer: false, - setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })), + removeLayer: false, + setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })), })); export const useRemovedLayer = create((set: any) => ({ - removedLayer: null, - setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })), + removedLayer: null, + setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })), })); export const useActiveLayer = create((set: any) => ({ - activeLayer: 1, - setActiveLayer: (x: any) => set({ activeLayer: x }), + activeLayer: 1, + setActiveLayer: (x: any) => set({ activeLayer: x }), })); interface RefTextUpdateState { - refTextupdate: number; - setRefTextUpdate: ( - callback: (currentValue: number) => number | number - ) => void; + refTextupdate: number; + setRefTextUpdate: ( + callback: (currentValue: number) => number | number + ) => void; } export const useRefTextUpdate = create((set) => ({ - refTextupdate: -1000, - setRefTextUpdate: (callback) => - set((state) => ({ - refTextupdate: - typeof callback === "function" - ? callback(state.refTextupdate) - : callback, - })), + refTextupdate: -1000, + setRefTextUpdate: (callback) => + set((state) => ({ + refTextupdate: + typeof callback === "function" + ? callback(state.refTextupdate) + : callback, + })), })); export const useResetCamera = create((set: any) => ({ - resetCamera: false, - setResetCamera: (x: any) => set({ resetCamera: x }), + resetCamera: false, + setResetCamera: (x: any) => set({ resetCamera: x }), })); export const useAddAction = create((set: any) => ({ - addAction: null, - setAddAction: (x: any) => set({ addAction: x }), + addAction: null, + setAddAction: (x: any) => set({ addAction: x }), })); export const useActiveTool = create((set: any) => ({ - activeTool: "cursor", - setActiveTool: (x: any) => set({ activeTool: x }), + activeTool: "cursor", + setActiveTool: (x: any) => set({ activeTool: x }), })); export const useActiveSubTool = create((set: any) => ({ - activeSubTool: "cursor", - setActiveSubTool: (x: any) => set({ activeSubTool: x }), + activeSubTool: "cursor", + setActiveSubTool: (x: any) => set({ activeSubTool: x }), })); export const use2DUndoRedo = create((set: any) => ({ - is2DUndoRedo: null, - set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }), + is2DUndoRedo: null, + set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }), })); export const useElevation = create((set: any) => ({ - elevation: 45, - setElevation: (x: any) => set({ elevation: x }), + elevation: 45, + setElevation: (x: any) => set({ elevation: x }), })); export const useAzimuth = create((set: any) => ({ - azimuth: -160, - setAzimuth: (x: any) => set({ azimuth: x }), + azimuth: -160, + setAzimuth: (x: any) => set({ azimuth: x }), })); export const useRenderDistance = create((set: any) => ({ - renderDistance: 40, - setRenderDistance: (x: any) => set({ renderDistance: x }), + renderDistance: 40, + setRenderDistance: (x: any) => set({ renderDistance: x }), })); export const useCamMode = create((set: any) => ({ - camMode: "ThirdPerson", - setCamMode: (x: any) => set({ camMode: x }), + camMode: "ThirdPerson", + setCamMode: (x: any) => set({ camMode: x }), })); export const useUserName = create((set: any) => ({ - userName: "", - setUserName: (x: any) => set({ userName: x }), + userName: "", + setUserName: (x: any) => set({ userName: x }), })); export const useObjectPosition = create((set: any) => ({ - objectPosition: { x: undefined, y: undefined, z: undefined }, - setObjectPosition: (newObjectPosition: any) => - set({ objectPosition: newObjectPosition }), + objectPosition: { x: undefined, y: undefined, z: undefined }, + setObjectPosition: (newObjectPosition: any) => + set({ objectPosition: newObjectPosition }), })); export const useObjectScale = create((set: any) => ({ - objectScale: { x: undefined, y: undefined, z: undefined }, - setObjectScale: (newObjectScale: any) => set({ objectScale: newObjectScale }), + objectScale: { x: undefined, y: undefined, z: undefined }, + setObjectScale: (newObjectScale: any) => set({ objectScale: newObjectScale }), })); export const useObjectRotation = create((set: any) => ({ - objectRotation: { x: undefined, y: undefined, z: undefined }, - setObjectRotation: (newObjectRotation: any) => - set({ objectRotation: newObjectRotation }), + objectRotation: { x: undefined, y: undefined, z: undefined }, + setObjectRotation: (newObjectRotation: any) => + set({ objectRotation: newObjectRotation }), })); export const useDrieTemp = create((set: any) => ({ - drieTemp: undefined, - setDrieTemp: (x: any) => set({ drieTemp: x }), + drieTemp: undefined, + setDrieTemp: (x: any) => set({ drieTemp: x }), })); export const useActiveUsers = create((set: any) => ({ - activeUsers: [], - setActiveUsers: (callback: (prev: any[]) => any[] | any[]) => - set((state: { activeUsers: any[] }) => ({ - activeUsers: - typeof callback === "function" ? callback(state.activeUsers) : callback, - })), + activeUsers: [], + setActiveUsers: (callback: (prev: any[]) => any[] | any[]) => + set((state: { activeUsers: any[] }) => ({ + activeUsers: + typeof callback === "function" ? callback(state.activeUsers) : callback, + })), })); export const useDrieUIValue = create((set: any) => ({ - drieUIValue: { touch: null, temperature: null, humidity: null }, + drieUIValue: { touch: null, temperature: null, humidity: null }, - setDrieUIValue: (x: any) => - set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), + setDrieUIValue: (x: any) => + set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), - setTouch: (value: any) => - set((state: any) => ({ - drieUIValue: { ...state.drieUIValue, touch: value }, - })), - setTemperature: (value: any) => - set((state: any) => ({ - drieUIValue: { ...state.drieUIValue, temperature: value }, - })), - setHumidity: (value: any) => - set((state: any) => ({ - drieUIValue: { ...state.drieUIValue, humidity: value }, - })), + setTouch: (value: any) => + set((state: any) => ({ + drieUIValue: { ...state.drieUIValue, touch: value }, + })), + setTemperature: (value: any) => + set((state: any) => ({ + drieUIValue: { ...state.drieUIValue, temperature: value }, + })), + setHumidity: (value: any) => + set((state: any) => ({ + drieUIValue: { ...state.drieUIValue, humidity: value }, + })), })); export const useStartSimulation = create((set: any) => ({ - startSimulation: false, - setStartSimulation: (x: any) => set({ startSimulation: x }), + startSimulation: false, + setStartSimulation: (x: any) => set({ startSimulation: x }), })); export const useEyeDropMode = create((set: any) => ({ - eyeDropMode: false, - setEyeDropMode: (x: any) => set({ eyeDropMode: x }), + eyeDropMode: false, + setEyeDropMode: (x: any) => set({ eyeDropMode: x }), })); export const useEditingPoint = create((set: any) => ({ - editingPoint: false, - setEditingPoint: (x: any) => set({ editingPoint: x }), + editingPoint: false, + setEditingPoint: (x: any) => set({ editingPoint: x }), })); export const usezoneTarget = create((set: any) => ({ - zoneTarget: [], - setZoneTarget: (x: any) => set({ zoneTarget: x }), + zoneTarget: [], + setZoneTarget: (x: any) => set({ zoneTarget: x }), })); export const usezonePosition = create((set: any) => ({ - zonePosition: [], - setZonePosition: (x: any) => set({ zonePosition: x }), + zonePosition: [], + setZonePosition: (x: any) => set({ zonePosition: x }), })); interface EditPositionState { - Edit: boolean; - setEdit: (value: boolean) => void; + Edit: boolean; + setEdit: (value: boolean) => void; } export const useEditPosition = create((set) => ({ - Edit: false, - setEdit: (value) => set({ Edit: value }), + Edit: false, + setEdit: (value) => set({ Edit: value }), })); export const useAsset3dWidget = create((set: any) => ({ - widgetSelect: "", - setWidgetSelect: (x: any) => set({ widgetSelect: x }), + widgetSelect: "", + setWidgetSelect: (x: any) => set({ widgetSelect: x }), })); export const useWidgetSubOption = create((set: any) => ({ - widgetSubOption: "2D", - setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), + widgetSubOption: "2D", + setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), })); export const useLimitDistance = create((set: any) => ({ - limitDistance: true, - setLimitDistance: (x: any) => set({ limitDistance: x }), + limitDistance: true, + setLimitDistance: (x: any) => set({ limitDistance: x }), })); export const useTileDistance = create((set: any) => ({ - gridValue: { size: 300, divisions: 75 }, - planeValue: { height: 300, width: 300 }, + gridValue: { size: 300, divisions: 75 }, + planeValue: { height: 300, width: 300 }, - setGridValue: (value: any) => - set((state: any) => ({ - gridValue: { ...state.gridValue, ...value }, - })), + setGridValue: (value: any) => + set((state: any) => ({ + gridValue: { ...state.gridValue, ...value }, + })), - setPlaneValue: (value: any) => - set((state: any) => ({ - planeValue: { ...state.planeValue, ...value }, - })), + setPlaneValue: (value: any) => + set((state: any) => ({ + planeValue: { ...state.planeValue, ...value }, + })), })); export const usePlayAgv = create((set, get) => ({ - PlayAgv: [], - setPlayAgv: (updateFn: (prev: any[]) => any[]) => - set({ PlayAgv: updateFn(get().PlayAgv) }), + PlayAgv: [], + setPlayAgv: (updateFn: (prev: any[]) => any[]) => + set({ PlayAgv: updateFn(get().PlayAgv) }), })); // Define the Asset type type Asset = { - id: string; - name: string; - position?: [number, number, number]; // Optional: 3D position - rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation + id: string; + name: string; + position?: [number, number, number]; // Optional: 3D position + rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation }; // Zustand store type type ZoneAssetState = { - zoneAssetId: Asset | null; - setZoneAssetId: (asset: Asset | null) => void; + zoneAssetId: Asset | null; + setZoneAssetId: (asset: Asset | null) => void; }; // Zustand store export const useZoneAssetId = create((set) => ({ - zoneAssetId: null, - setZoneAssetId: (asset) => set({ zoneAssetId: asset }), + zoneAssetId: null, + setZoneAssetId: (asset) => set({ zoneAssetId: asset }), })); - export const useMachineCount = create((set: any) => ({ - machineCount: 0, - setMachineCount: (x: any) => set({ activeLayer: x }), + machineCount: 0, + setMachineCount: (x: any) => set({ machineCount: x }), })); export const useMachineUptime = create((set: any) => ({ - machineActiveTime: 0, - setMachineActiveTime: (x: any) => set({ activeLayer: x }), + machineActiveTime: 0, + setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), })); export const useMaterialCycle = create((set: any) => ({ - materialCycleTime: 0, - setMaterialCycleTime: (x: any) => set({ activeLayer: x }), -})); \ No newline at end of file + materialCycleTime: 0, + setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), +})); From d0eaf3031d968ecbb30c7b4463dc1734d7110078 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 14 May 2025 09:57:31 +0530 Subject: [PATCH 04/14] analysis data --- .../layout/sidebarRight/analysis/Analysis.tsx | 15 +- .../analysis/RenderAnalysisInputs.tsx | 11 +- .../ui/analysis/ProductionCapacity.tsx | 3 - .../ui/analysis/ThroughputSummary.tsx | 36 ++- .../ui/inputs/InputWithDropDown.tsx | 3 +- .../simulation/analysis/ROI/roiData.tsx | 84 ++++++ .../productionCapacityData.tsx | 48 ++++ .../analysis/simulationAnalysis.tsx | 19 +- .../analysis/throughPut/throughPut.tsx | 239 ---------------- .../analysis/throughPut/throughPutData.tsx | 208 ++++++++++++++ .../armInstance/roboticArmInstance.tsx | 269 ++++-------------- .../simulation/simulator/simulator.tsx | 13 +- app/src/store/store.ts | 32 ++- 13 files changed, 497 insertions(+), 483 deletions(-) create mode 100644 app/src/modules/simulation/analysis/ROI/roiData.tsx create mode 100644 app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx delete mode 100644 app/src/modules/simulation/analysis/throughPut/throughPut.tsx create mode 100644 app/src/modules/simulation/analysis/throughPut/throughPutData.tsx diff --git a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx index 9b16186..cc0c597 100644 --- a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx +++ b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx @@ -3,6 +3,7 @@ import { AIIcon } from "../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../ui/inputs/RegularDropDown"; import { AnalysisPresetsType } from "../../../../types/analysis"; import RenderAnalysisInputs from "./RenderAnalysisInputs"; +import { useInputValues } from "../../../../store/store"; const Analysis: React.FC = () => { const [selectedOption, setSelectedOption] = useState("Throughput time"); @@ -48,6 +49,10 @@ const Analysis: React.FC = () => { type: "default", inputs: { label: "Fixed costs", activeOption: "INR" }, }, + { + type: "default", + inputs: { label: "Initial Investment", activeOption: "INR" }, + }, { type: "default", inputs: { label: "Salvage value", activeOption: "Hrs" }, @@ -63,6 +68,8 @@ const Analysis: React.FC = () => { ], }; + const { inputValues, setInputValues, updateInputValue } = useInputValues(); + return (
@@ -88,10 +95,14 @@ const Analysis: React.FC = () => { presets={ AnalysisPresets[selectedOption as keyof AnalysisPresetsType] } + inputValues={inputValues} + onInputChange={(label, value) => { + updateInputValue(label, value); + }} />
- - + setInputValues({})} /> + setInputValues(inputValues)} />
Create Custom Analysis
diff --git a/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx b/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx index e14b542..0204582 100644 --- a/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx +++ b/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx @@ -6,12 +6,11 @@ import { AnalysisPresetsType } from "../../../../types/analysis"; interface InputRendererProps { keyName: string; presets: AnalysisPresetsType[keyof AnalysisPresetsType]; + inputValues: Record; // <-- Add this line + onInputChange: (label: string, value: string) => void; } -const RenderAnalysisInputs: React.FC = ({ - keyName, - presets, -}) => { +const RenderAnalysisInputs: React.FC = ({ keyName, presets,inputValues, onInputChange }) => { return (
{presets.map((preset, index) => { @@ -20,9 +19,9 @@ const RenderAnalysisInputs: React.FC = ({ {}} + onChange={(newValue) => onInputChange(preset.inputs.label, newValue)} /> ); } diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx index 94ab1eb..e9242f6 100644 --- a/app/src/components/ui/analysis/ProductionCapacity.tsx +++ b/app/src/components/ui/analysis/ProductionCapacity.tsx @@ -21,9 +21,6 @@ const ThroughputSummary:React.FC = () => { }; const { machineActiveTime } = useMachineUptime(); - - - const energyConsumption = { energyConsumed: 456, unit: "KWH", diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index 1dfe184..a287a11 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { useMachineCount, useMachineUptime, useMaterialCycle } from "../../../store/store"; +import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from "../../../store/store"; import { ThroughputSummaryIcon, } from "../../icons/analysis"; @@ -13,26 +13,32 @@ const ProductionCapacity = ({ }) => { - const { machineCount } = useMachineCount(); + const { machineActiveTime } = useMachineUptime(); const { materialCycleTime } = useMaterialCycle(); - + const { throughputData } = useThroughPutData() + + const progressPercent = machineActiveTime; - - + + const totalBars = 6; const barsToFill = Math.floor((progressPercent / 100) * totalBars); const partialFillPercent = - ((progressPercent / 100) * totalBars - barsToFill) * 100; - + ((progressPercent / 100) * totalBars - barsToFill) * 100; + const [isLoading, setIsLoading] = useState(false); - // const { machineCount, setMachineCount } = useMachineCount() - // const { machineActiveTime, setMachineActiveTime } = useMachineUptime() + useEffect(() => { - setIsLoading(true); - machineUtilization = machineActiveTime - console.log('machineActiveTime: ', machineActiveTime); - }, [machineActiveTime]) + if (throughputData > 0) { + console.log('machineActiveTime: ', machineActiveTime); + console.log('materialCycleTime: ', materialCycleTime); + console.log('throughputData: ', throughputData); + + setIsLoading(true); + } + + }, [throughputData]) return (
@@ -52,7 +58,7 @@ const ProductionCapacity = ({ <>
- {machineActiveTime} Units/hour + {throughputData} Units/hour
{/* Dynamic Progress Bar */} @@ -79,7 +85,7 @@ const ProductionCapacity = ({
Machine Utilization - 1 + {machineActiveTime} {/* {machineActiveTime} */}
diff --git a/app/src/components/ui/inputs/InputWithDropDown.tsx b/app/src/components/ui/inputs/InputWithDropDown.tsx index 3d42917..c6316d6 100644 --- a/app/src/components/ui/inputs/InputWithDropDown.tsx +++ b/app/src/components/ui/inputs/InputWithDropDown.tsx @@ -52,7 +52,8 @@ const InputWithDropDown: React.FC = ({ max={max} step={step} type="number" - defaultValue={value} + // defaultValue={value} + value={value} onChange={(e) => { onChange(e.target.value); }} diff --git a/app/src/modules/simulation/analysis/ROI/roiData.tsx b/app/src/modules/simulation/analysis/ROI/roiData.tsx new file mode 100644 index 0000000..22b524d --- /dev/null +++ b/app/src/modules/simulation/analysis/ROI/roiData.tsx @@ -0,0 +1,84 @@ +import React, { useEffect } from 'react' +import { useInputValues, useProductionCapacityData } from '../../../../store/store'; + +export default function ROIData() { + const { inputValues } = useInputValues(); + const { productionCapacityData } = useProductionCapacityData() + + useEffect(() => { + if (inputValues === undefined) return; + + const electricityCost = parseFloat(inputValues["Electricity cost"]); + const fixedCost = parseFloat(inputValues["Fixed costs"]); + const laborCost = parseFloat(inputValues["Labor Cost"]); + const maintenanceCost = parseFloat(inputValues["Maintenance cost"]); // Remove space typ + const materialCost = parseFloat(inputValues["Material cost"]); + const productionPeriod = parseFloat(inputValues["Production period"]); + const salvageValue = parseFloat(inputValues["Salvage value"]); + const sellingPrice = parseFloat(inputValues["Selling price"]); + const initialInvestment = parseFloat(inputValues["Initial Investment"]); + const shiftLength = parseFloat(inputValues["Shift length"]); + const shiftsPerDay = parseFloat(inputValues["Shifts / day"]); + const workingDaysPerYear = parseFloat(inputValues["Working days / year"]); + + if (!isNaN(electricityCost) && !isNaN(fixedCost) && !isNaN(laborCost) && !isNaN(maintenanceCost) && + !isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) && + !isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) { + + console.log('sellingPrice: ', sellingPrice); + console.log('salvageValue: ', salvageValue); + console.log('productionPeriod: ', productionPeriod); + console.log('materialCost: ', materialCost); + console.log('maintenanceCost: ', maintenanceCost); + console.log('laborCost: ', laborCost); + console.log('fixedCost: ', fixedCost); + console.log('electricityCost: ', electricityCost); + + + // Revenue + const RevenueForYear = productionCapacityData * sellingPrice; + console.log('RevenueForYear: ', RevenueForYear); + + //Costs + let MaterialCost = productionCapacityData * materialCost + console.log('MaterialCost: ', MaterialCost); + let LaborCost = laborCost * shiftLength * shiftsPerDay * workingDaysPerYear; + console.log('LaborCost: ', LaborCost); + let EnergyCost = electricityCost * shiftLength * shiftsPerDay * workingDaysPerYear; + console.log('EnergyCost: ', EnergyCost); + let MaintenceCost = maintenanceCost + fixedCost; + console.log('MaintenceCost: ', MaintenceCost); + + //Total Anuual Cost + let TotalAnnualCost = MaterialCost + LaborCost + EnergyCost + MaintenceCost; + console.log('TotalAnnualCost: ', TotalAnnualCost); + + //Profit for Year + let ProfitforYear = RevenueForYear - TotalAnnualCost; + console.log('ProfitforYear: ', ProfitforYear); + + //Net Profit + let NetProfit = ProfitforYear * productionPeriod; + console.log('NetProfit: ', NetProfit); + + + //Final ROI + const ROIData = ((NetProfit + salvageValue - initialInvestment) / TotalAnnualCost) * 100; + console.log('ROIData: ', ROIData); + + + // Payback Period + const paybackPeriod = initialInvestment / ProfitforYear; + console.log('paybackPeriod: ', paybackPeriod); + + + } + + }, [inputValues, productionCapacityData]); + + return ( + <> + ) +} + + diff --git a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx new file mode 100644 index 0000000..b9739d3 --- /dev/null +++ b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx @@ -0,0 +1,48 @@ +import React, { useEffect } from 'react' +import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/store' + +export default function ProductionCapacityData() { + const { throughputData } = useThroughPutData() + const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData() + const { inputValues } = useInputValues(); + + useEffect(() => { + if (inputValues === undefined || throughputData === undefined) return; + + const shiftLength = parseFloat(inputValues["Shift length"]); + // console.log('shiftLength: ', shiftLength); + const shiftsPerDay = parseFloat(inputValues["Shifts / day"]); + // console.log('shiftsPerDay: ', shiftsPerDay); + const workingDaysPerYear = parseFloat(inputValues["Working days / year"]); + // console.log('workingDaysPerYear: ', workingDaysPerYear); + const yieldRate = parseFloat(inputValues["Yield rate"]); + // console.log('yieldRate: ', yieldRate); + + + if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && !isNaN(yieldRate) && throughputData > 0) { + //Daily Output + const dailyProduction = throughputData * shiftLength * shiftsPerDay; + console.log("DailyProduction: ", dailyProduction.toFixed(2)); + // Good units (after Yield) + const afterYield = dailyProduction * (yieldRate / 100); + console.log('afterYield: ', afterYield.toFixed(2)); + //Annual Output + const annualProduction = afterYield * workingDaysPerYear; + console.log('annualProduction: ', annualProduction.toFixed(2)); + setProductionCapacityData(annualProduction); + } + }, [throughputData, inputValues]); + + + + useEffect(() => { + + + }, []) + + return ( + <> + ) +} + + diff --git a/app/src/modules/simulation/analysis/simulationAnalysis.tsx b/app/src/modules/simulation/analysis/simulationAnalysis.tsx index 531c103..db5a88b 100644 --- a/app/src/modules/simulation/analysis/simulationAnalysis.tsx +++ b/app/src/modules/simulation/analysis/simulationAnalysis.tsx @@ -1,10 +1,23 @@ -import React from 'react' -import ThroughPut from './throughPut/throughPut' +import React, { useEffect } from 'react' +import { usePlayButtonStore } from '../../../store/usePlayButtonStore' +import ProductionCapacityData from './productionCapacity/productionCapacityData' +import ThroughPutData from './throughPut/throughPutData' +import ROIData from './ROI/roiData' function SimulationAnalysis() { + const { isPlaying } = usePlayButtonStore() + // useEffect(()=>{ + // if (isPlaying) { + // + // } else { + // + // } + // },[isPlaying]) return ( <> - + + + ) } diff --git a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx b/app/src/modules/simulation/analysis/throughPut/throughPut.tsx deleted file mode 100644 index 8a9e331..0000000 --- a/app/src/modules/simulation/analysis/throughPut/throughPut.tsx +++ /dev/null @@ -1,239 +0,0 @@ -// import React, { useEffect, useState } from 'react'; -// import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; -// import { useProductStore } from '../../../../store/simulation/useProductStore'; -// import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; -// import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; -// import { useMachineCount, useMachineUptime, useMaterialCycle } from '../../../../store/store'; -// import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; -// import { useMachineStore } from '../../../../store/simulation/useMachineStore'; -// import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; -// import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'; -// import { useMaterialStore } from '../../../../store/simulation/useMaterialStore'; - -// export default function ThroughPut() { -// const { selectedProduct } = useSelectedProduct(); -// const { products, getProductById } = useProductStore(); -// const { armBots } = useArmBotStore(); -// const { vehicles } = useVehicleStore(); -// const { machines } = useMachineStore(); -// const { conveyors } = useConveyorStore(); -// const { storageUnits } = useStorageUnitStore(); -// const { materials } = useMaterialStore(); - -// const { machineCount, setMachineCount } = useMachineCount(); -// const { setMachineActiveTime } = useMachineUptime(); -// const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle(); - -// const [totalActiveTime, setTotalActiveTime] = useState(0); - -// // 1. Setting static active times and counting machines -// useEffect(() => { -// const productData = getProductById(selectedProduct.productId); -// if (productData) { -// const productSequenceData = determineExecutionMachineSequences([productData]); -// if (productSequenceData?.length > 0) { -// let totalItems = 0; - -// productSequenceData.forEach((sequence) => { -// totalItems += sequence.length; -// sequence.forEach((item) => { -// if (item.type === "roboticArm") { -// armBots.filter(arm => arm.modelUuid === item.modelUuid) -// .forEach(arm => { -// if (arm.activeTime >= 0) { -// -// } -// }); -// } else if (item.type === "vehicle") { -// vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid) -// .forEach(vehicle => { -// if (vehicle.activeTime >= 0) { -// vehicle.activeTime = 10; // static -// } -// }); -// } else if (item.type === "machine") { -// machines.filter(machine => machine.modelUuid === item.modelUuid) -// .forEach(machine => { -// if (machine.activeTime >= 0) { -// machine.activeTime = 12; // static -// } -// }); -// } else if (item.type === "transfer") { -// conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid) -// .forEach(conveyor => { -// if (conveyor.activeTime >= 0) { -// conveyor.activeTime = 5; // static -// } -// }); -// } else if (item.type === "storageUnit") { -// storageUnits.filter(storage => storage.modelUuid === item.modelUuid) -// .forEach(storage => { -// if (storage.activeTime >= 0) { -// storage.activeTime = 8; // static -// } -// }); -// } -// }); -// }); - -// setMachineCount(totalItems); -// } -// } -// }, [products, selectedProduct, armBots, vehicles, machines, conveyors, storageUnits, getProductById, setMachineCount]); - -// // 2. Set material cycle time (static also) -// useEffect(() => { -// materials.forEach((material) => { -// material.startTime = 50; -// material.endTime = 100; -// const totalCycleTime = material.endTime - material.startTime; -// setMaterialCycleTime(totalCycleTime); -// }); -// }, [materials, setMaterialCycleTime]); - -// // 3. Sum of all activeTimes after static values are set -// useEffect(() => { -// let sum = 0; -// armBots.forEach(arm => { if (arm.activeTime > 0) sum += arm.activeTime; }); -// vehicles.forEach(vehicle => { if (vehicle.activeTime > 0) sum += vehicle.activeTime; }); -// machines.forEach(machine => { if (machine.activeTime > 0) sum += machine.activeTime; }); -// conveyors.forEach(conveyor => { if (conveyor.activeTime > 0) sum += conveyor.activeTime; }); -// storageUnits.forEach(storage => { if (storage.activeTime > 0) sum += storage.activeTime; }); - -// setTotalActiveTime(sum); -// setMachineActiveTime(sum); - -// }, [armBots, vehicles, machines, conveyors, storageUnits, setMachineActiveTime]); - -// // 4. Calculate throughput when activeTime and materialCycleTime are ready -// useEffect(() => { -// if (totalActiveTime > 0 && materialCycleTime > 0) { -// const avgProcessTime = (totalActiveTime / materialCycleTime) * 100; -// -// } -// }, [totalActiveTime, materialCycleTime]); - -// return ( -// <> -// -// ); -// } - - -import React, { useEffect, useState } from 'react'; -import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; -import { useProductStore } from '../../../../store/simulation/useProductStore'; -import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; -import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; -import { useMachineCount, useMachineUptime, useMaterialCycle } from '../../../../store/store'; -import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; -import { useMachineStore } from '../../../../store/simulation/useMachineStore'; -import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; -import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'; -import { useMaterialStore } from '../../../../store/simulation/useMaterialStore'; - -export default function ThroughPut() { - const { selectedProduct } = useSelectedProduct(); - const { products, getProductById } = useProductStore(); - const { armBots } = useArmBotStore(); - const { vehicles } = useVehicleStore(); - const { machines } = useMachineStore(); - const { conveyors } = useConveyorStore(); - const { storageUnits } = useStorageUnitStore(); - const { materials } = useMaterialStore(); - - const { setMachineCount } = useMachineCount(); - const { machineActiveTime, setMachineActiveTime } = useMachineUptime(); - console.log('machineActiveTime: ', machineActiveTime); - const { setMaterialCycleTime } = useMaterialCycle(); - - const [totalActiveTime, setTotalActiveTime] = useState(0); - const [throughputData, setThroughputData] = useState(0); // <=== ADD THIS - - // Setting machine count - useEffect(() => { - const productData = getProductById(selectedProduct.productId); - if (productData) { - const productSequenceData = determineExecutionMachineSequences([productData]); - if (productSequenceData?.length > 0) { - let totalItems = 0; - productSequenceData.forEach((sequence) => { - totalItems += sequence.length; - }); - setMachineCount(totalItems); - } - } - }, [products, selectedProduct, getProductById, setMachineCount]); - - // Setting material cycle time - useEffect(() => { - materials.forEach(() => { - const staticStartTime = 50; - const staticEndTime = 100; - const totalCycleTime = staticEndTime - staticStartTime; - setMaterialCycleTime(totalCycleTime); - }); - }, [materials, setMaterialCycleTime]); - - // Calculate Sum, Machine Uptime and Throughput - useEffect(() => { - let sum = 0; - - - armBots.forEach(arm => { - - if (arm.activeTime > 0) sum += arm.activeTime; - }); - - vehicles.forEach(vehicle => { - if (vehicle.activeTime > 0) sum += 10; // static - }); - - machines.forEach(machine => { - if (machine.activeTime > 0) sum += 12; // static - }); - - conveyors.forEach(conveyor => { - if (conveyor.activeTime > 0) sum += 5; // static - }); - - storageUnits.forEach(storage => { - if (storage.activeTime > 0) sum += 8; // static - }); - - - - const avgProcessTime = 100 - 50; // static 50 - - const machineUptime = (sum / avgProcessTime) * 100; - console.log('machineUptime: ', machineUptime); - - - - const machineCount = 3; // static - const throughput = (3600 / avgProcessTime) * machineCount * (machineUptime / 100); // **IMPORTANT divide by 100 for %** - - - - setTotalActiveTime(sum); - setMachineActiveTime(machineUptime) - setMaterialCycleTime(throughput) - // setMachineActiveTime(sum); - setThroughputData(throughput); // Save it properly here - - }, [armBots, vehicles, machines, conveyors, storageUnits, setMachineActiveTime]); - - // Just display throughput when ready - useEffect(() => { - - if (throughputData > 0) { - - } - }, [throughputData]); - - return ( - <> - - ); -} - diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx new file mode 100644 index 0000000..b7d6130 --- /dev/null +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -0,0 +1,208 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import { useProductStore } from '../../../../store/simulation/useProductStore'; +import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; +import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; +import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from '../../../../store/store'; +import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; +import { useMachineStore } from '../../../../store/simulation/useMachineStore'; +import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; +import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'; +import { useMaterialStore } from '../../../../store/simulation/useMaterialStore'; +import { usePauseButtonStore, usePlayButtonStore } from '../../../../store/usePlayButtonStore'; + +export default function ThroughPutData() { + const { selectedProduct } = useSelectedProduct(); + const { products, getProductById } = useProductStore(); + const { armBots, incrementActiveTime, incrementIdleTime } = useArmBotStore(); + const { vehicles } = useVehicleStore(); + const { machines } = useMachineStore(); + const { conveyors } = useConveyorStore(); + const { storageUnits } = useStorageUnitStore(); + const { materials } = useMaterialStore(); + + const { machineCount, setMachineCount } = useMachineCount(); + const { machineActiveTime, setMachineActiveTime } = useMachineUptime(); + + const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle(); + + // const [totalActiveTime, setTotalActiveTime] = useState(0); + const { setThroughputData } = useThroughPutData() // <=== ADD THIS + const { isPlaying } = usePlayButtonStore(); + + // Setting machine count + useEffect(() => { + if (materialCycleTime < 0) return + // console.log('materialCycleTime: ', materialCycleTime); + const fetchProductSequenceData = async () => { + const productData = getProductById(selectedProduct.productId); + if (productData) { + const productSequenceData = await determineExecutionMachineSequences([productData]); + // console.log('productSequenceData: ', productSequenceData); + + if (productSequenceData?.length > 0) { + let totalItems = 0; + let totalActiveTime = 0; + + productSequenceData.forEach((sequence) => { + // console.log('sequence: ', sequence); + + sequence.forEach((item) => { + if (item.type === "roboticArm") { + armBots.filter(arm => arm.modelUuid === item.modelUuid) + .forEach(arm => { + + if (arm.activeTime >= 0) { + totalActiveTime += arm.activeTime; + } + }); + } else if (item.type === "vehicle") { + vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid) + .forEach(vehicle => { + + if (vehicle.activeTime >= 0) { + // totalActiveTime += vehicle.activeTime; + // totalActiveTime += 10; + } + }); + } else if (item.type === "machine") { + machines.filter(machine => machine.modelUuid === item.modelUuid) + .forEach(machine => { + if (machine.activeTime >= 0) { + // totalActiveTime += machine.activeTime; + // totalActiveTime += 12; + } + }); + } else if (item.type === "transfer") { + conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid) + .forEach(conveyor => { + if (conveyor.activeTime >= 0) { + // totalActiveTime += conveyor.activeTime; + // totalActiveTime += 7; + } + }); + } else if (item.type === "storageUnit") { + storageUnits.filter(storage => storage.modelUuid === item.modelUuid) + .forEach(storage => { + if (storage.activeTime >= 0) { + // totalActiveTime += storage.activeTime; + // totalActiveTime += 9; + } + }); + } + }); + + totalItems += sequence.length; + }); + + setMachineCount(totalItems); + setMachineActiveTime(totalActiveTime); + + } + } + }; + + fetchProductSequenceData(); + }, [products, selectedProduct, getProductById, setMachineCount, isPlaying, armBots, materialCycleTime]); + + // Setting material cycle time + useEffect(() => { + materials.map((material) => { + // console.log('material: ', material); + // const totalCycleTime = material.endTime - material.startTime;//dynamic + const staticStartTime = 50; + const staticEndTime = 100; + const totalCycleTime = staticEndTime - staticStartTime; + setMaterialCycleTime(totalCycleTime) + + }) + }, [materials]); + + + useEffect(() => { + if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) { + const avgProcessTime = (machineActiveTime / materialCycleTime) * 100; // % value + const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100); // βœ… division by 100 + setThroughputData(throughput.toFixed(2)); // Set the throughput data in the store + + // console.log('---Throughput Results---'); + // console.log('Total Active Time:', machineActiveTime); + // console.log('Material Cycle Time:', materialCycleTime); + // console.log('Machine Count:', machineCount); + // console.log('Average Process Time (%):', avgProcessTime); + // console.log('Calculated Throughput:', throughput); + } + }, [machineActiveTime, materialCycleTime, machineCount]); + + + + return ( + <> + + ); +} + + + + // useEffect(() => { + // if (!isPlaying) return; + + // const intervalMs = 1000 + + // if (!armBot.isActive && armBot.state == "idle" && (currentPhase == "rest" || currentPhase == "init") && !isIdleRef.current) { + // isIdleRef.current = true + + // // Stop the timer + // // 🚨 1. Clear Active Timer + // if (activeTimerId.current) { + // clearInterval(activeTimerId.current); + // activeTimerId.current = null; + // } + // incrementActiveTime(armBot.modelUuid, activeSecondsElapsed.current) + // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current} seconds`); + + // // 🚨 2. Reset active timer seconds after logging + // // activeSecondsElapsed.current = 0; + + // // 🚨 3. Start Idle Timer (clean old idle timer first) + // if (idleTimerId.current) { + // clearInterval(idleTimerId.current); + // idleTimerId.current = null; + // } + + // idleSecondsElapsed.current = 0; + // idleTimerId.current = setInterval(() => { + // if (!isPausedRef.current) { + // idleSecondsElapsed.current += 1; + // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current} seconds`); + // } + // }, intervalMs); + // } + // if (armBot.isActive && armBot.state != "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) { + // isIdleRef.current = false + + // if (armBot.currentAction) { + // // 🚨 Clear Idle Timer + // if (idleTimerId.current) { + // clearInterval(idleTimerId.current); + // idleTimerId.current = null; + // } + // incrementIdleTime(armBot.modelUuid, idleSecondsElapsed.current) + // console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`); + // idleSecondsElapsed.current = 0; + + // // 🚨 Start Active Timer + // if (activeTimerId.current) { + // clearInterval(activeTimerId.current); + // } + // // activeSecondsElapsed.current = 0; + // activeTimerId.current = setInterval(() => { + // if (!isPausedRef.current) { + // activeSecondsElapsed.current += 1 + // console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current} seconds`); + // } + // }, intervalMs); + // } + // } + + // }, [armBot, currentPhase, isPlaying]) \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index d498783..6de5f1d 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -29,7 +29,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { const isIdleRef = useRef(false); let startTime: number; - const { setArmBotActive, setArmBotState, removeCurrentAction,incrementActiveTime,incrementIdleTime } = useArmBotStore(); + const { armBots, setArmBotActive, setArmBotState, removeCurrentAction, incrementActiveTime, incrementIdleTime } = useArmBotStore(); const { decrementVehicleLoad, removeLastMaterial } = useVehicleStore(); const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = useStorageUnitStore(); const { setIsVisible, getMaterialById } = useMaterialStore(); @@ -42,10 +42,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { const { speed } = useAnimationPlaySpeed(); const activeSecondsElapsed = useRef(0); - const activeTimerId = useRef | null>(null); - const idleSecondsElapsed = useRef(0); - const idleTimerId = useRef | null>(null); + + const animationFrameIdRef = useRef(null); + const previousTimeRef = useRef(null); function firstFrame() { startTime = performance.now(); @@ -168,12 +168,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } useEffect(() => { - isPausedRef.current = isPaused; }, [isPaused]); useEffect(() => { - isSpeedRef.current = speed; }, [speed]); @@ -189,12 +187,13 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { isPausedRef.current = false pauseTimeRef.current = null startTime = 0 - clearInterval(activeTimerId.current!); - clearInterval(idleTimerId.current!); - activeTimerId.current = null; activeSecondsElapsed.current = 0; idleSecondsElapsed.current = 0; - idleTimerId.current = null; + previousTimeRef.current = null; + if (animationFrameIdRef.current !== null) { + cancelAnimationFrame(animationFrameIdRef.current); + animationFrameIdRef.current = null; + } const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone ); if (targetBones && isPlaying) { @@ -207,186 +206,65 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } }, [isReset, isPlaying]) - useEffect(() => { - if (!isPlaying) return; - const intervalMs = 1000 - - if (!armBot.isActive && armBot.state == "idle" && (currentPhase == "rest" || currentPhase == "init") && !isIdleRef.current) { - isIdleRef.current = true - - // Stop the timer - // 🚨 1. Clear Active Timer - if (activeTimerId.current) { - clearInterval(activeTimerId.current); - activeTimerId.current = null; + function animate(currentTime: number) { + if (previousTimeRef.current === null) { + previousTimeRef.current = currentTime; + } + const deltaTime = (currentTime - previousTimeRef.current) / 1000; + previousTimeRef.current = currentTime; + if (armBot.isActive) { + if (!isPausedRef.current) { + activeSecondsElapsed.current += deltaTime * isSpeedRef.current; + // console.log(' activeSecondsElapsed.current: ', activeSecondsElapsed.current); } - incrementActiveTime(armBot.modelUuid, activeSecondsElapsed.current) - // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current} seconds`); - - // 🚨 2. Reset active timer seconds after logging - activeSecondsElapsed.current = 0; - - // 🚨 3. Start Idle Timer (clean old idle timer first) - if (idleTimerId.current) { - clearInterval(idleTimerId.current); - idleTimerId.current = null; - } - - idleSecondsElapsed.current = 0; - idleTimerId.current = setInterval(() => { - if (!isPausedRef.current) { - idleSecondsElapsed.current += 1; - // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current} seconds`); - } - }, intervalMs); - } else if (armBot.isActive && armBot.state != "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) { - isIdleRef.current = false - - if (armBot.currentAction) { - // 🚨 Clear Idle Timer - if (idleTimerId.current) { - clearInterval(idleTimerId.current); - idleTimerId.current = null; - } - incrementIdleTime(armBot.modelUuid, idleSecondsElapsed.current) - // console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`); - idleSecondsElapsed.current = 0; - - // 🚨 Start Active Timer - if (activeTimerId.current) { - clearInterval(activeTimerId.current); - } - activeSecondsElapsed.current = 0; - activeTimerId.current = setInterval(() => { - if (!isPausedRef.current) { - activeSecondsElapsed.current += 1 - // console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current} seconds`); - } - }, intervalMs); + } else { + if (!isPausedRef.current) { + idleSecondsElapsed.current += deltaTime * isSpeedRef.current; + // console.log('idleSecondsElapsed.current: ', idleSecondsElapsed.current); } } + animationFrameIdRef.current = requestAnimationFrame(animate); + } - }, [armBot, currentPhase, isPlaying]) + useEffect(() => { + if (!isPlaying) return + if (!armBot.isActive && armBot.state === "idle" && (currentPhase === "rest" || currentPhase === "init")) { + cancelAnimationFrame(animationFrameIdRef.current!); + animationFrameIdRef.current = null; + const roundedActiveTime = Math.round(activeSecondsElapsed.current); // Get the final rounded active time + console.log('Final Active Time:', roundedActiveTime, 'seconds'); + incrementActiveTime(armBot.modelUuid, roundedActiveTime); + activeSecondsElapsed.current = 0; - // useEffect(() => { - // if (!isPlaying) return; - // const now = () => performance.now(); + } else if (armBot.isActive && armBot.state !== "idle" && currentPhase !== "rest" && armBot.currentAction) { + cancelAnimationFrame(animationFrameIdRef.current!); + animationFrameIdRef.current = null; + const roundedIdleTime = Math.round(idleSecondsElapsed.current); // Get the final rounded idle time + console.log('Final Idle Time:', roundedIdleTime, 'seconds'); + incrementIdleTime(armBot.modelUuid, roundedIdleTime); + idleSecondsElapsed.current = 0; + } + if (animationFrameIdRef.current === null) { + animationFrameIdRef.current = requestAnimationFrame(animate); + } - // const startActiveTimer = () => { - // let lastTime = now(); + return () => { + if (animationFrameIdRef.current !== null) { + cancelAnimationFrame(animationFrameIdRef.current); + animationFrameIdRef.current = null; // Reset the animation frame ID + } + }; - // const update = () => { - // if (!isPausedRef.current) { - // const currentTime = now(); - // const delta = currentTime - lastTime; - // activeSecondsElapsed.current += delta / 1000; - // console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current.toFixed(2)} seconds`); - // lastTime = currentTime; - // } else { + }, [armBot.isActive, armBot.state, currentPhase]) - // lastTime = now(); - // } + useEffect(() => { - // if (!isIdleRef.current) { - // requestAnimationFrame(update); - // } - // }; + console.log('armBots: ', armBots); + }, [armBots]) - // activeSecondsElapsed.current = 0; - // update(); - // }; - - // const startIdleTimer = () => { - // let lastTime = now(); - - // const update = () => { - // if (!isPausedRef.current) { - // const currentTime = now(); - // const delta = currentTime - lastTime; - // idleSecondsElapsed.current += delta / 1000; - // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current.toFixed(2)} seconds`); - // lastTime = currentTime; - // } else { - // lastTime = now(); - // } - - // if (isIdleRef.current) { - // requestAnimationFrame(update); - // } - // }; - - // idleSecondsElapsed.current = 0; - // update(); - // }; - - // // State transition logic - // if (!armBot.isActive && armBot.state === "idle" && (currentPhase === "rest" || currentPhase === "init") && !isIdleRef.current) { - // isIdleRef.current = true; - // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current.toFixed(2)} seconds`); - // startIdleTimer(); - // } - // else if (armBot.isActive && armBot.state !== "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) { - // isIdleRef.current = false; - // console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current.toFixed(2)} seconds`); - // startActiveTimer(); - // } - - // }, [armBot, currentPhase, isPlaying, isIdleRef.current, isPausedRef.current]); - - - - // useEffect(() => { - // if (!isPlaying) return; - - // let frameId: number | null = null; - // let lastTime = performance.now(); - - // const tick = (currentTime: number) => { - // const delta = currentTime - lastTime; - // lastTime = currentTime; - - // const secondsToAdd = delta / 1000; // ⚑️REAL time passed (NO speed multiplication) - - // if (!isPausedRef.current) { - // // Update Timer - // if (isIdleRef.current) { - // idleSecondsElapsed.current += secondsToAdd; - // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current.toFixed(2)} seconds (Speed: ${isSpeedRef.current}x)`); - // } else { - // activeSecondsElapsed.current += secondsToAdd; - // console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current.toFixed(2)} seconds (Speed: ${isSpeedRef.current}x)`); - // } - // } - // frameId = requestAnimationFrame(tick); - // }; - // // Detect mode switch - // if (!armBot.isActive && armBot.state === "idle" && (currentPhase === "rest" || currentPhase === "init") && !isIdleRef.current) { - // isIdleRef.current = true; - - // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current.toFixed(2)} seconds`); - // activeSecondsElapsed.current = 0; - // idleSecondsElapsed.current = 0; - // } else if (armBot.isActive && armBot.state !== "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) { - // isIdleRef.current = false; - // console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current.toFixed(2)} seconds`); - // idleSecondsElapsed.current = 0; - // activeSecondsElapsed.current = 0; - // } - - // frameId = requestAnimationFrame(tick); - - // return () => { - // if (frameId !== null) { - // cancelAnimationFrame(frameId); - // } - // }; - // }, [armBot, currentPhase, isPlaying]); - - - useEffect(() => { const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); if (targetMesh) { @@ -409,7 +287,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } //Waiting for trigger. else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) { - logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction") } //Moving to pickup point @@ -449,12 +326,13 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { pauseTimeRef.current = null isPausedRef.current = false startTime = 0 - clearInterval(activeTimerId.current!); - clearInterval(idleTimerId.current!); - activeTimerId.current = null; activeSecondsElapsed.current = 0; idleSecondsElapsed.current = 0; - idleTimerId.current = null; + previousTimeRef.current = null; + if (animationFrameIdRef.current !== null) { + cancelAnimationFrame(animationFrameIdRef.current); + animationFrameIdRef.current = null; + } removeCurrentAction(armBot.modelUuid) } @@ -492,38 +370,13 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } else if (armBot.isActive && armBot.state == "running" && currentPhase == "end-to-rest") { logStatus(armBot.modelUuid, "Callback triggered: rest, cycle completed."); - // Stop the timer - // 🚨 1. Clear Active Timer - // if (activeTimerId.current) { - // clearInterval(activeTimerId.current); - // activeTimerId.current = null; - // } - // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current} seconds`); - - // // 🚨 2. Reset active timer seconds after logging - // activeSecondsElapsed.current = 0; - - // // 🚨 3. Start Idle Timer (clean old idle timer first) - // if (idleTimerId.current) { - // clearInterval(idleTimerId.current); - // idleTimerId.current = null; - // } - - // idleSecondsElapsed.current = 0; - // idleTimerId.current = setInterval(() => { - // if (!isPausedRef.current) { - // idleSecondsElapsed.current += 1; - // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current} seconds`); - // } - // }, 1000); - - setArmBotActive(armBot.modelUuid, false) setArmBotState(armBot.modelUuid, "idle") setCurrentPhase("rest"); setPath([]) } } + const logStatus = (id: string, status: string) => { // console.log('status: ', status); } diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx index d6ff2fa..aa0b9f6 100644 --- a/app/src/modules/simulation/simulator/simulator.tsx +++ b/app/src/modules/simulation/simulator/simulator.tsx @@ -3,22 +3,27 @@ import { useProductStore } from '../../../store/simulation/useProductStore'; import { useActionHandler } from '../actions/useActionHandler'; import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore'; import { determineExecutionOrder } from './functions/determineExecutionOrder'; +import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; function Simulator() { - const { products } = useProductStore(); + const { products, getProductById } = useProductStore(); const { handleAction } = useActionHandler(); + const { selectedProduct } = useSelectedProduct(); const { isPlaying } = usePlayButtonStore(); const { isReset } = useResetButtonStore(); useEffect(() => { - if (!isPlaying || isReset) return; + if (!isPlaying || isReset || !selectedProduct.productId) return; - const executionOrder = determineExecutionOrder(products); + const product = getProductById(selectedProduct.productId); + if (!product) return; + + const executionOrder = determineExecutionOrder([product]); executionOrder.forEach(point => { const action = 'actions' in point ? point.actions[0] : point.action; handleAction(action); }); - }, [products, isPlaying, isReset]); + }, [products, isPlaying, isReset, selectedProduct]); return ( diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 226e4e7..6192bdf 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -67,8 +67,8 @@ export const useWalls = create((set: any) => ({ })); export const useRoomsState = create((set: any) => ({ - roomsState: [], - setRoomsState: (x: any) => set(() => ({ walls: x })), + roomsState: [], + setRoomsState: (x: any) => set(() => ({ walls: x })), })); export const useZones = create((set: any) => ({ @@ -448,3 +448,31 @@ export const useMaterialCycle = create((set: any) => ({ materialCycleTime: 0, setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), })); + +export const useThroughPutData = create((set: any) => ({ + throughputData: 0, + setThroughputData: (x: any) => set({ throughputData: x }), +})); +export const useProductionCapacityData = create((set: any) => ({ + productionCapacityData: 0, + setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), +})); + + +type InputValuesStore = { + inputValues: Record; + setInputValues: (values: Record) => void; + updateInputValue: (label: string, value: string) => void; // <- New +}; + +export const useInputValues = create((set) => ({ + inputValues: {}, + setInputValues: (values) => set({ inputValues: values }), + updateInputValue: (label, value) => + set((state) => ({ + inputValues: { + ...state.inputValues, + [label]: value, + }, + })), +})); \ No newline at end of file From 1c31fa5bcb243b6d428e604ec75141631774c118 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 14 May 2025 10:07:19 +0530 Subject: [PATCH 05/14] Add new state management hooks for machine metrics and input values --- app/src/store/builder/store.ts | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 06c7bfc..b4534b5 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -451,4 +451,45 @@ export const useShortcutStore = create((set) => ({ setShowShortcuts: (value) => set({ showShortcuts: value }), toggleShortcuts: () => set((state) => ({ showShortcuts: !state.showShortcuts })), +})); + +export const useMachineCount = create((set: any) => ({ + machineCount: 0, + setMachineCount: (x: any) => set({ machineCount: x }), +})); +export const useMachineUptime = create((set: any) => ({ + machineActiveTime: 0, + setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), +})); +export const useMaterialCycle = create((set: any) => ({ + materialCycleTime: 0, + setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), +})); + +export const useThroughPutData = create((set: any) => ({ + throughputData: 0, + setThroughputData: (x: any) => set({ throughputData: x }), +})); +export const useProductionCapacityData = create((set: any) => ({ + productionCapacityData: 0, + setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), +})); + + +type InputValuesStore = { + inputValues: Record; + setInputValues: (values: Record) => void; + updateInputValue: (label: string, value: string) => void; // <- New +}; + +export const useInputValues = create((set) => ({ + inputValues: {}, + setInputValues: (values) => set({ inputValues: values }), + updateInputValue: (label, value) => + set((state) => ({ + inputValues: { + ...state.inputValues, + [label]: value, + }, + })), })); \ No newline at end of file From 3ccfc549229d2ae6398acfd8e468a82f3afde918 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 14 May 2025 10:08:55 +0530 Subject: [PATCH 06/14] Refactor imports to use the builder store for state management across analysis components --- app/src/components/layout/sidebarRight/analysis/Analysis.tsx | 2 +- app/src/components/ui/analysis/ProductionCapacity.tsx | 2 +- app/src/components/ui/analysis/ThroughputSummary.tsx | 2 +- app/src/modules/simulation/analysis/ROI/roiData.tsx | 2 +- .../analysis/productionCapacity/productionCapacityData.tsx | 2 +- .../modules/simulation/analysis/throughPut/throughPutData.tsx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx index cc0c597..0e88e18 100644 --- a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx +++ b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx @@ -3,7 +3,7 @@ import { AIIcon } from "../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../ui/inputs/RegularDropDown"; import { AnalysisPresetsType } from "../../../../types/analysis"; import RenderAnalysisInputs from "./RenderAnalysisInputs"; -import { useInputValues } from "../../../../store/store"; +import { useInputValues } from "../../../../store/builder/store"; const Analysis: React.FC = () => { const [selectedOption, setSelectedOption] = useState("Throughput time"); diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx index e9242f6..ab64229 100644 --- a/app/src/components/ui/analysis/ProductionCapacity.tsx +++ b/app/src/components/ui/analysis/ProductionCapacity.tsx @@ -9,7 +9,7 @@ import { } from "chart.js"; import { PowerIcon, ProductionCapacityIcon } from "../../icons/analysis"; import SkeletonUI from "../../templates/SkeletonUI"; -import { useMachineUptime } from "../../../store/store"; +import { useMachineUptime } from "../../../store/builder/store"; ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index a287a11..3665837 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from "../../../store/store"; +import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from "../../../store/builder/store"; import { ThroughputSummaryIcon, } from "../../icons/analysis"; diff --git a/app/src/modules/simulation/analysis/ROI/roiData.tsx b/app/src/modules/simulation/analysis/ROI/roiData.tsx index 22b524d..f23ceb5 100644 --- a/app/src/modules/simulation/analysis/ROI/roiData.tsx +++ b/app/src/modules/simulation/analysis/ROI/roiData.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react' -import { useInputValues, useProductionCapacityData } from '../../../../store/store'; +import { useInputValues, useProductionCapacityData } from '../../../../store/builder/store'; export default function ROIData() { const { inputValues } = useInputValues(); diff --git a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx index b9739d3..b860bb1 100644 --- a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx +++ b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react' -import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/store' +import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store' export default function ProductionCapacityData() { const { throughputData } = useThroughPutData() diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx index b7d6130..8d7d676 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -3,7 +3,7 @@ import { useSelectedProduct } from '../../../../store/simulation/useSimulationSt import { useProductStore } from '../../../../store/simulation/useProductStore'; import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; -import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from '../../../../store/store'; +import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from '../../../../store/builder/store'; import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; import { useMachineStore } from '../../../../store/simulation/useMachineStore'; import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; From 4e0240929d0b10ca5d1ceb5888c84b5f35365def Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Wed, 14 May 2025 10:16:30 +0530 Subject: [PATCH 07/14] added active time with play,pause,reset and based on speed for vehicle --- .../instances/instance/vehicleInstance.tsx | 95 ++++++++++++++++--- app/src/store/simulation/useVehicleStore.ts | 11 +++ .../components/marketPlace/marketPlace.scss | 1 + 3 files changed, 94 insertions(+), 13 deletions(-) diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index d054a10..4e9a298 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -11,10 +11,7 @@ import { useProductStore } from '../../../../../store/simulation/useProductStore import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import MaterialAnimator from '../animator/materialAnimator'; -type Timer = { - start: number | null; - active: boolean; -}; + function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) { const { navMesh } = useNavMesh(); const { isPlaying } = usePlayButtonStore(); @@ -23,20 +20,33 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) const { triggerPointActions } = useTriggerHandler(); const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial } = useVehicleStore(); + const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState('stationed'); const [path, setPath] = useState<[number, number, number][]>([]); const pauseTimeRef = useRef(null); + const idleTimeRef = useRef(0); + const activeTimeRef = useRef(0); const isPausedRef = useRef(false); + const isSpeedRef = useRef(0); let startTime: number; let fixedInterval: number; const { speed } = useAnimationPlaySpeed(); const { isPaused } = usePauseButtonStore(); + const previousTimeRef = useRef(null); // Tracks the last frame time + const isActiveRef = useRef(agvDetail.isActive); // Tracks the previous isActive state + const animationFrameIdRef = useRef(null); // Tracks the animation frame ID + + useEffect(() => { isPausedRef.current = isPaused; }, [isPaused]); + useEffect(() => { + isSpeedRef.current = speed; + }, [speed]); + const computePath = useCallback( (start: any, end: any) => { try { @@ -54,7 +64,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) ); function vehicleStatus(modelId: string, status: string) { - // + // console.log(`${modelId} , ${status}`); } // Function to reset everything @@ -68,6 +78,14 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) startTime = 0; isPausedRef.current = false; pauseTimeRef.current = 0; + resetTime(agvDetail.modelUuid) + activeTimeRef.current = 0 + idleTimeRef.current = 0 + previousTimeRef.current = null + if (animationFrameIdRef.current !== null) { + cancelAnimationFrame(animationFrameIdRef.current) + animationFrameIdRef.current = null + } } useEffect(() => { @@ -115,12 +133,60 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point'); } } - } else { + } + else { reset() } // eslint-disable-next-line react-hooks/exhaustive-deps }, [vehicles, currentPhase, path, isPlaying]); + + function animate(currentTime: number) { + if (previousTimeRef.current === null) { + previousTimeRef.current = currentTime; + } + + const deltaTime = (currentTime - previousTimeRef.current) / 1000; + previousTimeRef.current = currentTime; + + if (agvDetail.isActive) { + if (!isPausedRef.current) { + activeTimeRef.current += deltaTime * isSpeedRef.current; + } + } else { + if (!isPausedRef.current) { + idleTimeRef.current += deltaTime * isSpeedRef.current; // Scale idle time by speed + } + } + animationFrameIdRef.current = requestAnimationFrame(animate); + } + + useEffect(() => { + if (!isPlaying) return + if (!agvDetail.isActive) { + const roundedActiveTime = Math.round(activeTimeRef.current); + // console.log('Final Active Time:', roundedActiveTime, 'seconds'); + incrementActiveTime(agvDetail.modelUuid, roundedActiveTime); + activeTimeRef.current = 0; + } else { + const roundedIdleTime = Math.round(idleTimeRef.current); + // console.log('Final Idle Time:', roundedIdleTime, 'seconds'); + incrementIdleTime(agvDetail.modelUuid, roundedIdleTime); + idleTimeRef.current = 0; + } + + if (animationFrameIdRef.current === null) { + animationFrameIdRef.current = requestAnimationFrame(animate); + } + + return () => { + if (animationFrameIdRef.current !== null) { + cancelAnimationFrame(animationFrameIdRef.current); + animationFrameIdRef.current = null; + } + }; + }, [agvDetail]); + function handleCallBack() { if (currentPhase === 'stationed-pickup') { setCurrentPhase('picking'); @@ -147,9 +213,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) } } - - - function startUnloadingProcess() { if (agvDetail.point.action.triggers.length > 0) { const trigger = getTriggerByUuid(selectedProduct.productId, agvDetail.point.action.triggers[0].triggerUuid); @@ -213,7 +276,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) action: VehicleAction ) { startTime = performance.now(); - const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / speed)); + const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / isSpeedRef.current)); const unloadLoop = () => { if (isPausedRef.current) { @@ -295,7 +358,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) const elapsedTime = performance.now() - startTime; const unLoadDuration = agvDetail.point.action.unLoadDuration; - fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / speed)); + fixedInterval = ((unLoadDuration / agvDetail.currentLoad) * (1000 / isSpeedRef.current)); if (elapsedTime >= fixedInterval) { let droppedMat = droppedMaterial - 1; @@ -331,4 +394,10 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) ); } -export default VehicleInstance; \ No newline at end of file +export default VehicleInstance; + + + + + + diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts index e69c233..13b4b0a 100644 --- a/app/src/store/simulation/useVehicleStore.ts +++ b/app/src/store/simulation/useVehicleStore.ts @@ -28,6 +28,7 @@ interface VehiclesStore { clearCurrentMaterials: (modelUuid: string) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void; incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + resetTime: (modelUuid: string) => void; getVehicleById: (modelUuid: string) => VehicleStatus | undefined; getVehiclesByProduct: (productId: string) => VehicleStatus[]; @@ -206,6 +207,16 @@ export const useVehicleStore = create()( }); }, + resetTime: (modelUuid) => { + set((state) => { + const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); + if (vehicle) { + vehicle.activeTime = 0; + vehicle.idleTime = 0; + } + }); + }, + getVehicleById: (modelUuid) => { return get().vehicles.find((v) => v.modelUuid === modelUuid); }, diff --git a/app/src/styles/components/marketPlace/marketPlace.scss b/app/src/styles/components/marketPlace/marketPlace.scss index b4237f2..fa667a4 100644 --- a/app/src/styles/components/marketPlace/marketPlace.scss +++ b/app/src/styles/components/marketPlace/marketPlace.scss @@ -312,6 +312,7 @@ width: 100%; height: 100%; background: var(--background-color); + backdrop-filter: blur(16px); display: flex; gap: 12px; overflow: hidden; From e4be4505a9e51b005618dc3bd16fb4d0f5dc8344 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 14 May 2025 14:25:54 +0530 Subject: [PATCH 08/14] Enhance analysis components with new state management for production capacity and ROI data --- .../ui/analysis/ProductionCapacity.tsx | 20 ++- app/src/components/ui/analysis/ROISummary.tsx | 47 ++++--- .../ui/analysis/ThroughputSummary.tsx | 39 +++--- .../simulation/analysis/ROI/roiData.tsx | 16 ++- .../productionCapacityData.tsx | 2 +- .../analysis/throughPut/throughPutData.tsx | 115 ++++-------------- .../armInstance/roboticArmInstance.tsx | 8 +- app/src/store/builder/store.ts | 26 ++++ 8 files changed, 131 insertions(+), 142 deletions(-) diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx index ab64229..3e6fe03 100644 --- a/app/src/components/ui/analysis/ProductionCapacity.tsx +++ b/app/src/components/ui/analysis/ProductionCapacity.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import { Line } from "react-chartjs-2"; import { Chart as ChartJS, @@ -9,11 +9,11 @@ import { } from "chart.js"; import { PowerIcon, ProductionCapacityIcon } from "../../icons/analysis"; import SkeletonUI from "../../templates/SkeletonUI"; -import { useMachineUptime } from "../../../store/builder/store"; +import { useMachineUptime, useProductionCapacityData } from "../../../store/builder/store"; ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); -const ThroughputSummary:React.FC = () => { +const ThroughputSummary: React.FC = () => { // Define all data internally within the component const timeRange = { startTime: "08:00 AM", @@ -33,6 +33,7 @@ const ThroughputSummary:React.FC = () => { { shift: 3, percentage: 30, color: "#7981F5" }, ]; + const { productionCapacityData } = useProductionCapacityData() const chartOptions = { @@ -85,7 +86,16 @@ const ThroughputSummary:React.FC = () => { }, ], }; - const isLoading = false; + + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + if (productionCapacityData >= 0) { + setIsLoading(true); + console.log('productionCapacityData: ', productionCapacityData); + } + + }, [productionCapacityData]) return (
@@ -106,7 +116,7 @@ const ThroughputSummary:React.FC = () => { <>
- {throughputData.totalThroughput}{" "} + {productionCapacityData}{" "} Units/hour
diff --git a/app/src/components/ui/analysis/ROISummary.tsx b/app/src/components/ui/analysis/ROISummary.tsx index e0edb74..da9d496 100644 --- a/app/src/components/ui/analysis/ROISummary.tsx +++ b/app/src/components/ui/analysis/ROISummary.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { CostBreakDownIcon, LightBulpIcon, @@ -9,6 +9,8 @@ import { import SemiCircleProgress from "./SemiCircleProgress"; import { ArrowIcon } from "../../icons/ExportCommonIcons"; import SkeletonUI from "../../templates/SkeletonUI"; +import { useROISummaryData } from "../../../store/builder/store"; +import { set } from "immer/dist/internal"; const ROISummary = ({ roiSummaryData = { @@ -79,8 +81,21 @@ const ROISummary = ({ const year = now.getFullYear(); return `${day} ${month}, ${year}`; } + const [isLoading, setIsLoading] = useState(false); + const { roiSummary } = useROISummaryData(); + + useEffect(() => { + if (roiSummary && typeof roiSummary === 'object') { + + console.log('roiSummary: ', roiSummary); + setIsLoading(true) + } + + }, [roiSummary]) + + + - const isLoading = false; return (
@@ -104,8 +119,8 @@ const ROISummary = ({
- +{roiSummaryData.roiPercentage}% ROI with payback - in just {roiSummaryData.paybackPeriod} months + +{roiSummary.roiPercentage}% ROI with payback + in just {roiSummary.paybackPeriod} months
@@ -122,7 +137,7 @@ const ROISummary = ({ Total Cost Incurred β‚Ή - {roiSummaryData.totalCost} + {roiSummary.totalCost}
@@ -130,14 +145,13 @@ const ROISummary = ({ β‚Ή - {roiSummaryData.revenueGenerated} + {roiSummary.revenueGenerated}
↑ @@ -145,9 +159,9 @@ const ROISummary = ({
β‚Ή - {roiSummaryData.netProfit - ? roiSummaryData.netProfit - : roiSummaryData.netLoss} + {roiSummary.netProfit + ? roiSummary.netProfit + : roiSummary.netLoss}
@@ -164,9 +178,8 @@ const ROISummary = ({
{row.item} diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index 3665837..e87027b 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from "../../../store/builder/store"; +import { useMachineCount, useMachineUptime, useMaterialCycle, useProductionCapacityData, useThroughPutData } from "../../../store/builder/store"; import { ThroughputSummaryIcon, } from "../../icons/analysis"; @@ -17,23 +17,25 @@ const ProductionCapacity = ({ const { machineActiveTime } = useMachineUptime(); const { materialCycleTime } = useMaterialCycle(); const { throughputData } = useThroughPutData() - - - const progressPercent = machineActiveTime; - - - const totalBars = 6; - const barsToFill = Math.floor((progressPercent / 100) * totalBars); - const partialFillPercent = - ((progressPercent / 100) * totalBars - barsToFill) * 100; - - const [isLoading, setIsLoading] = useState(false); - - useEffect(() => { - if (throughputData > 0) { - console.log('machineActiveTime: ', machineActiveTime); - console.log('materialCycleTime: ', materialCycleTime); - console.log('throughputData: ', throughputData); + const { productionCapacityData } = useProductionCapacityData() + + const progressPercent = machineActiveTime; + + + const totalBars = 6; + const barsToFill = Math.floor((progressPercent / 100) * totalBars); + const partialFillPercent = + ((progressPercent / 100) * totalBars - barsToFill) * 100; + + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + if (throughputData >= 0) { + console.log('machineActiveTime: ', machineActiveTime); + console.log('materialCycleTime: ', materialCycleTime); + console.log('throughputData: ', throughputData); + console.log('productionCapacityData: ', productionCapacityData); + setIsLoading(true); } @@ -59,6 +61,7 @@ const ProductionCapacity = ({
{throughputData} Units/hour +
{/* Dynamic Progress Bar */} diff --git a/app/src/modules/simulation/analysis/ROI/roiData.tsx b/app/src/modules/simulation/analysis/ROI/roiData.tsx index f23ceb5..e2d854c 100644 --- a/app/src/modules/simulation/analysis/ROI/roiData.tsx +++ b/app/src/modules/simulation/analysis/ROI/roiData.tsx @@ -1,10 +1,12 @@ -import React, { useEffect } from 'react' -import { useInputValues, useProductionCapacityData } from '../../../../store/builder/store'; +import React, { useEffect, useState } from 'react' +import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store'; export default function ROIData() { const { inputValues } = useInputValues(); const { productionCapacityData } = useProductionCapacityData() + + const { setRoiSummaryData } = useROISummaryData(); useEffect(() => { if (inputValues === undefined) return; @@ -53,6 +55,7 @@ export default function ROIData() { let TotalAnnualCost = MaterialCost + LaborCost + EnergyCost + MaintenceCost; console.log('TotalAnnualCost: ', TotalAnnualCost); + //Profit for Year let ProfitforYear = RevenueForYear - TotalAnnualCost; console.log('ProfitforYear: ', ProfitforYear); @@ -70,7 +73,16 @@ export default function ROIData() { // Payback Period const paybackPeriod = initialInvestment / ProfitforYear; console.log('paybackPeriod: ', paybackPeriod); + + setRoiSummaryData({ + roiPercentage: ROIData, + paybackPeriod, + totalCost: TotalAnnualCost, + revenueGenerated: RevenueForYear, + netProfit: NetProfit > 0 ? NetProfit : 0, + netLoss: NetProfit < 0 ? -NetProfit : 0 + }); } diff --git a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx index b860bb1..77e68ff 100644 --- a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx +++ b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx @@ -19,7 +19,7 @@ export default function ProductionCapacityData() { // console.log('yieldRate: ', yieldRate); - if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && !isNaN(yieldRate) && throughputData > 0) { + if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && !isNaN(yieldRate) && throughputData >= 0) { //Daily Output const dailyProduction = throughputData * shiftLength * shiftsPerDay; console.log("DailyProduction: ", dailyProduction.toFixed(2)); diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx index 8d7d676..899dca9 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -19,7 +19,7 @@ export default function ThroughPutData() { const { machines } = useMachineStore(); const { conveyors } = useConveyorStore(); const { storageUnits } = useStorageUnitStore(); - const { materials } = useMaterialStore(); + const { materialHistory } = useMaterialStore(); const { machineCount, setMachineCount } = useMachineCount(); const { machineActiveTime, setMachineActiveTime } = useMachineUptime(); @@ -33,20 +33,14 @@ export default function ThroughPutData() { // Setting machine count useEffect(() => { if (materialCycleTime < 0) return - // console.log('materialCycleTime: ', materialCycleTime); const fetchProductSequenceData = async () => { const productData = getProductById(selectedProduct.productId); if (productData) { - const productSequenceData = await determineExecutionMachineSequences([productData]); - // console.log('productSequenceData: ', productSequenceData); - + const productSequenceData = await determineExecutionMachineSequences([productData]) if (productSequenceData?.length > 0) { let totalItems = 0; let totalActiveTime = 0; - productSequenceData.forEach((sequence) => { - // console.log('sequence: ', sequence); - sequence.forEach((item) => { if (item.type === "roboticArm") { armBots.filter(arm => arm.modelUuid === item.modelUuid) @@ -62,7 +56,7 @@ export default function ThroughPutData() { if (vehicle.activeTime >= 0) { // totalActiveTime += vehicle.activeTime; - // totalActiveTime += 10; + totalActiveTime += 34; } }); } else if (item.type === "machine") { @@ -70,7 +64,7 @@ export default function ThroughPutData() { .forEach(machine => { if (machine.activeTime >= 0) { // totalActiveTime += machine.activeTime; - // totalActiveTime += 12; + totalActiveTime += 12; } }); } else if (item.type === "transfer") { @@ -78,7 +72,7 @@ export default function ThroughPutData() { .forEach(conveyor => { if (conveyor.activeTime >= 0) { // totalActiveTime += conveyor.activeTime; - // totalActiveTime += 7; + totalActiveTime += 89; } }); } else if (item.type === "storageUnit") { @@ -86,12 +80,11 @@ export default function ThroughPutData() { .forEach(storage => { if (storage.activeTime >= 0) { // totalActiveTime += storage.activeTime; - // totalActiveTime += 9; + totalActiveTime += 45; } }); } }); - totalItems += sequence.length; }); @@ -107,16 +100,17 @@ export default function ThroughPutData() { // Setting material cycle time useEffect(() => { - materials.map((material) => { - // console.log('material: ', material); - // const totalCycleTime = material.endTime - material.startTime;//dynamic - const staticStartTime = 50; - const staticEndTime = 100; - const totalCycleTime = staticEndTime - staticStartTime; - setMaterialCycleTime(totalCycleTime) + materialHistory.forEach((material) => { + const start = material.material.startTime ?? 0; + const end = material.material.endTime ?? 0; + + if (start === 0 || end === 0) return; + + const totalCycleTime = end - start; + setMaterialCycleTime(totalCycleTime.toFixed(2)); // Set the material cycle time in the store + }); + }, [materialHistory]); - }) - }, [materials]); useEffect(() => { @@ -125,12 +119,12 @@ export default function ThroughPutData() { const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100); // βœ… division by 100 setThroughputData(throughput.toFixed(2)); // Set the throughput data in the store - // console.log('---Throughput Results---'); - // console.log('Total Active Time:', machineActiveTime); - // console.log('Material Cycle Time:', materialCycleTime); - // console.log('Machine Count:', machineCount); - // console.log('Average Process Time (%):', avgProcessTime); - // console.log('Calculated Throughput:', throughput); + console.log('---Throughput Results---'); + console.log('Total Active Time:', machineActiveTime); + console.log('Material Cycle Time:', materialCycleTime); + console.log('Machine Count:', machineCount); + console.log('Average Process Time (%):', avgProcessTime); + console.log('Calculated Throughput:', throughput); } }, [machineActiveTime, materialCycleTime, machineCount]); @@ -141,68 +135,3 @@ export default function ThroughPutData() { ); } - - - - // useEffect(() => { - // if (!isPlaying) return; - - // const intervalMs = 1000 - - // if (!armBot.isActive && armBot.state == "idle" && (currentPhase == "rest" || currentPhase == "init") && !isIdleRef.current) { - // isIdleRef.current = true - - // // Stop the timer - // // 🚨 1. Clear Active Timer - // if (activeTimerId.current) { - // clearInterval(activeTimerId.current); - // activeTimerId.current = null; - // } - // incrementActiveTime(armBot.modelUuid, activeSecondsElapsed.current) - // console.log(`βœ… Active Cycle completed in ${activeSecondsElapsed.current} seconds`); - - // // 🚨 2. Reset active timer seconds after logging - // // activeSecondsElapsed.current = 0; - - // // 🚨 3. Start Idle Timer (clean old idle timer first) - // if (idleTimerId.current) { - // clearInterval(idleTimerId.current); - // idleTimerId.current = null; - // } - - // idleSecondsElapsed.current = 0; - // idleTimerId.current = setInterval(() => { - // if (!isPausedRef.current) { - // idleSecondsElapsed.current += 1; - // console.log(`πŸ•’ Idle Timer: ${idleSecondsElapsed.current} seconds`); - // } - // }, intervalMs); - // } - // if (armBot.isActive && armBot.state != "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) { - // isIdleRef.current = false - - // if (armBot.currentAction) { - // // 🚨 Clear Idle Timer - // if (idleTimerId.current) { - // clearInterval(idleTimerId.current); - // idleTimerId.current = null; - // } - // incrementIdleTime(armBot.modelUuid, idleSecondsElapsed.current) - // console.log(`πŸ•’ Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`); - // idleSecondsElapsed.current = 0; - - // // 🚨 Start Active Timer - // if (activeTimerId.current) { - // clearInterval(activeTimerId.current); - // } - // // activeSecondsElapsed.current = 0; - // activeTimerId.current = setInterval(() => { - // if (!isPausedRef.current) { - // activeSecondsElapsed.current += 1 - // console.log(`πŸ•’ Active Timer: ${activeSecondsElapsed.current} seconds`); - // } - // }, intervalMs); - // } - // } - - // }, [armBot, currentPhase, isPlaying]) \ No newline at end of file diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 6de5f1d..4b0829e 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -234,7 +234,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { cancelAnimationFrame(animationFrameIdRef.current!); animationFrameIdRef.current = null; const roundedActiveTime = Math.round(activeSecondsElapsed.current); // Get the final rounded active time - console.log('Final Active Time:', roundedActiveTime, 'seconds'); + // console.log('🚨Final Active Time:',armBot.modelUuid, roundedActiveTime, 'seconds'); incrementActiveTime(armBot.modelUuid, roundedActiveTime); activeSecondsElapsed.current = 0; @@ -242,7 +242,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { cancelAnimationFrame(animationFrameIdRef.current!); animationFrameIdRef.current = null; const roundedIdleTime = Math.round(idleSecondsElapsed.current); // Get the final rounded idle time - console.log('Final Idle Time:', roundedIdleTime, 'seconds'); + // console.log('πŸ•’ Final Idle Time:', armBot.modelUuid,roundedIdleTime, 'seconds'); incrementIdleTime(armBot.modelUuid, roundedIdleTime); idleSecondsElapsed.current = 0; @@ -260,10 +260,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { }, [armBot.isActive, armBot.state, currentPhase]) - useEffect(() => { - - console.log('armBots: ', armBots); - }, [armBots]) useEffect(() => { const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index b4534b5..7c72855 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -492,4 +492,30 @@ export const useInputValues = create((set) => ({ [label]: value, }, })), +})); + +export interface ROISummaryData { + roiPercentage: number; + paybackPeriod: number; + totalCost: number; + revenueGenerated: number; + netProfit: number; + netLoss: number; +} + +interface ROISummaryStore { + roiSummary: ROISummaryData; + setRoiSummaryData: (values: ROISummaryData) => void; +} + +export const useROISummaryData = create((set) => ({ + roiSummary: { + roiPercentage: 0, + paybackPeriod: 0, + totalCost: 0, + revenueGenerated: 0, + netProfit: 0, + netLoss: 0, + }, + setRoiSummaryData: (values) => set({ roiSummary: values }), })); \ No newline at end of file From d88e93395f9a9a73a7f9d2dfe820b33a44873374 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 14 May 2025 18:21:49 +0530 Subject: [PATCH 09/14] Refactor loading state management and enhance data handling in analysis components --- .../ui/analysis/ProductionCapacity.tsx | 9 ++- app/src/components/ui/analysis/ROISummary.tsx | 23 +++--- .../ui/simulation/simulationPlayer.tsx | 80 ++++++++++--------- .../simulation/analysis/ROI/roiData.tsx | 16 +++- .../productionCapacityData.tsx | 14 ++-- .../analysis/throughPut/throughPutData.tsx | 48 +++++++---- app/src/store/builder/store.ts | 11 ++- 7 files changed, 116 insertions(+), 85 deletions(-) diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx index 3e6fe03..fd6150d 100644 --- a/app/src/components/ui/analysis/ProductionCapacity.tsx +++ b/app/src/components/ui/analysis/ProductionCapacity.tsx @@ -91,11 +91,12 @@ const ThroughputSummary: React.FC = () => { useEffect(() => { if (productionCapacityData >= 0) { - setIsLoading(true); - console.log('productionCapacityData: ', productionCapacityData); + setIsLoading(false); + console.log("productionCapacityData: ", productionCapacityData); + } else { + setIsLoading(true); } - - }, [productionCapacityData]) + }, [productionCapacityData]); return (
diff --git a/app/src/components/ui/analysis/ROISummary.tsx b/app/src/components/ui/analysis/ROISummary.tsx index da9d496..deaf87a 100644 --- a/app/src/components/ui/analysis/ROISummary.tsx +++ b/app/src/components/ui/analysis/ROISummary.tsx @@ -85,16 +85,13 @@ const ROISummary = ({ const { roiSummary } = useROISummaryData(); useEffect(() => { - if (roiSummary && typeof roiSummary === 'object') { - + if (roiSummary && typeof roiSummary === "object") { console.log('roiSummary: ', roiSummary); - setIsLoading(true) + setIsLoading(false); // Data loaded + } else { + setIsLoading(true); // Show skeleton while loading } - - }, [roiSummary]) - - - + }, [roiSummary]); return (
@@ -113,13 +110,13 @@ const ROISummary = ({
Product :
-
{roiSummaryData.productName}
+
{roiSummary.productName}
- +{roiSummary.roiPercentage}% ROI with payback + {roiSummary.roiPercentage}% ROI with payback in just {roiSummary.paybackPeriod} months
@@ -150,8 +147,7 @@ const ROISummary = ({
0 ? "profit" : "loss"}`} >
↑ @@ -159,7 +155,7 @@ const ROISummary = ({
β‚Ή - {roiSummary.netProfit + {roiSummary.netProfit > 0 ? roiSummary.netProfit : roiSummary.netLoss}
@@ -241,6 +237,7 @@ const ROISummary = ({ ) : ( + //
No Data
)}
diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 0a5b2de..2bac8ce 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -1,6 +1,6 @@ import React, { useState, useRef, useEffect } from "react"; import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons"; -import { useActiveTool } from "../../../store/builder/store"; +import { useActiveTool, useProcessBar } from "../../../store/builder/store"; import { useAnimationPlaySpeed, usePauseButtonStore, @@ -109,21 +109,25 @@ const SimulationPlayer: React.FC = () => { const hourlySimulation = 25; const dailyProduction = 75; const monthlyROI = 50; + const { processBar, setProcessBar } = useProcessBar(); + // const process = [ + // { name: "process 1", completed: 0 }, // 0% completed + // { name: "process 2", completed: 20 }, // 20% completed + // { name: "process 3", completed: 40 }, // 40% completed + // { name: "process 4", completed: 60 }, // 60% completed + // { name: "process 5", completed: 80 }, // 80% completed + // { name: "process 6", completed: 100 }, // 100% completed + // { name: "process 7", completed: 0 }, // 0% completed + // { name: "process 8", completed: 50 }, // 50% completed + // { name: "process 9", completed: 90 }, // 90% completed + // { name: "process 10", completed: 30 }, // 30% completed + // ]; - const process = [ - { name: "process 1", completed: 0 }, // 0% completed - { name: "process 2", completed: 20 }, // 20% completed - { name: "process 3", completed: 40 }, // 40% completed - { name: "process 4", completed: 60 }, // 60% completed - { name: "process 5", completed: 80 }, // 80% completed - { name: "process 6", completed: 100 }, // 100% completed - { name: "process 7", completed: 0 }, // 0% completed - { name: "process 8", completed: 50 }, // 50% completed - { name: "process 9", completed: 90 }, // 90% completed - { name: "process 10", completed: 30 }, // 30% completed - ]; + useEffect(() => { + // console.log('processBar: ', processBar); + }, [processBar]) - const intervals = [10, 20, 30, 40, 50, 60]; // in minutes + const intervals = [50, 20, 30, 40, 50, 60]; // in minutes const totalSegments = intervals.length; const progress = 20; // percent (example) @@ -285,11 +289,10 @@ const SimulationPlayer: React.FC = () => {
{index < intervals.length - 1 && (
= ((index + 1) / totalSegments) * 100 - ? "filled" - : "" - }`} + className={`line ${progress >= ((index + 1) / totalSegments) * 100 + ? "filled" + : "" + }`} >
)} @@ -328,9 +331,8 @@ const SimulationPlayer: React.FC = () => {
+ )) + ) : ( +
No process data available
+ )}
diff --git a/app/src/modules/simulation/analysis/ROI/roiData.tsx b/app/src/modules/simulation/analysis/ROI/roiData.tsx index e2d854c..fd77098 100644 --- a/app/src/modules/simulation/analysis/ROI/roiData.tsx +++ b/app/src/modules/simulation/analysis/ROI/roiData.tsx @@ -1,9 +1,11 @@ import React, { useEffect, useState } from 'react' import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store'; +import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; export default function ROIData() { const { inputValues } = useInputValues(); const { productionCapacityData } = useProductionCapacityData() + const { selectedProduct } = useSelectedProduct(); const { setRoiSummaryData } = useROISummaryData(); @@ -42,6 +44,11 @@ export default function ROIData() { console.log('RevenueForYear: ', RevenueForYear); //Costs + + let materialCount = 1200; + + //Material Cost + let MaterialCost = productionCapacityData * materialCost console.log('MaterialCost: ', MaterialCost); let LaborCost = laborCost * shiftLength * shiftsPerDay * workingDaysPerYear; @@ -52,7 +59,7 @@ export default function ROIData() { console.log('MaintenceCost: ', MaintenceCost); //Total Anuual Cost - let TotalAnnualCost = MaterialCost + LaborCost + EnergyCost + MaintenceCost; + let TotalAnnualCost = (MaterialCost * materialCount) + LaborCost + EnergyCost + MaintenceCost; console.log('TotalAnnualCost: ', TotalAnnualCost); @@ -73,11 +80,12 @@ export default function ROIData() { // Payback Period const paybackPeriod = initialInvestment / ProfitforYear; console.log('paybackPeriod: ', paybackPeriod); - + setRoiSummaryData({ - roiPercentage: ROIData, - paybackPeriod, + productName: selectedProduct.productName, + roiPercentage: parseFloat((ROIData / 100).toFixed(2)), + paybackPeriod: parseFloat(paybackPeriod.toFixed(2)), totalCost: TotalAnnualCost, revenueGenerated: RevenueForYear, netProfit: NetProfit > 0 ? NetProfit : 0, diff --git a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx index 77e68ff..a77e221 100644 --- a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx +++ b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx @@ -28,18 +28,14 @@ export default function ProductionCapacityData() { console.log('afterYield: ', afterYield.toFixed(2)); //Annual Output const annualProduction = afterYield * workingDaysPerYear; - console.log('annualProduction: ', annualProduction.toFixed(2)); - setProductionCapacityData(annualProduction); + console.log('annualProduction: ', Number(annualProduction.toFixed(2))); + //Production per Hour + const productionPerHour = throughputData * (yieldRate / 100); + console.log('productionPerHour: ', productionPerHour); + setProductionCapacityData(Number(productionPerHour.toFixed(2))); } }, [throughputData, inputValues]); - - - useEffect(() => { - - - }, []) - return ( <> ) diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx index 899dca9..401d730 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -3,7 +3,7 @@ import { useSelectedProduct } from '../../../../store/simulation/useSimulationSt import { useProductStore } from '../../../../store/simulation/useProductStore'; import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; import { useArmBotStore } from '../../../../store/simulation/useArmBotStore'; -import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from '../../../../store/builder/store'; +import { useMachineCount, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store'; import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'; import { useMachineStore } from '../../../../store/simulation/useMachineStore'; import { useConveyorStore } from '../../../../store/simulation/useConveyorStore'; @@ -25,6 +25,7 @@ export default function ThroughPutData() { const { machineActiveTime, setMachineActiveTime } = useMachineUptime(); const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle(); + const { processBar, setProcessBar } = useProcessBar(); // const [totalActiveTime, setTotalActiveTime] = useState(0); const { setThroughputData } = useThroughPutData() // <=== ADD THIS @@ -32,7 +33,8 @@ export default function ThroughPutData() { // Setting machine count useEffect(() => { - if (materialCycleTime < 0) return + if (materialCycleTime <= 0) return + let process: any = []; const fetchProductSequenceData = async () => { const productData = getProductById(selectedProduct.productId); if (productData) { @@ -42,45 +44,45 @@ export default function ThroughPutData() { let totalActiveTime = 0; productSequenceData.forEach((sequence) => { sequence.forEach((item) => { + if (item.type === "roboticArm") { armBots.filter(arm => arm.modelUuid === item.modelUuid) .forEach(arm => { - if (arm.activeTime >= 0) { + process.push({ modelid: arm.modelUuid, modelName: arm.modelName, activeTime: arm?.activeTime }) totalActiveTime += arm.activeTime; } }); } else if (item.type === "vehicle") { vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid) .forEach(vehicle => { - if (vehicle.activeTime >= 0) { - // totalActiveTime += vehicle.activeTime; - totalActiveTime += 34; + process.push({ modelid: vehicle.modelUuid, modelName: vehicle.modelName, activeTime: vehicle?.activeTime }) + + totalActiveTime += vehicle.activeTime; } }); } else if (item.type === "machine") { machines.filter(machine => machine.modelUuid === item.modelUuid) .forEach(machine => { if (machine.activeTime >= 0) { - // totalActiveTime += machine.activeTime; - totalActiveTime += 12; + process.push({ modelid: machine.modelUuid, modelName: machine.modelName, activeTime: machine?.activeTime }) + totalActiveTime += machine.activeTime; } }); } else if (item.type === "transfer") { conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid) .forEach(conveyor => { if (conveyor.activeTime >= 0) { - // totalActiveTime += conveyor.activeTime; - totalActiveTime += 89; + totalActiveTime += conveyor.activeTime; } }); } else if (item.type === "storageUnit") { storageUnits.filter(storage => storage.modelUuid === item.modelUuid) .forEach(storage => { if (storage.activeTime >= 0) { - // totalActiveTime += storage.activeTime; - totalActiveTime += 45; + totalActiveTime += storage.activeTime; + } }); } @@ -90,13 +92,20 @@ export default function ThroughPutData() { setMachineCount(totalItems); setMachineActiveTime(totalActiveTime); + let arr = process.map((item: any) => ({ + name: item.modelName, + completed: Math.round((item.activeTime / totalActiveTime) * 100) + })); + setProcessBar(arr); + + } } }; fetchProductSequenceData(); - }, [products, selectedProduct, getProductById, setMachineCount, isPlaying, armBots, materialCycleTime]); + }, [products, selectedProduct, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]); // Setting material cycle time useEffect(() => { @@ -106,8 +115,8 @@ export default function ThroughPutData() { if (start === 0 || end === 0) return; - const totalCycleTime = end - start; - setMaterialCycleTime(totalCycleTime.toFixed(2)); // Set the material cycle time in the store + const totalCycleTime = (end - start) / 1000; // Convert milliseconds to seconds + setMaterialCycleTime(Number(totalCycleTime.toFixed(2))); // Set the material cycle time in the store }); }, [materialHistory]); @@ -115,16 +124,21 @@ export default function ThroughPutData() { useEffect(() => { if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) { - const avgProcessTime = (machineActiveTime / materialCycleTime) * 100; // % value - const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100); // βœ… division by 100 + const avgProcessTime = (machineActiveTime / materialCycleTime) * 100; + const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100); setThroughputData(throughput.toFixed(2)); // Set the throughput data in the store + console.log('---Throughput Results---'); console.log('Total Active Time:', machineActiveTime); console.log('Material Cycle Time:', materialCycleTime); console.log('Machine Count:', machineCount); console.log('Average Process Time (%):', avgProcessTime); console.log('Calculated Throughput:', throughput); + + + + } }, [machineActiveTime, materialCycleTime, machineCount]); diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 7c72855..023716e 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -475,6 +475,11 @@ export const useProductionCapacityData = create((set: any) => ({ setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), })); +export const useProcessBar = create((set: any) => ({ + processBar: [], + setProcessBar: (x: any) => set({ processBar: x }), +})); + type InputValuesStore = { inputValues: Record; @@ -495,6 +500,7 @@ export const useInputValues = create((set) => ({ })); export interface ROISummaryData { + productName: string; roiPercentage: number; paybackPeriod: number; totalCost: number; @@ -510,6 +516,7 @@ interface ROISummaryStore { export const useROISummaryData = create((set) => ({ roiSummary: { + productName: "", roiPercentage: 0, paybackPeriod: 0, totalCost: 0, @@ -518,4 +525,6 @@ export const useROISummaryData = create((set) => ({ netLoss: 0, }, setRoiSummaryData: (values) => set({ roiSummary: values }), -})); \ No newline at end of file +})); + + From 28e11d04b447ab58d15475d246a09c032d726656 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Thu, 15 May 2025 18:00:07 +0530 Subject: [PATCH 10/14] Enhance analysis components with input values integration and improve state management for production capacity and ROI calculations --- .../ui/analysis/ProductionCapacity.tsx | 9 +- app/src/components/ui/analysis/ROISummary.tsx | 3 +- .../ui/analysis/ThroughputSummary.tsx | 32 ++-- .../simulation/analysis/ROI/roiData.tsx | 111 ++++++----- .../productionCapacityData.tsx | 41 ++-- .../analysis/throughPut/throughPutData.tsx | 176 +++++++++--------- .../machineInstance/machineInstance.tsx | 1 - .../armInstance/roboticArmInstance.tsx | 1 + 8 files changed, 201 insertions(+), 173 deletions(-) diff --git a/app/src/components/ui/analysis/ProductionCapacity.tsx b/app/src/components/ui/analysis/ProductionCapacity.tsx index fd6150d..0bc8b91 100644 --- a/app/src/components/ui/analysis/ProductionCapacity.tsx +++ b/app/src/components/ui/analysis/ProductionCapacity.tsx @@ -9,7 +9,7 @@ import { } from "chart.js"; import { PowerIcon, ProductionCapacityIcon } from "../../icons/analysis"; import SkeletonUI from "../../templates/SkeletonUI"; -import { useMachineUptime, useProductionCapacityData } from "../../../store/builder/store"; +import { useInputValues, useMachineUptime, useProductionCapacityData } from "../../../store/builder/store"; ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); @@ -73,6 +73,7 @@ const ThroughputSummary: React.FC = () => { assetUsage: assetUsage, }; + const { inputValues } = useInputValues(); // Chart data configuration const chartData = { labels: throughputData.labels, @@ -91,10 +92,10 @@ const ThroughputSummary: React.FC = () => { useEffect(() => { if (productionCapacityData >= 0) { - setIsLoading(false); + setIsLoading(false); console.log("productionCapacityData: ", productionCapacityData); } else { - setIsLoading(true); + setIsLoading(true); } }, [productionCapacityData]); @@ -123,7 +124,7 @@ const ThroughputSummary: React.FC = () => {
Asset usage
-
{throughputData.assetUsage}%
+
{parseFloat(inputValues["Yield rate"])}%
diff --git a/app/src/components/ui/analysis/ROISummary.tsx b/app/src/components/ui/analysis/ROISummary.tsx index deaf87a..287d631 100644 --- a/app/src/components/ui/analysis/ROISummary.tsx +++ b/app/src/components/ui/analysis/ROISummary.tsx @@ -86,7 +86,6 @@ const ROISummary = ({ useEffect(() => { if (roiSummary && typeof roiSummary === "object") { - console.log('roiSummary: ', roiSummary); setIsLoading(false); // Data loaded } else { setIsLoading(true); // Show skeleton while loading @@ -147,7 +146,7 @@ const ROISummary = ({
0 ? "profit" : "loss"}`} + className={`metric-item net-profit ${roiSummary.netProfit > 0 ? "profit" : "loss"}`} >
↑ diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index e87027b..bf570f9 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -17,26 +17,24 @@ const ProductionCapacity = ({ const { machineActiveTime } = useMachineUptime(); const { materialCycleTime } = useMaterialCycle(); const { throughputData } = useThroughPutData() - const { productionCapacityData } = useProductionCapacityData() - - const progressPercent = machineActiveTime; - - - const totalBars = 6; - const barsToFill = Math.floor((progressPercent / 100) * totalBars); - const partialFillPercent = + const { productionCapacityData } = useProductionCapacityData() + + const progressPercent = machineActiveTime; + + + const totalBars = 6; + const barsToFill = Math.floor((progressPercent / 100) * totalBars); + const partialFillPercent = ((progressPercent / 100) * totalBars - barsToFill) * 100; - - const [isLoading, setIsLoading] = useState(false); - - useEffect(() => { - if (throughputData >= 0) { - console.log('machineActiveTime: ', machineActiveTime); - console.log('materialCycleTime: ', materialCycleTime); - console.log('throughputData: ', throughputData); - console.log('productionCapacityData: ', productionCapacityData); + const [isLoading, setIsLoading] = useState(false); + useEffect(() => { + if (throughputData >= 0) { + // console.log('machineActiveTime: ', machineActiveTime); + // console.log('materialCycleTime: ', materialCycleTime); + // console.log('throughputData: ', throughputData); + // console.log('productionCapacityData: ', productionCapacityData); setIsLoading(true); } diff --git a/app/src/modules/simulation/analysis/ROI/roiData.tsx b/app/src/modules/simulation/analysis/ROI/roiData.tsx index fd77098..f1ddda5 100644 --- a/app/src/modules/simulation/analysis/ROI/roiData.tsx +++ b/app/src/modules/simulation/analysis/ROI/roiData.tsx @@ -1,15 +1,28 @@ import React, { useEffect, useState } from 'react' import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store'; import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; export default function ROIData() { const { inputValues } = useInputValues(); const { productionCapacityData } = useProductionCapacityData() const { selectedProduct } = useSelectedProduct(); - - + const { isPlaying } = usePlayButtonStore(); const { setRoiSummaryData } = useROISummaryData(); useEffect(() => { + if (!isPlaying) { + setRoiSummaryData({ + productName: "", + roiPercentage: 0, + paybackPeriod: 0, + totalCost: 0, + revenueGenerated: 0, + netProfit: 0, + netLoss: 0, + }) + return; + } + if (inputValues === undefined) return; const electricityCost = parseFloat(inputValues["Electricity cost"]); @@ -29,69 +42,77 @@ export default function ROIData() { !isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) && !isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) { - console.log('sellingPrice: ', sellingPrice); - console.log('salvageValue: ', salvageValue); - console.log('productionPeriod: ', productionPeriod); - console.log('materialCost: ', materialCost); - console.log('maintenanceCost: ', maintenanceCost); - console.log('laborCost: ', laborCost); - console.log('fixedCost: ', fixedCost); - console.log('electricityCost: ', electricityCost); - // Revenue - const RevenueForYear = productionCapacityData * sellingPrice; - console.log('RevenueForYear: ', RevenueForYear); - //Costs + const totalHoursPerYear = shiftLength * shiftsPerDay * workingDaysPerYear; - let materialCount = 1200; + // Total good units produced per year + const annualProductionUnits = productionCapacityData * totalHoursPerYear; - //Material Cost + // Revenue for a year + const annualRevenue = annualProductionUnits * sellingPrice; - let MaterialCost = productionCapacityData * materialCost - console.log('MaterialCost: ', MaterialCost); - let LaborCost = laborCost * shiftLength * shiftsPerDay * workingDaysPerYear; - console.log('LaborCost: ', LaborCost); - let EnergyCost = electricityCost * shiftLength * shiftsPerDay * workingDaysPerYear; - console.log('EnergyCost: ', EnergyCost); - let MaintenceCost = maintenanceCost + fixedCost; - console.log('MaintenceCost: ', MaintenceCost); + // Costs + const totalMaterialCost = annualProductionUnits * materialCost; + const totalLaborCost = laborCost * totalHoursPerYear; + const totalEnergyCost = electricityCost * totalHoursPerYear; + const totalMaintenanceCost = maintenanceCost + fixedCost; - //Total Anuual Cost - let TotalAnnualCost = (MaterialCost * materialCount) + LaborCost + EnergyCost + MaintenceCost; - console.log('TotalAnnualCost: ', TotalAnnualCost); + const totalAnnualCost = totalMaterialCost + totalLaborCost + totalEnergyCost + totalMaintenanceCost; + // Annual Profit + const annualProfit = annualRevenue - totalAnnualCost; + console.log('annualProfit: ', annualProfit); - //Profit for Year - let ProfitforYear = RevenueForYear - TotalAnnualCost; - console.log('ProfitforYear: ', ProfitforYear); - - //Net Profit - let NetProfit = ProfitforYear * productionPeriod; - console.log('NetProfit: ', NetProfit); - - - //Final ROI - const ROIData = ((NetProfit + salvageValue - initialInvestment) / TotalAnnualCost) * 100; - console.log('ROIData: ', ROIData); + // Net Profit over production period + const netProfit = annualProfit * productionPeriod; + // ROI + const roiPercentage = ((netProfit + salvageValue - initialInvestment) / initialInvestment) * 100; // Payback Period - const paybackPeriod = initialInvestment / ProfitforYear; + const paybackPeriod = initialInvestment / (annualProfit || 1); // Avoid division by 0 console.log('paybackPeriod: ', paybackPeriod); + // console.log("--- ROI Breakdown ---"); + // console.log("Annual Production Units:", annualProductionUnits.toFixed(2)); + // console.log("Annual Revenue:", annualRevenue.toFixed(2)); + // console.log("Total Annual Cost:", totalAnnualCost.toFixed(2)); + // console.log("Annual Profit:", annualProfit.toFixed(2)); + // console.log("Net Profit:", netProfit.toFixed(2)); + // console.log("ROI %:", roiPercentage.toFixed(2)); + // console.log("Payback Period (years):", paybackPeriod.toFixed(2)); setRoiSummaryData({ productName: selectedProduct.productName, - roiPercentage: parseFloat((ROIData / 100).toFixed(2)), + roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)), // normalized to 0.x format paybackPeriod: parseFloat(paybackPeriod.toFixed(2)), - totalCost: TotalAnnualCost, - revenueGenerated: RevenueForYear, - netProfit: NetProfit > 0 ? NetProfit : 0, - netLoss: NetProfit < 0 ? -NetProfit : 0 + totalCost: parseFloat(totalAnnualCost.toFixed(2)), + revenueGenerated: parseFloat(annualRevenue.toFixed(2)), + netProfit: netProfit > 0 ? parseFloat(netProfit.toFixed(2)) : 0, + netLoss: netProfit < 0 ? -netProfit : 0 }); + const productCount = 1000; + + // Cost per unit (based on full annual cost) + const costPerUnit = totalAnnualCost / annualProductionUnits; + + const costForTargetUnits = productCount * costPerUnit; + const revenueForTargetUnits = productCount * sellingPrice; + const profitForTargetUnits = revenueForTargetUnits - costForTargetUnits; + + const netProfitForTarget = profitForTargetUnits > 0 ? profitForTargetUnits : 0; + const netLossForTarget = profitForTargetUnits < 0 ? -profitForTargetUnits : 0; + + // console.log("--- Fixed Product Count (" + productCount + ") ---"); + // console.log("Cost per Unit:", costPerUnit.toFixed(2)); + // console.log("Total Cost for " + productCount + " Units:", costForTargetUnits.toFixed(2)); + // console.log("Revenue for " + productCount + " Units:", revenueForTargetUnits.toFixed(2)); + // console.log("Profit:", netProfitForTarget.toFixed(2)); + // console.log("Loss:", netLossForTarget.toFixed(2)); + } }, [inputValues, productionCapacityData]); diff --git a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx index a77e221..5c376a7 100644 --- a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx +++ b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx @@ -1,37 +1,44 @@ import React, { useEffect } from 'react' import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store' +import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; export default function ProductionCapacityData() { const { throughputData } = useThroughPutData() const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData() const { inputValues } = useInputValues(); + const { isPlaying } = usePlayButtonStore(); useEffect(() => { - if (inputValues === undefined || throughputData === undefined) return; + if (!isPlaying) { + setProductionCapacityData(0); + return; + } + if (!inputValues || throughputData === undefined) return; const shiftLength = parseFloat(inputValues["Shift length"]); - // console.log('shiftLength: ', shiftLength); const shiftsPerDay = parseFloat(inputValues["Shifts / day"]); - // console.log('shiftsPerDay: ', shiftsPerDay); const workingDaysPerYear = parseFloat(inputValues["Working days / year"]); - // console.log('workingDaysPerYear: ', workingDaysPerYear); const yieldRate = parseFloat(inputValues["Yield rate"]); - // console.log('yieldRate: ', yieldRate); - - if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && !isNaN(yieldRate) && throughputData >= 0) { - //Daily Output + if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && + !isNaN(yieldRate) && throughputData >= 0) { + // Total units produced per day before yield const dailyProduction = throughputData * shiftLength * shiftsPerDay; - console.log("DailyProduction: ", dailyProduction.toFixed(2)); - // Good units (after Yield) - const afterYield = dailyProduction * (yieldRate / 100); - console.log('afterYield: ', afterYield.toFixed(2)); - //Annual Output - const annualProduction = afterYield * workingDaysPerYear; - console.log('annualProduction: ', Number(annualProduction.toFixed(2))); - //Production per Hour + + + // Units after applying yield rate + const goodUnitsPerDay = dailyProduction * (yieldRate / 100); + + + // Annual output + const annualProduction = goodUnitsPerDay * workingDaysPerYear; + + + // Final production capacity per hour (after yield) const productionPerHour = throughputData * (yieldRate / 100); - console.log('productionPerHour: ', productionPerHour); + + + // Set the final capacity (units/hour) setProductionCapacityData(Number(productionPerHour.toFixed(2))); } }, [throughputData, inputValues]); diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx index 401d730..340e4e0 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -10,101 +10,107 @@ import { useConveyorStore } from '../../../../store/simulation/useConveyorStore' import { useStorageUnitStore } from '../../../../store/simulation/useStorageUnitStore'; import { useMaterialStore } from '../../../../store/simulation/useMaterialStore'; import { usePauseButtonStore, usePlayButtonStore } from '../../../../store/usePlayButtonStore'; +import { is, set } from 'immer/dist/internal'; export default function ThroughPutData() { const { selectedProduct } = useSelectedProduct(); const { products, getProductById } = useProductStore(); - const { armBots, incrementActiveTime, incrementIdleTime } = useArmBotStore(); + const { armBots } = useArmBotStore(); const { vehicles } = useVehicleStore(); const { machines } = useMachineStore(); const { conveyors } = useConveyorStore(); const { storageUnits } = useStorageUnitStore(); const { materialHistory } = useMaterialStore(); - const { machineCount, setMachineCount } = useMachineCount(); const { machineActiveTime, setMachineActiveTime } = useMachineUptime(); - const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle(); - const { processBar, setProcessBar } = useProcessBar(); - - // const [totalActiveTime, setTotalActiveTime] = useState(0); - const { setThroughputData } = useThroughPutData() // <=== ADD THIS + const { setProcessBar } = useProcessBar(); + const { setThroughputData } = useThroughPutData() const { isPlaying } = usePlayButtonStore(); // Setting machine count + let totalItems = 0; + let totalActiveTime = 0; useEffect(() => { - if (materialCycleTime <= 0) return - let process: any = []; - const fetchProductSequenceData = async () => { - const productData = getProductById(selectedProduct.productId); - if (productData) { - const productSequenceData = await determineExecutionMachineSequences([productData]) - if (productSequenceData?.length > 0) { - let totalItems = 0; - let totalActiveTime = 0; - productSequenceData.forEach((sequence) => { - sequence.forEach((item) => { + if (!isPlaying) { + totalActiveTime = 0; + totalItems = 0; + setMachineCount(0); + setMachineActiveTime(0); + setMaterialCycleTime(0); + setProcessBar([]); + setThroughputData(0); + return; + } else { + let process: any = []; + const fetchProductSequenceData = async () => { + const productData = getProductById(selectedProduct.productId); + if (productData) { + const productSequenceData = await determineExecutionMachineSequences([productData]) + if (productSequenceData?.length > 0) { + productSequenceData.forEach((sequence) => { + sequence.forEach((item) => { + if (item.type === "roboticArm") { + armBots.filter(arm => arm.modelUuid === item.modelUuid) + .forEach(arm => { + if (arm.activeTime >= 0) { + process.push({ modelid: arm.modelUuid, modelName: arm.modelName, activeTime: arm?.activeTime }) + totalActiveTime += arm.activeTime; - if (item.type === "roboticArm") { - armBots.filter(arm => arm.modelUuid === item.modelUuid) - .forEach(arm => { - if (arm.activeTime >= 0) { - process.push({ modelid: arm.modelUuid, modelName: arm.modelName, activeTime: arm?.activeTime }) - totalActiveTime += arm.activeTime; - } - }); - } else if (item.type === "vehicle") { - vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid) - .forEach(vehicle => { - if (vehicle.activeTime >= 0) { - process.push({ modelid: vehicle.modelUuid, modelName: vehicle.modelName, activeTime: vehicle?.activeTime }) + } + }); + } else if (item.type === "vehicle") { + vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid) + .forEach(vehicle => { + if (vehicle.activeTime >= 0) { + process.push({ modelid: vehicle.modelUuid, modelName: vehicle.modelName, activeTime: vehicle?.activeTime }) - totalActiveTime += vehicle.activeTime; - } - }); - } else if (item.type === "machine") { - machines.filter(machine => machine.modelUuid === item.modelUuid) - .forEach(machine => { - if (machine.activeTime >= 0) { - process.push({ modelid: machine.modelUuid, modelName: machine.modelName, activeTime: machine?.activeTime }) - totalActiveTime += machine.activeTime; - } - }); - } else if (item.type === "transfer") { - conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid) - .forEach(conveyor => { - if (conveyor.activeTime >= 0) { - totalActiveTime += conveyor.activeTime; - } - }); - } else if (item.type === "storageUnit") { - storageUnits.filter(storage => storage.modelUuid === item.modelUuid) - .forEach(storage => { - if (storage.activeTime >= 0) { - totalActiveTime += storage.activeTime; + totalActiveTime += vehicle.activeTime; + } + }); + } else if (item.type === "machine") { + machines.filter(machine => machine.modelUuid === item.modelUuid) + .forEach(machine => { + if (machine.activeTime >= 0) { + process.push({ modelid: machine.modelUuid, modelName: machine.modelName, activeTime: machine?.activeTime }) + totalActiveTime += machine.activeTime; + } + }); + } else if (item.type === "transfer") { + conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid) + .forEach(conveyor => { + if (conveyor.activeTime >= 0) { + totalActiveTime += conveyor.activeTime; + } + }); + } else if (item.type === "storageUnit") { + storageUnits.filter(storage => storage.modelUuid === item.modelUuid) + .forEach(storage => { + if (storage.activeTime >= 0) { + totalActiveTime += storage.activeTime; - } - }); - } + } + }); + } + }); + + totalItems += sequence.length; }); - totalItems += sequence.length; - }); - - setMachineCount(totalItems); - setMachineActiveTime(totalActiveTime); - let arr = process.map((item: any) => ({ - name: item.modelName, - completed: Math.round((item.activeTime / totalActiveTime) * 100) - })); - setProcessBar(arr); - - + setMachineCount(totalItems); + setMachineActiveTime(totalActiveTime); + let arr = process.map((item: any) => ({ + name: item.modelName, + completed: Math.round((item.activeTime / totalActiveTime) * 100) + })); + setProcessBar(arr); + } } - } - }; + }; - fetchProductSequenceData(); + fetchProductSequenceData(); + } + // if (materialCycleTime <= 0) return }, [products, selectedProduct, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]); // Setting material cycle time @@ -112,9 +118,7 @@ export default function ThroughPutData() { materialHistory.forEach((material) => { const start = material.material.startTime ?? 0; const end = material.material.endTime ?? 0; - if (start === 0 || end === 0) return; - const totalCycleTime = (end - start) / 1000; // Convert milliseconds to seconds setMaterialCycleTime(Number(totalCycleTime.toFixed(2))); // Set the material cycle time in the store }); @@ -124,26 +128,24 @@ export default function ThroughPutData() { useEffect(() => { if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) { - const avgProcessTime = (machineActiveTime / materialCycleTime) * 100; - const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100); - setThroughputData(throughput.toFixed(2)); // Set the throughput data in the store - - - console.log('---Throughput Results---'); - console.log('Total Active Time:', machineActiveTime); - console.log('Material Cycle Time:', materialCycleTime); - console.log('Machine Count:', machineCount); - console.log('Average Process Time (%):', avgProcessTime); - console.log('Calculated Throughput:', throughput); - - + const utilization = machineActiveTime / 3600; // Active time per hour + const unitsPerMachinePerHour = 3600 / materialCycleTime; + const throughput = unitsPerMachinePerHour * machineCount * utilization; + setThroughputData(throughput.toFixed(2)); // Set throughput to state/store + // console.log('---Throughput Results---'); + // console.log('Machine Active Time (s):', machineActiveTime); + // console.log('Material Cycle Time (s):', materialCycleTime); + // console.log('Machine Count:', machineCount); + // console.log('Utilization:', utilization); + // console.log('Throughput (units/hr):', throughput); } }, [machineActiveTime, materialCycleTime, machineCount]); + return ( <> diff --git a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx index a985248..ae8c97f 100644 --- a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx +++ b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx @@ -32,7 +32,6 @@ function MachineInstance({ machineDetail }: { machineDetail: MachineStatus }) { const reset = () => { setCurrentPhase("idle"); - console.log("exit"); setMachineState(machineDetail.modelUuid, 'idle'); setMachineActive(machineDetail.modelUuid, false); isIncrememtable.current = true; diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index 4b0829e..7be9002 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -190,6 +190,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { activeSecondsElapsed.current = 0; idleSecondsElapsed.current = 0; previousTimeRef.current = null; + if (animationFrameIdRef.current !== null) { cancelAnimationFrame(animationFrameIdRef.current); animationFrameIdRef.current = null; From b1dc6216b3cbaae515bf244170dae94e2782a469 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Sat, 17 May 2025 18:05:00 +0530 Subject: [PATCH 11/14] 2d and 3d widgets duplication removed --- app/.env | 1 + .../charts/BarGraphComponent.tsx | 94 --------- .../charts/LineGraphComponent.tsx | 93 --------- .../charts/PieGraphComponent.tsx | 90 --------- .../widgets/2d/charts/BarGraphComponent.tsx | 185 +----------------- .../widgets/2d/charts/PieGraphComponent.tsx | 185 ------------------ app/src/store/builder/store.ts | 1 + 7 files changed, 3 insertions(+), 646 deletions(-) delete mode 100644 app/src/modules/visualization/charts/BarGraphComponent.tsx delete mode 100644 app/src/modules/visualization/charts/LineGraphComponent.tsx delete mode 100644 app/src/modules/visualization/charts/PieGraphComponent.tsx diff --git a/app/.env b/app/.env index c50d174..8a98bdc 100644 --- a/app/.env +++ b/app/.env @@ -2,6 +2,7 @@ PORT=8200 # Base URL for the server socket API, used for real-time communication (e.g., WebSockets). +# REACT_APP_SERVER_SOCKET_API_BASE_URL=192.168.0.110:8000 REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000 # Base URL for the server REST API, used for HTTP requests to the backend server. diff --git a/app/src/modules/visualization/charts/BarGraphComponent.tsx b/app/src/modules/visualization/charts/BarGraphComponent.tsx deleted file mode 100644 index 9a07473..0000000 --- a/app/src/modules/visualization/charts/BarGraphComponent.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { useMemo } from "react"; - -import { Bar } from "react-chartjs-2"; - -interface ChartComponentProps { - type: any; - title: string; - fontFamily?: string; - fontSize?: string; - fontWeight?: "Light" | "Regular" | "Bold"; - data: any; -} - -const LineGraphComponent = ({ - title, - fontFamily, - fontSize, - fontWeight = "Regular", -}: ChartComponentProps) => { - // Memoize Font Weight Mapping - const chartFontWeightMap = useMemo( - () => ({ - Light: "lighter" as const, - Regular: "normal" as const, - Bold: "bold" as const, - }), - [] - ); - - // Parse and Memoize Font Size - const fontSizeValue = useMemo( - () => (fontSize ? parseInt(fontSize) : 12), - [fontSize] - ); - - // Determine and Memoize Font Weight - const fontWeightValue = useMemo( - () => chartFontWeightMap[fontWeight], - [fontWeight, chartFontWeightMap] - ); - - // Memoize Chart Font Style - const chartFontStyle = useMemo( - () => ({ - family: fontFamily || "Arial", - size: fontSizeValue, - weight: fontWeightValue, - }), - [fontFamily, fontSizeValue, fontWeightValue] - ); - - const options = useMemo( - () => ({ - responsive: true, - maintainAspectRatio: false, - plugins: { - title: { - display: true, - text: title, - font: chartFontStyle, - }, - legend: { - display: false, - }, - }, - scales: { - x: { - ticks: { - display: false, // This hides the x-axis labels - }, - }, - }, - }), - [title, chartFontStyle] - ); - - const chartData = { - labels: ["January", "February", "March", "April", "May", "June", "July"], - datasets: [ - { - label: "My First Dataset", - data: [65, 59, 80, 81, 56, 55, 40], - backgroundColor: "#6f42c1", - borderColor: "#ffffff", - borderWidth: 2, - fill: false, - }, - ], - }; - - return ; -}; - -export default LineGraphComponent; diff --git a/app/src/modules/visualization/charts/LineGraphComponent.tsx b/app/src/modules/visualization/charts/LineGraphComponent.tsx deleted file mode 100644 index cf1a47f..0000000 --- a/app/src/modules/visualization/charts/LineGraphComponent.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { useMemo } from "react"; -import { Line } from "react-chartjs-2"; - -interface ChartComponentProps { - type: any; - title: string; - fontFamily?: string; - fontSize?: string; - fontWeight?: "Light" | "Regular" | "Bold"; - data: any; -} - -const LineGraphComponent = ({ - title, - fontFamily, - fontSize, - fontWeight = "Regular", -}: ChartComponentProps) => { - // Memoize Font Weight Mapping - const chartFontWeightMap = useMemo( - () => ({ - Light: "lighter" as const, - Regular: "normal" as const, - Bold: "bold" as const, - }), - [] - ); - - // Parse and Memoize Font Size - const fontSizeValue = useMemo( - () => (fontSize ? parseInt(fontSize) : 12), - [fontSize] - ); - - // Determine and Memoize Font Weight - const fontWeightValue = useMemo( - () => chartFontWeightMap[fontWeight], - [fontWeight, chartFontWeightMap] - ); - - // Memoize Chart Font Style - const chartFontStyle = useMemo( - () => ({ - family: fontFamily || "Arial", - size: fontSizeValue, - weight: fontWeightValue, - }), - [fontFamily, fontSizeValue, fontWeightValue] - ); - - const options = useMemo( - () => ({ - responsive: true, - maintainAspectRatio: false, - plugins: { - title: { - display: true, - text: title, - font: chartFontStyle, - }, - legend: { - display: false, - }, - }, - scales: { - x: { - ticks: { - display: false, // This hides the x-axis labels - }, - }, - }, - }), - [title, chartFontStyle] - ); - - const chartData = { - labels: ["January", "February", "March", "April", "May", "June", "July"], - datasets: [ - { - label: "My First Dataset", - data: [65, 59, 80, 81, 56, 55, 40], - backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple) - borderColor: "#ffffff", // Keeping border color white - borderWidth: 2, - fill: false, - }, - ], - }; - - return ; -}; - -export default LineGraphComponent; diff --git a/app/src/modules/visualization/charts/PieGraphComponent.tsx b/app/src/modules/visualization/charts/PieGraphComponent.tsx deleted file mode 100644 index 912cbc3..0000000 --- a/app/src/modules/visualization/charts/PieGraphComponent.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useMemo } from "react"; -import { Pie } from "react-chartjs-2"; - -interface ChartComponentProps { - type: any; - title: string; - fontFamily?: string; - fontSize?: string; - fontWeight?: "Light" | "Regular" | "Bold"; - data: any; -} - -const PieChartComponent = ({ - title, - fontFamily, - fontSize, - fontWeight = "Regular", -}: ChartComponentProps) => { - // Memoize Font Weight Mapping - const chartFontWeightMap = useMemo( - () => ({ - Light: "lighter" as const, - Regular: "normal" as const, - Bold: "bold" as const, - }), - [] - ); - - // Parse and Memoize Font Size - const fontSizeValue = useMemo( - () => (fontSize ? parseInt(fontSize) : 12), - [fontSize] - ); - - // Determine and Memoize Font Weight - const fontWeightValue = useMemo( - () => chartFontWeightMap[fontWeight], - [fontWeight, chartFontWeightMap] - ); - - // Memoize Chart Font Style - const chartFontStyle = useMemo( - () => ({ - family: fontFamily || "Arial", - size: fontSizeValue, - weight: fontWeightValue, - }), - [fontFamily, fontSizeValue, fontWeightValue] - ); - - // Access the CSS variable for the primary accent color - const accentColor = getComputedStyle(document.documentElement) - .getPropertyValue("--accent-color") - .trim(); - - const options = useMemo( - () => ({ - responsive: true, - maintainAspectRatio: false, - plugins: { - title: { - display: true, - text: title, - font: chartFontStyle, - }, - legend: { - display: false, - }, - }, - }), - [title, chartFontStyle] - ); - - const chartData = { - labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], - datasets: [ - { - label: "Dataset", - data: [12, 19, 3, 5, 2, 3], - backgroundColor: ["#6f42c1"], - borderColor: "#ffffff", - borderWidth: 2, - }, - ], - }; - - return ; -}; - -export default PieChartComponent; diff --git a/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx index dc96083..56c2e4f 100644 --- a/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx +++ b/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx @@ -1,187 +1,4 @@ -// import React, { useEffect, useRef, useMemo, useState } from "react"; -// import { Chart } from "chart.js/auto"; -// import { useThemeStore } from "../../../../store/useThemeStore"; -// import io from "socket.io-client"; -// import { Bar } from 'react-chartjs-2'; -// import useChartStore from "../../../../store/useChartStore"; -// // WebSocket Connection -// // const socket = io("http://localhost:5000"); // Adjust to your backend URL - -// interface ChartComponentProps { -// type: any; -// title: string; -// fontFamily?: string; -// fontSize?: string; -// fontWeight?: "Light" | "Regular" | "Bold"; -// data: any; -// } - -// const LineGraphComponent = ({ -// type, -// title, -// fontFamily, -// fontSize, -// fontWeight = "Regular", -// data, -// }: ChartComponentProps) => { -// const canvasRef = useRef(null); -// const { themeColor } = useThemeStore(); -// const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ -// labels: [], -// datasets: [], -// }); - -// const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; - -// const defaultData = { -// labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], -// datasets: [ -// { -// label: "Dataset", -// data: [12, 19, 3, 5, 2, 3], -// backgroundColor: ["#6f42c1"], -// borderColor: "#ffffff", -// borderWidth: 2, -// }, -// ], -// }; - -// // Memoize Theme Colors to Prevent Unnecessary Recalculations -// const buttonActionColor = useMemo( -// () => themeColor[0] || "#5c87df", -// [themeColor] -// ); -// const buttonAbortColor = useMemo( -// () => themeColor[1] || "#ffffff", -// [themeColor] -// ); - -// // Memoize Font Weight Mapping -// const chartFontWeightMap = useMemo( -// () => ({ -// Light: "lighter" as const, -// Regular: "normal" as const, -// Bold: "bold" as const, -// }), -// [] -// ); - -// // Parse and Memoize Font Size -// const fontSizeValue = useMemo( -// () => (fontSize ? parseInt(fontSize) : 12), -// [fontSize] -// ); - -// // Determine and Memoize Font Weight -// const fontWeightValue = useMemo( -// () => chartFontWeightMap[fontWeight], -// [fontWeight, chartFontWeightMap] -// ); - -// // Memoize Chart Font Style -// const chartFontStyle = useMemo( -// () => ({ -// family: fontFamily || "Arial", -// size: fontSizeValue, -// weight: fontWeightValue, -// }), -// [fontFamily, fontSizeValue, fontWeightValue] -// ); - -// // Memoize Chart Data -// // const data = useMemo(() => propsData, [propsData]); - -// // Memoize Chart Options -// const options = useMemo( -// () => ({ -// responsive: true, -// maintainAspectRatio: false, -// plugins: { -// title: { -// display: true, -// text: title, -// font: chartFontStyle, -// }, -// legend: { -// display: false, -// }, -// }, -// scales: { -// x: { -// ticks: { -// display: true, // This hides the x-axis labels -// }, -// }, -// }, -// }), -// [title, chartFontStyle] -// ); - -// const { measurements, setMeasurements, updateDuration, duration } = useChartStore(); - -// useEffect(() => { - -// const socket = io(`http://${iotApiUrl}`); - -// if ( measurements.length > 0 ) { -// var inputes = { -// measurements: measurements, -// duration: duration, -// interval: 1000, -// } - -// // Start stream -// const startStream = () => { -// socket.emit("lineInput", inputes); -// } - -// socket.on('connect', startStream); - -// socket.on("lineOutput", (response) => { -// const responceData = response.data; -// console.log("Received data:", responceData); - -// // Extract timestamps and values -// const labels = responceData.time; -// const datasets = measurements.map((measurement: any) => { -// const key = `${measurement.name}.${measurement.fields}`; -// return { -// label: key, -// data: responceData[key]?.values ?? [], // Ensure it exists -// backgroundColor: "#6f42c1", -// borderColor: "#ffffff", -// }; -// }); - -// setChartData({ labels, datasets }); -// }); -// } - -// return () => { -// socket.off("lineOutput"); -// socket.emit("stop_stream"); // Stop streaming when component unmounts -// }; -// }, [measurements, duration]); - -// // useEffect(() => { -// // if (!canvasRef.current) return; -// // const ctx = canvasRef.current.getContext("2d"); -// // if (!ctx) return; - -// // const chart = new Chart(ctx, { -// // type, -// // data: chartData, -// // options: options, -// // }); - -// // return () => chart.destroy(); -// // }, [chartData, type, title]); - -// return 0 ? chartData : defaultData} options={options} />; -// }; - -// export default LineGraphComponent; import React, { useEffect, useMemo, useState } from "react"; import { Bar } from "react-chartjs-2"; @@ -243,7 +60,7 @@ const BarGraphComponent = ({ ], }; - useEffect(() => {}, []); + useEffect(() => { }, []); // Memoize Theme Colors const buttonActionColor = useMemo( diff --git a/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx index e331593..fdea15e 100644 --- a/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx +++ b/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx @@ -1,188 +1,3 @@ -// import React, { useEffect, useRef, useMemo, useState } from "react"; -// import { Chart } from "chart.js/auto"; -// import { useThemeStore } from "../../../../store/useThemeStore"; -// import io from "socket.io-client"; -// import { Pie } from 'react-chartjs-2'; -// import useChartStore from "../../../../store/useChartStore"; - -// // WebSocket Connection -// // const socket = io("http://localhost:5000"); // Adjust to your backend URL - -// interface ChartComponentProps { -// type: any; -// title: string; -// fontFamily?: string; -// fontSize?: string; -// fontWeight?: "Light" | "Regular" | "Bold"; -// data: any; -// } - -// const PieChartComponent = ({ -// type, -// title, -// fontFamily, -// fontSize, -// fontWeight = "Regular", -// data, -// }: ChartComponentProps) => { -// const canvasRef = useRef(null); -// const { themeColor } = useThemeStore(); -// const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ -// labels: [], -// datasets: [], -// }); - -// const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; - -// const defaultData = { -// labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], -// datasets: [ -// { -// label: "Dataset", -// data: [12, 19, 3, 5, 2, 3], -// backgroundColor: ["#6f42c1"], -// borderColor: "#ffffff", -// borderWidth: 2, -// }, -// ], -// }; - -// // Memoize Theme Colors to Prevent Unnecessary Recalculations -// const buttonActionColor = useMemo( -// () => themeColor[0] || "#6f42c1", -// [themeColor] -// ); -// const buttonAbortColor = useMemo( -// () => themeColor[1] || "#ffffff", -// [themeColor] -// ); - -// // Memoize Font Weight Mapping -// const chartFontWeightMap = useMemo( -// () => ({ -// Light: "lighter" as const, -// Regular: "normal" as const, -// Bold: "bold" as const, -// }), -// [] -// ); - -// // Parse and Memoize Font Size -// const fontSizeValue = useMemo( -// () => (fontSize ? parseInt(fontSize) : 12), -// [fontSize] -// ); - -// // Determine and Memoize Font Weight -// const fontWeightValue = useMemo( -// () => chartFontWeightMap[fontWeight], -// [fontWeight, chartFontWeightMap] -// ); - -// // Memoize Chart Font Style -// const chartFontStyle = useMemo( -// () => ({ -// family: fontFamily || "Arial", -// size: fontSizeValue, -// weight: fontWeightValue, -// }), -// [fontFamily, fontSizeValue, fontWeightValue] -// ); - -// // Memoize Chart Data -// // const data = useMemo(() => propsData, [propsData]); - -// // Memoize Chart Options -// const options = useMemo( -// () => ({ -// responsive: true, -// maintainAspectRatio: false, -// plugins: { -// title: { -// display: true, -// text: title, -// font: chartFontStyle, -// }, -// legend: { -// display: false, -// }, -// }, -// scales: { -// // x: { -// // ticks: { -// // display: true, // This hides the x-axis labels -// // }, -// // }, -// }, -// }), -// [title, chartFontStyle] -// ); - -// const { measurements, setMeasurements, updateDuration, duration } = useChartStore(); - -// useEffect(() => { - -// const socket = io(`http://${iotApiUrl}`); - -// if ( measurements.length > 0 ) { -// var inputes = { -// measurements: measurements, -// duration: duration, -// interval: 1000, -// } - -// // Start stream -// const startStream = () => { -// socket.emit("lineInput", inputes); -// } - -// socket.on('connect', startStream); - -// socket.on("lineOutput", (response) => { -// const responceData = response.data; -// console.log("Received data:", responceData); - -// // Extract timestamps and values -// const labels = responceData.time; -// const datasets = measurements.map((measurement: any) => { -// const key = `${measurement.name}.${measurement.fields}`; -// return { -// label: key, -// data: responceData[key]?.values ?? [], // Ensure it exists -// backgroundColor: "#6f42c1", -// borderColor: "#ffffff", -// }; -// }); - -// setChartData({ labels, datasets }); -// }); -// } - -// return () => { -// socket.off("lineOutput"); -// socket.emit("stop_stream"); // Stop streaming when component unmounts -// }; -// }, [measurements, duration]); - -// // useEffect(() => { -// // if (!canvasRef.current) return; -// // const ctx = canvasRef.current.getContext("2d"); -// // if (!ctx) return; - -// // const chart = new Chart(ctx, { -// // type, -// // data: chartData, -// // options: options, -// // }); - -// // return () => chart.destroy(); -// // }, [chartData, type, title]); - -// return 0 ? chartData : defaultData} options={options} />; -// }; - -// export default PieChartComponent; - import React, { useEffect, useMemo, useState } from "react"; import { Pie } from "react-chartjs-2"; import io from "socket.io-client"; diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 023716e..60e0d4f 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -28,6 +28,7 @@ export const useSocketStore = create((set: any, get: any) => ({ ); set({ socket, visualizationSocket }); + console.log('visualizationSocket: ', visualizationSocket); }, disconnectSocket: () => { set((state: any) => { From 48992317f4a335dfd68226a8451eccce4ffef18a Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Sat, 17 May 2025 18:05:36 +0530 Subject: [PATCH 12/14] Update server socket API base URL in environment configuration --- app/.env | 1 - 1 file changed, 1 deletion(-) diff --git a/app/.env b/app/.env index 8a98bdc..c50d174 100644 --- a/app/.env +++ b/app/.env @@ -2,7 +2,6 @@ PORT=8200 # Base URL for the server socket API, used for real-time communication (e.g., WebSockets). -# REACT_APP_SERVER_SOCKET_API_BASE_URL=192.168.0.110:8000 REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000 # Base URL for the server REST API, used for HTTP requests to the backend server. From d000ee193ae73ceb01590328c94105fda7b0a0d3 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 19 May 2025 10:53:16 +0530 Subject: [PATCH 13/14] Enable sprite rendering for 3D widgets in ProductionCapacity, ReturnOfInvestment, StateWorking, and Throughput components; update CSS to allow pointer events in realTimeViz --- .../visualization/widgets/3d/cards/ProductionCapacity.tsx | 2 +- .../visualization/widgets/3d/cards/ReturnOfInvestment.tsx | 2 +- .../visualization/widgets/3d/cards/StateWorking.tsx | 2 +- .../modules/visualization/widgets/3d/cards/Throughput.tsx | 7 +------ app/src/styles/pages/realTimeViz.scss | 2 +- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx index 53cc473..19fe97d 100644 --- a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx @@ -203,7 +203,7 @@ const ProductionCapacity: React.FC = ({ scale={[0.5, 0.5, 0.5]} rotation={rotation} transform - sprite={false} + sprite={true} zIndexRange={[1, 0]} // style={{ // transform: transformStyle.transform, diff --git a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx index 5e638cf..6aed5ca 100644 --- a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx @@ -242,7 +242,7 @@ const ReturnOfInvestment: React.FC = ({ rotation={rotation} scale={[0.5, 0.5, 0.5]} transform - sprite={false} + sprite={true} // style={{ // transform: transformStyle.transform, // transformStyle: "preserve-3d", diff --git a/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx b/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx index d5cc07e..da5c411 100644 --- a/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx @@ -121,7 +121,7 @@ const StateWorking: React.FC = ({ scale={[0.5, 0.5, 0.5]} transform zIndexRange={[1, 0]} - sprite={false} + sprite={true} // style={{ // transform: transformStyle.transform, // transformStyle: "preserve-3d", diff --git a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx index 1489c3d..f003607 100644 --- a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx @@ -223,12 +223,7 @@ const Throughput: React.FC = ({ scale={[0.5, 0.5, 0.5]} transform zIndexRange={[1, 0]} - sprite={false} - // style={{ - // transform: transformStyle.transform, - // transformStyle: "preserve-3d", - // transition: "transform 0.1s ease-out", - // }} + sprite={true} >
Date: Mon, 19 May 2025 10:58:25 +0530 Subject: [PATCH 14/14] Add modelUrl prop to card component in CardsContainer; clean up vehicleInstance imports --- app/src/modules/market/CardsContainer.tsx | 1 + .../simulation/vehicle/instances/instance/vehicleInstance.tsx | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/modules/market/CardsContainer.tsx b/app/src/modules/market/CardsContainer.tsx index e1766f2..2afa576 100644 --- a/app/src/modules/market/CardsContainer.tsx +++ b/app/src/modules/market/CardsContainer.tsx @@ -65,6 +65,7 @@ const CardsContainer: React.FC = ({ models }) => { onSelectCard={handleCardSelect} AssetID={assetDetail.AssetID} image={assetDetail.thumbnail} + modelUrl={assetDetail.modelfileID} description={assetDetail.description} /> diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 034a0ae..00837a4 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -24,8 +24,8 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) const { triggerPointActions } = useTriggerHandler(); const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore(); const { selectedProduct } = useSelectedProduct(); - const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = useVehicleStore(); - + const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = useVehicleStore(); + const [currentPhase, setCurrentPhase] = useState('stationed'); const [path, setPath] = useState<[number, number, number][]>([]); const pauseTimeRef = useRef(null);