Skip to content

Commit

Permalink
feat(3d): add the click event for location
Browse files Browse the repository at this point in the history
  • Loading branch information
wangzhu committed Nov 29, 2023
1 parent ff148cb commit 72bec05
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 31 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"homepage": "https://github.com/uchihamalolan/vite-react-ts",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"build": " vite build",
"test": "jest",
"serve": "vite preview",
"prepare": "husky install",
Expand Down
35 changes: 25 additions & 10 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Select } from '@react-three/drei';
import BasicElements from 'components/BasicElments';
import Floor from 'components/Floor';
import Lights from 'components/Lights';
Expand All @@ -7,32 +8,39 @@ import Shelf from 'components/Shelf';
import useAreaList from 'hooks/useAreaList';
import useCustomArea from 'hooks/useCustomArea';
import useLayouts from 'hooks/useLayouts';
import { useControls } from 'leva';
import GetAreaList from 'mock/GetAreaList.json';
import GetCustomAreaList from 'mock/GetCustomAreaList.json';
import GetMain from 'mock/GetMain.json';
import { useEffect, useRef } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useLayoutsStore } from 'stores';
import { IGetAreaList, IGetCustomAreaList } from 'types';

function App() {
const containerRef = useRef<HTMLDivElement>(null);
const { showAxes } = useControls({
showAxes: true,
});

const layouts = useLayouts(GetMain);
const setlayouts = useLayoutsStore((state) => state.setlayouts);
const { tunnels, shelfs } = useAreaList((GetAreaList as IGetAreaList).resultData, layouts);
const customAreas = useCustomArea((GetCustomAreaList as IGetCustomAreaList).resultData, layouts);

const [currentLocationId, setCurrentLocationId] = useState<string>();

const onLocationClick = (id: string) => {
setCurrentLocationId(id === currentLocationId ? undefined : id);
};

useEffect(() => {
setlayouts(layouts);
}, [layouts]);

return (
<div ref={containerRef} className="App h-full w-full">
<Setup>
{showAxes && <axesHelper position={[0, 0, 0]} args={[1000]}></axesHelper>}
<Setup
onClick={() => {
setCurrentLocationId(undefined);
}}
>
<axesHelper position={[0, 0, 0]} args={[1000]}></axesHelper>
<Lights />
<BasicElements />
<Floor {...GetMain.resultData} />
Expand All @@ -42,9 +50,16 @@ function App() {
{customAreas.map((customArea) => (
<CustomArea {...customArea} key={customArea.id} />
))}
{shelfs.map((shelf) => (
<Shelf {...shelf} key={shelf.id} />
))}
<Select box onChange={console.log} filter={(items) => items}>
{shelfs.map((shelf) => (
<Shelf
{...shelf}
key={shelf.id}
onLocationClick={onLocationClick}
currentLocationId={currentLocationId}
/>
))}
</Select>
</Setup>
</div>
);
Expand Down
4 changes: 3 additions & 1 deletion src/components/BasicElments/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OrbitControls, Stats, Grid } from '@react-three/drei';
import { OrbitControls, Stats, Grid, Environment, Sky } from '@react-three/drei';

export default function BasicElements() {
return (
Expand All @@ -7,6 +7,8 @@ export default function BasicElements() {
<Stats />
<gridHelper args={[20000, 150, '#fff', '#fff']} position={[0, -24, 0]} />
<fog attach="fog" args={['#edf0f7', 100, 10000]} />
{/* <Environment preset="city" /> */}
{/* <Sky distance={450000} sunPosition={[0, 1, 0]} inclination={0} azimuth={0.25} /> */}
</>
);
}
34 changes: 23 additions & 11 deletions src/components/Location/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { LOCATION_WIDTH } from 'components/Shelf';
import { memo, useMemo } from 'react';
import { memo, useMemo, useState } from 'react';
import * as THREE from 'three';
import { ELocationStatus } from 'types';

import { Box } from '@react-three/drei';
import { Box, Edges, ShapeProps, useCursor, useSelect } from '@react-three/drei';

import type { ColorRepresentation, Vector3Tuple } from 'three';
import type { ColorRepresentation } from 'three';

export const LOCATION_STATUS_MAP: Record<
ELocationStatus,
Expand All @@ -28,7 +28,7 @@ export const LOCATION_STATUS_MAP: Record<
color: '#DA70D6',
},
5: {
status: '空库位入库锁定',
status: '空库库锁定',
color: '#D8BFD8',
},
6: {
Expand All @@ -53,24 +53,36 @@ export const LOCATION_STATUS_MAP: Record<
},
};

export interface ILocationProps {
export interface ILocationProps extends Omit<ShapeProps<typeof THREE.BoxGeometry>, 'id'> {
locationStatus: ELocationStatus;
position: Vector3Tuple;
id?: string;
}

function Location({ locationStatus, position }: ILocationProps) {
function Location({ locationStatus, position, id, ...props }: ILocationProps) {
const [hovered, setHover] = useState(false);
const selected = useSelect();
const isSelected = (selected?.[0]?.userData?.id ?? '') === id;
const material = useMemo(() => {
const color = LOCATION_STATUS_MAP[locationStatus]?.color ?? '#fbf8f8';
const color = isSelected ? '#ef4444' : LOCATION_STATUS_MAP[locationStatus]?.color ?? '#fbf8f8';
return new THREE.MeshPhongMaterial({ color, transparent: true, opacity: 0.6 });
}, [locationStatus]);

}, [locationStatus, isSelected]);
useCursor(hovered);
return (
<Box
material={material}
args={[LOCATION_WIDTH, LOCATION_WIDTH, LOCATION_WIDTH]}
position={position}
></Box>
{...props}
onPointerOver={(e) => (e.stopPropagation(), setHover(true))}
onPointerOut={(e) => setHover(false)}
>
<Edges
visible={isSelected}
scale={1.1}
threshold={15} // Display edges only when the angle between two faces exceeds this value (default=15 degrees)
color="white"
/>
</Box>
);
}

Expand Down
7 changes: 5 additions & 2 deletions src/components/Setup/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Canvas } from '@react-three/fiber';
import { Canvas, CanvasProps } from '@react-three/fiber';
import { PropsWithChildren } from 'react';

function Setup({ children }: PropsWithChildren) {
type IProps = CanvasProps & PropsWithChildren;

function Setup({ children, ...props }: IProps) {
return (
<Canvas
camera={{
Expand All @@ -14,6 +16,7 @@ function Setup({ children }: PropsWithChildren) {
gl={{ logarithmicDepthBuffer: true, antialias: true }}
dpr={[1, 2]}
shadows={'soft'}
{...props}
>
<color attach="background" args={[0x444444]} />
{children}
Expand Down
28 changes: 26 additions & 2 deletions src/components/Shelf/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,32 @@ export interface IShelfProps {
position: Vector3Tuple;
locationsMatrix: ILocationProps[][];
id?: string;
currentLocationId?: string;
onLocationClick?: (id: string) => void;
}

type IRacket = Omit<ShapeProps<typeof THREE.BoxGeometry>, 'id'> & { id: string };

// 每列货架的间隙
export const SPACING = 2;
// 货架支架的宽度
export const BIN_WIDTH = 4;
// 每行货架的宽度
export const SHELF_WIDTH = 44;
// 每层货架的高度
export const LAYER_LENGTH = 40;
// 货物的宽度
export const LOCATION_WIDTH = SHELF_WIDTH - BIN_WIDTH * 2;

function Shelf({ layer, position, row, col, locationsMatrix }: IShelfProps) {
function Shelf({
layer,
position,
row,
col,
locationsMatrix,
currentLocationId,
onLocationClick,
}: IShelfProps) {
const brackets = useMemo(() => {
const length = layer * LAYER_LENGTH;
const width = row * SHELF_WIDTH;
Expand Down Expand Up @@ -98,7 +113,16 @@ function Shelf({ layer, position, row, col, locationsMatrix }: IShelfProps) {
<BracketShape {...extra} key={id} />
))}
{(locationsMatrix?.[index] ?? []).map(({ id, ...location }) => (
<Location key={id} {...location} />
<Location
userData={{ id }}
key={id}
{...location}
id={id}
onClick={(e) => {
e.nativeEvent.stopPropagation();
onLocationClick?.(id as string);
}}
/>
))}
</group>
))}
Expand Down
7 changes: 3 additions & 4 deletions src/hooks/useAreaList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default function useAreaList(canvasData: IGetAreaListResultData[], layout
col: toYaxis - fromYaxis + 1,
locationsMatrix: locationList.reduce<ILocationProps[][]>(
(acc, cur) => {
const { xaxis, yaxis, locationStatus, zaxis } = cur;
const { xaxis, yaxis, locationStatus, zaxis, id } = cur;
const z = zaxis * LAYER_LENGTH + LOCATION_WIDTH / 2;
const _xaxis = xaxis - fromXaxis;
const x = _xaxis * SHELF_WIDTH + LOCATION_WIDTH / 2 + BIN_WIDTH;
Expand All @@ -66,12 +66,11 @@ export default function useAreaList(canvasData: IGetAreaListResultData[], layout
acc[_yaxis].push({
position: [x, z, y],
locationStatus,
id,
});
return acc;
},
new Array(toYaxis - fromYaxis + 1)
.fill(0)
.map((_) => new Array(toXaxis - fromXaxis + 1).fill(0))
new Array(toYaxis - fromYaxis + 1).fill(0).map((_) => new Array())
),
});
}
Expand Down

0 comments on commit 72bec05

Please sign in to comment.