Merge branch 'main' into rtViz
This commit is contained in:
commit
6089c5538f
|
@ -29,6 +29,7 @@
|
||||||
"chartjs-plugin-annotation": "^3.1.0",
|
"chartjs-plugin-annotation": "^3.1.0",
|
||||||
"glob": "^11.0.0",
|
"glob": "^11.0.0",
|
||||||
"gsap": "^3.12.5",
|
"gsap": "^3.12.5",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
"leva": "^0.10.0",
|
"leva": "^0.10.0",
|
||||||
"mqtt": "^5.10.4",
|
"mqtt": "^5.10.4",
|
||||||
"postprocessing": "^6.36.4",
|
"postprocessing": "^6.36.4",
|
||||||
|
@ -2019,7 +2020,7 @@
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||||
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/trace-mapping": "0.3.9"
|
"@jridgewell/trace-mapping": "0.3.9"
|
||||||
},
|
},
|
||||||
|
@ -2031,7 +2032,7 @@
|
||||||
"version": "0.3.9",
|
"version": "0.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||||
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.0.3",
|
"@jridgewell/resolve-uri": "^3.0.3",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
|
@ -4134,26 +4135,6 @@
|
||||||
"url": "https://github.com/sponsors/gregberge"
|
"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": {
|
"node_modules/@testing-library/jest-dom": {
|
||||||
"version": "5.17.0",
|
"version": "5.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz",
|
||||||
|
@ -4265,25 +4246,25 @@
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
|
||||||
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
|
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
|
||||||
"devOptional": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@tsconfig/node12": {
|
"node_modules/@tsconfig/node12": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||||
"devOptional": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@tsconfig/node14": {
|
"node_modules/@tsconfig/node14": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||||
"devOptional": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@tsconfig/node16": {
|
"node_modules/@tsconfig/node16": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
||||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
||||||
"devOptional": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@turf/along": {
|
"node_modules/@turf/along": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
|
@ -8047,6 +8028,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
"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": {
|
"node_modules/base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
@ -9017,7 +9007,7 @@
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||||
"devOptional": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/cross-env": {
|
"node_modules/cross-env": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
|
@ -9102,6 +9092,15 @@
|
||||||
"postcss": "^8.4"
|
"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": {
|
"node_modules/css-loader": {
|
||||||
"version": "6.11.0",
|
"version": "6.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz",
|
||||||
|
@ -9885,7 +9884,7 @@
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.3.1"
|
"node": ">=0.3.1"
|
||||||
}
|
}
|
||||||
|
@ -12489,6 +12488,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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": {
|
"node_modules/htmlparser2": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
|
||||||
|
@ -15235,7 +15247,7 @@
|
||||||
"version": "1.3.6",
|
"version": "1.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||||
"devOptional": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/makeerror": {
|
"node_modules/makeerror": {
|
||||||
"version": "1.0.12",
|
"version": "1.0.12",
|
||||||
|
@ -20434,6 +20446,15 @@
|
||||||
"node": "*"
|
"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": {
|
"node_modules/text-table": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||||
|
@ -20694,7 +20715,7 @@
|
||||||
"version": "10.9.2",
|
"version": "10.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
||||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cspotcode/source-map-support": "^0.8.0",
|
"@cspotcode/source-map-support": "^0.8.0",
|
||||||
"@tsconfig/node10": "^1.0.7",
|
"@tsconfig/node10": "^1.0.7",
|
||||||
|
@ -20737,7 +20758,7 @@
|
||||||
"version": "8.3.4",
|
"version": "8.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
|
||||||
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
|
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.11.0"
|
"acorn": "^8.11.0"
|
||||||
},
|
},
|
||||||
|
@ -20749,7 +20770,7 @@
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||||
"devOptional": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/tsconfig-paths": {
|
"node_modules/tsconfig-paths": {
|
||||||
"version": "3.15.0",
|
"version": "3.15.0",
|
||||||
|
@ -21220,6 +21241,15 @@
|
||||||
"node": ">= 0.4.0"
|
"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": {
|
"node_modules/uuid": {
|
||||||
"version": "9.0.1",
|
"version": "9.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
|
@ -21236,7 +21266,7 @@
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||||
"devOptional": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/v8-to-istanbul": {
|
"node_modules/v8-to-istanbul": {
|
||||||
"version": "8.1.1",
|
"version": "8.1.1",
|
||||||
|
@ -22295,7 +22325,7 @@
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
"chartjs-plugin-annotation": "^3.1.0",
|
"chartjs-plugin-annotation": "^3.1.0",
|
||||||
"glob": "^11.0.0",
|
"glob": "^11.0.0",
|
||||||
"gsap": "^3.12.5",
|
"gsap": "^3.12.5",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
"leva": "^0.10.0",
|
"leva": "^0.10.0",
|
||||||
"mqtt": "^5.10.4",
|
"mqtt": "^5.10.4",
|
||||||
"postprocessing": "^6.36.4",
|
"postprocessing": "^6.36.4",
|
||||||
|
|
|
@ -8,37 +8,45 @@ export function CleanPannel() {
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<g clipPath="url(#clip0_1782_1158)">
|
<g clipPath="url(#clip0_1782_1158)">
|
||||||
<path d="M12 0H0V12H12V0Z" fill="white" fillOpacity="0.01" />
|
<path
|
||||||
|
d="M12 0H0V12H12V0Z"
|
||||||
|
fill="var(--text-color)"
|
||||||
|
fillOpacity="0.01"
|
||||||
|
/>
|
||||||
<path
|
<path
|
||||||
fillRule="evenodd"
|
fillRule="evenodd"
|
||||||
clipRule="evenodd"
|
clipRule="evenodd"
|
||||||
d="M5 1.47852H7V3.47853H10.75V5.47853H1.25V3.47853H5V1.47852Z"
|
d="M5 1.47852H7V3.47853H10.75V5.47853H1.25V3.47853H5V1.47852Z"
|
||||||
stroke="#2B3344"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
<path d="M2 10H10V5.5H2V10Z" stroke="#2B3344" strokeLinejoin="round" />
|
<path
|
||||||
|
d="M2 10H10V5.5H2V10Z"
|
||||||
|
stroke="var(--text-color)"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
<path
|
<path
|
||||||
d="M4 9.97439V8.47852"
|
d="M4 9.97439V8.47852"
|
||||||
stroke="#2B3344"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M6 9.97461V8.47461"
|
d="M6 9.97461V8.47461"
|
||||||
stroke="#2B3344"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M8 9.97439V8.47852"
|
d="M8 9.97439V8.47852"
|
||||||
stroke="#2B3344"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M3 10H9"
|
d="M3 10H9"
|
||||||
stroke="#2B3344"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -49,7 +49,7 @@ const SideBarLeft: React.FC = () => {
|
||||||
</>
|
</>
|
||||||
) : activeModule === "market" ? (
|
) : activeModule === "market" ? (
|
||||||
<></>
|
<></>
|
||||||
) : (
|
) : activeModule === "builder" ? (
|
||||||
<>
|
<>
|
||||||
<ToggleHeader
|
<ToggleHeader
|
||||||
options={["Outline", "Assets"]}
|
options={["Outline", "Assets"]}
|
||||||
|
@ -60,6 +60,17 @@ const SideBarLeft: React.FC = () => {
|
||||||
{activeOption === "Outline" ? <Outline /> : <Assets />}
|
{activeOption === "Outline" ? <Outline /> : <Assets />}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ToggleHeader
|
||||||
|
options={["Outline"]}
|
||||||
|
activeOption={activeOption}
|
||||||
|
handleClick={handleToggleClick}
|
||||||
|
/>
|
||||||
|
<div className="sidebar-left-content-container">
|
||||||
|
{activeOption === "Outline" ? <Outline /> : <Assets />}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -14,7 +14,7 @@ const chartTypes: ChartType[] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const sampleData = {
|
const sampleData = {
|
||||||
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
|
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
data: [65, 59, 80, 81, 56, 55, 40],
|
data: [65, 59, 80, 81, 56, 55, 40],
|
||||||
|
@ -102,7 +102,6 @@ const ProgressBarWidget = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const Widgets2D = () => {
|
const Widgets2D = () => {
|
||||||
return (
|
return (
|
||||||
<div className="widget2D">
|
<div className="widget2D">
|
||||||
|
|
|
@ -10,6 +10,7 @@ import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||||
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
|
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
|
||||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||||
import {
|
import {
|
||||||
|
useFloorItems,
|
||||||
useSelectedActionSphere,
|
useSelectedActionSphere,
|
||||||
useSelectedPath,
|
useSelectedPath,
|
||||||
useSimulationPaths,
|
useSimulationPaths,
|
||||||
|
@ -17,11 +18,14 @@ import {
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||||
|
import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||||
|
import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt";
|
||||||
|
|
||||||
const ConveyorMechanics: React.FC = () => {
|
const ConveyorMechanics: React.FC = () => {
|
||||||
const { selectedActionSphere } = useSelectedActionSphere();
|
const { selectedActionSphere } = useSelectedActionSphere();
|
||||||
const { selectedPath, setSelectedPath } = useSelectedPath();
|
const { selectedPath, setSelectedPath } = useSelectedPath();
|
||||||
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
|
|
||||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
@ -36,6 +40,19 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
.find((point) => point.uuid === selectedActionSphere.point.uuid);
|
.find((point) => point.uuid === selectedActionSphere.point.uuid);
|
||||||
}, [selectedActionSphere, simulationPaths]);
|
}, [selectedActionSphere, simulationPaths]);
|
||||||
|
|
||||||
|
const updateBackend = async (updatedPath: Types.ConveyorEventsSchema | undefined) => {
|
||||||
|
if (!updatedPath) return;
|
||||||
|
// const email = localStorage.getItem("email");
|
||||||
|
// const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||||
|
// console.log('updatedPath: ', updatedPath);
|
||||||
|
// const a = await setEventApi(
|
||||||
|
// organization,
|
||||||
|
// updatedPath.modeluuid,
|
||||||
|
// updatedPath.points
|
||||||
|
// );
|
||||||
|
// console.log('a: ', a);
|
||||||
|
}
|
||||||
|
|
||||||
const handleAddAction = () => {
|
const handleAddAction = () => {
|
||||||
if (!selectedActionSphere) return;
|
if (!selectedActionSphere) return;
|
||||||
|
|
||||||
|
@ -65,6 +82,15 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
return path;
|
return path;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,21 +100,30 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.filter(
|
actions: point.actions.filter(
|
||||||
(action) => action.uuid !== uuid
|
(action) => action.uuid !== uuid
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -98,36 +133,45 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) =>
|
actions: point.actions.map((action) =>
|
||||||
action.uuid === uuid
|
action.uuid === uuid
|
||||||
? {
|
? {
|
||||||
...action,
|
...action,
|
||||||
type: actionType,
|
type: actionType,
|
||||||
material:
|
material:
|
||||||
actionType === "Spawn" || actionType === "Swap"
|
actionType === "Spawn" || actionType === "Swap"
|
||||||
? "Inherit"
|
? "Inherit"
|
||||||
: action.material,
|
: action.material,
|
||||||
delay:
|
delay:
|
||||||
actionType === "Delay" ? "Inherit" : action.delay,
|
actionType === "Delay" ? "Inherit" : action.delay,
|
||||||
spawnInterval:
|
spawnInterval:
|
||||||
actionType === "Spawn"
|
actionType === "Spawn"
|
||||||
? "Inherit"
|
? "Inherit"
|
||||||
: action.spawnInterval,
|
: action.spawnInterval,
|
||||||
}
|
}
|
||||||
: action
|
: action
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
|
|
||||||
// Update the selected item to reflect changes
|
// Update the selected item to reflect changes
|
||||||
|
@ -156,24 +200,33 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) =>
|
actions: point.actions.map((action) =>
|
||||||
action.uuid === uuid &&
|
action.uuid === uuid &&
|
||||||
(action.type === "Spawn" || action.type === "Swap")
|
(action.type === "Spawn" || action.type === "Swap")
|
||||||
? { ...action, material }
|
? { ...action, material }
|
||||||
: action
|
: action
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
|
|
||||||
// Update selected item if it's the current action
|
// Update selected item if it's the current action
|
||||||
|
@ -194,21 +247,30 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) =>
|
actions: point.actions.map((action) =>
|
||||||
action.uuid === uuid ? { ...action, delay } : action
|
action.uuid === uuid ? { ...action, delay } : action
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -221,23 +283,32 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) =>
|
actions: point.actions.map((action) =>
|
||||||
action.uuid === uuid
|
action.uuid === uuid
|
||||||
? { ...action, spawnInterval }
|
? { ...action, spawnInterval }
|
||||||
: action
|
: action
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -248,6 +319,15 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
|
setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } });
|
||||||
};
|
};
|
||||||
|
@ -258,26 +338,35 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) => {
|
points: path.points.map((point) => {
|
||||||
if (point.uuid === selectedActionSphere.point.uuid) {
|
if (point.uuid === selectedActionSphere.point.uuid) {
|
||||||
const triggerIndex = point.triggers.length;
|
const triggerIndex = point.triggers.length;
|
||||||
const newTrigger = {
|
const newTrigger = {
|
||||||
uuid: THREE.MathUtils.generateUUID(),
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
name: `Trigger ${triggerIndex + 1}`,
|
name: `Trigger ${triggerIndex + 1}`,
|
||||||
type: "",
|
type: "",
|
||||||
bufferTime: 0,
|
bufferTime: 0,
|
||||||
isUsed: false,
|
isUsed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...point, triggers: [...point.triggers, newTrigger] };
|
return { ...point, triggers: [...point.triggers, newTrigger] };
|
||||||
}
|
}
|
||||||
return point;
|
return point;
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -287,21 +376,30 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
triggers: point.triggers.filter(
|
triggers: point.triggers.filter(
|
||||||
(trigger) => trigger.uuid !== uuid
|
(trigger) => trigger.uuid !== uuid
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -311,23 +409,32 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
triggers: point.triggers.map((trigger) =>
|
triggers: point.triggers.map((trigger) =>
|
||||||
trigger.uuid === uuid
|
trigger.uuid === uuid
|
||||||
? { ...trigger, type: triggerType }
|
? { ...trigger, type: triggerType }
|
||||||
: trigger
|
: trigger
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
|
|
||||||
// Ensure the selectedItem is updated immediately
|
// Ensure the selectedItem is updated immediately
|
||||||
|
@ -347,22 +454,31 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
actions: point.actions.map((action) => ({
|
actions: point.actions.map((action) => ({
|
||||||
...action,
|
...action,
|
||||||
isUsed: action.uuid === uuid ? !action.isUsed : false,
|
isUsed: action.uuid === uuid ? !action.isUsed : false,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
|
|
||||||
// Immediately update the selected item if it's the one being toggled
|
// Immediately update the selected item if it's the one being toggled
|
||||||
|
@ -384,22 +500,31 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
triggers: point.triggers.map((trigger) => ({
|
triggers: point.triggers.map((trigger) => ({
|
||||||
...trigger,
|
...trigger,
|
||||||
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
|
isUsed: trigger.uuid === uuid ? !trigger.isUsed : false,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
|
|
||||||
// Immediately update the selected item if it's the one being toggled
|
// Immediately update the selected item if it's the one being toggled
|
||||||
|
@ -420,23 +545,32 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
const updatedPaths = simulationPaths.map((path) =>
|
const updatedPaths = simulationPaths.map((path) =>
|
||||||
path.type === "Conveyor"
|
path.type === "Conveyor"
|
||||||
? {
|
? {
|
||||||
...path,
|
...path,
|
||||||
points: path.points.map((point) =>
|
points: path.points.map((point) =>
|
||||||
point.uuid === selectedActionSphere.point.uuid
|
point.uuid === selectedActionSphere.point.uuid
|
||||||
? {
|
? {
|
||||||
...point,
|
...point,
|
||||||
triggers: point.triggers.map((trigger) =>
|
triggers: point.triggers.map((trigger) =>
|
||||||
trigger.uuid === uuid
|
trigger.uuid === uuid
|
||||||
? { ...trigger, bufferTime }
|
? { ...trigger, bufferTime }
|
||||||
: trigger
|
: trigger
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: point
|
: point
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
: path
|
: path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const updatedPath = updatedPaths.find(
|
||||||
|
(path): path is Types.ConveyorEventsSchema =>
|
||||||
|
path.type === "Conveyor" &&
|
||||||
|
path.points.some(
|
||||||
|
(point) => point.uuid === selectedActionSphere.point.uuid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
updateBackend(updatedPath);
|
||||||
|
|
||||||
setSimulationPaths(updatedPaths);
|
setSimulationPaths(updatedPaths);
|
||||||
|
|
||||||
// Immediately update selectedItem if it's the currently selected trigger
|
// Immediately update selectedItem if it's the currently selected trigger
|
||||||
|
@ -493,12 +627,11 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
{selectedPoint?.actions.map((action) => (
|
{selectedPoint?.actions.map((action) => (
|
||||||
<div
|
<div
|
||||||
key={action.uuid}
|
key={action.uuid}
|
||||||
className={`list-item ${
|
className={`list-item ${selectedItem?.type === "action" &&
|
||||||
selectedItem?.type === "action" &&
|
|
||||||
selectedItem.item?.uuid === action.uuid
|
selectedItem.item?.uuid === action.uuid
|
||||||
? "active"
|
? "active"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="value"
|
className="value"
|
||||||
|
@ -506,7 +639,7 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
setSelectedItem({ type: "action", item: action })
|
setSelectedItem({ type: "action", item: action })
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<input type="radio" name="action" id="action" defaultChecked={action.isUsed}/>
|
<input type="radio" name="action" id="action" defaultChecked={action.isUsed} />
|
||||||
<RenameInput value={action.name} />
|
<RenameInput value={action.name} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
@ -543,12 +676,11 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
{selectedPoint?.triggers.map((trigger) => (
|
{selectedPoint?.triggers.map((trigger) => (
|
||||||
<div
|
<div
|
||||||
key={trigger.uuid}
|
key={trigger.uuid}
|
||||||
className={`list-item ${
|
className={`list-item ${selectedItem?.type === "trigger" &&
|
||||||
selectedItem?.type === "trigger" &&
|
|
||||||
selectedItem.item?.uuid === trigger.uuid
|
selectedItem.item?.uuid === trigger.uuid
|
||||||
? "active"
|
? "active"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="value"
|
className="value"
|
||||||
|
@ -588,8 +720,8 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
{selectedItem.type === "action" && (
|
{selectedItem.type === "action" && (
|
||||||
<>
|
<>
|
||||||
<InputToggle
|
<InputToggle
|
||||||
inputKey="enableTrigger"
|
inputKey="enableAction"
|
||||||
label="Enable Trigger"
|
label="Enable Action"
|
||||||
value={selectedItem.item.isUsed}
|
value={selectedItem.item.isUsed}
|
||||||
onClick={() => handleActionToggle(selectedItem.item.uuid)}
|
onClick={() => handleActionToggle(selectedItem.item.uuid)}
|
||||||
/>
|
/>
|
||||||
|
@ -604,19 +736,19 @@ const ConveyorMechanics: React.FC = () => {
|
||||||
{/* Only show material dropdown for Spawn/Swap actions */}
|
{/* Only show material dropdown for Spawn/Swap actions */}
|
||||||
{(selectedItem.item.type === "Spawn" ||
|
{(selectedItem.item.type === "Spawn" ||
|
||||||
selectedItem.item.type === "Swap") && (
|
selectedItem.item.type === "Swap") && (
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
label={
|
label={
|
||||||
selectedItem.item.type === "Spawn"
|
selectedItem.item.type === "Spawn"
|
||||||
? "Spawn Material"
|
? "Spawn Material"
|
||||||
: "Swap Material"
|
: "Swap Material"
|
||||||
}
|
}
|
||||||
defaultOption={selectedItem.item.material}
|
defaultOption={selectedItem.item.material}
|
||||||
options={["Inherit", "Crate", "Box"]}
|
options={["Inherit", "Crate", "Box"]}
|
||||||
onSelect={(option) =>
|
onSelect={(option) =>
|
||||||
handleMaterialSelect(selectedItem.item.uuid, option)
|
handleMaterialSelect(selectedItem.item.uuid, option)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Only show delay input for Delay actions */}
|
{/* Only show delay input for Delay actions */}
|
||||||
{selectedItem.item.type === "Delay" && (
|
{selectedItem.item.type === "Delay" && (
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
import { useState } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent";
|
import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent";
|
||||||
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
|
import { WalletIcon } from "../../../../icons/3dChartIcons";
|
||||||
|
import SimpleCard from "../../../../ui/realTimeVis/floating/SimpleCard";
|
||||||
|
|
||||||
// Define Props Interface
|
|
||||||
interface Widget {
|
interface Widget {
|
||||||
id: string;
|
id: string;
|
||||||
type: string; // Chart type (e.g., "bar", "line")
|
type?: string;
|
||||||
panel: "top" | "bottom" | "left" | "right"; // Panel location
|
panel: "top" | "bottom" | "left" | "right";
|
||||||
title: string;
|
title?: string;
|
||||||
|
header?: string;
|
||||||
fontFamily?: string;
|
fontFamily?: string;
|
||||||
fontSize?: string;
|
fontSize?: string;
|
||||||
fontWeight?: string;
|
fontWeight?: string;
|
||||||
data: {
|
className?: string;
|
||||||
|
data?: {
|
||||||
labels: string[];
|
labels: string[];
|
||||||
datasets: {
|
datasets: {
|
||||||
data: number[];
|
data: number[];
|
||||||
|
@ -20,162 +23,263 @@ interface Widget {
|
||||||
borderColor: string;
|
borderColor: string;
|
||||||
borderWidth: number;
|
borderWidth: number;
|
||||||
}[];
|
}[];
|
||||||
}; // Data for the chart
|
};
|
||||||
|
value?: string;
|
||||||
|
per?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChartElement {
|
||||||
|
tagName: string;
|
||||||
|
className: string;
|
||||||
|
textContent: string;
|
||||||
|
selector: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Design = () => {
|
const Design = () => {
|
||||||
const [selectedName, setSelectedName] = useState("drop down");
|
|
||||||
console.log("selectedName: ", selectedName);
|
|
||||||
|
|
||||||
const [selectedElement, setSelectedElement] = useState("drop down");
|
|
||||||
console.log("selectedElement: ", selectedElement);
|
|
||||||
|
|
||||||
const [selectedFont, setSelectedFont] = useState("drop down");
|
const [selectedFont, setSelectedFont] = useState("drop down");
|
||||||
console.log("selectedFont: ", selectedFont);
|
|
||||||
|
|
||||||
const [selectedSize, setSelectedSize] = useState("drop down");
|
const [selectedSize, setSelectedSize] = useState("drop down");
|
||||||
console.log("selectedSize: ", selectedSize);
|
|
||||||
|
|
||||||
const [selectedWeight, setSelectedWeight] = useState("drop down");
|
const [selectedWeight, setSelectedWeight] = useState("drop down");
|
||||||
console.log("selectedWeight: ", selectedWeight);
|
const [elementColor, setElementColor] = useState("#6f42c1");
|
||||||
|
const [showColorPicker, setShowColorPicker] = useState(false);
|
||||||
|
const [chartElements, setChartElements] = useState<ChartElement[]>([]);
|
||||||
|
const [selectedElementToStyle, setSelectedElementToStyle] = useState<string | null>(null);
|
||||||
|
const [nameInput, setNameInput] = useState("");
|
||||||
|
const chartRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [elementColor, setElementColor] = useState("#6f42c1"); // Default color for elements
|
const { selectedChartId, setSelectedChartId, widgets, setWidgets } = useWidgetStore();
|
||||||
const [showColorPicker, setShowColorPicker] = useState(false); // Manage visibility of the color picker
|
|
||||||
|
|
||||||
// Zustand Store Hooks
|
// Initialize name input and extract elements when selectedChartId changes
|
||||||
const { selectedChartId, setSelectedChartId, widgets, setWidgets } =
|
useEffect(() => {
|
||||||
useWidgetStore();
|
setNameInput(selectedChartId?.header || selectedChartId?.title || "");
|
||||||
|
|
||||||
|
if (!chartRef.current) return;
|
||||||
|
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
const chartContainer = chartRef.current;
|
||||||
|
if (!chartContainer) return;
|
||||||
|
|
||||||
|
const elements = Array.from(chartContainer.querySelectorAll("*"))
|
||||||
|
.filter((el) => {
|
||||||
|
const tagName = el.tagName.toLowerCase();
|
||||||
|
return !["script", "style", "meta", "link", "head"].includes(tagName);
|
||||||
|
})
|
||||||
|
.map((el, index) => {
|
||||||
|
const tagName = el.tagName.toLowerCase();
|
||||||
|
const className = typeof el.className === "string" ? el.className : "";
|
||||||
|
const textContent = el.textContent?.trim() || "";
|
||||||
|
|
||||||
|
let selector = tagName;
|
||||||
|
|
||||||
|
if (className && typeof className === "string") {
|
||||||
|
const classList = className.split(/\s+/).filter((c) => c.length > 0);
|
||||||
|
if (classList.length > 0) {
|
||||||
|
selector += "." + classList.join(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!className || className.trim() === "") {
|
||||||
|
const parent = el.parentElement;
|
||||||
|
if (parent) {
|
||||||
|
const siblings = Array.from(parent.children).filter(
|
||||||
|
(child) => child.tagName.toLowerCase() === tagName
|
||||||
|
);
|
||||||
|
const position = siblings.indexOf(el) + 1;
|
||||||
|
selector += `:nth-of-type(${position})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
tagName,
|
||||||
|
className,
|
||||||
|
textContent,
|
||||||
|
selector,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setChartElements(elements);
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [selectedChartId]);
|
||||||
|
|
||||||
|
const applyStyles = () => {
|
||||||
|
if (!selectedElementToStyle || !chartRef.current) return;
|
||||||
|
|
||||||
|
const element = chartRef.current.querySelector(selectedElementToStyle);
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
|
const elementToStyle = element as HTMLElement;
|
||||||
|
|
||||||
|
if (selectedFont !== "drop down") {
|
||||||
|
elementToStyle.style.fontFamily = selectedFont;
|
||||||
|
}
|
||||||
|
if (selectedSize !== "drop down") {
|
||||||
|
elementToStyle.style.fontSize = selectedSize;
|
||||||
|
}
|
||||||
|
if (selectedWeight !== "drop down") {
|
||||||
|
elementToStyle.style.fontWeight = selectedWeight.toLowerCase();
|
||||||
|
}
|
||||||
|
if (elementColor) {
|
||||||
|
elementToStyle.style.color = elementColor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
applyStyles();
|
||||||
|
}, [selectedFont, selectedSize, selectedWeight, elementColor, selectedElementToStyle]);
|
||||||
|
|
||||||
// Handle Widget Updates
|
|
||||||
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
|
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
|
||||||
if (!selectedChartId) return;
|
if (!selectedChartId) return;
|
||||||
|
|
||||||
// Update the selectedChartId
|
|
||||||
const updatedChartId = {
|
const updatedChartId = {
|
||||||
...selectedChartId,
|
...selectedChartId,
|
||||||
...updatedProperties,
|
...updatedProperties,
|
||||||
};
|
};
|
||||||
setSelectedChartId(updatedChartId);
|
setSelectedChartId(updatedChartId);
|
||||||
|
|
||||||
// Update the widgets array
|
|
||||||
const updatedWidgets = widgets.map((widget) =>
|
const updatedWidgets = widgets.map((widget) =>
|
||||||
widget.id === selectedChartId.id
|
widget.id === selectedChartId.id ? { ...widget, ...updatedProperties } : widget
|
||||||
? { ...widget, ...updatedProperties }
|
|
||||||
: widget
|
|
||||||
);
|
);
|
||||||
setWidgets(updatedWidgets);
|
setWidgets(updatedWidgets);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default Chart Data
|
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const newName = e.target.value;
|
||||||
|
setNameInput(newName);
|
||||||
|
|
||||||
|
if (selectedChartId?.title) {
|
||||||
|
handleUpdateWidget({ title: newName });
|
||||||
|
} else if (selectedChartId?.header) {
|
||||||
|
handleUpdateWidget({ header: newName });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const defaultChartData = {
|
const defaultChartData = {
|
||||||
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
|
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
data: [65, 59, 80, 81, 56, 55, 40],
|
data: [65, 59, 80, 81, 56, 55, 40],
|
||||||
backgroundColor: elementColor, // Default background color
|
backgroundColor: elementColor,
|
||||||
borderColor: "#ffffff", // Default border color
|
borderColor: "#ffffff",
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const elementOptions = chartElements.map((el) => {
|
||||||
|
let displayName = el.tagName;
|
||||||
|
if (el.className) displayName += `.${el.className}`;
|
||||||
|
if (el.textContent)
|
||||||
|
displayName += ` (${el.textContent.substring(0, 20)}${
|
||||||
|
el.textContent.length > 20 ? "..." : ""
|
||||||
|
})`;
|
||||||
|
return {
|
||||||
|
display: displayName,
|
||||||
|
value: el.selector,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="design">
|
<div className="design">
|
||||||
{/* Title of the Selected Widget */}
|
|
||||||
<div className="selectedWidget">
|
<div className="selectedWidget">
|
||||||
{selectedChartId?.title || "Widget 1"}
|
{selectedChartId?.title || selectedChartId?.header || "Widget 1"}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Chart Component */}
|
<div className="reviewChart" ref={chartRef}>
|
||||||
<div className="reviewChart">
|
{selectedChartId?.title ? (
|
||||||
{selectedChartId && (
|
|
||||||
<ChartComponent
|
<ChartComponent
|
||||||
type={selectedChartId.type}
|
type={selectedChartId.type || "bar"}
|
||||||
title={selectedChartId.title}
|
title={selectedChartId.title}
|
||||||
data={selectedChartId.data || defaultChartData} // Use widget data or default
|
data={selectedChartId.data || defaultChartData}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<SimpleCard
|
||||||
|
header={selectedChartId?.header || ""}
|
||||||
|
icon={WalletIcon}
|
||||||
|
value={selectedChartId?.value || ""}
|
||||||
|
per={selectedChartId?.per || ""}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Options Container */}
|
|
||||||
<div className="optionsContainer">
|
<div className="optionsContainer">
|
||||||
{/* Name Dropdown */}
|
<div className="option">
|
||||||
|
<span>Element to Style</span>
|
||||||
|
<RegularDropDown
|
||||||
|
header={selectedElementToStyle || "Select Element"}
|
||||||
|
options={
|
||||||
|
elementOptions.length > 0
|
||||||
|
? elementOptions.map((opt) => opt.display)
|
||||||
|
: ["No elements found"]
|
||||||
|
}
|
||||||
|
onSelect={(value) => {
|
||||||
|
const selected = elementOptions.find(
|
||||||
|
(opt) => opt.display === value
|
||||||
|
);
|
||||||
|
setSelectedElementToStyle(selected?.value || null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Name</span>
|
<span>Name</span>
|
||||||
<RegularDropDown
|
<input
|
||||||
header={selectedChartId?.title || "Select Name"}
|
type="text"
|
||||||
options={["Option 1", "Option 2", "Option 3"]}
|
value={nameInput}
|
||||||
onSelect={(value) => {
|
onChange={handleNameChange}
|
||||||
setSelectedName(value);
|
placeholder="Enter name"
|
||||||
handleUpdateWidget({ title: value });
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Element Dropdown */}
|
{selectedChartId?.title && (
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Element</span>
|
<span>Chart Type</span>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedChartId?.type || "Select Element"}
|
header={selectedChartId?.type || "Select Type"}
|
||||||
options={["bar", "line", "pie", "doughnut", "radar", "polarArea"]} // Valid chart types
|
options={["bar", "line", "pie", "doughnut", "radar", "polarArea"]}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
setSelectedElement(value);
|
handleUpdateWidget({ type: value });
|
||||||
handleUpdateWidget({ type: value });
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
{/* Font Family Dropdown */}
|
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Font Family</span>
|
<span>Font Family</span>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedChartId?.fontFamily || "Select Font"}
|
header={selectedChartId?.fontFamily || "Select Font"}
|
||||||
options={["Arial", "Roboto", "Sans-serif"]}
|
options={["Arial", "Roboto", "Sans-serif"]}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => setSelectedFont(value)}
|
||||||
setSelectedFont(value);
|
|
||||||
handleUpdateWidget({ fontFamily: value });
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Size Dropdown */}
|
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Size</span>
|
<span>Size</span>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedChartId?.fontSize || "Select Size"}
|
header={selectedChartId?.fontSize || "Select Size"}
|
||||||
options={["12px", "14px", "16px", "18px"]}
|
options={["12px", "14px", "16px", "18px"]}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => setSelectedSize(value)}
|
||||||
setSelectedSize(value);
|
|
||||||
handleUpdateWidget({ fontSize: value });
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Weight Dropdown */}
|
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<span>Weight</span>
|
<span>Weight</span>
|
||||||
<RegularDropDown
|
<RegularDropDown
|
||||||
header={selectedChartId?.fontWeight || "Select Weight"}
|
header={selectedChartId?.fontWeight || "Select Weight"}
|
||||||
options={["Light", "Regular", "Bold"]}
|
options={["Light", "Regular", "Bold"]}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => setSelectedWeight(value)}
|
||||||
setSelectedWeight(value);
|
|
||||||
handleUpdateWidget({ fontWeight: value });
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Element Color Picker */}
|
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<div
|
<div
|
||||||
className="header"
|
className="header"
|
||||||
onClick={() => setShowColorPicker((prev) => !prev)}
|
onClick={() => setShowColorPicker((prev) => !prev)}
|
||||||
>
|
>
|
||||||
<span>Element Color</span>
|
<span>Element Color</span>
|
||||||
<div className="icon">▾</div>{" "}
|
<div className="icon">▾</div>
|
||||||
{/* Change icon based on the visibility */}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Show color picker only when 'showColorPicker' is true */}
|
|
||||||
{showColorPicker && (
|
{showColorPicker && (
|
||||||
<div className="colorDisplayer">
|
<div className="colorDisplayer">
|
||||||
<input
|
<input
|
||||||
|
@ -183,20 +287,21 @@ const Design = () => {
|
||||||
value={elementColor}
|
value={elementColor}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setElementColor(e.target.value);
|
setElementColor(e.target.value);
|
||||||
handleUpdateWidget({
|
if (selectedChartId?.data) {
|
||||||
data: {
|
handleUpdateWidget({
|
||||||
labels: selectedChartId?.data?.labels || [],
|
data: {
|
||||||
datasets: [
|
...selectedChartId.data,
|
||||||
{
|
datasets: [
|
||||||
...selectedChartId?.data?.datasets[0],
|
{
|
||||||
backgroundColor: e.target.value, // Update the element color
|
...selectedChartId.data.datasets[0],
|
||||||
},
|
backgroundColor: e.target.value,
|
||||||
],
|
},
|
||||||
},
|
],
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* Display the selected color value */}
|
|
||||||
<span style={{ marginLeft: "10px" }}>{elementColor}</span>
|
<span style={{ marginLeft: "10px" }}>{elementColor}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -438,7 +438,6 @@ const Tools: React.FC = () => {
|
||||||
}`}
|
}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsPlaying(!isPlaying);
|
setIsPlaying(!isPlaying);
|
||||||
setActiveTool("play");
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PlayIcon isActive={activeTool === "play"} />
|
<PlayIcon isActive={activeTool === "play"} />
|
||||||
|
|
|
@ -124,8 +124,8 @@ const Panel: React.FC<PanelProps> = ({
|
||||||
selectedZone.widgets.filter((w) => w.panel === panel).length;
|
selectedZone.widgets.filter((w) => w.panel === panel).length;
|
||||||
|
|
||||||
const calculatePanelCapacity = (panel: Side) => {
|
const calculatePanelCapacity = (panel: Side) => {
|
||||||
const CHART_WIDTH = 150;
|
const CHART_WIDTH = 170;
|
||||||
const CHART_HEIGHT = 150;
|
const CHART_HEIGHT = 170;
|
||||||
const FALLBACK_HORIZONTAL_CAPACITY = 5;
|
const FALLBACK_HORIZONTAL_CAPACITY = 5;
|
||||||
const FALLBACK_VERTICAL_CAPACITY = 3;
|
const FALLBACK_VERTICAL_CAPACITY = 3;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
export function determinePosition(
|
export function determinePosition(
|
||||||
canvasRect: DOMRect,
|
canvasRect: DOMRect,
|
||||||
relativeX: number,
|
relativeX: number,
|
||||||
|
@ -12,6 +11,23 @@ export function determinePosition(
|
||||||
const centerX = canvasRect.width / 2;
|
const centerX = canvasRect.width / 2;
|
||||||
const centerY = canvasRect.height / 2;
|
const centerY = canvasRect.height / 2;
|
||||||
|
|
||||||
|
// Define a threshold for considering a point as "centered"
|
||||||
|
const centerThreshold = 10; // Adjust this value as needed
|
||||||
|
|
||||||
|
// Check if the point is within the center threshold
|
||||||
|
const isCenterX = Math.abs(relativeX - centerX) <= centerThreshold;
|
||||||
|
const isCenterY = Math.abs(relativeY - centerY) <= centerThreshold;
|
||||||
|
|
||||||
|
// If the point is centered, return a special "centered" position
|
||||||
|
if (isCenterX && isCenterY) {
|
||||||
|
return {
|
||||||
|
top: "auto",
|
||||||
|
left: "auto",
|
||||||
|
right: "auto",
|
||||||
|
bottom: "auto",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let position: {
|
let position: {
|
||||||
top: number | "auto";
|
top: number | "auto";
|
||||||
left: number | "auto";
|
left: number | "auto";
|
||||||
|
@ -21,7 +37,7 @@ export function determinePosition(
|
||||||
|
|
||||||
if (relativeY < centerY) {
|
if (relativeY < centerY) {
|
||||||
if (relativeX < centerX) {
|
if (relativeX < centerX) {
|
||||||
|
// Top-left quadrant
|
||||||
position = {
|
position = {
|
||||||
top: relativeY - 41.5,
|
top: relativeY - 41.5,
|
||||||
left: relativeX - 125,
|
left: relativeX - 125,
|
||||||
|
@ -29,7 +45,7 @@ export function determinePosition(
|
||||||
bottom: "auto",
|
bottom: "auto",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
// Top-right quadrant
|
||||||
position = {
|
position = {
|
||||||
top: relativeY - 41.5,
|
top: relativeY - 41.5,
|
||||||
right: canvasRect.width - relativeX - 125,
|
right: canvasRect.width - relativeX - 125,
|
||||||
|
@ -39,7 +55,7 @@ export function determinePosition(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (relativeX < centerX) {
|
if (relativeX < centerX) {
|
||||||
|
// Bottom-left quadrant
|
||||||
position = {
|
position = {
|
||||||
bottom: canvasRect.height - relativeY - 41.5,
|
bottom: canvasRect.height - relativeY - 41.5,
|
||||||
left: relativeX - 125,
|
left: relativeX - 125,
|
||||||
|
@ -47,7 +63,7 @@ export function determinePosition(
|
||||||
top: "auto",
|
top: "auto",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
// Bottom-right quadrant
|
||||||
position = {
|
position = {
|
||||||
bottom: canvasRect.height - relativeY - 41.5,
|
bottom: canvasRect.height - relativeY - 41.5,
|
||||||
right: canvasRect.width - relativeX - 125,
|
right: canvasRect.width - relativeX - 125,
|
||||||
|
|
|
@ -32,14 +32,22 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
||||||
listType = "default",
|
listType = "default",
|
||||||
remove,
|
remove,
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState<boolean>(defaultOpen);
|
const [isOpen, setIsOpen] = useState<boolean>(defaultOpen);
|
||||||
const { zones, setZones } = useZones()
|
const { zones, setZones } = useZones();
|
||||||
|
|
||||||
const handleToggle = () => {
|
const handleToggle = () => {
|
||||||
setIsOpen((prev) => !prev); // Toggle the state
|
setIsOpen((prev) => !prev); // Toggle the state
|
||||||
};
|
};
|
||||||
const [zoneDataList, setZoneDataList] = useState<{ id: string; name: string }[]>([]);
|
|
||||||
|
interface Asset {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [zoneDataList, setZoneDataList] = useState<
|
||||||
|
{ id: string; name: string; assets: Asset[] }[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -53,12 +61,65 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
||||||
// { id: "70fa55cd-b5c9-4f80-a8c4-6319af3bfb4e", name: "zone6" },
|
// { id: "70fa55cd-b5c9-4f80-a8c4-6319af3bfb4e", name: "zone6" },
|
||||||
// ])
|
// ])
|
||||||
|
|
||||||
|
const value = (zones || []).map(
|
||||||
|
(val: { zoneId: string; zoneName: string }) => ({
|
||||||
|
id: val.zoneId,
|
||||||
|
name: val.zoneName,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setZoneDataList([
|
||||||
|
{
|
||||||
|
id: "zone1",
|
||||||
|
name: "Zone 1",
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
id: "asset1",
|
||||||
|
name: "Asset 1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "asset2",
|
||||||
|
name: "Asset 2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "asset3",
|
||||||
|
name: "Asset 3",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "zone2",
|
||||||
|
name: "Zone 2",
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
id: "asset4",
|
||||||
|
name: "Asset 4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "asset5",
|
||||||
|
name: "Asset 5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "asset6",
|
||||||
|
name: "Asset 6",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "zone3",
|
||||||
|
name: "Zone 3",
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
id: "asset7",
|
||||||
|
name: "Asset 7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "asset8",
|
||||||
|
name: "Asset 8",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
const value = (zones || []).map((val: { zoneId: string; zoneName: string }) => ({
|
|
||||||
id: val.zoneId,
|
|
||||||
name: val.zoneName
|
|
||||||
}));
|
|
||||||
setZoneDataList(prev => (JSON.stringify(prev) !== JSON.stringify(value) ? value : prev));
|
|
||||||
}, [zones]);
|
}, [zones]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -101,6 +162,7 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
||||||
value="Buildings"
|
value="Buildings"
|
||||||
showKebabMenu={false}
|
showKebabMenu={false}
|
||||||
showAddIcon={false}
|
showAddIcon={false}
|
||||||
|
items={zoneDataList}
|
||||||
/>
|
/>
|
||||||
<DropDownList
|
<DropDownList
|
||||||
value="Zones"
|
value="Zones"
|
||||||
|
|
|
@ -1,20 +1,44 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import RenameInput from "../inputs/RenameInput";
|
import RenameInput from "../inputs/RenameInput";
|
||||||
import { EyeIcon, LockIcon, RmoveIcon } from "../../icons/ExportCommonIcons";
|
|
||||||
import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
||||||
import { getZoneData } from "../../../services/realTimeVisulization/zoneData/getZones";
|
import { getZoneData } from "../../../services/realTimeVisulization/zoneData/getZones";
|
||||||
import useModuleStore, { useSubModuleStore } from "../../../store/useModuleStore";
|
import useModuleStore, {
|
||||||
|
useSubModuleStore,
|
||||||
|
} from "../../../store/useModuleStore";
|
||||||
|
import {
|
||||||
|
ArrowIcon,
|
||||||
|
EyeIcon,
|
||||||
|
LockIcon,
|
||||||
|
RmoveIcon,
|
||||||
|
} from "../../icons/ExportCommonIcons";
|
||||||
|
|
||||||
|
interface Asset {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ZoneItem {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
assets?: Asset[];
|
||||||
|
}
|
||||||
|
|
||||||
interface ListProps {
|
interface ListProps {
|
||||||
items?: { id: string; name: string }[]; // Optional array of items to render
|
items?: ZoneItem[];
|
||||||
placeholder?: string; // Optional placeholder text
|
placeholder?: string;
|
||||||
remove?: boolean;
|
remove?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
|
console.log("items: ", items);
|
||||||
const { activeModule, setActiveModule } = useModuleStore();
|
const { activeModule, setActiveModule } = useModuleStore();
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
const { setSubModule } = useSubModuleStore();
|
const { setSubModule } = useSubModuleStore();
|
||||||
|
const [expandedZones, setExpandedZones] = useState<Record<string, boolean>>(
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
useSelectedZoneStore.getState().setSelectedZone({
|
useSelectedZoneStore.getState().setSelectedZone({
|
||||||
zoneName: "",
|
zoneName: "",
|
||||||
|
@ -28,10 +52,15 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
});
|
});
|
||||||
}, [activeModule]);
|
}, [activeModule]);
|
||||||
|
|
||||||
|
const toggleZoneExpansion = (zoneId: string) => {
|
||||||
|
setExpandedZones((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[zoneId]: !prev[zoneId],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
async function handleSelectZone(id: string) {
|
async function handleSelectZone(id: string) {
|
||||||
try {
|
try {
|
||||||
// Avoid re-fetching if the same zone is already selected
|
|
||||||
if (selectedZone?.zoneId === id) {
|
if (selectedZone?.zoneId === id) {
|
||||||
console.log("Zone is already selected:", selectedZone.zoneName);
|
console.log("Zone is already selected:", selectedZone.zoneName);
|
||||||
return;
|
return;
|
||||||
|
@ -65,27 +94,74 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
<>
|
<>
|
||||||
{items.length > 0 ? (
|
{items.length > 0 ? (
|
||||||
<ul className="list-wrapper">
|
<ul className="list-wrapper">
|
||||||
{items.map((item, index) => (
|
{items.map((item) => (
|
||||||
<li key={index} className="list-container">
|
<React.Fragment key={`zone-${item.id}`}>
|
||||||
<div className="list-item">
|
<li className="list-container">
|
||||||
<div className="value" onClick={() => handleSelectZone(item.id)}>
|
<div className="list-item">
|
||||||
<RenameInput value={item.name} />
|
<div className="zone-header">
|
||||||
</div>
|
<div
|
||||||
<div className="options-container">
|
className="value"
|
||||||
<div className="lock option">
|
onClick={() => handleSelectZone(item.id)}
|
||||||
<LockIcon isLocked />
|
>
|
||||||
</div>
|
<RenameInput value={item.name} />
|
||||||
<div className="visibe option">
|
|
||||||
<EyeIcon isClosed />
|
|
||||||
</div>
|
|
||||||
{remove && (
|
|
||||||
<div className="remove option">
|
|
||||||
<RmoveIcon />
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
|
<div className="options-container">
|
||||||
|
<div className="lock option">
|
||||||
|
<LockIcon isLocked />
|
||||||
|
</div>
|
||||||
|
<div className="visibe option">
|
||||||
|
<EyeIcon isClosed />
|
||||||
|
</div>
|
||||||
|
{remove && (
|
||||||
|
<div className="remove option">
|
||||||
|
<RmoveIcon />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{item.assets && item.assets.length > 0 && (
|
||||||
|
<div
|
||||||
|
className="expand-icon option"
|
||||||
|
onClick={() => toggleZoneExpansion(item.id)}
|
||||||
|
>
|
||||||
|
<ArrowIcon />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</li>
|
||||||
</li>
|
{/* Nested assets list - only shown when expanded */}
|
||||||
|
{item.assets &&
|
||||||
|
item.assets.length > 0 &&
|
||||||
|
expandedZones[item.id] && (
|
||||||
|
<ul className="asset-list">
|
||||||
|
{item.assets.map((asset) => (
|
||||||
|
<li
|
||||||
|
key={`asset-${asset.id}`}
|
||||||
|
className="list-container asset-item"
|
||||||
|
>
|
||||||
|
<div className="list-item">
|
||||||
|
<div className="value">
|
||||||
|
<RenameInput value={asset.name} />
|
||||||
|
</div>
|
||||||
|
<div className="options-container">
|
||||||
|
<div className="lock option">
|
||||||
|
<LockIcon isLocked />
|
||||||
|
</div>
|
||||||
|
<div className="visibe option">
|
||||||
|
<EyeIcon isClosed />
|
||||||
|
</div>
|
||||||
|
{remove && (
|
||||||
|
<div className="remove option">
|
||||||
|
<RmoveIcon />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useState, useRef, useEffect } from "react";
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons";
|
import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons";
|
||||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
|
import { useActiveTool } from "../../../store/store";
|
||||||
|
|
||||||
const SimulationPlayer: React.FC = () => {
|
const SimulationPlayer: React.FC = () => {
|
||||||
const [speed, setSpeed] = useState<number>(1);
|
const [speed, setSpeed] = useState<number>(1);
|
||||||
|
@ -8,6 +9,7 @@ const SimulationPlayer: React.FC = () => {
|
||||||
const { setIsPlaying } = usePlayButtonStore();
|
const { setIsPlaying } = usePlayButtonStore();
|
||||||
const sliderRef = useRef<HTMLDivElement>(null);
|
const sliderRef = useRef<HTMLDivElement>(null);
|
||||||
const isDragging = useRef(false);
|
const isDragging = useRef(false);
|
||||||
|
const { setActiveTool } = useActiveTool();
|
||||||
|
|
||||||
// Button functions
|
// Button functions
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
|
@ -19,6 +21,7 @@ const SimulationPlayer: React.FC = () => {
|
||||||
const handleExit = () => {
|
const handleExit = () => {
|
||||||
setPlaySimulation(false);
|
setPlaySimulation(false);
|
||||||
setIsPlaying(false);
|
setIsPlaying(false);
|
||||||
|
setActiveTool("cursor")
|
||||||
};
|
};
|
||||||
|
|
||||||
// Slider functions starts
|
// Slider functions starts
|
||||||
|
|
|
@ -19,7 +19,9 @@ const Agv = ({
|
||||||
}) => {
|
}) => {
|
||||||
const [pathPoints, setPathPoints] = useState<
|
const [pathPoints, setPathPoints] = useState<
|
||||||
{
|
{
|
||||||
uuid: string;
|
modelUuid: string;
|
||||||
|
modelSpeed: number;
|
||||||
|
bufferTime: number;
|
||||||
points: { x: number; y: number; z: number }[];
|
points: { x: number; y: number; z: number }[];
|
||||||
}[]
|
}[]
|
||||||
>([]);
|
>([]);
|
||||||
|
@ -32,6 +34,7 @@ const Agv = ({
|
||||||
(val: any) => val.modelName === "agv"
|
(val: any) => val.modelName === "agv"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log("agvModels: ", agvModels);
|
||||||
let findMesh = agvModels.filter(
|
let findMesh = agvModels.filter(
|
||||||
(val: any) =>
|
(val: any) =>
|
||||||
val.modeluuid === selectedActionSphere?.path?.modeluuid &&
|
val.modeluuid === selectedActionSphere?.path?.modeluuid &&
|
||||||
|
@ -49,8 +52,9 @@ const Agv = ({
|
||||||
"y" in findMesh[0].point.actions.end
|
"y" in findMesh[0].point.actions.end
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
uuid: findMesh[0].modeluuid, // Ensure it's a number
|
modelUuid: findMesh[0].modeluuid, // Ensure it's a number
|
||||||
|
modelSpeed: findMesh[0].point.speed,
|
||||||
|
bufferTime: findMesh[0].point.actions.buffer,
|
||||||
points: [
|
points: [
|
||||||
{
|
{
|
||||||
x: findMesh[0].position[0],
|
x: findMesh[0].position[0],
|
||||||
|
@ -72,15 +76,29 @@ const Agv = ({
|
||||||
]
|
]
|
||||||
: [];
|
: [];
|
||||||
if (result.length > 0) {
|
if (result.length > 0) {
|
||||||
|
// setPathPoints((prev) => [...prev, ...result]);
|
||||||
setPathPoints((prev) => {
|
setPathPoints((prev) => {
|
||||||
const existingUUIDs = new Set(prev.map((item) => item.uuid));
|
const existingIndex = prev.findIndex(
|
||||||
const newItems = result.filter(
|
(item) => item.modelUuid === result[0].modelUuid
|
||||||
(item) => !existingUUIDs.has(item.uuid)
|
|
||||||
);
|
);
|
||||||
return [...prev, ...newItems];
|
|
||||||
|
if (existingIndex !== -1) {
|
||||||
|
const updatedPathPoints = [...prev];
|
||||||
|
updatedPathPoints[existingIndex] = result[0];
|
||||||
|
return updatedPathPoints;
|
||||||
|
} else {
|
||||||
|
return [...prev, ...result];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// setPathPoints((prev) => {
|
||||||
|
// const existingUUIDs = new Set(prev.map((item) => item.uuid));
|
||||||
|
// const newItems = result.filter(
|
||||||
|
// (item) => !existingUUIDs.has(item.uuid)
|
||||||
|
// );
|
||||||
|
// return [...prev, ...newItems];
|
||||||
|
// });
|
||||||
}, [simulationPaths, selectedActionSphere]);
|
}, [simulationPaths, selectedActionSphere]);
|
||||||
|
|
||||||
let groupRef = useRef() as Types.RefGroup;
|
let groupRef = useRef() as Types.RefGroup;
|
||||||
|
@ -96,12 +114,40 @@ const Agv = ({
|
||||||
plane={plane}
|
plane={plane}
|
||||||
/>
|
/>
|
||||||
{pathPoints.map((pair, i) => (
|
{pathPoints.map((pair, i) => (
|
||||||
<PathNavigator
|
<>
|
||||||
navMesh={navMesh}
|
<PathNavigator
|
||||||
selectedPoints={pair.points}
|
navMesh={navMesh}
|
||||||
id={pair.uuid}
|
selectedPoints={pair.points}
|
||||||
key={i}
|
id={pair.modelUuid}
|
||||||
/>
|
key={i}
|
||||||
|
speed={pair.modelSpeed}
|
||||||
|
bufferTime={pair.bufferTime}
|
||||||
|
/>
|
||||||
|
{/* {pair.points.length > 2 && (
|
||||||
|
<>
|
||||||
|
<mesh
|
||||||
|
position={[
|
||||||
|
pair.points[1].x,
|
||||||
|
pair.points[1].y,
|
||||||
|
pair.points[1].z,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<sphereGeometry args={[0.3, 15, 15]} />
|
||||||
|
<meshStandardMaterial color="red" />
|
||||||
|
</mesh>
|
||||||
|
<mesh
|
||||||
|
position={[
|
||||||
|
pair.points[2].x,
|
||||||
|
pair.points[2].y,
|
||||||
|
pair.points[2].z,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<sphereGeometry args={[0.3, 15, 15]} />
|
||||||
|
<meshStandardMaterial color="red" />
|
||||||
|
</mesh>
|
||||||
|
</>
|
||||||
|
)} */}
|
||||||
|
</>
|
||||||
))}
|
))}
|
||||||
<group ref={groupRef} visible={false} name="Meshes"></group>
|
<group ref={groupRef} visible={false} name="Meshes"></group>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -3,30 +3,38 @@ import * as THREE from "three";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { NavMeshQuery } from "@recast-navigation/core";
|
import { NavMeshQuery } from "@recast-navigation/core";
|
||||||
import { Line } from "@react-three/drei";
|
import { Line } from "@react-three/drei";
|
||||||
import { useTh } from "leva/dist/declarations/src/styles";
|
|
||||||
import { useActiveTool } from "../../../store/store";
|
import { useActiveTool } from "../../../store/store";
|
||||||
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
|
|
||||||
// Define interface for props
|
|
||||||
interface PathNavigatorProps {
|
interface PathNavigatorProps {
|
||||||
navMesh: any;
|
navMesh: any;
|
||||||
selectedPoints: any;
|
selectedPoints: any;
|
||||||
id: string;
|
id: string;
|
||||||
|
speed: number;
|
||||||
|
bufferTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PathNavigator({
|
export default function PathNavigator({
|
||||||
navMesh,
|
navMesh,
|
||||||
selectedPoints,
|
selectedPoints,
|
||||||
id,
|
id,
|
||||||
|
speed,
|
||||||
|
bufferTime,
|
||||||
}: PathNavigatorProps) {
|
}: PathNavigatorProps) {
|
||||||
const [path, setPath] = useState<[number, number, number][]>([]);
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
const progressRef = useRef(0);
|
const progressRef = useRef(0);
|
||||||
const distancesRef = useRef<number[]>([]);
|
const distancesRef = useRef<number[]>([]);
|
||||||
const totalDistanceRef = useRef(0);
|
const totalDistanceRef = useRef(0);
|
||||||
const currentSegmentIndex = useRef(0);
|
const currentSegmentIndex = useRef(0);
|
||||||
|
const [stop, setStop] = useState<boolean>(true);
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const { activeTool } = useActiveTool();
|
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||||
const [startPoint, setStartPoint] = useState(new THREE.Vector3());
|
const [startPoint, setStartPoint] = useState(new THREE.Vector3());
|
||||||
const meshRef = useRef<THREE.Mesh | null>(null);
|
const isWaiting = useRef<boolean>(false); // Flag to track waiting state
|
||||||
|
const delayTime = bufferTime;
|
||||||
|
|
||||||
|
const movingForward = useRef<boolean>(true); // Tracks whether the object is moving forward
|
||||||
|
// Compute distances and total distance when the path changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!scene || !id || path.length < 2) return;
|
if (!scene || !id || path.length < 2) return;
|
||||||
|
|
||||||
|
@ -39,19 +47,17 @@ export default function PathNavigator({
|
||||||
distances.push(segmentDistance);
|
distances.push(segmentDistance);
|
||||||
totalDistance += segmentDistance;
|
totalDistance += segmentDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
distancesRef.current = distances;
|
distancesRef.current = distances;
|
||||||
totalDistanceRef.current = totalDistance;
|
totalDistanceRef.current = totalDistance;
|
||||||
progressRef.current = 0; // Reset progress when the path changes
|
progressRef.current = 0;
|
||||||
}, [path]);
|
}, [path]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!navMesh || selectedPoints.length === 0) return;
|
if (!navMesh || selectedPoints.length === 0) return;
|
||||||
|
|
||||||
// Flatten the selectedPoints array into a single list of points
|
|
||||||
const allPoints = selectedPoints.flat();
|
const allPoints = selectedPoints.flat();
|
||||||
|
|
||||||
// Compute paths between consecutive points
|
|
||||||
const computedPath: [number, number, number][] = [];
|
const computedPath: [number, number, number][] = [];
|
||||||
|
|
||||||
for (let i = 0; i < allPoints.length - 1; i++) {
|
for (let i = 0; i < allPoints.length - 1; i++) {
|
||||||
const start = allPoints[i];
|
const start = allPoints[i];
|
||||||
setStartPoint(
|
setStartPoint(
|
||||||
|
@ -64,36 +70,35 @@ export default function PathNavigator({
|
||||||
const navMeshQuery = new NavMeshQuery(navMesh);
|
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||||
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
||||||
|
|
||||||
if (segmentPath && segmentPath.length > 0) {
|
if (!segmentPath || segmentPath.length === 0) {
|
||||||
computedPath.push(
|
continue;
|
||||||
...segmentPath.map(({ x, y, z }): [number, number, number] => [
|
|
||||||
x,
|
|
||||||
y + 0.1,
|
|
||||||
z,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
computedPath.push(
|
||||||
|
...segmentPath.map(({ x, y, z }): [number, number, number] => [
|
||||||
|
x,
|
||||||
|
y + 0.1,
|
||||||
|
z,
|
||||||
|
])
|
||||||
|
);
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the full computed path
|
|
||||||
|
|
||||||
if (computedPath.length > 0) {
|
if (computedPath.length > 0) {
|
||||||
setPath(computedPath);
|
setPath(computedPath);
|
||||||
currentSegmentIndex.current = 0; // Reset to the first segment
|
currentSegmentIndex.current = 0;
|
||||||
}
|
}
|
||||||
}, [selectedPoints, navMesh, path]);
|
}, [selectedPoints, navMesh]);
|
||||||
|
|
||||||
useFrame((_, delta) => {
|
useFrame((_, delta) => {
|
||||||
if (!scene || !id || path.length < 2) return;
|
if (!scene || !id || path.length < 2) return;
|
||||||
|
|
||||||
// Find the object in the scene
|
// Find the object in the scene by its UUID
|
||||||
const findObject = scene.getObjectByProperty("uuid", id);
|
const findObject = scene.getObjectByProperty("uuid", id);
|
||||||
if (activeTool === "play") {
|
if (!findObject) return;
|
||||||
if (!findObject) return;
|
|
||||||
|
|
||||||
const speed = 5;
|
if (isPlaying) {
|
||||||
progressRef.current += delta * speed;
|
const fast = speed;
|
||||||
|
progressRef.current += delta * fast;
|
||||||
|
|
||||||
let coveredDistance = progressRef.current;
|
let coveredDistance = progressRef.current;
|
||||||
let accumulatedDistance = 0;
|
let accumulatedDistance = 0;
|
||||||
|
@ -108,9 +113,24 @@ export default function PathNavigator({
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the object has reached the end of the path, stop moving
|
|
||||||
if (index >= distancesRef.current.length) {
|
if (index >= distancesRef.current.length) {
|
||||||
progressRef.current = totalDistanceRef.current;
|
progressRef.current = totalDistanceRef.current;
|
||||||
|
|
||||||
|
if (!isWaiting.current) {
|
||||||
|
isWaiting.current = true; // Set waiting flag
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
progressRef.current = 0; // Reset progress
|
||||||
|
movingForward.current = !movingForward.current; // Toggle direction
|
||||||
|
|
||||||
|
// Reverse the path and distances arrays
|
||||||
|
path.reverse();
|
||||||
|
distancesRef.current.reverse();
|
||||||
|
|
||||||
|
// Reset the waiting flag
|
||||||
|
isWaiting.current = false;
|
||||||
|
}, delayTime * 1000); // Convert seconds to milliseconds
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,31 +139,35 @@ export default function PathNavigator({
|
||||||
const end = new THREE.Vector3(...path[index + 1]);
|
const end = new THREE.Vector3(...path[index + 1]);
|
||||||
const segmentDistance = distancesRef.current[index];
|
const segmentDistance = distancesRef.current[index];
|
||||||
|
|
||||||
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
const t = Math.min(
|
||||||
|
(coveredDistance - accumulatedDistance) / segmentDistance,
|
||||||
|
1
|
||||||
|
); // Clamp t to avoid overshooting
|
||||||
const position = start.clone().lerp(end, t);
|
const position = start.clone().lerp(end, t);
|
||||||
findObject.position.copy(position);
|
findObject.position.copy(position);
|
||||||
|
|
||||||
// Rotate the object to face the direction of movement
|
// Rotate the object to face the direction of movement
|
||||||
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
||||||
const targetQuaternion = new THREE.Quaternion().setFromUnitVectors(
|
const targetYRotation = Math.atan2(direction.x, direction.z);
|
||||||
new THREE.Vector3(0, 0, 1), // Assuming forward direction is (0, 0, 1)
|
findObject.rotation.y += (targetYRotation - findObject.rotation.y) * 0.1;
|
||||||
direction
|
} else {
|
||||||
);
|
findObject.position.copy(startPoint);
|
||||||
findObject.quaternion.slerp(targetQuaternion, 0.1); // Smoothly interpolate rotation
|
|
||||||
} else if (activeTool === "cursor") {
|
|
||||||
findObject?.position.copy(startPoint);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{path.length > 0 && <Line points={path} color="blue" lineWidth={3} />}
|
{path.length > 0 && (
|
||||||
{/* {path.length > 0 && (
|
<>
|
||||||
<mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}>
|
<Line points={path} color="blue" lineWidth={3} />
|
||||||
<boxGeometry args={[1, 1, 1]} />
|
{selectedPoints.map((val: any, i: any) => (
|
||||||
<meshNormalMaterial />
|
<mesh position={[val[0], val[1] + 1, val[2]]} key={i}>
|
||||||
</mesh>
|
<sphereGeometry args={[50, 5, 5]} />
|
||||||
)} */}
|
<meshBasicMaterial color={"red"} />
|
||||||
|
</mesh>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ async function addAssetModel(
|
||||||
socket: Socket<any>,
|
socket: Socket<any>,
|
||||||
selectedItem: any,
|
selectedItem: any,
|
||||||
setSelectedItem: any,
|
setSelectedItem: any,
|
||||||
|
setSimulationPaths: any,
|
||||||
plane: Types.RefMesh,
|
plane: Types.RefMesh,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ async function addAssetModel(
|
||||||
const cachedModel = THREE.Cache.get(selectedItem.id);
|
const cachedModel = THREE.Cache.get(selectedItem.id);
|
||||||
if (cachedModel) {
|
if (cachedModel) {
|
||||||
// console.log(`[Cache] Fetching ${selectedItem.name}`);
|
// console.log(`[Cache] Fetching ${selectedItem.name}`);
|
||||||
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
|
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
||||||
|
@ -77,7 +78,7 @@ async function addAssetModel(
|
||||||
URL.revokeObjectURL(blobUrl);
|
URL.revokeObjectURL(blobUrl);
|
||||||
THREE.Cache.remove(blobUrl);
|
THREE.Cache.remove(blobUrl);
|
||||||
THREE.Cache.add(selectedItem.id, gltf);
|
THREE.Cache.add(selectedItem.id, gltf);
|
||||||
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
|
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
||||||
|
@ -89,7 +90,7 @@ async function addAssetModel(
|
||||||
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
||||||
await storeGLTF(selectedItem.id, modelBlob);
|
await storeGLTF(selectedItem.id, modelBlob);
|
||||||
THREE.Cache.add(selectedItem.id, gltf);
|
THREE.Cache.add(selectedItem.id, gltf);
|
||||||
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
|
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationPaths, socket);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
|
||||||
|
@ -112,10 +113,11 @@ async function handleModelLoad(
|
||||||
tempLoader: Types.RefMesh,
|
tempLoader: Types.RefMesh,
|
||||||
isTempLoader: Types.RefBoolean,
|
isTempLoader: Types.RefBoolean,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
|
setSimulationPaths: any,
|
||||||
socket: Socket<any>
|
socket: Socket<any>
|
||||||
) {
|
) {
|
||||||
const model = gltf.scene.clone();
|
const model = gltf.scene.clone();
|
||||||
model.userData = { name: selectedItem.name, modelId: selectedItem.id };
|
model.userData = { name: selectedItem.name, modelId: selectedItem.id, modeluuid: model.uuid };
|
||||||
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
|
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
|
||||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||||
|
|
||||||
|
@ -152,7 +154,7 @@ async function handleModelLoad(
|
||||||
if (res.type === "Conveyor") {
|
if (res.type === "Conveyor") {
|
||||||
const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
|
const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID());
|
||||||
|
|
||||||
const eventData: Extract<Types.FloorItemType['eventData'], { type: 'Conveyor' }> = {
|
const backendEventData: Extract<Types.FloorItemType['eventData'], { type: 'Conveyor' }> = {
|
||||||
type: 'Conveyor',
|
type: 'Conveyor',
|
||||||
points: res.points.map((point: any, index: number) => ({
|
points: res.points.map((point: any, index: number) => ({
|
||||||
uuid: pointUUIDs[index],
|
uuid: pointUUIDs[index],
|
||||||
|
@ -176,49 +178,94 @@ async function handleModelLoad(
|
||||||
speed: 'Inherit'
|
speed: 'Inherit'
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('eventData: ', eventData);
|
// API
|
||||||
newFloorItem.eventData = eventData;
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// newFloorItem.modeluuid,
|
||||||
|
// newFloorItem.modelname,
|
||||||
|
// newFloorItem.modelfileID,
|
||||||
|
// newFloorItem.position,
|
||||||
|
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// newFloorItem.eventData
|
||||||
|
// );
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: backendEventData,
|
||||||
|
socketId: socket.id
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('data: ', data);
|
||||||
|
setFloorItems((prevItems) => {
|
||||||
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||||
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
|
||||||
|
const eventData: any = backendEventData;
|
||||||
|
eventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
eventData.modelName = newFloorItem.modelname;
|
||||||
|
eventData.position = newFloorItem.position;
|
||||||
|
eventData.rotation = [model.rotation.x, model.rotation.y, model.rotation.z];
|
||||||
|
|
||||||
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||||
|
...(prevEvents || []),
|
||||||
|
eventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// newFloorItem.modeluuid,
|
||||||
|
// newFloorItem.modelname,
|
||||||
|
// newFloorItem.modelfileID,
|
||||||
|
// newFloorItem.position,
|
||||||
|
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||||
|
// false,
|
||||||
|
// true
|
||||||
|
// );
|
||||||
|
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id
|
||||||
|
};
|
||||||
|
|
||||||
|
setFloorItems((prevItems) => {
|
||||||
|
const updatedItems = [...(prevItems || []), newFloorItem];
|
||||||
|
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
||||||
|
return updatedItems;
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setFloorItems((prevItems) => {
|
|
||||||
const updatedItems = [...(prevItems || []), newFloorItem];
|
|
||||||
localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
|
|
||||||
return updatedItems;
|
|
||||||
});
|
|
||||||
|
|
||||||
// API
|
|
||||||
|
|
||||||
// await setFloorItemApi(
|
|
||||||
// organization,
|
|
||||||
// newFloorItem.modeluuid,
|
|
||||||
// newFloorItem.modelname,
|
|
||||||
// newFloorItem.modelfileID,
|
|
||||||
// newFloorItem.position,
|
|
||||||
// { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
|
||||||
// false,
|
|
||||||
// true,
|
|
||||||
// newFloorItem.eventData
|
|
||||||
// );
|
|
||||||
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
organization,
|
|
||||||
modeluuid: newFloorItem.modeluuid,
|
|
||||||
modelname: newFloorItem.modelname,
|
|
||||||
modelfileID: newFloorItem.modelfileID,
|
|
||||||
position: newFloorItem.position,
|
|
||||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
|
|
||||||
isLocked: false,
|
|
||||||
isVisible: true,
|
|
||||||
eventData: newFloorItem.eventData,
|
|
||||||
socketId: socket.id
|
|
||||||
};
|
|
||||||
console.log('data: ', data);
|
|
||||||
|
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
|
||||||
|
|
||||||
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
|
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
|
||||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
|
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
|
||||||
});
|
});
|
||||||
|
|
|
@ -121,7 +121,7 @@ export default async function assetManager(
|
||||||
|
|
||||||
const model = gltf;
|
const model = gltf;
|
||||||
model.uuid = item.modeluuid;
|
model.uuid = item.modeluuid;
|
||||||
model.userData = { name: item.modelname, modelId: item.modelfileID };
|
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
|
||||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||||
model.position.set(...item.position);
|
model.position.set(...item.position);
|
||||||
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
|
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
|
||||||
|
|
|
@ -10,6 +10,7 @@ async function DeleteFloorItems(
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
hoveredDeletableFloorItem: Types.RefMesh,
|
hoveredDeletableFloorItem: Types.RefMesh,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
|
setSimulationPaths: any,
|
||||||
socket: Socket<any>
|
socket: Socket<any>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
||||||
|
@ -74,6 +75,12 @@ async function DeleteFloorItems(
|
||||||
itemsGroup.current.remove(hoveredDeletableFloorItem.current);
|
itemsGroup.current.remove(hoveredDeletableFloorItem.current);
|
||||||
}
|
}
|
||||||
setFloorItems(updatedItems);
|
setFloorItems(updatedItems);
|
||||||
|
|
||||||
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
||||||
|
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== removedItem.modeluuid);
|
||||||
|
return updatedEvents;
|
||||||
|
});
|
||||||
|
|
||||||
toast.success("Model Removed!");
|
toast.success("Model Removed!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
useRenderDistance,
|
useRenderDistance,
|
||||||
useselectedFloorItem,
|
useselectedFloorItem,
|
||||||
useSelectedItem,
|
useSelectedItem,
|
||||||
|
useSimulationPaths,
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
useToggleView,
|
useToggleView,
|
||||||
useTransformMode,
|
useTransformMode,
|
||||||
|
@ -64,6 +65,7 @@ const FloorItemsGroup = ({
|
||||||
const { setselectedFloorItem } = useselectedFloorItem();
|
const { setselectedFloorItem } = useselectedFloorItem();
|
||||||
const { activeTool } = useActiveTool();
|
const { activeTool } = useActiveTool();
|
||||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||||
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const { setLoadingProgress } = useLoadingProgress();
|
const { setLoadingProgress } = useLoadingProgress();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
|
@ -96,16 +98,23 @@ const FloorItemsGroup = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
getFloorAssets(organization).then((data) => {
|
getFloorAssets(organization).then((data) => {
|
||||||
const uniqueItems = (data as Types.FloorItems).filter(
|
if (data.length > 0) {
|
||||||
(item, index, self) =>
|
const uniqueItems = (data as Types.FloorItems).filter(
|
||||||
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
|
(item, index, self) =>
|
||||||
);
|
index === self.findIndex((t) => t.modelfileID === item.modelfileID)
|
||||||
totalAssets = uniqueItems.length;
|
);
|
||||||
if (totalAssets === 0) {
|
totalAssets = uniqueItems.length;
|
||||||
|
if (totalAssets === 0) {
|
||||||
|
updateLoadingProgress(100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gltfLoaderWorker.postMessage({ floorItems: data });
|
||||||
|
} else {
|
||||||
|
console.log('data: ', data);
|
||||||
|
gltfLoaderWorker.postMessage({ floorItems: [] });
|
||||||
|
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths);
|
||||||
updateLoadingProgress(100);
|
updateLoadingProgress(100);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
gltfLoaderWorker.postMessage({ floorItems: data });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
gltfLoaderWorker.onmessage = async (event) => {
|
gltfLoaderWorker.onmessage = async (event) => {
|
||||||
|
@ -122,7 +131,7 @@ const FloorItemsGroup = ({
|
||||||
updateLoadingProgress(progress);
|
updateLoadingProgress(progress);
|
||||||
|
|
||||||
if (loadedAssets === totalAssets) {
|
if (loadedAssets === totalAssets) {
|
||||||
loadInitialFloorItems(itemsGroup, setFloorItems);
|
loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationPaths);
|
||||||
updateLoadingProgress(100);
|
updateLoadingProgress(100);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -240,6 +249,7 @@ const FloorItemsGroup = ({
|
||||||
itemsGroup,
|
itemsGroup,
|
||||||
hoveredDeletableFloorItem,
|
hoveredDeletableFloorItem,
|
||||||
setFloorItems,
|
setFloorItems,
|
||||||
|
setSimulationPaths,
|
||||||
socket
|
socket
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -365,6 +375,7 @@ const FloorItemsGroup = ({
|
||||||
socket,
|
socket,
|
||||||
selectedItem,
|
selectedItem,
|
||||||
setSelectedItem,
|
setSelectedItem,
|
||||||
|
setSimulationPaths,
|
||||||
plane
|
plane
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -408,7 +419,6 @@ const FloorItemsGroup = ({
|
||||||
activeModule,
|
activeModule,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {}, [floorItems]);
|
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
if (controls)
|
if (controls)
|
||||||
|
|
|
@ -105,7 +105,7 @@ export default function SocketResponses({
|
||||||
// console.log(`Getting ${data.data.modelname} from cache`);
|
// console.log(`Getting ${data.data.modelname} from cache`);
|
||||||
const model = cachedModel.scene.clone();
|
const model = cachedModel.scene.clone();
|
||||||
model.uuid = data.data.modeluuid;
|
model.uuid = data.data.modeluuid;
|
||||||
model.userData = { name: data.data.modelname, modelId: data.data.modelFileID };
|
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.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.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
|
||||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||||
|
@ -183,7 +183,7 @@ export default function SocketResponses({
|
||||||
THREE.Cache.remove(url);
|
THREE.Cache.remove(url);
|
||||||
const model = gltf.scene;
|
const model = gltf.scene;
|
||||||
model.uuid = data.data.modeluuid;
|
model.uuid = data.data.modeluuid;
|
||||||
model.userData = { name: data.data.modelname, modelId: data.data.modelFileID };
|
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.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.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z);
|
||||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||||
|
|
|
@ -11,7 +11,8 @@ import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAss
|
||||||
|
|
||||||
async function loadInitialFloorItems(
|
async function loadInitialFloorItems(
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
setFloorItems: Types.setFloorItemSetState
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
|
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!itemsGroup.current) return;
|
if (!itemsGroup.current) return;
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
@ -22,6 +23,8 @@ async function loadInitialFloorItems(
|
||||||
localStorage.setItem("FloorItems", JSON.stringify(items));
|
localStorage.setItem("FloorItems", JSON.stringify(items));
|
||||||
await initializeDB();
|
await initializeDB();
|
||||||
|
|
||||||
|
if (items.message === "floorItems not found") return;
|
||||||
|
|
||||||
if (items) {
|
if (items) {
|
||||||
const storedFloorItems: Types.FloorItems = items;
|
const storedFloorItems: Types.FloorItems = items;
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
|
@ -50,6 +53,7 @@ async function loadInitialFloorItems(
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const item of storedFloorItems) {
|
for (const item of storedFloorItems) {
|
||||||
|
console.log('item: ', item);
|
||||||
if (!item.modelfileID) return;
|
if (!item.modelfileID) return;
|
||||||
const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
|
const itemPosition = new THREE.Vector3(item.position[0], item.position[1], item.position[2]);
|
||||||
let storedPosition;
|
let storedPosition;
|
||||||
|
@ -68,7 +72,7 @@ async function loadInitialFloorItems(
|
||||||
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
||||||
if (cachedModel) {
|
if (cachedModel) {
|
||||||
// console.log(`[Cache] Fetching ${item.modelname}`);
|
// console.log(`[Cache] Fetching ${item.modelname}`);
|
||||||
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems);
|
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
return;
|
return;
|
||||||
|
@ -85,7 +89,7 @@ async function loadInitialFloorItems(
|
||||||
URL.revokeObjectURL(blobUrl);
|
URL.revokeObjectURL(blobUrl);
|
||||||
THREE.Cache.remove(blobUrl);
|
THREE.Cache.remove(blobUrl);
|
||||||
THREE.Cache.add(item.modelfileID!, gltf);
|
THREE.Cache.add(item.modelfileID!, gltf);
|
||||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
},
|
},
|
||||||
|
@ -108,7 +112,7 @@ async function loadInitialFloorItems(
|
||||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||||
await storeGLTF(item.modelfileID!, modelBlob);
|
await storeGLTF(item.modelfileID!, modelBlob);
|
||||||
THREE.Cache.add(item.modelfileID!, gltf);
|
THREE.Cache.add(item.modelfileID!, gltf);
|
||||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationPaths);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
},
|
},
|
||||||
|
@ -121,34 +125,23 @@ async function loadInitialFloorItems(
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// console.log(`Item ${item.modelname} is not near`);
|
// console.log(`Item ${item.modelname} is not near`);
|
||||||
|
setFloorItems((prevItems) => [
|
||||||
|
...(prevItems || []),
|
||||||
|
{
|
||||||
|
modeluuid: item.modeluuid,
|
||||||
|
modelname: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: item.rotation,
|
||||||
|
modelfileID: item.modelfileID,
|
||||||
|
isLocked: item.isLocked,
|
||||||
|
isVisible: item.isVisible,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
if (item.eventData) {
|
if (item.eventData) {
|
||||||
setFloorItems((prevItems) => [
|
processEventData(item, setSimulationPaths);
|
||||||
...(prevItems || []),
|
|
||||||
{
|
|
||||||
modeluuid: item.modeluuid,
|
|
||||||
modelname: item.modelname,
|
|
||||||
position: item.position,
|
|
||||||
rotation: item.rotation,
|
|
||||||
modelfileID: item.modelfileID,
|
|
||||||
isLocked: item.isLocked,
|
|
||||||
isVisible: item.isVisible,
|
|
||||||
// eventData: item.eventData,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
setFloorItems((prevItems) => [
|
|
||||||
...(prevItems || []),
|
|
||||||
{
|
|
||||||
modeluuid: item.modeluuid,
|
|
||||||
modelname: item.modelname,
|
|
||||||
position: item.position,
|
|
||||||
rotation: item.rotation,
|
|
||||||
modelfileID: item.modelfileID,
|
|
||||||
isLocked: item.isLocked,
|
|
||||||
isVisible: item.isVisible,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, () => { });
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, () => { });
|
||||||
}
|
}
|
||||||
|
@ -164,12 +157,13 @@ function processLoadedModel(
|
||||||
gltf: any,
|
gltf: any,
|
||||||
item: Types.FloorItemType,
|
item: Types.FloorItemType,
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
setFloorItems: Types.setFloorItemSetState
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
|
setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void
|
||||||
) {
|
) {
|
||||||
const model = gltf;
|
const model = gltf;
|
||||||
model.uuid = item.modeluuid;
|
model.uuid = item.modeluuid;
|
||||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||||
model.userData = { name: item.modelname, modelId: item.modelfileID };
|
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
|
||||||
model.position.set(...item.position);
|
model.position.set(...item.position);
|
||||||
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
|
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
|
||||||
|
|
||||||
|
@ -186,39 +180,67 @@ function processLoadedModel(
|
||||||
|
|
||||||
itemsGroup?.current?.add(model);
|
itemsGroup?.current?.add(model);
|
||||||
|
|
||||||
if (item.eventData) {
|
setFloorItems((prevItems) => [
|
||||||
setFloorItems((prevItems) => [
|
...(prevItems || []),
|
||||||
...(prevItems || []),
|
{
|
||||||
{
|
modeluuid: item.modeluuid,
|
||||||
modeluuid: item.modeluuid,
|
modelname: item.modelname,
|
||||||
modelname: item.modelname,
|
position: item.position,
|
||||||
position: item.position,
|
rotation: item.rotation,
|
||||||
rotation: item.rotation,
|
modelfileID: item.modelfileID,
|
||||||
modelfileID: item.modelfileID,
|
isLocked: item.isLocked,
|
||||||
isLocked: item.isLocked,
|
isVisible: item.isVisible,
|
||||||
isVisible: item.isVisible,
|
},
|
||||||
// eventData: item.eventData,
|
]);
|
||||||
},
|
|
||||||
]);
|
if (item.eventData || item.modelfileID === '67e3da19c2e8f37134526e6a') {
|
||||||
} else {
|
processEventData(item, setSimulationPaths);
|
||||||
setFloorItems((prevItems) => [
|
|
||||||
...(prevItems || []),
|
|
||||||
{
|
|
||||||
modeluuid: item.modeluuid,
|
|
||||||
modelname: item.modelname,
|
|
||||||
position: item.position,
|
|
||||||
rotation: item.rotation,
|
|
||||||
modelfileID: item.modelfileID,
|
|
||||||
isLocked: item.isLocked,
|
|
||||||
isVisible: item.isVisible,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
||||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function processEventData(item: Types.FloorItemType, setSimulationPaths: any) {
|
||||||
|
|
||||||
|
if (item.eventData?.type === 'Conveyor') {
|
||||||
|
|
||||||
|
const data: any = item.eventData;
|
||||||
|
data.modeluuid = item.modeluuid;
|
||||||
|
data.modelName = item.modelname;
|
||||||
|
data.position = item.position;
|
||||||
|
data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z];
|
||||||
|
|
||||||
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||||
|
...(prevEvents || []),
|
||||||
|
data as Types.ConveyorEventsSchema
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
|
const pointPosition = new THREE.Vector3(0, 1.3, 0);
|
||||||
|
|
||||||
|
const newVehiclePath: Types.VehicleEventsSchema = {
|
||||||
|
modeluuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
type: 'Vehicle',
|
||||||
|
point: {
|
||||||
|
uuid: pointUUID,
|
||||||
|
position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
||||||
|
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
||||||
|
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
||||||
|
speed: 2,
|
||||||
|
},
|
||||||
|
position: [...item.position],
|
||||||
|
};
|
||||||
|
|
||||||
|
setSimulationPaths((prevEvents: (Types.VehicleEventsSchema)[]) => [
|
||||||
|
...(prevEvents || []),
|
||||||
|
newVehiclePath as Types.VehicleEventsSchema
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkLoadingCompletion(
|
function checkLoadingCompletion(
|
||||||
modelsLoaded: number,
|
modelsLoaded: number,
|
||||||
modelsToLoad: number,
|
modelsToLoad: number,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
|
@ -10,6 +10,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { socket } = useSocketStore()
|
const { socket } = useSocketStore()
|
||||||
|
@ -150,37 +151,128 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas
|
||||||
return updatedItems;
|
return updatedItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
|
||||||
|
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||||
|
if (eventData) {
|
||||||
|
if (eventData.type === 'Conveyor' && eventData) {
|
||||||
|
const createConveyorPoint = (index: number) => {
|
||||||
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
|
const hasActions = (eventData as Types.ConveyorEventsSchema)?.points[index].actions.length > 0;
|
||||||
|
|
||||||
//REST
|
const defaultAction = {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
name: 'Action 1',
|
||||||
|
type: 'Inherit',
|
||||||
|
material: 'Inherit',
|
||||||
|
delay: 'Inherit',
|
||||||
|
spawnInterval: 'Inherit',
|
||||||
|
isUsed: true
|
||||||
|
};
|
||||||
|
|
||||||
// await setFloorItemApi(
|
return {
|
||||||
// organization,
|
uuid: pointUUID,
|
||||||
// obj.uuid,
|
position: (eventData as Types.ConveyorEventsSchema)?.points[index].position,
|
||||||
// obj.userData.name,
|
rotation: (eventData as Types.ConveyorEventsSchema)?.points[index].rotation,
|
||||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
actions: hasActions
|
||||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
? (eventData as Types.ConveyorEventsSchema)?.points[index].actions.map(action => ({
|
||||||
// obj.userData.modelId,
|
...action,
|
||||||
// false,
|
uuid: THREE.MathUtils.generateUUID()
|
||||||
// true,
|
}))
|
||||||
// );
|
: [defaultAction],
|
||||||
|
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
|
||||||
|
connections: {
|
||||||
|
source: { pathUUID: obj.uuid, pointUUID },
|
||||||
|
targets: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
//SOCKET
|
const backendEventData = {
|
||||||
|
type: 'Conveyor',
|
||||||
|
points: [
|
||||||
|
createConveyorPoint(0), // point1
|
||||||
|
createConveyorPoint(1), // middlePoint
|
||||||
|
createConveyorPoint(2) // point2
|
||||||
|
],
|
||||||
|
speed: (eventData as Types.ConveyorEventsSchema)?.speed
|
||||||
|
};
|
||||||
|
|
||||||
const data = {
|
//REST
|
||||||
organization,
|
|
||||||
modeluuid: newFloorItem.modeluuid,
|
|
||||||
modelname: newFloorItem.modelname,
|
|
||||||
modelfileID: newFloorItem.modelfileID,
|
|
||||||
position: newFloorItem.position,
|
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
|
||||||
isLocked: false,
|
|
||||||
isVisible: true,
|
|
||||||
socketId: socket.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// backendEventData
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: backendEventData,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newEventData: any = backendEventData;
|
||||||
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
|
newEventData.position = newFloorItem.position;
|
||||||
|
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
|
|
||||||
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||||
|
...(prevEvents || []),
|
||||||
|
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
itemsGroupRef.current.add(obj);
|
itemsGroupRef.current.add(obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
|
@ -10,11 +10,11 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!camera || !scene || toggleView) return;
|
if (!camera || !scene || toggleView) return;
|
||||||
const canvasElement = gl.domElement;
|
const canvasElement = gl.domElement;
|
||||||
|
@ -131,37 +131,129 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb
|
||||||
return updatedItems;
|
return updatedItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
|
||||||
|
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||||
|
|
||||||
//REST
|
if (eventData) {
|
||||||
|
if (eventData.type === 'Conveyor' && eventData) {
|
||||||
|
const createConveyorPoint = (index: number) => {
|
||||||
|
const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
|
const hasActions = (eventData as Types.ConveyorEventsSchema)?.points[index].actions.length > 0;
|
||||||
|
|
||||||
// await setFloorItemApi(
|
const defaultAction = {
|
||||||
// organization,
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
// obj.uuid,
|
name: 'Action 1',
|
||||||
// obj.userData.name,
|
type: 'Inherit',
|
||||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
material: 'Inherit',
|
||||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
delay: 'Inherit',
|
||||||
// obj.userData.modelId,
|
spawnInterval: 'Inherit',
|
||||||
// false,
|
isUsed: true
|
||||||
// true,
|
};
|
||||||
// );
|
|
||||||
|
|
||||||
//SOCKET
|
return {
|
||||||
|
uuid: pointUUID,
|
||||||
|
position: (eventData as Types.ConveyorEventsSchema)?.points[index].position,
|
||||||
|
rotation: (eventData as Types.ConveyorEventsSchema)?.points[index].rotation,
|
||||||
|
actions: hasActions
|
||||||
|
? (eventData as Types.ConveyorEventsSchema)?.points[index].actions.map(action => ({
|
||||||
|
...action,
|
||||||
|
uuid: THREE.MathUtils.generateUUID()
|
||||||
|
}))
|
||||||
|
: [defaultAction],
|
||||||
|
triggers: (eventData as Types.ConveyorEventsSchema)?.points[index].triggers,
|
||||||
|
connections: {
|
||||||
|
source: { pathUUID: obj.uuid, pointUUID },
|
||||||
|
targets: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const data = {
|
const backendEventData = {
|
||||||
organization,
|
type: 'Conveyor',
|
||||||
modeluuid: newFloorItem.modeluuid,
|
points: [
|
||||||
modelname: newFloorItem.modelname,
|
createConveyorPoint(0), // point1
|
||||||
modelfileID: newFloorItem.modelfileID,
|
createConveyorPoint(1), // middlePoint
|
||||||
position: newFloorItem.position,
|
createConveyorPoint(2) // point2
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
],
|
||||||
isLocked: false,
|
speed: (eventData as Types.ConveyorEventsSchema)?.speed
|
||||||
isVisible: true,
|
};
|
||||||
socketId: socket.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
//REST
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// backendEventData
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: backendEventData,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newEventData: any = backendEventData;
|
||||||
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
|
newEventData.position = newFloorItem.position;
|
||||||
|
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
|
|
||||||
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => [
|
||||||
|
...(prevEvents || []),
|
||||||
|
newEventData as Types.ConveyorEventsSchema | Types.VehicleEventsSchema
|
||||||
|
]);
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
itemsGroupRef.current.add(obj);
|
itemsGroupRef.current.add(obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
|
@ -12,6 +12,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
||||||
|
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const itemsData = useRef<Types.FloorItems>([]);
|
const itemsData = useRef<Types.FloorItems>([]);
|
||||||
|
@ -179,37 +180,99 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje
|
||||||
return updatedItems;
|
return updatedItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
|
||||||
|
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||||
|
|
||||||
//REST
|
if (eventData) {
|
||||||
|
if (eventData.type === 'Conveyor' && eventData) {
|
||||||
|
|
||||||
// await setFloorItemApi(
|
const backendEventData = {
|
||||||
// organization,
|
type: 'Conveyor',
|
||||||
// obj.uuid,
|
points: eventData.points,
|
||||||
// obj.userData.name,
|
speed: (eventData as Types.ConveyorEventsSchema)?.speed
|
||||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
};
|
||||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
|
||||||
// obj.userData.modelId,
|
|
||||||
// false,
|
|
||||||
// true,
|
|
||||||
// );
|
|
||||||
|
|
||||||
//SOCKET
|
//REST
|
||||||
|
|
||||||
const data = {
|
// await setFloorItemApi(
|
||||||
organization,
|
// organization,
|
||||||
modeluuid: newFloorItem.modeluuid,
|
// obj.uuid,
|
||||||
modelname: newFloorItem.modelname,
|
// obj.userData.name,
|
||||||
modelfileID: newFloorItem.modelfileID,
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
position: newFloorItem.position,
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
// obj.userData.modelId,
|
||||||
isLocked: false,
|
// false,
|
||||||
isVisible: true,
|
// true,
|
||||||
socketId: socket.id,
|
// backendEventData
|
||||||
};
|
// );
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: backendEventData,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newEventData: any = backendEventData;
|
||||||
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
|
newEventData.position = newFloorItem.position;
|
||||||
|
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
|
|
||||||
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
||||||
|
const updatedEvents = (prevEvents || []).map(event =>
|
||||||
|
event.modeluuid === newFloorItem.modeluuid
|
||||||
|
? { ...event, ...newEventData }
|
||||||
|
: event
|
||||||
|
);
|
||||||
|
return updatedEvents;
|
||||||
|
});
|
||||||
|
|
||||||
|
// socket.emit("v2:model-asset:add", data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
itemsGroupRef.current.add(obj);
|
itemsGroupRef.current.add(obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
|
@ -12,6 +12,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
||||||
|
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
|
const { simulationPaths, setSimulationPaths } = useSimulationPaths();
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const itemsData = useRef<Types.FloorItems>([]);
|
const itemsData = useRef<Types.FloorItems>([]);
|
||||||
|
@ -182,37 +183,99 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo
|
||||||
return updatedItems;
|
return updatedItems;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | undefined = simulationPaths.find((events) => events.modeluuid === obj.userData.modeluuid);
|
||||||
|
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
const organization = email ? email.split("@")[1].split(".")[0] : "default";
|
||||||
|
|
||||||
//REST
|
if (eventData) {
|
||||||
|
if (eventData.type === 'Conveyor' && eventData) {
|
||||||
|
|
||||||
// await setFloorItemApi(
|
const backendEventData = {
|
||||||
// organization,
|
type: 'Conveyor',
|
||||||
// obj.uuid,
|
points: eventData.points,
|
||||||
// obj.userData.name,
|
speed: (eventData as Types.ConveyorEventsSchema)?.speed
|
||||||
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
};
|
||||||
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
|
||||||
// obj.userData.modelId,
|
|
||||||
// false,
|
|
||||||
// true,
|
|
||||||
// );
|
|
||||||
|
|
||||||
//SOCKET
|
//REST
|
||||||
|
|
||||||
const data = {
|
// await setFloorItemApi(
|
||||||
organization,
|
// organization,
|
||||||
modeluuid: newFloorItem.modeluuid,
|
// obj.uuid,
|
||||||
modelname: newFloorItem.modelname,
|
// obj.userData.name,
|
||||||
modelfileID: newFloorItem.modelfileID,
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
position: newFloorItem.position,
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
// obj.userData.modelId,
|
||||||
isLocked: false,
|
// false,
|
||||||
isVisible: true,
|
// true,
|
||||||
socketId: socket.id,
|
// backendEventData
|
||||||
};
|
// );
|
||||||
|
|
||||||
socket.emit("v2:model-asset:add", data);
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
eventData: backendEventData,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const newEventData: any = backendEventData;
|
||||||
|
newEventData.modeluuid = newFloorItem.modeluuid;
|
||||||
|
newEventData.modelName = newFloorItem.modelname;
|
||||||
|
newEventData.position = newFloorItem.position;
|
||||||
|
newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z];
|
||||||
|
|
||||||
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
||||||
|
const updatedEvents = (prevEvents || []).map(event =>
|
||||||
|
event.modeluuid === newFloorItem.modeluuid
|
||||||
|
? { ...event, ...newEventData }
|
||||||
|
: event
|
||||||
|
);
|
||||||
|
return updatedEvents;
|
||||||
|
});
|
||||||
|
|
||||||
|
// socket.emit("v2:model-asset:add", data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
|
||||||
|
//REST
|
||||||
|
|
||||||
|
// await setFloorItemApi(
|
||||||
|
// organization,
|
||||||
|
// obj.uuid,
|
||||||
|
// obj.userData.name,
|
||||||
|
// [worldPosition.x, worldPosition.y, worldPosition.z],
|
||||||
|
// { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z },
|
||||||
|
// obj.userData.modelId,
|
||||||
|
// false,
|
||||||
|
// true,
|
||||||
|
// );
|
||||||
|
|
||||||
|
//SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
organization,
|
||||||
|
modeluuid: newFloorItem.modeluuid,
|
||||||
|
modelname: newFloorItem.modelname,
|
||||||
|
modelfileID: newFloorItem.modelfileID,
|
||||||
|
position: newFloorItem.position,
|
||||||
|
rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z },
|
||||||
|
isLocked: false,
|
||||||
|
isVisible: true,
|
||||||
|
socketId: socket.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v2:model-asset:add", data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
itemsGroupRef.current.add(obj);
|
itemsGroupRef.current.add(obj);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
|
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
|
||||||
import { SelectionHelper } from "./selectionHelper";
|
import { SelectionHelper } from "./selectionHelper";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store";
|
import { useFloorItems, useSelectedAssets, useSimulationPaths, useSocketStore, useToggleView } from "../../../../store/store";
|
||||||
import BoundingBox from "./boundingBoxHelper";
|
import BoundingBox from "./boundingBoxHelper";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
|
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
|
||||||
|
@ -20,6 +20,7 @@ const SelectionControls: React.FC = () => {
|
||||||
const itemsGroupRef = useRef<THREE.Group | undefined>(undefined);
|
const itemsGroupRef = useRef<THREE.Group | undefined>(undefined);
|
||||||
const selectionGroup = useRef() as Types.RefGroup;
|
const selectionGroup = useRef() as Types.RefGroup;
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
|
const { setSimulationPaths } = useSimulationPaths();
|
||||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||||
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
|
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
|
||||||
const [rotatedObjects, setRotatedObjects] = useState<THREE.Object3D[]>([]);
|
const [rotatedObjects, setRotatedObjects] = useState<THREE.Object3D[]>([]);
|
||||||
|
@ -239,6 +240,11 @@ const SelectionControls: React.FC = () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setSimulationPaths((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => {
|
||||||
|
const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid);
|
||||||
|
return updatedEvents;
|
||||||
|
});
|
||||||
|
|
||||||
itemsGroupRef.current?.remove(selectedMesh);
|
itemsGroupRef.current?.remove(selectedMesh);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -93,13 +93,13 @@ export default function PostProcessing() {
|
||||||
<Outline
|
<Outline
|
||||||
selection={[selectedActionSphere.point]}
|
selection={[selectedActionSphere.point]}
|
||||||
selectionLayer={10}
|
selectionLayer={10}
|
||||||
width={750}
|
width={1000}
|
||||||
blendFunction={BlendFunction.ALPHA}
|
blendFunction={BlendFunction.ALPHA}
|
||||||
edgeStrength={15}
|
edgeStrength={10}
|
||||||
resolutionScale={2}
|
resolutionScale={2}
|
||||||
pulseSpeed={0}
|
pulseSpeed={0}
|
||||||
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
visibleEdgeColor={0x6f42c1}
|
||||||
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
hiddenEdgeColor={0x6f42c1}
|
||||||
blur={true}
|
blur={true}
|
||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
|
@ -108,9 +108,9 @@ export default function PostProcessing() {
|
||||||
<Outline
|
<Outline
|
||||||
selection={flattenChildren(selectedPath.group.children)}
|
selection={flattenChildren(selectedPath.group.children)}
|
||||||
selectionLayer={10}
|
selectionLayer={10}
|
||||||
width={750}
|
width={1000}
|
||||||
blendFunction={BlendFunction.ALPHA}
|
blendFunction={BlendFunction.ALPHA}
|
||||||
edgeStrength={15}
|
edgeStrength={10}
|
||||||
resolutionScale={2}
|
resolutionScale={2}
|
||||||
pulseSpeed={0}
|
pulseSpeed={0}
|
||||||
visibleEdgeColor={0x6f42c1}
|
visibleEdgeColor={0x6f42c1}
|
||||||
|
|
|
@ -10,76 +10,76 @@ function Behaviour() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = [];
|
const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = [];
|
||||||
|
|
||||||
floorItems.forEach((item: Types.FloorItemType) => {
|
// floorItems.forEach((item: Types.FloorItemType) => {
|
||||||
if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
|
// if (item.modelfileID === "672a090f80d91ac979f4d0bd") {
|
||||||
console.log('item: ', item);
|
// const point1Position = new THREE.Vector3(0, 0.85, 2.2);
|
||||||
const point1Position = new THREE.Vector3(0, 0.85, 2.2);
|
// const middlePointPosition = new THREE.Vector3(0, 0.85, 0);
|
||||||
const middlePointPosition = new THREE.Vector3(0, 0.85, 0);
|
// const point2Position = new THREE.Vector3(0, 0.85, -2.2);
|
||||||
const point2Position = new THREE.Vector3(0, 0.85, -2.2);
|
|
||||||
|
|
||||||
const point1UUID = THREE.MathUtils.generateUUID();
|
// const point1UUID = THREE.MathUtils.generateUUID();
|
||||||
const middlePointUUID = THREE.MathUtils.generateUUID();
|
// const middlePointUUID = THREE.MathUtils.generateUUID();
|
||||||
const point2UUID = THREE.MathUtils.generateUUID();
|
// const point2UUID = THREE.MathUtils.generateUUID();
|
||||||
|
|
||||||
const newPath: Types.ConveyorEventsSchema = {
|
// const newPath: Types.ConveyorEventsSchema = {
|
||||||
modeluuid: item.modeluuid,
|
// modeluuid: item.modeluuid,
|
||||||
modelName: item.modelname,
|
// modelName: item.modelname,
|
||||||
type: 'Conveyor',
|
// type: 'Conveyor',
|
||||||
points: [
|
// points: [
|
||||||
{
|
// {
|
||||||
uuid: point1UUID,
|
// uuid: point1UUID,
|
||||||
position: [point1Position.x, point1Position.y, point1Position.z],
|
// position: [point1Position.x, point1Position.y, point1Position.z],
|
||||||
rotation: [0, 0, 0],
|
// rotation: [0, 0, 0],
|
||||||
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
||||||
triggers: [],
|
// triggers: [],
|
||||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] },
|
// connections: { source: { pathUUID: item.modeluuid, pointUUID: point1UUID }, targets: [] },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
uuid: middlePointUUID,
|
// uuid: middlePointUUID,
|
||||||
position: [middlePointPosition.x, middlePointPosition.y, middlePointPosition.z],
|
// position: [middlePointPosition.x, middlePointPosition.y, middlePointPosition.z],
|
||||||
rotation: [0, 0, 0],
|
// rotation: [0, 0, 0],
|
||||||
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
||||||
triggers: [],
|
// triggers: [],
|
||||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] },
|
// connections: { source: { pathUUID: item.modeluuid, pointUUID: middlePointUUID }, targets: [] },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
uuid: point2UUID,
|
// uuid: point2UUID,
|
||||||
position: [point2Position.x, point2Position.y, point2Position.z],
|
// position: [point2Position.x, point2Position.y, point2Position.z],
|
||||||
rotation: [0, 0, 0],
|
// rotation: [0, 0, 0],
|
||||||
actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
// actions: [{ uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Inherit', material: 'Inherit', delay: 'Inherit', spawnInterval: 'Inherit', isUsed: true }],
|
||||||
triggers: [],
|
// triggers: [],
|
||||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
|
// connections: { source: { pathUUID: item.modeluuid, pointUUID: point2UUID }, targets: [] },
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
position: [...item.position],
|
// position: [...item.position],
|
||||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
// rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
speed: 'Inherit',
|
// speed: 'Inherit',
|
||||||
};
|
// };
|
||||||
|
|
||||||
newPaths.push(newPath);
|
// newPaths.push(newPath);
|
||||||
} else if (item.modelfileID === "67e3da19c2e8f37134526e6a") {
|
// } else if (item.modelfileID === "67e3da19c2e8f37134526e6a") {
|
||||||
const pointUUID = THREE.MathUtils.generateUUID();
|
// const pointUUID = THREE.MathUtils.generateUUID();
|
||||||
const pointPosition = new THREE.Vector3(0, 1.3, 0);
|
// const pointPosition = new THREE.Vector3(0, 1.3, 0);
|
||||||
|
|
||||||
const newVehiclePath: Types.VehicleEventsSchema = {
|
// const newVehiclePath: Types.VehicleEventsSchema = {
|
||||||
modeluuid: item.modeluuid,
|
// modeluuid: item.modeluuid,
|
||||||
modelName: item.modelname,
|
// modelName: item.modelname,
|
||||||
type: 'Vehicle',
|
// type: 'Vehicle',
|
||||||
point: {
|
// point: {
|
||||||
uuid: pointUUID,
|
// uuid: pointUUID,
|
||||||
position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
// position: [pointPosition.x, pointPosition.y, pointPosition.z],
|
||||||
actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
// actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 },
|
||||||
connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
// connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] },
|
||||||
speed: 2,
|
// speed: 2,
|
||||||
},
|
// },
|
||||||
position: [...item.position],
|
// position: [...item.position],
|
||||||
};
|
// };
|
||||||
|
|
||||||
newPaths.push(newVehiclePath);
|
// newPaths.push(newVehiclePath);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
setSimulationPaths(newPaths);
|
// setSimulationPaths(newPaths);
|
||||||
|
// console.log('floorItems: ', floorItems);
|
||||||
}, [floorItems]);
|
}, [floorItems]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -14,12 +14,14 @@ import {
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useSubModuleStore } from "../../../store/useModuleStore";
|
import { useSubModuleStore } from "../../../store/useModuleStore";
|
||||||
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
|
|
||||||
function PathCreation({
|
function PathCreation({
|
||||||
pathsGroupRef,
|
pathsGroupRef,
|
||||||
}: {
|
}: {
|
||||||
pathsGroupRef: React.MutableRefObject<THREE.Group>;
|
pathsGroupRef: React.MutableRefObject<THREE.Group>;
|
||||||
}) {
|
}) {
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { renderDistance } = useRenderDistance();
|
const { renderDistance } = useRenderDistance();
|
||||||
const { setSubModule } = useSubModuleStore();
|
const { setSubModule } = useSubModuleStore();
|
||||||
const { setSelectedActionSphere, selectedActionSphere } =
|
const { setSelectedActionSphere, selectedActionSphere } =
|
||||||
|
@ -66,7 +68,7 @@ function PathCreation({
|
||||||
const distance = new THREE.Vector3(
|
const distance = new THREE.Vector3(
|
||||||
...group.position.toArray()
|
...group.position.toArray()
|
||||||
).distanceTo(camera.position);
|
).distanceTo(camera.position);
|
||||||
group.visible = distance <= renderDistance;
|
group.visible = ((distance <= renderDistance) && !isPlaying);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -193,7 +195,7 @@ function PathCreation({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group name="simulation-simulationPaths-group" ref={pathsGroupRef}>
|
<group visible={!isPlaying} name="simulation-simulationPaths-group" ref={pathsGroupRef}>
|
||||||
{simulationPaths.map((path) => {
|
{simulationPaths.map((path) => {
|
||||||
if (path.type === "Conveyor") {
|
if (path.type === "Conveyor") {
|
||||||
const points = path.points.map(
|
const points = path.points.map(
|
||||||
|
|
|
@ -0,0 +1,916 @@
|
||||||
|
// // animation-worker.js
|
||||||
|
// // This web worker handles animation calculations off the main thread
|
||||||
|
|
||||||
|
// /* eslint-disable no-restricted-globals */
|
||||||
|
// // The above disables the ESLint rule for this file since 'self' is valid in web workers
|
||||||
|
|
||||||
|
// // Store process data, animation states, and objects
|
||||||
|
// let processes = [];
|
||||||
|
// let animationStates = {};
|
||||||
|
// let lastTimestamp = 0;
|
||||||
|
|
||||||
|
// // Message handler for communication with main thread
|
||||||
|
// self.onmessage = function (event) {
|
||||||
|
// const { type, data } = event.data;
|
||||||
|
|
||||||
|
// switch (type) {
|
||||||
|
// case "initialize":
|
||||||
|
// processes = data.processes;
|
||||||
|
// initializeAnimationStates();
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case "update":
|
||||||
|
// const { timestamp, isPlaying } = data;
|
||||||
|
// if (isPlaying) {
|
||||||
|
// const delta = (timestamp - lastTimestamp) / 1000; // Convert to seconds
|
||||||
|
// updateAnimations(delta, timestamp);
|
||||||
|
// }
|
||||||
|
// lastTimestamp = timestamp;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case "reset":
|
||||||
|
// resetAnimations();
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case "togglePlay":
|
||||||
|
// // If resuming from pause, recalculate the time delta
|
||||||
|
// lastTimestamp = data.timestamp;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Initialize animation states for all processes
|
||||||
|
// function initializeAnimationStates() {
|
||||||
|
// animationStates = {};
|
||||||
|
|
||||||
|
// processes.forEach((process) => {
|
||||||
|
// animationStates[process.id] = {
|
||||||
|
// spawnedObjects: {},
|
||||||
|
// nextSpawnTime: 0,
|
||||||
|
// objectIdCounter: 0,
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Send initial states back to main thread
|
||||||
|
// self.postMessage({
|
||||||
|
// type: "statesInitialized",
|
||||||
|
// data: { animationStates },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Reset all animations
|
||||||
|
// function resetAnimations() {
|
||||||
|
// initializeAnimationStates();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Find spawn point in a process
|
||||||
|
// function findSpawnPoint(process) {
|
||||||
|
// for (const path of process.paths || []) {
|
||||||
|
// for (const point of path.points || []) {
|
||||||
|
// const spawnAction = point.actions?.find(
|
||||||
|
// (a) => a.isUsed && a.type === "Spawn"
|
||||||
|
// );
|
||||||
|
// if (spawnAction) {
|
||||||
|
// return { point, path };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Create a new spawned object with proper initial position
|
||||||
|
// function createSpawnedObject(process, spawnPoint, currentTime, materialType) {
|
||||||
|
// // Extract spawn position from the actual spawn point
|
||||||
|
// const position = spawnPoint.point.position
|
||||||
|
// ? [...spawnPoint.point.position]
|
||||||
|
// : [0, 0, 0];
|
||||||
|
|
||||||
|
// // Get the path position and add it to the spawn point position
|
||||||
|
// const pathPosition = spawnPoint.path.pathPosition || [0, 0, 0];
|
||||||
|
// const absolutePosition = [
|
||||||
|
// position[0] + pathPosition[0],
|
||||||
|
// position[1] + pathPosition[1],
|
||||||
|
// position[2] + pathPosition[2],
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// id: `obj-${process.id}-${animationStates[process.id].objectIdCounter}`,
|
||||||
|
// position: absolutePosition,
|
||||||
|
// state: {
|
||||||
|
// currentIndex: 0,
|
||||||
|
// progress: 0,
|
||||||
|
// isAnimating: true,
|
||||||
|
// speed: process.speed || 1,
|
||||||
|
// isDelaying: false,
|
||||||
|
// delayStartTime: 0,
|
||||||
|
// currentDelayDuration: 0,
|
||||||
|
// delayComplete: false,
|
||||||
|
// currentPathIndex: 0,
|
||||||
|
// // Store the spawn point index to start animation from correct path point
|
||||||
|
// spawnPointIndex: getPointIndexInProcess(process, spawnPoint.point),
|
||||||
|
// },
|
||||||
|
// visible: true,
|
||||||
|
// materialType: materialType || "Default",
|
||||||
|
// spawnTime: currentTime,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Get the index of a point within the process animation path
|
||||||
|
// function getPointIndexInProcess(process, point) {
|
||||||
|
// if (!process.paths) return 0;
|
||||||
|
|
||||||
|
// let cumulativePoints = 0;
|
||||||
|
// for (const path of process.paths) {
|
||||||
|
// for (let i = 0; i < (path.points?.length || 0); i++) {
|
||||||
|
// if (path.points[i].uuid === point.uuid) {
|
||||||
|
// return cumulativePoints + i;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// cumulativePoints += path.points?.length || 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Get point data for current animation index
|
||||||
|
// function getPointDataForAnimationIndex(process, index) {
|
||||||
|
// if (!process.paths) return null;
|
||||||
|
|
||||||
|
// let cumulativePoints = 0;
|
||||||
|
// for (const path of process.paths) {
|
||||||
|
// const pointCount = path.points?.length || 0;
|
||||||
|
|
||||||
|
// if (index < cumulativePoints + pointCount) {
|
||||||
|
// const pointIndex = index - cumulativePoints;
|
||||||
|
// return path.points?.[pointIndex] || null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// cumulativePoints += pointCount;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Convert process paths to Vector3 format
|
||||||
|
// function getProcessPath(process) {
|
||||||
|
// return process.animationPath?.map((p) => ({ x: p.x, y: p.y, z: p.z })) || [];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Handle material swap for an object
|
||||||
|
// function handleMaterialSwap(processId, objectId, materialType) {
|
||||||
|
// const processState = animationStates[processId];
|
||||||
|
// if (!processState || !processState.spawnedObjects[objectId]) return;
|
||||||
|
|
||||||
|
// processState.spawnedObjects[objectId].materialType = materialType;
|
||||||
|
|
||||||
|
// // Notify main thread about material change
|
||||||
|
// self.postMessage({
|
||||||
|
// type: "materialChanged",
|
||||||
|
// data: {
|
||||||
|
// processId,
|
||||||
|
// objectId,
|
||||||
|
// materialType,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Handle point actions for an object
|
||||||
|
// function handlePointActions(processId, objectId, actions = [], currentTime) {
|
||||||
|
// let shouldStopAnimation = false;
|
||||||
|
// const processState = animationStates[processId];
|
||||||
|
|
||||||
|
// if (!processState || !processState.spawnedObjects[objectId]) return false;
|
||||||
|
|
||||||
|
// const objectState = processState.spawnedObjects[objectId];
|
||||||
|
|
||||||
|
// actions.forEach((action) => {
|
||||||
|
// if (!action.isUsed) return;
|
||||||
|
|
||||||
|
// switch (action.type) {
|
||||||
|
// case "Delay":
|
||||||
|
// if (objectState.state.isDelaying) return;
|
||||||
|
|
||||||
|
// const delayDuration =
|
||||||
|
// typeof action.delay === "number"
|
||||||
|
// ? action.delay
|
||||||
|
// : parseFloat(action.delay || "0");
|
||||||
|
|
||||||
|
// if (delayDuration > 0) {
|
||||||
|
// objectState.state.isDelaying = true;
|
||||||
|
// objectState.state.delayStartTime = currentTime;
|
||||||
|
// objectState.state.currentDelayDuration = delayDuration;
|
||||||
|
// objectState.state.delayComplete = false;
|
||||||
|
// shouldStopAnimation = true;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case "Despawn":
|
||||||
|
// delete processState.spawnedObjects[objectId];
|
||||||
|
// shouldStopAnimation = true;
|
||||||
|
|
||||||
|
// // Notify main thread about despawn
|
||||||
|
// self.postMessage({
|
||||||
|
// type: "objectDespawned",
|
||||||
|
// data: {
|
||||||
|
// processId,
|
||||||
|
// objectId,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case "Swap":
|
||||||
|
// if (action.material) {
|
||||||
|
// handleMaterialSwap(processId, objectId, action.material);
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return shouldStopAnimation;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Check if point has non-inherit actions
|
||||||
|
// function hasNonInheritActions(actions = []) {
|
||||||
|
// return actions.some((action) => action.isUsed && action.type !== "Inherit");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Calculate vector lerp (linear interpolation)
|
||||||
|
// function lerpVectors(v1, v2, alpha) {
|
||||||
|
// return {
|
||||||
|
// x: v1.x + (v2.x - v1.x) * alpha,
|
||||||
|
// y: v1.y + (v2.y - v1.y) * alpha,
|
||||||
|
// z: v1.z + (v2.z - v1.z) * alpha,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Calculate vector distance
|
||||||
|
// function distanceBetweenVectors(v1, v2) {
|
||||||
|
// const dx = v2.x - v1.x;
|
||||||
|
// const dy = v2.y - v1.y;
|
||||||
|
// const dz = v2.z - v1.z;
|
||||||
|
// return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Process spawn logic
|
||||||
|
// function processSpawns(currentTime) {
|
||||||
|
// processes.forEach((process) => {
|
||||||
|
// const processState = animationStates[process.id];
|
||||||
|
// if (!processState) return;
|
||||||
|
|
||||||
|
// const spawnPointData = findSpawnPoint(process);
|
||||||
|
// if (!spawnPointData || !spawnPointData.point.actions) return;
|
||||||
|
|
||||||
|
// const spawnAction = spawnPointData.point.actions.find(
|
||||||
|
// (a) => a.isUsed && a.type === "Spawn"
|
||||||
|
// );
|
||||||
|
// if (!spawnAction) return;
|
||||||
|
|
||||||
|
// const spawnInterval =
|
||||||
|
// typeof spawnAction.spawnInterval === "number"
|
||||||
|
// ? spawnAction.spawnInterval
|
||||||
|
// : parseFloat(spawnAction.spawnInterval || "0");
|
||||||
|
|
||||||
|
// if (currentTime >= processState.nextSpawnTime) {
|
||||||
|
// const newObject = createSpawnedObject(
|
||||||
|
// process,
|
||||||
|
// spawnPointData,
|
||||||
|
// currentTime,
|
||||||
|
// spawnAction.material || "Default"
|
||||||
|
// );
|
||||||
|
|
||||||
|
// processState.spawnedObjects[newObject.id] = newObject;
|
||||||
|
// processState.objectIdCounter++;
|
||||||
|
// processState.nextSpawnTime = currentTime + spawnInterval;
|
||||||
|
|
||||||
|
// // Notify main thread about new object
|
||||||
|
// self.postMessage({
|
||||||
|
// type: "objectSpawned",
|
||||||
|
// data: {
|
||||||
|
// processId: process.id,
|
||||||
|
// object: newObject,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Update all animations
|
||||||
|
// function updateAnimations(delta, currentTime) {
|
||||||
|
// // First handle spawning of new objects
|
||||||
|
// processSpawns(currentTime);
|
||||||
|
|
||||||
|
// // Then animate existing objects
|
||||||
|
// processes.forEach((process) => {
|
||||||
|
// const processState = animationStates[process.id];
|
||||||
|
// if (!processState) return;
|
||||||
|
|
||||||
|
// const path = getProcessPath(process);
|
||||||
|
// if (path.length < 2) return;
|
||||||
|
|
||||||
|
// const updatedObjects = {};
|
||||||
|
// let hasChanges = false;
|
||||||
|
|
||||||
|
// Object.entries(processState.spawnedObjects).forEach(([objectId, obj]) => {
|
||||||
|
// if (!obj.visible || !obj.state.isAnimating) return;
|
||||||
|
|
||||||
|
// const stateRef = obj.state;
|
||||||
|
|
||||||
|
// // Use the spawnPointIndex as starting point if it's the initial movement
|
||||||
|
// if (stateRef.currentIndex === 0 && stateRef.progress === 0) {
|
||||||
|
// stateRef.currentIndex = stateRef.spawnPointIndex || 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Get current point data
|
||||||
|
// const currentPointData = getPointDataForAnimationIndex(
|
||||||
|
// process,
|
||||||
|
// stateRef.currentIndex
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // Execute actions when arriving at a new point
|
||||||
|
// if (stateRef.progress === 0 && currentPointData?.actions) {
|
||||||
|
// const shouldStop = handlePointActions(
|
||||||
|
// process.id,
|
||||||
|
// objectId,
|
||||||
|
// currentPointData.actions,
|
||||||
|
// currentTime
|
||||||
|
// );
|
||||||
|
// if (shouldStop) return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Handle delays
|
||||||
|
// if (stateRef.isDelaying) {
|
||||||
|
// if (
|
||||||
|
// currentTime - stateRef.delayStartTime >=
|
||||||
|
// stateRef.currentDelayDuration
|
||||||
|
// ) {
|
||||||
|
// stateRef.isDelaying = false;
|
||||||
|
// stateRef.delayComplete = true;
|
||||||
|
// } else {
|
||||||
|
// updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
||||||
|
// return; // Keep waiting
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const nextPointIdx = stateRef.currentIndex + 1;
|
||||||
|
// const isLastPoint = nextPointIdx >= path.length;
|
||||||
|
|
||||||
|
// if (isLastPoint) {
|
||||||
|
// if (currentPointData?.actions) {
|
||||||
|
// const shouldStop = !hasNonInheritActions(currentPointData.actions);
|
||||||
|
// if (shouldStop) {
|
||||||
|
// // Reached the end of path with no more actions
|
||||||
|
// delete processState.spawnedObjects[objectId];
|
||||||
|
|
||||||
|
// // Notify main thread to remove the object
|
||||||
|
// self.postMessage({
|
||||||
|
// type: "objectCompleted",
|
||||||
|
// data: {
|
||||||
|
// processId: process.id,
|
||||||
|
// objectId,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!isLastPoint) {
|
||||||
|
// const currentPos = path[stateRef.currentIndex];
|
||||||
|
// const nextPos = path[nextPointIdx];
|
||||||
|
// const distance = distanceBetweenVectors(currentPos, nextPos);
|
||||||
|
// const movement = stateRef.speed * delta;
|
||||||
|
|
||||||
|
// // Update progress based on distance and speed
|
||||||
|
// const oldProgress = stateRef.progress;
|
||||||
|
// stateRef.progress += movement / distance;
|
||||||
|
|
||||||
|
// if (stateRef.progress >= 1) {
|
||||||
|
// // Reached next point
|
||||||
|
// stateRef.currentIndex = nextPointIdx;
|
||||||
|
// stateRef.progress = 0;
|
||||||
|
// stateRef.delayComplete = false;
|
||||||
|
// obj.position = [nextPos.x, nextPos.y, nextPos.z];
|
||||||
|
// } else {
|
||||||
|
// // Interpolate position
|
||||||
|
// const lerpedPos = lerpVectors(currentPos, nextPos, stateRef.progress);
|
||||||
|
// obj.position = [lerpedPos.x, lerpedPos.y, lerpedPos.z];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Only send updates when there's meaningful movement
|
||||||
|
// if (Math.abs(oldProgress - stateRef.progress) > 0.01) {
|
||||||
|
// hasChanges = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Update animation state with modified objects
|
||||||
|
// if (Object.keys(updatedObjects).length > 0) {
|
||||||
|
// processState.spawnedObjects = {
|
||||||
|
// ...processState.spawnedObjects,
|
||||||
|
// ...updatedObjects,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Only send position updates when there are meaningful changes
|
||||||
|
// if (hasChanges) {
|
||||||
|
// self.postMessage({
|
||||||
|
// type: "positionsUpdated",
|
||||||
|
// data: {
|
||||||
|
// processId: process.id,
|
||||||
|
// objects: updatedObjects,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// animation-worker.js
|
||||||
|
// This web worker handles animation calculations off the main thread
|
||||||
|
|
||||||
|
/* eslint-disable no-restricted-globals */
|
||||||
|
// The above disables the ESLint rule for this file since 'self' is valid in web workers
|
||||||
|
|
||||||
|
// Store process data, animation states, and objects
|
||||||
|
let processes = [];
|
||||||
|
let animationStates = {};
|
||||||
|
let lastTimestamp = 0;
|
||||||
|
let debugMode = true;
|
||||||
|
|
||||||
|
// Logger function for debugging
|
||||||
|
function log(...args) {
|
||||||
|
if (debugMode) {
|
||||||
|
self.postMessage({
|
||||||
|
type: "debug",
|
||||||
|
data: { message: args.join(' ') }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message handler for communication with main thread
|
||||||
|
self.onmessage = function (event) {
|
||||||
|
const { type, data } = event.data;
|
||||||
|
log(`Worker received message: ${type}`);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "initialize":
|
||||||
|
processes = data.processes;
|
||||||
|
log(`Initialized with ${processes.length} processes`);
|
||||||
|
initializeAnimationStates();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "update":
|
||||||
|
const { timestamp, isPlaying } = data;
|
||||||
|
if (isPlaying) {
|
||||||
|
const delta = lastTimestamp === 0 ? 0.016 : (timestamp - lastTimestamp) / 1000; // Convert to seconds
|
||||||
|
updateAnimations(delta, timestamp);
|
||||||
|
}
|
||||||
|
lastTimestamp = timestamp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "reset":
|
||||||
|
log("Resetting animations");
|
||||||
|
resetAnimations();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "togglePlay":
|
||||||
|
// If resuming from pause, recalculate the time delta
|
||||||
|
log(`Toggle play: ${data.isPlaying}`);
|
||||||
|
lastTimestamp = data.timestamp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "setDebug":
|
||||||
|
debugMode = data.enabled;
|
||||||
|
log(`Debug mode: ${debugMode}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize animation states for all processes
|
||||||
|
function initializeAnimationStates() {
|
||||||
|
animationStates = {};
|
||||||
|
|
||||||
|
processes.forEach((process) => {
|
||||||
|
if (!process || !process.id) {
|
||||||
|
log("Invalid process found:", process);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
animationStates[process.id] = {
|
||||||
|
spawnedObjects: {},
|
||||||
|
nextSpawnTime: 0,
|
||||||
|
objectIdCounter: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send initial states back to main thread
|
||||||
|
self.postMessage({
|
||||||
|
type: "statesInitialized",
|
||||||
|
data: { animationStates },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset all animations
|
||||||
|
function resetAnimations() {
|
||||||
|
initializeAnimationStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find spawn point in a process
|
||||||
|
function findSpawnPoint(process) {
|
||||||
|
if (!process || !process.paths) {
|
||||||
|
log(`No paths found for process ${process?.id}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const path of process.paths) {
|
||||||
|
if (!path || !path.points) continue;
|
||||||
|
|
||||||
|
for (const point of path.points) {
|
||||||
|
if (!point || !point.actions) continue;
|
||||||
|
|
||||||
|
const spawnAction = point.actions.find(
|
||||||
|
(a) => a && a.isUsed && a.type === "Spawn"
|
||||||
|
);
|
||||||
|
if (spawnAction) {
|
||||||
|
return { point, path };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log(`No spawn points found for process ${process.id}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new spawned object with proper initial position
|
||||||
|
function createSpawnedObject(process, spawnPoint, currentTime, materialType) {
|
||||||
|
// Extract spawn position from the actual spawn point
|
||||||
|
const position = spawnPoint.point.position
|
||||||
|
? [...spawnPoint.point.position]
|
||||||
|
: [0, 0, 0];
|
||||||
|
|
||||||
|
// Get the path position and add it to the spawn point position
|
||||||
|
const pathPosition = spawnPoint.path.pathPosition || [0, 0, 0];
|
||||||
|
const absolutePosition = [
|
||||||
|
position[0] + pathPosition[0],
|
||||||
|
position[1] + pathPosition[1],
|
||||||
|
position[2] + pathPosition[2],
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: `obj-${process.id}-${animationStates[process.id].objectIdCounter}`,
|
||||||
|
position: absolutePosition,
|
||||||
|
state: {
|
||||||
|
currentIndex: 0,
|
||||||
|
progress: 0,
|
||||||
|
isAnimating: true,
|
||||||
|
speed: process.speed || 1,
|
||||||
|
isDelaying: false,
|
||||||
|
delayStartTime: 0,
|
||||||
|
currentDelayDuration: 0,
|
||||||
|
delayComplete: false,
|
||||||
|
currentPathIndex: 0,
|
||||||
|
// Store the spawn point index to start animation from correct path point
|
||||||
|
spawnPointIndex: getPointIndexInProcess(process, spawnPoint.point),
|
||||||
|
},
|
||||||
|
visible: true,
|
||||||
|
materialType: materialType || "Default",
|
||||||
|
spawnTime: currentTime,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the index of a point within the process animation path
|
||||||
|
function getPointIndexInProcess(process, point) {
|
||||||
|
if (!process.paths) return 0;
|
||||||
|
|
||||||
|
let cumulativePoints = 0;
|
||||||
|
for (const path of process.paths) {
|
||||||
|
for (let i = 0; i < (path.points?.length || 0); i++) {
|
||||||
|
if (path.points[i].uuid === point.uuid) {
|
||||||
|
return cumulativePoints + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cumulativePoints += path.points?.length || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get point data for current animation index
|
||||||
|
function getPointDataForAnimationIndex(process, index) {
|
||||||
|
if (!process.paths) return null;
|
||||||
|
|
||||||
|
let cumulativePoints = 0;
|
||||||
|
for (const path of process.paths) {
|
||||||
|
const pointCount = path.points?.length || 0;
|
||||||
|
|
||||||
|
if (index < cumulativePoints + pointCount) {
|
||||||
|
const pointIndex = index - cumulativePoints;
|
||||||
|
return path.points?.[pointIndex] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
cumulativePoints += pointCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert process paths to Vector3 format
|
||||||
|
function getProcessPath(process) {
|
||||||
|
if (!process.animationPath) {
|
||||||
|
log(`No animation path for process ${process.id}`);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return process.animationPath.map((p) => ({ x: p.x, y: p.y, z: p.z })) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle material swap for an object
|
||||||
|
function handleMaterialSwap(processId, objectId, materialType) {
|
||||||
|
const processState = animationStates[processId];
|
||||||
|
if (!processState || !processState.spawnedObjects[objectId]) return;
|
||||||
|
|
||||||
|
processState.spawnedObjects[objectId].materialType = materialType;
|
||||||
|
|
||||||
|
// Notify main thread about material change
|
||||||
|
self.postMessage({
|
||||||
|
type: "materialChanged",
|
||||||
|
data: {
|
||||||
|
processId,
|
||||||
|
objectId,
|
||||||
|
materialType,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle point actions for an object
|
||||||
|
function handlePointActions(processId, objectId, actions = [], currentTime) {
|
||||||
|
let shouldStopAnimation = false;
|
||||||
|
const processState = animationStates[processId];
|
||||||
|
|
||||||
|
if (!processState || !processState.spawnedObjects[objectId]) return false;
|
||||||
|
|
||||||
|
const objectState = processState.spawnedObjects[objectId];
|
||||||
|
|
||||||
|
actions.forEach((action) => {
|
||||||
|
if (!action || !action.isUsed) return;
|
||||||
|
|
||||||
|
switch (action.type) {
|
||||||
|
case "Delay":
|
||||||
|
if (objectState.state.isDelaying) return;
|
||||||
|
|
||||||
|
const delayDuration =
|
||||||
|
typeof action.delay === "number"
|
||||||
|
? action.delay
|
||||||
|
: parseFloat(action.delay || "0");
|
||||||
|
|
||||||
|
if (delayDuration > 0) {
|
||||||
|
objectState.state.isDelaying = true;
|
||||||
|
objectState.state.delayStartTime = currentTime;
|
||||||
|
objectState.state.currentDelayDuration = delayDuration;
|
||||||
|
objectState.state.delayComplete = false;
|
||||||
|
shouldStopAnimation = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Despawn":
|
||||||
|
delete processState.spawnedObjects[objectId];
|
||||||
|
shouldStopAnimation = true;
|
||||||
|
|
||||||
|
// Notify main thread about despawn
|
||||||
|
self.postMessage({
|
||||||
|
type: "objectDespawned",
|
||||||
|
data: {
|
||||||
|
processId,
|
||||||
|
objectId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Swap":
|
||||||
|
if (action.material) {
|
||||||
|
handleMaterialSwap(processId, objectId, action.material);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return shouldStopAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if point has non-inherit actions
|
||||||
|
function hasNonInheritActions(actions = []) {
|
||||||
|
return actions.some((action) => action && action.isUsed && action.type !== "Inherit");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate vector lerp (linear interpolation)
|
||||||
|
function lerpVectors(v1, v2, alpha) {
|
||||||
|
return {
|
||||||
|
x: v1.x + (v2.x - v1.x) * alpha,
|
||||||
|
y: v1.y + (v2.y - v1.y) * alpha,
|
||||||
|
z: v1.z + (v2.z - v1.z) * alpha,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate vector distance
|
||||||
|
function distanceBetweenVectors(v1, v2) {
|
||||||
|
const dx = v2.x - v1.x;
|
||||||
|
const dy = v2.y - v1.y;
|
||||||
|
const dz = v2.z - v1.z;
|
||||||
|
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process spawn logic
|
||||||
|
function processSpawns(currentTime) {
|
||||||
|
processes.forEach((process) => {
|
||||||
|
const processState = animationStates[process.id];
|
||||||
|
if (!processState) return;
|
||||||
|
|
||||||
|
const spawnPointData = findSpawnPoint(process);
|
||||||
|
if (!spawnPointData || !spawnPointData.point.actions) return;
|
||||||
|
|
||||||
|
const spawnAction = spawnPointData.point.actions.find(
|
||||||
|
(a) => a.isUsed && a.type === "Spawn"
|
||||||
|
);
|
||||||
|
if (!spawnAction) return;
|
||||||
|
|
||||||
|
const spawnInterval =
|
||||||
|
typeof spawnAction.spawnInterval === "number"
|
||||||
|
? spawnAction.spawnInterval
|
||||||
|
: parseFloat(spawnAction.spawnInterval || "2"); // Default to 2 seconds if not specified
|
||||||
|
|
||||||
|
if (currentTime >= processState.nextSpawnTime) {
|
||||||
|
const newObject = createSpawnedObject(
|
||||||
|
process,
|
||||||
|
spawnPointData,
|
||||||
|
currentTime,
|
||||||
|
spawnAction.material || "Default"
|
||||||
|
);
|
||||||
|
|
||||||
|
processState.spawnedObjects[newObject.id] = newObject;
|
||||||
|
processState.objectIdCounter++;
|
||||||
|
processState.nextSpawnTime = currentTime + spawnInterval;
|
||||||
|
|
||||||
|
log(`Spawned object ${newObject.id} for process ${process.id}`);
|
||||||
|
|
||||||
|
// Notify main thread about new object
|
||||||
|
self.postMessage({
|
||||||
|
type: "objectSpawned",
|
||||||
|
data: {
|
||||||
|
processId: process.id,
|
||||||
|
object: newObject,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update all animations
|
||||||
|
function updateAnimations(delta, currentTime) {
|
||||||
|
// First handle spawning of new objects
|
||||||
|
processSpawns(currentTime);
|
||||||
|
|
||||||
|
// Then animate existing objects
|
||||||
|
processes.forEach((process) => {
|
||||||
|
const processState = animationStates[process.id];
|
||||||
|
if (!processState) return;
|
||||||
|
|
||||||
|
const path = getProcessPath(process);
|
||||||
|
if (path.length < 2) {
|
||||||
|
log(`Path too short for process ${process.id}, length: ${path.length}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedObjects = {};
|
||||||
|
let hasChanges = false;
|
||||||
|
|
||||||
|
Object.entries(processState.spawnedObjects).forEach(([objectId, obj]) => {
|
||||||
|
if (!obj.visible || !obj.state.isAnimating) return;
|
||||||
|
|
||||||
|
const stateRef = obj.state;
|
||||||
|
|
||||||
|
// Use the spawnPointIndex as starting point if it's the initial movement
|
||||||
|
if (stateRef.currentIndex === 0 && stateRef.progress === 0) {
|
||||||
|
stateRef.currentIndex = stateRef.spawnPointIndex || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current point data
|
||||||
|
const currentPointData = getPointDataForAnimationIndex(
|
||||||
|
process,
|
||||||
|
stateRef.currentIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
// Execute actions when arriving at a new point
|
||||||
|
if (stateRef.progress === 0 && currentPointData?.actions) {
|
||||||
|
const shouldStop = handlePointActions(
|
||||||
|
process.id,
|
||||||
|
objectId,
|
||||||
|
currentPointData.actions,
|
||||||
|
currentTime
|
||||||
|
);
|
||||||
|
if (shouldStop) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle delays
|
||||||
|
if (stateRef.isDelaying) {
|
||||||
|
if (
|
||||||
|
currentTime - stateRef.delayStartTime >=
|
||||||
|
stateRef.currentDelayDuration
|
||||||
|
) {
|
||||||
|
stateRef.isDelaying = false;
|
||||||
|
stateRef.delayComplete = true;
|
||||||
|
} else {
|
||||||
|
updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
||||||
|
return; // Keep waiting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextPointIdx = stateRef.currentIndex + 1;
|
||||||
|
const isLastPoint = nextPointIdx >= path.length;
|
||||||
|
|
||||||
|
if (isLastPoint) {
|
||||||
|
if (currentPointData?.actions) {
|
||||||
|
const shouldStop = !hasNonInheritActions(currentPointData.actions);
|
||||||
|
if (shouldStop) {
|
||||||
|
// Reached the end of path with no more actions
|
||||||
|
delete processState.spawnedObjects[objectId];
|
||||||
|
log(`Object ${objectId} completed path`);
|
||||||
|
|
||||||
|
// Notify main thread to remove the object
|
||||||
|
self.postMessage({
|
||||||
|
type: "objectCompleted",
|
||||||
|
data: {
|
||||||
|
processId: process.id,
|
||||||
|
objectId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLastPoint) {
|
||||||
|
const currentPos = path[stateRef.currentIndex];
|
||||||
|
const nextPos = path[nextPointIdx];
|
||||||
|
const distance = distanceBetweenVectors(currentPos, nextPos);
|
||||||
|
|
||||||
|
// Ensure we don't divide by zero
|
||||||
|
if (distance > 0) {
|
||||||
|
const movement = stateRef.speed * delta;
|
||||||
|
|
||||||
|
// Update progress based on distance and speed
|
||||||
|
const oldProgress = stateRef.progress;
|
||||||
|
stateRef.progress += movement / distance;
|
||||||
|
|
||||||
|
if (stateRef.progress >= 1) {
|
||||||
|
// Reached next point
|
||||||
|
stateRef.currentIndex = nextPointIdx;
|
||||||
|
stateRef.progress = 0;
|
||||||
|
stateRef.delayComplete = false;
|
||||||
|
obj.position = [nextPos.x, nextPos.y, nextPos.z];
|
||||||
|
} else {
|
||||||
|
// Interpolate position
|
||||||
|
const lerpedPos = lerpVectors(currentPos, nextPos, stateRef.progress);
|
||||||
|
obj.position = [lerpedPos.x, lerpedPos.y, lerpedPos.z];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send updates when there's meaningful movement
|
||||||
|
if (Math.abs(oldProgress - stateRef.progress) > 0.01) {
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Skip to next point if distance is zero
|
||||||
|
stateRef.currentIndex = nextPointIdx;
|
||||||
|
stateRef.progress = 0;
|
||||||
|
obj.position = [nextPos.x, nextPos.y, nextPos.z];
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update animation state with modified objects
|
||||||
|
if (Object.keys(updatedObjects).length > 0) {
|
||||||
|
processState.spawnedObjects = {
|
||||||
|
...processState.spawnedObjects,
|
||||||
|
...updatedObjects,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only send position updates when there are meaningful changes
|
||||||
|
if (hasChanges) {
|
||||||
|
self.postMessage({
|
||||||
|
type: "positionsUpdated",
|
||||||
|
data: {
|
||||||
|
processId: process.id,
|
||||||
|
objects: updatedObjects,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const Mesh: React.FC = () => {
|
||||||
|
return <mesh></mesh>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Mesh;
|
File diff suppressed because it is too large
Load Diff
|
@ -10,6 +10,7 @@ const ProcessContainer: React.FC = () => {
|
||||||
<>
|
<>
|
||||||
<ProcessCreator onProcessesCreated={setProcesses} />
|
<ProcessCreator onProcessesCreated={setProcesses} />
|
||||||
{processes.length > 0 && <ProcessAnimator processes={processes} />}
|
{processes.length > 0 && <ProcessAnimator processes={processes} />}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,402 @@
|
||||||
|
// import React, {
|
||||||
|
// useEffect,
|
||||||
|
// useMemo,
|
||||||
|
// useState,
|
||||||
|
// useCallback,
|
||||||
|
// useRef,
|
||||||
|
// } from "react";
|
||||||
|
// import { useSimulationPaths } from "../../../store/store";
|
||||||
|
// import * as THREE from "three";
|
||||||
|
// import { useThree } from "@react-three/fiber";
|
||||||
|
// import {
|
||||||
|
// ConveyorEventsSchema,
|
||||||
|
// VehicleEventsSchema,
|
||||||
|
// } from "../../../types/world/worldTypes";
|
||||||
|
|
||||||
|
// // Type definitions
|
||||||
|
// export interface PointAction {
|
||||||
|
// uuid: string;
|
||||||
|
// name: string;
|
||||||
|
// type: string;
|
||||||
|
// material: string;
|
||||||
|
// delay: number | string;
|
||||||
|
// spawnInterval: string | number;
|
||||||
|
// isUsed: boolean;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export interface PathPoint {
|
||||||
|
// uuid: string;
|
||||||
|
// position: [number, number, number];
|
||||||
|
// actions: PointAction[];
|
||||||
|
// connections: {
|
||||||
|
// targets: Array<{ pathUUID: string }>;
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export interface SimulationPath {
|
||||||
|
// modeluuid: string;
|
||||||
|
// points: PathPoint[];
|
||||||
|
// pathPosition: [number, number, number];
|
||||||
|
// speed?: number;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export interface Process {
|
||||||
|
// id: string;
|
||||||
|
// paths: SimulationPath[];
|
||||||
|
// animationPath: THREE.Vector3[];
|
||||||
|
// pointActions: PointAction[][];
|
||||||
|
// speed: number;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// interface ProcessCreatorProps {
|
||||||
|
// onProcessesCreated: (processes: Process[]) => void;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Convert event schemas to SimulationPath
|
||||||
|
// function convertToSimulationPath(
|
||||||
|
// path: ConveyorEventsSchema | VehicleEventsSchema
|
||||||
|
// ): SimulationPath {
|
||||||
|
// const { modeluuid } = path;
|
||||||
|
|
||||||
|
// // Simplified normalizeAction function that preserves exact original properties
|
||||||
|
// const normalizeAction = (action: any): PointAction => {
|
||||||
|
// return { ...action }; // Return exact copy with no modifications
|
||||||
|
// };
|
||||||
|
|
||||||
|
// if (path.type === "Conveyor") {
|
||||||
|
// return {
|
||||||
|
// modeluuid,
|
||||||
|
// points: path.points.map((point) => ({
|
||||||
|
// uuid: point.uuid,
|
||||||
|
// position: point.position,
|
||||||
|
// actions: point.actions.map(normalizeAction), // Preserve exact actions
|
||||||
|
// connections: {
|
||||||
|
// targets: point.connections.targets.map((target) => ({
|
||||||
|
// pathUUID: target.pathUUID,
|
||||||
|
// })),
|
||||||
|
// },
|
||||||
|
// })),
|
||||||
|
// pathPosition: path.position,
|
||||||
|
// speed:
|
||||||
|
// typeof path.speed === "string"
|
||||||
|
// ? parseFloat(path.speed) || 1
|
||||||
|
// : path.speed || 1,
|
||||||
|
// };
|
||||||
|
// } else {
|
||||||
|
// return {
|
||||||
|
// modeluuid,
|
||||||
|
// points: [
|
||||||
|
// {
|
||||||
|
// uuid: path.point.uuid,
|
||||||
|
// position: path.point.position,
|
||||||
|
// actions: Array.isArray(path.point.actions)
|
||||||
|
// ? path.point.actions.map(normalizeAction)
|
||||||
|
// : [normalizeAction(path.point.actions)],
|
||||||
|
// connections: {
|
||||||
|
// targets: path.point.connections.targets.map((target) => ({
|
||||||
|
// pathUUID: target.pathUUID,
|
||||||
|
// })),
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// pathPosition: path.position,
|
||||||
|
// speed: path.point.speed || 1,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Custom shallow comparison for arrays
|
||||||
|
// const areArraysEqual = (a: any[], b: any[]) => {
|
||||||
|
// if (a.length !== b.length) return false;
|
||||||
|
// for (let i = 0; i < a.length; i++) {
|
||||||
|
// if (a[i] !== b[i]) return false;
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Helper function to create an empty process
|
||||||
|
// const createEmptyProcess = (): Process => ({
|
||||||
|
// id: `process-${Math.random().toString(36).substring(2, 11)}`,
|
||||||
|
// paths: [],
|
||||||
|
// animationPath: [],
|
||||||
|
// pointActions: [],
|
||||||
|
// speed: 1,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // Enhanced connection checking function
|
||||||
|
// function shouldReverseNextPath(
|
||||||
|
// currentPath: SimulationPath,
|
||||||
|
// nextPath: SimulationPath
|
||||||
|
// ): boolean {
|
||||||
|
// if (nextPath.points.length !== 3) return false;
|
||||||
|
|
||||||
|
// const currentLastPoint = currentPath.points[currentPath.points.length - 1];
|
||||||
|
// const nextFirstPoint = nextPath.points[0];
|
||||||
|
// const nextLastPoint = nextPath.points[nextPath.points.length - 1];
|
||||||
|
|
||||||
|
// // Check if current last connects to next last (requires reversal)
|
||||||
|
// const connectsToLast = currentLastPoint.connections.targets.some(
|
||||||
|
// (target) =>
|
||||||
|
// target.pathUUID === nextPath.modeluuid &&
|
||||||
|
// nextLastPoint.connections.targets.some(
|
||||||
|
// (t) => t.pathUUID === currentPath.modeluuid
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // Check if current last connects to next first (no reversal needed)
|
||||||
|
// const connectsToFirst = currentLastPoint.connections.targets.some(
|
||||||
|
// (target) =>
|
||||||
|
// target.pathUUID === nextPath.modeluuid &&
|
||||||
|
// nextFirstPoint.connections.targets.some(
|
||||||
|
// (t) => t.pathUUID === currentPath.modeluuid
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // Only reverse if connected to last point and not to first point
|
||||||
|
// return connectsToLast && !connectsToFirst;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Updated path adjustment function
|
||||||
|
// function adjustPathPointsOrder(paths: SimulationPath[]): SimulationPath[] {
|
||||||
|
// if (paths.length < 2) return paths;
|
||||||
|
|
||||||
|
// const adjustedPaths = [...paths];
|
||||||
|
|
||||||
|
// for (let i = 0; i < adjustedPaths.length - 1; i++) {
|
||||||
|
// const currentPath = adjustedPaths[i];
|
||||||
|
// const nextPath = adjustedPaths[i + 1];
|
||||||
|
|
||||||
|
// if (shouldReverseNextPath(currentPath, nextPath)) {
|
||||||
|
// const reversedPoints = [
|
||||||
|
// nextPath.points[2],
|
||||||
|
// nextPath.points[1],
|
||||||
|
// nextPath.points[0],
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// adjustedPaths[i + 1] = {
|
||||||
|
// ...nextPath,
|
||||||
|
// points: reversedPoints,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return adjustedPaths;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Main hook for process creation
|
||||||
|
// export function useProcessCreation() {
|
||||||
|
// const { scene } = useThree();
|
||||||
|
// const [processes, setProcesses] = useState<Process[]>([]);
|
||||||
|
|
||||||
|
// const hasSpawnAction = useCallback((path: SimulationPath): boolean => {
|
||||||
|
// return path.points.some((point) =>
|
||||||
|
// point.actions.some((action) => action.type.toLowerCase() === "spawn")
|
||||||
|
// );
|
||||||
|
// }, []);
|
||||||
|
|
||||||
|
// const createProcess = useCallback(
|
||||||
|
// (paths: SimulationPath[]): Process => {
|
||||||
|
// if (!paths || paths.length === 0) {
|
||||||
|
// return createEmptyProcess();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const animationPath: THREE.Vector3[] = [];
|
||||||
|
// const pointActions: PointAction[][] = [];
|
||||||
|
// const processSpeed = paths[0]?.speed || 1;
|
||||||
|
|
||||||
|
// for (const path of paths) {
|
||||||
|
// for (const point of path.points) {
|
||||||
|
// const obj = scene.getObjectByProperty("uuid", point.uuid);
|
||||||
|
// if (!obj) {
|
||||||
|
// console.warn(`Object with UUID ${point.uuid} not found in scene`);
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const position = obj.getWorldPosition(new THREE.Vector3());
|
||||||
|
// animationPath.push(position.clone());
|
||||||
|
// pointActions.push(point.actions);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// id: `process-${Math.random().toString(36).substring(2, 11)}`,
|
||||||
|
// paths,
|
||||||
|
// animationPath,
|
||||||
|
// pointActions,
|
||||||
|
// speed: processSpeed,
|
||||||
|
// };
|
||||||
|
// },
|
||||||
|
// [scene]
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const getAllConnectedPaths = useCallback(
|
||||||
|
// (
|
||||||
|
// initialPath: SimulationPath,
|
||||||
|
// allPaths: SimulationPath[],
|
||||||
|
// visited: Set<string> = new Set()
|
||||||
|
// ): SimulationPath[] => {
|
||||||
|
// const connectedPaths: SimulationPath[] = [];
|
||||||
|
// const queue: SimulationPath[] = [initialPath];
|
||||||
|
// visited.add(initialPath.modeluuid);
|
||||||
|
|
||||||
|
// const pathMap = new Map<string, SimulationPath>();
|
||||||
|
// allPaths.forEach((path) => pathMap.set(path.modeluuid, path));
|
||||||
|
|
||||||
|
// while (queue.length > 0) {
|
||||||
|
// const currentPath = queue.shift()!;
|
||||||
|
// connectedPaths.push(currentPath);
|
||||||
|
|
||||||
|
// // Process outgoing connections
|
||||||
|
// for (const point of currentPath.points) {
|
||||||
|
// for (const target of point.connections.targets) {
|
||||||
|
// if (!visited.has(target.pathUUID)) {
|
||||||
|
// const targetPath = pathMap.get(target.pathUUID);
|
||||||
|
// if (targetPath) {
|
||||||
|
// visited.add(target.pathUUID);
|
||||||
|
// queue.push(targetPath);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Process incoming connections
|
||||||
|
// for (const [uuid, path] of pathMap) {
|
||||||
|
// if (!visited.has(uuid)) {
|
||||||
|
// const hasConnectionToCurrent = path.points.some((point) =>
|
||||||
|
// point.connections.targets.some(
|
||||||
|
// (t) => t.pathUUID === currentPath.modeluuid
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// if (hasConnectionToCurrent) {
|
||||||
|
// visited.add(uuid);
|
||||||
|
// queue.push(path);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return connectedPaths;
|
||||||
|
// },
|
||||||
|
// []
|
||||||
|
// );
|
||||||
|
|
||||||
|
// const createProcessesFromPaths = useCallback(
|
||||||
|
// (paths: SimulationPath[]): Process[] => {
|
||||||
|
// if (!paths || paths.length === 0) return [];
|
||||||
|
|
||||||
|
// const visited = new Set<string>();
|
||||||
|
// const processes: Process[] = [];
|
||||||
|
// const pathMap = new Map<string, SimulationPath>();
|
||||||
|
// paths.forEach((path) => pathMap.set(path.modeluuid, path));
|
||||||
|
|
||||||
|
// for (const path of paths) {
|
||||||
|
// if (!visited.has(path.modeluuid) && hasSpawnAction(path)) {
|
||||||
|
// const connectedPaths = getAllConnectedPaths(path, paths, visited);
|
||||||
|
// const adjustedPaths = adjustPathPointsOrder(connectedPaths);
|
||||||
|
// const process = createProcess(adjustedPaths);
|
||||||
|
// processes.push(process);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return processes;
|
||||||
|
// },
|
||||||
|
// [createProcess, getAllConnectedPaths, hasSpawnAction]
|
||||||
|
// );
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// processes,
|
||||||
|
// createProcessesFromPaths,
|
||||||
|
// setProcesses,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
|
||||||
|
// ({ onProcessesCreated }) => {
|
||||||
|
// const { simulationPaths } = useSimulationPaths();
|
||||||
|
// const { createProcessesFromPaths } = useProcessCreation();
|
||||||
|
// const prevPathsRef = useRef<SimulationPath[]>([]);
|
||||||
|
// const prevProcessesRef = useRef<Process[]>([]);
|
||||||
|
|
||||||
|
// const convertedPaths = useMemo((): SimulationPath[] => {
|
||||||
|
// if (!simulationPaths) return [];
|
||||||
|
// return simulationPaths.map((path) =>
|
||||||
|
// convertToSimulationPath(
|
||||||
|
// path as ConveyorEventsSchema | VehicleEventsSchema
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// }, [simulationPaths]);
|
||||||
|
|
||||||
|
// const pathsDependency = useMemo(() => {
|
||||||
|
// if (!convertedPaths) return null;
|
||||||
|
// return convertedPaths.map((path) => ({
|
||||||
|
// id: path.modeluuid,
|
||||||
|
// hasSpawn: path.points.some((p: PathPoint) =>
|
||||||
|
// p.actions.some((a: PointAction) => a.type.toLowerCase() === "spawn")
|
||||||
|
// ),
|
||||||
|
// connections: path.points
|
||||||
|
// .flatMap((p: PathPoint) =>
|
||||||
|
// p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID)
|
||||||
|
// )
|
||||||
|
// .join(","),
|
||||||
|
// }));
|
||||||
|
// }, [convertedPaths]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// if (!convertedPaths || convertedPaths.length === 0) {
|
||||||
|
// if (prevProcessesRef.current.length > 0) {
|
||||||
|
// onProcessesCreated([]);
|
||||||
|
// prevProcessesRef.current = [];
|
||||||
|
// }
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (areArraysEqual(prevPathsRef.current, convertedPaths)) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// prevPathsRef.current = convertedPaths;
|
||||||
|
// const newProcesses = createProcessesFromPaths(convertedPaths);
|
||||||
|
|
||||||
|
// // console.log("--- Action Types in Paths ---");
|
||||||
|
// // convertedPaths.forEach((path) => {
|
||||||
|
// // path.points.forEach((point) => {
|
||||||
|
// // point.actions.forEach((action) => {
|
||||||
|
// // console.log(
|
||||||
|
// // `Path ${path.modeluuid}, Point ${point.uuid}: ${action.type}`
|
||||||
|
// // );
|
||||||
|
// // });
|
||||||
|
// // });
|
||||||
|
// // });
|
||||||
|
// // console.log("New processes:", newProcesses);
|
||||||
|
|
||||||
|
// if (
|
||||||
|
// newProcesses.length !== prevProcessesRef.current.length ||
|
||||||
|
// !newProcesses.every(
|
||||||
|
// (proc, i) =>
|
||||||
|
// proc.paths.length === prevProcessesRef.current[i]?.paths.length &&
|
||||||
|
// proc.paths.every(
|
||||||
|
// (path, j) =>
|
||||||
|
// path.modeluuid ===
|
||||||
|
// prevProcessesRef.current[i]?.paths[j]?.modeluuid
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// ) {
|
||||||
|
// onProcessesCreated(newProcesses);
|
||||||
|
// // prevProcessesRef.current = newProcesses;
|
||||||
|
// }
|
||||||
|
// }, [
|
||||||
|
// pathsDependency,
|
||||||
|
// onProcessesCreated,
|
||||||
|
// convertedPaths,
|
||||||
|
// createProcessesFromPaths,
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// export default ProcessCreator;
|
||||||
|
|
||||||
import React, {
|
import React, {
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
|
@ -156,12 +555,38 @@ function shouldReverseNextPath(
|
||||||
return connectsToLast && !connectsToFirst;
|
return connectsToLast && !connectsToFirst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if a point has a spawn action
|
||||||
|
function hasSpawnAction(point: PathPoint): boolean {
|
||||||
|
return point.actions.some((action) => action.type.toLowerCase() === "spawn");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure spawn point is always at the beginning of the path
|
||||||
|
function ensureSpawnPointIsFirst(path: SimulationPath): SimulationPath {
|
||||||
|
if (path.points.length !== 3) return path;
|
||||||
|
|
||||||
|
// If the third point has spawn action and first doesn't, reverse the array
|
||||||
|
if (hasSpawnAction(path.points[2]) && !hasSpawnAction(path.points[0])) {
|
||||||
|
return {
|
||||||
|
...path,
|
||||||
|
points: [...path.points].reverse(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
// Updated path adjustment function
|
// Updated path adjustment function
|
||||||
function adjustPathPointsOrder(paths: SimulationPath[]): SimulationPath[] {
|
function adjustPathPointsOrder(paths: SimulationPath[]): SimulationPath[] {
|
||||||
if (paths.length < 2) return paths;
|
if (paths.length < 1) return paths;
|
||||||
|
|
||||||
const adjustedPaths = [...paths];
|
const adjustedPaths = [...paths];
|
||||||
|
|
||||||
|
// First ensure all paths have spawn points at the beginning
|
||||||
|
for (let i = 0; i < adjustedPaths.length; i++) {
|
||||||
|
adjustedPaths[i] = ensureSpawnPointIsFirst(adjustedPaths[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then handle connections between paths
|
||||||
for (let i = 0; i < adjustedPaths.length - 1; i++) {
|
for (let i = 0; i < adjustedPaths.length - 1; i++) {
|
||||||
const currentPath = adjustedPaths[i];
|
const currentPath = adjustedPaths[i];
|
||||||
const nextPath = adjustedPaths[i + 1];
|
const nextPath = adjustedPaths[i + 1];
|
||||||
|
@ -326,13 +751,17 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
|
||||||
);
|
);
|
||||||
}, [simulationPaths]);
|
}, [simulationPaths]);
|
||||||
|
|
||||||
|
// Enhanced dependency tracking that includes action types
|
||||||
const pathsDependency = useMemo(() => {
|
const pathsDependency = useMemo(() => {
|
||||||
if (!convertedPaths) return null;
|
if (!convertedPaths) return null;
|
||||||
return convertedPaths.map((path) => ({
|
return convertedPaths.map((path) => ({
|
||||||
id: path.modeluuid,
|
id: path.modeluuid,
|
||||||
hasSpawn: path.points.some((p: PathPoint) =>
|
// Track all action types for each point
|
||||||
p.actions.some((a: PointAction) => a.type.toLowerCase() === "spawn")
|
actionSignature: path.points
|
||||||
),
|
.map((point, index) =>
|
||||||
|
point.actions.map((action) => `${index}-${action.type}`).join("|")
|
||||||
|
)
|
||||||
|
.join(","),
|
||||||
connections: path.points
|
connections: path.points
|
||||||
.flatMap((p: PathPoint) =>
|
.flatMap((p: PathPoint) =>
|
||||||
p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID)
|
p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID)
|
||||||
|
@ -341,6 +770,7 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
|
||||||
}));
|
}));
|
||||||
}, [convertedPaths]);
|
}, [convertedPaths]);
|
||||||
|
|
||||||
|
// Force process recreation when paths change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!convertedPaths || convertedPaths.length === 0) {
|
if (!convertedPaths || convertedPaths.length === 0) {
|
||||||
if (prevProcessesRef.current.length > 0) {
|
if (prevProcessesRef.current.length > 0) {
|
||||||
|
@ -350,42 +780,16 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (areArraysEqual(prevPathsRef.current, convertedPaths)) {
|
// Always regenerate processes if the pathsDependency has changed
|
||||||
return;
|
// This ensures action type changes will be detected
|
||||||
}
|
|
||||||
|
|
||||||
prevPathsRef.current = convertedPaths;
|
|
||||||
const newProcesses = createProcessesFromPaths(convertedPaths);
|
const newProcesses = createProcessesFromPaths(convertedPaths);
|
||||||
|
prevPathsRef.current = convertedPaths;
|
||||||
|
|
||||||
// console.log("--- Action Types in Paths ---");
|
// Always update processes when action types change
|
||||||
// convertedPaths.forEach((path) => {
|
onProcessesCreated(newProcesses);
|
||||||
// path.points.forEach((point) => {
|
prevProcessesRef.current = newProcesses;
|
||||||
// point.actions.forEach((action) => {
|
|
||||||
// console.log(
|
|
||||||
// `Path ${path.modeluuid}, Point ${point.uuid}: ${action.type}`
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// console.log("New processes:", newProcesses);
|
|
||||||
|
|
||||||
if (
|
|
||||||
newProcesses.length !== prevProcessesRef.current.length ||
|
|
||||||
!newProcesses.every(
|
|
||||||
(proc, i) =>
|
|
||||||
proc.paths.length === prevProcessesRef.current[i]?.paths.length &&
|
|
||||||
proc.paths.every(
|
|
||||||
(path, j) =>
|
|
||||||
path.modeluuid ===
|
|
||||||
prevProcessesRef.current[i]?.paths[j]?.modeluuid
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
onProcessesCreated(newProcesses);
|
|
||||||
// prevProcessesRef.current = newProcesses;
|
|
||||||
}
|
|
||||||
}, [
|
}, [
|
||||||
pathsDependency,
|
pathsDependency, // This now includes action types
|
||||||
onProcessesCreated,
|
onProcessesCreated,
|
||||||
convertedPaths,
|
convertedPaths,
|
||||||
createProcessesFromPaths,
|
createProcessesFromPaths,
|
||||||
|
|
|
@ -19,7 +19,7 @@ function Simulation() {
|
||||||
const [processes, setProcesses] = useState([]);
|
const [processes, setProcesses] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log('simulationPaths: ', simulationPaths);
|
console.log('simulationPaths: ', simulationPaths);
|
||||||
}, [simulationPaths]);
|
}, [simulationPaths]);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
|
|
|
@ -30,7 +30,7 @@ export const handleSaveTemplate = async ({
|
||||||
}: HandleSaveTemplateProps): Promise<void> => {
|
}: HandleSaveTemplateProps): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
// Check if the selected zone has any widgets
|
// Check if the selected zone has any widgets
|
||||||
if (!selectedZone.widgets || selectedZone.widgets.length === 0) {
|
if (!selectedZone.panelOrder || selectedZone.panelOrder.length === 0) {
|
||||||
console.warn("No widgets found in the selected zone.");
|
console.warn("No widgets found in the selected zone.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
|
export const setEventApi = async (
|
||||||
|
organization: string,
|
||||||
|
modeluuid: string,
|
||||||
|
eventData: any
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const body: any = { organization, modeluuid, eventData };
|
||||||
|
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/eventDataUpdate`, {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to set or update Floor Item");
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -30,7 +30,6 @@ export const setFloorItemApi = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
console.log('result: ', result);
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||||
export const saveTemplateApi = async (organization: string, template: {}) => {
|
export const saveTemplateApi = async (organization: string, template: {}) => {
|
||||||
console.log('template: ', template);
|
console.log('template: ', template);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/v2/template/save`, {
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/template/save`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
@ -16,7 +16,7 @@ export const saveTemplateApi = async (organization: string, template: {}) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
console.log('result: ', result);
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
|
|
@ -343,14 +343,21 @@ export const useSelectedPath = create<any>((set: any) => ({
|
||||||
interface SimulationPathsStore {
|
interface SimulationPathsStore {
|
||||||
simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[];
|
simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[];
|
||||||
setSimulationPaths: (
|
setSimulationPaths: (
|
||||||
paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]
|
paths:
|
||||||
|
| (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]
|
||||||
|
| ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]
|
||||||
|
) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[])
|
||||||
) => void;
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
|
export const useSimulationPaths = create<SimulationPathsStore>((set) => ({
|
||||||
simulationPaths: [],
|
simulationPaths: [],
|
||||||
setSimulationPaths: (paths) => set({ simulationPaths: paths }),
|
setSimulationPaths: (paths) =>
|
||||||
}));
|
set((state) => ({
|
||||||
|
simulationPaths:
|
||||||
|
typeof paths === "function" ? paths(state.simulationPaths) : paths,
|
||||||
|
})),
|
||||||
|
}))
|
||||||
|
|
||||||
export const useIsConnecting = create<any>((set: any) => ({
|
export const useIsConnecting = create<any>((set: any) => ({
|
||||||
isConnecting: false,
|
isConnecting: false,
|
||||||
|
|
|
@ -3,15 +3,23 @@
|
||||||
|
|
||||||
.dropdown-list-container {
|
.dropdown-list-container {
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
|
||||||
|
.lists-container {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.head {
|
.head {
|
||||||
@include flex-space-between;
|
@include flex-space-between;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
|
|
||||||
.options {
|
.options {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -22,34 +30,52 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-wrapper {
|
.list-wrapper {
|
||||||
|
|
||||||
|
|
||||||
.no-item {
|
.no-item {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-container {
|
.list-container {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
// margin-left: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
@include flex-space-between;
|
@include flex-space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 4px 12px;
|
padding: 4px 8px;
|
||||||
border-radius: #{$border-radius-large};
|
border-radius: #{$border-radius-large};
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
max-width: 180px;
|
max-width: 180px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.options-container {
|
.options-container {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
background-color: var(--highlight-accent-color);
|
background-color: var(--highlight-accent-color);
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.asset-list {
|
||||||
|
border-left: 2px solid var(--border-color);
|
||||||
|
|
||||||
|
margin-left: 20px
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -253,6 +253,7 @@
|
||||||
|
|
||||||
.user-profile-container {
|
.user-profile-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
.user-profile {
|
.user-profile {
|
||||||
background: var(--accent-color);
|
background: var(--accent-color);
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
|
@ -483,6 +484,9 @@
|
||||||
height: 150px;
|
height: 150px;
|
||||||
background: #f0f0f0;
|
background: #f0f0f0;
|
||||||
// border-radius: 8px;
|
// border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
// justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.optionsContainer {
|
.optionsContainer {
|
||||||
|
@ -497,7 +501,8 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
|
||||||
.regularDropdown-container {
|
.regularDropdown-container,
|
||||||
|
input {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,6 +691,7 @@
|
||||||
font-weight: var(--font-weight-regular);
|
font-weight: var(--font-weight-regular);
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-toggle-container {
|
.input-toggle-container {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
|
@ -1009,11 +1015,9 @@
|
||||||
top: 50%;
|
top: 50%;
|
||||||
right: -10px;
|
right: -10px;
|
||||||
transform: translate(0, -50%);
|
transform: translate(0, -50%);
|
||||||
background: linear-gradient(
|
background: linear-gradient(144.19deg,
|
||||||
144.19deg,
|
#f1e7cd 16.62%,
|
||||||
#f1e7cd 16.62%,
|
#fffaef 85.81%);
|
||||||
#fffaef 85.81%
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-image {
|
.category-image {
|
||||||
|
@ -1117,10 +1121,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.assets-result {
|
.assets-result {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 8px 10px;
|
margin: 8px 10px;
|
||||||
|
|
||||||
.assets-wrapper {
|
.assets-wrapper {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
// max-width: calc(100% - 450px);
|
max-width: calc(100% - 500px);
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -166,14 +166,16 @@
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: white;
|
background: var(--background-color);
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
overflow: visible !important;
|
overflow: auto;
|
||||||
z-index: $z-index-tools;
|
z-index: $z-index-tools;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.panel-content {
|
.panel-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -319,6 +321,7 @@
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,6 +718,13 @@
|
||||||
z-index: 2 !important;
|
z-index: 2 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.connectionSuccess {
|
||||||
|
outline-color: #43C06D;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connectionFails {
|
||||||
|
outline-color: #ffe3e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.editWidgetOptions {
|
.editWidgetOptions {
|
||||||
|
|
Loading…
Reference in New Issue