feat: add camera-aware wall move handles and UI layer for floorplan editor, and remove unused elevator icon.

This commit is contained in:
sudhir
2026-05-20 00:41:26 +00:00
committed by open-pascal
parent db5c743e1c
commit 2b9bb769f3
2 changed files with 20 additions and 16 deletions
-10
View File
@@ -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)