Merge remote-tracking branch 'origin/main' into ui
This commit is contained in:
2033
app/package-lock.json
generated
2033
app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,10 +9,12 @@
|
|||||||
"@react-three/drei": "^9.113.0",
|
"@react-three/drei": "^9.113.0",
|
||||||
"@react-three/fiber": "^8.17.7",
|
"@react-three/fiber": "^8.17.7",
|
||||||
"@react-three/postprocessing": "^2.16.3",
|
"@react-three/postprocessing": "^2.16.3",
|
||||||
|
"@recast-navigation/three": "^0.39.0",
|
||||||
"@testing-library/jest-dom": "^5.17.0",
|
"@testing-library/jest-dom": "^5.17.0",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"@turf/turf": "^7.1.0",
|
"@turf/helpers": "^7.2.0",
|
||||||
|
"@turf/turf": "^7.2.0",
|
||||||
"@types/jest": "^27.5.2",
|
"@types/jest": "^27.5.2",
|
||||||
"@types/react": "^18.3.5",
|
"@types/react": "^18.3.5",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export function CommentsIcon() {
|
|||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<g clip-path="url(#clip0_2926_17620)">
|
<g clipPath="url(#clip0_2926_17620)">
|
||||||
<path
|
<path
|
||||||
fillRule="evenodd"
|
fillRule="evenodd"
|
||||||
clipRule="evenodd"
|
clipRule="evenodd"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const CardsScene = () => {
|
|||||||
<Canvas>
|
<Canvas>
|
||||||
{/* 3d-cards */}
|
{/* 3d-cards */}
|
||||||
|
|
||||||
{/* <Throughput /> */}
|
<Throughput />
|
||||||
{/* <ReturnOfInvestment /> */}
|
{/* <ReturnOfInvestment /> */}
|
||||||
{/* <ProductionCapacity /> */}
|
{/* <ProductionCapacity /> */}
|
||||||
{/* <StateWorking /> */}
|
{/* <StateWorking /> */}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ const SideBarRight: React.FC = () => {
|
|||||||
{subModule === "mechanics" && !selectedActionSphere && (
|
{subModule === "mechanics" && !selectedActionSphere && (
|
||||||
<div className="sidebar-right-container">
|
<div className="sidebar-right-container">
|
||||||
<div className="sidebar-right-content-container">
|
<div className="sidebar-right-content-container">
|
||||||
<MachineMechanics />
|
{/* <MachineMechanics /> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState, useMemo, useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
AddIcon,
|
AddIcon,
|
||||||
InfoIcon,
|
InfoIcon,
|
||||||
@@ -11,80 +11,332 @@ import LabledDropdown from "../../../ui/inputs/LabledDropdown";
|
|||||||
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
||||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||||
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
|
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
|
||||||
import { useSelectedActionSphere } from "../../../../store/store";
|
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from "../../../../store/store";
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||||
|
|
||||||
const MachineMechanics: React.FC = () => {
|
const MachineMechanics: React.FC = () => {
|
||||||
const { selectedActionSphere } = useSelectedActionSphere();
|
const { selectedActionSphere } = useSelectedActionSphere();
|
||||||
console.log("selectedActionSphere: ", selectedActionSphere);
|
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||||
const [actionList, setActionList] = useState<string[]>([]);
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const [triggerList, setTriggerList] = useState<string[]>([]);
|
|
||||||
const [selectedItem, setSelectedItem] = useState<{
|
|
||||||
type: "action" | "trigger";
|
|
||||||
name: string;
|
|
||||||
} | null>(null);
|
|
||||||
|
|
||||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const triggersContainerRef = 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 = () => {
|
const handleAddAction = () => {
|
||||||
setActionList([...actionList, `Action ${actionList.length + 1}`]);
|
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 = () => {
|
const handleAddTrigger = () => {
|
||||||
setTriggerList([...triggerList, `Trigger ${triggerList.length + 1}`]);
|
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 handleRemoveAction = (index: number) => {
|
const handleDeleteTrigger = (uuid: string) => {
|
||||||
setActionList(actionList.filter((_, i) => i !== index));
|
if (!selectedActionSphere) return;
|
||||||
if (
|
|
||||||
selectedItem?.type === "action" &&
|
const updatedPaths = simulationPaths.map((path) => ({
|
||||||
selectedItem.name === actionList[index]
|
...path,
|
||||||
) {
|
points: path.points.map((point) =>
|
||||||
setSelectedItem(null);
|
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
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveTrigger = (index: number) => {
|
// Do the same for trigger toggle
|
||||||
setTriggerList(triggerList.filter((_, i) => i !== index));
|
const handleTriggerToggle = (uuid: string) => {
|
||||||
if (
|
if (!selectedActionSphere) return;
|
||||||
selectedItem?.type === "trigger" &&
|
|
||||||
selectedItem.name === triggerList[index]
|
const updatedPaths = simulationPaths.map((path) => ({
|
||||||
) {
|
...path,
|
||||||
setSelectedItem(null);
|
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 handleSelectItem = (type: "action" | "trigger", name: string) => {
|
const [selectedItem, setSelectedItem] = useState<{ type: "action" | "trigger"; item: any; } | null>(null);
|
||||||
setSelectedItem({ type, name });
|
|
||||||
};
|
|
||||||
|
|
||||||
const [processes, setProcesses] = useState<string[]>([]);
|
useEffect(() => {
|
||||||
const [activeProcess, setActiveProcesses] = useState<string>();
|
setSelectedItem(null); // Reset selectedItem when selectedActionSphere changes
|
||||||
|
}, [selectedActionSphere]);
|
||||||
const handleSelect = (option: string) => {
|
|
||||||
setActiveProcesses(option); // Update the active option state
|
|
||||||
};
|
|
||||||
const handleAddProcess = () => {
|
|
||||||
const newProcess = `Process ${processes.length + 1}`; // Generate new process name dynamically
|
|
||||||
setProcesses((prevProcesses) => [...prevProcesses, newProcess]); // Update the state with the new process
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="machine-mechanics-container">
|
<div className="machine-mechanics-container">
|
||||||
<div className="machine-mechanics-header">
|
<div className="machine-mechanics-header">
|
||||||
{selectedActionSphere?.path?.modelName || "path name not found"}
|
{selectedActionSphere?.path?.modelName || "point name not found"}
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="process-list-container">
|
|
||||||
<div className="label">Process:</div>
|
|
||||||
<RegularDropDown
|
|
||||||
header={activeProcess || "add process ->"}
|
|
||||||
options={processes}
|
|
||||||
onSelect={handleSelect}
|
|
||||||
/>
|
|
||||||
<div className="add-new-process" onClick={handleAddProcess}>
|
|
||||||
<AddIcon />
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
<div className="machine-mechanics-content-container">
|
<div className="machine-mechanics-content-container">
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
@@ -99,25 +351,24 @@ const MachineMechanics: React.FC = () => {
|
|||||||
style={{ height: "120px" }}
|
style={{ height: "120px" }}
|
||||||
>
|
>
|
||||||
<div className="list-container">
|
<div className="list-container">
|
||||||
{actionList.map((action, index) => (
|
{selectedPoint?.actions.map((action) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={action.uuid}
|
||||||
className={`list-item ${
|
className={`list-item ${selectedItem?.type === "action" &&
|
||||||
selectedItem?.type === "action" &&
|
selectedItem.item?.uuid === action.uuid
|
||||||
selectedItem.name === action
|
? "active"
|
||||||
? "active"
|
: ""
|
||||||
: ""
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="value"
|
className="value"
|
||||||
onClick={() => handleSelectItem("action", action)}
|
onClick={() => setSelectedItem({ type: "action", item: action })}
|
||||||
>
|
>
|
||||||
<RenameInput value={action} />
|
<RenameInput value={action.name} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="remove-button"
|
className="remove-button"
|
||||||
onClick={() => handleRemoveAction(index)}
|
onClick={() => handleDeleteAction(action.uuid)}
|
||||||
>
|
>
|
||||||
<RemoveIcon />
|
<RemoveIcon />
|
||||||
</div>
|
</div>
|
||||||
@@ -146,25 +397,24 @@ const MachineMechanics: React.FC = () => {
|
|||||||
style={{ height: "120px" }}
|
style={{ height: "120px" }}
|
||||||
>
|
>
|
||||||
<div className="list-container">
|
<div className="list-container">
|
||||||
{triggerList.map((trigger, index) => (
|
{selectedPoint?.triggers.map((trigger) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={trigger.uuid}
|
||||||
className={`list-item ${
|
className={`list-item ${selectedItem?.type === "trigger" &&
|
||||||
selectedItem?.type === "trigger" &&
|
selectedItem.item?.uuid === trigger.uuid
|
||||||
selectedItem.name === trigger
|
? "active"
|
||||||
? "active"
|
: ""
|
||||||
: ""
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="value"
|
className="value"
|
||||||
onClick={() => handleSelectItem("trigger", trigger)}
|
onClick={() => setSelectedItem({ type: "trigger", item: trigger })}
|
||||||
>
|
>
|
||||||
<RenameInput value={trigger} />
|
<RenameInput value={trigger.name} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="remove-button"
|
className="remove-button"
|
||||||
onClick={() => handleRemoveTrigger(index)}
|
onClick={() => handleDeleteTrigger(trigger.uuid)}
|
||||||
>
|
>
|
||||||
<RemoveIcon />
|
<RemoveIcon />
|
||||||
</div>
|
</div>
|
||||||
@@ -183,28 +433,101 @@ const MachineMechanics: React.FC = () => {
|
|||||||
<div className="selected-properties-container">
|
<div className="selected-properties-container">
|
||||||
{selectedItem && (
|
{selectedItem && (
|
||||||
<>
|
<>
|
||||||
<div className="properties-header">{selectedItem.name}</div>
|
<div className="properties-header">{selectedItem.item.name}</div>
|
||||||
<LabledDropdown
|
|
||||||
defaultOption="On-hit"
|
{selectedItem.type === "action" && (
|
||||||
options={["On-hit", "Buffer"]}
|
<>
|
||||||
/>
|
<InputToggle
|
||||||
<InputWithDropDown
|
inputKey="enableTrigger"
|
||||||
label="Speed"
|
label="Enable Trigger"
|
||||||
value=""
|
value={selectedItem.item.isUsed}
|
||||||
activeOption=".mm"
|
onClick={() => handleActionToggle(selectedItem.item.uuid)}
|
||||||
onChange={() => {}}
|
/>
|
||||||
/>
|
<LabledDropdown
|
||||||
<EyeDropInput />
|
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>
|
||||||
<div className="footer">
|
<div className="footer">
|
||||||
<InfoIcon />
|
<InfoIcon />
|
||||||
By Selecting Path, you can create Object Triggers.
|
By selecting points, you can create events and triggers.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MachineMechanics;
|
export default MachineMechanics;
|
||||||
@@ -1,115 +1,115 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
|
import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
|
||||||
import { AddIcon } from '../../../../icons/ExportCommonIcons'
|
import { AddIcon } from '../../../../icons/ExportCommonIcons'
|
||||||
import RegularDropDown from '../../../../ui/inputs/RegularDropDown'
|
import RegularDropDown from '../../../../ui/inputs/RegularDropDown'
|
||||||
import useChartStore from '../../../../../store/useChartStore'
|
import useChartStore from '../../../../../store/useChartStore'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
type Props = {}
|
type Props = {}
|
||||||
|
|
||||||
const LineGrapInput = (props: Props) => {
|
const LineGrapInput = (props: Props) => {
|
||||||
const [dropDowndata, setDropDownData] = useState({})
|
const [dropDowndata, setDropDownData] = useState({})
|
||||||
const [selections, setSelections] = useState<Record<string, { name: string, fields: string }>>({})
|
const [selections, setSelections] = useState<Record<string, { name: string, fields: string }>>({})
|
||||||
const [selectedOption, setSelectedOption] = useState('1h')
|
const [selectedOption, setSelectedOption] = useState('1h')
|
||||||
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
||||||
|
|
||||||
const handleSelectDuration = (option: string) => {
|
const handleSelectDuration = (option: string) => {
|
||||||
updateDuration(option); // Normalize for key matching
|
updateDuration(option); // Normalize for key matching
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchZoneData = async () => {
|
const fetchZoneData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('http://192.168.0.192:5010/getinput');
|
const response = await axios.get('http://192.168.0.192:5010/getinput');
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
console.log('dropdown data:', response.data);
|
console.log('dropdown data:', response.data);
|
||||||
setDropDownData(response.data)
|
setDropDownData(response.data)
|
||||||
} else {
|
} else {
|
||||||
console.log('Unexpected response:', response);
|
console.log('Unexpected response:', response);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('There was an error!', error);
|
console.error('There was an error!', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fetchZoneData();
|
fetchZoneData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(selections);
|
console.log(selections);
|
||||||
}, [selections])
|
}, [selections])
|
||||||
|
|
||||||
const handleSelect = (inputKey: string, selectedData: { name: string, fields: string } | null) => {
|
const handleSelect = (inputKey: string, selectedData: { name: string, fields: string } | null) => {
|
||||||
setSelections(prev => {
|
setSelections(prev => {
|
||||||
if (selectedData === null) {
|
if (selectedData === null) {
|
||||||
const newSelections = { ...prev };
|
const newSelections = { ...prev };
|
||||||
delete newSelections[inputKey];
|
delete newSelections[inputKey];
|
||||||
return newSelections;
|
return newSelections;
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
[inputKey]: selectedData
|
[inputKey]: selectedData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Measurement {
|
interface Measurement {
|
||||||
name: string;
|
name: string;
|
||||||
fields: string;
|
fields: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InputData {
|
interface InputData {
|
||||||
[key: string]: Measurement;
|
[key: string]: Measurement;
|
||||||
}
|
}
|
||||||
|
|
||||||
const extractMeasurements = (input: InputData): Measurement[] => {
|
const extractMeasurements = (input: InputData): Measurement[] => {
|
||||||
return Object.values(input);
|
return Object.values(input);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const measurementsData = extractMeasurements(selections);
|
const measurementsData = extractMeasurements(selections);
|
||||||
setMeasurements(measurementsData);
|
setMeasurements(measurementsData);
|
||||||
}, [selections]);
|
}, [selections]);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="inputs-wrapper">
|
<div className="inputs-wrapper">
|
||||||
{[...Array(6)].map((_, index) => {
|
{[...Array(6)].map((_, index) => {
|
||||||
const inputKey = `input${index + 1}`;
|
const inputKey = `input${index + 1}`;
|
||||||
return (
|
return (
|
||||||
<div key={index} className="datas">
|
<div key={index} className="datas">
|
||||||
<div className="datas__label">Input {index + 1}</div>
|
<div className="datas__label">Input {index + 1}</div>
|
||||||
<div className="datas__class">
|
<div className="datas__class">
|
||||||
<MultiLevelDropdown
|
<MultiLevelDropdown
|
||||||
data={dropDowndata}
|
data={dropDowndata}
|
||||||
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
onUnselect={() => handleSelect(inputKey, null)}
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
selectedValue={selections[inputKey]}
|
selectedValue={selections[inputKey]}
|
||||||
/>
|
/>
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="datas">
|
<div className="datas">
|
||||||
<div className="datas__label">duration</div>
|
<div className="datas__label">duration</div>
|
||||||
<div className="datas__class">
|
<div className="datas__class">
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={duration}
|
header={duration}
|
||||||
options={["1h", "2h", "12h"]}
|
options={["1h", "2h", "12h"]}
|
||||||
onSelect={handleSelectDuration}
|
onSelect={handleSelectDuration}
|
||||||
search={false}
|
search={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default LineGrapInput
|
export default LineGrapInput
|
||||||
@@ -1,77 +1,77 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
|
import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown'
|
||||||
import { AddIcon } from '../../../../icons/ExportCommonIcons'
|
import { AddIcon } from '../../../../icons/ExportCommonIcons'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
type Props = {}
|
type Props = {}
|
||||||
|
|
||||||
const PieChartInput = (props: Props) => {
|
const PieChartInput = (props: Props) => {
|
||||||
const [dropDowndata, setDropDownData] = useState({})
|
const [dropDowndata, setDropDownData] = useState({})
|
||||||
const [selections, setSelections] = useState<Record<string, {name: string, fields: string}>>({})
|
const [selections, setSelections] = useState<Record<string, {name: string, fields: string}>>({})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchZoneData = async () => {
|
const fetchZoneData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('http://192.168.0.192:5010/getinput');
|
const response = await axios.get('http://192.168.0.192:5010/getinput');
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
console.log('dropdown data:', response.data);
|
console.log('dropdown data:', response.data);
|
||||||
setDropDownData(response.data)
|
setDropDownData(response.data)
|
||||||
} else {
|
} else {
|
||||||
console.log('Unexpected response:', response);
|
console.log('Unexpected response:', response);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('There was an error!', error);
|
console.error('There was an error!', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fetchZoneData();
|
fetchZoneData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {console.log(selections);
|
useEffect(() => {console.log(selections);
|
||||||
},[selections])
|
},[selections])
|
||||||
|
|
||||||
const handleSelect = (inputKey: string, selectedData: {name: string, fields: string} | null) => {
|
const handleSelect = (inputKey: string, selectedData: {name: string, fields: string} | null) => {
|
||||||
setSelections(prev => {
|
setSelections(prev => {
|
||||||
if (selectedData === null) {
|
if (selectedData === null) {
|
||||||
const newSelections = {...prev};
|
const newSelections = {...prev};
|
||||||
delete newSelections[inputKey];
|
delete newSelections[inputKey];
|
||||||
return newSelections;
|
return newSelections;
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
[inputKey]: selectedData
|
[inputKey]: selectedData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="inputs-wrapper">
|
<div className="inputs-wrapper">
|
||||||
{[...Array(3)].map((_, index) => {
|
{[...Array(3)].map((_, index) => {
|
||||||
const inputKey = `input${index+1}`;
|
const inputKey = `input${index+1}`;
|
||||||
return (
|
return (
|
||||||
<div key={index} className="datas">
|
<div key={index} className="datas">
|
||||||
<div className="datas__label">Input {index+1}</div>
|
<div className="datas__label">Input {index+1}</div>
|
||||||
<div className="datas__class">
|
<div className="datas__class">
|
||||||
<MultiLevelDropdown
|
<MultiLevelDropdown
|
||||||
data={dropDowndata}
|
data={dropDowndata}
|
||||||
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||||
onUnselect={() => handleSelect(inputKey, null)}
|
onUnselect={() => handleSelect(inputKey, null)}
|
||||||
selectedValue={selections[inputKey]}
|
selectedValue={selections[inputKey]}
|
||||||
/>
|
/>
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PieChartInput
|
export default PieChartInput
|
||||||
@@ -7,7 +7,6 @@ interface LoadingPageProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LoadingPage: React.FC<LoadingPageProps> = ({ progress }) => {
|
const LoadingPage: React.FC<LoadingPageProps> = ({ progress }) => {
|
||||||
// Ensure progress stays within 0-100 range
|
|
||||||
const validatedProgress = Math.min(100, Math.max(0, progress));
|
const validatedProgress = Math.min(100, Math.max(0, progress));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React, { useEffect, useRef, useState, useCallback } from "react";
|
import React, { useEffect, useRef, useState, useCallback } from "react";
|
||||||
import { Widget } from "../../../store/useWidgetStore";
|
import { Widget } from "../../../store/useWidgetStore";
|
||||||
import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons";
|
import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons";
|
||||||
|
import { InfoIcon } from "../../icons/ExportCommonIcons";
|
||||||
|
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
||||||
|
|
||||||
// Define the type for `Side`
|
// Define the type for `Side`
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
@@ -154,33 +156,40 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Zones Wrapper */}
|
{/* Zones Wrapper */}
|
||||||
<div ref={containerRef} className="zones-wrapper">
|
{Object.keys(zonesData).length !== 0 ? (
|
||||||
{Object.keys(zonesData).map((zoneName, index) => (
|
<div ref={containerRef} className="zones-wrapper">
|
||||||
<div
|
{Object.keys(zonesData).map((zoneName, index) => (
|
||||||
key={index}
|
<div
|
||||||
className={`zone ${
|
key={index}
|
||||||
selectedZone.zoneName === zoneName ? "active" : ""
|
className={`zone ${
|
||||||
}`}
|
selectedZone.zoneName === zoneName ? "active" : ""
|
||||||
onClick={() => {
|
}`}
|
||||||
console.log("zoneName: ", zoneName);
|
onClick={() => {
|
||||||
setSelectedZone({
|
useDroppedObjectsStore.getState().setZone(zoneName, zonesData[zoneName]?.zoneId);
|
||||||
zoneName,
|
setSelectedZone({
|
||||||
activeSides: zonesData[zoneName].activeSides || [],
|
zoneName,
|
||||||
panelOrder: zonesData[zoneName].panelOrder || [],
|
activeSides: zonesData[zoneName].activeSides || [],
|
||||||
lockedPanels: zonesData[zoneName].lockedPanels || [],
|
panelOrder: zonesData[zoneName].panelOrder || [],
|
||||||
widgets: zonesData[zoneName].widgets || [],
|
lockedPanels: zonesData[zoneName].lockedPanels || [],
|
||||||
zoneId: zonesData[zoneName]?.zoneId || "",
|
widgets: zonesData[zoneName].widgets || [],
|
||||||
zoneViewPortTarget:
|
zoneId: zonesData[zoneName]?.zoneId || "",
|
||||||
zonesData[zoneName].zoneViewPortTarget || [],
|
zoneViewPortTarget:
|
||||||
zoneViewPortPosition:
|
zonesData[zoneName].zoneViewPortTarget || [],
|
||||||
zonesData[zoneName].zoneViewPortPosition || [],
|
zoneViewPortPosition:
|
||||||
});
|
zonesData[zoneName].zoneViewPortPosition || [],
|
||||||
}}
|
});
|
||||||
>
|
}}
|
||||||
{zoneName}
|
>
|
||||||
</div>
|
{zoneName}
|
||||||
))}
|
</div>
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="no-zone">
|
||||||
|
<InfoIcon />
|
||||||
|
No zones? Create one!
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Right Arrow */}
|
{/* Right Arrow */}
|
||||||
{showRightArrow && (
|
{showRightArrow && (
|
||||||
|
|||||||
@@ -1,89 +1,215 @@
|
|||||||
// import { useState } from "react";
|
|
||||||
// import { useThree } from "@react-three/fiber";
|
|
||||||
// import * as THREE from "three";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// const DroppedObjects = () => {
|
import { WalletIcon } from "../../icons/3dChartIcons";
|
||||||
// const { camera } = useThree(); // Now inside Canvas ✅
|
import { useEffect, useRef, useState } from "react";
|
||||||
// const [objects, setObjects] = useState<{ id: number; position: [number, number, number] }[]>([]);
|
import { Line } from "react-chartjs-2";
|
||||||
|
import { useDroppedObjectsStore, Zones } from "../../../store/useDroppedObjectsStore";
|
||||||
// // Function to convert drop event into 3D position
|
|
||||||
// const handleDrop = (event: DragEvent) => {
|
|
||||||
// event.preventDefault();
|
|
||||||
|
|
||||||
// const data = event.dataTransfer?.getData("text/plain");
|
|
||||||
// if (!data) return;
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// const cardData = JSON.parse(data);
|
|
||||||
// if (!cardData.className.includes("floating total-card")) {
|
|
||||||
// console.log("Drop rejected: Incorrect element.");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Convert 2D drop position to 3D world coordinates
|
|
||||||
// const x = (event.clientX / window.innerWidth) * 2 - 1;
|
|
||||||
// const y = -(event.clientY / window.innerHeight) * 2 + 1;
|
|
||||||
|
|
||||||
// // Raycasting to determine the drop position in 3D
|
|
||||||
// const raycaster = new THREE.Raycaster();
|
|
||||||
// const mouseVector = new THREE.Vector2(x, y);
|
|
||||||
// raycaster.setFromCamera(mouseVector, camera);
|
|
||||||
|
|
||||||
// // Intersect with a ground plane (assume y = 0)
|
|
||||||
// const groundPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
|
|
||||||
// const intersection = new THREE.Vector3();
|
|
||||||
// raycaster.ray.intersectPlane(groundPlane, intersection);
|
|
||||||
|
|
||||||
// console.log("Spawn Object at:", intersection);
|
|
||||||
|
|
||||||
// // Add the dropped object to the scene state
|
|
||||||
// setObjects((prev) => [...prev, { id: Date.now(), position: [intersection.x, intersection.y, intersection.z] }]);
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Invalid data:", error);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <group>
|
|
||||||
// {/* Render dropped objects as green boxes */}
|
|
||||||
// {objects.map((obj) => (
|
|
||||||
// <mesh key={obj.id} position={obj.position}>
|
|
||||||
// <boxGeometry args={[1, 1, 1]} />
|
|
||||||
// <meshStandardMaterial color="green" />
|
|
||||||
// </mesh>
|
|
||||||
// ))}
|
|
||||||
// </group>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
import { Html } from "@react-three/drei";
|
|
||||||
import { useDroppedObjectsStore } from "../../../store/store";
|
|
||||||
|
|
||||||
|
|
||||||
const DroppedObjects: React.FC = () => {
|
const DroppedObjects: React.FC = () => {
|
||||||
const objects = useDroppedObjectsStore((state) => state.objects); // Get objects from Zustand store
|
const zones = useDroppedObjectsStore((state) => state.zones);
|
||||||
console.log('objects: ', objects);
|
|
||||||
|
const updateObjectPosition = useDroppedObjectsStore((state) => state.updateObjectPosition);
|
||||||
|
const [draggingIndex, setDraggingIndex] = useState<{ zone: string; index: number } | null>(null);
|
||||||
|
const [offset, setOffset] = useState<[number, number] | null>(null);
|
||||||
|
const positionRef = useRef<[number, number] | null>(null);
|
||||||
|
const animationRef = useRef<number | null>(null);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// const initialZones: Record<string, Zones> = {
|
||||||
|
// "Zone 1": {
|
||||||
|
// zoneName: "Zone 1",
|
||||||
|
// zoneId: "2e996073-546c-470c-8323-55bd3700c6aa",
|
||||||
|
// objects: [
|
||||||
|
// {
|
||||||
|
// header: "Today’s Money",
|
||||||
|
// value: 53000, // ✅ Converted to number
|
||||||
|
// per: "+55%",
|
||||||
|
// className: "floating total-card",
|
||||||
|
// position: [146, 214], // ✅ No need for 'as' here
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// header: "New Clients",
|
||||||
|
// value: 250, // ✅ Converted to number
|
||||||
|
// per: "+12%",
|
||||||
|
// className: "floating total-card",
|
||||||
|
// position: [344, 295],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// useDroppedObjectsStore.setState({ zones: initialZones });
|
||||||
|
// }, []);
|
||||||
|
|
||||||
|
const zoneEntries = Object.entries(zones);
|
||||||
|
if (zoneEntries.length === 0) return null; // No zone, nothing to render
|
||||||
|
const [zoneName, zone] = zoneEntries[0]; // Only render the first zone
|
||||||
|
|
||||||
|
function handlePointerDown(event: React.PointerEvent, index: number) {
|
||||||
|
const obj = zone.objects[index];
|
||||||
|
const offsetX = event.clientX - obj.position[1];
|
||||||
|
const offsetY = event.clientY - obj.position[0];
|
||||||
|
|
||||||
|
setDraggingIndex({ zone: zoneName, index });
|
||||||
|
setOffset([offsetY, offsetX]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePointerMove(event: React.PointerEvent) {
|
||||||
|
if (!draggingIndex || !offset) return;
|
||||||
|
|
||||||
|
const container = document.getElementById("real-time-vis-canvas");
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
const rect = container.getBoundingClientRect();
|
||||||
|
|
||||||
|
let newX = event.clientX - offset[1];
|
||||||
|
let newY = event.clientY - offset[0];
|
||||||
|
|
||||||
|
newX = Math.max(0, Math.min(rect.width - 50, newX));
|
||||||
|
newY = Math.max(0, Math.min(rect.height - 50, newY));
|
||||||
|
|
||||||
|
positionRef.current = [newY, newX];
|
||||||
|
|
||||||
|
if (!animationRef.current) {
|
||||||
|
animationRef.current = requestAnimationFrame(() => {
|
||||||
|
if (positionRef.current) {
|
||||||
|
updateObjectPosition(zoneName, draggingIndex.index, positionRef.current);
|
||||||
|
}
|
||||||
|
animationRef.current = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePointerUp() {
|
||||||
|
setDraggingIndex(null);
|
||||||
|
setOffset(null);
|
||||||
|
if (animationRef.current) {
|
||||||
|
cancelAnimationFrame(animationRef.current);
|
||||||
|
animationRef.current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div onPointerMove={handlePointerMove} onPointerUp={handlePointerUp}>
|
||||||
{objects.map((obj, index) => (
|
{zone.objects.map((obj, index) => (
|
||||||
<group key={index} position={[Math.random() * 5, Math.random() * 5, 0]}>
|
<div
|
||||||
<Html wrapperClass={obj.className}>
|
key={`${zoneName}-${index}`}
|
||||||
<div style={{ padding: "10px", background: "#fff", borderRadius: "6px" }}>
|
className={obj.className}
|
||||||
<div className="header">{obj.header}</div>
|
style={{
|
||||||
<div className="data-values">
|
top: obj.position[0] + "px",
|
||||||
<div className="value">{obj.value}</div>
|
left: obj.position[1] + "px",
|
||||||
<div className="per">{obj.per}</div>
|
transition: draggingIndex?.index === index ? "none" : "transform 0.1s ease-out",
|
||||||
|
}}
|
||||||
|
onPointerDown={(event) => handlePointerDown(event, index)}
|
||||||
|
>
|
||||||
|
{obj.className === "floating total-card" ? (
|
||||||
|
<div>
|
||||||
|
<div className="header-wrapper">
|
||||||
|
<div className="header">{obj.header}</div>
|
||||||
|
<div className="data-values">
|
||||||
|
<div className="value">{obj.value}</div>
|
||||||
|
<div className="per">{obj.per}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="icon">
|
||||||
|
<WalletIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Html>
|
) : obj.className === "warehouseThroughput floating" ? (
|
||||||
</group>
|
<div>
|
||||||
|
<div className="header">
|
||||||
|
<h2>Warehouse Throughput</h2>
|
||||||
|
<p>
|
||||||
|
<span>(+5) more</span> in 2025
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="lineGraph" style={{ height: "100%" }}>
|
||||||
|
{/* <Line data={lineGraphData} options={lineGraphOptions} /> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : obj.className === "fleetEfficiency floating" ? (
|
||||||
|
<div>
|
||||||
|
<h2 className="header">Fleet Efficiency</h2>
|
||||||
|
<div className="progressContainer">
|
||||||
|
<div className="progress">
|
||||||
|
<div className="barOverflow">
|
||||||
|
<div
|
||||||
|
className="bar"
|
||||||
|
style={{ transform: `rotate(${obj.value}deg)` }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="scaleLabels">
|
||||||
|
<span>0%</span>
|
||||||
|
<div className="centerText">
|
||||||
|
<div className="percentage">{obj.per}%</div>
|
||||||
|
<div className="status">Optimal</div>
|
||||||
|
</div>
|
||||||
|
<span>100%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default DroppedObjects;
|
export default DroppedObjects;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// import { Html } from "@react-three/drei";
|
||||||
|
// import { useDroppedObjectsStore } from "../../../store/store";
|
||||||
|
// import { CartIcon, DocumentIcon, GlobeIcon, WalletIcon } from "../../icons/3dChartIcons";
|
||||||
|
// import SimpleCard from "../realTimeVis/floating/SimpleCard";
|
||||||
|
|
||||||
|
// const ICON_MAP: Record<string, React.ComponentType<React.SVGProps<SVGSVGElement>>> = {
|
||||||
|
// WalletIcon,
|
||||||
|
// GlobeIcon,
|
||||||
|
// DocumentIcon,
|
||||||
|
// CartIcon
|
||||||
|
// };
|
||||||
|
// const DroppedObjects: React.FC = () => {
|
||||||
|
// const objects = useDroppedObjectsStore((state) => state.objects); // Get objects from Zustand store
|
||||||
|
//
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <>
|
||||||
|
// {objects.map((obj, index) => {
|
||||||
|
// const IconComponent = obj.Icon || WalletIcon; // Use obj.Icon directly if it exists
|
||||||
|
// return (
|
||||||
|
// <SimpleCard
|
||||||
|
// key={index}
|
||||||
|
// position={obj.position}
|
||||||
|
// header={obj.header}
|
||||||
|
// icon={IconComponent} // ✅ No need to look it up in ICON_MAP
|
||||||
|
// value={obj.value}
|
||||||
|
// per={obj.per}
|
||||||
|
// />
|
||||||
|
// );
|
||||||
|
// })}
|
||||||
|
// </>
|
||||||
|
// );
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export default DroppedObjects;
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
|||||||
import DisplayZone from "./DisplayZone";
|
import DisplayZone from "./DisplayZone";
|
||||||
import Scene from "../../../modules/scene/scene";
|
import Scene from "../../../modules/scene/scene";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
import { useDroppedObjectsStore, useZones } from "../../../store/store";
|
|
||||||
import DroppedObjects from "./DroppedFloatingWidgets";
|
import DroppedObjects from "./DroppedFloatingWidgets";
|
||||||
|
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
||||||
|
import { useZones } from "../../../store/store";
|
||||||
|
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
@@ -80,36 +82,36 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
});
|
});
|
||||||
}, [selectedZone]);
|
}, [selectedZone]);
|
||||||
|
|
||||||
// const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
|
|
||||||
// console.log("Drop event fired! ✅");
|
|
||||||
// event.preventDefault();
|
|
||||||
|
|
||||||
// const data = event.dataTransfer.getData("text/plain");
|
|
||||||
// if (!data) {
|
|
||||||
// console.log("❌ No data received on drop!");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// const droppedData = JSON.parse(data);
|
|
||||||
// console.log("✅ Dropped Data:", droppedData);
|
|
||||||
|
|
||||||
// console.log('droppedData: ', droppedData);
|
|
||||||
// setDroppedObjects((prev) => [...prev, droppedData]); // ✅ Add to state
|
|
||||||
// console.log(droppedObjects);
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("❌ Error parsing dropped data:", error);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
|
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const data = event.dataTransfer.getData("text/plain"); // Use "text/plain" to match the drag event
|
const data = event.dataTransfer.getData("text/plain");
|
||||||
|
if (!data || !selectedZone.zoneName) return;
|
||||||
if (data) {
|
|
||||||
const droppedData = JSON.parse(data);
|
const droppedData = JSON.parse(data);
|
||||||
useDroppedObjectsStore.getState().addObject(droppedData); // Add to Zustand store
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -133,9 +135,10 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
onDrop={(event) => handleDrop(event)}
|
onDrop={(event) => handleDrop(event)}
|
||||||
onDragOver={(event) => event.preventDefault()}
|
onDragOver={(event) => event.preventDefault()}
|
||||||
>
|
>
|
||||||
|
|
||||||
<Scene />
|
<Scene />
|
||||||
</div>
|
</div>
|
||||||
|
<DroppedObjects />
|
||||||
{activeModule === "visualization" && (
|
{activeModule === "visualization" && (
|
||||||
<>
|
<>
|
||||||
<DisplayZone
|
<DisplayZone
|
||||||
|
|||||||
@@ -47,12 +47,9 @@ export default function ZoneCentreTarget() {
|
|||||||
const worldUp = new THREE.Vector3(0, 0, 1);
|
const worldUp = new THREE.Vector3(0, 0, 1);
|
||||||
const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize();
|
const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize();
|
||||||
const up = new THREE.Vector3().crossVectors(direction, right).normalize();
|
const up = new THREE.Vector3().crossVectors(direction, right).normalize();
|
||||||
|
|
||||||
const offsetPosition = up.clone().multiplyScalar(20);
|
const offsetPosition = up.clone().multiplyScalar(20);
|
||||||
|
|
||||||
camPosition.add(offsetPosition);
|
camPosition.add(offsetPosition);
|
||||||
|
|
||||||
|
|
||||||
const setCam = async () => {
|
const setCam = async () => {
|
||||||
controls.setLookAt(centrePoint[0], 100, centrePoint[2], ...centrePoint, true);
|
controls.setLookAt(centrePoint[0], 100, centrePoint[2], ...centrePoint, true);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React from "react";
|
||||||
|
|
||||||
interface InputToggleProps {
|
interface InputToggleProps {
|
||||||
label: string; // Represents the toggle state (on/off)
|
label: string; // Represents the toggle state (on/off)
|
||||||
@@ -7,23 +7,18 @@ interface InputToggleProps {
|
|||||||
inputKey: string;
|
inputKey: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update InputToggle.tsx to be fully controlled
|
||||||
const InputToggle: React.FC<InputToggleProps> = ({
|
const InputToggle: React.FC<InputToggleProps> = ({
|
||||||
label,
|
label,
|
||||||
onClick,
|
onClick,
|
||||||
value = false,
|
value = false,
|
||||||
inputKey,
|
inputKey,
|
||||||
}) => {
|
}) => {
|
||||||
const [activeValue, setActiveValue] = useState<boolean>(value);
|
// Remove internal state and use the value prop directly
|
||||||
|
|
||||||
function handleOnClick() {
|
function handleOnClick() {
|
||||||
setActiveValue(!activeValue);
|
|
||||||
if (onClick) onClick();
|
if (onClick) onClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setActiveValue(value);
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="input-toggle-container">
|
<div className="input-toggle-container">
|
||||||
<label htmlFor={`toogle-input-${inputKey}`} className="label">
|
<label htmlFor={`toogle-input-${inputKey}`} className="label">
|
||||||
@@ -33,15 +28,16 @@ const InputToggle: React.FC<InputToggleProps> = ({
|
|||||||
<div
|
<div
|
||||||
className="check-box-style"
|
className="check-box-style"
|
||||||
style={{
|
style={{
|
||||||
left: activeValue ? "50%" : "2px",
|
left: value ? "50%" : "2px",
|
||||||
background: activeValue ? "" : "var(--text-disabled)",
|
background: value ? "" : "var(--text-disabled)",
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name=""
|
name=""
|
||||||
id={`toogle-input-${inputKey}`}
|
id={`toogle-input-${inputKey}`}
|
||||||
defaultChecked={value}
|
checked={value}
|
||||||
|
readOnly
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,21 +4,27 @@ import RenameInput from "./RenameInput";
|
|||||||
type InputWithDropDownProps = {
|
type InputWithDropDownProps = {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
min?: number
|
||||||
|
defaultValue?: string;
|
||||||
options?: string[]; // Array of dropdown options
|
options?: string[]; // Array of dropdown options
|
||||||
activeOption?: string; // The currently active dropdown option
|
activeOption?: string; // The currently active dropdown option
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
onChange: (newValue: string) => void;
|
onChange: (newValue: string) => void;
|
||||||
editableLabel?: boolean;
|
editableLabel?: boolean;
|
||||||
|
placeholder?: string; // New placeholder prop
|
||||||
};
|
};
|
||||||
|
|
||||||
const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
||||||
label,
|
label,
|
||||||
value,
|
value,
|
||||||
|
min,
|
||||||
|
defaultValue,
|
||||||
options,
|
options,
|
||||||
activeOption,
|
activeOption,
|
||||||
onClick,
|
onClick,
|
||||||
onChange,
|
onChange,
|
||||||
editableLabel = false,
|
editableLabel = false,
|
||||||
|
placeholder = "Inherit", // Default empty placeholder
|
||||||
}) => {
|
}) => {
|
||||||
const separatedWords = label
|
const separatedWords = label
|
||||||
.split(/(?=[A-Z])/)
|
.split(/(?=[A-Z])/)
|
||||||
@@ -38,11 +44,13 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
|||||||
)}
|
)}
|
||||||
<div className="input default" id={separatedWords}>
|
<div className="input default" id={separatedWords}>
|
||||||
<input
|
<input
|
||||||
type="text"
|
min={min}
|
||||||
|
type="number"
|
||||||
defaultValue={value}
|
defaultValue={value}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}
|
}}
|
||||||
|
placeholder={placeholder} // Added placeholder prop
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{activeOption && (
|
{activeOption && (
|
||||||
@@ -73,4 +81,4 @@ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default InputWithDropDown;
|
export default InputWithDropDown;
|
||||||
@@ -1,29 +1,49 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import RegularDropDown from "./RegularDropDown";
|
import RegularDropDown from "./RegularDropDown";
|
||||||
|
|
||||||
type LabledDropdownProps = {
|
type LabledDropdownProps = {
|
||||||
defaultOption: string; // Initial active option
|
defaultOption: string; // Initial active option
|
||||||
options: string[]; // Array of dropdown options
|
options: string[]; // Array of dropdown options
|
||||||
|
label?: string; // Customizable label text
|
||||||
|
onSelect?: (option: string) => void; // Callback when option is selected
|
||||||
|
className?: string; // Additional className for styling
|
||||||
|
disabled?: boolean; // Disable dropdown
|
||||||
|
search?: boolean; // Enable/disable search functionality
|
||||||
};
|
};
|
||||||
|
|
||||||
const LabledDropdown: React.FC<LabledDropdownProps> = ({ defaultOption, options }) => {
|
const LabledDropdown: React.FC<LabledDropdownProps> = ({
|
||||||
const [activeOption, setActiveOption] = useState(defaultOption); // State for active option
|
defaultOption,
|
||||||
|
options,
|
||||||
|
label = "Type",
|
||||||
|
onSelect,
|
||||||
|
className = "",
|
||||||
|
search = false
|
||||||
|
}) => {
|
||||||
|
const [activeOption, setActiveOption] = useState(defaultOption);
|
||||||
|
|
||||||
|
// Update active option if defaultOption changes
|
||||||
|
useEffect(() => {
|
||||||
|
setActiveOption(defaultOption);
|
||||||
|
}, [defaultOption]);
|
||||||
|
|
||||||
const handleSelect = (option: string) => {
|
const handleSelect = (option: string) => {
|
||||||
setActiveOption(option); // Update the active option state
|
setActiveOption(option);
|
||||||
|
if (onSelect) {
|
||||||
|
onSelect(option);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="value-field-container">
|
<div className={`value-field-container ${className}`}>
|
||||||
<div className="label">Type</div>
|
<div className="label">{label}</div>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={activeOption} // Display the current active option
|
header={activeOption}
|
||||||
options={options} // Use the options from props
|
options={options}
|
||||||
onSelect={handleSelect} // Handle option selection
|
onSelect={handleSelect}
|
||||||
search = {false}
|
search={search}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LabledDropdown;
|
export default LabledDropdown;
|
||||||
@@ -201,18 +201,16 @@ const LineGraphComponent = ({
|
|||||||
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
const { measurements, setMeasurements, updateDuration, duration } = useChartStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if ( measurements.length > 0 ) {
|
|
||||||
const socket = io("http://192.168.0.192:5010");
|
|
||||||
|
|
||||||
|
const socket = io("http://192.168.0.192:5010");
|
||||||
|
|
||||||
|
if ( measurements.length > 0 ) {
|
||||||
var inputes = {
|
var inputes = {
|
||||||
measurements: measurements,
|
measurements: measurements,
|
||||||
duration: duration,
|
duration: duration,
|
||||||
interval: 1000,
|
interval: 1000,
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('graphHHHHHHHHHHHHHHHHHHHHHHHHHHHHH',inputes);
|
|
||||||
|
|
||||||
|
|
||||||
// Start stream
|
// Start stream
|
||||||
const startStream = () => {
|
const startStream = () => {
|
||||||
socket.emit("lineInput", inputes);
|
socket.emit("lineInput", inputes);
|
||||||
@@ -226,23 +224,24 @@ const LineGraphComponent = ({
|
|||||||
|
|
||||||
// Extract timestamps and values
|
// Extract timestamps and values
|
||||||
const labels = responceData.time;
|
const labels = responceData.time;
|
||||||
const datasets = data.measurements.map((measurement: any) => ({
|
const datasets = measurements.map((measurement: any) => {
|
||||||
label: `${measurement.name}.${measurement.fields}`,
|
const key = `${measurement.name}.${measurement.fields}`;
|
||||||
data: responceData[`${measurement.name}.${measurement.fields}`]?.values || [],
|
return {
|
||||||
backgroundColor: themeColor[0] || "#5c87df",
|
label: key,
|
||||||
borderColor: themeColor[1] || "#ffffff",
|
data: responceData[key]?.values ?? [], // Ensure it exists
|
||||||
borderWidth: 2,
|
backgroundColor: themeColor[0] || "#5c87df",
|
||||||
// fill: false,
|
borderColor: themeColor[1] || "#ffffff",
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
|
|
||||||
setChartData({ labels, datasets });
|
setChartData({ labels, datasets });
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.off("lineOutput");
|
socket.off("lineOutput");
|
||||||
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}, [measurements, duration]);
|
}, [measurements, duration]);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
|
|||||||
@@ -4,8 +4,24 @@ const FleetEfficiency = () => {
|
|||||||
// Calculate the rotation angle for the progress bar
|
// Calculate the rotation angle for the progress bar
|
||||||
const rotationAngle = -90 + progress * 3.6; // Progress starts from the left (-90°)
|
const rotationAngle = -90 + progress * 3.6; // Progress starts from the left (-90°)
|
||||||
|
|
||||||
|
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
const rect = event.currentTarget.getBoundingClientRect(); // Get position
|
||||||
|
|
||||||
|
const cardData = JSON.stringify({
|
||||||
|
className: event.currentTarget.className,
|
||||||
|
position: [rect.top, rect.left], // Store position
|
||||||
|
value: rotationAngle, // Example value (you can change if dynamic)
|
||||||
|
per: progress,
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Dragged Data:", cardData);
|
||||||
|
event.dataTransfer.setData("text/plain", cardData);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fleetEfficiency floating">
|
<div className="fleetEfficiency floating" draggable onDragStart={handleDragStart}>
|
||||||
<h2 className="header">Fleet Efficiency</h2>
|
<h2 className="header">Fleet Efficiency</h2>
|
||||||
|
|
||||||
<div className="progressContainer">
|
<div className="progressContainer">
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ interface SimpleCardProps {
|
|||||||
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>; // React component for SVG icon
|
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>; // React component for SVG icon
|
||||||
value: string;
|
value: string;
|
||||||
per: string; // Percentage change
|
per: string; // Percentage change
|
||||||
|
position?: [number, number]
|
||||||
}
|
}
|
||||||
|
|
||||||
const SimpleCard: React.FC<SimpleCardProps> = ({
|
const SimpleCard: React.FC<SimpleCardProps> = ({
|
||||||
@@ -12,23 +13,30 @@ const SimpleCard: React.FC<SimpleCardProps> = ({
|
|||||||
icon: Icon,
|
icon: Icon,
|
||||||
value,
|
value,
|
||||||
per,
|
per,
|
||||||
|
position = [0, 0],
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
|
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
const rect = event.currentTarget.getBoundingClientRect(); // Get position
|
||||||
const cardData = JSON.stringify({
|
const cardData = JSON.stringify({
|
||||||
header,
|
header,
|
||||||
value,
|
value,
|
||||||
per,
|
per,
|
||||||
className: event.currentTarget.className,
|
icon: Icon,
|
||||||
|
className: event.currentTarget.className,
|
||||||
|
position: [rect.top, rect.left], // ✅ Store position
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Dragging Data:", cardData); // ✅ Debugging log
|
|
||||||
|
|
||||||
event.dataTransfer.setData("text/plain", cardData);
|
event.dataTransfer.setData("text/plain", cardData);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="floating total-card" draggable onDragStart={handleDragStart}>
|
<div
|
||||||
|
className="floating total-card"
|
||||||
|
draggable
|
||||||
|
onDragStart={handleDragStart}
|
||||||
|
style={{ top: position[0], left: position[1] }} // No need for ?? 0 if position is guaranteed
|
||||||
|
>
|
||||||
<div className="header-wrapper">
|
<div className="header-wrapper">
|
||||||
<div className="header">{header}</div>
|
<div className="header">{header}</div>
|
||||||
<div className="data-values">
|
<div className="data-values">
|
||||||
|
|||||||
@@ -111,8 +111,27 @@ const WarehouseThroughput = () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
const rect = event.currentTarget.getBoundingClientRect(); // Get element position
|
||||||
|
|
||||||
|
const cardData = JSON.stringify({
|
||||||
|
header: "Warehouse Throughput", // Static header
|
||||||
|
value: "+5", // Example value (you can change if dynamic)
|
||||||
|
per: "2025", // Example percentage or date
|
||||||
|
icon: "📊", // Placeholder for an icon (if needed)
|
||||||
|
className: event.currentTarget.className,
|
||||||
|
position: [rect.top, rect.left], // ✅ Store initial position
|
||||||
|
lineGraphData, // ✅ Include chart data
|
||||||
|
lineGraphOptions, // ✅ Include chart options
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
event.dataTransfer.setData("text/plain", cardData);
|
||||||
|
// event.dataTransfer.effectAllowed = "move"; // Improve drag effect
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="warehouseThroughput floating" draggable>
|
<div className="warehouseThroughput floating" draggable onDragStart={handleDragStart}>
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<h2>Warehouse Throughput</h2>
|
<h2>Warehouse Throughput</h2>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
51
app/src/modules/builder/agv/agv.tsx
Normal file
51
app/src/modules/builder/agv/agv.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import PolygonGenerator from "./polygonGenerator";
|
||||||
|
import { useThree } from "@react-three/fiber";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
|
import PathNavigator from "./pathNavigator";
|
||||||
|
import NavMeshDetails from "./navMeshDetails";
|
||||||
|
|
||||||
|
const Agv = ({
|
||||||
|
lines,
|
||||||
|
plane,
|
||||||
|
}: {
|
||||||
|
lines: Types.RefLines;
|
||||||
|
plane: Types.RefMesh;
|
||||||
|
}) => {
|
||||||
|
let pathPoints = [
|
||||||
|
[
|
||||||
|
{ x: 8.477161935339709, y: 0, z: 17.41343083550102 },
|
||||||
|
{ x: 9.175416491482693, y: 0, z: -12.361001232663693 },
|
||||||
|
],
|
||||||
|
,
|
||||||
|
// [
|
||||||
|
// { x: 13.508213355232144, y: 0, z: -15.456970649652018 },
|
||||||
|
// { x: -30.464866520869617, y: 0, z: 9.779806557688929 },
|
||||||
|
// ],
|
||||||
|
[
|
||||||
|
{ x: 16.792040856420844, y: 0, z: 15.86281907549489 },
|
||||||
|
{ x: -42.77173264503395, y: 0, z: -15.821322764400804 },
|
||||||
|
],
|
||||||
|
];
|
||||||
|
let groupRef = useRef() as Types.RefGroup;
|
||||||
|
const [navMesh, setNavMesh] = useState();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PolygonGenerator groupRef={groupRef} lines={lines} plane={plane} />
|
||||||
|
<NavMeshDetails
|
||||||
|
lines={lines}
|
||||||
|
setNavMesh={setNavMesh}
|
||||||
|
groupRef={groupRef}
|
||||||
|
plane={plane}
|
||||||
|
/>
|
||||||
|
{pathPoints.map((pair, i) => (
|
||||||
|
<PathNavigator navMesh={navMesh} selectedPoints={pair} key={i} />
|
||||||
|
))}
|
||||||
|
<group ref={groupRef} visible={false} name="Meshes"></group>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Agv;
|
||||||
63
app/src/modules/builder/agv/navMeshDetails.tsx
Normal file
63
app/src/modules/builder/agv/navMeshDetails.tsx
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { init as initRecastNavigation } from "@recast-navigation/core";
|
||||||
|
import { generateSoloNavMesh } from "@recast-navigation/generators";
|
||||||
|
import { DebugDrawer, getPositionsAndIndices } from "@recast-navigation/three";
|
||||||
|
import { useThree } from "@react-three/fiber";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
|
|
||||||
|
interface NavMeshDetailsProps {
|
||||||
|
setNavMesh: (navMesh: any) => void;
|
||||||
|
groupRef: React.MutableRefObject<THREE.Group | null>;
|
||||||
|
lines: Types.RefLines;
|
||||||
|
plane: Types.RefMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function NavMeshDetails({
|
||||||
|
lines,
|
||||||
|
setNavMesh,
|
||||||
|
groupRef,
|
||||||
|
plane,
|
||||||
|
}: NavMeshDetailsProps) {
|
||||||
|
const { scene } = useThree();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const initializeNavigation = async () => {
|
||||||
|
try {
|
||||||
|
await initRecastNavigation();
|
||||||
|
|
||||||
|
if (!groupRef.current || groupRef.current.children.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const meshes = groupRef?.current?.children as THREE.Mesh[];
|
||||||
|
|
||||||
|
const [positions, indices] = getPositionsAndIndices(meshes);
|
||||||
|
|
||||||
|
const cs = 0.5;
|
||||||
|
const ch = 0.5;
|
||||||
|
const walkableRadius = 0.89;
|
||||||
|
|
||||||
|
const { success, navMesh } = generateSoloNavMesh(positions, indices, {
|
||||||
|
cs,
|
||||||
|
ch,
|
||||||
|
walkableRadius: Math.round(walkableRadius / ch),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!success || !navMesh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNavMesh(navMesh);
|
||||||
|
|
||||||
|
const debugDrawer = new DebugDrawer();
|
||||||
|
debugDrawer.drawNavMesh(navMesh);
|
||||||
|
// scene.add(debugDrawer);
|
||||||
|
} catch (error) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
initializeNavigation();
|
||||||
|
}, [scene, groupRef, lines.current]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
98
app/src/modules/builder/agv/pathNavigator.tsx
Normal file
98
app/src/modules/builder/agv/pathNavigator.tsx
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { useFrame } from "@react-three/fiber";
|
||||||
|
import { NavMeshQuery } from "@recast-navigation/core";
|
||||||
|
import { Line } from "@react-three/drei";
|
||||||
|
|
||||||
|
// Define interface for props
|
||||||
|
interface PathNavigatorProps {
|
||||||
|
navMesh: any;
|
||||||
|
selectedPoints: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PathNavigator({
|
||||||
|
navMesh,
|
||||||
|
selectedPoints,
|
||||||
|
}: PathNavigatorProps) {
|
||||||
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
|
const progressRef = useRef(0);
|
||||||
|
const meshRef = useRef<THREE.Mesh | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedPoints.length === 2 && navMesh) {
|
||||||
|
const [start, end] = selectedPoints;
|
||||||
|
if (!start || !end) return;
|
||||||
|
|
||||||
|
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||||
|
|
||||||
|
const { path: computedPath } = navMeshQuery.computePath(start, end);
|
||||||
|
|
||||||
|
if (computedPath.length > 0) {
|
||||||
|
setPath(computedPath.map(({ x, y, z }) => [x, y + 0.1, z]));
|
||||||
|
progressRef.current = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedPoints, navMesh]);
|
||||||
|
|
||||||
|
useFrame((_, delta) => {
|
||||||
|
if (path.length > 1 && meshRef.current) {
|
||||||
|
const speed = 3;
|
||||||
|
progressRef.current += delta * speed;
|
||||||
|
|
||||||
|
let totalDistance = 0;
|
||||||
|
const distances: number[] = [];
|
||||||
|
for (let i = 0; i < path.length - 1; i++) {
|
||||||
|
const start = new THREE.Vector3(...path[i]);
|
||||||
|
const end = new THREE.Vector3(...path[i + 1]);
|
||||||
|
const segmentDistance = start.distanceTo(end);
|
||||||
|
distances.push(segmentDistance);
|
||||||
|
totalDistance += segmentDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
let coveredDistance = progressRef.current;
|
||||||
|
let accumulatedDistance = 0;
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while (
|
||||||
|
index < distances.length &&
|
||||||
|
coveredDistance > accumulatedDistance + distances[index]
|
||||||
|
) {
|
||||||
|
accumulatedDistance += distances[index];
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < distances.length) {
|
||||||
|
const start = new THREE.Vector3(...path[index]);
|
||||||
|
const end = new THREE.Vector3(...path[index + 1]);
|
||||||
|
const segmentDistance = distances[index];
|
||||||
|
|
||||||
|
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
||||||
|
const position = start.clone().lerp(end, t); // Use clone() to avoid mutating the original vector
|
||||||
|
meshRef.current.position.copy(position);
|
||||||
|
|
||||||
|
const direction = new THREE.Vector3()
|
||||||
|
.subVectors(end, start)
|
||||||
|
.normalize();
|
||||||
|
const targetQuaternion = new THREE.Quaternion().setFromUnitVectors(
|
||||||
|
new THREE.Vector3(0, 0, 1),
|
||||||
|
direction
|
||||||
|
);
|
||||||
|
meshRef.current.quaternion.slerp(targetQuaternion, 0.1);
|
||||||
|
} else {
|
||||||
|
progressRef.current = totalDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{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]} />
|
||||||
|
<meshNormalMaterial />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
146
app/src/modules/builder/agv/polygonGenerator.tsx
Normal file
146
app/src/modules/builder/agv/polygonGenerator.tsx
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
import * as THREE from "three";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import * as turf from "@turf/turf";
|
||||||
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
|
import arrayLinesToObject from "../geomentries/lines/lineConvertions/arrayLinesToObject";
|
||||||
|
interface PolygonGeneratorProps {
|
||||||
|
groupRef: React.MutableRefObject<THREE.Group | null>;
|
||||||
|
lines: Types.RefLines;
|
||||||
|
plane: Types.RefMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PolygonGenerator({
|
||||||
|
groupRef,
|
||||||
|
lines,
|
||||||
|
plane,
|
||||||
|
}: PolygonGeneratorProps) {
|
||||||
|
// const [rooms, setRooms] = useState<THREE.Vector3[][]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (groupRef.current && plane.current) {
|
||||||
|
groupRef.current.add(plane.current.clone());
|
||||||
|
}
|
||||||
|
}, [groupRef, plane]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let allLines = arrayLinesToObject(lines.current);
|
||||||
|
const wallLines = allLines?.filter((line) => line?.type === "WallLine");
|
||||||
|
const aisleLines = allLines?.filter((line) => line?.type === "AisleLine");
|
||||||
|
|
||||||
|
const wallPoints = wallLines
|
||||||
|
.map((pair) => pair?.line.map((vals) => vals.position))
|
||||||
|
.filter((wall): wall is THREE.Vector3[] => !!wall);
|
||||||
|
|
||||||
|
const result = aisleLines.map((pair) =>
|
||||||
|
pair?.line.map((point) => ({
|
||||||
|
position: [point.position.x, point.position.z],
|
||||||
|
uuid: point.uuid,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
if (!result || result.some((line) => !line)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = [];
|
||||||
|
|
||||||
|
polygons.features.forEach((feature) => {
|
||||||
|
union.push(feature);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (union.length > 1) {
|
||||||
|
const unionResult = turf.union(turf.featureCollection(union));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
for (let i = 0; i < wall.length - 1; i++) {
|
||||||
|
const start = new THREE.Vector3(wall[i].x, wall[i].y, wall[i].z);
|
||||||
|
const end = new THREE.Vector3(
|
||||||
|
wall[i + 1].x,
|
||||||
|
wall[i + 1].y,
|
||||||
|
wall[i + 1].z
|
||||||
|
);
|
||||||
|
|
||||||
|
const wallHeight = 10;
|
||||||
|
const direction = new THREE.Vector3().subVectors(end, start);
|
||||||
|
const length = direction.length();
|
||||||
|
direction.normalize();
|
||||||
|
|
||||||
|
const wallGeometry = new THREE.BoxGeometry(length, wallHeight);
|
||||||
|
const wallMaterial = new THREE.MeshBasicMaterial({
|
||||||
|
color: "#aaa",
|
||||||
|
transparent: true,
|
||||||
|
opacity: 0.5,
|
||||||
|
});
|
||||||
|
|
||||||
|
const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
|
||||||
|
const midPoint = new THREE.Vector3()
|
||||||
|
.addVectors(start, end)
|
||||||
|
.multiplyScalar(0.5);
|
||||||
|
wallMesh.position.set(midPoint.x, wallHeight / 2, midPoint.z);
|
||||||
|
|
||||||
|
const quaternion = new THREE.Quaternion();
|
||||||
|
quaternion.setFromUnitVectors(new THREE.Vector3(1, 0, 0), direction);
|
||||||
|
wallMesh.quaternion.copy(quaternion);
|
||||||
|
|
||||||
|
groupRef.current?.add(wallMesh);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useActiveTool, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useRenderDistance, useselectedFloorItem, useSelectedItem, useSocketStore, useToggleView, useTransformMode } from "../../../store/store";
|
import { useActiveTool, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useLoadingProgress, useRenderDistance, useselectedFloorItem, useSelectedItem, useSocketStore, useToggleView, useTransformMode } from "../../../store/store";
|
||||||
import assetVisibility from "../geomentries/assets/assetVisibility";
|
import assetVisibility from "../geomentries/assets/assetVisibility";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
@@ -11,24 +11,27 @@ import DeletableHoveredFloorItems from "../geomentries/assets/deletableHoveredFl
|
|||||||
import DeleteFloorItems from "../geomentries/assets/deleteFloorItems";
|
import DeleteFloorItems from "../geomentries/assets/deleteFloorItems";
|
||||||
import loadInitialFloorItems from "../../scene/IntialLoad/loadInitialFloorItems";
|
import loadInitialFloorItems from "../../scene/IntialLoad/loadInitialFloorItems";
|
||||||
import addAssetModel from "../geomentries/assets/addAssetModel";
|
import addAssetModel from "../geomentries/assets/addAssetModel";
|
||||||
// import { getFloorItems } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
import { getFloorItems } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
||||||
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
// import { retrieveGLTF } from "../../../utils/indexDB/idbUtils";
|
||||||
const assetManagerWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/assetManagerWorker.js', import.meta.url));
|
const assetManagerWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/assetManagerWorker.js', import.meta.url));
|
||||||
// const gltfLoaderWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js', import.meta.url));
|
const gltfLoaderWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js', import.meta.url));
|
||||||
|
|
||||||
const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane }: any) => {
|
const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane }: any) => {
|
||||||
const state: Types.ThreeState = useThree();
|
const state: Types.ThreeState = useThree();
|
||||||
const { raycaster, camera, controls, pointer }: any = state;
|
const { raycaster, controls }: any = state;
|
||||||
const { renderDistance, setRenderDistance } = useRenderDistance();
|
const { renderDistance } = useRenderDistance();
|
||||||
const { toggleView, setToggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { camMode, setCamMode } = useCamMode();
|
const { camMode } = useCamMode();
|
||||||
const { deleteModels, setDeleteModels } = useDeleteModels();
|
const { deleteModels } = useDeleteModels();
|
||||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
const { setDeletableFloorItem } = useDeletableFloorItem();
|
||||||
const { transformMode, setTransformMode } = useTransformMode();
|
const { transformMode } = useTransformMode();
|
||||||
const { selectedFloorItem, setselectedFloorItem } = useselectedFloorItem();
|
const { setselectedFloorItem } = useselectedFloorItem();
|
||||||
const { activeTool, setActiveTool } = useActiveTool();
|
const { activeTool } = useActiveTool();
|
||||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||||
|
const { setLoadingProgress } = useLoadingProgress();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
|
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
@@ -38,32 +41,57 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
|||||||
loader.setDRACOLoader(dracoLoader);
|
loader.setDRACOLoader(dracoLoader);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Load initial floor items
|
const email = localStorage.getItem('email');
|
||||||
|
const organization = (email!.split("@")[1]).split(".")[0];
|
||||||
|
|
||||||
// const email = localStorage.getItem('email');
|
let totalAssets = 0;
|
||||||
// const organization = (email!.split("@")[1]).split(".")[0];
|
let loadedAssets = 0;
|
||||||
|
|
||||||
// getFloorItems(organization).then((data) => {
|
const updateLoadingProgress = (progress: number) => {
|
||||||
// gltfLoaderWorker.postMessage({ FloorItems: data })
|
if (progress < 100) {
|
||||||
// })
|
setLoadingProgress(progress);
|
||||||
|
} else if (progress === 100) {
|
||||||
|
setTimeout(() => {
|
||||||
|
setLoadingProgress(100);
|
||||||
|
setTimeout(() => {
|
||||||
|
setLoadingProgress(0);
|
||||||
|
}, 1500);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// gltfLoaderWorker.onmessage = async (event) => {
|
getFloorItems(organization).then((data) => {
|
||||||
// if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
const uniqueItems = (data as Types.FloorItems).filter((item, index, self) =>
|
||||||
// const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
|
||||||
|
);
|
||||||
|
totalAssets = uniqueItems.length;
|
||||||
|
if (totalAssets === 0) {
|
||||||
|
updateLoadingProgress(100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gltfLoaderWorker.postMessage({ floorItems: data });
|
||||||
|
});
|
||||||
|
|
||||||
// loader.load(blobUrl, (gltf) => {
|
gltfLoaderWorker.onmessage = async (event) => {
|
||||||
// URL.revokeObjectURL(blobUrl);
|
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
||||||
// THREE.Cache.remove(blobUrl);
|
const blobUrl = URL.createObjectURL(event.data.modelBlob);
|
||||||
// THREE.Cache.add(event.data.modelID, gltf);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// } else if (event.data.message === "done") {
|
loader.load(blobUrl, (gltf) => {
|
||||||
// loadInitialFloorItems(itemsGroup, setFloorItems);
|
URL.revokeObjectURL(blobUrl);
|
||||||
// }
|
THREE.Cache.remove(blobUrl);
|
||||||
// }
|
THREE.Cache.add(event.data.modelID, gltf);
|
||||||
|
|
||||||
|
loadedAssets++;
|
||||||
|
const progress = Math.round((loadedAssets / totalAssets) * 100);
|
||||||
|
updateLoadingProgress(progress);
|
||||||
|
|
||||||
loadInitialFloorItems(itemsGroup, setFloorItems);
|
if (loadedAssets === totalAssets) {
|
||||||
|
loadInitialFloorItems(itemsGroup, setFloorItems);
|
||||||
|
updateLoadingProgress(100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -253,12 +281,20 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
if (activeModule === "builder") {
|
||||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
canvasElement.addEventListener("dblclick", onDblClick);
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
canvasElement.addEventListener("drop", onDrop);
|
canvasElement.addEventListener("dblclick", onDblClick);
|
||||||
canvasElement.addEventListener("dragover", onDragOver);
|
canvasElement.addEventListener("drop", onDrop);
|
||||||
|
canvasElement.addEventListener("dragover", onDragOver);
|
||||||
|
} else {
|
||||||
|
if (controls) {
|
||||||
|
const target = controls.getTarget(new THREE.Vector3());
|
||||||
|
controls.setTarget(target.x, 0, target.z, true);
|
||||||
|
setselectedFloorItem(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
@@ -268,7 +304,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
|||||||
canvasElement.removeEventListener("drop", onDrop);
|
canvasElement.removeEventListener("drop", onDrop);
|
||||||
canvasElement.removeEventListener("dragover", onDragOver);
|
canvasElement.removeEventListener("dragover", onDragOver);
|
||||||
};
|
};
|
||||||
}, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool]);
|
}, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (controls)
|
if (controls)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
CommentsIcon,
|
CommentsIcon,
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
@@ -15,6 +15,7 @@ interface CardProps {
|
|||||||
price: number;
|
price: number;
|
||||||
rating: number;
|
rating: number;
|
||||||
views: number;
|
views: number;
|
||||||
|
image: string;
|
||||||
onSelectCard: (cardData: {
|
onSelectCard: (cardData: {
|
||||||
assetName: string;
|
assetName: string;
|
||||||
uploadedOn: string;
|
uploadedOn: string;
|
||||||
@@ -30,6 +31,7 @@ const Card: React.FC<CardProps> = ({
|
|||||||
price,
|
price,
|
||||||
rating,
|
rating,
|
||||||
views,
|
views,
|
||||||
|
image,
|
||||||
onSelectCard,
|
onSelectCard,
|
||||||
}) => {
|
}) => {
|
||||||
const handleCardSelect = () => {
|
const handleCardSelect = () => {
|
||||||
@@ -42,12 +44,19 @@ const Card: React.FC<CardProps> = ({
|
|||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
</div>
|
</div>
|
||||||
<div className="image-container">
|
<div className="image-container">
|
||||||
<img src={assetImage} alt={assetName} />
|
<img src={image} alt={assetName} />
|
||||||
</div>
|
</div>
|
||||||
<div className="assets-container">
|
<div className="assets-container">
|
||||||
<div className="name-container">
|
<div className="name-container">
|
||||||
<div className="assets-name">{assetName}</div>
|
<div className="assets-name">{assetName.split("_").join(" ")}</div>
|
||||||
<div className="assets-date">{uploadedOn}</div>
|
<div className="assets-date">
|
||||||
|
Uploaded on -{" "}
|
||||||
|
{new Date(uploadedOn).toLocaleDateString("en-GB", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
year: "2-digit",
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="details">
|
<div className="details">
|
||||||
<div className="content">
|
<div className="content">
|
||||||
|
|||||||
@@ -1,9 +1,25 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Card from "./Card";
|
import Card from "./Card";
|
||||||
import AssetPreview from "./AssetPreview";
|
import AssetPreview from "./AssetPreview";
|
||||||
import RenderOverlay from "../../components/templates/Overlay";
|
import RenderOverlay from "../../components/templates/Overlay";
|
||||||
|
import { fetchAssets } from "../../services/marketplace/fetchAssets";
|
||||||
|
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 CardsContainer: React.FC = () => {
|
const CardsContainer: React.FC = () => {
|
||||||
|
const [models, setModels] = useState<ModelData[]>([]);
|
||||||
|
|
||||||
const array = [
|
const array = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -120,12 +136,23 @@ const CardsContainer: React.FC = () => {
|
|||||||
}) => {
|
}) => {
|
||||||
setSelectedCard(cardData);
|
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 (
|
return (
|
||||||
<div className="cards-container-container">
|
<div className="cards-container-container">
|
||||||
<div className="header">Products You May Like</div>
|
<div className="header">Products You May Like</div>
|
||||||
<div className="cards-wrapper-container">
|
<div className="cards-wrapper-container">
|
||||||
{array.map((asset) => (
|
{/* {array.map((asset) => (
|
||||||
<Card
|
<Card
|
||||||
key={asset.id}
|
key={asset.id}
|
||||||
assetName={asset.name}
|
assetName={asset.name}
|
||||||
@@ -135,14 +162,27 @@ const CardsContainer: React.FC = () => {
|
|||||||
views={asset.views}
|
views={asset.views}
|
||||||
onSelectCard={handleCardSelect}
|
onSelectCard={handleCardSelect}
|
||||||
/>
|
/>
|
||||||
))}
|
))} */}
|
||||||
{/* <RenderOverlay> */}
|
{models.length > 0 &&
|
||||||
{selectedCard && (
|
models.map((assetDetail) => (
|
||||||
<AssetPreview
|
<Card
|
||||||
selectedCard={selectedCard}
|
key={assetDetail._id}
|
||||||
setSelectedCard={setSelectedCard}
|
assetName={assetDetail?.filename}
|
||||||
|
uploadedOn={assetDetail.uploadDate.toString()}
|
||||||
|
price={36500}
|
||||||
|
rating={4.5}
|
||||||
|
views={500}
|
||||||
|
onSelectCard={handleCardSelect}
|
||||||
|
image={assetDetail.thumbnail}
|
||||||
/>
|
/>
|
||||||
)}
|
))}
|
||||||
|
{/* <RenderOverlay> */}
|
||||||
|
{selectedCard && (
|
||||||
|
<AssetPreview
|
||||||
|
selectedCard={selectedCard}
|
||||||
|
setSelectedCard={setSelectedCard}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{/* </RenderOverlay> */}
|
{/* </RenderOverlay> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import FilterSearch from "./FilterSearch";
|
import FilterSearch from "./FilterSearch";
|
||||||
import CardsContainer from "./CardsContainer";
|
import CardsContainer from "./CardsContainer";
|
||||||
|
|
||||||
const MarketPlace = () => {
|
const MarketPlace = () => {
|
||||||
return (
|
return (
|
||||||
<div className="marketplace-wrapper">
|
<div className="marketplace-wrapper">
|
||||||
<div className="marketplace-container">
|
<div className="marketplace-container">
|
||||||
<div className="marketPlace">
|
<div className="marketPlace">
|
||||||
<FilterSearch />
|
<FilterSearch />
|
||||||
<CardsContainer />
|
<CardsContainer />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MarketPlace;
|
export default MarketPlace;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import DuplicationControls from "./duplicationControls";
|
|||||||
import CopyPasteControls from "./copyPasteControls";
|
import CopyPasteControls from "./copyPasteControls";
|
||||||
import MoveControls from "./moveControls";
|
import MoveControls from "./moveControls";
|
||||||
import RotateControls from "./rotateControls";
|
import RotateControls from "./rotateControls";
|
||||||
|
import useModuleStore from "../../../../store/useModuleStore";
|
||||||
|
|
||||||
const SelectionControls: React.FC = () => {
|
const SelectionControls: React.FC = () => {
|
||||||
const { camera, controls, gl, scene, pointer } = useThree();
|
const { camera, controls, gl, scene, pointer } = useThree();
|
||||||
@@ -27,6 +28,7 @@ const SelectionControls: React.FC = () => {
|
|||||||
const [duplicatedObjects, setDuplicatedObjects] = useState<THREE.Object3D[]>([]);
|
const [duplicatedObjects, setDuplicatedObjects] = useState<THREE.Object3D[]>([]);
|
||||||
const boundingBoxRef = useRef<THREE.Mesh>();
|
const boundingBoxRef = useRef<THREE.Mesh>();
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]);
|
const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]);
|
||||||
|
|
||||||
@@ -97,13 +99,16 @@ const SelectionControls: React.FC = () => {
|
|||||||
clearSelection();
|
clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!toggleView) {
|
if (!toggleView && activeModule === "builder") {
|
||||||
helper.enabled = true;
|
helper.enabled = true;
|
||||||
canvasElement.addEventListener("pointerdown", onPointerDown);
|
canvasElement.addEventListener("pointerdown", onPointerDown);
|
||||||
canvasElement.addEventListener("pointermove", onPointerMove);
|
canvasElement.addEventListener("pointermove", onPointerMove);
|
||||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||||
canvasElement.addEventListener("pointerup", onPointerUp);
|
canvasElement.addEventListener("pointerup", onPointerUp);
|
||||||
canvasElement.addEventListener("keydown", onKeyDown);
|
canvasElement.addEventListener("keydown", onKeyDown);
|
||||||
|
} else {
|
||||||
|
helper.enabled = false;
|
||||||
|
helper.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -115,7 +120,13 @@ const SelectionControls: React.FC = () => {
|
|||||||
helper.enabled = false;
|
helper.enabled = false;
|
||||||
helper.dispose();
|
helper.dispose();
|
||||||
};
|
};
|
||||||
}, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, floorItems, rotatedObjects]);
|
}, [camera, controls, scene, toggleView, selectedAssets, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, floorItems, rotatedObjects, activeModule]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeModule !== "builder") {
|
||||||
|
clearSelection();
|
||||||
|
}
|
||||||
|
}, [activeModule]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
if (pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) {
|
||||||
|
|||||||
@@ -15,13 +15,10 @@ import background from "../../assets/textures/hdr/mudroadpuresky2k.hdr";
|
|||||||
import SelectionControls from "./controls/selection/selectionControls";
|
import SelectionControls from "./controls/selection/selectionControls";
|
||||||
import MeasurementTool from "./tools/measurementTool";
|
import MeasurementTool from "./tools/measurementTool";
|
||||||
import Simulation from "../simulation/simulation";
|
import Simulation from "../simulation/simulation";
|
||||||
import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget";
|
|
||||||
|
|
||||||
import { useThree } from "@react-three/fiber";
|
|
||||||
import * as THREE from "three";
|
|
||||||
import DroppedObjects from "../../components/ui/componets/DroppedFloatingWidgets";
|
import DroppedObjects from "../../components/ui/componets/DroppedFloatingWidgets";
|
||||||
|
|
||||||
// import Simulation from "./simulationtemp/simulation";
|
// import Simulation from "./simulationtemp/simulation";
|
||||||
|
import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget";
|
||||||
|
|
||||||
export default function Scene() {
|
export default function Scene() {
|
||||||
|
|
||||||
@@ -30,7 +27,6 @@ export default function Scene() {
|
|||||||
{ name: "backward", keys: ["ArrowDown", "s", "S"] },
|
{ name: "backward", keys: ["ArrowDown", "s", "S"] },
|
||||||
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
||||||
{ name: "right", keys: ["ArrowRight", "d", "D"] },
|
{ name: "right", keys: ["ArrowRight", "d", "D"] },
|
||||||
// { name: "jump", keys: ["Space"] },
|
|
||||||
], [])
|
], [])
|
||||||
|
|
||||||
|
|
||||||
@@ -47,7 +43,6 @@ export default function Scene() {
|
|||||||
}}
|
}}
|
||||||
|
|
||||||
>
|
>
|
||||||
<DroppedObjects/>
|
|
||||||
<Controls />
|
<Controls />
|
||||||
<TransformControl />
|
<TransformControl />
|
||||||
<SelectionControls />
|
<SelectionControls />
|
||||||
@@ -63,6 +58,9 @@ export default function Scene() {
|
|||||||
<MqttEvents />
|
<MqttEvents />
|
||||||
<Environment files={background} environmentIntensity={1.5} />
|
<Environment files={background} environmentIntensity={1.5} />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</KeyboardControls>
|
</KeyboardControls>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
useShadows,
|
useShadows,
|
||||||
useUpdateScene,
|
useUpdateScene,
|
||||||
useWalls,
|
useWalls,
|
||||||
useToolMode
|
useToolMode,
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
|
|
||||||
////////// 3D Function Imports //////////
|
////////// 3D Function Imports //////////
|
||||||
@@ -50,16 +50,17 @@ import { findEnvironment } from "../../../services/factoryBuilder/environment/fi
|
|||||||
import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility";
|
import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility";
|
||||||
import DrieHtmlTemp from "../mqttTemp/drieHtmlTemp";
|
import DrieHtmlTemp from "../mqttTemp/drieHtmlTemp";
|
||||||
import ZoneGroup from "../../builder/groups/zoneGroup";
|
import ZoneGroup from "../../builder/groups/zoneGroup";
|
||||||
|
import Agv from "../../builder/agv/agv";
|
||||||
|
|
||||||
export default function World() {
|
export default function World() {
|
||||||
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
||||||
const csg = useRef(); // Reference for CSG object, used for 3D modeling.
|
const csg = useRef(); // Reference for CSG object, used for 3D modeling.
|
||||||
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
|
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
|
||||||
const scene = useRef() as Types.RefScene; // Reference to the scene.
|
const scene = useRef() as Types.RefScene; // Reference to the scene.
|
||||||
const camera = useRef() as Types.RefCamera; // Reference to the camera object.
|
const camera = useRef() as Types.RefCamera; // Reference to the camera object.
|
||||||
const controls = useRef<any>(); // Reference to the controls object.
|
const controls = useRef<any>(); // Reference to the controls object.
|
||||||
const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
|
const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
|
||||||
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
|
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
|
||||||
|
|
||||||
// Assigning the scene and camera from the Three.js state to the references.
|
// Assigning the scene and camera from the Three.js state to the references.
|
||||||
|
|
||||||
@@ -68,47 +69,48 @@ export default function World() {
|
|||||||
controls.current = state.controls;
|
controls.current = state.controls;
|
||||||
raycaster.current = state.raycaster;
|
raycaster.current = state.raycaster;
|
||||||
|
|
||||||
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
|
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
|
||||||
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
|
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
|
||||||
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
|
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
|
||||||
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
|
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
|
||||||
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
|
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
|
||||||
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
|
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
|
||||||
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
|
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
|
||||||
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
|
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
|
||||||
const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
|
const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
|
||||||
const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
|
const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
|
||||||
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
|
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
|
||||||
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
|
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
|
||||||
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
|
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
|
||||||
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
|
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
|
||||||
const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
|
const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
|
||||||
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
|
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
|
||||||
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
|
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
|
||||||
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
|
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
|
||||||
const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
|
const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
|
||||||
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
|
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
|
||||||
const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
|
const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
|
||||||
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
|
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
|
||||||
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
|
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
|
||||||
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
|
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
|
||||||
const floorGroupAisle = useRef() as Types.RefGroup;
|
const floorGroupAisle = useRef() as Types.RefGroup;
|
||||||
const zoneGroup = useRef() as Types.RefGroup;
|
const zoneGroup = useRef() as Types.RefGroup;
|
||||||
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
|
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
|
||||||
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
|
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
|
||||||
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
|
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
|
||||||
const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
|
const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
|
||||||
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
|
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
|
||||||
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
|
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
|
||||||
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
|
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
|
||||||
|
|
||||||
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
||||||
|
|
||||||
const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
const [selectedItemsIndex, setSelectedItemsIndex] =
|
||||||
const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
||||||
const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D.
|
const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
||||||
|
const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D.
|
||||||
const { toolMode, setToolMode } = useToolMode();
|
const { toolMode, setToolMode } = useToolMode();
|
||||||
const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not.
|
const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not.
|
||||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
||||||
@@ -118,7 +120,6 @@ export default function World() {
|
|||||||
const { walls, setWalls } = useWalls();
|
const { walls, setWalls } = useWalls();
|
||||||
const [RefTextupdate, setRefTextUpdate] = useState(-1000);
|
const [RefTextupdate, setRefTextUpdate] = useState(-1000);
|
||||||
|
|
||||||
|
|
||||||
// const loader = new GLTFLoader();
|
// const loader = new GLTFLoader();
|
||||||
// const dracoLoader = new DRACOLoader();
|
// const dracoLoader = new DRACOLoader();
|
||||||
|
|
||||||
@@ -162,7 +163,14 @@ export default function World() {
|
|||||||
dragPointControls.current.enabled = false;
|
dragPointControls.current.enabled = false;
|
||||||
}
|
}
|
||||||
if (toggleView) {
|
if (toggleView) {
|
||||||
Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
Layer2DVisibility(
|
||||||
|
activeLayer,
|
||||||
|
floorPlanGroup,
|
||||||
|
floorPlanGroupLine,
|
||||||
|
floorPlanGroupPoint,
|
||||||
|
currentLayerPoint,
|
||||||
|
dragPointControls
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
setToolMode(null);
|
setToolMode(null);
|
||||||
setDeletePointOrLine(false);
|
setDeletePointOrLine(false);
|
||||||
@@ -179,11 +187,14 @@ export default function World() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const email = localStorage.getItem('email')
|
const email = localStorage.getItem("email");
|
||||||
const organization = (email!.split("@")[1]).split(".")[0];
|
const organization = email!.split("@")[1].split(".")[0];
|
||||||
|
|
||||||
async function fetchVisibility() {
|
async function fetchVisibility() {
|
||||||
const visibility = await findEnvironment(organization, localStorage.getItem('userId')!);
|
const visibility = await findEnvironment(
|
||||||
|
organization,
|
||||||
|
localStorage.getItem("userId")!
|
||||||
|
);
|
||||||
if (visibility) {
|
if (visibility) {
|
||||||
setRoofVisibility(visibility.roofVisibility);
|
setRoofVisibility(visibility.roofVisibility);
|
||||||
setWallVisibility(visibility.wallVisibility);
|
setWallVisibility(visibility.wallVisibility);
|
||||||
@@ -191,13 +202,33 @@ export default function World() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchVisibility();
|
fetchVisibility();
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
////////// UseFrame is Here //////////
|
////////// UseFrame is Here //////////
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (toolMode) {
|
if (toolMode) {
|
||||||
Draw(state, plane, cursorPosition, floorPlanGroupPoint, floorPlanGroupLine, snappedPoint, isSnapped, isSnappedUUID, line, lines, ispreSnapped, floorPlanGroup, ReferenceLineMesh, LineCreated, setRefTextUpdate, Tube, anglesnappedPoint, isAngleSnapped, toolMode)
|
Draw(
|
||||||
|
state,
|
||||||
|
plane,
|
||||||
|
cursorPosition,
|
||||||
|
floorPlanGroupPoint,
|
||||||
|
floorPlanGroupLine,
|
||||||
|
snappedPoint,
|
||||||
|
isSnapped,
|
||||||
|
isSnappedUUID,
|
||||||
|
line,
|
||||||
|
lines,
|
||||||
|
ispreSnapped,
|
||||||
|
floorPlanGroup,
|
||||||
|
ReferenceLineMesh,
|
||||||
|
LineCreated,
|
||||||
|
setRefTextUpdate,
|
||||||
|
Tube,
|
||||||
|
anglesnappedPoint,
|
||||||
|
isAngleSnapped,
|
||||||
|
toolMode
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -304,7 +335,6 @@ export default function World() {
|
|||||||
anglesnappedPoint={anglesnappedPoint}
|
anglesnappedPoint={anglesnappedPoint}
|
||||||
/> */}
|
/> */}
|
||||||
|
|
||||||
|
|
||||||
<ZoneGroup />
|
<ZoneGroup />
|
||||||
|
|
||||||
<FloorGroupAilse
|
<FloorGroupAilse
|
||||||
@@ -327,10 +357,9 @@ export default function World() {
|
|||||||
anglesnappedPoint={anglesnappedPoint}
|
anglesnappedPoint={anglesnappedPoint}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DrieHtmlTemp
|
<DrieHtmlTemp itemsGroup={itemsGroup} />
|
||||||
itemsGroup={itemsGroup}
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
<Agv lines={lines} plane={plane} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import * as THREE from 'three';
|
|||||||
import * as Types from '../../../types/world/worldTypes';
|
import * as Types from '../../../types/world/worldTypes';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
|
||||||
interface Path {
|
interface Path {
|
||||||
modeluuid: string;
|
modeluuid: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
@@ -11,8 +10,9 @@ interface Path {
|
|||||||
uuid: string;
|
uuid: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
rotation: [number, number, number];
|
rotation: [number, number, number];
|
||||||
actions: { uuid: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
||||||
triggers: { uuid: string; type: 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];
|
pathPosition: [number, number, number];
|
||||||
pathRotation: [number, number, number];
|
pathRotation: [number, number, number];
|
||||||
@@ -32,8 +32,8 @@ function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
|
|||||||
const point2Position = new THREE.Vector3(0, 1.25, -3.3);
|
const point2Position = new THREE.Vector3(0, 1.25, -3.3);
|
||||||
|
|
||||||
const point1UUID = THREE.MathUtils.generateUUID();
|
const point1UUID = THREE.MathUtils.generateUUID();
|
||||||
const point2UUID = THREE.MathUtils.generateUUID();
|
|
||||||
const middlePointUUID = THREE.MathUtils.generateUUID();
|
const middlePointUUID = THREE.MathUtils.generateUUID();
|
||||||
|
const point2UUID = THREE.MathUtils.generateUUID();
|
||||||
|
|
||||||
const newPath: Path = {
|
const newPath: Path = {
|
||||||
modeluuid: item.modeluuid,
|
modeluuid: item.modeluuid,
|
||||||
@@ -43,22 +43,25 @@ function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
|
|||||||
uuid: point1UUID,
|
uuid: point1UUID,
|
||||||
position: [point1Position.x, point1Position.y, point1Position.z],
|
position: [point1Position.x, point1Position.y, point1Position.z],
|
||||||
rotation: [0, 0, 0],
|
rotation: [0, 0, 0],
|
||||||
actions: [{ uuid: THREE.MathUtils.generateUUID(), type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false }],
|
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false }],
|
||||||
triggers: [],
|
triggers: [],
|
||||||
|
connections: { source: { pathUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uuid: middlePointUUID,
|
uuid: middlePointUUID,
|
||||||
position: [middlePointPosition.x, middlePointPosition.y, middlePointPosition.z],
|
position: [middlePointPosition.x, middlePointPosition.y, middlePointPosition.z],
|
||||||
rotation: [0, 0, 0],
|
rotation: [0, 0, 0],
|
||||||
actions: [{ uuid: THREE.MathUtils.generateUUID(), type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false }],
|
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false }],
|
||||||
triggers: [],
|
triggers: [],
|
||||||
|
connections: { source: { pathUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uuid: point2UUID,
|
uuid: point2UUID,
|
||||||
position: [point2Position.x, point2Position.y, point2Position.z],
|
position: [point2Position.x, point2Position.y, point2Position.z],
|
||||||
rotation: [0, 0, 0],
|
rotation: [0, 0, 0],
|
||||||
actions: [{ uuid: THREE.MathUtils.generateUUID(), type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false }],
|
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false }],
|
||||||
triggers: [],
|
triggers: [],
|
||||||
|
connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
pathPosition: [...item.position],
|
pathPosition: [...item.position],
|
||||||
@@ -76,4 +79,4 @@ function Behaviour({ setSimulationPaths }: { setSimulationPaths: any }) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Behaviour;
|
export default Behaviour;
|
||||||
@@ -2,21 +2,100 @@ import { useFrame, useThree } from '@react-three/fiber';
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { QuadraticBezierLine } from '@react-three/drei';
|
import { QuadraticBezierLine } from '@react-three/drei';
|
||||||
import { useConnections, useIsConnecting, useSimulationPaths } from '../../../store/store';
|
import { useIsConnecting, useSimulationPaths } from '../../../store/store';
|
||||||
import useModuleStore from '../../../store/useModuleStore';
|
import useModuleStore from '../../../store/useModuleStore';
|
||||||
|
|
||||||
function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
|
function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { gl, raycaster, scene, pointer, camera } = useThree();
|
const { gl, raycaster, scene, pointer, camera } = useThree();
|
||||||
const { connections, setConnections, addConnection } = useConnections();
|
const { setIsConnecting } = useIsConnecting();
|
||||||
const { isConnecting, setIsConnecting } = useIsConnecting();
|
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
|
|
||||||
const [firstSelected, setFirstSelected] = useState<{ pathUUID: string; sphereUUID: string; position: THREE.Vector3; isCorner: boolean; } | null>(null);
|
const [firstSelected, setFirstSelected] = useState<{
|
||||||
|
pathUUID: string;
|
||||||
|
sphereUUID: string;
|
||||||
|
position: THREE.Vector3;
|
||||||
|
isCorner: boolean;
|
||||||
|
} | null>(null);
|
||||||
const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3, end: THREE.Vector3, mid: THREE.Vector3 } | null>(null);
|
const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3, end: THREE.Vector3, mid: THREE.Vector3 } | null>(null);
|
||||||
const [hoveredSphere, setHoveredSphere] = useState<{ sphereUUID: string, position: THREE.Vector3 } | null>(null);
|
|
||||||
const [helperlineColor, setHelperLineColor] = useState<string>('red');
|
const [helperlineColor, setHelperLineColor] = useState<string>('red');
|
||||||
|
|
||||||
|
const updatePathConnections = (
|
||||||
|
fromPathUUID: string,
|
||||||
|
fromPointUUID: string,
|
||||||
|
toPathUUID: string,
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
});
|
||||||
|
|
||||||
|
setSimulationPaths(updatedPaths);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddConnection = (fromPathUUID: string, fromUUID: string, toPathUUID: string, toUUID: string) => {
|
||||||
|
updatePathConnections(fromPathUUID, fromUUID, toPathUUID, toUUID);
|
||||||
|
setFirstSelected(null);
|
||||||
|
setCurrentLine(null);
|
||||||
|
setIsConnecting(false);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
let drag = false;
|
let drag = false;
|
||||||
@@ -47,7 +126,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
if (intersects.length > 0) {
|
if (intersects.length > 0) {
|
||||||
const intersected = intersects[0].object;
|
const intersected = intersects[0].object;
|
||||||
|
|
||||||
if (intersected.name.includes("event-sphere")) {
|
if (intersected.name.includes("action-sphere")) {
|
||||||
const pathUUID = intersected.userData.path.modeluuid;
|
const pathUUID = intersected.userData.path.modeluuid;
|
||||||
const sphereUUID = intersected.uuid;
|
const sphereUUID = intersected.uuid;
|
||||||
const worldPosition = new THREE.Vector3();
|
const worldPosition = new THREE.Vector3();
|
||||||
@@ -59,9 +138,12 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (pathUUID) {
|
if (pathUUID) {
|
||||||
const isAlreadyConnected = connections.some((connection) =>
|
// Check if sphere is already connected
|
||||||
connection.fromUUID === sphereUUID ||
|
const isAlreadyConnected = simulationPaths.some(path =>
|
||||||
connection.toConnections.some(conn => conn.toUUID === sphereUUID)
|
path.points.some(point =>
|
||||||
|
point.uuid === sphereUUID &&
|
||||||
|
point.connections.targets.length > 0
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isAlreadyConnected) {
|
if (isAlreadyConnected) {
|
||||||
@@ -89,16 +171,12 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
addConnection({
|
handleAddConnection(
|
||||||
fromPathUUID: firstSelected.pathUUID,
|
firstSelected.pathUUID,
|
||||||
fromUUID: firstSelected.sphereUUID,
|
firstSelected.sphereUUID,
|
||||||
toConnections: [{ toPathUUID: pathUUID, toUUID: sphereUUID }]
|
pathUUID,
|
||||||
});
|
sphereUUID
|
||||||
|
);
|
||||||
setFirstSelected(null);
|
|
||||||
setCurrentLine(null);
|
|
||||||
setIsConnecting(false);
|
|
||||||
setHoveredSphere(null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,7 +184,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
setFirstSelected(null);
|
setFirstSelected(null);
|
||||||
setCurrentLine(null);
|
setCurrentLine(null);
|
||||||
setIsConnecting(false);
|
setIsConnecting(false);
|
||||||
setHoveredSphere(null);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,7 +196,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
setFirstSelected(null);
|
setFirstSelected(null);
|
||||||
setCurrentLine(null);
|
setCurrentLine(null);
|
||||||
setIsConnecting(false);
|
setIsConnecting(false);
|
||||||
setHoveredSphere(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -128,7 +204,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||||
};
|
};
|
||||||
}, [camera, scene, raycaster, firstSelected, connections]);
|
}, [camera, scene, raycaster, firstSelected, simulationPaths]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (firstSelected) {
|
if (firstSelected) {
|
||||||
@@ -153,7 +229,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sphereIntersects = raycaster.intersectObjects(pathsGroupRef.current.children, true).filter((obj) =>
|
const sphereIntersects = raycaster.intersectObjects(pathsGroupRef.current.children, true).filter((obj) =>
|
||||||
obj.object.name.includes("event-sphere")
|
obj.object.name.includes("action-sphere")
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sphereIntersects.length > 0) {
|
if (sphereIntersects.length > 0) {
|
||||||
@@ -168,9 +244,11 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
sphereUUID === sphere.userData.path.points[sphere.userData.path.points.length - 1].uuid
|
sphereUUID === sphere.userData.path.points[sphere.userData.path.points.length - 1].uuid
|
||||||
);
|
);
|
||||||
|
|
||||||
const isAlreadyConnected = connections.some((connection) =>
|
const isAlreadyConnected = simulationPaths.some(path =>
|
||||||
connection.fromUUID === sphereUUID ||
|
path.points.some(point =>
|
||||||
connection.toConnections.some(conn => conn.toUUID === sphereUUID)
|
point.uuid === sphereUUID &&
|
||||||
|
point.connections.targets.length > 0
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -186,10 +264,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (snappedSphere) {
|
if (snappedSphere) {
|
||||||
setHoveredSphere(snappedSphere);
|
|
||||||
point = snappedSphere.position;
|
point = snappedSphere.position;
|
||||||
} else {
|
|
||||||
setHoveredSphere(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (point) {
|
if (point) {
|
||||||
@@ -224,49 +299,48 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Render connections from simulationPaths
|
||||||
useEffect(() => {
|
|
||||||
console.log('connections: ', connections);
|
|
||||||
}, [connections]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{connections.map((connection, index) => {
|
{simulationPaths.flatMap(path =>
|
||||||
const fromSphere = scene.getObjectByProperty('uuid', connection.fromUUID);
|
path.points.flatMap(point =>
|
||||||
const toSphere = scene.getObjectByProperty('uuid', connection.toConnections[0].toUUID);
|
point.connections.targets.map((target, index) => {
|
||||||
|
const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
|
||||||
|
const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);
|
||||||
|
|
||||||
if (fromSphere && toSphere) {
|
if (fromSphere && toSphere) {
|
||||||
const fromWorldPosition = new THREE.Vector3();
|
const fromWorldPosition = new THREE.Vector3();
|
||||||
const toWorldPosition = new THREE.Vector3();
|
const toWorldPosition = new THREE.Vector3();
|
||||||
fromSphere.getWorldPosition(fromWorldPosition);
|
fromSphere.getWorldPosition(fromWorldPosition);
|
||||||
toSphere.getWorldPosition(toWorldPosition);
|
toSphere.getWorldPosition(toWorldPosition);
|
||||||
|
|
||||||
const distance = fromWorldPosition.distanceTo(toWorldPosition);
|
const distance = fromWorldPosition.distanceTo(toWorldPosition);
|
||||||
const heightFactor = Math.max(0.5, distance * 0.2);
|
const heightFactor = Math.max(0.5, distance * 0.2);
|
||||||
|
|
||||||
const midPoint = new THREE.Vector3(
|
const midPoint = new THREE.Vector3(
|
||||||
(fromWorldPosition.x + toWorldPosition.x) / 2,
|
(fromWorldPosition.x + toWorldPosition.x) / 2,
|
||||||
Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
|
Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
|
||||||
(fromWorldPosition.z + toWorldPosition.z) / 2
|
(fromWorldPosition.z + toWorldPosition.z) / 2
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QuadraticBezierLine
|
<QuadraticBezierLine
|
||||||
key={index}
|
key={`${point.uuid}-${target.pointUUID}-${index}`}
|
||||||
start={fromWorldPosition.toArray()}
|
start={fromWorldPosition.toArray()}
|
||||||
end={toWorldPosition.toArray()}
|
end={toWorldPosition.toArray()}
|
||||||
mid={midPoint.toArray()}
|
mid={midPoint.toArray()}
|
||||||
color="white"
|
color="white"
|
||||||
lineWidth={4}
|
lineWidth={4}
|
||||||
dashed
|
dashed
|
||||||
dashSize={1}
|
dashSize={1}
|
||||||
dashScale={20}
|
dashScale={20}
|
||||||
userData={connection}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
}
|
||||||
}
|
return null;
|
||||||
return null;
|
})
|
||||||
})}
|
)
|
||||||
|
)}
|
||||||
|
|
||||||
{currentLine && (
|
{currentLine && (
|
||||||
<QuadraticBezierLine
|
<QuadraticBezierLine
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ interface Path {
|
|||||||
uuid: string;
|
uuid: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
rotation: [number, number, number];
|
rotation: [number, number, number];
|
||||||
actions: { uuid: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
|
||||||
triggers: { uuid: string; type: 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];
|
pathPosition: [number, number, number];
|
||||||
pathRotation: [number, number, number];
|
pathRotation: [number, number, number];
|
||||||
@@ -26,7 +27,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
|||||||
const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
|
const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere();
|
||||||
const { setSelectedPath } = useSelectedPath();
|
const { setSelectedPath } = useSelectedPath();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const { isConnecting, setIsConnecting } = useIsConnecting();
|
const { isConnecting } = useIsConnecting();
|
||||||
const { camera } = useThree();
|
const { camera } = useThree();
|
||||||
|
|
||||||
const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
|
const groupRefs = useRef<{ [key: string]: THREE.Group }>({});
|
||||||
@@ -105,6 +106,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
|||||||
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
setSelectedPath({ path, group: groupRefs.current[path.modeluuid] });
|
||||||
setSelectedActionSphere(null);
|
setSelectedActionSphere(null);
|
||||||
setTransformMode(null);
|
setTransformMode(null);
|
||||||
|
setSubModule('mechanics');
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPath(null);
|
setSelectedPath(null);
|
||||||
@@ -117,7 +119,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject
|
|||||||
uuid={point.uuid}
|
uuid={point.uuid}
|
||||||
position={point.position}
|
position={point.position}
|
||||||
args={[0.15, 32, 32]}
|
args={[0.15, 32, 32]}
|
||||||
name='event-sphere'
|
name='action-sphere'
|
||||||
ref={el => (sphereRefs.current[point.uuid] = el!)}
|
ref={el => (sphereRefs.current[point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (isConnecting) return;
|
if (isConnecting) return;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState, useEffect, useRef } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { useConnections, useFloorItems, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../store/store';
|
import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../store/store';
|
||||||
import { useThree } from '@react-three/fiber';
|
import { useThree } from '@react-three/fiber';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import Behaviour from './behaviour/behaviour';
|
import Behaviour from './behaviour/behaviour';
|
||||||
@@ -11,7 +11,6 @@ function Simulation() {
|
|||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const pathsGroupRef = useRef() as React.MutableRefObject<THREE.Group>;
|
const pathsGroupRef = useRef() as React.MutableRefObject<THREE.Group>;
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const { connections, setConnections, addConnection, removeConnection } = useConnections();
|
|
||||||
const [processes, setProcesses] = useState([]);
|
const [processes, setProcesses] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -32,9 +31,9 @@ function Simulation() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Behaviour setSimulationPaths={setSimulationPaths} />
|
||||||
{activeModule === 'simulation' && (
|
{activeModule === 'simulation' && (
|
||||||
<>
|
<>
|
||||||
<Behaviour setSimulationPaths={setSimulationPaths} />
|
|
||||||
<PathCreation pathsGroupRef={pathsGroupRef} />
|
<PathCreation pathsGroupRef={pathsGroupRef} />
|
||||||
<PathConnector pathsGroupRef={pathsGroupRef} />
|
<PathConnector pathsGroupRef={pathsGroupRef} />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation } from '../../store/store';
|
import { useSelectedActionSphere, useToggleView, useSimulationPaths, useSelectedPath, useStartSimulation, useDrawMaterialPath } from '../../store/store';
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import useModuleStore from '../../store/useModuleStore';
|
import useModuleStore from '../../store/useModuleStore';
|
||||||
|
|
||||||
@@ -10,19 +10,31 @@ function SimulationUI() {
|
|||||||
const { selectedActionSphere } = useSelectedActionSphere();
|
const { selectedActionSphere } = useSelectedActionSphere();
|
||||||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
|
const { drawMaterialPath, setDrawMaterialPath } = useDrawMaterialPath();
|
||||||
|
const [activeButton, setActiveButton] = useState<string | null>(null);
|
||||||
|
|
||||||
const handleAddAction = () => {
|
const handleAddAction = () => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const newAction = { uuid: THREE.MathUtils.generateUUID(), type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: false };
|
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) => {
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||||
? { ...point, actions: [...point.actions, newAction] }
|
const actionIndex = point.actions.length;
|
||||||
: point
|
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;
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
@@ -137,15 +149,22 @@ function SimulationUI() {
|
|||||||
const handleAddTrigger = () => {
|
const handleAddTrigger = () => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
const newTrigger = { uuid: THREE.MathUtils.generateUUID(), type: '', isUsed: false };
|
|
||||||
|
|
||||||
const updatedPaths = simulationPaths.map((path) => ({
|
const updatedPaths = simulationPaths.map((path) => ({
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) => {
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||||
? { ...point, triggers: [...point.triggers, newTrigger] }
|
const triggerIndex = point.triggers.length;
|
||||||
: point
|
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;
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
@@ -239,10 +258,15 @@ function SimulationUI() {
|
|||||||
return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
|
return simulationPaths.flatMap((path) => path.points).find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||||
}, [selectedActionSphere, simulationPaths]);
|
}, [selectedActionSphere, simulationPaths]);
|
||||||
|
|
||||||
|
const createPath = () => {
|
||||||
|
setActiveButton(activeButton !== 'addMaterialPath' ? 'addMaterialPath' : null);
|
||||||
|
setDrawMaterialPath(!drawMaterialPath);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{activeModule === "simulation" && (
|
{activeModule === "simulation" && (
|
||||||
<div style={{ zIndex: 10, position: "relative", width: '260px' }}>
|
<div style={{ zIndex: 10, position: "fixed", width: '260px' }}>
|
||||||
{!ToggleView && (
|
{!ToggleView && (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
@@ -257,6 +281,10 @@ function SimulationUI() {
|
|||||||
{startSimulation ? 'Stop Simulation' : 'Start Simulation'}
|
{startSimulation ? 'Stop Simulation' : 'Start Simulation'}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<div style={{ zIndex: "10", position: "relative" }}>
|
||||||
|
{!ToggleView && <button onClick={createPath} style={{ marginTop: "10px", background: activeButton === 'addMaterialPath' ? '#ff320e' : '' }}> Add Material Path</button>}
|
||||||
|
</div>
|
||||||
|
|
||||||
{selectedPath && (
|
{selectedPath && (
|
||||||
<div style={{ marginTop: "10px" }}>
|
<div style={{ marginTop: "10px" }}>
|
||||||
<label>Path Speed:</label>
|
<label>Path Speed:</label>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as THREE from 'three';
|
|||||||
import { useState, useEffect, useRef, useMemo } from "react";
|
import { useState, useEffect, useRef, useMemo } from "react";
|
||||||
import { useLoader, useFrame } from "@react-three/fiber";
|
import { useLoader, useFrame } from "@react-three/fiber";
|
||||||
import { GLTFLoader } from "three-stdlib";
|
import { GLTFLoader } from "three-stdlib";
|
||||||
import crate from "../../../../assets/models/gltf-glb/crate_box.glb";
|
import crate from "../../../../assets/gltf-glb/crate_box.glb";
|
||||||
import { useOrganization } from '../../../../store/store';
|
import { useOrganization } from '../../../../store/store';
|
||||||
import { useControls } from 'leva';
|
import { useControls } from 'leva';
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ export default function PathFlow({ path, connections }: PathFlowProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (organization !== 'hexrfactory' || isStopped || !path) return;
|
if (isStopped || !path) return;
|
||||||
|
|
||||||
const now = performance.now();
|
const now = performance.now();
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import SideBarRight from "../components/layout/sidebarRight/SideBarRight";
|
|||||||
import useModuleStore from "../store/useModuleStore";
|
import useModuleStore from "../store/useModuleStore";
|
||||||
import RealTimeVisulization from "../components/ui/componets/RealTimeVisulization";
|
import RealTimeVisulization from "../components/ui/componets/RealTimeVisulization";
|
||||||
import Tools from "../components/ui/Tools";
|
import Tools from "../components/ui/Tools";
|
||||||
import Scene from "../modules/scene/scene";
|
// import Scene from "../modules/scene/scene";
|
||||||
import {
|
import {
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
useFloorItems,
|
useFloorItems,
|
||||||
@@ -13,17 +13,18 @@ import {
|
|||||||
useUserName,
|
useUserName,
|
||||||
useWallItems,
|
useWallItems,
|
||||||
useZones,
|
useZones,
|
||||||
|
useLoadingProgress,
|
||||||
} from "../store/store";
|
} from "../store/store";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { usePlayButtonStore } from "../store/usePlayButtonStore";
|
import { usePlayButtonStore } from "../store/usePlayButtonStore";
|
||||||
import SimulationUI from "../modules/simulation/simulationUI";
|
|
||||||
import MarketPlace from "../modules/market/MarketPlace";
|
import MarketPlace from "../modules/market/MarketPlace";
|
||||||
|
import LoadingPage from "../components/templates/LoadingPage";
|
||||||
import SimulationPlayer from "../components/ui/simulation/simulationPlayer";
|
import SimulationPlayer from "../components/ui/simulation/simulationPlayer";
|
||||||
|
|
||||||
const Project: React.FC = () => {
|
const Project: React.FC = () => {
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
|
const { loadingProgress, setLoadingProgress } = useLoadingProgress();
|
||||||
const { setUserName } = useUserName();
|
const { setUserName } = useUserName();
|
||||||
const { setOrganization } = useOrganization();
|
const { setOrganization } = useOrganization();
|
||||||
const { setFloorItems } = useFloorItems();
|
const { setFloorItems } = useFloorItems();
|
||||||
@@ -51,8 +52,10 @@ const Project: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="project-main">
|
<div className="project-main">
|
||||||
|
{loadingProgress && <LoadingPage progress={loadingProgress} />}
|
||||||
{!isPlaying && (
|
{!isPlaying && (
|
||||||
<>
|
<>
|
||||||
|
<ModuleToggle />
|
||||||
<ModuleToggle />
|
<ModuleToggle />
|
||||||
<SideBarLeft />
|
<SideBarLeft />
|
||||||
<SideBarRight />
|
<SideBarRight />
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ import React, { useState, FormEvent } from "react";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { LogoIconLarge } from "../components/icons/Logo";
|
import { LogoIconLarge } from "../components/icons/Logo";
|
||||||
import { EyeIcon } from "../components/icons/ExportCommonIcons";
|
import { EyeIcon } from "../components/icons/ExportCommonIcons";
|
||||||
import { useOrganization, useUserName } from "../store/store";
|
import { useLoadingProgress, useOrganization, useUserName } from "../store/store";
|
||||||
import { signInApi } from "../services/factoryBuilder/signInSignUp/signInApi";
|
import { signInApi } from "../services/factoryBuilder/signInSignUp/signInApi";
|
||||||
import { signUpApi } from "../services/factoryBuilder/signInSignUp/signUpApi";
|
import { signUpApi } from "../services/factoryBuilder/signInSignUp/signUpApi";
|
||||||
// import LoadingPage from "../components/templates/LoadingPage";
|
|
||||||
|
|
||||||
const UserAuth: React.FC = () => {
|
const UserAuth: React.FC = () => {
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
@@ -14,7 +13,8 @@ const UserAuth: React.FC = () => {
|
|||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [isSignIn, setIsSignIn] = useState(true);
|
const [isSignIn, setIsSignIn] = useState(true);
|
||||||
const { userName, setUserName } = useUserName();
|
const { userName, setUserName } = useUserName();
|
||||||
const { organization, setOrganization } = useOrganization();
|
const { setOrganization } = useOrganization();
|
||||||
|
const { setLoadingProgress } = useLoadingProgress();
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ const UserAuth: React.FC = () => {
|
|||||||
localStorage.setItem("email", res.email);
|
localStorage.setItem("email", res.email);
|
||||||
localStorage.setItem("userName", res.name);
|
localStorage.setItem("userName", res.name);
|
||||||
if (res.isShare) {
|
if (res.isShare) {
|
||||||
|
setLoadingProgress(1);
|
||||||
navigate("/Project");
|
navigate("/Project");
|
||||||
}
|
}
|
||||||
} else if (res.message === "User Not Found!!! Kindly signup...") {
|
} else if (res.message === "User Not Found!!! Kindly signup...") {
|
||||||
@@ -63,7 +64,6 @@ const UserAuth: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* <LoadingPage progress={20} /> */}
|
|
||||||
<div className="auth-container">
|
<div className="auth-container">
|
||||||
<div className="logo-icon">
|
<div className="logo-icon">
|
||||||
<LogoIconLarge />
|
<LogoIconLarge />
|
||||||
@@ -141,7 +141,7 @@ const UserAuth: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
{!isSignIn && (
|
{!isSignIn && (
|
||||||
<div className="policy-checkbox">
|
<div className="policy-checkbox">
|
||||||
<input type="checkbox" name="" id="" required/>
|
<input type="checkbox" name="" id="" required />
|
||||||
<div className="label">
|
<div className="label">
|
||||||
I have read and agree to the terms of service
|
I have read and agree to the terms of service
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||||
import { retrieveGLTF, storeGLTF } from '../../../components/scene/indexDB/idbUtils';
|
import { retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
|
||||||
|
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
const dracoLoader = new DRACOLoader();
|
const dracoLoader = new DRACOLoader();
|
||||||
|
|||||||
14
app/src/services/marketplace/fetchAssets.ts
Normal file
14
app/src/services/marketplace/fetchAssets.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
export const fetchAssets = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${BackEnd_url}/api/v1/getAllAssets`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Network response was not ok");
|
||||||
|
}
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error: ", error);
|
||||||
|
// throw new Error(error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -2,30 +2,47 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_BACKEND_URL}`;
|
|||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
|
||||||
export const panelData = async (organization: string, zoneID: string, panelOrder: Side[]) => {
|
export const panelData = async (
|
||||||
console.log('panelOrder: ', panelOrder);
|
organization: string,
|
||||||
console.log('zoneID: ', zoneID);
|
zoneID: string,
|
||||||
console.log('organization: ', organization);
|
panelOrder: Side[]
|
||||||
try {
|
) => {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/v1/panel/save`, {
|
console.log("panelOrder: ", panelOrder);
|
||||||
method: "POST",
|
console.log("zoneID: ", zoneID);
|
||||||
headers: {
|
console.log("organization: ", organization);
|
||||||
"Content-Type": "application/json",
|
try {
|
||||||
},
|
const response = await fetch(`${url_Backend_dwinzo}/api/v1/panel/save`, {
|
||||||
body: JSON.stringify({ organization, zoneID, panelOrder }),
|
method: "POST",
|
||||||
});
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ organization, zoneID, panelOrder }),
|
||||||
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Failed to add panelOrder for Zone");
|
throw new Error("Failed to add panelOrder for 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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// {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,6 +2,7 @@ import * as THREE from "three";
|
|||||||
import * as Types from "../types/world/worldTypes";
|
import * as Types from "../types/world/worldTypes";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client";
|
||||||
|
import { ComponentType, SVGProps } from "react";
|
||||||
|
|
||||||
export const useSocketStore = create<any>((set: any, get: any) => ({
|
export const useSocketStore = create<any>((set: any, get: any) => ({
|
||||||
socket: null,
|
socket: null,
|
||||||
@@ -29,6 +30,11 @@ 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 }),
|
||||||
|
}));
|
||||||
|
|
||||||
export const useOrganization = create<any>((set: any) => ({
|
export const useOrganization = create<any>((set: any) => ({
|
||||||
organization: "",
|
organization: "",
|
||||||
setOrganization: (x: any) => set(() => ({ organization: x })),
|
setOrganization: (x: any) => set(() => ({ organization: x })),
|
||||||
@@ -306,27 +312,19 @@ export const useSelectedPath = create<any>((set: any) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
interface Path {
|
interface Path {
|
||||||
modeluuid: string;
|
modeluuid: string;
|
||||||
modelName: string;
|
modelName: string;
|
||||||
points: {
|
points: {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
position: [number, number, number];
|
position: [number, number, number];
|
||||||
rotation: [number, number, number];
|
rotation: [number, number, number];
|
||||||
actions:
|
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 }[] | [];
|
||||||
uuid: string;
|
connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
|
||||||
type: string;
|
}[];
|
||||||
material: string;
|
pathPosition: [number, number, number];
|
||||||
delay: number | string;
|
pathRotation: [number, number, number];
|
||||||
spawnInterval: number | string;
|
speed: number;
|
||||||
isUsed: boolean;
|
|
||||||
}[]
|
|
||||||
| [];
|
|
||||||
triggers: { uuid: string; type: string; isUsed: boolean }[] | [];
|
|
||||||
}[];
|
|
||||||
pathPosition: [number, number, number];
|
|
||||||
pathRotation: [number, number, number];
|
|
||||||
speed: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SimulationPathsStore {
|
interface SimulationPathsStore {
|
||||||
@@ -335,79 +333,8 @@ interface SimulationPathsStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
|
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
|
||||||
simulationPaths: [],
|
simulationPaths: [],
|
||||||
setSimulationPaths: (paths) => set({ simulationPaths: paths }),
|
setSimulationPaths: (paths: Path[]) => set({ simulationPaths: paths }),
|
||||||
}));
|
|
||||||
|
|
||||||
// interface Point {
|
|
||||||
// uuid: string;
|
|
||||||
// position: [number, number, number];
|
|
||||||
// rotation: [number, number, number];
|
|
||||||
// event: {
|
|
||||||
// uuid: string;
|
|
||||||
// type: string;
|
|
||||||
// material: string;
|
|
||||||
// delay: number | string;
|
|
||||||
// spawnInterval: number | string;
|
|
||||||
// isUsed: boolean;
|
|
||||||
// };
|
|
||||||
// trigger: {
|
|
||||||
// uuid: string;
|
|
||||||
// type: string;
|
|
||||||
// isUsed: boolean;
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// interface Process {
|
|
||||||
// processId: string;
|
|
||||||
// processName: string;
|
|
||||||
// points: Point[];
|
|
||||||
// pathPosition: [number, number, number];
|
|
||||||
// pathRotation: [number, number, number];
|
|
||||||
// speed: number;
|
|
||||||
// isUsed: boolean;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// interface Path {
|
|
||||||
// modeluuid: string;
|
|
||||||
// processes: Process[];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// interface SimulationPathsStore {
|
|
||||||
// simulationPaths: Path[];
|
|
||||||
// setSimulationPaths: (paths: Path[]) => void;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
|
|
||||||
// simulationPaths: [],
|
|
||||||
// setSimulationPaths: (paths) => set({ simulationPaths: paths }),
|
|
||||||
// }));
|
|
||||||
|
|
||||||
export const useConnections = create<Types.ConnectionStore>((set) => ({
|
|
||||||
connections: [],
|
|
||||||
|
|
||||||
setConnections: (connections) => set({ connections }),
|
|
||||||
|
|
||||||
addConnection: (newConnection) =>
|
|
||||||
set((state) => ({
|
|
||||||
connections: [...state.connections, newConnection],
|
|
||||||
})),
|
|
||||||
|
|
||||||
removeConnection: (fromUUID, toUUID) =>
|
|
||||||
set((state) => ({
|
|
||||||
connections: state.connections
|
|
||||||
.map((connection) =>
|
|
||||||
connection.fromUUID === fromUUID
|
|
||||||
? {
|
|
||||||
...connection,
|
|
||||||
toConnections: connection.toConnections.filter(
|
|
||||||
(to) => to.toUUID !== toUUID
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: connection
|
|
||||||
)
|
|
||||||
.filter((connection) => connection.toConnections.length > 0),
|
|
||||||
})),
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useIsConnecting = create<any>((set: any) => ({
|
export const useIsConnecting = create<any>((set: any) => ({
|
||||||
@@ -428,30 +355,14 @@ export const usezonePosition = create<any>((set: any) => ({
|
|||||||
setZonePosition: (x: any) => set({ zonePosition: x }),
|
setZonePosition: (x: any) => set({ zonePosition: x }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
interface EditPositionState {
|
interface EditPositionState {
|
||||||
Edit: boolean;
|
Edit: boolean;
|
||||||
setEdit: (value: boolean) => void;
|
setEdit: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useEditPosition = create<EditPositionState>((set) => ({
|
export const useEditPosition = create<EditPositionState>((set) => ({
|
||||||
Edit: false,
|
Edit: false,
|
||||||
setEdit: (value) => set({ Edit: value }), // Properly updating the state
|
setEdit: (value) => set({ Edit: value }), // Properly updating the state
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
interface DroppedObject {
|
|
||||||
header: string;
|
|
||||||
value: string;
|
|
||||||
per: string;
|
|
||||||
className: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DroppedObjectsState {
|
|
||||||
objects: DroppedObject[];
|
|
||||||
addObject: (obj: DroppedObject) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useDroppedObjectsStore = create<DroppedObjectsState>((set) => ({
|
|
||||||
objects: [],
|
|
||||||
addObject: (obj) => set((state) => ({ objects: [...state.objects, obj] })),
|
|
||||||
}));
|
|
||||||
@@ -1,28 +1,28 @@
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
|
||||||
interface Measurement {
|
interface Measurement {
|
||||||
name: string;
|
name: string;
|
||||||
fields: string;
|
fields: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MeasurementStore {
|
interface MeasurementStore {
|
||||||
measurements: Measurement[];
|
measurements: Measurement[];
|
||||||
interval: number;
|
interval: number;
|
||||||
duration: string;
|
duration: string;
|
||||||
setMeasurements: (newMeasurements: Measurement[]) => void;
|
setMeasurements: (newMeasurements: Measurement[]) => void;
|
||||||
updateDuration: (newDuration: string) => void;
|
updateDuration: (newDuration: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useChartStore = create<MeasurementStore>((set) => ({
|
const useChartStore = create<MeasurementStore>((set) => ({
|
||||||
measurements: [],
|
measurements: [],
|
||||||
interval: 1000,
|
interval: 1000,
|
||||||
duration: "1h",
|
duration: "1h",
|
||||||
|
|
||||||
setMeasurements: (newMeasurements) =>
|
setMeasurements: (newMeasurements) =>
|
||||||
set(() => ({ measurements: newMeasurements })),
|
set(() => ({ measurements: newMeasurements })),
|
||||||
|
|
||||||
updateDuration: (newDuration) =>
|
updateDuration: (newDuration) =>
|
||||||
set(() => ({ duration: newDuration })),
|
set(() => ({ duration: newDuration })),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default useChartStore;
|
export default useChartStore;
|
||||||
|
|||||||
78
app/src/store/useDroppedObjectsStore.ts
Normal file
78
app/src/store/useDroppedObjectsStore.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
|
||||||
|
type DroppedObject = {
|
||||||
|
className: string;
|
||||||
|
position: [number, number];
|
||||||
|
value?: number;
|
||||||
|
per?: string;
|
||||||
|
header?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Zone = {
|
||||||
|
zoneName: string;
|
||||||
|
zoneId: string;
|
||||||
|
objects: DroppedObject[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type DroppedObjectsState = {
|
||||||
|
zones: Record<string, Zone>;
|
||||||
|
setZone: (zoneName: string, zoneId: string) => void;
|
||||||
|
addObject: (zoneName: string, newObject: DroppedObject) => void;
|
||||||
|
updateObjectPosition: (
|
||||||
|
zoneName: string,
|
||||||
|
index: number,
|
||||||
|
newPosition: [number, number]
|
||||||
|
) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDroppedObjectsStore = create<DroppedObjectsState>((set) => ({
|
||||||
|
zones: {},
|
||||||
|
|
||||||
|
setZone: (zoneName: string, zoneId: string) =>
|
||||||
|
set((state) => ({
|
||||||
|
zones: {
|
||||||
|
[zoneName]: state.zones[zoneName] || { zoneName, zoneId, objects: [] }, // Keep existing zone if it exists
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
|
||||||
|
addObject: (zoneName: string, newObject: DroppedObject) =>
|
||||||
|
set((state) => ({
|
||||||
|
zones: {
|
||||||
|
...state.zones,
|
||||||
|
[zoneName]: {
|
||||||
|
...state.zones[zoneName],
|
||||||
|
objects: [...state.zones[zoneName].objects, newObject], // Append new object
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
|
||||||
|
updateObjectPosition: (zoneName, index, newPosition) =>
|
||||||
|
set((state) => {
|
||||||
|
const zone = state.zones[zoneName];
|
||||||
|
if (!zone) return state;
|
||||||
|
return {
|
||||||
|
zones: {
|
||||||
|
[zoneName]: {
|
||||||
|
...zone,
|
||||||
|
objects: zone.objects.map((obj, i) =>
|
||||||
|
i === index ? { ...obj, position: newPosition } : obj
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
export interface DroppedObjects {
|
||||||
|
header: string;
|
||||||
|
value: string | number; // ✅ Allows both numbers and formatted strings
|
||||||
|
per: string;
|
||||||
|
className: string;
|
||||||
|
position: [number, number]; // ✅ Ensures position is a tuple
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Zones {
|
||||||
|
zoneName: string;
|
||||||
|
zoneId: string;
|
||||||
|
objects: DroppedObject[];
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
background-color: var(--background-color-secondary);
|
background-color: var(--background-color-secondary);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
top: 0;
|
||||||
padding: 100px 50px;
|
padding: 100px 50px;
|
||||||
padding-bottom: 32px;
|
padding-bottom: 32px;
|
||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(6px);
|
||||||
@@ -89,6 +90,7 @@
|
|||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
font-weight: $medium-weight;
|
font-weight: $medium-weight;
|
||||||
font-size: $xlarge;
|
font-size: $xlarge;
|
||||||
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cards-wrapper-container {
|
.cards-wrapper-container {
|
||||||
@@ -122,7 +124,13 @@
|
|||||||
.image-container {
|
.image-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
max-height: 180px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
img{
|
||||||
|
height: inherit;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.assets-container {
|
.assets-container {
|
||||||
@@ -133,6 +141,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 3px;
|
gap: 3px;
|
||||||
|
.assets-name{
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
.asstes-container {
|
.asstes-container {
|
||||||
font-weight: #{$bold-weight};
|
font-weight: #{$bold-weight};
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
padding: 6px;
|
padding: 6px;
|
||||||
|
|
||||||
.floating {
|
.floating {
|
||||||
|
|
||||||
min-height: 170px;
|
min-height: 170px;
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
border: 1.23px solid var(--border-color);
|
border: 1.23px solid var(--border-color);
|
||||||
|
|||||||
@@ -530,7 +530,7 @@
|
|||||||
border-radius: #{$border-radius-medium};
|
border-radius: #{$border-radius-medium};
|
||||||
path {
|
path {
|
||||||
stroke: var(--accent-color);
|
stroke: var(--accent-color);
|
||||||
stroke-width: 1.5px;
|
strokeWidth: 1.5px;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--accent-color);
|
background: var(--accent-color);
|
||||||
|
|||||||
@@ -15,7 +15,18 @@
|
|||||||
border-radius: #{$border-radius-medium};
|
border-radius: #{$border-radius-medium};
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
z-index: #{$z-index-default};
|
z-index: #{$z-index-default};
|
||||||
|
.floating {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 250px;
|
||||||
|
min-height: 83px;
|
||||||
|
background: var(--background-color);
|
||||||
|
border: 1.23px solid var(--border-color);
|
||||||
|
box-shadow: 0px 4.91px 4.91px 0px #0000001c;
|
||||||
|
border-radius: $border-radius-medium;
|
||||||
|
padding: 18px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
.scene-container {
|
.scene-container {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -69,7 +80,12 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.no-zone {
|
||||||
|
@include flex-center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
color: var(--text-disabled);
|
||||||
|
}
|
||||||
.zone {
|
.zone {
|
||||||
width: auto;
|
width: auto;
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
|
|||||||
Reference in New Issue
Block a user