Merge remote-tracking branch 'origin/main' into ui
This commit is contained in:
commit
893d01ee4e
6
app/.env
6
app/.env
|
@ -9,3 +9,9 @@ REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000
|
|||
|
||||
# Base URL for the server marketplace API.
|
||||
REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011
|
||||
|
||||
# base url for IoT socket server
|
||||
REACT_APP_IOT_SOCKET_SERVER_URL =185.100.212.76:5010
|
||||
|
||||
# Base URL for the server mqtt.
|
||||
REACT_APP_SERVER_MQTT_URL=185.100.212.76:23457
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,6 +9,7 @@
|
|||
"@react-three/drei": "^9.113.0",
|
||||
"@react-three/fiber": "^8.17.7",
|
||||
"@react-three/postprocessing": "^2.16.3",
|
||||
"@recast-navigation/core": "^0.39.0",
|
||||
"@recast-navigation/three": "^0.39.0",
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
|
|
|
@ -11,10 +11,10 @@ const CardsScene = () => {
|
|||
<Canvas>
|
||||
{/* 3d-cards */}
|
||||
|
||||
<Throughput />
|
||||
{/* <ReturnOfInvestment /> */}
|
||||
{/* <ProductionCapacity /> */}
|
||||
{/* <ReturnOfInvestment /> */}
|
||||
{/* <StateWorking /> */}
|
||||
{/* <Throughput /> */}
|
||||
|
||||
<OrbitControls />
|
||||
</Canvas>
|
||||
|
|
|
@ -21,8 +21,11 @@ ChartJS.register(
|
|||
Tooltip,
|
||||
Legend
|
||||
);
|
||||
interface ProductionCapacityProps {
|
||||
position: [number, number, number];
|
||||
}
|
||||
|
||||
const ProductionCapacity = () => {
|
||||
const ProductionCapacity : React.FC<ProductionCapacityProps> = ({ position }) => {
|
||||
// Chart data for a week
|
||||
const chartData = {
|
||||
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], // Days of the week
|
||||
|
@ -76,7 +79,10 @@ const ProductionCapacity = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Html position={[0, 0, 0]} transform occlude>
|
||||
<Html position={[position[0], position[1], position[2]]}
|
||||
scale={[0.5, 0.5, 0.5]}
|
||||
transform
|
||||
sprite>
|
||||
<div className="productionCapacity-wrapper card">
|
||||
<div className="headeproductionCapacityr-wrapper">
|
||||
<div className="header">Production Capacity</div>
|
||||
|
|
|
@ -35,8 +35,10 @@ const SmoothLineGraphComponent: React.FC<SmoothLineGraphProps> = ({
|
|||
}) => {
|
||||
return <Line data={data} options={options} />;
|
||||
};
|
||||
|
||||
const ReturnOfInvestment = () => {
|
||||
interface ReturnOfInvestmentProps {
|
||||
position: [number, number, number];
|
||||
}
|
||||
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ position }) => {
|
||||
// Improved sample data for the smooth curve graph (single day)
|
||||
const graphData: ChartData<"line"> = {
|
||||
labels: [
|
||||
|
@ -106,7 +108,10 @@ const ReturnOfInvestment = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Html position={[0, 0, 0]} transform occlude>
|
||||
<Html position={[position[0], position[1], position[2]]}
|
||||
scale={[0.5, 0.5, 0.5]}
|
||||
transform
|
||||
sprite>
|
||||
<div className="returnOfInvestment card">
|
||||
<div className="header">Return of Investment</div>
|
||||
<div className="lineGraph charts">
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { Html } from "@react-three/drei";
|
||||
import image from "../../../../assets/image/temp/image.png";
|
||||
const StateWorking = () => {
|
||||
// import image from "../../../../assets/image/temp/image.png";
|
||||
interface StateWorkingProps {
|
||||
position: [number, number, number];
|
||||
}
|
||||
const StateWorking: React.FC<StateWorkingProps> = ({ position }) => {
|
||||
const datas = [
|
||||
{ key: "Oil Tank:", value: "24/341" },
|
||||
{ key: "Oil Refin:", value: 36.023 },
|
||||
|
@ -10,7 +13,10 @@ const StateWorking = () => {
|
|||
{ key: "Time:", value: 13 - 9 - 2023 },
|
||||
];
|
||||
return (
|
||||
<Html position={[0, 0, 0]} transform occlude>
|
||||
<Html position={[position[0], position[1], position[2]]}
|
||||
scale={[0.5, 0.5, 0.5]}
|
||||
transform
|
||||
sprite>
|
||||
<div className="stateWorking-wrapper card">
|
||||
<div className="header-wrapper">
|
||||
<div className="header">
|
||||
|
@ -20,7 +26,7 @@ const StateWorking = () => {
|
|||
</span>
|
||||
</div>
|
||||
<div className="img">
|
||||
<img src={image} alt="" />
|
||||
{/* <img src={image} alt="" /> */}
|
||||
</div>
|
||||
</div>
|
||||
{/* Data */}
|
||||
|
|
|
@ -37,7 +37,12 @@ const LineGraphComponent: React.FC<LineGraphProps> = ({ data, options }) => {
|
|||
return <Line data={data} options={options} />;
|
||||
};
|
||||
|
||||
const Throughput = () => {
|
||||
interface ThroughputProps {
|
||||
position: [number, number, number];
|
||||
}
|
||||
|
||||
const Throughput: React.FC<ThroughputProps> = ({ position }) => {
|
||||
|
||||
// Sample data for the line graph
|
||||
const graphData: ChartData<"line"> = {
|
||||
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
|
||||
|
@ -86,7 +91,10 @@ const Throughput = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Html position={[0, 0, 0]} transform occlude>
|
||||
<Html position={[position[0], position[1], position[2]]}
|
||||
scale={[0.5, 0.5, 0.5]}
|
||||
transform
|
||||
sprite>
|
||||
<div className="throughput-wrapper">
|
||||
<div className="header">Throughput</div>
|
||||
<div className="display-value">
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
|||
import { ChartType } from "chart.js/auto";
|
||||
import ChartComponent from "./ChartComponent";
|
||||
import { StockIncreseIcon } from "../../../../icons/RealTimeVisulationIcons";
|
||||
import { generateUniqueId } from "../../../../../functions/generateUniqueId";
|
||||
|
||||
const chartTypes: ChartType[] = [
|
||||
"bar",
|
||||
|
@ -18,7 +19,7 @@ const sampleData = {
|
|||
{
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
backgroundColor: "#6f42c1",
|
||||
borderColor: "#ffffff",
|
||||
borderColor: "#b392f0",
|
||||
borderWidth: 1,
|
||||
},
|
||||
],
|
||||
|
@ -40,7 +41,8 @@ const ChartWidget: React.FC<WidgetProps> = ({ type, index, title }) => {
|
|||
onDragStart={() => {
|
||||
setDraggedAsset({
|
||||
type,
|
||||
id: `widget-${index + 1}`,
|
||||
id: generateUniqueId(
|
||||
),
|
||||
title,
|
||||
panel: "top",
|
||||
data: sampleData,
|
||||
|
|
|
@ -2,6 +2,7 @@ import widget1 from "../../../../../assets/image/3D/ProductionCapacity.png";
|
|||
import widget2 from "../../../../../assets/image/3D/ReturnOfInvestment.png";
|
||||
import widget3 from "../../../../../assets/image/3D/StateWorking.png";
|
||||
import widget4 from "../../../../../assets/image/3D/Throughput.png";
|
||||
import { useAsset3dWidget } from "../../../../../store/store";
|
||||
const Widgets3D = () => {
|
||||
const widgets = [
|
||||
{ name: "Widget 1", img: widget1 },
|
||||
|
@ -9,17 +10,38 @@ const Widgets3D = () => {
|
|||
{ name: "Widget 3", img: widget3 },
|
||||
{ name: "Widget 4", img: widget4 },
|
||||
];
|
||||
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
||||
|
||||
|
||||
return (
|
||||
<div className="widgets-container widget3D">
|
||||
{widgets?.map((widget, index) => (
|
||||
<div key={index} className="widget-item" draggable>
|
||||
<div className="widget-name">{widget.name}</div>
|
||||
<div
|
||||
key={index}
|
||||
className="widget-item"
|
||||
draggable
|
||||
onDragStart={(e) => {
|
||||
let crt = e.target
|
||||
if (crt instanceof HTMLElement) {
|
||||
const widget = crt.cloneNode(true) as HTMLElement;
|
||||
console.log('widget: ', widget);
|
||||
e.dataTransfer.setDragImage(widget,0,0)
|
||||
e.dataTransfer.effectAllowed="move"
|
||||
}
|
||||
}}
|
||||
onPointerDown={() => {
|
||||
setWidgetSelect("ui-" + widget.name);
|
||||
}}
|
||||
onPointerUp={() => {
|
||||
setWidgetSelect(""); // Clearing selection correctly
|
||||
}}
|
||||
>
|
||||
{/* <div className="widget-name">{widget.name}</div> */}
|
||||
<img
|
||||
className="widget-image"
|
||||
src={widget.img}
|
||||
alt={widget.name}
|
||||
draggable={false}
|
||||
// draggable={false}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
SimulationIcon,
|
||||
} from "../../icons/SimulationIcons";
|
||||
import useToggleStore from "../../../store/useUIToggleStore";
|
||||
import MachineMechanics from "./mechanics/MachineMechanics";
|
||||
import ConveyorMechanics from "./mechanics/ConveyorMechanics";
|
||||
import Visualization from "./visualization/Visualization";
|
||||
import Analysis from "./analysis/Analysis";
|
||||
import Simulations from "./simulation/Simulations";
|
||||
|
@ -18,6 +18,7 @@ import { useSelectedActionSphere } from "../../../store/store";
|
|||
import GlobalProperties from "./properties/GlobalProperties";
|
||||
import AsstePropertiies from "./properties/AssetProperties";
|
||||
import ZoneProperties from "./properties/ZoneProperties";
|
||||
import VehicleMechanics from "./mechanics/VehicleMechanics";
|
||||
|
||||
const SideBarRight: React.FC = () => {
|
||||
const { activeModule } = useModuleStore();
|
||||
|
@ -98,17 +99,24 @@ const SideBarRight: React.FC = () => {
|
|||
|
||||
{toggleUI && activeModule === "simulation" && (
|
||||
<>
|
||||
{subModule === "mechanics" && selectedActionSphere && (
|
||||
{subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Conveyor" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<MachineMechanics />
|
||||
<ConveyorMechanics />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{subModule === "mechanics" && selectedActionSphere && selectedActionSphere.path.type === "Vehicle" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
{/* <VehicleMechanics /> */}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{subModule === "mechanics" && !selectedActionSphere && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
{/* <MachineMechanics /> */}
|
||||
<ConveyorMechanics />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -0,0 +1,586 @@
|
|||
import React, { useRef, useState, useMemo, useEffect } from "react";
|
||||
import {
|
||||
AddIcon,
|
||||
InfoIcon,
|
||||
RemoveIcon,
|
||||
ResizeHeightIcon,
|
||||
} from "../../../icons/ExportCommonIcons";
|
||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
|
||||
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
|
||||
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store";
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||
|
||||
const ConveyorMechanics: React.FC = () => {
|
||||
const { selectedActionSphere } = useSelectedActionSphere();
|
||||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||
|
||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const selectedPoint = useMemo(() => {
|
||||
if (!selectedActionSphere) return null;
|
||||
return simulationPaths
|
||||
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
|
||||
.flatMap((path) => path.points)
|
||||
.find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||
}, [selectedActionSphere, simulationPaths]);
|
||||
|
||||
const handleAddAction = () => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => {
|
||||
if (path.type === "Conveyor") {
|
||||
return {
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
const actionIndex = point.actions.length;
|
||||
const newAction = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: `Action ${actionIndex + 1}`,
|
||||
type: 'Inherit',
|
||||
material: 'Inherit',
|
||||
delay: 'Inherit',
|
||||
spawnInterval: 'Inherit',
|
||||
isUsed: false
|
||||
};
|
||||
|
||||
return { ...point, actions: [...point.actions, newAction] };
|
||||
}
|
||||
return point;
|
||||
}),
|
||||
};
|
||||
}
|
||||
return path;
|
||||
});
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleDeleteAction = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleActionSelect = (uuid: string, actionType: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid
|
||||
? {
|
||||
...action,
|
||||
type: actionType,
|
||||
material: actionType === 'Spawn' || actionType === 'Swap' ? 'Inherit' : action.material,
|
||||
delay: actionType === 'Delay' ? 'Inherit' : action.delay,
|
||||
spawnInterval: actionType === 'Spawn' ? 'Inherit' : action.spawnInterval
|
||||
}
|
||||
: action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Update the selected item to reflect changes
|
||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||
const updatedAction = updatedPaths
|
||||
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
|
||||
.flatMap(path => path.points)
|
||||
.find(p => p.uuid === selectedActionSphere.point.uuid)
|
||||
?.actions.find(a => a.uuid === uuid);
|
||||
|
||||
if (updatedAction) {
|
||||
setSelectedItem({
|
||||
type: "action",
|
||||
item: updatedAction
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Modified handleMaterialSelect to ensure it only applies to relevant action types
|
||||
const handleMaterialSelect = (uuid: string, material: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid &&
|
||||
(action.type === 'Spawn' || action.type === 'Swap')
|
||||
? { ...action, material }
|
||||
: action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Update selected item if it's the current action
|
||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||
setSelectedItem({
|
||||
...selectedItem,
|
||||
item: {
|
||||
...selectedItem.item,
|
||||
material
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelayChange = (uuid: string, delay: number | string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, delay } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, spawnInterval } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleSpeedChange = (speed: number) => {
|
||||
if (!selectedPath) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
|
||||
};
|
||||
|
||||
const handleAddTrigger = () => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
const triggerIndex = point.triggers.length;
|
||||
const newTrigger = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: `Trigger ${triggerIndex + 1}`,
|
||||
type: '',
|
||||
isUsed: false
|
||||
};
|
||||
|
||||
return { ...point, triggers: [...point.triggers, newTrigger] };
|
||||
}
|
||||
return point;
|
||||
}),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleDeleteTrigger = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleTriggerSelect = (uuid: string, triggerType: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) =>
|
||||
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
// Update the toggle handlers to immediately update the selected item
|
||||
const handleActionToggle = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) => ({
|
||||
...action,
|
||||
isUsed: action.uuid === uuid ? !action.isUsed : false,
|
||||
})),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Immediately update the selected item if it's the one being toggled
|
||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||
setSelectedItem({
|
||||
...selectedItem,
|
||||
item: {
|
||||
...selectedItem.item,
|
||||
isUsed: !selectedItem.item.isUsed
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Do the same for trigger toggle
|
||||
const handleTriggerToggle = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) => ({
|
||||
...trigger,
|
||||
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
|
||||
})),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Immediately update the selected item if it's the one being toggled
|
||||
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
|
||||
setSelectedItem({
|
||||
...selectedItem,
|
||||
item: {
|
||||
...selectedItem.item,
|
||||
isUsed: !selectedItem.item.isUsed
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const [selectedItem, setSelectedItem] = useState<{ type: "action" | "trigger"; item: any; } | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedItem(null); // Reset selectedItem when selectedActionSphere changes
|
||||
}, [selectedActionSphere]);
|
||||
|
||||
return (
|
||||
<div className="machine-mechanics-container">
|
||||
<div className="machine-mechanics-header">
|
||||
{selectedActionSphere?.path?.modelName || "point name not found"}
|
||||
</div>
|
||||
|
||||
<div className="machine-mechanics-content-container">
|
||||
{!selectedPath &&
|
||||
<>
|
||||
<div className="actions">
|
||||
<div className="header">
|
||||
<div className="header-value">Actions</div>
|
||||
<div className="add-button" onClick={handleAddAction}>
|
||||
<AddIcon /> Add
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={actionsContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{selectedPoint?.actions.map((action) => (
|
||||
<div
|
||||
key={action.uuid}
|
||||
className={`list-item ${selectedItem?.type === "action" &&
|
||||
selectedItem.item?.uuid === action.uuid
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
onClick={() => setSelectedItem({ type: "action", item: action })}
|
||||
>
|
||||
<RenameInput value={action.name} />
|
||||
</div>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleDeleteAction(action.uuid)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="resize-icon"
|
||||
id="action-resize"
|
||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="triggers">
|
||||
<div className="header">
|
||||
<div className="header-value">Triggers</div>
|
||||
<div className="add-button" onClick={handleAddTrigger}>
|
||||
<AddIcon /> Add
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={triggersContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{selectedPoint?.triggers.map((trigger) => (
|
||||
<div
|
||||
key={trigger.uuid}
|
||||
className={`list-item ${selectedItem?.type === "trigger" &&
|
||||
selectedItem.item?.uuid === trigger.uuid
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
onClick={() => setSelectedItem({ type: "trigger", item: trigger })}
|
||||
>
|
||||
<RenameInput value={trigger.name} />
|
||||
</div>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleDeleteTrigger(trigger.uuid)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="resize-icon"
|
||||
id="trigger-resize"
|
||||
onMouseDown={(e) => handleResize(e, triggersContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
<div className="selected-properties-container">
|
||||
{selectedItem && (
|
||||
<>
|
||||
<div className="properties-header">{selectedItem.item.name}</div>
|
||||
|
||||
{selectedItem.type === "action" && (
|
||||
<>
|
||||
<InputToggle
|
||||
inputKey="enableTrigger"
|
||||
label="Enable Trigger"
|
||||
value={selectedItem.item.isUsed}
|
||||
onClick={() => handleActionToggle(selectedItem.item.uuid)}
|
||||
/>
|
||||
<LabledDropdown
|
||||
defaultOption={selectedItem.item.type}
|
||||
options={["Inherit", "Spawn", "Swap", "Despawn", "Delay"]}
|
||||
onSelect={(option) => handleActionSelect(selectedItem.item.uuid, option)}
|
||||
/>
|
||||
|
||||
{/* Only show material dropdown for Spawn/Swap actions */}
|
||||
{(selectedItem.item.type === 'Spawn' || selectedItem.item.type === 'Swap') && (
|
||||
<LabledDropdown
|
||||
label={selectedItem.item.type === 'Spawn' ? 'Spawn Material' : 'Swap Material'}
|
||||
defaultOption={selectedItem.item.material}
|
||||
options={["Inherit", "Crate", "Box"]}
|
||||
onSelect={(option) => handleMaterialSelect(selectedItem.item.uuid, option)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Only show delay input for Delay actions */}
|
||||
{selectedItem.item.type === 'Delay' && (
|
||||
<InputWithDropDown
|
||||
label="Delay Time"
|
||||
value={selectedItem.item.delay === 'Inherit'
|
||||
? undefined
|
||||
: selectedItem.item.delay}
|
||||
onChange={(value) => {
|
||||
const numValue = parseInt(value);
|
||||
handleDelayChange(
|
||||
selectedItem.item.uuid,
|
||||
!value ? 'Inherit' : numValue
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Only show spawn interval for Spawn actions */}
|
||||
{selectedItem.item.type === 'Spawn' && (
|
||||
<InputWithDropDown
|
||||
label="Spawn Interval"
|
||||
min={0}
|
||||
defaultValue={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
|
||||
value={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
|
||||
onChange={(value) => {
|
||||
handleSpawnIntervalChange(selectedItem.item.uuid, (value === "") ? "Inherit" : parseInt(value));
|
||||
}}
|
||||
/>
|
||||
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedItem.type === "trigger" && (
|
||||
<>
|
||||
<InputToggle
|
||||
inputKey="enableTrigger"
|
||||
label="Enable Trigger"
|
||||
value={selectedItem.item.isUsed}
|
||||
onClick={() => handleTriggerToggle(selectedItem.item.uuid)}
|
||||
/>
|
||||
|
||||
<LabledDropdown
|
||||
defaultOption={selectedItem.item.type || "Select Trigger Type"}
|
||||
options={["On-Hit", "Buffer"]}
|
||||
onSelect={(option) => handleTriggerSelect(selectedItem.item.uuid, option)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedPath && !selectedItem && (
|
||||
<div className="speed-control">
|
||||
<InputWithDropDown
|
||||
label="Conveyor Speed"
|
||||
value={selectedPath.path.speed.toString()}
|
||||
onChange={(value) => handleSpeedChange(parseFloat(value))}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="footer">
|
||||
<InfoIcon />
|
||||
By selecting points, you can create events and triggers.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConveyorMechanics;
|
|
@ -1,533 +0,0 @@
|
|||
import React, { useRef, useState, useMemo, useEffect } from "react";
|
||||
import {
|
||||
AddIcon,
|
||||
InfoIcon,
|
||||
RemoveIcon,
|
||||
ResizeHeightIcon,
|
||||
} from "../../../icons/ExportCommonIcons";
|
||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
|
||||
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
|
||||
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store";
|
||||
import * as THREE from 'three';
|
||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||
|
||||
const MachineMechanics: React.FC = () => {
|
||||
const { selectedActionSphere } = useSelectedActionSphere();
|
||||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||
|
||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const selectedPoint = useMemo(() => {
|
||||
if (!selectedActionSphere) return null;
|
||||
return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||
}, [selectedActionSphere, simulationPaths]);
|
||||
|
||||
const handleAddAction = () => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
const actionIndex = point.actions.length;
|
||||
const newAction = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: `Action ${actionIndex + 1}`,
|
||||
type: 'Inherit',
|
||||
material: 'Inherit',
|
||||
delay: 'Inherit',
|
||||
spawnInterval: 'Inherit',
|
||||
isUsed: false
|
||||
};
|
||||
|
||||
return { ...point, actions: [...point.actions, newAction] };
|
||||
}
|
||||
return point;
|
||||
}),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleDeleteAction = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
||||
: point
|
||||
),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleActionSelect = (uuid: string, actionType: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid
|
||||
? {
|
||||
...action,
|
||||
type: actionType,
|
||||
// Reset dependent fields when type changes
|
||||
material: actionType === 'Spawn' || actionType === 'Swap' ? 'Inherit' : action.material,
|
||||
delay: actionType === 'Delay' ? 'Inherit' : action.delay,
|
||||
spawnInterval: actionType === 'Spawn' ? 'Inherit' : action.spawnInterval
|
||||
}
|
||||
: action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Update the selected item to reflect changes
|
||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||
const updatedAction = updatedPaths
|
||||
.flatMap(path => path.points)
|
||||
.find(p => p.uuid === selectedActionSphere.point.uuid)
|
||||
?.actions.find(a => a.uuid === uuid);
|
||||
|
||||
if (updatedAction) {
|
||||
setSelectedItem({
|
||||
type: "action",
|
||||
item: updatedAction
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Modified handleMaterialSelect to ensure it only applies to relevant action types
|
||||
const handleMaterialSelect = (uuid: string, material: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid &&
|
||||
(action.type === 'Spawn' || action.type === 'Swap')
|
||||
? { ...action, material }
|
||||
: action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Update selected item if it's the current action
|
||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||
setSelectedItem({
|
||||
...selectedItem,
|
||||
item: {
|
||||
...selectedItem.item,
|
||||
material
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelayChange = (uuid: string, delay: number | string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, delay } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, spawnInterval } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleSpeedChange = (speed: number) => {
|
||||
if (!selectedPath) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
|
||||
};
|
||||
|
||||
const handleAddTrigger = () => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
const triggerIndex = point.triggers.length;
|
||||
const newTrigger = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: `Trigger ${triggerIndex + 1}`,
|
||||
type: '',
|
||||
isUsed: false
|
||||
};
|
||||
|
||||
return { ...point, triggers: [...point.triggers, newTrigger] };
|
||||
}
|
||||
return point;
|
||||
}),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleDeleteTrigger = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
||||
: point
|
||||
),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleTriggerSelect = (uuid: string, triggerType: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) =>
|
||||
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
// Update the toggle handlers to immediately update the selected item
|
||||
const handleActionToggle = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) => ({
|
||||
...action,
|
||||
isUsed: action.uuid === uuid ? !action.isUsed : false,
|
||||
})),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Immediately update the selected item if it's the one being toggled
|
||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||
setSelectedItem({
|
||||
...selectedItem,
|
||||
item: {
|
||||
...selectedItem.item,
|
||||
isUsed: !selectedItem.item.isUsed
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Do the same for trigger toggle
|
||||
const handleTriggerToggle = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) => ({
|
||||
...trigger,
|
||||
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
|
||||
})),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Immediately update the selected item if it's the one being toggled
|
||||
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
|
||||
setSelectedItem({
|
||||
...selectedItem,
|
||||
item: {
|
||||
...selectedItem.item,
|
||||
isUsed: !selectedItem.item.isUsed
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const [selectedItem, setSelectedItem] = useState<{ type: "action" | "trigger"; item: any; } | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedItem(null); // Reset selectedItem when selectedActionSphere changes
|
||||
}, [selectedActionSphere]);
|
||||
|
||||
return (
|
||||
<div className="machine-mechanics-container">
|
||||
<div className="machine-mechanics-header">
|
||||
{selectedActionSphere?.path?.modelName || "point name not found"}
|
||||
</div>
|
||||
|
||||
<div className="machine-mechanics-content-container">
|
||||
<div className="actions">
|
||||
<div className="header">
|
||||
<div className="header-value">Actions</div>
|
||||
<div className="add-button" onClick={handleAddAction}>
|
||||
<AddIcon /> Add
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={actionsContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{selectedPoint?.actions.map((action) => (
|
||||
<div
|
||||
key={action.uuid}
|
||||
className={`list-item ${selectedItem?.type === "action" &&
|
||||
selectedItem.item?.uuid === action.uuid
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
onClick={() => setSelectedItem({ type: "action", item: action })}
|
||||
>
|
||||
<RenameInput value={action.name} />
|
||||
</div>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleDeleteAction(action.uuid)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="resize-icon"
|
||||
id="action-resize"
|
||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="triggers">
|
||||
<div className="header">
|
||||
<div className="header-value">Triggers</div>
|
||||
<div className="add-button" onClick={handleAddTrigger}>
|
||||
<AddIcon /> Add
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={triggersContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{selectedPoint?.triggers.map((trigger) => (
|
||||
<div
|
||||
key={trigger.uuid}
|
||||
className={`list-item ${selectedItem?.type === "trigger" &&
|
||||
selectedItem.item?.uuid === trigger.uuid
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
onClick={() => setSelectedItem({ type: "trigger", item: trigger })}
|
||||
>
|
||||
<RenameInput value={trigger.name} />
|
||||
</div>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleDeleteTrigger(trigger.uuid)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="resize-icon"
|
||||
id="trigger-resize"
|
||||
onMouseDown={(e) => handleResize(e, triggersContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="selected-properties-container">
|
||||
{selectedItem && (
|
||||
<>
|
||||
<div className="properties-header">{selectedItem.item.name}</div>
|
||||
|
||||
{selectedItem.type === "action" && (
|
||||
<>
|
||||
<InputToggle
|
||||
inputKey="enableTrigger"
|
||||
label="Enable Trigger"
|
||||
value={selectedItem.item.isUsed}
|
||||
onClick={() => handleActionToggle(selectedItem.item.uuid)}
|
||||
/>
|
||||
<LabledDropdown
|
||||
defaultOption={selectedItem.item.type}
|
||||
options={["Inherit", "Spawn", "Swap", "Despawn", "Delay"]}
|
||||
onSelect={(option) => handleActionSelect(selectedItem.item.uuid, option)}
|
||||
/>
|
||||
|
||||
{/* Only show material dropdown for Spawn/Swap actions */}
|
||||
{(selectedItem.item.type === 'Spawn' || selectedItem.item.type === 'Swap') && (
|
||||
<LabledDropdown
|
||||
label={selectedItem.item.type === 'Spawn' ? 'Spawn Material' : 'Swap Material'}
|
||||
defaultOption={selectedItem.item.material}
|
||||
options={["Inherit", "Crate", "Box"]}
|
||||
onSelect={(option) => handleMaterialSelect(selectedItem.item.uuid, option)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Only show delay input for Delay actions */}
|
||||
{selectedItem.item.type === 'Delay' && (
|
||||
<InputWithDropDown
|
||||
label="Delay Time"
|
||||
value={selectedItem.item.delay === 'Inherit'
|
||||
? undefined
|
||||
: selectedItem.item.delay}
|
||||
onChange={(value) => {
|
||||
const numValue = parseInt(value);
|
||||
handleDelayChange(
|
||||
selectedItem.item.uuid,
|
||||
!value ? 'Inherit' : numValue
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Only show spawn interval for Spawn actions */}
|
||||
{selectedItem.item.type === 'Spawn' && (
|
||||
<InputWithDropDown
|
||||
label="Spawn Interval"
|
||||
min={0}
|
||||
defaultValue={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
|
||||
value={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
|
||||
onChange={(value) => {
|
||||
handleSpawnIntervalChange(selectedItem.item.uuid, (value === "") ? "Inherit" : parseInt(value));
|
||||
}}
|
||||
/>
|
||||
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedItem.type === "trigger" && (
|
||||
<>
|
||||
<InputToggle
|
||||
inputKey="enableTrigger"
|
||||
label="Enable Trigger"
|
||||
value={selectedItem.item.isUsed}
|
||||
onClick={() => handleTriggerToggle(selectedItem.item.uuid)}
|
||||
/>
|
||||
|
||||
<LabledDropdown
|
||||
defaultOption={selectedItem.item.type || "Select Trigger Type"}
|
||||
options={["On-Hit", "Buffer"]}
|
||||
onSelect={(option) => handleTriggerSelect(selectedItem.item.uuid, option)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedPath && !selectedItem && (
|
||||
<div className="speed-control">
|
||||
<InputWithDropDown
|
||||
label="Path Speed"
|
||||
value={selectedPath.path.speed.toString()}
|
||||
onChange={(value) => handleSpeedChange(parseFloat(value))}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="footer">
|
||||
<InfoIcon />
|
||||
By selecting points, you can create events and triggers.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MachineMechanics;
|
|
@ -0,0 +1,561 @@
|
|||
import React, { useRef, useState, useMemo, useEffect } from "react";
|
||||
import {
|
||||
AddIcon,
|
||||
InfoIcon,
|
||||
RemoveIcon,
|
||||
ResizeHeightIcon,
|
||||
} from "../../../icons/ExportCommonIcons";
|
||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
|
||||
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
|
||||
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store";
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||
|
||||
const VehicleMechanics: React.FC = () => {
|
||||
const { selectedActionSphere } = useSelectedActionSphere();
|
||||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||
|
||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const selectedPoint = useMemo(() => {
|
||||
if (!selectedActionSphere) return null;
|
||||
return simulationPaths
|
||||
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
|
||||
.flatMap((path) => path.points)
|
||||
.find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||
}, [selectedActionSphere, simulationPaths]);
|
||||
|
||||
const handleAddAction = () => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => {
|
||||
if (path.type === "Conveyor") {
|
||||
return {
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
const actionIndex = point.actions.length;
|
||||
const newAction = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: `Action ${actionIndex + 1}`,
|
||||
type: 'Inherit',
|
||||
material: 'Inherit',
|
||||
delay: 'Inherit',
|
||||
spawnInterval: 'Inherit',
|
||||
isUsed: false
|
||||
};
|
||||
|
||||
return { ...point, actions: [...point.actions, newAction] };
|
||||
}
|
||||
return point;
|
||||
}),
|
||||
};
|
||||
}
|
||||
return path;
|
||||
});
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleDeleteAction = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleActionSelect = (uuid: string, actionType: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid
|
||||
? {
|
||||
...action,
|
||||
type: actionType,
|
||||
material: actionType === 'Spawn' || actionType === 'Swap' ? 'Inherit' : action.material,
|
||||
delay: actionType === 'Delay' ? 'Inherit' : action.delay,
|
||||
spawnInterval: actionType === 'Spawn' ? 'Inherit' : action.spawnInterval
|
||||
}
|
||||
: action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Update the selected item to reflect changes
|
||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||
const updatedAction = updatedPaths
|
||||
.filter((path): path is Types.ConveyorEventsSchema => path.type === "Conveyor")
|
||||
.flatMap(path => path.points)
|
||||
.find(p => p.uuid === selectedActionSphere.point.uuid)
|
||||
?.actions.find(a => a.uuid === uuid);
|
||||
|
||||
if (updatedAction) {
|
||||
setSelectedItem({
|
||||
type: "action",
|
||||
item: updatedAction
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Modified handleMaterialSelect to ensure it only applies to relevant action types
|
||||
const handleMaterialSelect = (uuid: string, material: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid &&
|
||||
(action.type === 'Spawn' || action.type === 'Swap')
|
||||
? { ...action, material }
|
||||
: action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Update selected item if it's the current action
|
||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||
setSelectedItem({
|
||||
...selectedItem,
|
||||
item: {
|
||||
...selectedItem.item,
|
||||
material
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelayChange = (uuid: string, delay: number | string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, delay } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, spawnInterval } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleSpeedChange = (speed: number) => {
|
||||
if (!selectedPath) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
|
||||
};
|
||||
|
||||
const handleAddTrigger = () => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
const triggerIndex = point.triggers.length;
|
||||
const newTrigger = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: `Trigger ${triggerIndex + 1}`,
|
||||
type: '',
|
||||
isUsed: false
|
||||
};
|
||||
|
||||
return { ...point, triggers: [...point.triggers, newTrigger] };
|
||||
}
|
||||
return point;
|
||||
}),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleDeleteTrigger = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
const handleTriggerSelect = (uuid: string, triggerType: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) =>
|
||||
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
// Update the toggle handlers to immediately update the selected item
|
||||
const handleActionToggle = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) => ({
|
||||
...action,
|
||||
isUsed: action.uuid === uuid ? !action.isUsed : false,
|
||||
})),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Immediately update the selected item if it's the one being toggled
|
||||
if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) {
|
||||
setSelectedItem({
|
||||
...selectedItem,
|
||||
item: {
|
||||
...selectedItem.item,
|
||||
isUsed: !selectedItem.item.isUsed
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Do the same for trigger toggle
|
||||
const handleTriggerToggle = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.type === "Conveyor"
|
||||
? {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) => ({
|
||||
...trigger,
|
||||
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
|
||||
})),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}
|
||||
: path
|
||||
);
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
|
||||
// Immediately update the selected item if it's the one being toggled
|
||||
if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) {
|
||||
setSelectedItem({
|
||||
...selectedItem,
|
||||
item: {
|
||||
...selectedItem.item,
|
||||
isUsed: !selectedItem.item.isUsed
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const [selectedItem, setSelectedItem] = useState<{ type: "action" | "trigger"; item: any; } | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedItem(null); // Reset selectedItem when selectedActionSphere changes
|
||||
}, [selectedActionSphere]);
|
||||
|
||||
return (
|
||||
<div className="machine-mechanics-container">
|
||||
<div className="machine-mechanics-header">
|
||||
{selectedActionSphere?.path?.modelName || "point name not found"}
|
||||
</div>
|
||||
|
||||
<div className="machine-mechanics-content-container">
|
||||
<div className="actions">
|
||||
<div className="header">
|
||||
<div className="header-value">Actions</div>
|
||||
<div className="add-button" onClick={handleAddAction}>
|
||||
<AddIcon /> Add
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={actionsContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
<>
|
||||
{console.log(selectedPoint)}
|
||||
</>
|
||||
</div>
|
||||
<div
|
||||
className="resize-icon"
|
||||
id="action-resize"
|
||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="triggers">
|
||||
<div className="header">
|
||||
<div className="header-value">Triggers</div>
|
||||
<div className="add-button" onClick={handleAddTrigger}>
|
||||
<AddIcon /> Add
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={triggersContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{selectedPoint?.triggers.map((trigger) => (
|
||||
<div
|
||||
key={trigger.uuid}
|
||||
className={`list-item ${selectedItem?.type === "trigger" &&
|
||||
selectedItem.item?.uuid === trigger.uuid
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
onClick={() => setSelectedItem({ type: "trigger", item: trigger })}
|
||||
>
|
||||
<RenameInput value={trigger.name} />
|
||||
</div>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleDeleteTrigger(trigger.uuid)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="resize-icon"
|
||||
id="trigger-resize"
|
||||
onMouseDown={(e) => handleResize(e, triggersContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="selected-properties-container">
|
||||
{selectedItem && (
|
||||
<>
|
||||
<div className="properties-header">{selectedItem.item.name}</div>
|
||||
|
||||
{selectedItem.type === "action" && (
|
||||
<>
|
||||
<InputToggle
|
||||
inputKey="enableTrigger"
|
||||
label="Enable Trigger"
|
||||
value={selectedItem.item.isUsed}
|
||||
onClick={() => handleActionToggle(selectedItem.item.uuid)}
|
||||
/>
|
||||
<LabledDropdown
|
||||
defaultOption={selectedItem.item.type}
|
||||
options={["Inherit", "Spawn", "Swap", "Despawn", "Delay"]}
|
||||
onSelect={(option) => handleActionSelect(selectedItem.item.uuid, option)}
|
||||
/>
|
||||
|
||||
{/* Only show material dropdown for Spawn/Swap actions */}
|
||||
{(selectedItem.item.type === 'Spawn' || selectedItem.item.type === 'Swap') && (
|
||||
<LabledDropdown
|
||||
label={selectedItem.item.type === 'Spawn' ? 'Spawn Material' : 'Swap Material'}
|
||||
defaultOption={selectedItem.item.material}
|
||||
options={["Inherit", "Crate", "Box"]}
|
||||
onSelect={(option) => handleMaterialSelect(selectedItem.item.uuid, option)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Only show delay input for Delay actions */}
|
||||
{selectedItem.item.type === 'Delay' && (
|
||||
<InputWithDropDown
|
||||
label="Delay Time"
|
||||
value={selectedItem.item.delay === 'Inherit'
|
||||
? undefined
|
||||
: selectedItem.item.delay}
|
||||
onChange={(value) => {
|
||||
const numValue = parseInt(value);
|
||||
handleDelayChange(
|
||||
selectedItem.item.uuid,
|
||||
!value ? 'Inherit' : numValue
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Only show spawn interval for Spawn actions */}
|
||||
{selectedItem.item.type === 'Spawn' && (
|
||||
<InputWithDropDown
|
||||
label="Spawn Interval"
|
||||
min={0}
|
||||
defaultValue={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
|
||||
value={selectedItem.item.spawnInterval === "Inherit" ? "" : selectedItem.item.spawnInterval.toString()}
|
||||
onChange={(value) => {
|
||||
handleSpawnIntervalChange(selectedItem.item.uuid, (value === "") ? "Inherit" : parseInt(value));
|
||||
}}
|
||||
/>
|
||||
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedItem.type === "trigger" && (
|
||||
<>
|
||||
<InputToggle
|
||||
inputKey="enableTrigger"
|
||||
label="Enable Trigger"
|
||||
value={selectedItem.item.isUsed}
|
||||
onClick={() => handleTriggerToggle(selectedItem.item.uuid)}
|
||||
/>
|
||||
|
||||
<LabledDropdown
|
||||
defaultOption={selectedItem.item.type || "Select Trigger Type"}
|
||||
options={["On-Hit", "Buffer"]}
|
||||
onSelect={(option) => handleTriggerSelect(selectedItem.item.uuid, option)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedPath && !selectedItem && (
|
||||
<div className="speed-control">
|
||||
<InputWithDropDown
|
||||
label="ConveyorEventsSchema Speed"
|
||||
value={selectedPath.path.speed.toString()}
|
||||
onChange={(value) => handleSpeedChange(parseFloat(value))}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="footer">
|
||||
<InfoIcon />
|
||||
By selecting points, you can create events and triggers.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VehicleMechanics;
|
|
@ -1,115 +1,215 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
|
||||
import { AddIcon } from '../../../../icons/ExportCommonIcons'
|
||||
import RegularDropDown from '../../../../ui/inputs/RegularDropDown'
|
||||
import useChartStore from '../../../../../store/useChartStore'
|
||||
import axios from 'axios'
|
||||
// import React, { useEffect, useState } from 'react'
|
||||
// import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
|
||||
// import { AddIcon } from '../../../../icons/ExportCommonIcons'
|
||||
// import RegularDropDown from '../../../../ui/inputs/RegularDropDown'
|
||||
// import useChartStore from '../../../../../store/useChartStore'
|
||||
// import axios from 'axios'
|
||||
|
||||
type Props = {}
|
||||
// type Props = {}
|
||||
|
||||
const LineGrapInput = (props: Props) => {
|
||||
const [dropDowndata, setDropDownData] = useState({})
|
||||
const [selections, setSelections] = useState<Record<string, { name: string, fields: string }>>({})
|
||||
const [selectedOption, setSelectedOption] = useState('1h')
|
||||
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
||||
// const LineGrapInput = (props: Props) => {
|
||||
// const [dropDowndata, setDropDownData] = useState({})
|
||||
// const [selections, setSelections] = useState<Record<string, { name: string, fields: string }>>({})
|
||||
// const [selectedOption, setSelectedOption] = useState('1h')
|
||||
// const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
||||
// const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
|
||||
const handleSelectDuration = (option: string) => {
|
||||
updateDuration(option); // Normalize for key matching
|
||||
};
|
||||
// const handleSelectDuration = (option: string) => {
|
||||
// updateDuration(option); // Normalize for key matching
|
||||
// };
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
try {
|
||||
const response = await axios.get('http://192.168.0.192:5010/getinput');
|
||||
if (response.status === 200) {
|
||||
console.log('dropdown data:', response.data);
|
||||
setDropDownData(response.data)
|
||||
} else {
|
||||
console.log('Unexpected response:', response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('There was an error!', error);
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
}, []);
|
||||
// useEffect(() => {
|
||||
// const fetchZoneData = async () => {
|
||||
// try {
|
||||
// const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||
// if (response.status === 200) {
|
||||
// console.log('dropdown data:', response.data);
|
||||
// setDropDownData(response.data)
|
||||
// } else {
|
||||
// console.log('Unexpected response:', response);
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('There was an error!', error);
|
||||
// }
|
||||
// };
|
||||
// fetchZoneData();
|
||||
// }, []);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(selections);
|
||||
}, [selections])
|
||||
// useEffect(() => {
|
||||
// console.log(selections);
|
||||
// }, [selections])
|
||||
|
||||
const handleSelect = (inputKey: string, selectedData: { name: string, fields: string } | null) => {
|
||||
setSelections(prev => {
|
||||
if (selectedData === null) {
|
||||
const newSelections = { ...prev };
|
||||
delete newSelections[inputKey];
|
||||
return newSelections;
|
||||
} else {
|
||||
return {
|
||||
...prev,
|
||||
[inputKey]: selectedData
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
// const handleSelect = (inputKey: string, selectedData: { name: string, fields: string } | null) => {
|
||||
// setSelections(prev => {
|
||||
// if (selectedData === null) {
|
||||
// const newSelections = { ...prev };
|
||||
// delete newSelections[inputKey];
|
||||
// return newSelections;
|
||||
// } else {
|
||||
// return {
|
||||
// ...prev,
|
||||
// [inputKey]: selectedData
|
||||
// };
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
interface Measurement {
|
||||
name: string;
|
||||
fields: string;
|
||||
}
|
||||
// interface Measurement {
|
||||
// name: string;
|
||||
// fields: string;
|
||||
// }
|
||||
|
||||
interface InputData {
|
||||
[key: string]: Measurement;
|
||||
}
|
||||
// interface InputData {
|
||||
// [key: string]: Measurement;
|
||||
// }
|
||||
|
||||
const extractMeasurements = (input: InputData): Measurement[] => {
|
||||
return Object.values(input);
|
||||
};
|
||||
// const extractMeasurements = (input: InputData): Measurement[] => {
|
||||
// return Object.values(input);
|
||||
// };
|
||||
|
||||
useEffect(() => {
|
||||
const measurementsData = extractMeasurements(selections);
|
||||
setMeasurements(measurementsData);
|
||||
}, [selections]);
|
||||
// useEffect(() => {
|
||||
// const measurementsData = extractMeasurements(selections);
|
||||
// setMeasurements(measurementsData);
|
||||
// }, [selections]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="inputs-wrapper">
|
||||
{[...Array(6)].map((_, index) => {
|
||||
const inputKey = `input${index + 1}`;
|
||||
return (
|
||||
<div key={index} className="datas">
|
||||
<div className="datas__label">Input {index + 1}</div>
|
||||
<div className="datas__class">
|
||||
<MultiLevelDropdown
|
||||
data={dropDowndata}
|
||||
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||
onUnselect={() => handleSelect(inputKey, null)}
|
||||
selectedValue={selections[inputKey]}
|
||||
/>
|
||||
<div className="icon">
|
||||
<AddIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<div className="datas">
|
||||
<div className="datas__label">duration</div>
|
||||
<div className="datas__class">
|
||||
<RegularDropDown
|
||||
header={duration}
|
||||
options={["1h", "2h", "12h"]}
|
||||
onSelect={handleSelectDuration}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
// return (
|
||||
// <>
|
||||
// <div className="inputs-wrapper">
|
||||
// {[...Array(6)].map((_, index) => {
|
||||
// const inputKey = `input${index + 1}`;
|
||||
// return (
|
||||
// <div key={index} className="datas">
|
||||
// <div className="datas__label">Input {index + 1}</div>
|
||||
// <div className="datas__class">
|
||||
// <MultiLevelDropdown
|
||||
// data={dropDowndata}
|
||||
// onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||
// onUnselect={() => handleSelect(inputKey, null)}
|
||||
// selectedValue={selections[inputKey]}
|
||||
// />
|
||||
// <div className="icon">
|
||||
// <AddIcon />
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// })}
|
||||
// </div>
|
||||
// <div>
|
||||
// <div className="datas">
|
||||
// <div className="datas__label">duration</div>
|
||||
// <div className="datas__class">
|
||||
// <RegularDropDown
|
||||
// header={duration}
|
||||
// options={["1h", "2h", "12h"]}
|
||||
// onSelect={handleSelectDuration}
|
||||
// search={false}
|
||||
// />
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </>
|
||||
// )
|
||||
// }
|
||||
|
||||
export default LineGrapInput
|
||||
// export default LineGrapInput
|
||||
|
||||
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||
import useChartStore from "../../../../../store/useChartStore";
|
||||
import axios from "axios";
|
||||
|
||||
type Props = {};
|
||||
|
||||
const LineGrapInput = (props: Props) => {
|
||||
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
||||
|
||||
const [dropDowndata, setDropDownData] = useState({});
|
||||
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>(measurements);
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
try {
|
||||
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||
if (response.status === 200) {
|
||||
console.log("dropdown data:", response.data);
|
||||
setDropDownData(response.data);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
}, []);
|
||||
|
||||
// Sync Zustand state when component mounts
|
||||
useEffect(() => {
|
||||
setSelections(measurements);
|
||||
}, [measurements]);
|
||||
|
||||
const handleSelect = (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||
setSelections((prev) => {
|
||||
const newSelections = { ...prev };
|
||||
if (selectedData === null) {
|
||||
delete newSelections[inputKey];
|
||||
} else {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
setMeasurements(newSelections); // Update Zustand store
|
||||
return newSelections;
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelectDuration = (option: string) => {
|
||||
updateDuration(option);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="inputs-wrapper">
|
||||
{[...Array(6)].map((_, index) => {
|
||||
const inputKey = `input${index + 1}`;
|
||||
return (
|
||||
<div key={index} className="datas">
|
||||
<div className="datas__label">Input {index + 1}</div>
|
||||
<div className="datas__class">
|
||||
<MultiLevelDropdown
|
||||
data={dropDowndata}
|
||||
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||
onUnselect={() => handleSelect(inputKey, null)}
|
||||
selectedValue={selections[inputKey]} // Load from Zustand
|
||||
/>
|
||||
<div className="icon">
|
||||
<AddIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<div className="datas">
|
||||
<div className="datas__label">Duration</div>
|
||||
<div className="datas__class">
|
||||
<RegularDropDown
|
||||
header={duration}
|
||||
options={["1h", "2h", "12h"]}
|
||||
onSelect={handleSelectDuration}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LineGrapInput;
|
||||
|
|
|
@ -8,11 +8,12 @@ type Props = {}
|
|||
const PieChartInput = (props: Props) => {
|
||||
const [dropDowndata, setDropDownData] = useState({})
|
||||
const [selections, setSelections] = useState<Record<string, {name: string, fields: string}>>({})
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
try {
|
||||
const response = await axios.get('http://192.168.0.192:5010/getinput');
|
||||
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||
if (response.status === 200) {
|
||||
console.log('dropdown data:', response.data);
|
||||
setDropDownData(response.data)
|
||||
|
|
|
@ -16,6 +16,7 @@ interface ButtonsProps {
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -33,6 +34,7 @@ interface ButtonsProps {
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -120,23 +122,39 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
console.log("updatedZone: ", updatedZone);
|
||||
setSelectedZone(updatedZone);
|
||||
} else {
|
||||
// If the panel is not active, activate it
|
||||
const newActiveSides = [...selectedZone.activeSides, side];
|
||||
const updatePanelData = async () => {
|
||||
try {
|
||||
// Get email and organization safely
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg"; // Fallback value
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
activeSides: newActiveSides,
|
||||
panelOrder: newActiveSides,
|
||||
// Prevent duplicate side entries
|
||||
const newActiveSides = selectedZone.activeSides.includes(side)
|
||||
? [...selectedZone.activeSides]
|
||||
: [...selectedZone.activeSides, side];
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
activeSides: newActiveSides,
|
||||
panelOrder: newActiveSides,
|
||||
};
|
||||
|
||||
// API call
|
||||
const response = await panelData(organization, selectedZone.zoneId, newActiveSides);
|
||||
console.log("response: ", response);
|
||||
|
||||
// Update state
|
||||
console.log("updatedZone: ", updatedZone);
|
||||
setSelectedZone(updatedZone);
|
||||
} catch (error) {
|
||||
console.error("Error updating panel data:", error);
|
||||
}
|
||||
};
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
// let response = panelData(organization, selectedZone.zoneId, newActiveSides)
|
||||
// console.log('response: ', response);
|
||||
|
||||
// Update the selectedZone state
|
||||
console.log("updatedZone: ", updatedZone);
|
||||
setSelectedZone(updatedZone);
|
||||
updatePanelData(); // Call the async function
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -146,9 +164,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
<div key={side} className={`side-button-container ${side}`}>
|
||||
{/* "+" Button */}
|
||||
<button
|
||||
className={`side-button ${side}${
|
||||
selectedZone.activeSides.includes(side) ? " active" : ""
|
||||
}`}
|
||||
className={`side-button ${side}${selectedZone.activeSides.includes(side) ? " active" : ""
|
||||
}`}
|
||||
onClick={() => handlePlusButtonClick(side)}
|
||||
title={
|
||||
selectedZone.activeSides.includes(side)
|
||||
|
@ -166,9 +183,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
<div className="extra-Bs">
|
||||
{/* Hide Panel */}
|
||||
<div
|
||||
className={`icon ${
|
||||
hiddenPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
className={`icon ${hiddenPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
|
||||
}
|
||||
|
@ -190,9 +206,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
|
||||
{/* Lock/Unlock Panel */}
|
||||
<div
|
||||
className={`icon ${
|
||||
selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
selectedZone.lockedPanels.includes(side)
|
||||
? "Unlock Panel"
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Widget } from "../../../store/useWidgetStore";
|
|||
import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons";
|
||||
import { InfoIcon } from "../../icons/ExportCommonIcons";
|
||||
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
||||
import { getSelect2dZoneData } from "../../../services/realTimeVisulization/zoneData/getSelect2dZoneData";
|
||||
|
||||
// Define the type for `Side`
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
@ -12,6 +13,7 @@ interface DisplayZoneProps {
|
|||
[key: string]: {
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
zoneId: string;
|
||||
|
@ -23,6 +25,7 @@ interface DisplayZoneProps {
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -40,6 +43,7 @@ interface DisplayZoneProps {
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -60,6 +64,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||
selectedZone,
|
||||
setSelectedZone,
|
||||
}) => {
|
||||
|
||||
// Ref for the container element
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
|
@ -141,6 +146,24 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||
}
|
||||
};
|
||||
|
||||
async function handleSelect2dZoneData(zoneId: string, zoneName: string) {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]
|
||||
let response = await getSelect2dZoneData(zoneId, organization)
|
||||
setSelectedZone({
|
||||
zoneName,
|
||||
activeSides: response.activeSides,
|
||||
panelOrder: response.panelOrder,
|
||||
lockedPanels: response.lockedPanels,
|
||||
widgets: response.widgets,
|
||||
zoneId: zoneId,
|
||||
zoneViewPortTarget:
|
||||
response.viewPortCenter,
|
||||
zoneViewPortPosition:
|
||||
response.viewPortposition,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
|
@ -161,23 +184,11 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||
{Object.keys(zonesData).map((zoneName, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`zone ${
|
||||
selectedZone.zoneName === zoneName ? "active" : ""
|
||||
}`}
|
||||
className={`zone ${selectedZone.zoneName === zoneName ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
useDroppedObjectsStore.getState().setZone(zoneName, zonesData[zoneName]?.zoneId);
|
||||
setSelectedZone({
|
||||
zoneName,
|
||||
activeSides: zonesData[zoneName].activeSides || [],
|
||||
panelOrder: zonesData[zoneName].panelOrder || [],
|
||||
lockedPanels: zonesData[zoneName].lockedPanels || [],
|
||||
widgets: zonesData[zoneName].widgets || [],
|
||||
zoneId: zonesData[zoneName]?.zoneId || "",
|
||||
zoneViewPortTarget:
|
||||
zonesData[zoneName].zoneViewPortTarget || [],
|
||||
zoneViewPortPosition:
|
||||
zonesData[zoneName].zoneViewPortPosition || [],
|
||||
});
|
||||
handleSelect2dZoneData(zonesData[zoneName]?.zoneId, zoneName)
|
||||
}}
|
||||
>
|
||||
{zoneName}
|
||||
|
|
|
@ -36,6 +36,7 @@ export const DraggableWidget = ({
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
widgets: Widget[];
|
||||
};
|
||||
|
@ -44,6 +45,7 @@ export const DraggableWidget = ({
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -78,9 +80,11 @@ export const DraggableWidget = ({
|
|||
const isPanelHidden = hiddenPanels.includes(widget.panel);
|
||||
|
||||
const deleteSelectedChart = () => {
|
||||
console.log('widget.id: ', widget.id);
|
||||
const updatedWidgets = selectedZone.widgets.filter(
|
||||
(w: Widget) => w.id !== widget.id
|
||||
);
|
||||
console.log('updatedWidgets: ', updatedWidgets);
|
||||
|
||||
setSelectedZone((prevZone: any) => ({
|
||||
...prevZone,
|
||||
|
@ -122,7 +126,6 @@ export const DraggableWidget = ({
|
|||
...widget,
|
||||
id: `${widget.id}-copy-${Date.now()}`,
|
||||
};
|
||||
|
||||
setSelectedZone((prevZone: any) => ({
|
||||
...prevZone,
|
||||
widgets: [...prevZone.widgets, duplicatedWidget],
|
||||
|
@ -130,7 +133,7 @@ export const DraggableWidget = ({
|
|||
|
||||
setOpenKebabId(null);
|
||||
|
||||
console.log("Duplicated widget with ID:", duplicatedWidget.id);
|
||||
|
||||
};
|
||||
|
||||
const handleKebabClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||
|
@ -173,6 +176,7 @@ export const DraggableWidget = ({
|
|||
};
|
||||
|
||||
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
|
||||
|
||||
event.preventDefault();
|
||||
const fromIndex = parseInt(event.dataTransfer.getData("text/plain"), 10); // Get the dragged widget's index
|
||||
const toIndex = index; // The index of the widget where the drop occurred
|
||||
|
@ -186,9 +190,8 @@ export const DraggableWidget = ({
|
|||
<div
|
||||
draggable
|
||||
key={widget.id}
|
||||
className={`chart-container ${
|
||||
selectedChartId?.id === widget.id && "activeChart"
|
||||
}`}
|
||||
className={`chart-container ${selectedChartId?.id === widget.id && "activeChart"
|
||||
}`}
|
||||
onPointerDown={handlePointerDown}
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnter={handleDragEnter}
|
||||
|
@ -208,9 +211,8 @@ export const DraggableWidget = ({
|
|||
{openKebabId === widget.id && (
|
||||
<div className="kebab-options" ref={widgetRef}>
|
||||
<div
|
||||
className={`edit btn ${
|
||||
isPanelFull(widget.panel) ? "btn-blur" : ""
|
||||
}`}
|
||||
className={`edit btn ${isPanelFull(widget.panel) ? "btn-blur" : ""
|
||||
}`}
|
||||
onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget}
|
||||
>
|
||||
<div className="icon">
|
||||
|
@ -237,14 +239,14 @@ export const DraggableWidget = ({
|
|||
title={widget.title}
|
||||
fontSize={widget.fontSize}
|
||||
fontWeight={widget.fontWeight}
|
||||
data={{
|
||||
measurements: [
|
||||
{ name: "testDevice", fields: "powerConsumption" },
|
||||
{ name: "furnace", fields: "powerConsumption" },
|
||||
],
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
}}
|
||||
// data={{
|
||||
// measurements: [
|
||||
// { name: "testDevice", fields: "powerConsumption" },
|
||||
// { name: "furnace", fields: "powerConsumption" },
|
||||
// ],
|
||||
// interval: 1000,
|
||||
// duration: "1h",
|
||||
// }}
|
||||
/>
|
||||
)}
|
||||
{widget.type === "bar" && (
|
||||
|
@ -253,14 +255,14 @@ export const DraggableWidget = ({
|
|||
title={widget.title}
|
||||
fontSize={widget.fontSize}
|
||||
fontWeight={widget.fontWeight}
|
||||
data={{
|
||||
measurements: [
|
||||
{ name: "testDevice", fields: "powerConsumption" },
|
||||
{ name: "furnace", fields: "powerConsumption" },
|
||||
],
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
}}
|
||||
// data={{
|
||||
// measurements: [
|
||||
// { name: "testDevice", fields: "powerConsumption" },
|
||||
// { name: "furnace", fields: "powerConsumption" },
|
||||
// ],
|
||||
// interval: 1000,
|
||||
// duration: "1h",
|
||||
// }}
|
||||
/>
|
||||
)}
|
||||
{widget.type === "pie" && (
|
||||
|
@ -269,14 +271,14 @@ export const DraggableWidget = ({
|
|||
title={widget.title}
|
||||
fontSize={widget.fontSize}
|
||||
fontWeight={widget.fontWeight}
|
||||
data={{
|
||||
measurements: [
|
||||
{ name: "testDevice", fields: "powerConsumption" },
|
||||
{ name: "furnace", fields: "powerConsumption" },
|
||||
],
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
}}
|
||||
// data={{
|
||||
// measurements: [
|
||||
// { name: "testDevice", fields: "powerConsumption" },
|
||||
// { name: "furnace", fields: "powerConsumption" },
|
||||
// ],
|
||||
// interval: 1000,
|
||||
// duration: "1h",
|
||||
// }}
|
||||
/>
|
||||
)}
|
||||
{widget.type === "doughnut" && (
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useAsset3dWidget } from "../../../store/store";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
import { ThreeState } from "../../../types/world/worldTypes";
|
||||
import * as THREE from "three";
|
||||
import Throughput from "../../layout/3D-cards/cards/Throughput";
|
||||
import ProductionCapacity from "../../layout/3D-cards/cards/ProductionCapacity";
|
||||
import ReturnOfInvestment from "../../layout/3D-cards/cards/ReturnOfInvestment";
|
||||
import StateWorking from "../../layout/3D-cards/cards/StateWorking";
|
||||
|
||||
export default function Dropped3dWidgets() {
|
||||
const { widgetSelect } = useAsset3dWidget();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { raycaster, gl, scene }: ThreeState = useThree();
|
||||
|
||||
// 🔥 Store multiple instances per widget type
|
||||
const [widgetPositions, setWidgetPositions] = useState<Record<string, [number, number, number][]>>({});
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModule !== "visualization") return;
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
const onDrop = (event: DragEvent) => {
|
||||
event.preventDefault(); // Prevent default browser behavior
|
||||
|
||||
if (!widgetSelect.startsWith("ui")) return;
|
||||
|
||||
|
||||
const group1 = scene.getObjectByName("itemsGroup");
|
||||
if (!group1) return;
|
||||
|
||||
|
||||
|
||||
const Assets = group1.children
|
||||
.map((val) => scene.getObjectByProperty("uuid", val.uuid))
|
||||
.filter(Boolean) as THREE.Object3D[];
|
||||
|
||||
|
||||
const intersects = raycaster.intersectObjects(Assets);
|
||||
|
||||
if (intersects.length > 0) {
|
||||
const { x, y, z } = intersects[0].point;
|
||||
|
||||
|
||||
// ✅ Allow multiple instances by storing positions in an array
|
||||
setWidgetPositions((prev) => ({
|
||||
...prev,
|
||||
[widgetSelect]: [...(prev[widgetSelect] || []), [x, y, z]],
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
};
|
||||
}, [widgetSelect, activeModule]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{widgetPositions["ui-Widget 1"]?.map((pos, index) => (
|
||||
<ProductionCapacity key={`Widget1-${index}`} position={pos} />
|
||||
))}
|
||||
{widgetPositions["ui-Widget 2"]?.map((pos, index) => (
|
||||
<ReturnOfInvestment key={`Widget2-${index}`} position={pos} />
|
||||
))}
|
||||
{widgetPositions["ui-Widget 3"]?.map((pos, index) => (
|
||||
<StateWorking key={`Widget3-${index}`} position={pos} />
|
||||
))}
|
||||
{widgetPositions["ui-Widget 4"]?.map((pos, index) => (
|
||||
<Throughput key={`Widget4-${index}`} position={pos} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import { useDroppedObjectsStore, Zones } from "../../../store/useDroppedObjectsS
|
|||
|
||||
const DroppedObjects: React.FC = () => {
|
||||
const zones = useDroppedObjectsStore((state) => state.zones);
|
||||
|
||||
const updateObjectPosition = useDroppedObjectsStore((state) => state.updateObjectPosition);
|
||||
const [draggingIndex, setDraggingIndex] = useState<{ zone: string; index: number } | null>(null);
|
||||
const [offset, setOffset] = useState<[number, number] | null>(null);
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useWidgetStore } from "../../../store/useWidgetStore";
|
|||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
import { DraggableWidget } from "./DraggableWidget";
|
||||
import { arrayMove } from "@dnd-kit/sortable";
|
||||
import { addingWidgets } from "../../../services/realTimeVisulization/zoneData/addWidgets";
|
||||
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
|
@ -19,6 +20,7 @@ interface PanelProps {
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -30,6 +32,7 @@ interface PanelProps {
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -72,9 +75,8 @@ const Panel: React.FC<PanelProps> = ({
|
|||
case "top":
|
||||
case "bottom":
|
||||
return {
|
||||
width: `calc(100% - ${
|
||||
(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
|
||||
}px)`,
|
||||
width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
|
||||
}px)`,
|
||||
height: `${panelSize - 2}px`,
|
||||
left: leftActive ? `${panelSize}px` : "0",
|
||||
right: rightActive ? `${panelSize}px` : "0",
|
||||
|
@ -84,9 +86,8 @@ const Panel: React.FC<PanelProps> = ({
|
|||
case "right":
|
||||
return {
|
||||
width: `${panelSize - 2}px`,
|
||||
height: `calc(100% - ${
|
||||
(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
|
||||
}px)`,
|
||||
height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
|
||||
}px)`,
|
||||
top: topActive ? `${panelSize}px` : "0",
|
||||
bottom: bottomActive ? `${panelSize}px` : "0",
|
||||
[side]: "0",
|
||||
|
@ -99,6 +100,7 @@ const Panel: React.FC<PanelProps> = ({
|
|||
);
|
||||
|
||||
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
||||
|
||||
e.preventDefault();
|
||||
const { draggedAsset } = useWidgetStore.getState();
|
||||
if (!draggedAsset) return;
|
||||
|
@ -109,8 +111,6 @@ const Panel: React.FC<PanelProps> = ({
|
|||
|
||||
if (currentWidgetsCount >= maxCapacity) return;
|
||||
|
||||
console.log("draggedAsset: ", draggedAsset);
|
||||
console.log("panel: ", panel);
|
||||
addWidgetToPanel(draggedAsset, panel);
|
||||
};
|
||||
|
||||
|
@ -139,17 +139,27 @@ const Panel: React.FC<PanelProps> = ({
|
|||
};
|
||||
|
||||
// while dublicate check this and add
|
||||
const addWidgetToPanel = (asset: any, panel: Side) => {
|
||||
const addWidgetToPanel = async (asset: any, panel: Side) => {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]
|
||||
const newWidget = {
|
||||
...asset,
|
||||
id: generateUniqueId(),
|
||||
panel,
|
||||
};
|
||||
try {
|
||||
let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
|
||||
console.log("response: ", response);
|
||||
if (response.message === "Widget created successfully") {
|
||||
setSelectedZone((prev) => ({
|
||||
...prev,
|
||||
widgets: [...prev.widgets, newWidget],
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error adding widget:", error);
|
||||
}
|
||||
|
||||
setSelectedZone((prev) => ({
|
||||
...prev,
|
||||
widgets: [...prev.widgets, newWidget],
|
||||
}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -180,7 +190,7 @@ const Panel: React.FC<PanelProps> = ({
|
|||
|
||||
const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => {
|
||||
if (!selectedZone) return; // Ensure selectedZone is not null
|
||||
console.log("selectedZone: ", selectedZone);
|
||||
|
||||
|
||||
setSelectedZone((prev) => {
|
||||
if (!prev) return prev; // Ensure prev is not null
|
||||
|
|
|
@ -9,7 +9,9 @@ import useModuleStore from "../../../store/useModuleStore";
|
|||
|
||||
import DroppedObjects from "./DroppedFloatingWidgets";
|
||||
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
||||
import { useZones } from "../../../store/store";
|
||||
import { useAsset3dWidget, useZones } from "../../../store/store";
|
||||
import { getZoneData } from "../../../services/realTimeVisulization/zoneData/getZones";
|
||||
import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/getZoneData";
|
||||
|
||||
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
@ -19,6 +21,7 @@ type FormattedZoneData = Record<
|
|||
{
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -43,25 +46,38 @@ const RealTimeVisulization: React.FC = () => {
|
|||
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
|
||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||
const { zones } = useZones()
|
||||
|
||||
const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({});
|
||||
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
||||
useEffect(() => {
|
||||
const data = Array.isArray(zones) ? zones : [];
|
||||
async function GetZoneData() {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
try {
|
||||
const response = await getZone2dData(organization);
|
||||
if (!Array.isArray(response)) {
|
||||
return;
|
||||
}
|
||||
const formattedData = response.reduce<FormattedZoneData>((acc, zone) => {
|
||||
acc[zone.zoneName] = {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
zoneId: zone.zoneId,
|
||||
zoneViewPortTarget: zone.viewPortCenter,
|
||||
zoneViewPortPosition: zone.viewPortposition,
|
||||
widgets: [],
|
||||
};
|
||||
return acc;
|
||||
}, {});
|
||||
setZonesData(formattedData);
|
||||
} catch (error) {
|
||||
console.log('error: ', error);
|
||||
}
|
||||
}
|
||||
|
||||
const formattedData = data.reduce<FormattedZoneData>((acc, zone) => {
|
||||
acc[zone.zoneName] = {
|
||||
activeSides: [],
|
||||
panelOrder: [],
|
||||
lockedPanels: [],
|
||||
zoneId: zone.zoneId,
|
||||
zoneViewPortTarget: zone.viewPortCenter,
|
||||
zoneViewPortPosition: zone.viewPortposition,
|
||||
widgets: [],
|
||||
};
|
||||
return acc;
|
||||
}, {});
|
||||
GetZoneData();
|
||||
}, []); // Removed `zones` from dependencies
|
||||
|
||||
setZonesData(formattedData);
|
||||
}, [zones]);
|
||||
|
||||
useEffect(() => {
|
||||
setZonesData((prev) => {
|
||||
|
@ -81,37 +97,47 @@ const RealTimeVisulization: React.FC = () => {
|
|||
};
|
||||
});
|
||||
}, [selectedZone]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
}, [floatingWidgets])
|
||||
|
||||
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
const data = event.dataTransfer.getData("text/plain");
|
||||
if (!data || !selectedZone.zoneName) return;
|
||||
|
||||
if (widgetSelect !== "") return;
|
||||
if (!data || selectedZone.zoneName === "") return;
|
||||
|
||||
const droppedData = JSON.parse(data);
|
||||
const canvasElement = document.getElementById("real-time-vis-canvas");
|
||||
if (!canvasElement) return;
|
||||
|
||||
|
||||
const canvasRect = canvasElement.getBoundingClientRect();
|
||||
const relativeX = event.clientX - canvasRect.left;
|
||||
const relativeY = event.clientY - canvasRect.top;
|
||||
|
||||
|
||||
const newObject = {
|
||||
...droppedData,
|
||||
position: [relativeY, relativeX], // Y first because of top/left style
|
||||
};
|
||||
|
||||
console.log("newObject: ", newObject);
|
||||
|
||||
// Only set zone if it’s not already in the store (prevents overwriting objects)
|
||||
const existingZone = useDroppedObjectsStore.getState().zones[selectedZone.zoneName];
|
||||
if (!existingZone) {
|
||||
useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId);
|
||||
}
|
||||
|
||||
// Add the dropped object to the zone
|
||||
useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, newObject);
|
||||
setFloatingWidgets((prevWidgets) => ({
|
||||
...prevWidgets,
|
||||
[selectedZone.zoneName]: {
|
||||
...prevWidgets[selectedZone.zoneName],
|
||||
zoneName: selectedZone.zoneName,
|
||||
zoneId: selectedZone.zoneId,
|
||||
objects: [...(prevWidgets[selectedZone.zoneName]?.objects || []), newObject],
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -123,6 +149,7 @@ const RealTimeVisulization: React.FC = () => {
|
|||
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
||||
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
||||
}}
|
||||
|
||||
>
|
||||
<div
|
||||
className="scene-container"
|
||||
|
|
|
@ -1,6 +1,195 @@
|
|||
import { useMemo } from "react";
|
||||
// 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<HTMLCanvasElement>(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 <Bar data={measurements && measurements.length > 0 ? chartData : defaultData} options={options} />;
|
||||
// };
|
||||
|
||||
// export default LineGraphComponent;
|
||||
|
||||
|
||||
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { Bar } from "react-chartjs-2";
|
||||
import io from "socket.io-client";
|
||||
import { useThemeStore } from "../../../../store/useThemeStore";
|
||||
import useChartStore from "../../../../store/useChartStore";
|
||||
|
||||
interface ChartComponentProps {
|
||||
type: any;
|
||||
|
@ -8,16 +197,42 @@ interface ChartComponentProps {
|
|||
fontFamily?: string;
|
||||
fontSize?: string;
|
||||
fontWeight?: "Light" | "Regular" | "Bold";
|
||||
data: any;
|
||||
}
|
||||
|
||||
const LineGraphComponent = ({
|
||||
const BarGraphComponent = ({
|
||||
type,
|
||||
title,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontWeight = "Regular",
|
||||
}: ChartComponentProps) => {
|
||||
// Memoize Font Weight Mapping
|
||||
const { themeColor } = useThemeStore();
|
||||
const { measurements, duration } = useChartStore(); // Zustand Store
|
||||
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: "#b392f0",
|
||||
borderWidth: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Memoize Theme Colors
|
||||
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
|
||||
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
|
||||
|
||||
// Memoize Font Styling
|
||||
const chartFontWeightMap = useMemo(
|
||||
() => ({
|
||||
Light: "lighter" as const,
|
||||
|
@ -27,19 +242,9 @@ const LineGraphComponent = ({
|
|||
[]
|
||||
);
|
||||
|
||||
// Parse and Memoize Font Size
|
||||
const fontSizeValue = useMemo(
|
||||
() => (fontSize ? parseInt(fontSize) : 12),
|
||||
[fontSize]
|
||||
);
|
||||
const fontSizeValue = useMemo(() => (fontSize ? parseInt(fontSize) : 12), [fontSize]);
|
||||
const fontWeightValue = useMemo(() => chartFontWeightMap[fontWeight], [fontWeight, chartFontWeightMap]);
|
||||
|
||||
// Determine and Memoize Font Weight
|
||||
const fontWeightValue = useMemo(
|
||||
() => chartFontWeightMap[fontWeight],
|
||||
[fontWeight, chartFontWeightMap]
|
||||
);
|
||||
|
||||
// Memoize Chart Font Style
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
|
@ -49,6 +254,7 @@ const LineGraphComponent = ({
|
|||
[fontFamily, fontSizeValue, fontWeightValue]
|
||||
);
|
||||
|
||||
// Memoized Chart Options
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
responsive: true,
|
||||
|
@ -66,7 +272,7 @@ const LineGraphComponent = ({
|
|||
scales: {
|
||||
x: {
|
||||
ticks: {
|
||||
display: false, // This hides the x-axis labels
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -74,21 +280,53 @@ const LineGraphComponent = ({
|
|||
[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,
|
||||
},
|
||||
],
|
||||
};
|
||||
useEffect(() => {
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||
|
||||
return <Bar data={chartData} options={options} />;
|
||||
const socket = io(`http://${iotApiUrl}`);
|
||||
|
||||
const inputData = {
|
||||
measurements,
|
||||
duration,
|
||||
interval: 1000,
|
||||
};
|
||||
|
||||
const startStream = () => {
|
||||
socket.emit("lineInput", inputData);
|
||||
};
|
||||
|
||||
socket.on("connect", startStream);
|
||||
|
||||
socket.on("lineOutput", (response) => {
|
||||
const responseData = response.data;
|
||||
console.log("Received data:", responseData);
|
||||
|
||||
// Extract timestamps and values
|
||||
const labels = responseData.time;
|
||||
const datasets = Object.keys(measurements).map((key) => {
|
||||
const measurement = measurements[key];
|
||||
const datasetKey = `${measurement.name}.${measurement.fields}`;
|
||||
return {
|
||||
label: datasetKey,
|
||||
data: responseData[datasetKey]?.values ?? [],
|
||||
backgroundColor: "#6f42c1",
|
||||
borderColor: "#b392f0",
|
||||
borderWidth: 1,
|
||||
};
|
||||
});
|
||||
|
||||
setChartData({ labels, datasets });
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.off("lineOutput");
|
||||
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||
socket.disconnect();
|
||||
};
|
||||
}, [measurements, duration, iotApiUrl]);
|
||||
|
||||
return <Bar data={Object.keys(measurements).length > 0 ? chartData : defaultData} options={options} />;
|
||||
};
|
||||
|
||||
export default LineGraphComponent;
|
||||
export default BarGraphComponent;
|
||||
|
||||
|
|
|
@ -1,115 +1,15 @@
|
|||
// 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: true, // 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 <Line data={chartData} options={options} />;
|
||||
// };
|
||||
|
||||
// export default LineGraphComponent;
|
||||
|
||||
|
||||
import React, { useEffect, useRef, useMemo, useState } from "react";
|
||||
import { Chart } from "chart.js/auto";
|
||||
import { useThemeStore } from "../../../../store/useThemeStore";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { Line } from "react-chartjs-2";
|
||||
import io from "socket.io-client";
|
||||
import { Line } from 'react-chartjs-2';
|
||||
import { useThemeStore } from "../../../../store/useThemeStore";
|
||||
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 = ({
|
||||
|
@ -118,60 +18,55 @@ const LineGraphComponent = ({
|
|||
fontFamily,
|
||||
fontSize,
|
||||
fontWeight = "Regular",
|
||||
data,
|
||||
}: ChartComponentProps) => {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const { themeColor } = useThemeStore();
|
||||
const { measurements, duration } = useChartStore(); // Zustand Store
|
||||
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
|
||||
labels: [],
|
||||
datasets: [],
|
||||
});
|
||||
|
||||
// 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]);
|
||||
|
||||
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: "#b392f0",
|
||||
borderWidth: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Memoize Theme Colors
|
||||
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
|
||||
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
|
||||
|
||||
// Memoize Font Styling
|
||||
const chartFontWeightMap = useMemo(
|
||||
() => ({
|
||||
Light: "lighter" as const,
|
||||
Regular: "normal" as const,
|
||||
Bold: "bold" as const,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const fontSizeValue = useMemo(() => (fontSize ? parseInt(fontSize) : 12), [fontSize]);
|
||||
const fontWeightValue = useMemo(() => chartFontWeightMap[fontWeight], [fontWeight, chartFontWeightMap]);
|
||||
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
size: fontSizeValue,
|
||||
weight: fontWeightValue,
|
||||
}),
|
||||
[fontFamily, fontSizeValue, fontWeightValue]
|
||||
);
|
||||
|
||||
// Memoize Chart Options
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
|
@ -198,67 +93,54 @@ const LineGraphComponent = ({
|
|||
[title, chartFontStyle]
|
||||
);
|
||||
|
||||
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
||||
useEffect(() => {console.log(measurements);
|
||||
},[measurements])
|
||||
|
||||
useEffect(() => {
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||
|
||||
const socket = io("http://192.168.0.192:5010");
|
||||
const socket = io(`http://${iotApiUrl}`);
|
||||
|
||||
if ( measurements.length > 0 ) {
|
||||
var inputes = {
|
||||
measurements: measurements,
|
||||
duration: duration,
|
||||
interval: 1000,
|
||||
}
|
||||
const inputData = {
|
||||
measurements,
|
||||
duration,
|
||||
interval: 1000,
|
||||
};
|
||||
|
||||
// Start stream
|
||||
const startStream = () => {
|
||||
socket.emit("lineInput", inputes);
|
||||
}
|
||||
socket.emit("lineInput", inputData);
|
||||
};
|
||||
|
||||
socket.on('connect', startStream);
|
||||
socket.on("connect", startStream);
|
||||
|
||||
socket.on("lineOutput", (response) => {
|
||||
const responceData = response.data;
|
||||
console.log("Received data:", responceData);
|
||||
const responseData = response.data;
|
||||
|
||||
// Extract timestamps and values
|
||||
const labels = responceData.time;
|
||||
const datasets = measurements.map((measurement: any) => {
|
||||
const key = `${measurement.name}.${measurement.fields}`;
|
||||
const labels = responseData.time;
|
||||
const datasets = Object.keys(measurements).map((key) => {
|
||||
const measurement = measurements[key];
|
||||
const datasetKey = `${measurement.name}.${measurement.fields}`;
|
||||
return {
|
||||
label: key,
|
||||
data: responceData[key]?.values ?? [], // Ensure it exists
|
||||
backgroundColor: themeColor[0] || "#5c87df",
|
||||
borderColor: themeColor[1] || "#ffffff",
|
||||
label: datasetKey,
|
||||
data: responseData[datasetKey]?.values ?? [],
|
||||
backgroundColor: "#6f42c1",
|
||||
borderColor: "#b392f0",
|
||||
borderWidth: 1,
|
||||
};
|
||||
});
|
||||
|
||||
setChartData({ labels, datasets });
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
socket.off("lineOutput");
|
||||
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||
socket.disconnect();
|
||||
};
|
||||
}, [measurements, duration]);
|
||||
}, [measurements, duration, iotApiUrl]);
|
||||
|
||||
// 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 <Line data={chartData} options={options} />;
|
||||
return <Line data={Object.keys(measurements).length > 0 ? chartData : defaultData} options={options} />;
|
||||
};
|
||||
|
||||
export default LineGraphComponent;
|
||||
export default LineGraphComponent;
|
||||
|
|
|
@ -1,5 +1,195 @@
|
|||
import { useMemo } from "react";
|
||||
// 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<HTMLCanvasElement>(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 <Pie data={measurements && measurements.length > 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";
|
||||
import { useThemeStore } from "../../../../store/useThemeStore";
|
||||
import useChartStore from "../../../../store/useChartStore";
|
||||
|
||||
interface ChartComponentProps {
|
||||
type: any;
|
||||
|
@ -7,16 +197,42 @@ interface ChartComponentProps {
|
|||
fontFamily?: string;
|
||||
fontSize?: string;
|
||||
fontWeight?: "Light" | "Regular" | "Bold";
|
||||
data: any;
|
||||
}
|
||||
|
||||
const PieChartComponent = ({
|
||||
type,
|
||||
title,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontWeight = "Regular",
|
||||
}: ChartComponentProps) => {
|
||||
// Memoize Font Weight Mapping
|
||||
const { themeColor } = useThemeStore();
|
||||
const { measurements, duration } = useChartStore(); // Zustand Store
|
||||
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: "#b392f0",
|
||||
borderWidth: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Memoize Theme Colors
|
||||
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
|
||||
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
|
||||
|
||||
// Memoize Font Styling
|
||||
const chartFontWeightMap = useMemo(
|
||||
() => ({
|
||||
Light: "lighter" as const,
|
||||
|
@ -26,19 +242,9 @@ const PieChartComponent = ({
|
|||
[]
|
||||
);
|
||||
|
||||
// Parse and Memoize Font Size
|
||||
const fontSizeValue = useMemo(
|
||||
() => (fontSize ? parseInt(fontSize) : 12),
|
||||
[fontSize]
|
||||
);
|
||||
const fontSizeValue = useMemo(() => (fontSize ? parseInt(fontSize) : 12), [fontSize]);
|
||||
const fontWeightValue = useMemo(() => chartFontWeightMap[fontWeight], [fontWeight, chartFontWeightMap]);
|
||||
|
||||
// Determine and Memoize Font Weight
|
||||
const fontWeightValue = useMemo(
|
||||
() => chartFontWeightMap[fontWeight],
|
||||
[fontWeight, chartFontWeightMap]
|
||||
);
|
||||
|
||||
// Memoize Chart Font Style
|
||||
const chartFontStyle = useMemo(
|
||||
() => ({
|
||||
family: fontFamily || "Arial",
|
||||
|
@ -48,12 +254,7 @@ const PieChartComponent = ({
|
|||
[fontFamily, fontSizeValue, fontWeightValue]
|
||||
);
|
||||
|
||||
// Access the CSS variable for the primary accent color
|
||||
const accentColor = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--accent-color")
|
||||
.trim();
|
||||
|
||||
console.log("accentColor: ", accentColor);
|
||||
// Memoized Chart Options
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
responsive: true,
|
||||
|
@ -68,24 +269,64 @@ const PieChartComponent = ({
|
|||
display: false,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
// x: {
|
||||
// ticks: {
|
||||
// display: true,
|
||||
// },
|
||||
// },
|
||||
},
|
||||
}),
|
||||
[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,
|
||||
},
|
||||
],
|
||||
};
|
||||
useEffect(() => {
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||
|
||||
return <Pie data={chartData} options={options} />;
|
||||
const socket = io(`http://${iotApiUrl}`);
|
||||
|
||||
const inputData = {
|
||||
measurements,
|
||||
duration,
|
||||
interval: 1000,
|
||||
};
|
||||
|
||||
const startStream = () => {
|
||||
socket.emit("lineInput", inputData);
|
||||
};
|
||||
|
||||
socket.on("connect", startStream);
|
||||
|
||||
socket.on("lineOutput", (response) => {
|
||||
const responseData = response.data;
|
||||
console.log("Received data:", responseData);
|
||||
|
||||
// Extract timestamps and values
|
||||
const labels = responseData.time;
|
||||
const datasets = Object.keys(measurements).map((key) => {
|
||||
const measurement = measurements[key];
|
||||
const datasetKey = `${measurement.name}.${measurement.fields}`;
|
||||
return {
|
||||
label: datasetKey,
|
||||
data: responseData[datasetKey]?.values ?? [],
|
||||
backgroundColor: "#6f42c1",
|
||||
borderColor: "#b392f0",
|
||||
borderWidth: 1,
|
||||
};
|
||||
});
|
||||
|
||||
setChartData({ labels, datasets });
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.off("lineOutput");
|
||||
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||
socket.disconnect();
|
||||
};
|
||||
}, [measurements, duration, iotApiUrl]);
|
||||
|
||||
return <Pie data={Object.keys(measurements).length > 0 ? chartData : defaultData} options={options} />;
|
||||
};
|
||||
|
||||
export default PieChartComponent;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ const ProgressCard = ({
|
|||
}) => (
|
||||
<div className="chart progressBar">
|
||||
<div className="header">{title}</div>
|
||||
{data?.stocks.map((stock, index) => (
|
||||
{data?.stocks?.map((stock, index) => (
|
||||
<div key={index} className="stock">
|
||||
<span className="stock-item">
|
||||
<span className="stockValues">
|
||||
|
|
|
@ -34,15 +34,11 @@ export default function NavMeshDetails({
|
|||
|
||||
const [positions, indices] = getPositionsAndIndices(meshes);
|
||||
|
||||
const cs = 0.5;
|
||||
const cs = 0.25;
|
||||
const ch = 0.5;
|
||||
const walkableRadius = 0.89;
|
||||
const walkableRadius = 0.5;
|
||||
|
||||
const { success, navMesh } = generateSoloNavMesh(positions, indices, {
|
||||
cs,
|
||||
ch,
|
||||
walkableRadius: Math.round(walkableRadius / ch),
|
||||
});
|
||||
const { success, navMesh } = generateSoloNavMesh(positions, indices, { cs, ch, walkableRadius: Math.round(walkableRadius / ch), });
|
||||
|
||||
if (!success || !navMesh) {
|
||||
return;
|
||||
|
@ -53,7 +49,7 @@ export default function NavMeshDetails({
|
|||
const debugDrawer = new DebugDrawer();
|
||||
debugDrawer.drawNavMesh(navMesh);
|
||||
// scene.add(debugDrawer);
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
initializeNavigation();
|
||||
|
|
|
@ -86,7 +86,7 @@ export default function PathNavigator({
|
|||
|
||||
return (
|
||||
<>
|
||||
{path.length > 0 && <Line points={path} color="blue" lineWidth={3} />}
|
||||
{/* {path.length > 0 && <Line points={path} color="blue" lineWidth={3} />} */}
|
||||
{path.length > 0 && (
|
||||
<mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}>
|
||||
<boxGeometry args={[1, 1, 1]} />
|
||||
|
|
|
@ -43,66 +43,46 @@ export default function PolygonGenerator({
|
|||
|
||||
const lineFeatures = result?.map((line: any) =>
|
||||
turf.lineString(line.map((p: any) => p?.position))
|
||||
);
|
||||
);
|
||||
|
||||
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
||||
renderWallGeometry(wallPoints);
|
||||
|
||||
let union: any = [];
|
||||
if (polygons.features.length > 1) {
|
||||
polygons.features.forEach((feature) => {
|
||||
if (feature.geometry.type === "Polygon") {
|
||||
|
||||
polygons.features.forEach((feature) => {
|
||||
union.push(feature);
|
||||
});
|
||||
const shape = new THREE.Shape();
|
||||
const coords = feature.geometry.coordinates[0];
|
||||
|
||||
if (union.length > 1) {
|
||||
const unionResult = turf.union(turf.featureCollection(union));
|
||||
shape.moveTo(coords[0][0], coords[0][1]);
|
||||
|
||||
if (unionResult?.geometry.type === "MultiPolygon") {
|
||||
unionResult.geometry.coordinates.forEach((poly) => {
|
||||
const coordinates = poly[0].map(([x, z]) => {
|
||||
return new THREE.Vector3(x, 0, z);
|
||||
});
|
||||
renderBoxGeometry(coordinates);
|
||||
});
|
||||
} else if (unionResult?.geometry.type === "Polygon") {
|
||||
const coordinates = unionResult.geometry.coordinates[0].map(
|
||||
([x, z]) => {
|
||||
return new THREE.Vector3(x, 0, z);
|
||||
for (let i = 1; i < coords.length; i++) {
|
||||
shape.lineTo(coords[i][0], coords[i][1]);
|
||||
}
|
||||
);
|
||||
renderBoxGeometry(coordinates);
|
||||
}
|
||||
} else if (union.length === 1) {
|
||||
const coordinates = union[0].geometry.coordinates[0].map(
|
||||
([x, z]: [number, number]) => {
|
||||
return new THREE.Vector3(x, 0, z);
|
||||
shape.lineTo(coords[0][0], coords[0][1]);
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: 5,
|
||||
bevelEnabled: false,
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
|
||||
const material = new THREE.MeshBasicMaterial({ color: "blue", transparent: true, opacity: 0.5 });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.name = "agv-collider";
|
||||
mesh.position.y = 5;
|
||||
|
||||
mesh.receiveShadow = true;
|
||||
groupRef.current?.add(mesh);
|
||||
}
|
||||
);
|
||||
// setRooms((prevRooms) => [...prevRooms, coordinates]);
|
||||
});
|
||||
|
||||
}
|
||||
}, [lines.current]);
|
||||
|
||||
const renderBoxGeometry = (coordinates: THREE.Vector3[]) => {
|
||||
const minX = Math.min(...coordinates.map((p) => p.x));
|
||||
const maxX = Math.max(...coordinates.map((p) => p.x));
|
||||
const minZ = Math.min(...coordinates.map((p) => p.z));
|
||||
const maxZ = Math.max(...coordinates.map((p) => p.z));
|
||||
|
||||
const width = maxX - minX;
|
||||
const depth = maxZ - minZ;
|
||||
const height = 3;
|
||||
|
||||
const geometry = new THREE.BoxGeometry(width, height, depth);
|
||||
const material = new THREE.MeshBasicMaterial({
|
||||
color: "#ff66cc",
|
||||
visible: false,
|
||||
});
|
||||
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.position.set((minX + maxX) / 2, height / 2, (minZ + maxZ) / 2);
|
||||
groupRef.current?.add(mesh);
|
||||
};
|
||||
|
||||
const renderWallGeometry = (walls: THREE.Vector3[][]) => {
|
||||
walls.forEach((wall) => {
|
||||
if (wall.length < 2) return;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { useActiveTool, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useLoadingProgress, useRenderDistance, useselectedFloorItem, useSelectedItem, useSocketStore, useToggleView, useTransformMode } from "../../../store/store";
|
||||
import { useActiveTool, useAsset3dWidget, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useLoadingProgress, useRenderDistance, useselectedFloorItem, useSelectedItem, useSocketStore, useToggleView, useTransformMode } from "../../../store/store";
|
||||
import assetVisibility from "../geomentries/assets/assetVisibility";
|
||||
import { useEffect } from "react";
|
||||
import * as THREE from "three";
|
||||
|
@ -33,7 +33,6 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
|||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { socket } = useSocketStore();
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
|
@ -306,6 +305,8 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
|||
};
|
||||
}, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule]);
|
||||
|
||||
|
||||
|
||||
useFrame(() => {
|
||||
if (controls)
|
||||
assetVisibility(itemsGroup, state.camera.position, renderDistance);
|
||||
|
|
|
@ -224,6 +224,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable
|
|||
const onDrop = (event: any) => {
|
||||
|
||||
if (!event.dataTransfer?.files[0]) return
|
||||
|
||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
|
|
|
@ -112,7 +112,7 @@ const CamModelsGroup = () => {
|
|||
socket.off("userDisConnectRespones");
|
||||
socket.off("cameraUpdateResponse");
|
||||
};
|
||||
}, [socket]);
|
||||
}, [socket, activeUsers]);
|
||||
|
||||
useFrame(() => {
|
||||
if (!groupRef.current) return;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import React from "react";
|
||||
import React, { Suspense, useEffect } from "react";
|
||||
import assetImage from "../../assets/image/image.png";
|
||||
import { FiileedStarsIconSmall } from "../../components/icons/marketPlaceIcons";
|
||||
import { Canvas, useThree } from "@react-three/fiber";
|
||||
import { ContactShadows, OrbitControls, Text } from "@react-three/drei";
|
||||
import GltfLoader from "./GltfLoader";
|
||||
import * as THREE from "three";
|
||||
|
||||
// Define the shape of the selected card
|
||||
interface SelectedCard {
|
||||
|
@ -17,6 +21,14 @@ interface AssetPreviewProps {
|
|||
setSelectedCard: React.Dispatch<React.SetStateAction<SelectedCard | null>>; // Type for setter function
|
||||
}
|
||||
|
||||
function Ui() {
|
||||
return (
|
||||
<Text color="#6f42c1" anchorX="center" anchorY="middle" scale={0.3}>
|
||||
Loading your model...
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
const AssetPreview: React.FC<AssetPreviewProps> = ({
|
||||
selectedCard,
|
||||
setSelectedCard,
|
||||
|
@ -27,8 +39,6 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
|
|||
Math.min(5, isNaN(selectedCard.rating) ? 0 : selectedCard.rating)
|
||||
);
|
||||
|
||||
console.log("selectedCard: ", selectedCard);
|
||||
|
||||
// Ensure that the rating is a valid positive integer for array length
|
||||
const starsArray = Array.from({ length: rating }, (_, index) => index);
|
||||
|
||||
|
@ -36,8 +46,38 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
|
|||
<div className="assetPreview-wrapper">
|
||||
<div className="assetPreview">
|
||||
<div className="image-preview">
|
||||
<img src={assetImage} alt="" />
|
||||
{/* <img src={assetImage} alt="" /> */}
|
||||
{/* Add canvas here */}
|
||||
<div className="canvas-container" style={{ height: "100%" }}>
|
||||
<Canvas
|
||||
flat
|
||||
shadows
|
||||
color="#FFFFFF"
|
||||
camera={{ fov: 75 }}
|
||||
gl={{
|
||||
preserveDrawingBuffer: true,
|
||||
}}
|
||||
onCreated={({ scene }) => {
|
||||
scene.background = new THREE.Color(0xffffff);
|
||||
}}
|
||||
>
|
||||
<Suspense fallback={<Ui />}>
|
||||
{selectedCard.assetName && (
|
||||
<GltfLoader fromServer={selectedCard.assetName} />
|
||||
)}
|
||||
<OrbitControls minPolarAngle={0} maxPolarAngle={Math.PI / 2} />
|
||||
<ContactShadows
|
||||
renderOrder={2}
|
||||
frames={1}
|
||||
resolution={1024}
|
||||
scale={120}
|
||||
blur={2}
|
||||
opacity={0.4}
|
||||
far={100}
|
||||
/>
|
||||
</Suspense>
|
||||
</Canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="asset-details-preview">
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
} from "../../components/icons/marketPlaceIcons";
|
||||
|
||||
import assetImage from "../../assets/image/image.png";
|
||||
import { getAssetDownload } from "../../services/marketplace/getAssetDownload";
|
||||
|
||||
interface CardProps {
|
||||
assetName: string;
|
||||
|
@ -40,9 +41,9 @@ const Card: React.FC<CardProps> = ({
|
|||
|
||||
return (
|
||||
<div className="card-container">
|
||||
<div className="icon">
|
||||
{/* <a href={getAssetDownload(assetName)} download className="icon">
|
||||
<DownloadIcon />
|
||||
</div>
|
||||
</a> */}
|
||||
<div className="image-container">
|
||||
<img src={image} alt={assetName} />
|
||||
</div>
|
||||
|
|
|
@ -16,109 +16,11 @@ interface ModelData {
|
|||
uploadDate: number;
|
||||
_id: string;
|
||||
}
|
||||
interface ModelsProps {
|
||||
models: ModelData[];
|
||||
}
|
||||
|
||||
const CardsContainer: React.FC = () => {
|
||||
const [models, setModels] = useState<ModelData[]>([]);
|
||||
|
||||
const array = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Asset 1",
|
||||
uploadedOn: "12 Jan 23",
|
||||
price: 36500,
|
||||
rating: 4.5,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Asset 2",
|
||||
uploadedOn: "14 Jan 23",
|
||||
price: 45000,
|
||||
rating: 4.0,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Asset 3",
|
||||
uploadedOn: "15 Jan 23",
|
||||
price: 52000,
|
||||
rating: 4.8,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Asset 4",
|
||||
uploadedOn: "18 Jan 23",
|
||||
price: 37000,
|
||||
rating: 3.9,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Asset 5",
|
||||
uploadedOn: "20 Jan 23",
|
||||
price: 60000,
|
||||
rating: 5.0,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Asset 6",
|
||||
uploadedOn: "22 Jan 23",
|
||||
price: 46000,
|
||||
rating: 4.2,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Asset 7",
|
||||
uploadedOn: "25 Jan 23",
|
||||
price: 38000,
|
||||
rating: 4.3,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Asset 8",
|
||||
uploadedOn: "27 Jan 23",
|
||||
price: 41000,
|
||||
rating: 4.1,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Asset 9",
|
||||
uploadedOn: "30 Jan 23",
|
||||
price: 55000,
|
||||
rating: 4.6,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Asset 10",
|
||||
uploadedOn: "2 Feb 23",
|
||||
price: 49000,
|
||||
rating: 4.4,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Asset 11",
|
||||
uploadedOn: "5 Feb 23",
|
||||
price: 62000,
|
||||
rating: 5.0,
|
||||
views: 500,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Asset 12",
|
||||
uploadedOn: "7 Feb 23",
|
||||
price: 53000,
|
||||
rating: 4.7,
|
||||
views: 500,
|
||||
},
|
||||
];
|
||||
|
||||
const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
|
||||
const [selectedCard, setSelectedCard] = useState<{
|
||||
assetName: string;
|
||||
uploadedOn: string;
|
||||
|
@ -136,33 +38,11 @@ const CardsContainer: React.FC = () => {
|
|||
}) => {
|
||||
setSelectedCard(cardData);
|
||||
};
|
||||
const getAllAssets = async () => {
|
||||
try {
|
||||
const assetsData = await fetchAssets();
|
||||
const reversedData = [...assetsData]?.reverse().slice(0, 8);
|
||||
setModels(reversedData);
|
||||
} catch (error) {
|
||||
} finally {
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
getAllAssets();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="cards-container-container">
|
||||
<div className="header">Products You May Like</div>
|
||||
<div className="cards-wrapper-container">
|
||||
{/* {array.map((asset) => (
|
||||
<Card
|
||||
key={asset.id}
|
||||
assetName={asset.name}
|
||||
uploadedOn={asset.uploadedOn}
|
||||
price={asset.price}
|
||||
rating={asset.rating}
|
||||
views={asset.views}
|
||||
onSelectCard={handleCardSelect}
|
||||
/>
|
||||
))} */}
|
||||
{models.length > 0 &&
|
||||
models.map((assetDetail) => (
|
||||
<Card
|
||||
|
@ -171,7 +51,7 @@ const CardsContainer: React.FC = () => {
|
|||
uploadedOn={assetDetail.uploadDate.toString()}
|
||||
price={36500}
|
||||
rating={4.5}
|
||||
views={500}
|
||||
views={800}
|
||||
onSelectCard={handleCardSelect}
|
||||
image={assetDetail.thumbnail}
|
||||
/>
|
||||
|
|
|
@ -1,19 +1,69 @@
|
|||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
// import RegularDropDown from "./ui/inputs/RegularDropDown";
|
||||
|
||||
import Search from "../../components/ui/inputs/Search";
|
||||
import { StarsIcon } from "../../components/icons/marketPlaceIcons";
|
||||
import RegularDropDown from "../../components/ui/inputs/RegularDropDown";
|
||||
|
||||
const FilterSearch: React.FC = () => {
|
||||
import { getSortedAssets } from "../../services/marketplace/getSortedAssets";
|
||||
interface ModelData {
|
||||
CreatedBy: string;
|
||||
animated: string | null;
|
||||
category: string;
|
||||
description: string;
|
||||
filename: string;
|
||||
isArchieve: boolean;
|
||||
modelfileID: string;
|
||||
tags: string;
|
||||
thumbnail: string;
|
||||
uploadDate: number;
|
||||
_id: string;
|
||||
}
|
||||
interface ModelsProps {
|
||||
models: ModelData[];
|
||||
setModels: React.Dispatch<React.SetStateAction<ModelData[]>>;
|
||||
filteredModels: ModelData[];
|
||||
}
|
||||
const FilterSearch: React.FC<ModelsProps> = ({
|
||||
models,
|
||||
setModels,
|
||||
filteredModels,
|
||||
}) => {
|
||||
const [activeOption, setActiveOption] = useState("Sort by"); // State for active option
|
||||
console.log("filteredModels: ", filteredModels);
|
||||
|
||||
const handleSelect = (option: string) => {
|
||||
setActiveOption(option);
|
||||
console.log("option: ", option);
|
||||
// Alphabet ascending
|
||||
// Alphabet descending
|
||||
// All
|
||||
};
|
||||
useEffect(() => {
|
||||
if (activeOption == "Alphabet ascending") {
|
||||
let ascending = models
|
||||
?.slice()
|
||||
.sort((a, b) => a.filename.localeCompare(b.filename))
|
||||
.map((val) => val);
|
||||
setModels(ascending);
|
||||
} else if (activeOption == "Alphabet descending") {
|
||||
let descending = models
|
||||
?.slice()
|
||||
.sort((a, b) => b.filename.localeCompare(a.filename))
|
||||
.map((val) => val);
|
||||
setModels(descending);
|
||||
}
|
||||
}, [activeOption]);
|
||||
const handleSearch = (val: string) => {
|
||||
const filteredModel = filteredModels?.filter((model) =>
|
||||
model.filename.toLowerCase().includes(val.toLowerCase())
|
||||
);
|
||||
|
||||
setModels(filteredModel);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="filter-search-container">
|
||||
<Search onChange={() => {}} />
|
||||
<Search onChange={handleSearch} />
|
||||
<RegularDropDown
|
||||
header={activeOption}
|
||||
options={["Alphabet ascending", "Alphabet descending", ""]}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
import { useRef, useEffect } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { Stage, useGLTF } from "@react-three/drei";
|
||||
import { AnimationMixer, AnimationAction, Object3D } from "three";
|
||||
import * as THREE from "three";
|
||||
import { fetchGltfUrl } from "../../services/marketplace/fetchGltfUrl";
|
||||
|
||||
interface GltfLoaderProps {
|
||||
glbdata?: boolean;
|
||||
fromServer?: string;
|
||||
setAnimations?: (animations?: string[]) => void;
|
||||
selectedAnimation?: string;
|
||||
setSelectedAnimation?: (animation: string) => void;
|
||||
}
|
||||
|
||||
// const getGLTFUrl = (url: string) => url; // Placeholder for your actual function
|
||||
|
||||
const GltfLoader: React.FC<GltfLoaderProps> = ({
|
||||
glbdata,
|
||||
fromServer,
|
||||
setAnimations,
|
||||
selectedAnimation,
|
||||
}) => {
|
||||
const modelUrl: any = fromServer ? fetchGltfUrl(fromServer) : glbdata;
|
||||
const { scene, animations } = useGLTF(modelUrl ?? "") as {
|
||||
scene: Object3D;
|
||||
animations: THREE.AnimationClip[];
|
||||
};
|
||||
|
||||
const mixer = useRef<AnimationMixer | null>(
|
||||
scene ? new AnimationMixer(scene) : null
|
||||
);
|
||||
const actions = useRef<Record<string, AnimationAction>>({});
|
||||
|
||||
useEffect(() => {
|
||||
if (animations.length > 0 && mixer.current && setAnimations) {
|
||||
const animationNames = animations.map((animation) => animation.name);
|
||||
setAnimations(animationNames);
|
||||
|
||||
animations.forEach((animation) => {
|
||||
const action = mixer.current!.clipAction(animation);
|
||||
actions.current[animation.name] = action;
|
||||
});
|
||||
} else {
|
||||
setAnimations && setAnimations([]);
|
||||
}
|
||||
}, [animations, setAnimations]);
|
||||
|
||||
useEffect(() => {
|
||||
if (actions.current && selectedAnimation) {
|
||||
const action = actions.current[selectedAnimation];
|
||||
if (action) {
|
||||
action.reset().fadeIn(0.5).play();
|
||||
return () => {
|
||||
action.fadeOut(0.5);
|
||||
};
|
||||
}
|
||||
}
|
||||
}, [selectedAnimation]);
|
||||
|
||||
useFrame((_, delta) => {
|
||||
if (mixer.current) {
|
||||
mixer.current.update(delta);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Stage
|
||||
adjustCamera={false}
|
||||
intensity={0.5}
|
||||
shadows="contact"
|
||||
environment="city"
|
||||
>
|
||||
<primitive object={scene} scale={1} />
|
||||
</Stage>
|
||||
);
|
||||
};
|
||||
|
||||
export default GltfLoader;
|
|
@ -1,14 +1,46 @@
|
|||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import FilterSearch from "./FilterSearch";
|
||||
import CardsContainer from "./CardsContainer";
|
||||
|
||||
import { fetchAssets } from "../../services/marketplace/fetchAssets";
|
||||
import { getAssetImages } from "../../services/factoryBuilder/assest/assets/getAssetImages";
|
||||
interface ModelData {
|
||||
CreatedBy: string;
|
||||
animated: string | null;
|
||||
category: string;
|
||||
description: string;
|
||||
filename: string;
|
||||
isArchieve: boolean;
|
||||
modelfileID: string;
|
||||
tags: string;
|
||||
thumbnail: string;
|
||||
uploadDate: number;
|
||||
_id: string;
|
||||
}
|
||||
const MarketPlace = () => {
|
||||
const [models, setModels] = useState<ModelData[]>([]);
|
||||
const [filteredModels, setFilteredModels] = useState<ModelData[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const filteredAssets = async () => {
|
||||
try {
|
||||
const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6");
|
||||
setModels(filt.items);
|
||||
setFilteredModels(filt.items);
|
||||
} catch {}
|
||||
};
|
||||
filteredAssets();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="marketplace-wrapper">
|
||||
<div className="marketplace-container">
|
||||
<div className="marketPlace">
|
||||
<FilterSearch />
|
||||
<CardsContainer />
|
||||
<FilterSearch
|
||||
models={models}
|
||||
setModels={setModels}
|
||||
filteredModels={filteredModels}
|
||||
/>
|
||||
<CardsContainer models={models} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -19,6 +19,8 @@ import DroppedObjects from "../../components/ui/componets/DroppedFloatingWidgets
|
|||
|
||||
// import Simulation from "./simulationtemp/simulation";
|
||||
import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget";
|
||||
import ProductionCapacity from "../../components/layout/3D-cards/cards/ProductionCapacity";
|
||||
import Dropped3dWidgets from "../../components/ui/componets/Dropped3dWidget";
|
||||
|
||||
export default function Scene() {
|
||||
|
||||
|
@ -43,13 +45,13 @@ export default function Scene() {
|
|||
}}
|
||||
|
||||
>
|
||||
<Dropped3dWidgets/>
|
||||
<Controls />
|
||||
<TransformControl />
|
||||
<SelectionControls />
|
||||
<MeasurementTool />
|
||||
<World />
|
||||
<ZoneCentreTarget />
|
||||
{/* <Simulation /> */}
|
||||
<Simulation />
|
||||
<PostProcessing />
|
||||
<Sun />
|
||||
|
@ -58,9 +60,6 @@ export default function Scene() {
|
|||
<MqttEvents />
|
||||
<Environment files={background} environmentIntensity={1.5} />
|
||||
</Canvas>
|
||||
|
||||
|
||||
|
||||
</KeyboardControls>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,43 +1,29 @@
|
|||
import { useFloorItems } from '../../../store/store';
|
||||
import { useFloorItems, useSimulationPaths } from '../../../store/store';
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
interface Path {
|
||||
modeluuid: string;
|
||||
modelName: string;
|
||||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
||||
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
|
||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
}[];
|
||||
pathPosition: [number, number, number];
|
||||
pathRotation: [number, number, number];
|
||||
speed: number;
|
||||
}
|
||||
|
||||
function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
|
||||
function Behaviour() {
|
||||
const { setSimulationPaths } = useSimulationPaths();
|
||||
const { floorItems } = useFloorItems();
|
||||
|
||||
useEffect(() => {
|
||||
const newPaths: Path[] = [];
|
||||
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = [];
|
||||
|
||||
floorItems.forEach((item: Types.FloorItemType) => {
|
||||
if (item.modelfileID === "6633215057b31fe671145959") {
|
||||
const point1Position = new THREE.Vector3(0, 1.25, 3.3);
|
||||
const middlePointPosition = new THREE.Vector3(0, 1.25, 0);
|
||||
const point2Position = new THREE.Vector3(0, 1.25, -3.3);
|
||||
if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
|
||||
const point1Position = new THREE.Vector3(0, 0.85, 2.2);
|
||||
const middlePointPosition = new THREE.Vector3(0, 0.85, 0);
|
||||
const point2Position = new THREE.Vector3(0, 0.85, -2.2);
|
||||
|
||||
const point1UUID = THREE.MathUtils.generateUUID();
|
||||
const middlePointUUID = THREE.MathUtils.generateUUID();
|
||||
const point2UUID = THREE.MathUtils.generateUUID();
|
||||
|
||||
const newPath: Path = {
|
||||
const newPath: Types.ConveyorEventsSchema = {
|
||||
modeluuid: item.modeluuid,
|
||||
modelName: item.modelname,
|
||||
type: 'Conveyor',
|
||||
points: [
|
||||
{
|
||||
uuid: point1UUID,
|
||||
|
@ -64,12 +50,32 @@ function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
|
|||
connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
|
||||
},
|
||||
],
|
||||
pathPosition: [...item.position],
|
||||
pathRotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
assetPosition: [...item.position],
|
||||
assetRotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
speed: 1,
|
||||
};
|
||||
|
||||
newPaths.push(newPath);
|
||||
} else if (item.modelfileID === "67e3da19c2e8f37134526e6a") {
|
||||
const pointUUID = THREE.MathUtils.generateUUID();
|
||||
const pointPosition = new THREE.Vector3(0, 1.3, 0);
|
||||
|
||||
const newVehiclePath: Types.VehicleEventsSchema = {
|
||||
modeluuid: item.modeluuid,
|
||||
modelName: item.modelname,
|
||||
type: 'Vehicle',
|
||||
point: {
|
||||
uuid: pointUUID,
|
||||
position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
||||
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: THREE.MathUtils.generateUUID(), hitCount: 1, end: THREE.MathUtils.generateUUID(), buffer: 0, isUsed: false }],
|
||||
triggers: [],
|
||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
||||
},
|
||||
assetPosition: [...item.position],
|
||||
speed: 2,
|
||||
};
|
||||
|
||||
newPaths.push(newVehiclePath);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import { QuadraticBezierLine } from '@react-three/drei';
|
||||
import { useIsConnecting, useSimulationPaths } from '../../../store/store';
|
||||
import useModuleStore from '../../../store/useModuleStore';
|
||||
|
@ -27,61 +28,113 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
toPointUUID: string
|
||||
) => {
|
||||
const updatedPaths = simulationPaths.map(path => {
|
||||
if (path.modeluuid === fromPathUUID) {
|
||||
return {
|
||||
...path,
|
||||
points: path.points.map(point => {
|
||||
if (point.uuid === fromPointUUID) {
|
||||
const newTarget = {
|
||||
pathUUID: toPathUUID,
|
||||
pointUUID: toPointUUID
|
||||
};
|
||||
const existingTargets = point.connections.targets || [];
|
||||
|
||||
if (!existingTargets.some(target =>
|
||||
target.pathUUID === newTarget.pathUUID &&
|
||||
target.pointUUID === newTarget.pointUUID
|
||||
)) {
|
||||
return {
|
||||
...point,
|
||||
connections: {
|
||||
...point.connections,
|
||||
targets: [...existingTargets, newTarget]
|
||||
}
|
||||
if (path.type === 'Conveyor') {
|
||||
if (path.modeluuid === fromPathUUID) {
|
||||
return {
|
||||
...path,
|
||||
points: path.points.map(point => {
|
||||
if (point.uuid === fromPointUUID) {
|
||||
const newTarget = {
|
||||
pathUUID: toPathUUID,
|
||||
pointUUID: toPointUUID
|
||||
};
|
||||
const existingTargets = point.connections.targets || [];
|
||||
|
||||
if (!existingTargets.some(target =>
|
||||
target.pathUUID === newTarget.pathUUID &&
|
||||
target.pointUUID === newTarget.pointUUID
|
||||
)) {
|
||||
return {
|
||||
...point,
|
||||
connections: {
|
||||
...point.connections,
|
||||
targets: [...existingTargets, newTarget]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return point;
|
||||
})
|
||||
};
|
||||
return point;
|
||||
})
|
||||
};
|
||||
}
|
||||
else if (path.modeluuid === toPathUUID) {
|
||||
return {
|
||||
...path,
|
||||
points: path.points.map(point => {
|
||||
if (point.uuid === toPointUUID) {
|
||||
const reverseTarget = {
|
||||
pathUUID: fromPathUUID,
|
||||
pointUUID: fromPointUUID
|
||||
};
|
||||
const existingTargets = point.connections.targets || [];
|
||||
|
||||
if (!existingTargets.some(target =>
|
||||
target.pathUUID === reverseTarget.pathUUID &&
|
||||
target.pointUUID === reverseTarget.pointUUID
|
||||
)) {
|
||||
return {
|
||||
...point,
|
||||
connections: {
|
||||
...point.connections,
|
||||
targets: [...existingTargets, reverseTarget]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return point;
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (path.modeluuid === toPathUUID) {
|
||||
return {
|
||||
...path,
|
||||
points: path.points.map(point => {
|
||||
if (point.uuid === toPointUUID) {
|
||||
const reverseTarget = {
|
||||
pathUUID: fromPathUUID,
|
||||
pointUUID: fromPointUUID
|
||||
};
|
||||
const existingTargets = point.connections.targets || [];
|
||||
else if (path.type === 'Vehicle') {
|
||||
// Handle outgoing connections from Vehicle
|
||||
if (path.modeluuid === fromPathUUID && path.point.uuid === fromPointUUID) {
|
||||
const newTarget = {
|
||||
pathUUID: toPathUUID,
|
||||
pointUUID: toPointUUID
|
||||
};
|
||||
const existingTargets = path.point.connections.targets || [];
|
||||
|
||||
if (!existingTargets.some(target =>
|
||||
target.pathUUID === reverseTarget.pathUUID &&
|
||||
target.pointUUID === reverseTarget.pointUUID
|
||||
)) {
|
||||
return {
|
||||
...point,
|
||||
connections: {
|
||||
...point.connections,
|
||||
targets: [...existingTargets, reverseTarget]
|
||||
}
|
||||
};
|
||||
if (!existingTargets.some(target =>
|
||||
target.pathUUID === newTarget.pathUUID &&
|
||||
target.pointUUID === newTarget.pointUUID
|
||||
)) {
|
||||
return {
|
||||
...path,
|
||||
point: {
|
||||
...path.point,
|
||||
connections: {
|
||||
...path.point.connections,
|
||||
targets: [...existingTargets, newTarget]
|
||||
}
|
||||
}
|
||||
}
|
||||
return point;
|
||||
})
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
// Handle incoming connections to Vehicle
|
||||
else if (path.modeluuid === toPathUUID && path.point.uuid === toPointUUID) {
|
||||
const reverseTarget = {
|
||||
pathUUID: fromPathUUID,
|
||||
pointUUID: fromPointUUID
|
||||
};
|
||||
const existingTargets = path.point.connections.targets || [];
|
||||
|
||||
if (!existingTargets.some(target =>
|
||||
target.pathUUID === reverseTarget.pathUUID &&
|
||||
target.pointUUID === reverseTarget.pointUUID
|
||||
)) {
|
||||
return {
|
||||
...path,
|
||||
point: {
|
||||
...path.point,
|
||||
connections: {
|
||||
...path.point.connections,
|
||||
targets: [...existingTargets, reverseTarget]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return path;
|
||||
});
|
||||
|
@ -126,25 +179,43 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
if (intersects.length > 0) {
|
||||
const intersected = intersects[0].object;
|
||||
|
||||
if (intersected.name.includes("action-sphere")) {
|
||||
if (intersected.name.includes("events-sphere")) {
|
||||
const pathUUID = intersected.userData.path.modeluuid;
|
||||
const sphereUUID = intersected.uuid;
|
||||
const worldPosition = new THREE.Vector3();
|
||||
intersected.getWorldPosition(worldPosition);
|
||||
|
||||
const isStartOrEnd = intersected.userData.path.points.length > 0 && (
|
||||
sphereUUID === intersected.userData.path.points[0].uuid ||
|
||||
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
|
||||
);
|
||||
let isStartOrEnd = false;
|
||||
|
||||
if (intersected.userData.path.points) {
|
||||
isStartOrEnd = intersected.userData.path.points.length > 0 && (
|
||||
sphereUUID === intersected.userData.path.points[0].uuid ||
|
||||
sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
|
||||
);
|
||||
} else if (intersected.userData.path.point) {
|
||||
isStartOrEnd = sphereUUID === intersected.userData.path.point.uuid;
|
||||
}
|
||||
|
||||
if (pathUUID) {
|
||||
// Check if sphere is already connected
|
||||
const isAlreadyConnected = simulationPaths.some(path =>
|
||||
path.points.some(point =>
|
||||
point.uuid === sphereUUID &&
|
||||
point.connections.targets.length > 0
|
||||
)
|
||||
);
|
||||
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected?.pathUUID);
|
||||
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
|
||||
|
||||
if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') {
|
||||
console.log("Cannot connect two vehicle paths together");
|
||||
return;
|
||||
}
|
||||
const isAlreadyConnected = simulationPaths.some(path => {
|
||||
if (path.type === 'Conveyor') {
|
||||
return path.points.some(point =>
|
||||
point.uuid === sphereUUID &&
|
||||
point.connections.targets.length > 0
|
||||
);
|
||||
} else if (path.type === 'Vehicle') {
|
||||
return path.point.uuid === sphereUUID &&
|
||||
path.point.connections.targets.length > 0;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (isAlreadyConnected) {
|
||||
console.log("Sphere is already connected. Ignoring.");
|
||||
|
@ -211,6 +282,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true).filter((intersect) =>
|
||||
!intersect.object.name.includes("Roof") &&
|
||||
!intersect.object.name.includes("agv-collider") &&
|
||||
!intersect.object.name.includes("MeasurementReference") &&
|
||||
!intersect.object.userData.isPathObject &&
|
||||
!(intersect.object.type === "GridHelper")
|
||||
|
@ -229,7 +301,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
}
|
||||
|
||||
const sphereIntersects = raycaster.intersectObjects(pathsGroupRef.current.children, true).filter((obj) =>
|
||||
obj.object.name.includes("action-sphere")
|
||||
obj.object.name.includes("events-sphere")
|
||||
);
|
||||
|
||||
if (sphereIntersects.length > 0) {
|
||||
|
@ -237,27 +309,45 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
const sphereUUID = sphere.uuid;
|
||||
const spherePosition = new THREE.Vector3();
|
||||
sphere.getWorldPosition(spherePosition);
|
||||
const pathUUID = sphere.userData.path.modeluuid;
|
||||
const pathData = sphere.userData.path;
|
||||
const pathUUID = pathData.modeluuid;
|
||||
|
||||
const isStartOrEnd = sphere.userData.path.points.length > 0 && (
|
||||
sphereUUID === sphere.userData.path.points[0].uuid ||
|
||||
sphereUUID === sphere.userData.path.points[sphere.userData.path.points.length - 1].uuid
|
||||
);
|
||||
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected.pathUUID);
|
||||
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
|
||||
const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle';
|
||||
|
||||
const isAlreadyConnected = simulationPaths.some(path =>
|
||||
path.points.some(point =>
|
||||
point.uuid === sphereUUID &&
|
||||
point.connections.targets.length > 0
|
||||
)
|
||||
);
|
||||
const isConnectable = (pathData.type === 'Vehicle' ||
|
||||
(pathData.points.length > 0 && (
|
||||
sphereUUID === pathData.points[0].uuid ||
|
||||
sphereUUID === pathData.points[pathData.points.length - 1].uuid
|
||||
))) && !isVehicleToVehicle;
|
||||
|
||||
const isAlreadyConnected = simulationPaths.some(path => {
|
||||
if (path.type === 'Conveyor') {
|
||||
return path.points.some(point =>
|
||||
point.uuid === sphereUUID &&
|
||||
point.connections.targets.length > 0
|
||||
);
|
||||
} else if (path.type === 'Vehicle') {
|
||||
return path.point.uuid === sphereUUID &&
|
||||
path.point.connections.targets.length > 0;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (
|
||||
!isAlreadyConnected &&
|
||||
!isVehicleToVehicle &&
|
||||
firstSelected.sphereUUID !== sphereUUID &&
|
||||
firstSelected.pathUUID !== pathUUID &&
|
||||
(firstSelected.isCorner || isStartOrEnd)
|
||||
(firstSelected.isCorner || isConnectable)
|
||||
) {
|
||||
snappedSphere = { sphereUUID, position: spherePosition, pathUUID, isCorner: isStartOrEnd };
|
||||
snappedSphere = {
|
||||
sphereUUID,
|
||||
position: spherePosition,
|
||||
pathUUID,
|
||||
isCorner: isConnectable
|
||||
};
|
||||
} else {
|
||||
isInvalidConnection = true;
|
||||
}
|
||||
|
@ -281,8 +371,13 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
end: point,
|
||||
mid: midPoint,
|
||||
});
|
||||
console.log({
|
||||
start: firstSelected.position,
|
||||
end: point,
|
||||
mid: midPoint,
|
||||
});
|
||||
|
||||
setIsConnecting(true);
|
||||
// setIsConnecting(true);
|
||||
|
||||
if (sphereIntersects.length > 0) {
|
||||
setHelperLineColor(isInvalidConnection ? 'red' : '#6cf542');
|
||||
|
@ -299,13 +394,53 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
}
|
||||
});
|
||||
|
||||
// Render connections from simulationPaths
|
||||
return (
|
||||
<>
|
||||
{simulationPaths.flatMap(path =>
|
||||
path.points.flatMap(point =>
|
||||
point.connections.targets.map((target, index) => {
|
||||
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
|
||||
{simulationPaths.flatMap(path => {
|
||||
if (path.type === 'Conveyor') {
|
||||
return path.points.flatMap(point =>
|
||||
point.connections.targets.map((target, index) => {
|
||||
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
|
||||
if (targetPath?.type === 'Vehicle') return null;
|
||||
|
||||
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
|
||||
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
||||
|
||||
if (fromSphere && toSphere) {
|
||||
const fromWorldPosition = new THREE.Vector3();
|
||||
const toWorldPosition = new THREE.Vector3();
|
||||
fromSphere.getWorldPosition(fromWorldPosition);
|
||||
toSphere.getWorldPosition(toWorldPosition);
|
||||
|
||||
const distance = fromWorldPosition.distanceTo(toWorldPosition);
|
||||
const heightFactor = Math.max(0.5, distance * 0.2);
|
||||
|
||||
const midPoint = new THREE.Vector3(
|
||||
(fromWorldPosition.x + toWorldPosition.x) / 2,
|
||||
Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
|
||||
(fromWorldPosition.z + toWorldPosition.z) / 2
|
||||
);
|
||||
|
||||
return (
|
||||
<QuadraticBezierLine
|
||||
key={`${point.uuid}-${target.pointUUID}-${index}`}
|
||||
start={fromWorldPosition.toArray()}
|
||||
end={toWorldPosition.toArray()}
|
||||
mid={midPoint.toArray()}
|
||||
color="white"
|
||||
lineWidth={4}
|
||||
dashed
|
||||
dashSize={0.75}
|
||||
dashScale={20}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
);
|
||||
} else if (path.type === 'Vehicle') {
|
||||
return path.point.connections.targets.map((target, index) => {
|
||||
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.point.uuid);
|
||||
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
||||
|
||||
if (fromSphere && toSphere) {
|
||||
|
@ -325,22 +460,23 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
|
||||
return (
|
||||
<QuadraticBezierLine
|
||||
key={`${point.uuid}-${target.pointUUID}-${index}`}
|
||||
key={`${path.point.uuid}-${target.pointUUID}-${index}`}
|
||||
start={fromWorldPosition.toArray()}
|
||||
end={toWorldPosition.toArray()}
|
||||
mid={midPoint.toArray()}
|
||||
color="white"
|
||||
color="orange"
|
||||
lineWidth={4}
|
||||
dashed
|
||||
dashSize={1}
|
||||
dashSize={0.75}
|
||||
dashScale={20}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
)
|
||||
)}
|
||||
});
|
||||
}
|
||||
return [];
|
||||
})}
|
||||
|
||||
{currentLine && (
|
||||
<QuadraticBezierLine
|
||||
|
|
|
@ -4,10 +4,12 @@ import { Sphere, TransformControls } from '@react-three/drei';
|
|||
import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { useSubModuleStore } from '../../../store/useModuleStore';
|
||||
import { point } from '@turf/helpers';
|
||||
|
||||
interface Path {
|
||||
interface ConveyorEventsSchema {
|
||||
modeluuid: string;
|
||||
modelName: string;
|
||||
type: 'Conveyor';
|
||||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
|
@ -16,8 +18,8 @@ interface Path {
|
|||
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
|
||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
}[];
|
||||
pathPosition: [number, number, number];
|
||||
pathRotation: [number, number, number];
|
||||
assetPosition: [number, number, number];
|
||||
assetRotation: [number, number, number];
|
||||
speed: number;
|
||||
}
|
||||
|
||||
|
@ -63,99 +65,154 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
|||
const updateSimulationPaths = () => {
|
||||
if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths: Path[] = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
position: [
|
||||
selectedActionSphere.point.position.x,
|
||||
selectedActionSphere.point.position.y,
|
||||
selectedActionSphere.point.position.z,
|
||||
],
|
||||
rotation: [
|
||||
selectedActionSphere.point.rotation.x,
|
||||
selectedActionSphere.point.rotation.y,
|
||||
selectedActionSphere.point.rotation.z,
|
||||
]
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
const updatedPaths = simulationPaths.map((path) => {
|
||||
if (path.type === "Conveyor") {
|
||||
return {
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
position: [
|
||||
selectedActionSphere.point.position.x,
|
||||
selectedActionSphere.point.position.y,
|
||||
selectedActionSphere.point.position.z,
|
||||
],
|
||||
rotation: [
|
||||
selectedActionSphere.point.rotation.x,
|
||||
selectedActionSphere.point.rotation.y,
|
||||
selectedActionSphere.point.rotation.z,
|
||||
]
|
||||
}
|
||||
: point
|
||||
),
|
||||
};
|
||||
}
|
||||
return path;
|
||||
}) as ConveyorEventsSchema[];
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<group name='simulation-simulationPaths-group' ref={pathsGroupRef} >
|
||||
<group name='simulation-simulationPaths-group' ref={pathsGroupRef}>
|
||||
{simulationPaths.map((path) => {
|
||||
const points = path.points.map(point => new THREE.Vector3(...point.position));
|
||||
if (path.type === 'Conveyor') {
|
||||
const points = path.points.map(point => new THREE.Vector3(...point.position));
|
||||
|
||||
return (
|
||||
<group
|
||||
name={`${path.modeluuid}-event-path`}
|
||||
key={path.modeluuid}
|
||||
ref={el => (groupRefs.current[path.modeluuid] = el!)}
|
||||
position={path.pathPosition}
|
||||
rotation={path.pathRotation}
|
||||
onClick={(e) => {
|
||||
if (isConnecting) return;
|
||||
e.stopPropagation();
|
||||
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||
setSelectedActionSphere(null);
|
||||
setTransformMode(null);
|
||||
setSubModule('mechanics');
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
setSelectedPath(null);
|
||||
setSubModule('properties');
|
||||
}}
|
||||
>
|
||||
{path.points.map((point, index) => (
|
||||
return (
|
||||
<group
|
||||
name={`${path.modeluuid}-event-path`}
|
||||
key={path.modeluuid}
|
||||
ref={el => (groupRefs.current[path.modeluuid] = el!)}
|
||||
position={path.assetPosition}
|
||||
rotation={path.assetRotation}
|
||||
onClick={(e) => {
|
||||
if (isConnecting) return;
|
||||
e.stopPropagation();
|
||||
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||
setSelectedActionSphere(null);
|
||||
setTransformMode(null);
|
||||
setSubModule('mechanics');
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
setSelectedPath(null);
|
||||
setSubModule('properties');
|
||||
}}
|
||||
>
|
||||
{path.points.map((point, index) => (
|
||||
<Sphere
|
||||
key={point.uuid}
|
||||
uuid={point.uuid}
|
||||
position={point.position}
|
||||
args={[0.15, 32, 32]}
|
||||
name='events-sphere'
|
||||
ref={el => (sphereRefs.current[point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
if (isConnecting) return;
|
||||
e.stopPropagation();
|
||||
setSelectedActionSphere({
|
||||
path,
|
||||
point: sphereRefs.current[point.uuid]
|
||||
});
|
||||
setSubModule('mechanics');
|
||||
setSelectedPath(null);
|
||||
}}
|
||||
userData={{ point, path }}
|
||||
onPointerMissed={() => {
|
||||
setSubModule('properties');
|
||||
setSelectedActionSphere(null);
|
||||
}}
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={index === 0 ? 'orange' : index === path.points.length - 1 ? 'blue' : 'green'}
|
||||
/>
|
||||
</Sphere>
|
||||
))}
|
||||
|
||||
{points.slice(0, -1).map((point, index) => {
|
||||
const nextPoint = points[index + 1];
|
||||
const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint]);
|
||||
const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false);
|
||||
|
||||
return (
|
||||
<mesh name='event-connection-tube' key={`tube-${index}`} geometry={tubeGeometry}>
|
||||
<meshStandardMaterial transparent opacity={0.9} color="red" />
|
||||
</mesh>
|
||||
);
|
||||
})}
|
||||
</group>
|
||||
);
|
||||
} else if (path.type === 'Vehicle') {
|
||||
return (
|
||||
<group
|
||||
name={`${path.modeluuid}-vehicle-path`}
|
||||
key={path.modeluuid}
|
||||
ref={el => (groupRefs.current[path.modeluuid] = el!)}
|
||||
position={path.assetPosition}
|
||||
onClick={(e) => {
|
||||
if (isConnecting) return;
|
||||
e.stopPropagation();
|
||||
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||
setSelectedActionSphere(null);
|
||||
setTransformMode(null);
|
||||
setSubModule('mechanics');
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
setSelectedPath(null);
|
||||
setSubModule('properties');
|
||||
}}
|
||||
>
|
||||
<Sphere
|
||||
key={point.uuid}
|
||||
uuid={point.uuid}
|
||||
position={point.position}
|
||||
key={path.point.uuid}
|
||||
uuid={path.point.uuid}
|
||||
position={path.point.position}
|
||||
args={[0.15, 32, 32]}
|
||||
name='action-sphere'
|
||||
ref={el => (sphereRefs.current[point.uuid] = el!)}
|
||||
name='events-sphere'
|
||||
ref={el => (sphereRefs.current[path.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
if (isConnecting) return;
|
||||
e.stopPropagation();
|
||||
setSelectedActionSphere({
|
||||
path,
|
||||
point: sphereRefs.current[point.uuid]
|
||||
point: sphereRefs.current[path.point.uuid]
|
||||
});
|
||||
setSubModule('mechanics');
|
||||
setSelectedPath(null);
|
||||
}}
|
||||
userData={{ point, path }}
|
||||
userData={{ point: path.point, path }}
|
||||
onPointerMissed={() => {
|
||||
setSubModule('properties');
|
||||
setSelectedActionSphere(null)
|
||||
setSelectedActionSphere(null);
|
||||
}}
|
||||
>
|
||||
<meshStandardMaterial
|
||||
color={index === 0 ? 'orange' : index === path.points.length - 1 ? 'blue' : 'green'}
|
||||
/>
|
||||
<meshStandardMaterial color="purple" />
|
||||
</Sphere>
|
||||
))}
|
||||
|
||||
{points.slice(0, -1).map((point, index) => {
|
||||
const nextPoint = points[index + 1];
|
||||
const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint]);
|
||||
const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false);
|
||||
|
||||
return (
|
||||
<mesh name='event-connection-tube' key={`tube-${index}`} geometry={tubeGeometry}>
|
||||
<meshStandardMaterial transparent opacity={0.9} color="red" />
|
||||
</mesh>
|
||||
);
|
||||
})}
|
||||
</group>
|
||||
);
|
||||
</group>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
|
||||
{selectedActionSphere && transformMode && (
|
||||
|
@ -163,7 +220,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
|||
ref={transformRef}
|
||||
object={selectedActionSphere.point}
|
||||
mode={transformMode}
|
||||
onObjectChange={updateSimulationPaths}
|
||||
onMouseUp={updateSimulationPaths}
|
||||
/>
|
||||
)}
|
||||
</group>
|
||||
|
|
|
@ -14,7 +14,7 @@ function Simulation() {
|
|||
const [processes, setProcesses] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('simulationPaths: ', simulationPaths);
|
||||
|
||||
}, [simulationPaths]);
|
||||
|
||||
// useEffect(() => {
|
||||
|
@ -31,7 +31,7 @@ function Simulation() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Behaviour setSimulationPaths={setSimulationPaths} />
|
||||
<Behaviour/>
|
||||
{activeModule === 'simulation' && (
|
||||
<>
|
||||
<PathCreation pathsGroupRef={pathsGroupRef} />
|
||||
|
|
|
@ -1,409 +1,409 @@
|
|||
import { useMemo, useState } from 'react';
|
||||
import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store';
|
||||
import * as THREE from 'three';
|
||||
import useModuleStore from '../../store/useModuleStore';
|
||||
// import { useMemo, useState } from 'react';
|
||||
// import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store';
|
||||
// import * as THREE from 'three';
|
||||
// import useModuleStore from '../../store/useModuleStore';
|
||||
|
||||
function SimulationUI() {
|
||||
const { ToggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { startSimulation, setStartSimulation } = useStartSimulation();
|
||||
const { selectedActionSphere } = useSelectedActionSphere();
|
||||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||
const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath();
|
||||
const [activeButton, setActiveButton] = useState<string | null>(null);
|
||||
// function SimulationUI() {
|
||||
// const { ToggleView } = useToggleView();
|
||||
// const { activeModule } = useModuleStore();
|
||||
// const { startSimulation, setStartSimulation } = useStartSimulation();
|
||||
// const { selectedActionSphere } = useSelectedActionSphere();
|
||||
// const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||
// const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||
// const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath();
|
||||
// const [activeButton, setActiveButton] = useState<string | null>(null);
|
||||
|
||||
const handleAddAction = () => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleAddAction = () => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
const actionIndex = point.actions.length;
|
||||
const newAction = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: `Action ${actionIndex + 1}`, // Assign action name based on index
|
||||
type: 'Inherit',
|
||||
material: 'Inherit',
|
||||
delay: 'Inherit',
|
||||
spawnInterval: 'Inherit',
|
||||
isUsed: false
|
||||
};
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) => {
|
||||
// if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
// const actionIndex = point.actions.length;
|
||||
// const newAction = {
|
||||
// uuid: THREE.MathUtils.generateUUID(),
|
||||
// name: `Action ${actionIndex + 1}`, // Assign action name based on index
|
||||
// type: 'Inherit',
|
||||
// material: 'Inherit',
|
||||
// delay: 'Inherit',
|
||||
// spawnInterval: 'Inherit',
|
||||
// isUsed: false
|
||||
// };
|
||||
|
||||
return { ...point, actions: [...point.actions, newAction] };
|
||||
}
|
||||
return point;
|
||||
}),
|
||||
}));
|
||||
// return { ...point, actions: [...point.actions, newAction] };
|
||||
// }
|
||||
// return point;
|
||||
// }),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleDeleteAction = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleDeleteAction = (uuid: string) => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
||||
: point
|
||||
),
|
||||
}));
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// ? { ...point, actions: point.actions.filter(action => action.uuid !== uuid) }
|
||||
// : point
|
||||
// ),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleActionSelect = (uuid: string, actionType: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleActionSelect = (uuid: string, actionType: string) => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, type: actionType } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) =>
|
||||
// action.uuid === uuid ? { ...action, type: actionType } : action
|
||||
// ),
|
||||
// }
|
||||
// : point
|
||||
// ),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleMaterialSelect = (uuid: string, material: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleMaterialSelect = (uuid: string, material: string) => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, material } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) =>
|
||||
// action.uuid === uuid ? { ...action, material } : action
|
||||
// ),
|
||||
// }
|
||||
// : point
|
||||
// ),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleDelayChange = (uuid: string, delay: number | string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleDelayChange = (uuid: string, delay: number | string) => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, delay } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) =>
|
||||
// action.uuid === uuid ? { ...action, delay } : action
|
||||
// ),
|
||||
// }
|
||||
// : point
|
||||
// ),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleSpawnIntervalChange = (uuid: string, spawnInterval: number | string) => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) =>
|
||||
action.uuid === uuid ? { ...action, spawnInterval } : action
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) =>
|
||||
// action.uuid === uuid ? { ...action, spawnInterval } : action
|
||||
// ),
|
||||
// }
|
||||
// : point
|
||||
// ),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleSpeedChange = (speed: number) => {
|
||||
if (!selectedPath) return;
|
||||
// const handleSpeedChange = (speed: number) => {
|
||||
// if (!selectedPath) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) =>
|
||||
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
||||
);
|
||||
// const updatedPaths = simulationPaths.map((path) =>
|
||||
// path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
||||
// );
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
|
||||
// };
|
||||
|
||||
const handleAddTrigger = () => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleAddTrigger = () => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) => {
|
||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
const triggerIndex = point.triggers.length;
|
||||
const newTrigger = {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
name: `Trigger ${triggerIndex + 1}`, // Assign name based on index
|
||||
type: '',
|
||||
isUsed: false
|
||||
};
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) => {
|
||||
// if (point.uuid === selectedActionSphere.point.uuid) {
|
||||
// const triggerIndex = point.triggers.length;
|
||||
// const newTrigger = {
|
||||
// uuid: THREE.MathUtils.generateUUID(),
|
||||
// name: `Trigger ${triggerIndex + 1}`, // Assign name based on index
|
||||
// type: '',
|
||||
// isUsed: false
|
||||
// };
|
||||
|
||||
return { ...point, triggers: [...point.triggers, newTrigger] };
|
||||
}
|
||||
return point;
|
||||
}),
|
||||
}));
|
||||
// return { ...point, triggers: [...point.triggers, newTrigger] };
|
||||
// }
|
||||
// return point;
|
||||
// }),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleDeleteTrigger = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleDeleteTrigger = (uuid: string) => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
||||
: point
|
||||
),
|
||||
}));
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// ? { ...point, triggers: point.triggers.filter(trigger => trigger.uuid !== uuid) }
|
||||
// : point
|
||||
// ),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleTriggerSelect = (uuid: string, triggerType: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleTriggerSelect = (uuid: string, triggerType: string) => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) =>
|
||||
trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
|
||||
),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// triggers: point.triggers.map((trigger) =>
|
||||
// trigger.uuid === uuid ? { ...trigger, type: triggerType } : trigger
|
||||
// ),
|
||||
// }
|
||||
// : point
|
||||
// ),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleResetPath = () => {
|
||||
if (!selectedPath) return;
|
||||
// const handleResetPath = () => {
|
||||
// if (!selectedPath) return;
|
||||
|
||||
};
|
||||
// };
|
||||
|
||||
|
||||
const handleActionToggle = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleActionToggle = (uuid: string) => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
actions: point.actions.map((action) => ({
|
||||
...action,
|
||||
isUsed: action.uuid === uuid ? !action.isUsed : false,
|
||||
})),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// actions: point.actions.map((action) => ({
|
||||
// ...action,
|
||||
// isUsed: action.uuid === uuid ? !action.isUsed : false,
|
||||
// })),
|
||||
// }
|
||||
// : point
|
||||
// ),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const handleTriggerToggle = (uuid: string) => {
|
||||
if (!selectedActionSphere) return;
|
||||
// const handleTriggerToggle = (uuid: string) => {
|
||||
// if (!selectedActionSphere) return;
|
||||
|
||||
const updatedPaths = simulationPaths.map((path) => ({
|
||||
...path,
|
||||
points: path.points.map((point) =>
|
||||
point.uuid === selectedActionSphere.point.uuid
|
||||
? {
|
||||
...point,
|
||||
triggers: point.triggers.map((trigger) => ({
|
||||
...trigger,
|
||||
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
|
||||
})),
|
||||
}
|
||||
: point
|
||||
),
|
||||
}));
|
||||
// const updatedPaths = simulationPaths.map((path) => ({
|
||||
// ...path,
|
||||
// points: path.points.map((point) =>
|
||||
// point.uuid === selectedActionSphere.point.uuid
|
||||
// ? {
|
||||
// ...point,
|
||||
// triggers: point.triggers.map((trigger) => ({
|
||||
// ...trigger,
|
||||
// isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
|
||||
// })),
|
||||
// }
|
||||
// : point
|
||||
// ),
|
||||
// }));
|
||||
|
||||
setSimulationPaths(updatedPaths);
|
||||
};
|
||||
// setSimulationPaths(updatedPaths);
|
||||
// };
|
||||
|
||||
const selectedPoint = useMemo(() => {
|
||||
if (!selectedActionSphere) return null;
|
||||
return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||
}, [selectedActionSphere, simulationPaths]);
|
||||
// const selectedPoint = useMemo(() => {
|
||||
// if (!selectedActionSphere) return null;
|
||||
// return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||
// }, [selectedActionSphere, simulationPaths]);
|
||||
|
||||
const createPath = () => {
|
||||
setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);
|
||||
setDrawMaterialPath(!drawMaterialPath);
|
||||
}
|
||||
// const createPath = () => {
|
||||
// setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);
|
||||
// setDrawMaterialPath(!drawMaterialPath);
|
||||
// }
|
||||
|
||||
return (
|
||||
<>
|
||||
{activeModule === "simulation" && (
|
||||
<div style={{ zIndex: 10, position: "fixed", width: '260px' }}>
|
||||
{!ToggleView && (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setStartSimulation(!startSimulation)}
|
||||
style={{
|
||||
marginTop: "10px",
|
||||
background: startSimulation ? '#ff320e' : '',
|
||||
padding: "10px",
|
||||
borderRadius: "5px"
|
||||
}}
|
||||
>
|
||||
{startSimulation ? 'Stop Simulation' : 'Start Simulation'}
|
||||
</button>
|
||||
// return (
|
||||
// <>
|
||||
// {activeModule === "simulation" && (
|
||||
// <div style={{ zIndex: 10, position: "fixed", width: '260px' }}>
|
||||
// {!ToggleView && (
|
||||
// <>
|
||||
// <button
|
||||
// onClick={() => setStartSimulation(!startSimulation)}
|
||||
// style={{
|
||||
// marginTop: "10px",
|
||||
// background: startSimulation ? '#ff320e' : '',
|
||||
// padding: "10px",
|
||||
// borderRadius: "5px"
|
||||
// }}
|
||||
// >
|
||||
// {startSimulation ? 'Stop Simulation' : 'Start Simulation'}
|
||||
// </button>
|
||||
|
||||
<div style={{ zIndex: "10", position: "relative" }}>
|
||||
{!ToggleView && <button onClick={createPath} style={{ marginTop: "10px", background: activeButton === 'addMaterialPath' ? '#ff320e' : '' }}> Add Material Path</button>}
|
||||
</div>
|
||||
// <div style={{ zIndex: "10", position: "relative" }}>
|
||||
// {!ToggleView && <button onClick={createPath} style={{ marginTop: "10px", background: activeButton === 'addMaterialPath' ? '#ff320e' : '' }}> Add Material Path</button>}
|
||||
// </div>
|
||||
|
||||
{selectedPath && (
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
<label>Path Speed:</label>
|
||||
<input
|
||||
style={{ width: '50px' }}
|
||||
type="number"
|
||||
value={selectedPath.path.speed}
|
||||
min="0.1"
|
||||
step="0.1"
|
||||
onChange={(e) => handleSpeedChange(parseFloat(e.target.value))}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
// {selectedPath && (
|
||||
// <div style={{ marginTop: "10px" }}>
|
||||
// <label>Path Speed:</label>
|
||||
// <input
|
||||
// style={{ width: '50px' }}
|
||||
// type="number"
|
||||
// value={selectedPath.path.speed}
|
||||
// min="0.1"
|
||||
// step="0.1"
|
||||
// onChange={(e) => handleSpeedChange(parseFloat(e.target.value))}
|
||||
// />
|
||||
// </div>
|
||||
// )}
|
||||
|
||||
{selectedActionSphere && (
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
<button onClick={handleAddAction}>Add Action</button>
|
||||
<button onClick={handleAddTrigger}>Add Trigger</button>
|
||||
// {selectedActionSphere && (
|
||||
// <div style={{ marginTop: "10px" }}>
|
||||
// <button onClick={handleAddAction}>Add Action</button>
|
||||
// <button onClick={handleAddTrigger}>Add Trigger</button>
|
||||
|
||||
{selectedPoint?.actions.map((action) => (
|
||||
<div key={action.uuid} style={{ marginTop: "10px" }}>
|
||||
<select value={action.type} onChange={(e) => handleActionSelect(action.uuid, e.target.value)}>
|
||||
<option value="Inherit">Inherit</option>
|
||||
<option value="Spawn">Spawn Point</option>
|
||||
<option value="Swap">Swap Material</option>
|
||||
<option value="Despawn">Despawn Point</option>
|
||||
<option value="Delay">Delay</option>
|
||||
</select>
|
||||
<button onClick={() => handleDeleteAction(action.uuid)}>Delete Action</button>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={action.isUsed}
|
||||
onChange={() => handleActionToggle(action.uuid)}
|
||||
/>
|
||||
</label>
|
||||
// {selectedPoint?.actions.map((action) => (
|
||||
// <div key={action.uuid} style={{ marginTop: "10px" }}>
|
||||
// <select value={action.type} onChange={(e) => handleActionSelect(action.uuid, e.target.value)}>
|
||||
// <option value="Inherit">Inherit</option>
|
||||
// <option value="Spawn">Spawn Point</option>
|
||||
// <option value="Swap">Swap Material</option>
|
||||
// <option value="Despawn">Despawn Point</option>
|
||||
// <option value="Delay">Delay</option>
|
||||
// </select>
|
||||
// <button onClick={() => handleDeleteAction(action.uuid)}>Delete Action</button>
|
||||
// <label>
|
||||
// <input
|
||||
// type="checkbox"
|
||||
// checked={action.isUsed}
|
||||
// onChange={() => handleActionToggle(action.uuid)}
|
||||
// />
|
||||
// </label>
|
||||
|
||||
{(action.type === 'Spawn' || action.type === 'Swap') && (
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
<select value={action.material} onChange={(e) => handleMaterialSelect(action.uuid, e.target.value)}>
|
||||
<option value="Inherit">Inherit</option>
|
||||
<option value="Crate">Crate</option>
|
||||
<option value="Box">Box</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
// {(action.type === 'Spawn' || action.type === 'Swap') && (
|
||||
// <div style={{ marginTop: "10px" }}>
|
||||
// <select value={action.material} onChange={(e) => handleMaterialSelect(action.uuid, e.target.value)}>
|
||||
// <option value="Inherit">Inherit</option>
|
||||
// <option value="Crate">Crate</option>
|
||||
// <option value="Box">Box</option>
|
||||
// </select>
|
||||
// </div>
|
||||
// )}
|
||||
|
||||
{action.type === 'Delay' && (
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
<label>Delay Time:</label>
|
||||
<input
|
||||
style={{ width: '50px' }}
|
||||
type="text"
|
||||
value={isNaN(Number(action.delay)) || action.delay === "Inherit" ? "Inherit" : action.delay}
|
||||
min="1"
|
||||
onChange={(e) => handleDelayChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
|
||||
/>
|
||||
// {action.type === 'Delay' && (
|
||||
// <div style={{ marginTop: "10px" }}>
|
||||
// <label>Delay Time:</label>
|
||||
// <input
|
||||
// style={{ width: '50px' }}
|
||||
// type="text"
|
||||
// value={isNaN(Number(action.delay)) || action.delay === "Inherit" ? "Inherit" : action.delay}
|
||||
// min="1"
|
||||
// onChange={(e) => handleDelayChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
|
||||
// />
|
||||
|
||||
</div>
|
||||
)}
|
||||
// </div>
|
||||
// )}
|
||||
|
||||
{action.type === 'Spawn' && (
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
<label>Spawn Interval:</label>
|
||||
<input
|
||||
style={{ width: '50px' }}
|
||||
type="text"
|
||||
value={isNaN(Number(action.spawnInterval)) || action.spawnInterval === "Inherit" ? "Inherit" : action.spawnInterval}
|
||||
min="1"
|
||||
onChange={(e) => handleSpawnIntervalChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
|
||||
/>
|
||||
// {action.type === 'Spawn' && (
|
||||
// <div style={{ marginTop: "10px" }}>
|
||||
// <label>Spawn Interval:</label>
|
||||
// <input
|
||||
// style={{ width: '50px' }}
|
||||
// type="text"
|
||||
// value={isNaN(Number(action.spawnInterval)) || action.spawnInterval === "Inherit" ? "Inherit" : action.spawnInterval}
|
||||
// min="1"
|
||||
// onChange={(e) => handleSpawnIntervalChange(action.uuid, parseInt(e.target.value) || 'Inherit')}
|
||||
// />
|
||||
|
||||
</div>
|
||||
)}
|
||||
<hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
|
||||
</div>
|
||||
))}
|
||||
// </div>
|
||||
// )}
|
||||
// <hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
|
||||
// </div>
|
||||
// ))}
|
||||
|
||||
<hr style={{ margin: "10px 0", border: "1px solid black" }} />
|
||||
// <hr style={{ margin: "10px 0", border: "1px solid black" }} />
|
||||
|
||||
{selectedPoint?.triggers.map((trigger) => (
|
||||
<div key={trigger.uuid} style={{ marginTop: "10px" }}>
|
||||
<select value={trigger.type} onChange={(e) => handleTriggerSelect(trigger.uuid, e.target.value)}>
|
||||
<option value="">Select Trigger Type</option>
|
||||
<option value="On-Hit">On Hit</option>
|
||||
<option value="Buffer">Buffer</option>
|
||||
</select>
|
||||
<button onClick={() => handleDeleteTrigger(trigger.uuid)}>Delete Trigger</button>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={trigger.isUsed}
|
||||
onChange={() => handleTriggerToggle(trigger.uuid)}
|
||||
/>
|
||||
</label>
|
||||
<hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
|
||||
</div>
|
||||
))}
|
||||
// {selectedPoint?.triggers.map((trigger) => (
|
||||
// <div key={trigger.uuid} style={{ marginTop: "10px" }}>
|
||||
// <select value={trigger.type} onChange={(e) => handleTriggerSelect(trigger.uuid, e.target.value)}>
|
||||
// <option value="">Select Trigger Type</option>
|
||||
// <option value="On-Hit">On Hit</option>
|
||||
// <option value="Buffer">Buffer</option>
|
||||
// </select>
|
||||
// <button onClick={() => handleDeleteTrigger(trigger.uuid)}>Delete Trigger</button>
|
||||
// <label>
|
||||
// <input
|
||||
// type="checkbox"
|
||||
// checked={trigger.isUsed}
|
||||
// onChange={() => handleTriggerToggle(trigger.uuid)}
|
||||
// />
|
||||
// </label>
|
||||
// <hr style={{ margin: "10px 0", borderColor: "#ccc" }} />
|
||||
// </div>
|
||||
// ))}
|
||||
|
||||
|
||||
</div>
|
||||
)}
|
||||
// </div>
|
||||
// )}
|
||||
|
||||
{selectedPath && (
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
<button
|
||||
onClick={handleResetPath}
|
||||
style={{ padding: "10px", borderRadius: "5px", background: "#ff0000", color: "#fff" }}
|
||||
>
|
||||
Reset Path
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
// {selectedPath && (
|
||||
// <div style={{ marginTop: "10px" }}>
|
||||
// <button
|
||||
// onClick={handleResetPath}
|
||||
// style={{ padding: "10px", borderRadius: "5px", background: "#ff0000", color: "#fff" }}
|
||||
// >
|
||||
// Reset Path
|
||||
// </button>
|
||||
// </div>
|
||||
// )}
|
||||
// </>
|
||||
// )}
|
||||
// </div>
|
||||
// )}
|
||||
// </>
|
||||
// );
|
||||
// }
|
||||
|
||||
export default SimulationUI;
|
||||
// export default SimulationUI;
|
|
@ -64,7 +64,6 @@ const Project: React.FC = () => {
|
|||
{activeModule === "market" && <MarketPlace />}
|
||||
<RealTimeVisulization />
|
||||
{activeModule !== "market" && <Tools />}
|
||||
{/* <SimulationUI /> */}
|
||||
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -6,10 +6,7 @@ const MqttEvents = () => {
|
|||
const { setTouch, setTemperature, setHumidity } = useDrieUIValue();
|
||||
useEffect(() => {
|
||||
|
||||
const client = mqtt.connect("ws://192.168.0.192:1884", {
|
||||
username: "gabby",
|
||||
password: "gabby"
|
||||
});
|
||||
const client = mqtt.connect(`ws://${process.env.REACT_APP_SERVER_MQTT_URL}`);
|
||||
|
||||
client.subscribe("touch");
|
||||
client.subscribe("temperature");
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
export const getAssetDetails = async (filename: string) => {
|
||||
try {
|
||||
const response = await fetch(`${BackEnd_url}/api/v1/assetDetails`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ filename }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch asset details");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
// console.error("Error fetching category:", error.message);
|
||||
throw new Error(error.message);
|
||||
}
|
||||
};
|
|
@ -6,6 +6,8 @@ export const fetchAssets = async () => {
|
|||
throw new Error("Network response was not ok");
|
||||
}
|
||||
const result = await response.json();
|
||||
const last10Assets = result.slice(-10);
|
||||
console.log('last10Assets: ', last10Assets);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.log("error: ", error);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
export const fetchGltfUrl = (filename: string) => {
|
||||
if (filename) {
|
||||
return `${BackEnd_url}/api/v1/getAssetFile/${filename}`;
|
||||
}
|
||||
return null; // or handle the case when filename is not provided
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
export const getAssetDownload = (filename: any) => {
|
||||
return `${BackEnd_url}/api/v1/getAssetFile/${filename}.gltf`;
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
export const getSortedAssets = async (category: any, orders: any) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BackEnd_url}/api/v1/categoryWise/${category}?sortBy=${orders}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Error: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
return result; // Return the result to be used later
|
||||
} catch (error: any) {
|
||||
console.error("Error fetching category:", error.message);
|
||||
throw new Error(error.message);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
export const addingWidgets = async (
|
||||
zoneId: string,
|
||||
organization: string,
|
||||
widget: {}
|
||||
) => {
|
||||
try {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/v2/widget/save`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ organization, zoneId, widget }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to add widget in the zone");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(error.message);
|
||||
} else {
|
||||
throw new Error("An unknown error occurred");
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
console.log("url_Backend_dwinzo: ", url_Backend_dwinzo);
|
||||
|
||||
export const getSelect2dZoneData = async (
|
||||
ZoneId?: string,
|
||||
organization?: string
|
||||
) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${url_Backend_dwinzo}/api/v2/ZoneVisualization/${ZoneId}?organization=${organization}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch zoneDatas");
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
export const getZone2dData = async (organization?: string) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${url_Backend_dwinzo}/api/v2/pageZodeData?organization=${organization}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch zoneDatas");
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message);
|
||||
}
|
||||
};
|
|
@ -1,22 +1,19 @@
|
|||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_BACKEND_URL}`;
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
export const panelData = async (
|
||||
organization: string,
|
||||
zoneID: string,
|
||||
zoneId: string,
|
||||
panelOrder: Side[]
|
||||
) => {
|
||||
console.log("panelOrder: ", panelOrder);
|
||||
console.log("zoneID: ", zoneID);
|
||||
console.log("organization: ", organization);
|
||||
try {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/v1/panel/save`, {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/v2/panel/save`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ organization, zoneID, panelOrder }),
|
||||
body: JSON.stringify({ organization, zoneId, panelOrder }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
|
@ -33,16 +30,3 @@ export const panelData = async (
|
|||
}
|
||||
}
|
||||
};
|
||||
// {objects.map((obj, index) => (
|
||||
// <group key={index} position={[Math.random() * 5, Math.random() * 5, 0]}>
|
||||
// <Html wrapperClass={obj.className}>
|
||||
// <div style={{ padding: "10px", background: "#fff", borderRadius: "6px" }}>
|
||||
// <div className="header">{obj.header}</div>
|
||||
// <div className="data-values">
|
||||
// <div className="value">{obj.value}</div>
|
||||
// <div className="per">{obj.per}</div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </Html>
|
||||
// </group>
|
||||
// ))}
|
||||
|
|
|
@ -2,7 +2,6 @@ import * as THREE from "three";
|
|||
import * as Types from "../types/world/worldTypes";
|
||||
import { create } from "zustand";
|
||||
import { io } from "socket.io-client";
|
||||
import { ComponentType, SVGProps } from "react";
|
||||
|
||||
export const useSocketStore = create<any>((set: any, get: any) => ({
|
||||
socket: null,
|
||||
|
@ -31,8 +30,8 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
|
|||
}));
|
||||
|
||||
export const useLoadingProgress = create<{ 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<any>((set: any) => ({
|
||||
|
@ -311,30 +310,14 @@ export const useSelectedPath = create<any>((set: any) => ({
|
|||
setSelectedPath: (x: any) => set({ selectedPath: x }),
|
||||
}));
|
||||
|
||||
interface Path {
|
||||
modeluuid: string;
|
||||
modelName: string;
|
||||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
||||
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
|
||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
}[];
|
||||
pathPosition: [number, number, number];
|
||||
pathRotation: [number, number, number];
|
||||
speed: number;
|
||||
}
|
||||
|
||||
interface SimulationPathsStore {
|
||||
simulationPaths: Path[];
|
||||
setSimulationPaths: (paths: Path[]) => void;
|
||||
simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[];
|
||||
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void;
|
||||
}
|
||||
|
||||
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
|
||||
simulationPaths: [],
|
||||
setSimulationPaths: (paths: Path[]) => set({ simulationPaths: paths }),
|
||||
simulationPaths: [],
|
||||
setSimulationPaths: (paths) => set({ simulationPaths: paths }),
|
||||
}));
|
||||
|
||||
export const useIsConnecting = create<any>((set: any) => ({
|
||||
|
@ -365,4 +348,7 @@ export const useEditPosition = create<EditPositionState>((set) => ({
|
|||
setEdit: (value) => set({ Edit: value }), // Properly updating the state
|
||||
}));
|
||||
|
||||
|
||||
export const useAsset3dWidget = create<any>((set: any) => ({
|
||||
widgetSelect: "",
|
||||
setWidgetSelect: (x: any) => set({ widgetSelect: x }),
|
||||
}));
|
||||
|
|
|
@ -6,15 +6,15 @@ interface Measurement {
|
|||
}
|
||||
|
||||
interface MeasurementStore {
|
||||
measurements: Measurement[];
|
||||
measurements: Record<string, Measurement>; // Change array to Record<string, Measurement>
|
||||
interval: number;
|
||||
duration: string;
|
||||
setMeasurements: (newMeasurements: Measurement[]) => void;
|
||||
setMeasurements: (newMeasurements: Record<string, Measurement>) => void;
|
||||
updateDuration: (newDuration: string) => void;
|
||||
}
|
||||
|
||||
const useChartStore = create<MeasurementStore>((set) => ({
|
||||
measurements: [],
|
||||
measurements: {}, // Initialize as an empty object
|
||||
interval: 1000,
|
||||
duration: "1h",
|
||||
|
||||
|
@ -26,3 +26,4 @@ const useChartStore = create<MeasurementStore>((set) => ({
|
|||
}));
|
||||
|
||||
export default useChartStore;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ interface SelectedZoneState {
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
|
|
@ -126,6 +126,8 @@
|
|||
display: flex;
|
||||
max-height: 180px;
|
||||
justify-content: center;
|
||||
border-radius: #{$border-radius-medium};
|
||||
overflow: hidden;
|
||||
img{
|
||||
height: inherit;
|
||||
width: 100%;
|
||||
|
@ -211,7 +213,7 @@
|
|||
background-color: var(--background-color);
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
z-index: 100;
|
||||
overflow: hidden;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
|
||||
|
||||
.productionCapacity-wrapper {
|
||||
background: var(--background-color);
|
||||
background-color: var(--background-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
|
@ -170,6 +170,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.bar-chart{
|
||||
padding:14px 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -284,4 +284,36 @@ interface ConnectionStore {
|
|||
setConnections: (connections: PathConnection[]) => void;
|
||||
addConnection: (newConnection: PathConnection) => void;
|
||||
removeConnection: (fromUUID: string, toUUID: string) => void;
|
||||
}
|
||||
|
||||
interface ConveyorEventsSchema {
|
||||
modeluuid: string;
|
||||
modelName: string;
|
||||
type: 'Conveyor';
|
||||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
||||
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
|
||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
}[];
|
||||
assetPosition: [number, number, number];
|
||||
assetRotation: [number, number, number];
|
||||
speed: number;
|
||||
}
|
||||
|
||||
interface VehicleEventsSchema {
|
||||
modeluuid: string;
|
||||
modelName: string;
|
||||
type: 'Vehicle';
|
||||
point: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; start: string, hitCount: number, end: string, buffer: number; isUsed: boolean }[] | [];
|
||||
triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] | [];
|
||||
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||
};
|
||||
assetPosition: [number, number, number];
|
||||
speed: number;
|
||||
}
|
Loading…
Reference in New Issue