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:
Vishnu 2025-04-09 13:33:48 +00:00
commit 8cb7b5186b
48 changed files with 1605 additions and 987 deletions

98
app/package-lock.json generated
View File

@ -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"
}

View File

@ -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",

View File

@ -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,8 +220,8 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({
// e.stopPropagation();
}}
wrapperClass="pointer-none"
className={`${selectedChartId?.id === id ? "activeChart" : ""}`}
>
>
<div
className={`productionCapacity-wrapper card ${selectedChartId?.id === id ? "activeChart" : ""}`}
onClick={() => setSelectedChartId({ id: id, type: type })}

View File

@ -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">

View File

@ -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,
@ -46,7 +57,6 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio
socket.on("connect", startStream);
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;

View File

@ -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

View File

@ -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

View File

@ -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)}

View File

@ -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))}
/>
<LabledDropdown
key={`trigger-select-${selectedPoint.uuid}`}
label="Select Trigger"
defaultOption={connectedTriggers.find(t => t.uuid === selectedTrigger)?.displayName || ''}
onSelect={handleTriggerSelect}
options={connectedTriggers.map(trigger => trigger.displayName)}
/>
<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>
{selectedTrigger && (
<>
{selectedProcessIndex !== null && (
<div className="process-configuration">
<LabledDropdown
key={`start-point-${selectedTrigger}`}
key={`trigger-select-${selectedProcessIndex}`}
label="Select Trigger"
defaultOption={
connectedTriggers.find(t =>
t.uuid === getProcessByIndex(selectedProcessIndex)?.triggerId
)?.displayName || 'Select a trigger'
}
onSelect={(value) => handleTriggerSelect(value, selectedProcessIndex)}
options={getFilteredTriggerOptions(selectedProcessIndex)}
/>
<LabledDropdown
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">

View File

@ -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

View File

@ -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">

View File

@ -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);
};
// 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]);
let lockedPanel = {
organization: organization,
lockedPanel: newLockedPanels,
zoneId: selectedZone.zoneId,
};
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,9 +250,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
<div key={side} className={`side-button-container ${side}`}>
{/* "+" Button */}
<button
className={`side-button ${side}${
selectedZone.activeSides.includes(side) ? " active" : ""
}`}
className={`side-button ${side}${selectedZone.activeSides.includes(side) ? " active" : ""
}`}
onClick={() => handlePlusButtonClick(side)}
title={
selectedZone.activeSides.includes(side)
@ -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,9 +301,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
{/* Lock/Unlock Panel */}
<div
className={`icon ${
selectedZone.lockedPanels.includes(side) ? "active" : ""
}`}
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : ""
}`}
title={
selectedZone.lockedPanels.includes(side)
? "Unlock Panel"

View File

@ -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);

View File

@ -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

View File

@ -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,46 +519,41 @@ 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")
? `${heightMultiplier - 55}px`
: "0px"
})`
? `calc(${obj.position.top}px + ${isPlaying && selectedZone.activeSides.includes("top")
? `${heightMultiplier - 55}px`
: "0px"
})`
: "auto";
const leftPosition =
typeof obj.position.left === "number"
? `calc(${obj.position.left}px + ${
isPlaying && selectedZone.activeSides.includes("left")
? `${widthMultiplier - 100}px`
: "0px"
})`
? `calc(${obj.position.left}px + ${isPlaying && selectedZone.activeSides.includes("left")
? `${widthMultiplier - 100}px`
: "0px"
})`
: "auto";
const rightPosition =
typeof obj.position.right === "number"
? `calc(${obj.position.right}px + ${
isPlaying && selectedZone.activeSides.includes("right")
? `${widthMultiplier - 100}px`
: "0px"
})`
? `calc(${obj.position.right}px + ${isPlaying && selectedZone.activeSides.includes("right")
? `${widthMultiplier - 100}px`
: "0px"
})`
: "auto";
const bottomPosition =
typeof obj.position.bottom === "number"
? `calc(${obj.position.bottom}px + ${
isPlaying && selectedZone.activeSides.includes("bottom")
? `${heightMultiplier - 55}px`
: "0px"
})`
? `calc(${obj.position.bottom}px + ${isPlaying && selectedZone.activeSides.includes("bottom")
? `${heightMultiplier - 55}px`
: "0px"
})`
: "auto";
return (
<div
key={`${zoneName}-${index}`}
className={`${obj.className} ${
selectedChartId?.id === obj.id && "activeChart"
}`}
className={`${obj.className} ${selectedChartId?.id === obj.id && "activeChart"
}`}
ref={chartWidget}
style={{
position: "absolute",

View File

@ -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,9 +299,11 @@ const Panel: React.FC<PanelProps> = ({
<div
className={`panel-content ${isPlaying && "fullScreen"}`}
style={{
pointerEvents: selectedZone.lockedPanels.includes(side)
? "none"
: "auto",
pointerEvents:
selectedZone.lockedPanels.includes(side) ||
hiddenPanels[selectedZone.zoneId]?.includes(side)
? "none"
: "auto",
opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
}}
>

View File

@ -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>

View File

@ -12,25 +12,66 @@ 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());
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 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);
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, });
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);
} 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());
setSelectedFloorItem(AssetMesh);
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])

View File

@ -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">

View File

@ -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">

View File

@ -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, {

View File

@ -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: [] },

View File

@ -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!);

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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,16 +82,14 @@ async function loadInitialFloorItems(
if (indexedDBModel) {
// console.log(`[IndexedDB] Fetching ${item.modelname}`);
const blobUrl = URL.createObjectURL(indexedDBModel);
loader.load(
blobUrl,
(gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(item.modelfileID!, gltf);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
},
loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl);
THREE.Cache.add(item.modelfileID!, gltf);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
},
undefined,
(error) => {
toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
@ -104,17 +102,15 @@ 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 modelBlob = await fetch(modelUrl).then((res) => res.blob());
await storeGLTF(item.modelfileID!, modelBlob);
THREE.Cache.add(item.modelfileID!, gltf);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
},
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);
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates);
modelsLoaded++;
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
},
undefined,
(error) => {
toast.error(`[Backend] Error loading ${item.modelname}:`);
@ -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 || []),

View File

@ -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,

View File

@ -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,

View File

@ -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 =>

View File

@ -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 =>

View File

@ -122,10 +122,15 @@ const SelectionControls: React.FC = () => {
if (!toggleView && activeModule === "builder") {
helper.enabled = true;
canvasElement.addEventListener("pointerdown", onPointerDown);
canvasElement.addEventListener("pointermove", onPointerMove);
if (duplicatedObjects.length === 0 && pastedObjects.length === 0) {
canvasElement.addEventListener("pointerdown", onPointerDown);
canvasElement.addEventListener("pointermove", onPointerMove);
canvasElement.addEventListener("pointerup", onPointerUp);
} else {
helper.enabled = false;
helper.dispose();
}
canvasElement.addEventListener("contextmenu", onContextMenu);
canvasElement.addEventListener("pointerup", onPointerUp);
canvasElement.addEventListener("keydown", onKeyDown);
} else {
helper.enabled = false;

View File

@ -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
}
};

View File

@ -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 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;
try {
// Use html2canvas to capture the container
// const canvas = await html2canvas(container, {
// scale: 1, // Adjust scale for higher/lower resolution
// });
const rect = container.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;
// // Convert the canvas to a data URL (PNG format)
// const dataUrl = canvas.toDataURL("image/png");
// return dataUrl;
// 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;
});
const svgRect = svg.getBoundingClientRect();
ctx.drawImage(
img,
svgRect.left - rect.left,
svgRect.top - rect.top,
svgRect.width,
svgRect.height
);
} finally {
URL.revokeObjectURL(url);
}
}
return canvas.toDataURL("image/png");
return null;
} catch (error) {
console.error("Error capturing visualization:", error);
return null;
}
};

View File

@ -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;
@ -64,8 +65,7 @@ export const handleSaveTemplate = async ({
floatingWidget,
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);
//
}
};

View File

@ -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);
}
}
});
}

View File

@ -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",

View File

@ -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) {

View File

@ -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 {

View File

@ -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";

View File

@ -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 {

View File

@ -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");
}
}
};

View File

@ -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");
}
}
};

View File

@ -9,20 +9,16 @@ export const update3dWidget = async (
console.log("organization: ", organization);
console.log("zoneId: ", zoneId);
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
organization,
zoneId,
id,
position,
}),
}
const response = await fetch(`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`, {
method: "PATCH",
headers: { "Content-Type": "application/json", },
body: JSON.stringify({
organization,
zoneId,
id,
position,
}),
}
);
if (!response.ok) {

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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 }[] };

View File

@ -148,11 +148,10 @@ const KeyPressListener: React.FC = () => {
setActiveTool("draw-floor");
setToolMode("Floor");
}
} else {
if (keyCombination === "M") {
setActiveTool("measure");
setToolMode("MeasurementScale");
}
}
if (keyCombination === "M") {
setActiveTool("measure");
setToolMode("MeasurementScale");
}
}