feat: add camera-aware wall move handles and UI layer for floorplan editor, and remove unused elevator icon.
This commit is contained in:
@@ -1,10 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Elevator">
|
|
||||||
<rect x="12" y="6" width="40" height="52" rx="5" fill="#d9e2ec"/>
|
|
||||||
<rect x="16" y="10" width="32" height="44" rx="2" fill="#64748b"/>
|
|
||||||
<path d="M32 10v44" stroke="#d9e2ec" stroke-width="2.5"/>
|
|
||||||
<rect x="20" y="15" width="10" height="15" rx="1.5" fill="#9bd7ff" opacity=".9"/>
|
|
||||||
<rect x="34" y="15" width="10" height="15" rx="1.5" fill="#9bd7ff" opacity=".9"/>
|
|
||||||
<circle cx="23" cy="41" r="2.2" fill="#fbbf24"/>
|
|
||||||
<circle cx="41" cy="41" r="2.2" fill="#fbbf24"/>
|
|
||||||
<path d="M26 48h12" stroke="#d9e2ec" stroke-linecap="round" stroke-width="3"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 649 B |
@@ -3,7 +3,9 @@
|
|||||||
import {
|
import {
|
||||||
type AnyNodeId,
|
type AnyNodeId,
|
||||||
DEFAULT_WALL_HEIGHT,
|
DEFAULT_WALL_HEIGHT,
|
||||||
|
getWallCurveFrameAt,
|
||||||
getWallThickness,
|
getWallThickness,
|
||||||
|
isCurvedWall,
|
||||||
sceneRegistry,
|
sceneRegistry,
|
||||||
useScene,
|
useScene,
|
||||||
type WallNode,
|
type WallNode,
|
||||||
@@ -11,6 +13,7 @@ import {
|
|||||||
import { useViewer } from '@pascal-app/viewer'
|
import { useViewer } from '@pascal-app/viewer'
|
||||||
import { createPortal, type ThreeEvent } from '@react-three/fiber'
|
import { createPortal, type ThreeEvent } from '@react-three/fiber'
|
||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
|
import { useThree } from '@react-three/fiber'
|
||||||
import {
|
import {
|
||||||
BufferGeometry,
|
BufferGeometry,
|
||||||
ConeGeometry,
|
ConeGeometry,
|
||||||
@@ -18,6 +21,7 @@ import {
|
|||||||
DoubleSide,
|
DoubleSide,
|
||||||
Float32BufferAttribute,
|
Float32BufferAttribute,
|
||||||
type Object3D,
|
type Object3D,
|
||||||
|
OrthographicCamera,
|
||||||
} from 'three'
|
} from 'three'
|
||||||
import { sfxEmitter } from '../../lib/sfx-bus'
|
import { sfxEmitter } from '../../lib/sfx-bus'
|
||||||
import useEditor from '../../store/use-editor'
|
import useEditor from '../../store/use-editor'
|
||||||
@@ -157,6 +161,14 @@ function WallMoveSideHandlesForWall({ wall }: { wall: WallNode }) {
|
|||||||
function WallMoveArrowHandle({ wall, handle }: { wall: WallNode; handle: WallMoveHandle }) {
|
function WallMoveArrowHandle({ wall, handle }: { wall: WallNode; handle: WallMoveHandle }) {
|
||||||
const [isHovered, setIsHovered] = useState(false)
|
const [isHovered, setIsHovered] = useState(false)
|
||||||
const arrowGeometry = useMemo(() => createArrowHandleGeometry(), [])
|
const arrowGeometry = useMemo(() => createArrowHandleGeometry(), [])
|
||||||
|
const { camera } = useThree()
|
||||||
|
|
||||||
|
const zoom =
|
||||||
|
camera instanceof OrthographicCamera
|
||||||
|
? 1 / camera.zoom
|
||||||
|
: 1
|
||||||
|
|
||||||
|
const scale = (isHovered ? 1.12 : 1) * zoom
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
@@ -186,7 +198,7 @@ function WallMoveArrowHandle({ wall, handle }: { wall: WallNode; handle: WallMov
|
|||||||
<group
|
<group
|
||||||
position={handle.position}
|
position={handle.position}
|
||||||
rotation={[0, handle.rotationY, 0]}
|
rotation={[0, handle.rotationY, 0]}
|
||||||
scale={isHovered ? 1.12 : 1}
|
scale={scale}
|
||||||
>
|
>
|
||||||
<mesh
|
<mesh
|
||||||
frustumCulled={false}
|
frustumCulled={false}
|
||||||
@@ -228,11 +240,13 @@ function getWallMoveHandles(wall: WallNode): WallMoveHandle[] {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
const normal: [number, number] = [-dz / length, dx / length]
|
const frame = isCurvedWall(wall) ? getWallCurveFrameAt(wall, 0.5) : null
|
||||||
const midpoint: [number, number] = [
|
const normal: [number, number] = frame
|
||||||
(wall.start[0] + wall.end[0]) / 2,
|
? [frame.normal.x, frame.normal.y]
|
||||||
(wall.start[1] + wall.end[1]) / 2,
|
: [-dz / length, dx / length]
|
||||||
]
|
const midpoint: [number, number] = frame
|
||||||
|
? [frame.point.x, frame.point.y]
|
||||||
|
: [(wall.start[0] + wall.end[0]) / 2, (wall.start[1] + wall.end[1]) / 2]
|
||||||
const wallHeight = wall.height ?? DEFAULT_WALL_HEIGHT
|
const wallHeight = wall.height ?? DEFAULT_WALL_HEIGHT
|
||||||
const handleHeight = Math.max(wallHeight - HANDLE_TOP_INSET, HANDLE_MIN_HEIGHT)
|
const handleHeight = Math.max(wallHeight - HANDLE_TOP_INSET, HANDLE_MIN_HEIGHT)
|
||||||
const offset = Math.max(getWallThickness(wall) / 2 + HANDLE_OFFSET, HANDLE_MIN_OFFSET)
|
const offset = Math.max(getWallThickness(wall) / 2 + HANDLE_OFFSET, HANDLE_MIN_OFFSET)
|
||||||
|
|||||||
Reference in New Issue
Block a user