Fix spawn floorplan move handle
This commit is contained in:
@@ -31,6 +31,7 @@ describe('spawn definition', () => {
|
||||
expect(spawnDefinition.schemaVersion).toBe(1)
|
||||
expect(spawnDefinition.category).toBe('site')
|
||||
expect(spawnDefinition.schema).toBe(SpawnNode)
|
||||
expect(typeof spawnDefinition.floorplanMoveTarget).toBe('function')
|
||||
})
|
||||
|
||||
test('defaults() returns a value that the schema accepts', () => {
|
||||
@@ -111,6 +112,7 @@ describe('spawn definition', () => {
|
||||
|
||||
const flat = flattenFloorplan(geometry)
|
||||
expect(flat.some((entry) => entry.kind === 'path' && entry.stroke === '#818cf8')).toBe(true)
|
||||
expect(flat.some((entry) => entry.kind === 'move-handle')).toBe(true)
|
||||
expect(flat.some((entry) => entry.kind === 'rotate-arrow')).toBe(true)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { HandleDescriptor, NodeDefinition, SpawnNode as SpawnNodeType } from '@pascal-app/core'
|
||||
import { buildSpawnFloorplan } from './floorplan'
|
||||
import { spawnRotateAffordance } from './floorplan-affordances'
|
||||
import { spawnFloorplanMoveTarget } from './floorplan-move'
|
||||
import { spawnParametrics } from './parametrics'
|
||||
import { SpawnNode } from './schema'
|
||||
|
||||
@@ -92,6 +93,7 @@ export const spawnDefinition: NodeDefinition<typeof SpawnNode> = {
|
||||
// delete. Legacy spawn click handlers in FloorplanNodeLayer become
|
||||
// dead code once Phase 6 cleanup removes the [] entries path.
|
||||
floorplan: buildSpawnFloorplan,
|
||||
floorplanMoveTarget: spawnFloorplanMoveTarget,
|
||||
floorplanAffordances: {
|
||||
'spawn-rotate': spawnRotateAffordance,
|
||||
},
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
type AnyNodeId,
|
||||
type FloorplanMoveTarget,
|
||||
type FloorplanMoveTargetSession,
|
||||
type SpawnNode,
|
||||
snapScalar,
|
||||
useScene,
|
||||
} from '@pascal-app/core'
|
||||
import { getSegmentGridStep } from '@pascal-app/editor'
|
||||
|
||||
export const spawnFloorplanMoveTarget: FloorplanMoveTarget<SpawnNode> = ({ node }) => {
|
||||
const spawnId = node.id as AnyNodeId
|
||||
const startY = node.position[1]
|
||||
const originalPosition: [number, number, number] = [...node.position]
|
||||
let lastPosition: [number, number, number] | null = null
|
||||
|
||||
const session: FloorplanMoveTargetSession = {
|
||||
affectedIds: [spawnId],
|
||||
apply({ planPoint, modifiers }) {
|
||||
const step = getSegmentGridStep()
|
||||
const snap = (value: number) => (modifiers.shiftKey ? value : snapScalar(value, step))
|
||||
const next: [number, number, number] = [snap(planPoint[0]), startY, snap(planPoint[1])]
|
||||
|
||||
if (lastPosition && lastPosition[0] === next[0] && lastPosition[2] === next[2]) return
|
||||
lastPosition = next
|
||||
useScene.getState().updateNodes([{ id: spawnId, data: { position: next } }])
|
||||
},
|
||||
canCommit() {
|
||||
if (!lastPosition) return false
|
||||
return lastPosition[0] !== originalPosition[0] || lastPosition[2] !== originalPosition[2]
|
||||
},
|
||||
commit() {
|
||||
if (!lastPosition) return
|
||||
useScene.getState().updateNodes([{ id: spawnId, data: { position: lastPosition } }])
|
||||
},
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
@@ -113,6 +113,11 @@ export function buildSpawnFloorplan(node: SpawnNode, ctx: GeometryContext): Floo
|
||||
]
|
||||
|
||||
if (isSelected) {
|
||||
children.push({
|
||||
kind: 'move-handle',
|
||||
point: [px, pz],
|
||||
})
|
||||
|
||||
const cornerLocalX = 0.34 + ROTATE_ARROW_CORNER_OFFSET
|
||||
const cornerLocalZ = 0.34 + ROTATE_ARROW_CORNER_OFFSET
|
||||
const [cornerX, cornerZ] = rotatePlanVector(cornerLocalX, cornerLocalZ, planRotation)
|
||||
|
||||
Reference in New Issue
Block a user