| | |
| | | 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 Text from './text'; |
| | | |
| | | const Y = 1; |
| | | const Area = (props) => { |
| | | const { x, y, width, height, textContent, textHeight, strokeColor } = props; |
| | | 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 color = !hovered ? strokeColor : 'white'; |
| | | const material = box.material; |
| | | material.color.set(color); |
| | | material.linewidth = thickness; |
| | | material.linewidth = 0.2; |
| | | } |
| | | }); |
| | | |
| | | return ( |
| | | <group |
| | | onClick={handleClick} |
| | | onPointerOver={handlePointerOver} |
| | | onPointerOut={handlePointerOut} |
| | | onDoubleClick={handleDoubleClick} |
| | | onPointerMissed={() => setClicked(false)} |
| | | onPointerOver={() => setHover(true)} |
| | | onPointerOut={() => setHover(false)} |
| | | > |
| | | <mesh ref={meshRef} position={position}> |
| | | <boxGeometry attach="geometry" args={size} /> |