diff --git a/package.json b/package.json index de4f817..eeb57b7 100644 --- a/package.json +++ b/package.json @@ -39,8 +39,8 @@ "build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts", "postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts", "lint": "concurrently \"npm run eslint\" \"npm run fs-lint\"", - "eslint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx", - "lint:fix": "cross-env NODE_ENV=development eslint . --fix --ext .js,.jsx,.ts,.tsx", + "eslint": "cross-env NODE_ENV=development eslint ./src --ext .js,.jsx,.ts,.tsx", + "lint:fix": "cross-env NODE_ENV=development eslint ./src --fix --ext .js,.jsx,.ts,.tsx", "fs-lint": "cross-env fs-lint", "package": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never", "prepare": "husky install", diff --git a/src/renderer/constants/routes.ts b/src/renderer/constants/routes.ts index fa3e36d..cdec84c 100644 --- a/src/renderer/constants/routes.ts +++ b/src/renderer/constants/routes.ts @@ -10,5 +10,6 @@ export default { COLUMNS_2D: '/modelling-ui-poc/columns-2d', COLUMN_SYSTEM: '/modelling-ui-poc/column-system', COLUMN_GROUP: '/modelling-ui-poc/column-group', + COLUMN_SELECT: '/modelling-ui-poc/column-select', }, }; diff --git a/src/renderer/pages/modelling-ui-poc/column-select/column-select.tsx b/src/renderer/pages/modelling-ui-poc/column-select/column-select.tsx new file mode 100644 index 0000000..284cf11 --- /dev/null +++ b/src/renderer/pages/modelling-ui-poc/column-select/column-select.tsx @@ -0,0 +1,201 @@ +import { useEffect } from 'react'; +import { + WebGLRenderer, + OrthographicCamera, + Scene, + Color, + Vector2, + Raycaster, +} from 'three'; +import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; +import invariant from 'tiny-invariant'; +import { + InfiniteGrid, + ModelGrid, + ColumnsGroup, +} from 'renderer/three/components'; +import { CSS3DRenderer } from 'three/examples/jsm/renderers/CSS3DRenderer'; +import { COLORS } from 'renderer/constants'; + +const ColumnGroup = () => { + useEffect(() => { + const scene = new Scene(); + const webglContainerEl = document.querySelector('.webgl-wrapper'); + invariant(webglContainerEl, 'could not find container tag'); + const camera = new OrthographicCamera( + -webglContainerEl.clientWidth / 2, + webglContainerEl.clientWidth / 2, + webglContainerEl.clientHeight / 2, + -webglContainerEl.clientHeight / 2, + 0.1, + 1000 + ); + const mouse = new Vector2(); + const raycaster = new Raycaster(); + + function hoverPointer() { + raycaster.setFromCamera(mouse, camera); + const intersects = raycaster.intersectObjects(scene.children); + for (let i = 0; i < intersects.length; i += 1) { + const intObject = intersects[i].object as any; + if (intObject.name === 'column') { + intObject.material.color?.set(COLORS.NOTICE_SOFT_yellow); + } + } + } + + function onPointerMove(event: any) { + // calculate pointer position in normalized device coordinates + // (-1 to +1) for both components + if (!webglContainerEl) return null; + const clientRects = webglContainerEl.getBoundingClientRect(); + const myCoordx = event.clientX - clientRects.x; + const myCoordy = event.clientY - clientRects.y; + mouse.x = (myCoordx / clientRects.width) * 2 - 1; + mouse.y = -(myCoordy / clientRects.height) * 2 + 1; + hoverPointer(); + return null; + } + + const renderer = new WebGLRenderer({ alpha: true }); + renderer.setSize( + webglContainerEl.clientWidth, + webglContainerEl.clientHeight + ); + + webglContainerEl.appendChild(renderer.domElement); + + const cssContainerEl = document.querySelector('.css-wrapper'); + invariant(cssContainerEl, 'could not find container tag'); + + const cssRenderer = new CSS3DRenderer(); + cssRenderer.setSize( + cssContainerEl.clientWidth, + cssContainerEl.clientHeight + ); + + cssContainerEl.appendChild(cssRenderer.domElement); + + const controls = new OrbitControls(camera, renderer.domElement); + const cssControls = new OrbitControls(camera, cssRenderer.domElement); + + controls.enableRotate = false; + cssControls.enableRotate = false; + + camera.position.set(0, 0, 10); + controls.update(); + cssControls.update(); + + scene.background = new Color(COLORS.GRAY_DARK); + + const grid = new InfiniteGrid({ + spacingX: 10, + spacingY: 10, + color: new Color(COLORS.GRAY_SOFT), + distance: 2000, + }); + + grid.position.set(0, 0, -0.0001); // little tweak to make sure the grid stays behind all objects + + // scene.add(grid); + + const modelGrid = new ModelGrid({ + disposition: { + x: [ + { + label: 'A', + + coordinate: 0, + }, + { + label: 'B', + coordinate: 12.5, + }, + { + label: 'C', + coordinate: 17.5, + }, + ], + y: [ + { + label: '1', + coordinate: 0, + }, + { + label: '2', + coordinate: 7.5, + }, + { + label: '3', + coordinate: 15, + }, + ], + }, + containerEl: cssContainerEl, + }); + + const columns = [ + { + width: 2, + height: 2, + coorX: 15, + coorY: 17.5, + color: COLORS.NOTICE_SOFT_yellow, + }, + { + width: 2, + height: 2, + coorX: 0, + coorY: 5, + color: COLORS.NOTICE_RED, + }, + { + width: 1, + height: 3, + coorX: 0, + coorY: 10, + color: COLORS.NOTICE_RED, + }, + { + width: 2, + height: 4, + coorX: 5, + coorY: 0, + color: COLORS.NOTICE_RED, + }, + { + width: 2, + height: 1, + coorX: 10, + coorY: 0, + color: COLORS.NOTICE_RED, + }, + ]; + scene.add(modelGrid.object3D); + const columnGroup = ColumnsGroup({ columns }); + scene.add(columnGroup); + + window.addEventListener('click', onPointerMove, false); + function animate() { + requestAnimationFrame(animate); + controls.update(); + // cssControls.update(); + // cssRenderer.render(scene, camera); + renderer.render(scene, camera); + } + animate(); + }, []); + + return ( +