diff --git a/package-lock.json b/package-lock.json index f1d6e04..b84ead5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,9 @@ "dependencies": { "@aws-amplify/cli-extensibility-helper": "^3.0.1", "@aws-amplify/ui-react": "^5.3.3", + "@babylonjs/core": "^7.34.4", + "@babylonjs/loaders": "^7.34.4", + "@babylonjs/materials": "^7.37.0", "@blueprintjs/core": "^4.17.8", "@blueprintjs/icons": "^4.14.5", "@emotion/react": "^11.10.6", @@ -30,6 +33,7 @@ "assign-deep": "^1.0.1", "aws-amplify": "^5.0.23", "aws-amplify-react": "^5.1.9", + "babylonjs": "^7.34.4", "bootstrap": "^5.2.3", "caniuse-lite": "^1.0.30001487", "cypress-file-upload": "^5.0.8", @@ -50,6 +54,7 @@ "query-string": "^8.1.0", "react": "^18.2.0", "react-3d-viewer": "^1.0.12", + "react-babylonjs": "^3.2.1", "react-csv": "^2.2.2", "react-dom": "^18.2.0", "react-focus-lock": "^2.9.4", @@ -12785,6 +12790,41 @@ "node": ">=6.9.0" } }, + "node_modules/@babylonjs/core": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-7.34.4.tgz", + "integrity": "sha512-RwAEixWrTPmxN8WCtBav/fNveejRK5f9Cmc88qMiE3jc0HegVS+WarDS5yldMeIQKSuzOVaRfZo1xEY3CTmmFA==", + "license": "Apache-2.0" + }, + "node_modules/@babylonjs/gui": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-7.34.4.tgz", + "integrity": "sha512-yADpmCMSAaLS7vGBtViB8HyDfkBkJ4aMZPspwhtjM5iVqNKkkrQ2cvtVHI69nAO5NLwwOOSlYgHDDhTaAGMWPA==", + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "@babylonjs/core": "^7.0.0" + } + }, + "node_modules/@babylonjs/loaders": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-7.34.4.tgz", + "integrity": "sha512-CZfwtJXOZf5JrABbzxZ9s/5Ig8WZfS3XmYP69fAHoxcVedUNopctimM6KhjJYipeknbm1FUKMJ8TBBT/Tv8lig==", + "license": "Apache-2.0", + "peerDependencies": { + "@babylonjs/core": "^7.0.0", + "babylonjs-gltf2interface": "^7.0.0" + } + }, + "node_modules/@babylonjs/materials": { + "version": "7.37.0", + "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-7.37.0.tgz", + "integrity": "sha512-a8vmj2+2moiaV6pU9IfAa1CMz56ydE5hk4LhvZ4kLpfWCH+lrcApzZKKskBTFIAKBZ1NJzwsKEh99ELiDlJ1NA==", + "license": "Apache-2.0", + "peerDependencies": { + "@babylonjs/core": "^7.0.0" + } + }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -21371,6 +21411,20 @@ "babel-plugin-transform-react-remove-prop-types": "^0.4.24" } }, + "node_modules/babylonjs": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-7.34.4.tgz", + "integrity": "sha512-ejssY7KbbLrSYtxf+2MdoPezpMh+cCtyf/ZMutdNNYlvFdIS+QUWaNad3GSRABHeBrRvthQtCSsYZx0+wp/+Sw==", + "hasInstallScript": true, + "license": "Apache-2.0" + }, + "node_modules/babylonjs-gltf2interface": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.34.4.tgz", + "integrity": "sha512-9K+gfJZ3Vn9AYVk8zrJeXPIzghCChDPH85sI+22VKhsnnyUfZs5lbO+muShOTrlBiOkCQQDyL2S8vOt5D1OIYg==", + "license": "Apache-2.0", + "peer": true + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -38888,6 +38942,29 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, + "node_modules/react-babylonjs": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/react-babylonjs/-/react-babylonjs-3.2.1.tgz", + "integrity": "sha512-nre7ArbP5mKmJK4VZ1Qs2qG+e1t/YlurmaE0O/lZUexwudOnbL17BzkHJl2jpu0h9m7otoqVdeKw9A6bDtsV5Q==", + "license": "MIT", + "dependencies": { + "react-reconciler": "^0.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babylonjs/core": "5.x || 6.x || 7.x", + "@babylonjs/gui": "5.x || 6.x || 7.x", + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/react-beautiful-dnd": { "version": "13.1.1", "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", @@ -39442,6 +39519,31 @@ "react-dom": "^16 || ^17 || ^18" } }, + "node_modules/react-reconciler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", + "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.21.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/react-reconciler/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/react-redux": { "version": "7.2.9", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", @@ -58171,6 +58273,30 @@ "to-fast-properties": "^2.0.0" } }, + "@babylonjs/core": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-7.34.4.tgz", + "integrity": "sha512-RwAEixWrTPmxN8WCtBav/fNveejRK5f9Cmc88qMiE3jc0HegVS+WarDS5yldMeIQKSuzOVaRfZo1xEY3CTmmFA==" + }, + "@babylonjs/gui": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-7.34.4.tgz", + "integrity": "sha512-yADpmCMSAaLS7vGBtViB8HyDfkBkJ4aMZPspwhtjM5iVqNKkkrQ2cvtVHI69nAO5NLwwOOSlYgHDDhTaAGMWPA==", + "peer": true, + "requires": {} + }, + "@babylonjs/loaders": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-7.34.4.tgz", + "integrity": "sha512-CZfwtJXOZf5JrABbzxZ9s/5Ig8WZfS3XmYP69fAHoxcVedUNopctimM6KhjJYipeknbm1FUKMJ8TBBT/Tv8lig==", + "requires": {} + }, + "@babylonjs/materials": { + "version": "7.37.0", + "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-7.37.0.tgz", + "integrity": "sha512-a8vmj2+2moiaV6pU9IfAa1CMz56ydE5hk4LhvZ4kLpfWCH+lrcApzZKKskBTFIAKBZ1NJzwsKEh99ELiDlJ1NA==", + "requires": {} + }, "@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -64766,6 +64892,17 @@ "babel-plugin-transform-react-remove-prop-types": "^0.4.24" } }, + "babylonjs": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/babylonjs/-/babylonjs-7.34.4.tgz", + "integrity": "sha512-ejssY7KbbLrSYtxf+2MdoPezpMh+cCtyf/ZMutdNNYlvFdIS+QUWaNad3GSRABHeBrRvthQtCSsYZx0+wp/+Sw==" + }, + "babylonjs-gltf2interface": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.34.4.tgz", + "integrity": "sha512-9K+gfJZ3Vn9AYVk8zrJeXPIzghCChDPH85sI+22VKhsnnyUfZs5lbO+muShOTrlBiOkCQQDyL2S8vOt5D1OIYg==", + "peer": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -77795,6 +77932,14 @@ } } }, + "react-babylonjs": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/react-babylonjs/-/react-babylonjs-3.2.1.tgz", + "integrity": "sha512-nre7ArbP5mKmJK4VZ1Qs2qG+e1t/YlurmaE0O/lZUexwudOnbL17BzkHJl2jpu0h9m7otoqVdeKw9A6bDtsV5Q==", + "requires": { + "react-reconciler": "^0.27.0" + } + }, "react-beautiful-dnd": { "version": "13.1.1", "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", @@ -78218,6 +78363,25 @@ "quill": "^1.3.7" } }, + "react-reconciler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", + "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.21.0" + }, + "dependencies": { + "scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "requires": { + "loose-envify": "^1.1.0" + } + } + } + }, "react-redux": { "version": "7.2.9", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", diff --git a/package.json b/package.json index e692c57..e17c278 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "dependencies": { "@aws-amplify/cli-extensibility-helper": "^3.0.1", "@aws-amplify/ui-react": "^5.3.3", + "@babylonjs/core": "^7.34.4", + "@babylonjs/loaders": "^7.34.4", + "@babylonjs/materials": "^7.37.0", "@blueprintjs/core": "^4.17.8", "@blueprintjs/icons": "^4.14.5", "@emotion/react": "^11.10.6", @@ -25,6 +28,7 @@ "assign-deep": "^1.0.1", "aws-amplify": "^5.0.23", "aws-amplify-react": "^5.1.9", + "babylonjs": "^7.34.4", "bootstrap": "^5.2.3", "caniuse-lite": "^1.0.30001487", "cypress-file-upload": "^5.0.8", @@ -45,6 +49,7 @@ "query-string": "^8.1.0", "react": "^18.2.0", "react-3d-viewer": "^1.0.12", + "react-babylonjs": "^3.2.1", "react-csv": "^2.2.2", "react-dom": "^18.2.0", "react-focus-lock": "^2.9.4", diff --git a/src/components/BabylonElement.jsx b/src/components/BabylonElement.jsx new file mode 100644 index 0000000..81b581e --- /dev/null +++ b/src/components/BabylonElement.jsx @@ -0,0 +1,147 @@ +import React, { useEffect } from "react"; +import { registerBuiltInLoaders } from "@babylonjs/loaders/dynamic"; +import * as BABYLON from "@babylonjs/core"; +import { GridMaterial } from "@babylonjs/materials/"; +import "../css/_3dViewer.scss"; + +const BabylonElement = (props) => { + const disableScroll = () => { + [document.body, document.html].forEach((el) => { + el?.classList.add("no-scroll"); + }); + }; + + const enableScroll = () => { + [document.body, document.html].forEach((el) => { + el?.classList.remove("no-scroll"); + }); + }; + + const addListeners = (canvas, engine) => { + canvas.addEventListener("mouseover", disableScroll); + canvas.addEventListener("mouseout", enableScroll); + + window.addEventListener("resize", () => { + engine.resize(); + }); + }; + + const removeListeners = (canvas, engine) => { + canvas.removeEventListener("mouseover", disableScroll); + canvas.removeEventListener("mouseout", enableScroll); + + window.removeEventListener("resize", () => { + engine.resize(); + }); + }; + + const createScene = async (canvas, engine, modelURL) => { + const AXES_LENGTH = 10; + const scene = new BABYLON.Scene(engine); + scene.environmentTexture = BABYLON.CubeTexture.CreateFromPrefilteredData( + props.env, + scene + ); + const ground = BABYLON.MeshBuilder.CreateGround( + "ground", + { width: AXES_LENGTH, height: AXES_LENGTH, updatable: false }, + scene + ); + const grid = new GridMaterial("grid", scene); + grid.backFaceCulling = false; + grid.mainColor = BABYLON.Color3.White(); + grid.lineColor = BABYLON.Color3.White(); + grid.opacity = 0.25; + + ground.material = grid; + ground.alwaysSelectAsActiveMesh = true; + ground.isPickable = false; + + // scene.clearColor = new BABYLON.Color4(0,0,0,1); + const model = await loadModel(scene, modelURL); + const modelDimensions = model.ellipsoid; + const modelMaxSize = Math.max( + modelDimensions._x, + modelDimensions._y, + modelDimensions._z + ); + + model.position = new BABYLON.Vector3(0, modelDimensions._y, 0); + const camera = new BABYLON.ArcRotateCamera( + "camera", + 0, + modelDimensions._y, + modelMaxSize * 2, + new BABYLON.Vector3(0, modelDimensions._y, 0), + scene + ); + camera.setPosition( + new BABYLON.Vector3(0, modelDimensions._y, modelMaxSize * 2) + ); + camera.setTarget( + new BABYLON.Vector3(0, modelDimensions._y, modelMaxSize * 2) + ); + camera.wheelPrecision = 100; + camera.lowerRadiusLimit = modelMaxSize; + camera.upperRadiusLimit = modelMaxSize * 10; + camera.attachControl(canvas, true); + camera.minZ = 0.1; + + engine.runRenderLoop(function () { + camera.setTarget(model.position); + scene.render(); + }); + }; + + const createCanvas = (canvasWrapper) => { + const canvas = document.createElement("canvas"); + canvas.style.width = "100%"; + canvas.style.height = "100%"; + canvas.id = "three-d-canvas"; + canvasWrapper.innerHTML = ""; + canvasWrapper.appendChild(canvas); + + return canvas; + }; + + const loadModel = async (scene, url) => { + const filename = url.split("/").pop(); + const path = url.replace(filename, ""); + const response = await BABYLON.SceneLoader.ImportMeshAsync( + null, + path, + filename, + scene + ); + const model = response.meshes[0]; + + return model; + }; + + useEffect(() => { + registerBuiltInLoaders(); + const canvasWrapper = document.getElementById("canvas-wrapper"); + const canvas = createCanvas(canvasWrapper); + const engine = new BABYLON.Engine(canvas, true); + + createScene(canvas, engine, props.model); + + addListeners(canvas, engine); + + return () => { + removeListeners(canvas, engine); + enableScroll(); + engine.dispose(); + }; + }, [props.model]); + + return ( +
+
+
+
+
+ ); +}; + +export default BabylonElement; diff --git a/src/components/CollapsibleCards.js b/src/components/CollapsibleCards.js index 5833d98..5169804 100644 --- a/src/components/CollapsibleCards.js +++ b/src/components/CollapsibleCards.js @@ -191,7 +191,10 @@ export default function CollapsibleCard({ } else if (facetSearchItems.includes(key)) { return (
- + {value}
@@ -282,7 +285,6 @@ export default function CollapsibleCard({ ) : renderContent(data[key], 0)} -
) : null )} diff --git a/src/components/X3DElement.jsx b/src/components/X3DElement.jsx index 8f79942..fab67e0 100644 --- a/src/components/X3DElement.jsx +++ b/src/components/X3DElement.jsx @@ -68,7 +68,7 @@ class X3DElement extends Component {
- + + +
+ ); + } else if (this.is3D_2DiiifType(item)) { display = (