Merge pull request 'simulation' (#53) from simulation into main
Reviewed-on: http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev/pulls/53
This commit is contained in:
commit
8cb7b5186b
|
@ -29,7 +29,6 @@
|
|||
"chartjs-plugin-annotation": "^3.1.0",
|
||||
"glob": "^11.0.0",
|
||||
"gsap": "^3.12.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
"leva": "^0.10.0",
|
||||
"mqtt": "^5.10.4",
|
||||
"postprocessing": "^6.36.4",
|
||||
|
@ -2020,7 +2019,7 @@
|
|||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "0.3.9"
|
||||
},
|
||||
|
@ -2032,7 +2031,7 @@
|
|||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
|
@ -4135,6 +4134,26 @@
|
|||
"url": "https://github.com/sponsors/gregberge"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom": {
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
|
||||
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@types/aria-query": "^5.0.1",
|
||||
"aria-query": "5.3.0",
|
||||
"chalk": "^4.1.0",
|
||||
"dom-accessibility-api": "^0.5.9",
|
||||
"lz-string": "^1.5.0",
|
||||
"pretty-format": "^27.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/jest-dom": {
|
||||
"version": "5.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz",
|
||||
|
@ -4246,25 +4265,25 @@
|
|||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
|
||||
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@tsconfig/node12": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@tsconfig/node14": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@tsconfig/node16": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@turf/along": {
|
||||
"version": "7.2.0",
|
||||
|
@ -8028,15 +8047,6 @@
|
|||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/base64-arraybuffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
|
@ -9007,7 +9017,7 @@
|
|||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "7.0.3",
|
||||
|
@ -9092,15 +9102,6 @@
|
|||
"postcss": "^8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/css-line-break": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/css-loader": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz",
|
||||
|
@ -9884,7 +9885,7 @@
|
|||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
|
@ -12488,19 +12489,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/html2canvas": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
|
||||
|
@ -15247,7 +15235,7 @@
|
|||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/makeerror": {
|
||||
"version": "1.0.12",
|
||||
|
@ -20446,15 +20434,6 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/text-segmentation": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
|
@ -20715,7 +20694,7 @@
|
|||
"version": "10.9.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
|
@ -20758,7 +20737,7 @@
|
|||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
|
||||
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.11.0"
|
||||
},
|
||||
|
@ -20770,7 +20749,7 @@
|
|||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
|
@ -21241,15 +21220,6 @@
|
|||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/utrie": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||
|
@ -21266,7 +21236,7 @@
|
|||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/v8-to-istanbul": {
|
||||
"version": "8.1.1",
|
||||
|
@ -22325,7 +22295,7 @@
|
|||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
"chartjs-plugin-annotation": "^3.1.0",
|
||||
"glob": "^11.0.0",
|
||||
"gsap": "^3.12.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
"leva": "^0.10.0",
|
||||
"mqtt": "^5.10.4",
|
||||
"postprocessing": "^6.36.4",
|
||||
|
|
|
@ -166,6 +166,7 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({
|
|||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`
|
||||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
setmeasurements(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
|
@ -219,7 +220,7 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({
|
|||
// e.stopPropagation();
|
||||
}}
|
||||
wrapperClass="pointer-none"
|
||||
className={`${selectedChartId?.id === id ? "activeChart" : ""}`}
|
||||
|
||||
>
|
||||
<div
|
||||
className={`productionCapacity-wrapper card ${selectedChartId?.id === id ? "activeChart" : ""}`}
|
||||
|
|
|
@ -46,20 +46,32 @@ interface ReturnOfInvestmentProps {
|
|||
rotation: [number, number, number];
|
||||
onContextMenu?: (event: React.MouseEvent) => void;
|
||||
}
|
||||
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, position, rotation, onContextMenu }) => {
|
||||
|
||||
const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({
|
||||
id,
|
||||
type,
|
||||
position,
|
||||
rotation,
|
||||
onContextMenu,
|
||||
}) => {
|
||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||
const {
|
||||
measurements: chartMeasurements,
|
||||
duration: chartDuration,
|
||||
name: widgetName,
|
||||
} = useChartStore();
|
||||
const [measurements, setmeasurements] = useState<any>({});
|
||||
const [duration, setDuration] = useState("1h")
|
||||
const [name, setName] = useState("Widget")
|
||||
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
|
||||
const [duration, setDuration] = useState("1h");
|
||||
const [name, setName] = useState("Widget");
|
||||
const [chartData, setChartData] = useState<{
|
||||
labels: string[];
|
||||
datasets: any[];
|
||||
}>({
|
||||
labels: [],
|
||||
datasets: [],
|
||||
});
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
// Improved sample data for the smooth curve graph (single day)
|
||||
const graphData: ChartData<"line"> = {
|
||||
labels: [
|
||||
|
@ -129,7 +141,8 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0)
|
||||
return;
|
||||
|
||||
const socket = io(`http://${iotApiUrl}`);
|
||||
|
||||
|
@ -139,7 +152,6 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
|
|||
interval: 1000,
|
||||
};
|
||||
|
||||
|
||||
const startStream = () => {
|
||||
socket.emit("lineInput", inputData);
|
||||
};
|
||||
|
@ -157,8 +169,10 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
|
|||
return {
|
||||
label: datasetKey,
|
||||
data: responseData[datasetKey]?.values ?? [],
|
||||
borderColor: index === 0 ? "rgba(75, 192, 192, 1)" : "rgba(255, 99, 132, 1)", // Light blue color
|
||||
backgroundColor: index === 0 ? "rgba(75, 192, 192, 0.2)" : "rgba(255, 99, 132, 0.2)",
|
||||
borderColor:
|
||||
index === 0 ? "rgba(75, 192, 192, 1)" : "rgba(255, 99, 132, 1)", // Light blue color
|
||||
backgroundColor:
|
||||
index === 0 ? "rgba(75, 192, 192, 0.2)" : "rgba(255, 99, 132, 0.2)",
|
||||
fill: true,
|
||||
tension: 0.4, // Smooth curve effect
|
||||
pointRadius: 0, // Hide dots
|
||||
|
@ -177,14 +191,15 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
|
|||
}, [measurements, duration, iotApiUrl]);
|
||||
|
||||
const fetchSavedInputes = async () => {
|
||||
|
||||
if (id !== "") {
|
||||
try {
|
||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setmeasurements(response.data.Data.measurements)
|
||||
setDuration(response.data.Data.duration)
|
||||
setName(response.data.widgetName)
|
||||
setmeasurements(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
|
@ -192,7 +207,7 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
|
|||
console.error("There was an error!", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchSavedInputes();
|
||||
|
@ -202,8 +217,7 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
|
|||
if (selectedChartId?.id === id) {
|
||||
fetchSavedInputes();
|
||||
}
|
||||
}
|
||||
, [chartMeasurements, chartDuration, widgetName])
|
||||
}, [chartMeasurements, chartDuration, widgetName]);
|
||||
const rotationDegrees = {
|
||||
x: (rotation[0] * 180) / Math.PI,
|
||||
y: (rotation[1] * 180) / Math.PI,
|
||||
|
@ -215,27 +229,32 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit
|
|||
};
|
||||
|
||||
return (
|
||||
<Html position={[position[0], position[1], position[2]]}
|
||||
<Html
|
||||
position={[position[0], position[1], position[2]]}
|
||||
scale={[0.5, 0.5, 0.5]}
|
||||
transform
|
||||
zIndexRange={[1, 0]}
|
||||
sprite
|
||||
style={{
|
||||
transform: transformStyle.transform,
|
||||
transformStyle: 'preserve-3d',
|
||||
transition: 'transform 0.1s ease-out'
|
||||
|
||||
transformStyle: "preserve-3d",
|
||||
transition: "transform 0.1s ease-out",
|
||||
}}
|
||||
className={`${selectedChartId?.id === id ? "activeChart" : ""}`}
|
||||
>
|
||||
<div className="returnOfInvestment card"
|
||||
<div
|
||||
className={`returnOfInvestment card ${
|
||||
selectedChartId?.id === id ? "activeChart" : ""
|
||||
}`}
|
||||
onClick={() => setSelectedChartId({ id: id, type: type })}
|
||||
onContextMenu={onContextMenu}
|
||||
>
|
||||
<div className="header">Return of Investment</div>
|
||||
<div className="lineGraph charts">
|
||||
{/* Smooth curve graph with two datasets */}
|
||||
<SmoothLineGraphComponent data={Object.keys(measurements).length > 0 ? chartData : graphData} options={graphOptions} />
|
||||
<SmoothLineGraphComponent
|
||||
data={Object.keys(measurements).length > 0 ? chartData : graphData}
|
||||
options={graphOptions}
|
||||
/>
|
||||
</div>
|
||||
<div className="returns-wrapper">
|
||||
<div className="icon">
|
||||
|
|
|
@ -13,16 +13,26 @@ interface StateWorkingProps {
|
|||
rotation: [number, number, number];
|
||||
onContextMenu?: (event: React.MouseEvent) => void;
|
||||
}
|
||||
const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotation, onContextMenu }) => {
|
||||
const StateWorking: React.FC<StateWorkingProps> = ({
|
||||
id,
|
||||
type,
|
||||
position,
|
||||
rotation,
|
||||
onContextMenu,
|
||||
}) => {
|
||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||
const {
|
||||
measurements: chartMeasurements,
|
||||
duration: chartDuration,
|
||||
name: widgetName,
|
||||
} = useChartStore();
|
||||
const [measurements, setmeasurements] = useState<any>({});
|
||||
const [duration, setDuration] = useState("1h")
|
||||
const [name, setName] = useState("Widget")
|
||||
const [duration, setDuration] = useState("1h");
|
||||
const [name, setName] = useState("Widget");
|
||||
const [datas, setDatas] = useState<any>({});
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
// const datas = [
|
||||
// { key: "Oil Tank:", value: "24/341" },
|
||||
// { key: "Oil Refin:", value: 36.023 },
|
||||
|
@ -33,7 +43,8 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
|
|||
// ];
|
||||
|
||||
useEffect(() => {
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0)
|
||||
return;
|
||||
const socket = io(`http://${iotApiUrl}`);
|
||||
const inputData = {
|
||||
measurements,
|
||||
|
@ -47,7 +58,6 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
|
|||
socket.on("lastOutput", (response) => {
|
||||
const responseData = response;
|
||||
|
||||
|
||||
setDatas(responseData);
|
||||
});
|
||||
|
||||
|
@ -59,14 +69,15 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
|
|||
}, [measurements, duration, iotApiUrl]);
|
||||
|
||||
const fetchSavedInputes = async () => {
|
||||
|
||||
if (id !== "") {
|
||||
try {
|
||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setmeasurements(response.data.Data.measurements)
|
||||
setDuration(response.data.Data.duration)
|
||||
setName(response.data.widgetName)
|
||||
setmeasurements(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
|
@ -74,10 +85,7 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
|
|||
console.error("There was an error!", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchSavedInputes();
|
||||
|
@ -87,8 +95,7 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
|
|||
if (selectedChartId?.id === id) {
|
||||
fetchSavedInputes();
|
||||
}
|
||||
}
|
||||
, [chartMeasurements, chartDuration, widgetName])
|
||||
}, [chartMeasurements, chartDuration, widgetName]);
|
||||
|
||||
const rotationDegrees = {
|
||||
x: (rotation[0] * 180) / Math.PI,
|
||||
|
@ -100,20 +107,22 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
|
|||
transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`,
|
||||
};
|
||||
return (
|
||||
<Html position={[position[0], position[1], position[2]]}
|
||||
<Html
|
||||
position={[position[0], position[1], position[2]]}
|
||||
scale={[0.5, 0.5, 0.5]}
|
||||
transform
|
||||
zIndexRange={[1, 0]}
|
||||
sprite
|
||||
style={{
|
||||
transform: transformStyle.transform,
|
||||
transformStyle: 'preserve-3d',
|
||||
transition: 'transform 0.1s ease-out'
|
||||
|
||||
transformStyle: "preserve-3d",
|
||||
transition: "transform 0.1s ease-out",
|
||||
}}
|
||||
className={`${selectedChartId?.id === id ? "activeChart" : ""}`}
|
||||
>
|
||||
<div className="stateWorking-wrapper card"
|
||||
<div
|
||||
className={`stateWorking-wrapper card ${
|
||||
selectedChartId?.id === id ? "activeChart" : ""
|
||||
}`}
|
||||
onClick={() => setSelectedChartId({ id: id, type: type })}
|
||||
onContextMenu={onContextMenu}
|
||||
>
|
||||
|
@ -121,12 +130,10 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
|
|||
<div className="header">
|
||||
<span>State</span>
|
||||
<span>
|
||||
{datas?.input1 ? datas.input1 : 'input1'} <span>.</span>
|
||||
{datas?.input1 ? datas.input1 : "input1"} <span>.</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="img">
|
||||
{/* <img src={image} alt="" /> */}
|
||||
</div>
|
||||
<div className="img">{/* <img src={image} alt="" /> */}</div>
|
||||
</div>
|
||||
{/* Data */}
|
||||
<div className="data-wrapper">
|
||||
|
@ -137,28 +144,52 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
|
|||
</div>
|
||||
))} */}
|
||||
<div className="data-table">
|
||||
<div className="data">{measurements?.input2?.fields ? measurements.input2.fields : 'input2'}</div>
|
||||
<div className="key">{datas?.input2 ? datas.input2 : 'data'}</div>
|
||||
<div className="data">
|
||||
{measurements?.input2?.fields
|
||||
? measurements.input2.fields
|
||||
: "input2"}
|
||||
</div>
|
||||
<div className="key">{datas?.input2 ? datas.input2 : "data"}</div>
|
||||
</div>
|
||||
<div className="data-table">
|
||||
<div className="data">{measurements?.input3?.fields ? measurements.input3.fields : 'input3'}</div>
|
||||
<div className="key">{datas?.input3 ? datas.input3 : 'data'}</div>
|
||||
<div className="data">
|
||||
{measurements?.input3?.fields
|
||||
? measurements.input3.fields
|
||||
: "input3"}
|
||||
</div>
|
||||
<div className="key">{datas?.input3 ? datas.input3 : "data"}</div>
|
||||
</div>
|
||||
<div className="data-table">
|
||||
<div className="data">{measurements?.input4?.fields ? measurements.input4.fields : 'input4'}</div>
|
||||
<div className="key">{datas?.input4 ? datas.input4 : 'data'}</div>
|
||||
<div className="data">
|
||||
{measurements?.input4?.fields
|
||||
? measurements.input4.fields
|
||||
: "input4"}
|
||||
</div>
|
||||
<div className="key">{datas?.input4 ? datas.input4 : "data"}</div>
|
||||
</div>
|
||||
<div className="data-table">
|
||||
<div className="data">{measurements?.input5?.fields ? measurements.input5.fields : 'input5'}</div>
|
||||
<div className="key">{datas?.input5 ? datas.input5 : 'data'}</div>
|
||||
<div className="data">
|
||||
{measurements?.input5?.fields
|
||||
? measurements.input5.fields
|
||||
: "input5"}
|
||||
</div>
|
||||
<div className="key">{datas?.input5 ? datas.input5 : "data"}</div>
|
||||
</div>
|
||||
<div className="data-table">
|
||||
<div className="data">{measurements?.input6?.fields ? measurements.input6.fields : 'input6'}</div>
|
||||
<div className="key">{datas?.input6 ? datas.input6 : 'data'}</div>
|
||||
<div className="data">
|
||||
{measurements?.input6?.fields
|
||||
? measurements.input6.fields
|
||||
: "input6"}
|
||||
</div>
|
||||
<div className="key">{datas?.input6 ? datas.input6 : "data"}</div>
|
||||
</div>
|
||||
<div className="data-table">
|
||||
<div className="data">{measurements?.input7?.fields ? measurements.input7.fields : 'input7'}</div>
|
||||
<div className="key">{datas?.input7 ? datas.input7 : 'data'}</div>
|
||||
<div className="data">
|
||||
{measurements?.input7?.fields
|
||||
? measurements.input7.fields
|
||||
: "input7"}
|
||||
</div>
|
||||
<div className="key">{datas?.input7 ? datas.input7 : "data"}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -167,5 +198,3 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
|
|||
};
|
||||
|
||||
export default StateWorking;
|
||||
|
||||
|
||||
|
|
|
@ -49,20 +49,32 @@ interface ThroughputProps {
|
|||
onContextMenu?: (event: React.MouseEvent) => void;
|
||||
}
|
||||
|
||||
const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, onContextMenu }) => {
|
||||
|
||||
const Throughput: React.FC<ThroughputProps> = ({
|
||||
id,
|
||||
type,
|
||||
position,
|
||||
rotation,
|
||||
onContextMenu,
|
||||
}) => {
|
||||
const { selectedChartId, setSelectedChartId } = useWidgetStore();
|
||||
const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
|
||||
const {
|
||||
measurements: chartMeasurements,
|
||||
duration: chartDuration,
|
||||
name: widgetName,
|
||||
} = useChartStore();
|
||||
const [measurements, setmeasurements] = useState<any>({});
|
||||
const [duration, setDuration] = useState("1h")
|
||||
const [name, setName] = useState("Widget")
|
||||
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
|
||||
const [duration, setDuration] = useState("1h");
|
||||
const [name, setName] = useState("Widget");
|
||||
const [chartData, setChartData] = useState<{
|
||||
labels: string[];
|
||||
datasets: any[];
|
||||
}>({
|
||||
labels: [],
|
||||
datasets: [],
|
||||
});
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
// Sample data for the line graph
|
||||
const graphData: ChartData<"line"> = {
|
||||
|
@ -112,7 +124,8 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, o
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0)
|
||||
return;
|
||||
|
||||
const socket = io(`http://${iotApiUrl}`);
|
||||
|
||||
|
@ -122,7 +135,6 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, o
|
|||
interval: 1000,
|
||||
};
|
||||
|
||||
|
||||
const startStream = () => {
|
||||
socket.emit("lineInput", inputData);
|
||||
};
|
||||
|
@ -157,14 +169,15 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, o
|
|||
}, [measurements, duration, iotApiUrl]);
|
||||
|
||||
const fetchSavedInputes = async () => {
|
||||
|
||||
if (id !== "") {
|
||||
try {
|
||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`);
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setmeasurements(response.data.Data.measurements)
|
||||
setDuration(response.data.Data.duration)
|
||||
setName(response.data.widgetName)
|
||||
setmeasurements(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
|
@ -172,7 +185,7 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, o
|
|||
console.error("There was an error!", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchSavedInputes();
|
||||
|
@ -182,8 +195,7 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, o
|
|||
if (selectedChartId?.id === id) {
|
||||
fetchSavedInputes();
|
||||
}
|
||||
}
|
||||
, [chartMeasurements, chartDuration, widgetName])
|
||||
}, [chartMeasurements, chartDuration, widgetName]);
|
||||
const rotationDegrees = {
|
||||
x: (rotation[0] * 180) / Math.PI,
|
||||
y: (rotation[1] * 180) / Math.PI,
|
||||
|
@ -195,20 +207,22 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, o
|
|||
};
|
||||
|
||||
return (
|
||||
<Html position={[position[0], position[1], position[2]]}
|
||||
<Html
|
||||
position={[position[0], position[1], position[2]]}
|
||||
scale={[0.5, 0.5, 0.5]}
|
||||
transform
|
||||
zIndexRange={[1, 0]}
|
||||
sprite
|
||||
style={{
|
||||
transform: transformStyle.transform,
|
||||
transformStyle: 'preserve-3d',
|
||||
transition: 'transform 0.1s ease-out'
|
||||
|
||||
transformStyle: "preserve-3d",
|
||||
transition: "transform 0.1s ease-out",
|
||||
}}
|
||||
className={`${selectedChartId?.id === id ? "activeChart" : ""}`}
|
||||
>
|
||||
<div className="throughput-wrapper"
|
||||
<div
|
||||
className={`throughput-wrapper card ${
|
||||
selectedChartId?.id === id ? "activeChart" : ""
|
||||
}`}
|
||||
onClick={() => setSelectedChartId({ id: id, type: type })}
|
||||
onContextMenu={onContextMenu}
|
||||
>
|
||||
|
@ -235,7 +249,10 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, o
|
|||
</div>
|
||||
<div className="line-graph">
|
||||
{/* Line graph using react-chartjs-2 */}
|
||||
<LineGraphComponent data={Object.keys(measurements).length > 0 ? chartData : graphData} options={graphOptions} />
|
||||
<LineGraphComponent
|
||||
data={Object.keys(measurements).length > 0 ? chartData : graphData}
|
||||
options={graphOptions}
|
||||
/>
|
||||
</div>
|
||||
<div className="footer">
|
||||
You made an extra <span className="value">$1256.13</span> this month
|
||||
|
|
|
@ -129,6 +129,7 @@ const Assets: React.FC = () => {
|
|||
} else {
|
||||
try {
|
||||
const res = await getCategoryAsset(asset);
|
||||
console.log('res: ', res);
|
||||
setCategoryAssets(res);
|
||||
setFiltereredAssets(res);
|
||||
} catch (error) {}
|
||||
|
@ -147,7 +148,7 @@ const Assets: React.FC = () => {
|
|||
<div className="assets-container">
|
||||
{categoryAssets &&
|
||||
categoryAssets?.map((asset: any, index: number) => (
|
||||
<div key={index} className="assets">
|
||||
<div key={index} className="assets" id={asset.filename}>
|
||||
<img
|
||||
src={asset?.thumbnail}
|
||||
alt={asset.filename}
|
||||
|
@ -171,6 +172,7 @@ const Assets: React.FC = () => {
|
|||
<div className="assets-wrapper">
|
||||
<div
|
||||
className="back-button"
|
||||
id="asset-backButtom"
|
||||
onClick={() => {
|
||||
setSelectedCategory(null);
|
||||
setCategoryAssets([]);
|
||||
|
@ -182,7 +184,7 @@ const Assets: React.FC = () => {
|
|||
<div className="assets-container">
|
||||
{categoryAssets &&
|
||||
categoryAssets?.map((asset: any, index: number) => (
|
||||
<div key={index} className="assets">
|
||||
<div key={index} className="assets" id={asset.filename}>
|
||||
<img
|
||||
src={asset?.thumbnail}
|
||||
alt={asset.filename}
|
||||
|
@ -190,7 +192,7 @@ const Assets: React.FC = () => {
|
|||
onPointerDown={() =>
|
||||
setSelectedItem({
|
||||
name: asset.filename,
|
||||
id: asset.modelfileID,
|
||||
id: asset.AssetID,
|
||||
})
|
||||
}
|
||||
/>
|
||||
|
@ -222,6 +224,7 @@ const Assets: React.FC = () => {
|
|||
<div
|
||||
key={index}
|
||||
className="category"
|
||||
id={category}
|
||||
onClick={() => fetchCategoryAssets(category)}
|
||||
>
|
||||
<img
|
||||
|
|
|
@ -4,6 +4,7 @@ import useTemplateStore from "../../../../store/useTemplateStore";
|
|||
import { useSelectedZoneStore } from "../../../../store/useZoneStore";
|
||||
import { getTemplateData } from "../../../../services/realTimeVisulization/zoneData/getTemplate";
|
||||
import { useSocketStore } from "../../../../store/store";
|
||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||
|
||||
const Templates = () => {
|
||||
const { templates, removeTemplate, setTemplates } = useTemplateStore();
|
||||
|
@ -34,7 +35,10 @@ const Templates = () => {
|
|||
templateID: id,
|
||||
};
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-template:deleteTemplate", deleteTemplate);
|
||||
visualizationSocket.emit(
|
||||
"v2:viz-template:deleteTemplate",
|
||||
deleteTemplate
|
||||
);
|
||||
}
|
||||
removeTemplate(id);
|
||||
} catch (error) {
|
||||
|
@ -65,11 +69,15 @@ const Templates = () => {
|
|||
widgets: template.widgets,
|
||||
});
|
||||
|
||||
useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId);
|
||||
useDroppedObjectsStore
|
||||
.getState()
|
||||
.setZone(selectedZone.zoneName, selectedZone.zoneId);
|
||||
|
||||
if (Array.isArray(template.floatingWidget)) {
|
||||
template.floatingWidget.forEach((val: any) => {
|
||||
useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val);
|
||||
useDroppedObjectsStore
|
||||
.getState()
|
||||
.addObject(selectedZone.zoneName, val);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -79,7 +87,7 @@ const Templates = () => {
|
|||
|
||||
return (
|
||||
<div className="template-list">
|
||||
{templates.map((template) => (
|
||||
{templates.map((template, index) => (
|
||||
<div key={template.id} className="template-item">
|
||||
{template?.snapshot && (
|
||||
<div className="template-image-container">
|
||||
|
@ -96,7 +104,8 @@ const Templates = () => {
|
|||
onClick={() => handleLoadTemplate(template)}
|
||||
className="template-name"
|
||||
>
|
||||
{template.name}
|
||||
{/* {`Template ${index + 1}`} */}
|
||||
<RenameInput value={`Template ${index + 1}`} />
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleDeleteTemplate(template.id)}
|
||||
|
|
|
@ -1,32 +1,128 @@
|
|||
import React, { useRef, useMemo, useCallback, useState } from "react";
|
||||
import { InfoIcon } from "../../../icons/ExportCommonIcons";
|
||||
import { InfoIcon, AddIcon, RemoveIcon, ResizeHeightIcon } from "../../../icons/ExportCommonIcons";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
import {
|
||||
useSelectedActionSphere,
|
||||
useSimulationStates,
|
||||
useSocketStore
|
||||
} from "../../../../store/store";
|
||||
import { useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store";
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import LabeledButton from "../../../ui/inputs/LabledButton";
|
||||
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
|
||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||
|
||||
interface ConnectedModel {
|
||||
modelUUID: string;
|
||||
modelName: string;
|
||||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
index?: number;
|
||||
}[];
|
||||
triggers?: {
|
||||
uuid: string;
|
||||
name: string;
|
||||
type: string;
|
||||
isUsed: boolean;
|
||||
}[];
|
||||
}
|
||||
|
||||
const ArmBotMechanics: React.FC = () => {
|
||||
const { selectedActionSphere } = useSelectedActionSphere();
|
||||
const { simulationStates, setSimulationStates } = useSimulationStates();
|
||||
const { socket } = useSocketStore();
|
||||
const [selectedTrigger, setSelectedTrigger] = useState<string | null>(null);
|
||||
const [selectedProcessIndex, setSelectedProcessIndex] = useState<number | null>(null);
|
||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const propertiesContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Get connected models for dropdowns
|
||||
const connectedModels = useMemo(() => {
|
||||
// Get connected models and their triggers
|
||||
const connectedModels = useMemo<ConnectedModel[]>(() => {
|
||||
if (!selectedActionSphere?.points?.uuid) return [];
|
||||
|
||||
const armBotPaths = simulationStates.filter(
|
||||
(path): path is Types.ArmBotEventsSchema => path.type === "ArmBot"
|
||||
);
|
||||
|
||||
const currentPoint = armBotPaths.find(
|
||||
(path) => path.points.uuid === selectedActionSphere.points.uuid
|
||||
)?.points;
|
||||
|
||||
if (!currentPoint?.connections?.targets) return [];
|
||||
|
||||
return currentPoint.connections.targets.reduce<ConnectedModel[]>((acc, target) => {
|
||||
const connectedModel = simulationStates.find(
|
||||
(model) => model.modeluuid === target.modelUUID
|
||||
);
|
||||
|
||||
if (!connectedModel) return acc;
|
||||
|
||||
let triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] = [];
|
||||
let points: { uuid: string; position: [number, number, number] }[] = [];
|
||||
|
||||
if (connectedModel.type === "Conveyor") {
|
||||
const conveyor = connectedModel as Types.ConveyorEventsSchema;
|
||||
|
||||
const connectedPointUUIDs = currentPoint?.connections?.targets
|
||||
.filter(t => t.modelUUID === connectedModel.modeluuid)
|
||||
.map(t => t.pointUUID) || [];
|
||||
|
||||
points = conveyor.points
|
||||
.map((point, idx) => ({
|
||||
uuid: point.uuid,
|
||||
position: point.position,
|
||||
index: idx
|
||||
}))
|
||||
.filter(point => connectedPointUUIDs.includes(point.uuid));
|
||||
|
||||
|
||||
triggers = conveyor.points.flatMap(p => p.triggers?.filter(t => t.isUsed) || []);
|
||||
}
|
||||
else if (connectedModel.type === "StaticMachine") {
|
||||
const staticMachine = connectedModel as Types.StaticMachineEventsSchema;
|
||||
|
||||
points = [{
|
||||
uuid: staticMachine.points.uuid,
|
||||
position: staticMachine.points.position
|
||||
}];
|
||||
|
||||
triggers = staticMachine.points.triggers ?
|
||||
[{
|
||||
uuid: staticMachine.points.triggers.uuid,
|
||||
name: staticMachine.points.triggers.name,
|
||||
type: staticMachine.points.triggers.type,
|
||||
isUsed: true // StaticMachine triggers are always considered used
|
||||
}] : [];
|
||||
}
|
||||
|
||||
if (!acc.some(m => m.modelUUID === connectedModel.modeluuid)) {
|
||||
acc.push({
|
||||
modelUUID: connectedModel.modeluuid,
|
||||
modelName: connectedModel.modelName,
|
||||
points,
|
||||
triggers
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
}, [selectedActionSphere, simulationStates]);
|
||||
|
||||
// Get triggers only from connected models
|
||||
// Get triggers from connected models
|
||||
const connectedTriggers = useMemo(() => {
|
||||
}, [connectedModels, simulationStates]);
|
||||
return connectedModels.flatMap(model =>
|
||||
(model.triggers || []).map(trigger => ({
|
||||
...trigger,
|
||||
displayName: `${model.modelName} - ${trigger.name}`,
|
||||
modelUUID: model.modelUUID
|
||||
}))
|
||||
);
|
||||
}, [connectedModels]);
|
||||
|
||||
// Get all points from connected models
|
||||
const connectedPoints = useMemo(() => {
|
||||
return connectedModels.flatMap(model =>
|
||||
model.points.map(point => ({
|
||||
...point,
|
||||
displayName: `${model.modelName} - Point${typeof point.index === 'number' ? ` ${point.index}` : ''}`,
|
||||
modelUUID: model.modelUUID
|
||||
}))
|
||||
);
|
||||
}, [connectedModels]);
|
||||
|
||||
|
||||
const { selectedPoint } = useMemo(() => {
|
||||
if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null };
|
||||
|
@ -45,77 +141,148 @@ const ArmBotMechanics: React.FC = () => {
|
|||
}, [selectedActionSphere, simulationStates]);
|
||||
|
||||
const updateBackend = async (updatedPath: Types.ArmBotEventsSchema | undefined) => {
|
||||
// if (!updatedPath) return;
|
||||
// const email = localStorage.getItem("email");
|
||||
// const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||
if (!updatedPath) return;
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||
|
||||
// const data = {
|
||||
// organization: organization,
|
||||
// modeluuid: updatedPath.modeluuid,
|
||||
// eventData: { type: "ArmBot", points: updatedPath.points }
|
||||
// }
|
||||
const data = {
|
||||
organization: organization,
|
||||
modeluuid: updatedPath.modeluuid,
|
||||
eventData: { type: "ArmBot", points: updatedPath.points }
|
||||
}
|
||||
console.log('data: ', data);
|
||||
|
||||
// socket.emit('v2:model-asset:updateEventData', data);
|
||||
socket.emit('v2:model-asset:updateEventData', data);
|
||||
}
|
||||
|
||||
// const handleActionUpdate = useCallback((updatedAction: Partial<Types.ArmBotEventsSchema['points']['actions']>) => {
|
||||
// if (!selectedActionSphere?.points?.uuid) return;
|
||||
const handleActionUpdate = useCallback((updatedAction: Partial<Types.ArmBotEventsSchema['points']['actions']>) => {
|
||||
if (!selectedActionSphere?.points?.uuid || !selectedPoint) return;
|
||||
|
||||
// const updatedPaths = simulationStates.map((path) => {
|
||||
// return path;
|
||||
// });
|
||||
const updatedPaths = simulationStates.map((path) => {
|
||||
if (path.type === "ArmBot" && path.points.uuid === selectedActionSphere.points.uuid) {
|
||||
return {
|
||||
...path,
|
||||
points: {
|
||||
...path.points,
|
||||
actions: {
|
||||
...path.points.actions,
|
||||
...updatedAction
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return path;
|
||||
});
|
||||
|
||||
// const updatedPath = updatedPaths.find(
|
||||
// (path): path is Types.ArmBotEventsSchema =>
|
||||
// path.type === "ArmBot" &&
|
||||
// path.points.uuid === selectedActionSphere.points.uuid
|
||||
// );
|
||||
// updateBackend(updatedPath);
|
||||
const updatedPath = updatedPaths.find(
|
||||
(path): path is Types.ArmBotEventsSchema =>
|
||||
path.type === "ArmBot" &&
|
||||
path.points.uuid === selectedActionSphere.points.uuid
|
||||
);
|
||||
updateBackend(updatedPath);
|
||||
|
||||
// setSimulationStates(updatedPaths);
|
||||
// }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]);
|
||||
setSimulationStates(updatedPaths);
|
||||
}, [selectedActionSphere?.points?.uuid, selectedPoint, simulationStates, setSimulationStates]);
|
||||
|
||||
// const handleSpeedChange = useCallback((speed: number) => {
|
||||
// handleActionUpdate({ speed });
|
||||
// }, [handleActionUpdate]);
|
||||
const handleSpeedChange = useCallback((speed: number) => {
|
||||
handleActionUpdate({ speed });
|
||||
}, [handleActionUpdate]);
|
||||
|
||||
// const handleProcessChange = useCallback((processes: Types.ArmBotEventsSchema['points']['actions']['processes']) => {
|
||||
// handleActionUpdate({ processes });
|
||||
// }, [handleActionUpdate]);
|
||||
const handleProcessChange = useCallback((processes: Types.ArmBotEventsSchema['points']['actions']['processes']) => {
|
||||
handleActionUpdate({ processes });
|
||||
}, [handleActionUpdate]);
|
||||
|
||||
// const handleTriggerSelect = useCallback((displayName: string) => {
|
||||
// const selected = connectedTriggers.find(t => t.displayName === displayName);
|
||||
// setSelectedTrigger(selected?.uuid || null);
|
||||
// }, [connectedTriggers]);
|
||||
const handleAddProcess = useCallback(() => {
|
||||
if (!selectedPoint) return;
|
||||
|
||||
// const handleStartPointSelect = useCallback((pointUUID: string) => {
|
||||
// if (!selectedTrigger || !selectedPoint) return;
|
||||
const newProcess: any = {
|
||||
triggerId: "",
|
||||
startPoint: "",
|
||||
endPoint: ""
|
||||
};
|
||||
|
||||
// const updatedProcesses = selectedPoint.actions.processes?.map(process =>
|
||||
// process.triggerId === selectedTrigger
|
||||
// ? { ...process, startPoint: pointUUID }
|
||||
// : process
|
||||
// ) || [];
|
||||
const updatedProcesses = selectedPoint.actions.processes ? [...selectedPoint.actions.processes, newProcess] : [newProcess];
|
||||
|
||||
// handleProcessChange(updatedProcesses);
|
||||
// }, [selectedTrigger, selectedPoint, handleProcessChange]);
|
||||
handleProcessChange(updatedProcesses);
|
||||
setSelectedProcessIndex(updatedProcesses.length - 1);
|
||||
}, [selectedPoint, handleProcessChange]);
|
||||
|
||||
// const handleEndPointSelect = useCallback((pointUUID: string) => {
|
||||
// if (!selectedTrigger || !selectedPoint) return;
|
||||
const handleDeleteProcess = useCallback((index: number) => {
|
||||
if (!selectedPoint?.actions.processes) return;
|
||||
|
||||
// const updatedProcesses = selectedPoint.actions.processes?.map(process =>
|
||||
// process.triggerId === selectedTrigger
|
||||
// ? { ...process, endPoint: pointUUID }
|
||||
// : process
|
||||
// ) || [];
|
||||
const updatedProcesses = [...selectedPoint.actions.processes];
|
||||
updatedProcesses.splice(index, 1);
|
||||
|
||||
// handleProcessChange(updatedProcesses);
|
||||
// }, [selectedTrigger, selectedPoint, handleProcessChange]);
|
||||
handleProcessChange(updatedProcesses);
|
||||
|
||||
// const getCurrentProcess = useCallback(() => {
|
||||
// if (!selectedTrigger || !selectedPoint) return null;
|
||||
// return selectedPoint.actions.processes?.find(p => p.triggerId === selectedTrigger);
|
||||
// }, [selectedTrigger, selectedPoint]);
|
||||
// Reset selection if deleting the currently selected process
|
||||
if (selectedProcessIndex === index) {
|
||||
setSelectedProcessIndex(null);
|
||||
} else if (selectedProcessIndex !== null && selectedProcessIndex > index) {
|
||||
// Adjust selection index if needed
|
||||
setSelectedProcessIndex(selectedProcessIndex - 1);
|
||||
}
|
||||
}, [selectedPoint, selectedProcessIndex, handleProcessChange]);
|
||||
|
||||
const handleTriggerSelect = useCallback((displayName: string, index: number) => {
|
||||
const selected = connectedTriggers.find(t => t.displayName === displayName);
|
||||
if (!selected || !selectedPoint?.actions.processes) return;
|
||||
|
||||
const oldProcess = selectedPoint.actions.processes[index];
|
||||
|
||||
const updatedProcesses = [...selectedPoint.actions.processes];
|
||||
|
||||
// Only reset start/end if new trigger invalidates them (your logic can expand this)
|
||||
updatedProcesses[index] = {
|
||||
...oldProcess,
|
||||
triggerId: selected.uuid,
|
||||
startPoint: oldProcess.startPoint || "", // preserve if exists
|
||||
endPoint: oldProcess.endPoint || "" // preserve if exists
|
||||
};
|
||||
|
||||
handleProcessChange(updatedProcesses);
|
||||
}, [connectedTriggers, selectedPoint, handleProcessChange]);
|
||||
|
||||
const handleStartPointSelect = useCallback((displayName: string, index: number) => {
|
||||
if (!selectedPoint?.actions.processes) return;
|
||||
|
||||
const point = connectedPoints.find(p => p.displayName === displayName);
|
||||
if (!point) return;
|
||||
|
||||
const updatedProcesses = [...selectedPoint.actions.processes];
|
||||
updatedProcesses[index] = {
|
||||
...updatedProcesses[index],
|
||||
startPoint: point.uuid
|
||||
};
|
||||
|
||||
handleProcessChange(updatedProcesses);
|
||||
}, [selectedPoint, connectedPoints, handleProcessChange]);
|
||||
|
||||
const handleEndPointSelect = useCallback((displayName: string, index: number) => {
|
||||
if (!selectedPoint?.actions.processes) return;
|
||||
|
||||
const point = connectedPoints.find(p => p.displayName === displayName);
|
||||
if (!point) return;
|
||||
|
||||
const updatedProcesses = [...selectedPoint.actions.processes];
|
||||
updatedProcesses[index] = {
|
||||
...updatedProcesses[index],
|
||||
endPoint: point.uuid
|
||||
};
|
||||
|
||||
handleProcessChange(updatedProcesses);
|
||||
}, [selectedPoint, connectedPoints, handleProcessChange]);
|
||||
|
||||
const getProcessByIndex = useCallback((index: number) => {
|
||||
if (!selectedPoint?.actions.processes || index >= selectedPoint.actions.processes.length) return null;
|
||||
return selectedPoint.actions.processes[index];
|
||||
}, [selectedPoint]);
|
||||
|
||||
const getFilteredTriggerOptions = (currentIndex: number) => {
|
||||
const usedTriggerUUIDs = selectedPoint?.actions.processes?.filter((_, i) => i !== currentIndex).map(p => p.triggerId).filter(Boolean) ?? [];
|
||||
|
||||
return connectedTriggers.filter(trigger => !usedTriggerUUIDs.includes(trigger.uuid)).map(trigger => trigger.displayName);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="machine-mechanics-container" key={selectedPoint?.uuid}>
|
||||
|
@ -124,10 +291,10 @@ const ArmBotMechanics: React.FC = () => {
|
|||
</div>
|
||||
|
||||
<div className="machine-mechanics-content-container">
|
||||
<div className="selected-properties-container" ref={propertiesContainerRef}>
|
||||
<div className="selected-properties-container">
|
||||
<div className="properties-header">ArmBot Properties</div>
|
||||
|
||||
{/* {selectedPoint && (
|
||||
{selectedPoint && (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
key={`speed-${selectedPoint.uuid}`}
|
||||
|
@ -136,36 +303,90 @@ const ArmBotMechanics: React.FC = () => {
|
|||
onChange={(value) => handleSpeedChange(parseInt(value))}
|
||||
/>
|
||||
|
||||
<div className="actions">
|
||||
<div className="header">
|
||||
<div className="header-value">Processes</div>
|
||||
<div className="add-button" onClick={handleAddProcess}>
|
||||
<AddIcon /> Add
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="lists-main-container"
|
||||
ref={actionsContainerRef}
|
||||
style={{ height: "120px" }}
|
||||
>
|
||||
<div className="list-container">
|
||||
{selectedPoint.actions.processes?.map((process, index) => (
|
||||
<div
|
||||
key={`process-${index}`}
|
||||
className={`list-item ${selectedProcessIndex === index ? "active" : ""}`}
|
||||
>
|
||||
<div
|
||||
className="value"
|
||||
onClick={() => setSelectedProcessIndex(index)}
|
||||
>
|
||||
Process {index + 1}
|
||||
</div>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleDeleteProcess(index)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className="resize-icon"
|
||||
id="action-resize"
|
||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
||||
>
|
||||
<ResizeHeightIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedProcessIndex !== null && (
|
||||
<div className="process-configuration">
|
||||
<LabledDropdown
|
||||
key={`trigger-select-${selectedPoint.uuid}`}
|
||||
key={`trigger-select-${selectedProcessIndex}`}
|
||||
label="Select Trigger"
|
||||
defaultOption={connectedTriggers.find(t => t.uuid === selectedTrigger)?.displayName || ''}
|
||||
onSelect={handleTriggerSelect}
|
||||
options={connectedTriggers.map(trigger => trigger.displayName)}
|
||||
defaultOption={
|
||||
connectedTriggers.find(t =>
|
||||
t.uuid === getProcessByIndex(selectedProcessIndex)?.triggerId
|
||||
)?.displayName || 'Select a trigger'
|
||||
}
|
||||
onSelect={(value) => handleTriggerSelect(value, selectedProcessIndex)}
|
||||
options={getFilteredTriggerOptions(selectedProcessIndex)}
|
||||
/>
|
||||
|
||||
{selectedTrigger && (
|
||||
<>
|
||||
<LabledDropdown
|
||||
key={`start-point-${selectedTrigger}`}
|
||||
key={`start-point-${selectedProcessIndex}`}
|
||||
label="Start Point"
|
||||
defaultOption={getCurrentProcess()?.startPoint || ''}
|
||||
onSelect={handleStartPointSelect}
|
||||
options={connectedModels.map((model, index) => `${model.modelName} [${index}]`)}
|
||||
defaultOption={
|
||||
connectedPoints.find(p =>
|
||||
p.uuid === getProcessByIndex(selectedProcessIndex)?.startPoint
|
||||
)?.displayName || 'Select start point'
|
||||
}
|
||||
onSelect={(value) => handleStartPointSelect(value, selectedProcessIndex)}
|
||||
options={connectedPoints.map(point => point.displayName)}
|
||||
/>
|
||||
|
||||
<LabledDropdown
|
||||
key={`end-point-${selectedTrigger}`}
|
||||
key={`end-point-${selectedProcessIndex}`}
|
||||
label="End Point"
|
||||
defaultOption={getCurrentProcess()?.endPoint || ''}
|
||||
onSelect={handleEndPointSelect}
|
||||
options={connectedModels.map((model, index) => `${model.modelName} [${index}]`)}
|
||||
defaultOption={
|
||||
connectedPoints.find(p =>
|
||||
p.uuid === getProcessByIndex(selectedProcessIndex)?.endPoint
|
||||
)?.displayName || 'Select end point'
|
||||
}
|
||||
onSelect={(value) => handleEndPointSelect(value, selectedProcessIndex)}
|
||||
options={connectedPoints.map(point => point.displayName)}
|
||||
/>
|
||||
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)} */}
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="footer">
|
||||
|
|
|
@ -647,7 +647,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
setSelectedItem({ type: "action", item: action })
|
||||
}
|
||||
>
|
||||
<input type="radio" name="action" id="action" defaultChecked={action.isUsed} />
|
||||
<input type="radio" name="action" id="action" checked={action.isUsed} readOnly />
|
||||
<RenameInput value={action.name} />
|
||||
</div>
|
||||
<div
|
||||
|
@ -696,7 +696,7 @@ const ConveyorMechanics: React.FC = () => {
|
|||
setSelectedItem({ type: "trigger", item: trigger })
|
||||
}
|
||||
>
|
||||
<input type="radio" name="trigger" id="trigger" defaultChecked={trigger.isUsed} />
|
||||
<input type="radio" name="trigger" id="trigger" checked={trigger.isUsed} readOnly />
|
||||
<RenameInput value={trigger.name} />
|
||||
</div>
|
||||
<div
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
|||
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||
import Vector3Input from "../customInput/Vector3Input";
|
||||
import { useSelectedZoneStore } from "../../../../store/useZoneStore";
|
||||
import { useEditPosition, usezonePosition, usezoneTarget } from "../../../../store/store";
|
||||
import { useEditPosition, usezonePosition, useZones, usezoneTarget } from "../../../../store/store";
|
||||
import { zoneCameraUpdate } from "../../../../services/realTimeVisulization/zoneData/zoneCameraUpdation";
|
||||
|
||||
const ZoneProperties: React.FC = () => {
|
||||
|
@ -10,6 +10,7 @@ const ZoneProperties: React.FC = () => {
|
|||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||
const { zonePosition, setZonePosition } = usezonePosition();
|
||||
const { zoneTarget, setZoneTarget } = usezoneTarget();
|
||||
const { zones, setZones } = useZones();
|
||||
|
||||
useEffect(() => {
|
||||
setZonePosition(selectedZone.zoneViewPortPosition)
|
||||
|
@ -31,11 +32,11 @@ const ZoneProperties: React.FC = () => {
|
|||
if (response.message === "updated successfully") {
|
||||
setEdit(false);
|
||||
} else {
|
||||
console.log("Not updated Camera Position and Target");
|
||||
console.log(response);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error in handleSetView:", error);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,17 +44,32 @@ const ZoneProperties: React.FC = () => {
|
|||
setEdit(!Edit); // This will toggle the `Edit` state correctly
|
||||
}
|
||||
|
||||
function handleZoneNameChange(newName: string) {
|
||||
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
||||
async function handleZoneNameChange(newName: string) {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const zonesdata = {
|
||||
zoneId: selectedZone.zoneId,
|
||||
zoneName: newName
|
||||
};
|
||||
// Call your API to update the zone
|
||||
let response = await zoneCameraUpdate(zonesdata, organization);
|
||||
console.log('response: ', response);
|
||||
if (response.message === "updated successfully") {
|
||||
setZones((prevZones: any[]) =>
|
||||
prevZones.map((zone) =>
|
||||
zone.zoneId === selectedZone.zoneId
|
||||
? { ...zone, zoneName: newName }
|
||||
: zone
|
||||
)
|
||||
);
|
||||
}else{
|
||||
console.log(response?.message);
|
||||
}
|
||||
}
|
||||
|
||||
function handleVectorChange(key: "zoneViewPortTarget" | "zoneViewPortPosition", newValue: [number, number, number]) {
|
||||
setSelectedZone((prev) => ({ ...prev, [key]: newValue }));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
}, [selectedZone]);
|
||||
|
||||
return (
|
||||
<div className="zone-properties-container">
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
import React, { useEffect } from "react";
|
||||
import React from "react";
|
||||
import {
|
||||
CleanPannel,
|
||||
EyeIcon,
|
||||
LockIcon,
|
||||
} from "../../icons/RealTimeVisulationIcons";
|
||||
import { panelData } from "../../../services/realTimeVisulization/zoneData/panel";
|
||||
import { AddIcon } from "../../icons/ExportCommonIcons";
|
||||
import { deletePanelApi } from "../../../services/realTimeVisulization/zoneData/deletePanel";
|
||||
import { useSocketStore } from "../../../store/store";
|
||||
import { clearPanel } from "../../../services/realTimeVisulization/zoneData/clearPanel";
|
||||
import { lockPanel } from "../../../services/realTimeVisulization/zoneData/lockPanel";
|
||||
|
||||
// Define the type for `Side`
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
// Define the type for HiddenPanels, where keys are zone IDs and values are arrays of hidden sides
|
||||
interface HiddenPanels {
|
||||
[zoneId: string]: Side[];
|
||||
}
|
||||
|
||||
// Define the type for the props passed to the Buttons component
|
||||
interface ButtonsProps {
|
||||
selectedZone: {
|
||||
|
@ -35,7 +40,6 @@ interface ButtonsProps {
|
|||
zoneName: string;
|
||||
activeSides: Side[];
|
||||
panelOrder: Side[];
|
||||
|
||||
lockedPanels: Side[];
|
||||
zoneId: string;
|
||||
zoneViewPortTarget: number[];
|
||||
|
@ -49,8 +53,8 @@ interface ButtonsProps {
|
|||
}[];
|
||||
}>
|
||||
>;
|
||||
hiddenPanels: Side[]; // Add this prop for hidden panels
|
||||
setHiddenPanels: React.Dispatch<React.SetStateAction<Side[]>>; // Add this prop for updating hidden panels
|
||||
hiddenPanels: HiddenPanels; // Updated prop type
|
||||
setHiddenPanels: React.Dispatch<React.SetStateAction<HiddenPanels>>; // Updated prop type
|
||||
}
|
||||
|
||||
const AddButtons: React.FC<ButtonsProps> = ({
|
||||
|
@ -61,11 +65,35 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
}) => {
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
|
||||
// Local state to track hidden panels
|
||||
// Function to toggle visibility of a panel
|
||||
const toggleVisibility = (side: Side) => {
|
||||
const isHidden = hiddenPanels[selectedZone.zoneId]?.includes(side) ?? false;
|
||||
|
||||
if (isHidden) {
|
||||
// If the panel is already hidden, remove it from the hiddenPanels array for this zone
|
||||
setHiddenPanels((prevHiddenPanels) => ({
|
||||
...prevHiddenPanels,
|
||||
[selectedZone.zoneId]: prevHiddenPanels[selectedZone.zoneId].filter(
|
||||
(panel) => panel !== side
|
||||
),
|
||||
}));
|
||||
} else {
|
||||
// If the panel is visible, add it to the hiddenPanels array for this zone
|
||||
setHiddenPanels((prevHiddenPanels) => ({
|
||||
...prevHiddenPanels,
|
||||
[selectedZone.zoneId]: [
|
||||
...(prevHiddenPanels[selectedZone.zoneId] || []),
|
||||
side,
|
||||
],
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// Function to toggle lock/unlock a panel
|
||||
const toggleLockPanel = (side: Side) => {
|
||||
console.log('side: ', side);
|
||||
const toggleLockPanel = async (side: Side) => {
|
||||
// console.log('side: ', side);
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value
|
||||
//add api
|
||||
const newLockedPanels = selectedZone.lockedPanels.includes(side)
|
||||
? selectedZone.lockedPanels.filter((panel) => panel !== side)
|
||||
|
@ -76,36 +104,65 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
lockedPanels: newLockedPanels,
|
||||
};
|
||||
|
||||
// Update the selectedZone state
|
||||
setSelectedZone(updatedZone);
|
||||
let lockedPanel = {
|
||||
organization: organization,
|
||||
lockedPanel: newLockedPanels,
|
||||
zoneId: selectedZone.zoneId,
|
||||
};
|
||||
|
||||
// Function to toggle visibility of a panel
|
||||
const toggleVisibility = (side: Side) => {
|
||||
const isHidden = hiddenPanels.includes(side);
|
||||
if (isHidden) {
|
||||
// If the panel is already hidden, remove it from the hiddenPanels array
|
||||
setHiddenPanels(hiddenPanels.filter((panel) => panel !== side));
|
||||
} else {
|
||||
// If the panel is visible, add it to the hiddenPanels array
|
||||
setHiddenPanels([...hiddenPanels, side]);
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-panel:locked", lockedPanel);
|
||||
}
|
||||
|
||||
setSelectedZone(updatedZone);
|
||||
// let response = await lockPanel(selectedZone.zoneId, organization, newLockedPanels)
|
||||
// console.log('response: ', response);
|
||||
// if (response.message === 'locked panel updated successfully') {
|
||||
// // Update the selectedZone state
|
||||
// setSelectedZone(updatedZone);
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
// Function to clean all widgets from a panel
|
||||
const cleanPanel = (side: Side) => {
|
||||
const cleanPanel = async (side: Side) => {
|
||||
//add api
|
||||
console.log('side: ', side);
|
||||
// console.log('side: ', side);
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value
|
||||
|
||||
let clearPanel = {
|
||||
organization: organization,
|
||||
panelName: side,
|
||||
zoneId: selectedZone.zoneId,
|
||||
};
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-panel:clear", clearPanel);
|
||||
}
|
||||
const cleanedWidgets = selectedZone.widgets.filter(
|
||||
(widget) => widget.panel !== side
|
||||
);
|
||||
|
||||
const updatedZone = {
|
||||
...selectedZone,
|
||||
widgets: cleanedWidgets,
|
||||
};
|
||||
// Update the selectedZone state
|
||||
// console.log('updatedZone: ', updatedZone);
|
||||
setSelectedZone(updatedZone);
|
||||
|
||||
// let response = await clearPanel(selectedZone.zoneId, organization, side)
|
||||
// console.log('response: ', response);
|
||||
// if (response.message === 'PanelWidgets cleared successfully') {
|
||||
|
||||
// const cleanedWidgets = selectedZone.widgets.filter(
|
||||
// (widget) => widget.panel !== side
|
||||
// );
|
||||
// const updatedZone = {
|
||||
// ...selectedZone,
|
||||
// widgets: cleanedWidgets,
|
||||
// };
|
||||
// // Update the selectedZone state
|
||||
// setSelectedZone(updatedZone);
|
||||
// }
|
||||
};
|
||||
|
||||
// Function to handle "+" button click
|
||||
|
@ -150,8 +207,6 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
//
|
||||
// }
|
||||
} else {
|
||||
setHiddenPanels(hiddenPanels.filter((panel) => panel !== side));
|
||||
|
||||
// Panel does not exist: Create panel
|
||||
try {
|
||||
// Get email and organization safely with a default fallback
|
||||
|
@ -185,10 +240,9 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
// } else {
|
||||
//
|
||||
// }
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
|
@ -196,8 +250,7 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
<div key={side} className={`side-button-container ${side}`}>
|
||||
{/* "+" Button */}
|
||||
<button
|
||||
className={`side-button ${side}${
|
||||
selectedZone.activeSides.includes(side) ? " active" : ""
|
||||
className={`side-button ${side}${selectedZone.activeSides.includes(side) ? " active" : ""
|
||||
}`}
|
||||
onClick={() => handlePlusButtonClick(side)}
|
||||
title={
|
||||
|
@ -217,16 +270,20 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
{/* Hide Panel */}
|
||||
<div
|
||||
className={`icon ${
|
||||
hiddenPanels.includes(side) ? "active" : ""
|
||||
hiddenPanels[selectedZone.zoneId]?.includes(side)
|
||||
? "active"
|
||||
: ""
|
||||
}`}
|
||||
title={
|
||||
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
|
||||
hiddenPanels[selectedZone.zoneId]?.includes(side)
|
||||
? "Show Panel"
|
||||
: "Hide Panel"
|
||||
}
|
||||
onClick={() => toggleVisibility(side)}
|
||||
>
|
||||
<EyeIcon
|
||||
fill={
|
||||
hiddenPanels.includes(side)
|
||||
hiddenPanels[selectedZone.zoneId]?.includes(side)
|
||||
? "var(--primary-color)"
|
||||
: "var(--text-color)"
|
||||
}
|
||||
|
@ -244,8 +301,7 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
|
||||
{/* Lock/Unlock Panel */}
|
||||
<div
|
||||
className={`icon ${
|
||||
selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
selectedZone.lockedPanels.includes(side)
|
||||
|
|
|
@ -157,6 +157,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
let response = await getSelect2dZoneData(zoneId, organization);
|
||||
|
||||
|
||||
let res = await getFloatingZoneData(zoneId, organization);
|
||||
|
||||
setFloatingWidget(res);
|
||||
|
|
|
@ -88,12 +88,15 @@ export const DraggableWidget = ({
|
|||
|
||||
const chartWidget = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isPanelHidden = hiddenPanels.includes(widget.panel);
|
||||
|
||||
// OuterClick({
|
||||
// contextClassName: ["chart-container", "floating", "sidebar-right-wrapper"],
|
||||
// setMenuVisible: () => setSelectedChartId(null),
|
||||
// });
|
||||
OuterClick({
|
||||
contextClassName: [
|
||||
"chart-container",
|
||||
"floating",
|
||||
"sidebar-right-wrapper",
|
||||
"card",
|
||||
],
|
||||
setMenuVisible: () => setSelectedChartId(null),
|
||||
});
|
||||
|
||||
const deleteSelectedChart = async () => {
|
||||
try {
|
||||
|
@ -397,4 +400,4 @@ export const DraggableWidget = ({
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
// by using canvasDimensions.height canvasDimensions.width dynamically div value insted of static 6 and 4 calculate according to canvasDimensions.width canvasDimensions.height
|
||||
|
|
|
@ -143,7 +143,7 @@ const DroppedObjects: React.FC = () => {
|
|||
// if (res.message === "FloatingWidget deleted successfully") {
|
||||
// deleteObject(zoneName, id, index); // Call the deleteObject method from the store
|
||||
// }
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
||||
|
@ -510,7 +510,6 @@ const DroppedObjects: React.FC = () => {
|
|||
|
||||
const widthMultiplier = parseFloat(containerWidth) * 0.13;
|
||||
|
||||
console.log("zone.objects: ", zone.objects);
|
||||
return (
|
||||
<div
|
||||
onPointerMove={handlePointerMove}
|
||||
|
@ -520,8 +519,7 @@ const DroppedObjects: React.FC = () => {
|
|||
{zone.objects.map((obj, index) => {
|
||||
const topPosition =
|
||||
typeof obj.position.top === "number"
|
||||
? `calc(${obj.position.top}px + ${
|
||||
isPlaying && selectedZone.activeSides.includes("top")
|
||||
? `calc(${obj.position.top}px + ${isPlaying && selectedZone.activeSides.includes("top")
|
||||
? `${heightMultiplier - 55}px`
|
||||
: "0px"
|
||||
})`
|
||||
|
@ -529,8 +527,7 @@ const DroppedObjects: React.FC = () => {
|
|||
|
||||
const leftPosition =
|
||||
typeof obj.position.left === "number"
|
||||
? `calc(${obj.position.left}px + ${
|
||||
isPlaying && selectedZone.activeSides.includes("left")
|
||||
? `calc(${obj.position.left}px + ${isPlaying && selectedZone.activeSides.includes("left")
|
||||
? `${widthMultiplier - 100}px`
|
||||
: "0px"
|
||||
})`
|
||||
|
@ -538,8 +535,7 @@ const DroppedObjects: React.FC = () => {
|
|||
|
||||
const rightPosition =
|
||||
typeof obj.position.right === "number"
|
||||
? `calc(${obj.position.right}px + ${
|
||||
isPlaying && selectedZone.activeSides.includes("right")
|
||||
? `calc(${obj.position.right}px + ${isPlaying && selectedZone.activeSides.includes("right")
|
||||
? `${widthMultiplier - 100}px`
|
||||
: "0px"
|
||||
})`
|
||||
|
@ -547,8 +543,7 @@ const DroppedObjects: React.FC = () => {
|
|||
|
||||
const bottomPosition =
|
||||
typeof obj.position.bottom === "number"
|
||||
? `calc(${obj.position.bottom}px + ${
|
||||
isPlaying && selectedZone.activeSides.includes("bottom")
|
||||
? `calc(${obj.position.bottom}px + ${isPlaying && selectedZone.activeSides.includes("bottom")
|
||||
? `${heightMultiplier - 55}px`
|
||||
: "0px"
|
||||
})`
|
||||
|
@ -557,8 +552,7 @@ const DroppedObjects: React.FC = () => {
|
|||
return (
|
||||
<div
|
||||
key={`${zoneName}-${index}`}
|
||||
className={`${obj.className} ${
|
||||
selectedChartId?.id === obj.id && "activeChart"
|
||||
className={`${obj.className} ${selectedChartId?.id === obj.id && "activeChart"
|
||||
}`}
|
||||
ref={chartWidget}
|
||||
style={{
|
||||
|
|
|
@ -39,7 +39,7 @@ interface PanelProps {
|
|||
widgets: Widget[];
|
||||
}>
|
||||
>;
|
||||
hiddenPanels: string[];
|
||||
hiddenPanels: any;
|
||||
setZonesData: React.Dispatch<React.SetStateAction<any>>;
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,12 @@ const Panel: React.FC<PanelProps> = ({
|
|||
const handleDrop = (e: React.DragEvent, panel: Side) => {
|
||||
e.preventDefault();
|
||||
const { draggedAsset } = useWidgetStore.getState();
|
||||
if (!draggedAsset || isPanelLocked(panel)) return;
|
||||
if (
|
||||
!draggedAsset ||
|
||||
isPanelLocked(panel) ||
|
||||
hiddenPanels[selectedZone.zoneId]?.includes(panel)
|
||||
)
|
||||
return;
|
||||
|
||||
const currentWidgetsCount = getCurrentWidgetCount(panel);
|
||||
const maxCapacity = calculatePanelCapacity(panel);
|
||||
|
@ -261,7 +266,7 @@ const Panel: React.FC<PanelProps> = ({
|
|||
{`
|
||||
:root {
|
||||
--topWidth: ${topWidth};
|
||||
--bottomWidth: ${bottomWidth};
|
||||
--bottomWidth: ${bottomWidth} ;
|
||||
--leftHeight: ${leftHeight};
|
||||
--rightHeight: ${rightHeight};
|
||||
|
||||
|
@ -278,7 +283,7 @@ const Panel: React.FC<PanelProps> = ({
|
|||
key={side}
|
||||
id="panel-wrapper"
|
||||
className={`panel ${side}-panel absolute ${
|
||||
hiddenPanels.includes(side) ? "hidePanel" : ""
|
||||
hiddenPanels[selectedZone.zoneId]?.includes(side) ? "hidePanel" : ""
|
||||
}`}
|
||||
style={getPanelStyle(side)}
|
||||
onDrop={(e) => handleDrop(e, side)}
|
||||
|
@ -294,7 +299,9 @@ const Panel: React.FC<PanelProps> = ({
|
|||
<div
|
||||
className={`panel-content ${isPlaying && "fullScreen"}`}
|
||||
style={{
|
||||
pointerEvents: selectedZone.lockedPanels.includes(side)
|
||||
pointerEvents:
|
||||
selectedZone.lockedPanels.includes(side) ||
|
||||
hiddenPanels[selectedZone.zoneId]?.includes(side)
|
||||
? "none"
|
||||
: "auto",
|
||||
opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
|
||||
|
|
|
@ -7,7 +7,7 @@ import DisplayZone from "./DisplayZone";
|
|||
import Scene from "../../../modules/scene/scene";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
|
||||
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
||||
import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore";
|
||||
import {
|
||||
useAsset3dWidget,
|
||||
useSocketStore,
|
||||
|
@ -53,8 +53,13 @@ type Widget = {
|
|||
data: any;
|
||||
};
|
||||
|
||||
// Define the type for HiddenPanels, where keys are zone IDs and values are arrays of hidden sides
|
||||
interface HiddenPanels {
|
||||
[zoneId: string]: Side[];
|
||||
}
|
||||
|
||||
const RealTimeVisulization: React.FC = () => {
|
||||
const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]);
|
||||
const [hiddenPanels, setHiddenPanels] = React.useState<HiddenPanels>({});
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
|
@ -68,12 +73,12 @@ const RealTimeVisulization: React.FC = () => {
|
|||
const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
|
||||
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
|
||||
|
||||
const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({});
|
||||
// const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({});
|
||||
const { floatingWidget, setFloatingWidget } = useFloatingWidget()
|
||||
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
async function GetZoneData() {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
|
@ -100,7 +105,7 @@ const RealTimeVisulization: React.FC = () => {
|
|||
{}
|
||||
);
|
||||
setZonesData(formattedData);
|
||||
} catch (error) { }
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
GetZoneData();
|
||||
|
@ -129,7 +134,6 @@ const RealTimeVisulization: React.FC = () => {
|
|||
|
||||
const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
try {
|
||||
event.preventDefault();
|
||||
const email = localStorage.getItem("email") || "";
|
||||
|
@ -175,6 +179,25 @@ const RealTimeVisulization: React.FC = () => {
|
|||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
|
||||
}
|
||||
useDroppedObjectsStore
|
||||
.getState()
|
||||
.addObject(selectedZone.zoneName, newObject);
|
||||
|
||||
//I need to console here objects based on selectedZone.zoneId
|
||||
// Console the objects after adding
|
||||
const droppedObjectsStore = useDroppedObjectsStore.getState();
|
||||
const currentZone = droppedObjectsStore.zones[selectedZone.zoneName];
|
||||
|
||||
if (currentZone && currentZone.zoneId === selectedZone.zoneId) {
|
||||
console.log(
|
||||
`Objects for Zone ID: ${selectedZone.zoneId}`,
|
||||
currentZone.objects
|
||||
);
|
||||
setFloatingWidget(currentZone.objects)
|
||||
} else {
|
||||
console.warn("Zone not found or mismatched zoneId");
|
||||
}
|
||||
|
||||
// let response = await addingFloatingWidgets(
|
||||
// selectedZone.zoneId,
|
||||
// organization,
|
||||
|
@ -182,23 +205,10 @@ const RealTimeVisulization: React.FC = () => {
|
|||
// );
|
||||
// Add the dropped object to the zone if the API call is successful
|
||||
// if (response.message === "FloatWidget created successfully") {
|
||||
useDroppedObjectsStore
|
||||
.getState()
|
||||
.addObject(selectedZone.zoneName, newObject);
|
||||
// }
|
||||
|
||||
// Update floating widgets state
|
||||
setFloatingWidgets((prevWidgets) => ({
|
||||
...prevWidgets,
|
||||
[selectedZone.zoneName]: {
|
||||
...prevWidgets[selectedZone.zoneName],
|
||||
zoneName: selectedZone.zoneName,
|
||||
zoneId: selectedZone.zoneId,
|
||||
objects: [
|
||||
...(prevWidgets[selectedZone.zoneName]?.objects || []),
|
||||
newObject,
|
||||
],
|
||||
},
|
||||
}));
|
||||
|
||||
} catch (error) { }
|
||||
|
||||
};
|
||||
|
@ -223,8 +233,6 @@ const RealTimeVisulization: React.FC = () => {
|
|||
};
|
||||
}, [setRightClickSelected]);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
|
@ -257,7 +265,6 @@ const RealTimeVisulization: React.FC = () => {
|
|||
}}
|
||||
onDrop={(event) => handleDrop(event)}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
|
||||
>
|
||||
<Scene />
|
||||
</div>
|
||||
|
|
|
@ -12,8 +12,7 @@ export default function ZoneAssets() {
|
|||
if (!zoneAssetId) return
|
||||
console.log('zoneAssetId: ', zoneAssetId);
|
||||
let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id);
|
||||
if (!AssetMesh) return;
|
||||
|
||||
if (AssetMesh) {
|
||||
const bbox = new THREE.Box3().setFromObject(AssetMesh);
|
||||
const size = bbox.getSize(new THREE.Vector3());
|
||||
const center = bbox.getCenter(new THREE.Vector3());
|
||||
|
@ -30,7 +29,49 @@ export default function ZoneAssets() {
|
|||
controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, });
|
||||
|
||||
setSelectedFloorItem(AssetMesh);
|
||||
} else {
|
||||
console.log('zoneAssetId: ', zoneAssetId)
|
||||
if (Array.isArray(zoneAssetId.position) && zoneAssetId.position.length >= 3) {
|
||||
let selectedAssetPosition = [
|
||||
zoneAssetId.position[0],
|
||||
10,
|
||||
zoneAssetId.position[2]
|
||||
];
|
||||
console.log('selectedAssetPosition: ', selectedAssetPosition);
|
||||
let selectedAssetTarget = [
|
||||
zoneAssetId.position[0],
|
||||
zoneAssetId.position[1],
|
||||
zoneAssetId.position[2]
|
||||
];
|
||||
console.log('selectedAssetTarget: ', selectedAssetTarget);
|
||||
const setCam = async () => {
|
||||
await controls?.setLookAt(...selectedAssetPosition, ...selectedAssetTarget, true);
|
||||
setTimeout(() => {
|
||||
let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id);
|
||||
if (AssetMesh) {
|
||||
const bbox = new THREE.Box3().setFromObject(AssetMesh);
|
||||
const size = bbox.getSize(new THREE.Vector3());
|
||||
const center = bbox.getCenter(new THREE.Vector3());
|
||||
|
||||
const front = new THREE.Vector3(0, 0, 1);
|
||||
AssetMesh.localToWorld(front);
|
||||
front.sub(AssetMesh.position).normalize();
|
||||
|
||||
const distance = Math.max(size.x, size.y, size.z) * 2;
|
||||
const newPosition = center.clone().addScaledVector(front, distance);
|
||||
|
||||
controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true);
|
||||
controls.setTarget(center.x, center.y, center.z, true);
|
||||
controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, });
|
||||
|
||||
setSelectedFloorItem(AssetMesh);
|
||||
}
|
||||
}, 500)
|
||||
|
||||
};
|
||||
setCam();
|
||||
}
|
||||
}
|
||||
}, [zoneAssetId, scene, controls])
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons";
|
|||
import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect";
|
||||
import { useFloorItems, useZones } from "../../../store/store";
|
||||
import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
||||
import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/getZoneData";
|
||||
|
||||
interface DropDownListProps {
|
||||
value?: string; // Value to display in the DropDownList
|
||||
|
@ -52,10 +53,10 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
|||
interface ZoneData {
|
||||
id: string;
|
||||
name: string;
|
||||
assets: { id: string; name: string; position?: [] ;rotation?:{}}[];
|
||||
assets: { id: string; name: string; position?: []; rotation?: {} }[];
|
||||
}
|
||||
const [zoneDataList, setZoneDataList] = useState<ZoneData[]>([]);
|
||||
const { floorItems, setFloorItems } = useFloorItems();
|
||||
const { floorItems } = useFloorItems();
|
||||
|
||||
const isPointInsidePolygon = (point: [number, number], polygon: [number, number][]) => {
|
||||
let inside = false;
|
||||
|
@ -70,9 +71,9 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
|||
}
|
||||
return inside;
|
||||
};
|
||||
useEffect(() => {
|
||||
|
||||
const updatedZoneList: ZoneData[] = zones.map((zone: Zone) => {
|
||||
useEffect(() => {
|
||||
const updatedZoneList: ZoneData[] = zones?.map((zone: Zone) => {
|
||||
const polygon2D = zone.points.map((p: [number, number, number]) => [p[0], p[2]]) as [number, number][];
|
||||
|
||||
const assetsInZone = floorItems
|
||||
|
@ -84,7 +85,7 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
|||
id: item.modeluuid,
|
||||
name: item.modelname,
|
||||
position: item.position,
|
||||
rotation:item.rotation
|
||||
rotation: item.rotation
|
||||
}));
|
||||
|
||||
return {
|
||||
|
@ -96,9 +97,6 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
|||
setZoneDataList(updatedZoneList);
|
||||
}, [zones, floorItems]);
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="dropdown-list-container">
|
||||
<div className="head">
|
||||
|
|
|
@ -13,7 +13,9 @@ import {
|
|||
RmoveIcon,
|
||||
} from "../../icons/ExportCommonIcons";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import { useZoneAssetId } from "../../../store/store";
|
||||
import { useFloorItems, useZoneAssetId } from "../../../store/store";
|
||||
import { zoneCameraUpdate } from "../../../services/realTimeVisulization/zoneData/zoneCameraUpdation";
|
||||
import { setFloorItemApi } from "../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||
|
||||
interface Asset {
|
||||
id: string;
|
||||
|
@ -38,11 +40,12 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||
const { activeModule, setActiveModule } = useModuleStore();
|
||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
|
||||
|
||||
const { setSubModule } = useSubModuleStore();
|
||||
const [expandedZones, setExpandedZones] = useState<Record<string, boolean>>(
|
||||
{}
|
||||
);
|
||||
|
||||
const { floorItems, setFloorItems } = useFloorItems();
|
||||
|
||||
useEffect(() => {
|
||||
useSelectedZoneStore.getState().setSelectedZone({
|
||||
|
@ -67,7 +70,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||
async function handleSelectZone(id: string) {
|
||||
try {
|
||||
if (selectedZone?.zoneId === id) {
|
||||
console.log("Zone is already selected:", selectedZone.zoneName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -89,19 +92,52 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||
zoneViewPortPosition: response?.viewPortposition || [],
|
||||
});
|
||||
|
||||
console.log("Zone selected:", response?.zoneName);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error selecting zone:", error);
|
||||
|
||||
}
|
||||
}
|
||||
function handleAssetClick(asset: Asset) {
|
||||
setZoneAssetId(asset)
|
||||
}
|
||||
async function handleZoneNameChange(newName: string) {
|
||||
//zone apiiiiii
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
let zonesdata = {
|
||||
zoneId: selectedZone.zoneId,
|
||||
zoneName: newName
|
||||
};
|
||||
let response = await zoneCameraUpdate(zonesdata, organization);
|
||||
if (response.message === "updated successfully") {
|
||||
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
||||
}
|
||||
}
|
||||
async function handleZoneAssetName(newName: string) {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
if (zoneAssetId?.id) {
|
||||
let response = await setFloorItemApi(organization, zoneAssetId.id, newName)
|
||||
console.log('response: ', response);
|
||||
setFloorItems((prevFloorItems: any[]) =>
|
||||
prevFloorItems.map((floorItems) =>
|
||||
floorItems.modeluuid === zoneAssetId.id
|
||||
? { ...floorItems, modelname: response.modelname }
|
||||
: floorItems
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
console.log('newName: ', newName);
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{items.length > 0 ? (
|
||||
{items?.length > 0 ? (
|
||||
<ul className="list-wrapper">
|
||||
{items.map((item) => (
|
||||
{items?.map((item) => (
|
||||
<React.Fragment key={`zone-${item.id}`}>
|
||||
<li className="list-container">
|
||||
<div className="list-item">
|
||||
|
@ -110,7 +146,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||
className="value"
|
||||
onClick={() => handleSelectZone(item.id)}
|
||||
>
|
||||
<RenameInput value={item.name} />
|
||||
<RenameInput value={item.name} onRename={handleZoneNameChange} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="options-container">
|
||||
|
@ -147,8 +183,8 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||
className="list-container asset-item"
|
||||
>
|
||||
<div className="list-item">
|
||||
<div className="value" onClick={() => handleAssetClick(asset)}>
|
||||
<RenameInput value={asset.name} />
|
||||
<div className="value" onClick={() => handleAssetClick(asset)} >
|
||||
<RenameInput value={asset.name} onRename={handleZoneAssetName} />
|
||||
</div>
|
||||
<div className="options-container">
|
||||
<div className="lock option">
|
||||
|
|
|
@ -32,7 +32,7 @@ export default function NavMeshDetails({
|
|||
|
||||
const [positions, indices] = getPositionsAndIndices(meshes);
|
||||
|
||||
const cellSize = 0.35;
|
||||
const cellSize = 0.2;
|
||||
const cellHeight = 0.7;
|
||||
const walkableRadius = 0.5;
|
||||
const { success, navMesh } = generateSoloNavMesh(positions, indices, {
|
||||
|
|
|
@ -86,8 +86,8 @@ async function addAssetModel(
|
|||
} else {
|
||||
// console.log(`Added ${selectedItem.name} from Backend`);
|
||||
|
||||
loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => {
|
||||
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
||||
loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, async (gltf) => {
|
||||
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
||||
await storeGLTF(selectedItem.id, modelBlob);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket);
|
||||
|
@ -235,6 +235,7 @@ async function handleModelLoad(
|
|||
points: {
|
||||
uuid: pointUUID,
|
||||
position: res.points.position as [number, number, number],
|
||||
rotation: res.points.rotation as [number, number, number],
|
||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: '', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
||||
connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
|
||||
speed: 2,
|
||||
|
@ -297,6 +298,7 @@ async function handleModelLoad(
|
|||
points: {
|
||||
uuid: pointUUID,
|
||||
position: res.points.position as [number, number, number],
|
||||
rotation: res.points.rotation as [number, number, number],
|
||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', buffer: 0, material: 'Inherit' },
|
||||
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
|
||||
connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
|
||||
|
@ -360,6 +362,7 @@ async function handleModelLoad(
|
|||
points: {
|
||||
uuid: pointUUID,
|
||||
position: res.points.position as [number, number, number],
|
||||
rotation: res.points.rotation as [number, number, number],
|
||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', speed: 1, processes: [] },
|
||||
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
|
||||
connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] },
|
||||
|
|
|
@ -53,7 +53,7 @@ export default async function assetManager(
|
|||
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
|
||||
|
||||
await new Promise<void>(async (resolve) => {
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`;
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`;
|
||||
|
||||
// Check Three.js Cache
|
||||
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
||||
|
|
|
@ -2,12 +2,23 @@ import React, { useState, useEffect, useMemo, useRef } from "react";
|
|||
import { Line, Sphere } from "@react-three/drei";
|
||||
import { useThree, useFrame } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import { useActiveLayer, useDeleteTool, useDeletePointOrLine, useMovePoint, useSocketStore, useToggleView, useToolMode, useRemovedLayer, useZones, useZonePoints } from "../../../store/store";
|
||||
import {
|
||||
useActiveLayer,
|
||||
useDeleteTool,
|
||||
useDeletePointOrLine,
|
||||
useMovePoint,
|
||||
useSocketStore,
|
||||
useToggleView,
|
||||
useToolMode,
|
||||
useRemovedLayer,
|
||||
useZones,
|
||||
useZonePoints,
|
||||
} from "../../../store/store";
|
||||
// import { setZonesApi } from "../../../services/factoryBuilder/zones/setZonesApi";
|
||||
// import { deleteZonesApi } from "../../../services/factoryBuilder/zones/deleteZoneApi";
|
||||
import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi";
|
||||
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
|
||||
const ZoneGroup: React.FC = () => {
|
||||
const { camera, pointer, gl, raycaster, scene, controls } = useThree();
|
||||
|
@ -16,8 +27,13 @@ const ZoneGroup: React.FC = () => {
|
|||
const { zones, setZones } = useZones();
|
||||
const { zonePoints, setZonePoints } = useZonePoints();
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>(null);
|
||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||
const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>(
|
||||
null
|
||||
);
|
||||
const plane = useMemo(
|
||||
() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
|
||||
[]
|
||||
);
|
||||
const { toggleView } = useToggleView();
|
||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
||||
const { removedLayer, setRemovedLayer } = useRemovedLayer();
|
||||
|
@ -29,7 +45,9 @@ const ZoneGroup: React.FC = () => {
|
|||
|
||||
const groupsRef = useRef<any>();
|
||||
|
||||
const zoneMaterial = useMemo(() => new THREE.ShaderMaterial({
|
||||
const zoneMaterial = useMemo(
|
||||
() =>
|
||||
new THREE.ShaderMaterial({
|
||||
side: THREE.DoubleSide,
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
|
@ -55,7 +73,7 @@ const ZoneGroup: React.FC = () => {
|
|||
|
||||
useEffect(() => {
|
||||
const fetchZones = async () => {
|
||||
const email = localStorage.getItem('email');
|
||||
const email = localStorage.getItem("email");
|
||||
if (!email) return;
|
||||
|
||||
const organization = email.split("@")[1].split(".")[0];
|
||||
|
@ -68,13 +86,17 @@ const ZoneGroup: React.FC = () => {
|
|||
points: zone.points,
|
||||
viewPortCenter: zone.viewPortCenter,
|
||||
viewPortposition: zone.viewPortposition,
|
||||
layer: zone.layer
|
||||
layer: zone.layer,
|
||||
}));
|
||||
|
||||
setZones(fetchedZones);
|
||||
|
||||
const fetchedPoints = data.data.flatMap((zone: any) =>
|
||||
zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point))
|
||||
zone.points
|
||||
.slice(0, 4)
|
||||
.map(
|
||||
(point: [number, number, number]) => new THREE.Vector3(...point)
|
||||
)
|
||||
);
|
||||
|
||||
setZonePoints(fetchedPoints);
|
||||
|
@ -85,14 +107,14 @@ const ZoneGroup: React.FC = () => {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
localStorage.setItem('zones', JSON.stringify(zones));
|
||||
|
||||
}, [zones])
|
||||
localStorage.setItem("zones", JSON.stringify(zones));
|
||||
}, [zones]);
|
||||
|
||||
useEffect(() => {
|
||||
if (removedLayer) {
|
||||
const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer);
|
||||
const updatedZones = zones.filter(
|
||||
(zone: any) => zone.layer !== removedLayer
|
||||
);
|
||||
setZones(updatedZones);
|
||||
|
||||
const updatedzonePoints = zonePoints.filter((_: any, index: any) => {
|
||||
|
@ -101,7 +123,9 @@ const ZoneGroup: React.FC = () => {
|
|||
});
|
||||
setZonePoints(updatedzonePoints);
|
||||
|
||||
zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => {
|
||||
zones
|
||||
.filter((zone: any) => zone.layer === removedLayer)
|
||||
.forEach((zone: any) => {
|
||||
deleteZoneFromBackend(zone.zoneId);
|
||||
});
|
||||
|
||||
|
@ -124,17 +148,22 @@ const ZoneGroup: React.FC = () => {
|
|||
}
|
||||
}, [toolMode, toggleView]);
|
||||
|
||||
|
||||
const addZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => {
|
||||
|
||||
const email = localStorage.getItem('email');
|
||||
const userId = localStorage.getItem('userId');
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const addZoneToBackend = async (zone: {
|
||||
zoneId: string;
|
||||
zoneName: string;
|
||||
points: [number, number, number][];
|
||||
layer: string;
|
||||
}) => {
|
||||
const email = localStorage.getItem("email");
|
||||
const userId = localStorage.getItem("userId");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
const calculateCenter = (points: number[][]) => {
|
||||
if (!points || points.length === 0) return null;
|
||||
|
||||
let sumX = 0, sumY = 0, sumZ = 0;
|
||||
let sumX = 0,
|
||||
sumY = 0,
|
||||
sumZ = 0;
|
||||
const numPoints = points.length;
|
||||
|
||||
points.forEach(([x, y, z]) => {
|
||||
|
@ -143,10 +172,16 @@ const ZoneGroup: React.FC = () => {
|
|||
sumZ += z;
|
||||
});
|
||||
|
||||
return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number];
|
||||
return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
|
||||
number,
|
||||
number,
|
||||
number
|
||||
];
|
||||
};
|
||||
|
||||
const target: [number, number, number] | null = calculateCenter(zone.points);
|
||||
const target: [number, number, number] | null = calculateCenter(
|
||||
zone.points
|
||||
);
|
||||
if (!target) return;
|
||||
const position = [target[0], 10, target[2]];
|
||||
|
||||
|
@ -159,23 +194,29 @@ const ZoneGroup: React.FC = () => {
|
|||
points: zone.points,
|
||||
viewPortCenter: target,
|
||||
viewPortposition: position,
|
||||
layer: zone.layer
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('v2:zone:set', input);
|
||||
layer: zone.layer,
|
||||
},
|
||||
};
|
||||
|
||||
const updateZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => {
|
||||
socket.emit("v2:zone:set", input);
|
||||
};
|
||||
|
||||
const email = localStorage.getItem('email');
|
||||
const userId = localStorage.getItem('userId');
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const updateZoneToBackend = async (zone: {
|
||||
zoneId: string;
|
||||
zoneName: string;
|
||||
points: [number, number, number][];
|
||||
layer: string;
|
||||
}) => {
|
||||
const email = localStorage.getItem("email");
|
||||
const userId = localStorage.getItem("userId");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
const calculateCenter = (points: number[][]) => {
|
||||
if (!points || points.length === 0) return null;
|
||||
|
||||
let sumX = 0, sumY = 0, sumZ = 0;
|
||||
let sumX = 0,
|
||||
sumY = 0,
|
||||
sumZ = 0;
|
||||
const numPoints = points.length;
|
||||
|
||||
points.forEach(([x, y, z]) => {
|
||||
|
@ -184,10 +225,16 @@ const ZoneGroup: React.FC = () => {
|
|||
sumZ += z;
|
||||
});
|
||||
|
||||
return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number];
|
||||
return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [
|
||||
number,
|
||||
number,
|
||||
number
|
||||
];
|
||||
};
|
||||
|
||||
const target: [number, number, number] | null = calculateCenter(zone.points);
|
||||
const target: [number, number, number] | null = calculateCenter(
|
||||
zone.points
|
||||
);
|
||||
if (!target) return;
|
||||
const position = [target[0], 10, target[2]];
|
||||
|
||||
|
@ -200,27 +247,25 @@ const ZoneGroup: React.FC = () => {
|
|||
points: zone.points,
|
||||
viewPortCenter: target,
|
||||
viewPortposition: position,
|
||||
layer: zone.layer
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('v2:zone:set', input);
|
||||
layer: zone.layer,
|
||||
},
|
||||
};
|
||||
|
||||
socket.emit("v2:zone:set", input);
|
||||
};
|
||||
|
||||
const deleteZoneFromBackend = async (zoneId: string) => {
|
||||
|
||||
const email = localStorage.getItem('email');
|
||||
const userId = localStorage.getItem('userId');
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const email = localStorage.getItem("email");
|
||||
const userId = localStorage.getItem("userId");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
const input = {
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
zoneId: zoneId
|
||||
}
|
||||
zoneId: zoneId,
|
||||
};
|
||||
|
||||
socket.emit('v2:zone:delete', input);
|
||||
socket.emit("v2:zone:delete", input);
|
||||
};
|
||||
|
||||
const handleDeleteZone = (zoneId: string) => {
|
||||
|
@ -229,9 +274,17 @@ const ZoneGroup: React.FC = () => {
|
|||
|
||||
const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId);
|
||||
if (zoneIndex !== -1) {
|
||||
const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4);
|
||||
zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point));
|
||||
const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4);
|
||||
const zonePointsToRemove = zonePoints.slice(
|
||||
zoneIndex * 4,
|
||||
zoneIndex * 4 + 4
|
||||
);
|
||||
zonePointsToRemove.forEach((point: any) =>
|
||||
groupsRef.current.remove(point)
|
||||
);
|
||||
const updatedzonePoints = zonePoints.filter(
|
||||
(_: any, index: any) =>
|
||||
index < zoneIndex * 4 || index >= zoneIndex * 4 + 4
|
||||
);
|
||||
setZonePoints(updatedzonePoints);
|
||||
}
|
||||
|
||||
|
@ -251,11 +304,16 @@ const ZoneGroup: React.FC = () => {
|
|||
drag = false;
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
|
||||
const intersects = raycaster.intersectObjects(
|
||||
groupsRef.current.children,
|
||||
true
|
||||
);
|
||||
|
||||
if (intersects.length > 0 && movePoint) {
|
||||
const clickedObject = intersects[0].object;
|
||||
const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position));
|
||||
const sphereIndex = zonePoints.findIndex((point: any) =>
|
||||
point.equals(clickedObject.position)
|
||||
);
|
||||
if (sphereIndex !== -1) {
|
||||
(controls as any).enabled = false;
|
||||
setDraggedSphere(zonePoints[sphereIndex]);
|
||||
|
@ -297,7 +355,7 @@ const ZoneGroup: React.FC = () => {
|
|||
zoneId,
|
||||
zoneName,
|
||||
points: points,
|
||||
layer: activeLayer
|
||||
layer: activeLayer,
|
||||
};
|
||||
|
||||
const newZones = [...zones, newZone];
|
||||
|
@ -319,14 +377,24 @@ const ZoneGroup: React.FC = () => {
|
|||
setStartPoint(null);
|
||||
setEndPoint(null);
|
||||
}
|
||||
} else if (evt.button === 0 && !drag && !isDragging && deletePointOrLine) {
|
||||
} else if (
|
||||
evt.button === 0 &&
|
||||
!drag &&
|
||||
!isDragging &&
|
||||
deletePointOrLine
|
||||
) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
|
||||
const intersects = raycaster.intersectObjects(
|
||||
groupsRef.current.children,
|
||||
true
|
||||
);
|
||||
|
||||
if (intersects.length > 0) {
|
||||
const clickedObject = intersects[0].object;
|
||||
|
||||
const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position));
|
||||
const sphereIndex = zonePoints.findIndex((point: any) =>
|
||||
point.equals(clickedObject.position)
|
||||
);
|
||||
if (sphereIndex !== -1) {
|
||||
const zoneIndex = Math.floor(sphereIndex / 4);
|
||||
const zoneId = zones[zoneIndex].zoneId;
|
||||
|
@ -341,7 +409,9 @@ const ZoneGroup: React.FC = () => {
|
|||
setIsDragging(false);
|
||||
setDraggedSphere(null);
|
||||
|
||||
const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere);
|
||||
const sphereIndex = zonePoints.findIndex(
|
||||
(point: any) => point === draggedSphere
|
||||
);
|
||||
if (sphereIndex !== -1) {
|
||||
const zoneIndex = Math.floor(sphereIndex / 4);
|
||||
|
||||
|
@ -358,9 +428,15 @@ const ZoneGroup: React.FC = () => {
|
|||
drag = true;
|
||||
}
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
|
||||
const intersects = raycaster.intersectObjects(
|
||||
groupsRef.current.children,
|
||||
true
|
||||
);
|
||||
|
||||
if (intersects.length > 0 && intersects[0].object.name.includes('point')) {
|
||||
if (
|
||||
intersects.length > 0 &&
|
||||
intersects[0].object.name.includes("point")
|
||||
) {
|
||||
gl.domElement.style.cursor = movePoint ? "pointer" : "default";
|
||||
} else {
|
||||
gl.domElement.style.cursor = "default";
|
||||
|
@ -372,7 +448,9 @@ const ZoneGroup: React.FC = () => {
|
|||
if (point) {
|
||||
draggedSphere.set(point.x, 0.15, point.z);
|
||||
|
||||
const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere);
|
||||
const sphereIndex = zonePoints.findIndex(
|
||||
(point: any) => point === draggedSphere
|
||||
);
|
||||
if (sphereIndex !== -1) {
|
||||
const zoneIndex = Math.floor(sphereIndex / 4);
|
||||
const cornerIndex = sphereIndex % 4;
|
||||
|
@ -399,7 +477,7 @@ const ZoneGroup: React.FC = () => {
|
|||
setEndPoint(null);
|
||||
};
|
||||
|
||||
if (toolMode === 'Zone' || deletePointOrLine || movePoint) {
|
||||
if (toolMode === "Zone" || deletePointOrLine || movePoint) {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
|
@ -411,7 +489,21 @@ const ZoneGroup: React.FC = () => {
|
|||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("contextmenu", onContext);
|
||||
};
|
||||
}, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, deletePointOrLine, zonePoints, draggedSphere, movePoint, activeLayer]);
|
||||
}, [
|
||||
gl,
|
||||
camera,
|
||||
startPoint,
|
||||
toggleView,
|
||||
scene,
|
||||
toolMode,
|
||||
zones,
|
||||
isDragging,
|
||||
deletePointOrLine,
|
||||
zonePoints,
|
||||
draggedSphere,
|
||||
movePoint,
|
||||
activeLayer,
|
||||
]);
|
||||
|
||||
useFrame(() => {
|
||||
if (!startPoint) return;
|
||||
|
@ -423,23 +515,36 @@ const ZoneGroup: React.FC = () => {
|
|||
}
|
||||
});
|
||||
return (
|
||||
<group ref={groupsRef} name='zoneGroup' >
|
||||
<group ref={groupsRef} name="zoneGroup">
|
||||
<group name="zones" visible={!toggleView}>
|
||||
{zones
|
||||
.map((zone: any) => (
|
||||
{zones.map((zone: any) => (
|
||||
<group key={zone.zoneId} name={zone.zoneName}>
|
||||
{zone.points.slice(0, -1).map((point: [number, number, number], index: number) => {
|
||||
{zone.points
|
||||
.slice(0, -1)
|
||||
.map((point: [number, number, number], index: number) => {
|
||||
const nextPoint = zone.points[index + 1];
|
||||
|
||||
const point1 = new THREE.Vector3(point[0], point[1], point[2]);
|
||||
const point2 = new THREE.Vector3(nextPoint[0], nextPoint[1], nextPoint[2]);
|
||||
const point2 = new THREE.Vector3(
|
||||
nextPoint[0],
|
||||
nextPoint[1],
|
||||
nextPoint[2]
|
||||
);
|
||||
|
||||
const planeWidth = point1.distanceTo(point2);
|
||||
const planeHeight = CONSTANTS.zoneConfig.height;
|
||||
|
||||
const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.zoneConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.zoneConfig.height), (point1.z + point2.z) / 2);
|
||||
const midpoint = new THREE.Vector3(
|
||||
(point1.x + point2.x) / 2,
|
||||
CONSTANTS.zoneConfig.height / 2 +
|
||||
(zone.layer - 1) * CONSTANTS.zoneConfig.height,
|
||||
(point1.z + point2.z) / 2
|
||||
);
|
||||
|
||||
const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x);
|
||||
const angle = Math.atan2(
|
||||
point2.z - point1.z,
|
||||
point2.x - point1.x
|
||||
);
|
||||
|
||||
return (
|
||||
<mesh
|
||||
|
@ -458,7 +563,7 @@ const ZoneGroup: React.FC = () => {
|
|||
</group>
|
||||
))}
|
||||
</group>
|
||||
<group name='zoneLines' visible={toggleView}>
|
||||
<group name="zoneLines" visible={toggleView}>
|
||||
{zones
|
||||
.filter((zone: any) => zone.layer === activeLayer)
|
||||
.map((zone: any) => (
|
||||
|
@ -477,7 +582,9 @@ const ZoneGroup: React.FC = () => {
|
|||
))}
|
||||
</group>
|
||||
<group name="zonePoints" visible={toggleView}>
|
||||
{zones.filter((zone: any) => zone.layer === activeLayer).flatMap((zone: any) => (
|
||||
{zones
|
||||
.filter((zone: any) => zone.layer === activeLayer)
|
||||
.flatMap((zone: any) =>
|
||||
zone.points.slice(0, 4).map((point: any, pointIndex: number) => (
|
||||
<Sphere
|
||||
key={`${zone.zoneId}-point-${pointIndex}`}
|
||||
|
@ -488,7 +595,7 @@ const ZoneGroup: React.FC = () => {
|
|||
<meshBasicMaterial color="red" />
|
||||
</Sphere>
|
||||
))
|
||||
))}
|
||||
)}
|
||||
</group>
|
||||
<group name="tempGroup" visible={toggleView}>
|
||||
{startPoint && endPoint && (
|
||||
|
|
|
@ -105,7 +105,7 @@ export default function SocketResponses({
|
|||
// console.log(`Getting ${data.data.modelname} from cache`);
|
||||
const model = cachedModel.scene.clone();
|
||||
model.uuid = data.data.modeluuid;
|
||||
model.userData = { name: data.data.modelname, modelId: data.data.modelFileID, modeluuid: data.data.modeluuid };
|
||||
model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid };
|
||||
model.position.set(...data.data.position as [number, number, number]);
|
||||
model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||
|
@ -159,7 +159,7 @@ export default function SocketResponses({
|
|||
url = URL.createObjectURL(indexedDBModel);
|
||||
} else {
|
||||
// console.log(`Getting ${data.data.modelname} from Backend`);
|
||||
url = `${url_Backend_dwinzo}/api/v1/AssetFile/${data.data.modelfileID}`;
|
||||
url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`;
|
||||
const modelBlob = await fetch(url).then((res) => res.blob());
|
||||
await storeGLTF(data.data.modelfileID, modelBlob);
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ export default function SocketResponses({
|
|||
THREE.Cache.remove(url);
|
||||
const model = gltf.scene;
|
||||
model.uuid = data.data.modeluuid;
|
||||
model.userData = { name: data.data.modelname, modelId: data.data.modelFileID, modeluuid: data.data.modeluuid };
|
||||
model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid };
|
||||
model.position.set(...data.data.position as [number, number, number]);
|
||||
model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||
|
|
|
@ -12,7 +12,7 @@ import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAss
|
|||
async function loadInitialFloorItems(
|
||||
itemsGroup: Types.RefGroup,
|
||||
setFloorItems: Types.setFloorItemSetState,
|
||||
setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void
|
||||
setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => void
|
||||
): Promise<void> {
|
||||
if (!itemsGroup.current) return;
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
@ -82,9 +82,7 @@ async function loadInitialFloorItems(
|
|||
if (indexedDBModel) {
|
||||
// console.log(`[IndexedDB] Fetching ${item.modelname}`);
|
||||
const blobUrl = URL.createObjectURL(indexedDBModel);
|
||||
loader.load(
|
||||
blobUrl,
|
||||
(gltf) => {
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(item.modelfileID!, gltf);
|
||||
|
@ -104,10 +102,8 @@ async function loadInitialFloorItems(
|
|||
|
||||
// Fetch from Backend
|
||||
// console.log(`[Backend] Fetching ${item.modelname}`);
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`;
|
||||
loader.load(
|
||||
modelUrl,
|
||||
async (gltf) => {
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`;
|
||||
loader.load(modelUrl, async (gltf) => {
|
||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
await storeGLTF(item.modelfileID!, modelBlob);
|
||||
THREE.Cache.add(item.modelfileID!, gltf);
|
||||
|
@ -137,7 +133,7 @@ async function loadInitialFloorItems(
|
|||
},
|
||||
]);
|
||||
|
||||
if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') {
|
||||
if (item.eventData) {
|
||||
processEventData(item, setSimulationStates);
|
||||
}
|
||||
|
||||
|
@ -157,7 +153,7 @@ function processLoadedModel(
|
|||
item: Types.EventData,
|
||||
itemsGroup: Types.RefGroup,
|
||||
setFloorItems: Types.setFloorItemSetState,
|
||||
setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void
|
||||
setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => void
|
||||
) {
|
||||
const model = gltf;
|
||||
model.uuid = item.modeluuid;
|
||||
|
@ -192,7 +188,7 @@ function processLoadedModel(
|
|||
},
|
||||
]);
|
||||
|
||||
if (item.eventData || item.modelfileID === '67e3db5ac2e8f37134526f40') {
|
||||
if (item.eventData) {
|
||||
processEventData(item, setSimulationStates);
|
||||
}
|
||||
|
||||
|
@ -221,6 +217,7 @@ function processEventData(item: Types.EventData, setSimulationStates: any) {
|
|||
data.modeluuid = item.modeluuid;
|
||||
data.modelName = item.modelname;
|
||||
data.position = item.position;
|
||||
data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
|
||||
|
||||
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
|
|
|
@ -263,6 +263,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
|||
return {
|
||||
uuid: pointUUID,
|
||||
position: vehiclePoint?.position,
|
||||
rotation: vehiclePoint?.rotation,
|
||||
actions: hasActions
|
||||
? {
|
||||
...vehiclePoint.actions,
|
||||
|
@ -315,6 +316,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
|||
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||
|
||||
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
|
@ -339,12 +341,14 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
|||
return {
|
||||
uuid: pointUUID,
|
||||
position: vehiclePoint?.position,
|
||||
rotation: vehiclePoint?.rotation,
|
||||
actions: hasActions
|
||||
? {
|
||||
...vehiclePoint.actions,
|
||||
uuid: THREE.MathUtils.generateUUID()
|
||||
}
|
||||
: defaultAction,
|
||||
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
|
||||
connections: {
|
||||
source: { modelUUID: obj.uuid, pointUUID },
|
||||
targets: []
|
||||
|
@ -415,6 +419,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
|||
return {
|
||||
uuid: pointUUID,
|
||||
position: vehiclePoint?.position,
|
||||
rotation: vehiclePoint?.rotation,
|
||||
actions: hasActions
|
||||
? {
|
||||
...vehiclePoint.actions,
|
||||
|
|
|
@ -245,6 +245,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
|||
return {
|
||||
uuid: pointUUID,
|
||||
position: vehiclePoint?.position,
|
||||
rotation: vehiclePoint?.rotation,
|
||||
actions: hasActions
|
||||
? {
|
||||
...vehiclePoint.actions,
|
||||
|
@ -297,6 +298,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
|||
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||
|
||||
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [
|
||||
...(prevEvents || []),
|
||||
|
@ -321,12 +323,14 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
|||
return {
|
||||
uuid: pointUUID,
|
||||
position: vehiclePoint?.position,
|
||||
rotation: vehiclePoint?.rotation,
|
||||
actions: hasActions
|
||||
? {
|
||||
...vehiclePoint.actions,
|
||||
uuid: THREE.MathUtils.generateUUID()
|
||||
}
|
||||
: defaultAction,
|
||||
triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' },
|
||||
connections: {
|
||||
source: { modelUUID: obj.uuid, pointUUID },
|
||||
targets: []
|
||||
|
@ -397,6 +401,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
|||
return {
|
||||
uuid: pointUUID,
|
||||
position: vehiclePoint?.position,
|
||||
rotation: vehiclePoint?.rotation,
|
||||
actions: hasActions
|
||||
? {
|
||||
...vehiclePoint.actions,
|
||||
|
|
|
@ -279,6 +279,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
|||
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||
|
||||
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
|
||||
const updatedEvents = (prevEvents || []).map(event =>
|
||||
|
|
|
@ -284,6 +284,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
|||
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||
newEventData.modelName = newFloorItem.modelname;
|
||||
newEventData.position = newFloorItem.position;
|
||||
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||
|
||||
setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
|
||||
const updatedEvents = (prevEvents || []).map(event =>
|
||||
|
|
|
@ -122,10 +122,15 @@ const SelectionControls: React.FC = () => {
|
|||
|
||||
if (!toggleView && activeModule === "builder") {
|
||||
helper.enabled = true;
|
||||
if (duplicatedObjects.length === 0 && pastedObjects.length === 0) {
|
||||
canvasElement.addEventListener("pointerdown", onPointerDown);
|
||||
canvasElement.addEventListener("pointermove", onPointerMove);
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
canvasElement.addEventListener("pointerup", onPointerUp);
|
||||
} else {
|
||||
helper.enabled = false;
|
||||
helper.dispose();
|
||||
}
|
||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||
canvasElement.addEventListener("keydown", onKeyDown);
|
||||
} else {
|
||||
helper.enabled = false;
|
||||
|
|
|
@ -952,8 +952,17 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
|
|||
);
|
||||
})
|
||||
},
|
||||
// Ensure all required ArmBot point properties are included
|
||||
actions: state.points.actions,
|
||||
actions: {
|
||||
...state.points.actions,
|
||||
processes: state.points.actions.processes?.filter(process => {
|
||||
return !(
|
||||
process.startPoint === connection1.point ||
|
||||
process.endPoint === connection1.point ||
|
||||
process.startPoint === connection2.point ||
|
||||
process.endPoint === connection2.point
|
||||
);
|
||||
}) || []
|
||||
},
|
||||
triggers: state.points.triggers
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,55 +1,22 @@
|
|||
// import html2canvas from "html2canvas";
|
||||
|
||||
export const captureVisualization = async (): Promise<string | null> => {
|
||||
const container = document.getElementById("real-time-vis-canvas");
|
||||
if (!container) return null;
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return null;
|
||||
|
||||
const rect = container.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
|
||||
// Draw background
|
||||
ctx.fillStyle = getComputedStyle(container).backgroundColor;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Capture all canvas elements
|
||||
const canvases = container.querySelectorAll("canvas");
|
||||
canvases.forEach((childCanvas) => {
|
||||
const childRect = childCanvas.getBoundingClientRect();
|
||||
const x = childRect.left - rect.left;
|
||||
const y = childRect.top - rect.top;
|
||||
ctx.drawImage(childCanvas, x, y, childRect.width, childRect.height);
|
||||
});
|
||||
|
||||
// Capture SVG elements
|
||||
const svgs = container.querySelectorAll("svg");
|
||||
for (const svg of Array.from(svgs)) {
|
||||
const svgString = new XMLSerializer().serializeToString(svg);
|
||||
const svgBlob = new Blob([svgString], { type: "image/svg+xml" });
|
||||
const url = URL.createObjectURL(svgBlob);
|
||||
|
||||
try {
|
||||
const img = await new Promise<HTMLImageElement>((resolve, reject) => {
|
||||
const image = new Image();
|
||||
image.onload = () => resolve(image);
|
||||
image.onerror = reject;
|
||||
image.src = url;
|
||||
});
|
||||
// Use html2canvas to capture the container
|
||||
// const canvas = await html2canvas(container, {
|
||||
// scale: 1, // Adjust scale for higher/lower resolution
|
||||
// });
|
||||
|
||||
const svgRect = svg.getBoundingClientRect();
|
||||
ctx.drawImage(
|
||||
img,
|
||||
svgRect.left - rect.left,
|
||||
svgRect.top - rect.top,
|
||||
svgRect.width,
|
||||
svgRect.height
|
||||
);
|
||||
} finally {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
}
|
||||
// // Convert the canvas to a data URL (PNG format)
|
||||
// const dataUrl = canvas.toDataURL("image/png");
|
||||
// return dataUrl;
|
||||
|
||||
return canvas.toDataURL("image/png");
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error("Error capturing visualization:", error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -28,10 +28,10 @@ export const handleSaveTemplate = async ({
|
|||
templates = [],
|
||||
visualizationSocket,
|
||||
}: HandleSaveTemplateProps): Promise<void> => {
|
||||
console.log('floatingWidget: ', floatingWidget);
|
||||
try {
|
||||
// Check if the selected zone has any widgets
|
||||
if (!selectedZone.panelOrder || selectedZone.panelOrder.length === 0) {
|
||||
console.warn("No widgets found in the selected zone.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,8 @@ export const handleSaveTemplate = async ({
|
|||
}
|
||||
|
||||
// Capture visualization snapshot
|
||||
const snapshot = await captureVisualization();
|
||||
// const snapshot = await captureVisualization();
|
||||
const snapshot = null;
|
||||
|
||||
// if (!snapshot) {
|
||||
// return;
|
||||
|
@ -65,7 +66,6 @@ export const handleSaveTemplate = async ({
|
|||
widgets3D,
|
||||
};
|
||||
|
||||
console.log('newTemplate: ', newTemplate);
|
||||
// Extract organization from email
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email.includes("@")
|
||||
|
@ -73,7 +73,6 @@ export const handleSaveTemplate = async ({
|
|||
: "";
|
||||
|
||||
if (!organization) {
|
||||
console.error("Organization could not be determined from email.");
|
||||
return;
|
||||
}
|
||||
let saveTemplate = {
|
||||
|
@ -88,13 +87,13 @@ export const handleSaveTemplate = async ({
|
|||
try {
|
||||
addTemplate(newTemplate);
|
||||
// const response = await saveTemplateApi(organization, newTemplate);
|
||||
// console.log("Save API Response:", response);
|
||||
//
|
||||
|
||||
// Add template only if API call succeeds
|
||||
} catch (apiError) {
|
||||
// console.error("Error saving template to API:", apiError);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error("Error in handleSaveTemplate:", error);
|
||||
//
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,22 +15,19 @@ type WidgetData = {
|
|||
|
||||
export default function SocketRealTimeViz() {
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||
const { setSelectedZone } = useSelectedZoneStore();
|
||||
const deleteObject = useDroppedObjectsStore((state) => state.deleteObject);
|
||||
const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject);
|
||||
const updateObjectPosition = useDroppedObjectsStore((state) => state.updateObjectPosition);
|
||||
const { addWidget } = useZoneWidgetStore()
|
||||
const { templates, removeTemplate } = useTemplateStore();
|
||||
const { removeTemplate } = useTemplateStore();
|
||||
const { setTemplates } = useTemplateStore();
|
||||
const { zoneWidgetData, setZoneWidgetData, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore();
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
if (visualizationSocket) {
|
||||
//add panel response
|
||||
visualizationSocket.on("viz-panel:response:updates", (addPanel: any) => {
|
||||
console.log('addPanel: ', addPanel);
|
||||
|
||||
if (addPanel.success) {
|
||||
let addPanelData = addPanel.data.data
|
||||
setSelectedZone(addPanelData)
|
||||
|
@ -38,15 +35,33 @@ export default function SocketRealTimeViz() {
|
|||
})
|
||||
//delete panel response
|
||||
visualizationSocket.on("viz-panel:response:delete", (deletePanel: any) => {
|
||||
console.log('deletePanel: ', deletePanel);
|
||||
|
||||
if (deletePanel.success) {
|
||||
let deletePanelData = deletePanel.data.data
|
||||
setSelectedZone(deletePanelData)
|
||||
}
|
||||
})
|
||||
//clear Panel response
|
||||
visualizationSocket.on("viz-panel:response:clear", (clearPanel: any) => {
|
||||
|
||||
if (clearPanel.success && clearPanel.message === "PanelWidgets cleared successfully") {
|
||||
|
||||
let clearPanelData = clearPanel.data.data
|
||||
setSelectedZone(clearPanelData)
|
||||
}
|
||||
})
|
||||
//lock Panel response
|
||||
visualizationSocket.on("viz-panel:response:locked", (lockPanel: any) => {
|
||||
|
||||
if (lockPanel.success && lockPanel.message === "locked panel updated successfully") {
|
||||
|
||||
let lockPanelData = lockPanel.data.data
|
||||
setSelectedZone(lockPanelData)
|
||||
}
|
||||
})
|
||||
// add 2dWidget response
|
||||
visualizationSocket.on("viz-widget:response:updates", (add2dWidget: any) => {
|
||||
console.log('add2dWidget: ', add2dWidget);
|
||||
|
||||
|
||||
if (add2dWidget.success && add2dWidget.data) {
|
||||
setSelectedZone((prev) => {
|
||||
|
@ -65,7 +80,7 @@ export default function SocketRealTimeViz() {
|
|||
});
|
||||
//delete 2D Widget response
|
||||
visualizationSocket.on("viz-widget:response:delete", (deleteWidget: any) => {
|
||||
console.log('deleteWidget: ', deleteWidget);
|
||||
|
||||
|
||||
if (deleteWidget?.success && deleteWidget.data) {
|
||||
setSelectedZone((prevZone: any) => ({
|
||||
|
@ -78,7 +93,7 @@ export default function SocketRealTimeViz() {
|
|||
});
|
||||
//add Floating Widget response
|
||||
visualizationSocket.on("viz-float:response:updates", (addFloatingWidget: any) => {
|
||||
console.log('addFloatingWidget: ', addFloatingWidget);
|
||||
|
||||
|
||||
if (addFloatingWidget.success) {
|
||||
if (addFloatingWidget.success && addFloatingWidget.message === "FloatWidget created successfully") {
|
||||
|
@ -105,7 +120,7 @@ export default function SocketRealTimeViz() {
|
|||
});
|
||||
//duplicate Floating Widget response
|
||||
visualizationSocket.on("viz-float:response:addDuplicate", (duplicateFloatingWidget: any) => {
|
||||
console.log('duplicateFloatingWidget: ', duplicateFloatingWidget);
|
||||
|
||||
|
||||
if (duplicateFloatingWidget.success && duplicateFloatingWidget.message === "duplicate FloatWidget created successfully") {
|
||||
useDroppedObjectsStore.setState((state) => {
|
||||
|
@ -133,7 +148,7 @@ export default function SocketRealTimeViz() {
|
|||
});
|
||||
//delete Floating Widget response
|
||||
visualizationSocket.on("viz-float:response:delete", (deleteFloatingWidget: any) => {
|
||||
console.log('deleteFloatingWidget: ', deleteFloatingWidget);
|
||||
|
||||
|
||||
if (deleteFloatingWidget.success) {
|
||||
deleteObject(deleteFloatingWidget.data.zoneName, deleteFloatingWidget.data.floatWidgetID);
|
||||
|
@ -142,9 +157,9 @@ export default function SocketRealTimeViz() {
|
|||
//add 3D Widget response
|
||||
visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => {
|
||||
|
||||
console.log('add3DWidget: ', add3DWidget);
|
||||
|
||||
if (add3DWidget.success) {
|
||||
console.log('add3DWidget: ', add3DWidget);
|
||||
|
||||
if (add3DWidget.message === "Widget created successfully") {
|
||||
addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget);
|
||||
}
|
||||
|
@ -152,7 +167,7 @@ export default function SocketRealTimeViz() {
|
|||
});
|
||||
//delete 3D Widget response
|
||||
visualizationSocket.on("viz-widget3D:response:delete", (delete3DWidget: any) => {
|
||||
console.log('delete3DWidget: ', delete3DWidget);
|
||||
|
||||
// "3DWidget delete unsuccessfull"
|
||||
if (delete3DWidget.success && delete3DWidget.message === "3DWidget delete successfull") {
|
||||
const activeZoneWidgets = zoneWidgetData[delete3DWidget.data.zoneId] || [];
|
||||
|
@ -164,16 +179,16 @@ export default function SocketRealTimeViz() {
|
|||
});
|
||||
//update3D widget response
|
||||
visualizationSocket.on("viz-widget3D:response:modifyPositionRotation", (update3DWidget: any) => {
|
||||
console.log('update3DWidget: ', update3DWidget);
|
||||
|
||||
if (update3DWidget.success && update3DWidget.message==="widget update successfully") {
|
||||
|
||||
if (update3DWidget.success && update3DWidget.message === "widget update successfully") {
|
||||
updateWidgetPosition(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.position);
|
||||
updateWidgetRotation(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.rotation);
|
||||
}
|
||||
});
|
||||
// add Template response
|
||||
visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => {
|
||||
console.log('addingTemplate: ', addingTemplate);
|
||||
|
||||
|
||||
if (addingTemplate.success) {
|
||||
if (addingTemplate.message === "Template saved successfully") {
|
||||
|
@ -183,7 +198,7 @@ export default function SocketRealTimeViz() {
|
|||
});
|
||||
//load Template response
|
||||
visualizationSocket.on("viz-template:response:addTemplateZone", (loadTemplate: any) => {
|
||||
console.log('loadTemplate: ', loadTemplate);
|
||||
|
||||
|
||||
if (loadTemplate.success) {
|
||||
if (loadTemplate.message === "Template placed in Zone") {
|
||||
|
@ -206,14 +221,12 @@ export default function SocketRealTimeViz() {
|
|||
});
|
||||
//delete Template response
|
||||
visualizationSocket.on("viz-template:response:delete", (deleteTemplate: any) => {
|
||||
console.log('deleteTemplate: ', deleteTemplate);
|
||||
|
||||
|
||||
if (deleteTemplate.success) {
|
||||
if (deleteTemplate.message === 'Template deleted successfully') {
|
||||
removeTemplate(deleteTemplate.data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}
|
|||
|
||||
export const getAssetModel = async (modelId: string) => {
|
||||
try {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${modelId}`, {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${modelId}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
|
||||
export const getFloorAssets = async (organization: string) => {
|
||||
try {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/v2/floorAssets/${organization}`, {
|
||||
|
@ -14,6 +15,7 @@ export const getFloorAssets = async (organization: string) => {
|
|||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
export const setFloorItemApi = async (
|
||||
organization: string,
|
||||
modeluuid: string,
|
||||
modelname: string,
|
||||
modelfileID: string,
|
||||
position: Object,
|
||||
rotation: Object,
|
||||
isLocked: boolean,
|
||||
isVisible: boolean,
|
||||
modeluuid?: string,
|
||||
modelname?: string,
|
||||
modelfileID?: string,
|
||||
position?: Object,
|
||||
rotation?: Object,
|
||||
isLocked?: boolean,
|
||||
isVisible?: boolean,
|
||||
eventData?: any
|
||||
) => {
|
||||
try {
|
||||
|
|
|
@ -26,7 +26,7 @@ onmessage = async (event) => {
|
|||
const message = "gltfLoaded";
|
||||
postMessage({ message, modelID, modelBlob });
|
||||
} else {
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${modelID}`;
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${modelID}`;
|
||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
await storeGLTF(modelID, modelBlob);
|
||||
const message = "gltfLoaded";
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||
|
||||
export const getZonesApi = async (organization: string) => {
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||
export const clearPanel = async (
|
||||
zoneId: string,
|
||||
organization: string,
|
||||
panelName: string
|
||||
) => {
|
||||
try {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/v2/clearpanel`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ organization, zoneId, panelName }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to clearPanel in the zone");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(error.message);
|
||||
} else {
|
||||
throw new Error("An unknown error occurred");
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||
export const lockPanel = async (
|
||||
zoneId: string,
|
||||
organization: string,
|
||||
lockedPanel: any
|
||||
) => {
|
||||
try {
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/v2/zones/lockedPanels`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ organization, zoneId, lockedPanel }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to Lock Panel in the zone");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(error.message);
|
||||
} else {
|
||||
throw new Error("An unknown error occurred");
|
||||
}
|
||||
}
|
||||
};
|
|
@ -9,13 +9,9 @@ export const update3dWidget = async (
|
|||
console.log("organization: ", organization);
|
||||
console.log("zoneId: ", zoneId);
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`,
|
||||
{
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
headers: { "Content-Type": "application/json", },
|
||||
body: JSON.stringify({
|
||||
organization,
|
||||
zoneId,
|
||||
|
|
|
@ -68,7 +68,11 @@ export const useWalls = create<any>((set: any) => ({
|
|||
|
||||
export const useZones = create<any>((set: any) => ({
|
||||
zones: [],
|
||||
setZones: (x: any) => set(() => ({ zones: x })),
|
||||
setZones: (callback: any) =>
|
||||
set((state: any) => ({
|
||||
zones:
|
||||
typeof callback === 'function' ? callback(state.zones) : callback
|
||||
}))
|
||||
}));
|
||||
|
||||
interface ZonePointsState {
|
||||
|
|
|
@ -81,9 +81,12 @@
|
|||
|
||||
.returnOfInvestment {
|
||||
gap: 10px;
|
||||
min-width: 150px;
|
||||
|
||||
.charts {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.returns-wrapper {
|
||||
|
@ -126,6 +129,12 @@
|
|||
gap: 6px;
|
||||
border-radius: 5.2px;
|
||||
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.header {
|
||||
font-size: $small;
|
||||
text-align: start;
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
max-width: 80%;
|
||||
overflow: auto;
|
||||
max-width: calc(100% - 500px);
|
||||
min-width: 150px;
|
||||
z-index: 3;
|
||||
transform: translate(-50%, -10%);
|
||||
|
||||
|
@ -363,6 +364,7 @@
|
|||
}
|
||||
|
||||
.panel.hidePanel {
|
||||
pointer-events: none;
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -310,11 +310,13 @@ interface VehicleEventsSchema {
|
|||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
||||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||
speed: number;
|
||||
};
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
}
|
||||
|
||||
interface StaticMachineEventsSchema {
|
||||
|
@ -324,6 +326,7 @@ interface StaticMachineEventsSchema {
|
|||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||
triggers: { uuid: string; name: string; type: string };
|
||||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||
|
@ -339,6 +342,7 @@ interface ArmBotEventsSchema {
|
|||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] };
|
||||
triggers: { uuid: string; name: string; type: string };
|
||||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||
|
@ -371,6 +375,7 @@ export type EventData = {
|
|||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
|
||||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||
speed: number;
|
||||
|
@ -380,6 +385,7 @@ export type EventData = {
|
|||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; buffer: number; material: string; };
|
||||
triggers: { uuid: string; name: string; type: string };
|
||||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||
|
@ -389,6 +395,7 @@ export type EventData = {
|
|||
points: {
|
||||
uuid: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] };
|
||||
triggers: { uuid: string; name: string; type: string };
|
||||
connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
|
||||
|
|
|
@ -148,13 +148,12 @@ const KeyPressListener: React.FC = () => {
|
|||
setActiveTool("draw-floor");
|
||||
setToolMode("Floor");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (keyCombination === "M") {
|
||||
setActiveTool("measure");
|
||||
setToolMode("MeasurementScale");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Undo redo
|
||||
if (keyCombination === "Ctrl+Z") {
|
||||
|
|
Loading…
Reference in New Issue