#
luxiaotao1123
2024-04-24 6546ed84364eacccf10351f0c671dffb545900a0
#
3个文件已添加
1个文件已修改
177 ■■■■■ 已修改文件
src/assets/data/area.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/area.jsx 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/text.jsx 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/warehouse.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/data/area.js
New file
@@ -0,0 +1,15 @@
const areaData = [
  {
    x: -500,
    y: -400,
    width: 700,
    height: 800,
    name: 'selected-rect1684723196047',
    type: 'area',
    strokeColor: 'rgb(255, 0, 14)',
    areaNumber: 'A1',
    textHeight: 400,
  },
];
export default areaData;
src/components/area.jsx
New file
@@ -0,0 +1,115 @@
import React, { useRef, useState } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';
import { CameraControls } from '@react-three/drei';
import Text2 from './text';
// import Annotation, { IAnnotationDataItem, IAnnotationRef } from './annotation';
const Y = 1;
const Area = ({
  x,
  y,
  width,
  height,
  areaNumber,
  textHeight,
  strokeColor,
}) => {
  const [hovered, setHover] = useState(false);
  const [clicked, setClicked] = useState(false);
  const meshRef = useRef(null);
  const { controls } = useThree((state) => ({
    controls: state.controls,
  }));
  // 转换为x轴和z轴组成的坐标系中的位置
  const position = new THREE.Vector3(x + width / 2, Y, y + height / 2);
  const size = [width, 1, height];
  textHeight ||= Y + 50;
  // 相机移动到区域的位置
  const handleClick = () => {
    if (clicked) return;
    setClicked(true);
    // controls.fitToBox(meshRef.current!, true);
    const mesh = meshRef.current;
    const { x, y, z } = mesh.position;
    const box = new THREE.Box3().setFromCenterAndSize(
      new THREE.Vector3(x, (y + textHeight) / 2, z),
      new THREE.Vector3(width, textHeight, height)
    );
    controls.fitToBox(box, true);
    // annotationRef.current?.show();
  };
  // 相机移动回原来的位置
  const handleDoubleClick = () => {
    setClicked(false);
  };
  // 监听鼠标移入和移出事件,改变hover状态
  const handlePointerOver = () => setHover(true);
  const handlePointerOut = () => setHover(false);
  // 每帧更新边框的颜色和粗细
  useFrame(() => {
    const box = meshRef.current;
    if (box) {
      const color = hovered || clicked ? strokeColor : 'white';
      const thickness = clicked ? 0.5 : 0.2;
      const material = box.material;
      material.color.set(color);
      material.linewidth = thickness;
    }
  });
  // const annotationRef = useRef(null);
  const annotationData = [
    {
      label: '长',
      value: width + '米',
    },
    {
      label: '宽',
      value: height + '米',
    },
  ];
  return (
    <group
      onClick={handleClick}
      onPointerOver={handlePointerOver}
      onPointerOut={handlePointerOut}
      onDoubleClick={handleDoubleClick}
      onPointerMissed={() => setClicked(false)}
    >
      <mesh ref={meshRef} position={position}>
        <boxGeometry attach="geometry" args={size} />
        <lineSegments>
          <edgesGeometry attach="geometry" args={[new THREE.BoxGeometry(...size)]} />
          <lineBasicMaterial attach="material" color={strokeColor} linewidth={0.2} />
        </lineSegments>
        <meshBasicMaterial attach="material" color={strokeColor} transparent opacity={0.2} />
      </mesh>
      {areaNumber && (
        <Text2
          position={new THREE.Vector3(position.x, textHeight, position.z)}
          text={areaNumber}
          scale={new THREE.Vector3(100, 100, 100)}
          fontSize={100}
        />
      )}
      {/* <Annotation
        ref={annotationRef}
        title={areaNumber}
        position={position}
        data={annotationData}
      ></Annotation> */}
    </group>
  );
};
export default Area;
src/components/text.jsx
New file
@@ -0,0 +1,40 @@
import * as THREE from 'three';
import { useEffect, useState } from 'react';
function generateSprite(text, color, fontSize = 50) {
  const canvas = document.createElement('canvas');
  canvas.width = 300;
  canvas.height = 300;
  const context = canvas.getContext('2d');
  context.beginPath();
  context.font = `${fontSize}px Microsoft YaHei`;
  context.fillStyle = color;
  context.textAlign = 'center';
  context.textBaseline = 'middle';
  context.fillText(text, canvas.width / 2, canvas.height / 2);
  context.fill();
  context.stroke();
  return canvas;
}
const Text2 = ({
  text,
  position,
  scale = new THREE.Vector3(100, 100, 100),
  color = '#00D1D1',
  fontSize = 50,
}) => {
  const [material, setMaterial] = useState(undefined);
  useEffect(() => {
    const material = new THREE.SpriteMaterial({
      map: new THREE.CanvasTexture(generateSprite(text, color, fontSize)),
      blending: THREE.AdditiveBlending,
    });
    setMaterial(material);
  }, [text, color, fontSize]);
  return <sprite material={material} position={position} scale={scale} />;
}
export default Text2;
src/core/warehouse.jsx
@@ -2,11 +2,13 @@
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';
import Tunnel from '../components/tunnel';
import Area from '../components/area';
import Shelf from '../components/shelf';
import Box from '../components/box';
import Agv from '../components/agv';
import tunnelData from '@/assets/data/tunnel';
import areaData from '@/assets/data/area';
import shelfData from '@/assets/data/shelf';
import agvRealDataList from '@/assets/data/agv';
import { INTERVAL_TIME } from '@/config/setting'
@@ -40,6 +42,10 @@
        return tunnelData.map((data, index) => <Tunnel key={index} {...data} />)
    }, []);
    const areaEl = useMemo(() => {
        return areaData.map((area, index) => <Area key={index} {...area} />)
    }, []);
    const shelfEl = useMemo(() => {
        return shelfData.map((data, index) => <Shelf key={index} {...data} />)
    }, []);
@@ -64,6 +70,7 @@
        <>
            <group>
                {tunnelEl}
                {areaEl}
                {shelfEl}
                {/* {shelfEl1} */}
                {agvEl}