@weasel-js/core 1.11.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +611 -0
- package/README.md +1 -1
- package/dist/WeaselProvider.js +1 -1
- package/dist/affordances/pathAnchors.js +10 -6
- package/dist/affordances/pathAnchors.js.map +1 -1
- package/dist/animation/index.js +3 -3
- package/dist/animation/rig/bindRig.js +1 -1
- package/dist/animation/rig/rigNode.js.map +1 -1
- package/dist/barrel/canvas.js +9 -3
- package/dist/barrel/interactions.js +5 -4
- package/dist/barrel/paint.js +4 -4
- package/dist/barrel/paths.js +10 -6
- package/dist/barrel/renderer.js +5 -3
- package/dist/barrel/routing.js +7 -12
- package/dist/barrel/scene.js +9 -5
- package/dist/barrel/text.js +2 -2
- package/dist/barrel/viewport.js +9 -4
- package/dist/canvas/Canvas.js +5 -2
- package/dist/canvas/Canvas.js.map +1 -1
- package/dist/canvas/CanvasView.js +23 -34
- package/dist/canvas/CanvasView.js.map +1 -1
- package/dist/canvas/ModalityHud.js +1 -1
- package/dist/canvas/NodeShape.js +4 -1
- package/dist/canvas/NodeShape.js.map +1 -1
- package/dist/canvas/SceneCanvas/ActionsProviderIfRoot.js +1 -1
- package/dist/canvas/SceneCanvas/DepRegistryProviderIfRoot.js +1 -1
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +1 -1
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js +17 -3
- package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
- package/dist/canvas/SceneCanvas/SurfaceDeclarations.js +23 -0
- package/dist/canvas/SceneCanvas/SurfaceDeclarations.js.map +1 -0
- package/dist/canvas/SceneCanvas/builtinToolSets.js +30 -0
- package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -0
- package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -0
- package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
- package/dist/canvas/SceneCanvas/coordTrace.js +5 -16
- package/dist/canvas/SceneCanvas/coordTrace.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js +5 -0
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
- package/dist/canvas/SceneCanvas/features.js +45 -5
- package/dist/canvas/SceneCanvas/features.js.map +1 -1
- package/dist/canvas/SceneCanvas/props.js +1 -11
- package/dist/canvas/SceneCanvas/props.js.map +1 -1
- package/dist/canvas/SceneCanvas/scenePointQuery.js +7 -3
- package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -1
- package/dist/canvas/SceneCanvas/toolRegistry.js +8 -4
- package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
- package/dist/canvas/SceneCanvas/useActionTunings.js +6 -1
- package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -1
- package/dist/canvas/SceneCanvas/useActionsPropResolver.js +1 -11
- package/dist/canvas/SceneCanvas/useActionsPropResolver.js.map +1 -1
- package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useBuiltinTools.js +2 -9
- package/dist/canvas/SceneCanvas/useBuiltinTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js +94 -0
- package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js.map +1 -0
- package/dist/canvas/SceneCanvas/useCanvasSelection.js +7 -2
- package/dist/canvas/SceneCanvas/useCanvasSelection.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasTools.js +15 -10
- package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useNodeKinds.js +1 -1
- package/dist/canvas/SceneCanvas/useNodeKinds.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js +9 -3
- package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +23 -4
- package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +2 -3
- package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneChrome.js +6 -7
- package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +24 -7
- package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
- package/dist/canvas/SceneCanvas/useScenePicking.js +2 -3
- package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +2 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js +5 -5
- package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +27 -24
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/SurfaceCanvas.js +5 -22
- package/dist/canvas/SurfaceCanvas.js.map +1 -1
- package/dist/canvas/ViewMarker.js +35 -0
- package/dist/canvas/ViewMarker.js.map +1 -0
- package/dist/canvas/canvasRenderer.js +9 -5
- package/dist/canvas/canvasRenderer.js.map +1 -1
- package/dist/canvas/contextAttributes.js +14 -0
- package/dist/canvas/contextAttributes.js.map +1 -0
- package/dist/canvas/defaultDrawOne.js +2 -0
- package/dist/canvas/defaultDrawOne.js.map +1 -1
- package/dist/canvas/deps/booleans.js +2 -1
- package/dist/canvas/deps/booleans.js.map +1 -1
- package/dist/canvas/deps/editAnchors.js +9 -113
- package/dist/canvas/deps/editAnchors.js.map +1 -1
- package/dist/canvas/deps/hitTestArea.js +2 -2
- package/dist/canvas/deps/hitTestArea.js.map +1 -1
- package/dist/canvas/deps/insert.js +10 -4
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/pathEditCommits.js +189 -0
- package/dist/canvas/deps/pathEditCommits.js.map +1 -0
- package/dist/canvas/deps/snap.js +12 -9
- package/dist/canvas/deps/snap.js.map +1 -1
- package/dist/canvas/deps/transformFollowers.js +20 -0
- package/dist/canvas/deps/transformFollowers.js.map +1 -0
- package/dist/canvas/derivedPath.js +20 -1
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/drawnBounds.js +38 -4
- package/dist/canvas/drawnBounds.js.map +1 -1
- package/dist/canvas/inheritedPaints.js +44 -0
- package/dist/canvas/inheritedPaints.js.map +1 -0
- package/dist/canvas/nodeShapes/derivedPainter.js +23 -16
- package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/nodePaint.js +13 -34
- package/dist/canvas/nodeShapes/nodePaint.js.map +1 -1
- package/dist/canvas/nodeShapes/pathPainter.js +12 -10
- package/dist/canvas/nodeShapes/pathPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/rectFallbackPainter.js +4 -5
- package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -1
- package/dist/canvas/nodeShapes/shapePainter.js +12 -11
- package/dist/canvas/nodeShapes/shapePainter.js.map +1 -1
- package/dist/canvas/nodeShapes/textPainter.js +13 -12
- package/dist/canvas/nodeShapes/textPainter.js.map +1 -1
- package/dist/canvas/overlayRoleStrokes.js +12 -0
- package/dist/canvas/overlayRoleStrokes.js.map +1 -1
- package/dist/canvas/pathOverlay.js +27 -7
- package/dist/canvas/pathOverlay.js.map +1 -1
- package/dist/canvas/pickReach.js +3 -3
- package/dist/canvas/pickReach.js.map +1 -1
- package/dist/canvas/pickWalk.js +3 -1
- package/dist/canvas/pickWalk.js.map +1 -1
- package/dist/canvas/renderDebugSnapshot.js +1 -0
- package/dist/canvas/renderDebugSnapshot.js.map +1 -1
- package/dist/canvas/renderSceneToPixels.js +7 -6
- package/dist/canvas/renderSceneToPixels.js.map +1 -1
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneSlotWiring.js +2 -1
- package/dist/canvas/sceneSlotWiring.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +2 -1
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/surfaceContribution.js +12 -8
- package/dist/canvas/surfaceContribution.js.map +1 -1
- package/dist/canvas/useCanvasPaint.js +2 -1
- package/dist/canvas/useCanvasPaint.js.map +1 -1
- package/dist/canvas/useCanvasView.js +4 -2
- package/dist/canvas/useCanvasView.js.map +1 -1
- package/dist/canvas/useInFlightBounds.js +52 -0
- package/dist/canvas/useInFlightBounds.js.map +1 -0
- package/dist/canvas/useLayerStack.js +6 -2
- package/dist/canvas/useLayerStack.js.map +1 -1
- package/dist/canvas/useViewAim.js +121 -0
- package/dist/canvas/useViewAim.js.map +1 -0
- package/dist/canvas/useViewHelpers.js +7 -9
- package/dist/canvas/useViewHelpers.js.map +1 -1
- package/dist/canvas/useViewNesting.js +3 -2
- package/dist/canvas/useViewNesting.js.map +1 -1
- package/dist/canvas/useViewRegistrySurface.js +4 -2
- package/dist/canvas/useViewRegistrySurface.js.map +1 -1
- package/dist/canvas/viewMarkers.js +63 -0
- package/dist/canvas/viewMarkers.js.map +1 -0
- package/dist/canvas/viewRegistry.js +27 -1
- package/dist/canvas/viewRegistry.js.map +1 -1
- package/dist/clipboard.d.ts +3 -2
- package/dist/{clone-DZDrfIlU.d.ts → clone-C3e0OTuF.d.ts} +8 -21
- package/dist/clone.d.ts +4 -3
- package/dist/core/geometry/autoPoseDescriptor.js +1 -1
- package/dist/core/ops/setDependsOn.js +37 -0
- package/dist/core/ops/setDependsOn.js.map +1 -0
- package/dist/core/ops/writtenBy.js +53 -0
- package/dist/core/ops/writtenBy.js.map +1 -0
- package/dist/core/pages/fitViewToPage.js +12 -1
- package/dist/core/pages/fitViewToPage.js.map +1 -1
- package/dist/core/pages/pageEdits.js +163 -0
- package/dist/core/pages/pageEdits.js.map +1 -0
- package/dist/core/pages/pages.js +30 -1
- package/dist/core/pages/pages.js.map +1 -1
- package/dist/core/paint/meshKindLazy.js +59 -2
- package/dist/core/paint/meshKindLazy.js.map +1 -1
- package/dist/core/scene/NodeRouting.js +8 -3
- package/dist/core/scene/NodeRouting.js.map +1 -1
- package/dist/core/scene/arrivalWindow.js.map +1 -1
- package/dist/core/scene/carryDescendants.js +51 -0
- package/dist/core/scene/carryDescendants.js.map +1 -0
- package/dist/core/scene/clipNothing.js +13 -0
- package/dist/core/scene/clipNothing.js.map +1 -0
- package/dist/core/scene/depMemo.js +11 -3
- package/dist/core/scene/depMemo.js.map +1 -1
- package/dist/core/scene/dependents.js +7 -1
- package/dist/core/scene/dependents.js.map +1 -1
- package/dist/core/scene/derivedParts.js +10 -11
- package/dist/core/scene/derivedParts.js.map +1 -1
- package/dist/core/scene/docValues.js +57 -0
- package/dist/core/scene/docValues.js.map +1 -0
- package/dist/core/scene/editPass.js +111 -0
- package/dist/core/scene/editPass.js.map +1 -0
- package/dist/core/scene/effectivePose.js +13 -2
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/fieldEdits.js +4 -1
- package/dist/core/scene/fieldEdits.js.map +1 -1
- package/dist/core/scene/fontReads.js +37 -0
- package/dist/core/scene/fontReads.js.map +1 -0
- package/dist/core/scene/historyFacade.js +1 -0
- package/dist/core/scene/historyFacade.js.map +1 -1
- package/dist/core/scene/inheritedPaint.js +75 -0
- package/dist/core/scene/inheritedPaint.js.map +1 -0
- package/dist/core/scene/kitRegistry.js +5 -0
- package/dist/core/scene/kitRegistry.js.map +1 -1
- package/dist/core/scene/layoutPass.js +28 -3
- package/dist/core/scene/layoutPass.js.map +1 -1
- package/dist/core/scene/nodeMemo.js +15 -7
- package/dist/core/scene/nodeMemo.js.map +1 -1
- package/dist/core/scene/pathEffects/blend.js.map +1 -1
- package/dist/core/scene/pathEffects/derive.js +7 -2
- package/dist/core/scene/pathEffects/derive.js.map +1 -1
- package/dist/core/scene/pathEffects/effects.js +3 -1
- package/dist/core/scene/pathEffects/effects.js.map +1 -1
- package/dist/core/scene/pathEffects/textAlong.js +95 -0
- package/dist/core/scene/pathEffects/textAlong.js.map +1 -0
- package/dist/core/scene/recorder.js +28 -19
- package/dist/core/scene/recorder.js.map +1 -1
- package/dist/core/scene/scene.js +15 -9
- package/dist/core/scene/scene.js.map +1 -1
- package/dist/core/scene/sceneChanges.js +13 -0
- package/dist/core/scene/sceneChanges.js.map +1 -0
- package/dist/core/scene/sceneEdits.js +8 -1
- package/dist/core/scene/sceneEdits.js.map +1 -1
- package/dist/core/scene/sceneMutators.js +1 -0
- package/dist/core/scene/sceneMutators.js.map +1 -1
- package/dist/core/scene/sceneRecording.js +20 -3
- package/dist/core/scene/sceneRecording.js.map +1 -1
- package/dist/core/scene/sceneSelection.js +4 -1
- package/dist/core/scene/sceneSelection.js.map +1 -1
- package/dist/core/scene/sceneState.js +11 -5
- package/dist/core/scene/sceneState.js.map +1 -1
- package/dist/core/scene/serialization.js +5 -3
- package/dist/core/scene/serialization.js.map +1 -1
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/scene/unitScopes.js +19 -1
- package/dist/core/scene/unitScopes.js.map +1 -1
- package/dist/core/selection/usePublishSceneSelection.js +6 -12
- package/dist/core/selection/usePublishSceneSelection.js.map +1 -1
- package/dist/core/shapeKinds.js +25 -11
- package/dist/core/shapeKinds.js.map +1 -1
- package/dist/{cornerHandles-Camw_yeu.d.ts → cornerHandles-p8fDIAKt.d.ts} +3 -2
- package/dist/debug/createDebugOverlayLayer.js +16 -111
- package/dist/debug/createDebugOverlayLayer.js.map +1 -1
- package/dist/debug/createDebugSink.js +2 -1
- package/dist/debug/createDebugSink.js.map +1 -1
- package/dist/debug/defaultTheme.js +4 -2
- package/dist/debug/defaultTheme.js.map +1 -1
- package/dist/debug/features.js +17 -0
- package/dist/debug/features.js.map +1 -0
- package/dist/debug/overlayPanels.js +117 -0
- package/dist/debug/overlayPanels.js.map +1 -0
- package/dist/debug/parseDebugFlags.js +4 -13
- package/dist/debug/parseDebugFlags.js.map +1 -1
- package/dist/{depSchema-Cgfu_G9s.d.ts → depSchema-mG19aEdD.d.ts} +174 -904
- package/dist/devtools/handlers.js +112 -0
- package/dist/devtools/handlers.js.map +1 -0
- package/dist/devtools/history.js +71 -0
- package/dist/devtools/history.js.map +1 -0
- package/dist/devtools/hook.js +74 -0
- package/dist/devtools/hook.js.map +1 -0
- package/dist/devtools/label.js +25 -0
- package/dist/devtools/label.js.map +1 -0
- package/dist/devtools/notices.js +58 -0
- package/dist/devtools/notices.js.map +1 -0
- package/dist/devtools/protocol.js +7 -0
- package/dist/devtools/protocol.js.map +1 -0
- package/dist/devtools/registry.js +90 -0
- package/dist/devtools/registry.js.map +1 -0
- package/dist/devtools/root.js +80 -0
- package/dist/devtools/root.js.map +1 -0
- package/dist/devtools/serialize.js +86 -0
- package/dist/devtools/serialize.js.map +1 -0
- package/dist/devtools/session.js +111 -0
- package/dist/devtools/session.js.map +1 -0
- package/dist/devtools/transport.js +67 -0
- package/dist/devtools/transport.js.map +1 -0
- package/dist/devtools/useDevtoolsRoot.js +81 -0
- package/dist/devtools/useDevtoolsRoot.js.map +1 -0
- package/dist/devtools-protocol.d.ts +435 -0
- package/dist/devtools-protocol.js +7 -0
- package/dist/devtools.d.ts +8 -0
- package/dist/devtools.js +12 -0
- package/dist/devtools.js.map +1 -0
- package/dist/features/chrome-caps/useHoverTracking.js +16 -10
- package/dist/features/chrome-caps/useHoverTracking.js.map +1 -1
- package/dist/features/ingestion/contentHandlers.js +25 -2
- package/dist/features/ingestion/contentHandlers.js.map +1 -1
- package/dist/features/measure/measureCommands.js +7 -5
- package/dist/features/measure/measureCommands.js.map +1 -1
- package/dist/features/measure/measureContribution.js +4 -2
- package/dist/features/measure/measureContribution.js.map +1 -1
- package/dist/features/modes/modeTriggers.js +7 -3
- package/dist/features/modes/modeTriggers.js.map +1 -1
- package/dist/features/pathEffects/effectSources.js +60 -0
- package/dist/features/pathEffects/effectSources.js.map +1 -0
- package/dist/features/pathEffects/readSource.js +17 -1
- package/dist/features/pathEffects/readSource.js.map +1 -1
- package/dist/features/pathEffects/textItems.js +53 -0
- package/dist/features/pathEffects/textItems.js.map +1 -0
- package/dist/features/pathEffects/useEffectSourcesLayer.js +57 -0
- package/dist/features/pathEffects/useEffectSourcesLayer.js.map +1 -0
- package/dist/features/paths/index.js +2 -2
- package/dist/features/paths/pathEditExtension.js.map +1 -1
- package/dist/features/paths/pathEditState.js +5 -2
- package/dist/features/paths/pathEditState.js.map +1 -1
- package/dist/features/paths/pathSnap/pathSnapSource.js +5 -5
- package/dist/features/paths/pathSnap/pathSnapSource.js.map +1 -1
- package/dist/features/paths/pathSnap/sceneIndex.js +10 -3
- package/dist/features/paths/pathSnap/sceneIndex.js.map +1 -1
- package/dist/features/selection/selectionPose.js +4 -1
- package/dist/features/selection/selectionPose.js.map +1 -1
- package/dist/features/snap/gather.js +9 -1
- package/dist/features/snap/gather.js.map +1 -1
- package/dist/features/snap/lazySession.js +17 -0
- package/dist/features/snap/lazySession.js.map +1 -0
- package/dist/features/snap/marks.js.map +1 -1
- package/dist/features/snap/probes2d.js +27 -19
- package/dist/features/snap/probes2d.js.map +1 -1
- package/dist/features/snap/readoutLayer.js.map +1 -1
- package/dist/features/snap/roles.js +2 -1
- package/dist/features/snap/roles.js.map +1 -1
- package/dist/features/snap/rotationSource.js +25 -8
- package/dist/features/snap/rotationSource.js.map +1 -1
- package/dist/features/snap/sceneSession2d.js +6 -4
- package/dist/features/snap/sceneSession2d.js.map +1 -1
- package/dist/features/snap/session2d.js +37 -23
- package/dist/features/snap/session2d.js.map +1 -1
- package/dist/features/snap/spanSnap.js +5 -2
- package/dist/features/snap/spanSnap.js.map +1 -1
- package/dist/features/text/sceneTextDrafts.js +65 -0
- package/dist/features/text/sceneTextDrafts.js.map +1 -0
- package/dist/features/text/textHitAt.js +31 -2
- package/dist/features/text/textHitAt.js.map +1 -1
- package/dist/features/text/useSceneTextEdit.js +22 -18
- package/dist/features/text/useSceneTextEdit.js.map +1 -1
- package/dist/features/viewports/aim.js +105 -0
- package/dist/features/viewports/aim.js.map +1 -0
- package/dist/features/viewports/viewMarker.js +82 -0
- package/dist/features/viewports/viewMarker.js.map +1 -0
- package/dist/features/viewports/viewMarkerDrag.js +55 -0
- package/dist/features/viewports/viewMarkerDrag.js.map +1 -0
- package/dist/icons.table.js +1 -1
- package/dist/icons.table.js.map +1 -1
- package/dist/icons.table.json +0 -10
- package/dist/index.d.ts +1198 -894
- package/dist/index.js +55 -38
- package/dist/interactions/actions/align/action.js +6 -4
- package/dist/interactions/actions/align/action.js.map +1 -1
- package/dist/interactions/actions/align/align.js.map +1 -1
- package/dist/interactions/actions/booleans/action.js +7 -1
- package/dist/interactions/actions/booleans/action.js.map +1 -1
- package/dist/interactions/actions/booleans/booleans.js +2 -1
- package/dist/interactions/actions/booleans/booleans.js.map +1 -1
- package/dist/interactions/actions/booleans/operands.js +6 -5
- package/dist/interactions/actions/booleans/operands.js.map +1 -1
- package/dist/interactions/actions/clipboard/action.js +27 -17
- package/dist/interactions/actions/clipboard/action.js.map +1 -1
- package/dist/interactions/actions/clone/action.js +1 -1
- package/dist/interactions/actions/clone/behaviors.js +4 -4
- package/dist/interactions/actions/clone/behaviors.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js +44 -23
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorJoin.js +12 -6
- package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -1
- package/dist/interactions/actions/defaults/bendSegment.js +8 -5
- package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
- package/dist/interactions/actions/defaults/cancelGesture.js +11 -8
- package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
- package/dist/interactions/actions/defaults/contextMenu.js +17 -8
- package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
- package/dist/interactions/actions/defaults/createPaintAction.js +2 -2
- package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
- package/dist/interactions/actions/defaults/delete.js +64 -41
- package/dist/interactions/actions/defaults/delete.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js +12 -9
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/enterPathEdit.js +19 -9
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/escape.js +11 -8
- package/dist/interactions/actions/defaults/escape.js.map +1 -1
- package/dist/interactions/actions/defaults/exitPathEdit.js +7 -4
- package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/group.js +21 -15
- package/dist/interactions/actions/defaults/group.js.map +1 -1
- package/dist/interactions/actions/defaults/ingest.js +17 -9
- package/dist/interactions/actions/defaults/ingest.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -4
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
- package/dist/interactions/actions/defaults/nudge.js +21 -40
- package/dist/interactions/actions/defaults/nudge.js.map +1 -1
- package/dist/interactions/actions/defaults/pathEditTools.js +11 -8
- package/dist/interactions/actions/defaults/pathEditTools.js.map +1 -1
- package/dist/interactions/actions/defaults/pinchZoom.js +7 -4
- package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
- package/dist/interactions/actions/defaults/reorder.js +24 -6
- package/dist/interactions/actions/defaults/reorder.js.map +1 -1
- package/dist/interactions/actions/defaults/selectAll.js +8 -5
- package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
- package/dist/interactions/actions/defaults/setFill.js +7 -3
- package/dist/interactions/actions/defaults/setFill.js.map +1 -1
- package/dist/interactions/actions/defaults/setFillOpacity.js +1 -1
- package/dist/interactions/actions/defaults/setStroke.js +12 -11
- package/dist/interactions/actions/defaults/setStroke.js.map +1 -1
- package/dist/interactions/actions/defaults/setStrokeOpacity.js +1 -1
- package/dist/interactions/actions/defaults/toolActivate.js +7 -1
- package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
- package/dist/interactions/actions/defaults/toolResetToDefault.js +7 -4
- package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
- package/dist/interactions/actions/defaults/undoRedo.js +19 -13
- package/dist/interactions/actions/defaults/undoRedo.js.map +1 -1
- package/dist/interactions/actions/defaults/viewportWheelPan.js +16 -7
- package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
- package/dist/interactions/actions/defaults/viewportZoom.js +24 -6
- package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
- package/dist/interactions/actions/distribute/action.js +6 -4
- package/dist/interactions/actions/distribute/action.js.map +1 -1
- package/dist/interactions/actions/drawnBoxes.js +2 -1
- package/dist/interactions/actions/drawnBoxes.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/action.js +10 -10
- package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/preview.js +41 -8
- package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
- package/dist/interactions/actions/flip/action.js +14 -6
- package/dist/interactions/actions/flip/action.js.map +1 -1
- package/dist/interactions/actions/gestureLifecycle.js +5 -2
- package/dist/interactions/actions/gestureLifecycle.js.map +1 -1
- package/dist/interactions/actions/insert/action.js +1 -2
- package/dist/interactions/actions/insert/action.js.map +1 -1
- package/dist/interactions/actions/insert/commit.js +1 -1
- package/dist/interactions/actions/insert/parent.js +11 -0
- package/dist/interactions/actions/insert/parent.js.map +1 -0
- package/dist/interactions/actions/insert/placeAction.js +7 -2
- package/dist/interactions/actions/insert/placeAction.js.map +1 -1
- package/dist/interactions/actions/insert/repositionAction.js +2 -1
- package/dist/interactions/actions/insert/repositionAction.js.map +1 -1
- package/dist/interactions/actions/insert/session.js +5 -1
- package/dist/interactions/actions/insert/session.js.map +1 -1
- package/dist/interactions/actions/move/action.js +15 -8
- package/dist/interactions/actions/move/action.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/layoutDrop.js +0 -1
- package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/snapToContainer.js +1 -1
- package/dist/interactions/actions/move/capture.js +1 -1
- package/dist/interactions/actions/move/commit/index.js +0 -2
- package/dist/interactions/actions/move/commit/index.js.map +1 -1
- package/dist/interactions/actions/move/commit/layoutDrop.js +2 -2
- package/dist/interactions/actions/move/commit/layoutRelease.js +2 -2
- package/dist/interactions/actions/move/commit/reparent.js +11 -5
- package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
- package/dist/interactions/actions/move/frame.js +4 -10
- package/dist/interactions/actions/move/frame.js.map +1 -1
- package/dist/interactions/actions/move/landedDescendants.js +20 -17
- package/dist/interactions/actions/move/landedDescendants.js.map +1 -1
- package/dist/interactions/actions/move/layout/container.js +2 -1
- package/dist/interactions/actions/move/layout/container.js.map +1 -1
- package/dist/interactions/actions/move/layout/dragged.js +1 -1
- package/dist/interactions/actions/move/layout/dropPass.js +18 -1
- package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
- package/dist/interactions/actions/move/layout/exits.js +5 -5
- package/dist/interactions/actions/move/layout/exits.js.map +1 -1
- package/dist/interactions/actions/move/session.js +14 -3
- package/dist/interactions/actions/move/session.js.map +1 -1
- package/dist/interactions/actions/move/translate.js +8 -37
- package/dist/interactions/actions/move/translate.js.map +1 -1
- package/dist/interactions/actions/moveNodes.js +87 -0
- package/dist/interactions/actions/moveNodes.js.map +1 -0
- package/dist/interactions/actions/outlines/createOutlinesAction.js +8 -5
- package/dist/interactions/actions/outlines/createOutlinesAction.js.map +1 -1
- package/dist/interactions/actions/outlines/outlineStroke.js +5 -3
- package/dist/interactions/actions/outlines/outlineStroke.js.map +1 -1
- package/dist/interactions/actions/pathCommands/cutJoin.js +8 -5
- package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -1
- package/dist/interactions/actions/planeInput.js.map +1 -1
- package/dist/interactions/actions/resize/action.js +83 -72
- package/dist/interactions/actions/resize/action.js.map +1 -1
- package/dist/interactions/actions/resize/commit.js +2 -1
- package/dist/interactions/actions/resize/commit.js.map +1 -1
- package/dist/interactions/actions/resize/cornerHandles.js +2 -1
- package/dist/interactions/actions/resize/cornerHandles.js.map +1 -1
- package/dist/interactions/actions/resize/session.js +2 -0
- package/dist/interactions/actions/resize/session.js.map +1 -1
- package/dist/interactions/actions/resolvePreviews.js +3 -3
- package/dist/interactions/actions/resolvePreviews.js.map +1 -1
- package/dist/interactions/actions/rotate/action.js +7 -4
- package/dist/interactions/actions/rotate/action.js.map +1 -1
- package/dist/interactions/actions/rotate/commit.js +2 -1
- package/dist/interactions/actions/rotate/commit.js.map +1 -1
- package/dist/interactions/actions/rotate/session.js +2 -0
- package/dist/interactions/actions/rotate/session.js.map +1 -1
- package/dist/interactions/actions/selectionSubtree.js +25 -9
- package/dist/interactions/actions/selectionSubtree.js.map +1 -1
- package/dist/interactions/actions/testUtils.js.map +1 -1
- package/dist/interactions/actions/transform-again/action.js +13 -11
- package/dist/interactions/actions/transform-again/action.js.map +1 -1
- package/dist/interactions/actions/transformFinish.js +106 -0
- package/dist/interactions/actions/transformFinish.js.map +1 -0
- package/dist/json.d.ts +4 -0
- package/dist/json.js +3 -0
- package/dist/kitSettingsSchema.js +8 -5
- package/dist/kitSettingsSchema.js.map +1 -1
- package/dist/{math-CrJULaZI.d.ts → math-B56zxVs5.d.ts} +10 -1
- package/dist/math.d.ts +1 -1
- package/dist/math.js +2 -1
- package/dist/move.d.ts +5 -4
- package/dist/{options-p9GZMXbY.d.ts → options-DBxEryYq.d.ts} +1 -1
- package/dist/resize.d.ts +4 -3
- package/dist/routing.d.ts +1 -1
- package/dist/routing.js +2 -2
- package/dist/test-hook/createTestHook.js +1 -1
- package/dist/test-hook/createTestHook.js.map +1 -1
- package/dist/test-hook/useTestHook.js +2 -1
- package/dist/test-hook/useTestHook.js.map +1 -1
- package/dist/test-seams.d.ts +9 -5
- package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
- package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js +2 -1
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
- package/dist/tools/builtin/hand/dragPanContribution.js +4 -1
- package/dist/tools/builtin/hand/dragPanContribution.js.map +1 -1
- package/dist/tools/builtin/hand/useHandTool.js +7 -4
- package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
- package/dist/tools/builtin/image/useImageTool.js +1 -0
- package/dist/tools/builtin/image/useImageTool.js.map +1 -1
- package/dist/tools/builtin/lasso/useLassoTool.js +1 -0
- package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
- package/dist/tools/builtin/line/useLineTool.js +1 -0
- package/dist/tools/builtin/line/useLineTool.js.map +1 -1
- package/dist/tools/builtin/measure/useMeasureTool.js +12 -5
- package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
- package/dist/tools/builtin/pen/penHandle.js +3 -5
- package/dist/tools/builtin/pen/penHandle.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +14 -6
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
- package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js +13 -4
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
- package/dist/tools/builtin/rect/useRectTool.js +1 -0
- package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
- package/dist/tools/builtin/select/adapterPointQuery.js +3 -2
- package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
- package/dist/tools/builtin/select/pressDecision.js +32 -0
- package/dist/tools/builtin/select/pressDecision.js.map +1 -0
- package/dist/tools/builtin/select/selectionContributions.js +22 -13
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +13 -10
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/slice/useSliceTool.js +22 -8
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/tools/builtin/star/useStarTool.js +13 -4
- package/dist/tools/builtin/star/useStarTool.js.map +1 -1
- package/dist/tools/builtin/sticky/stickyNode.js +4 -1
- package/dist/tools/builtin/sticky/stickyNode.js.map +1 -1
- package/dist/tools/builtin/sticky/useStickyTool.js +10 -5
- package/dist/tools/builtin/sticky/useStickyTool.js.map +1 -1
- package/dist/tools/builtin/text/useTextTool.js +3 -1
- package/dist/tools/builtin/text/useTextTool.js.map +1 -1
- package/dist/tools/index.js +26 -0
- package/dist/{types-CHVXGfYm.d.ts → types-7puAuVD2.d.ts} +3 -262
- package/dist/types-BN9hbdMI.d.ts +184 -0
- package/dist/types-CniVctmk.d.ts +949 -0
- package/dist/types-oFeQ5VjV.d.ts +264 -0
- package/dist/util/paint.js +1 -3
- package/dist/util/paint.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +39 -25
- package/dist/canvas/SceneCanvas/useBuiltinRigTools.js +0 -65
- package/dist/canvas/SceneCanvas/useBuiltinRigTools.js.map +0 -1
- package/dist/tools/builtin/bone/boneActions.js +0 -156
- package/dist/tools/builtin/bone/boneActions.js.map +0 -1
- package/dist/tools/builtin/bone/boneOverlay.js +0 -71
- package/dist/tools/builtin/bone/boneOverlay.js.map +0 -1
- package/dist/tools/builtin/bone/placedRig.js +0 -28
- package/dist/tools/builtin/bone/placedRig.js.map +0 -1
- package/dist/tools/builtin/bone/rigEditState.js +0 -30
- package/dist/tools/builtin/bone/rigEditState.js.map +0 -1
- package/dist/tools/builtin/bone/useBoneTool.js +0 -125
- package/dist/tools/builtin/bone/useBoneTool.js.map +0 -1
- package/dist/tools/builtin/weight/useWeightTool.js +0 -101
- package/dist/tools/builtin/weight/useWeightTool.js.map +0 -1
- package/dist/tools/builtin/weight/weightActions.js +0 -140
- package/dist/tools/builtin/weight/weightActions.js.map +0 -1
- package/dist/tools/builtin/weight/weightOverlay.js +0 -78
- package/dist/tools/builtin/weight/weightOverlay.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pathSnapSource.js","names":[],"sources":["../../../../src/features/paths/pathSnap/pathSnapSource.ts"],"sourcesContent":["import { findPathSnap, findPathSnaps, PATH_SNAP_KINDS, type PathSnapKind } from '@weasel-js/geom';\nimport type { Scene } from 'core/scene/types';\nimport { DEFAULT_SNAP_PX } from 'features/snap/session2d';\nimport type { SnapSource } from 'features/snap/types';\nimport { PATH_SNAP_LABELS } from './glyphs';\nimport { sceneSnapIndex } from './sceneIndex';\n\ntype Point = { x: number; y: number };\n\n/** Options for `pathSnapSource`. */\nexport interface PathSnapSourceOptions {\n /** The kinds offered. Default: every kind. */\n only?: readonly PathSnapKind[];\n /** Kinds to turn on or off. A kind not named is on. */\n kinds?: Partial<Record<PathSnapKind, boolean>>;\n /** Overrides the canvas's reach for path targets, in screen px. */\n reachPx?: number;\n}\n\n/**\n * The scene's paths as snap targets: a point for every enabled kind of\n * target in range of a pointer or geometry probe. `nearest` is offered only\n * when no other kind is in range of that probe. Tangent and perpendicular\n * targets need the query's `origin`.\n */\nexport function pathSnapSource(opts: PathSnapSourceOptions = {}): SnapSource {\n const kinds = (opts.only ?? PATH_SNAP_KINDS).filter((k) => opts.kinds?.[k] !== false);\n return {\n id: 'path-snap',\n roles: ['pointer', 'geometry'],\n ...(opts.reachPx !== undefined ? { reachPx: opts.reachPx } : {}),\n *collect(q) {\n if (!q.scene) return;\n const { ids, index } = sceneSnapIndex(q.scene, q.also);\n const exclude = new Set(q.exclude);\n const include = q.include ? new Set(q.include) : null;\n const radius = q.reachWorld(opts.reachPx ?? q.reachPx);\n const skip = (i: number) => {\n const id = ids[i];\n if (id === null) return false;\n return exclude.has(id) || (include ? !include.has(id) : false);\n };\n for (const p of q.probes) {\n const hits = findPathSnaps(index, p.at, { radius, kinds, skip, ...(q.origin ? { origin: q.origin } : {}) });\n for (const h of hits) {\n const at = { x: h.x, y: h.y };\n yield {\n probe: p.id,\n locus: { at, dirs: [] },\n mark: { kind: 'point', at, glyph: h.kind, label: PATH_SNAP_LABELS[h.kind] },\n };\n }\n }\n },\n };\n}\n\n/** The point of the nodes `ids`' own geometry nearest `press`, within
|
|
1
|
+
{"version":3,"file":"pathSnapSource.js","names":[],"sources":["../../../../src/features/paths/pathSnap/pathSnapSource.ts"],"sourcesContent":["import { findPathSnap, findPathSnaps, PATH_SNAP_KINDS, type PathSnapKind } from '@weasel-js/geom';\nimport type { Scene } from 'core/scene/types';\nimport { DEFAULT_SNAP_PX } from 'features/snap/session2d';\nimport type { SnapSource } from 'features/snap/types';\nimport { PATH_SNAP_LABELS } from './glyphs';\nimport { sceneSnapIndex } from './sceneIndex';\n\ntype Point = { x: number; y: number };\n\n/** Options for `pathSnapSource`. */\nexport interface PathSnapSourceOptions {\n /** The kinds offered. Default: every kind. */\n only?: readonly PathSnapKind[];\n /** Kinds to turn on or off. A kind not named is on. */\n kinds?: Partial<Record<PathSnapKind, boolean>>;\n /** Overrides the canvas's reach for path targets, in screen px. */\n reachPx?: number;\n}\n\n/**\n * The scene's paths as snap targets: a point for every enabled kind of\n * target in range of a pointer or geometry probe. `nearest` is offered only\n * when no other kind is in range of that probe. Tangent and perpendicular\n * targets need the query's `origin`.\n */\nexport function pathSnapSource(opts: PathSnapSourceOptions = {}): SnapSource {\n const kinds = (opts.only ?? PATH_SNAP_KINDS).filter((k) => opts.kinds?.[k] !== false);\n return {\n id: 'path-snap',\n roles: ['pointer', 'geometry'],\n ...(opts.reachPx !== undefined ? { reachPx: opts.reachPx } : {}),\n *collect(q) {\n if (!q.scene) return;\n const { ids, index } = sceneSnapIndex(q.scene, q.also);\n const exclude = new Set(q.exclude);\n const include = q.include ? new Set(q.include) : null;\n const radius = q.reachWorld(opts.reachPx ?? q.reachPx);\n const skip = (i: number) => {\n const id = ids[i];\n if (id === null) return false;\n return exclude.has(id) || (include ? !include.has(id) : false);\n };\n for (const p of q.probes) {\n const hits = findPathSnaps(index, p.at, { radius, kinds, skip, ...(q.origin ? { origin: q.origin } : {}) });\n for (const h of hits) {\n const at = { x: h.x, y: h.y };\n yield {\n probe: p.id,\n locus: { at, dirs: [] },\n mark: { kind: 'point', at, glyph: h.kind, label: PATH_SNAP_LABELS[h.kind] },\n };\n }\n }\n },\n };\n}\n\n/** The point of the nodes `ids`' own geometry nearest `press`, within\n * `reachPx` screen px, or null: where a move's `geometry` probe sits. Leaves\n * no mark. */\nexport function ownGeometryAt(\n scene: Pick<Scene<unknown, string, unknown>, 'nodes' | 'layers' | 'getVersion'>,\n press: Point,\n ids: readonly string[],\n scale: { x: number; y: number },\n reachPx = DEFAULT_SNAP_PX,\n): Point | null {\n const { ids: owners, index } = sceneSnapIndex(scene);\n const own = new Set(ids);\n const hit = findPathSnap(index, press, {\n radius: reachPx,\n scale,\n skip: (i) => {\n const id = owners[i];\n return id !== null && !own.has(id);\n },\n });\n return hit ? { x: hit.x, y: hit.y } : null;\n}\n"],"mappings":";;;;;;;;;;;;AAyBA,SAAgB,eAAe,OAA8B,CAAC,GAAe;CAC3E,MAAM,SAAS,KAAK,QAAQ,gBAAA,CAAiB,QAAQ,MAAM,KAAK,QAAQ,OAAO,KAAK;CACpF,OAAO;EACL,IAAI;EACJ,OAAO,CAAC,WAAW,UAAU;EAC7B,GAAI,KAAK,YAAY,SAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;EAC9D,CAAC,QAAQ,GAAG;GACV,IAAI,CAAC,EAAE,OAAO;GACd,MAAM,EAAE,KAAK,UAAU,eAAe,EAAE,OAAO,EAAE,IAAI;GACrD,MAAM,UAAU,IAAI,IAAI,EAAE,OAAO;GACjC,MAAM,UAAU,EAAE,UAAU,IAAI,IAAI,EAAE,OAAO,IAAI;GACjD,MAAM,SAAS,EAAE,WAAW,KAAK,WAAW,EAAE,OAAO;GACrD,MAAM,QAAQ,MAAc;IAC1B,MAAM,KAAK,IAAI;IACf,IAAI,OAAO,MAAM,OAAO;IACxB,OAAO,QAAQ,IAAI,EAAE,MAAM,UAAU,CAAC,QAAQ,IAAI,EAAE,IAAI;GAC1D;GACA,KAAK,MAAM,KAAK,EAAE,QAAQ;IACxB,MAAM,OAAO,cAAc,OAAO,EAAE,IAAI;KAAE;KAAQ;KAAO;KAAM,GAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,IAAI,CAAC;IAAG,CAAC;IAC1G,KAAK,MAAM,KAAK,MAAM;KACpB,MAAM,KAAK;MAAE,GAAG,EAAE;MAAG,GAAG,EAAE;KAAE;KAC5B,MAAM;MACJ,OAAO,EAAE;MACT,OAAO;OAAE;OAAI,MAAM,CAAC;MAAE;MACtB,MAAM;OAAE,MAAM;OAAS;OAAI,OAAO,EAAE;OAAM,OAAO,iBAAiB,EAAE;MAAM;KAC5E;IACF;GACF;EACF;CACF;AACF;;;;AAKA,SAAgB,cACd,OACA,OACA,KACA,OACA,UAAU,iBACI;CACd,MAAM,EAAE,KAAK,QAAQ,UAAU,eAAe,KAAK;CACnD,MAAM,MAAM,IAAI,IAAI,GAAG;CACvB,MAAM,MAAM,aAAa,OAAO,OAAO;EACrC,QAAQ;EACR;EACA,OAAO,MAAM;GACX,MAAM,KAAK,OAAO;GAClB,OAAO,OAAO,QAAQ,CAAC,IAAI,IAAI,EAAE;EACnC;CACF,CAAC;CACD,OAAO,MAAM;EAAE,GAAG,IAAI;EAAG,GAAG,IAAI;CAAE,IAAI;AACxC"}
|
|
@@ -6,12 +6,19 @@ import { createPathSnapIndex } from "@weasel-js/geom";
|
|
|
6
6
|
//#region src/features/paths/pathSnap/sceneIndex.ts
|
|
7
7
|
/** Indexes every leaf of `scene` with geometry (`nodeSnapGeometry`), but
|
|
8
8
|
* hidden ones (`nodeGates`) and those on an annotation layer, once per scene
|
|
9
|
-
* version, and again when a query brings geometry of its own.
|
|
9
|
+
* version, and again when a query brings geometry of its own. The scene
|
|
10
|
+
* alone and the scene with the last `also` are cached apart, so a query
|
|
11
|
+
* without geometry does not evict a gesture's. */
|
|
10
12
|
function createSceneSnapIndexer(scene) {
|
|
11
|
-
|
|
13
|
+
const slots = {
|
|
14
|
+
bare: null,
|
|
15
|
+
also: null
|
|
16
|
+
};
|
|
12
17
|
return (also) => {
|
|
13
18
|
const version = scene.getVersion();
|
|
14
19
|
const layers = scene.layers;
|
|
20
|
+
const key = also ? "also" : "bare";
|
|
21
|
+
const cached = slots[key];
|
|
15
22
|
if (cached?.version === version && cached.layers === layers && cached.also === also) return cached.built;
|
|
16
23
|
const notes = new Set(layers.filter(isAnnotationLayer).map((l) => l.id));
|
|
17
24
|
const gates = nodeGates({
|
|
@@ -55,7 +62,7 @@ function createSceneSnapIndexer(scene) {
|
|
|
55
62
|
ids,
|
|
56
63
|
index: createPathSnapIndex(paths, extra)
|
|
57
64
|
};
|
|
58
|
-
|
|
65
|
+
slots[key] = {
|
|
59
66
|
version,
|
|
60
67
|
layers,
|
|
61
68
|
also,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sceneIndex.js","names":[],"sources":["../../../../src/features/paths/pathSnap/sceneIndex.ts"],"sourcesContent":["import {\n createPathSnapIndex, type Path, type PathSnapIndex, type PathSnapTarget,\n} from '@weasel-js/geom';\nimport type { Scene } from 'core/scene/types';\nimport { isAnnotationLayer } from 'core/scene/annotation';\nimport { nodeGates } from 'core/scene/nodeGates';\nimport type { SnapGeometry } from 'interactions/actions/snapDep';\nimport { nodeSnapGeometry } from './snapGeometry';\n\ntype SnapScene = Pick<Scene<unknown, string, unknown>, 'nodes' | 'layers' | 'getVersion'>;\n\n/** A scene's paths indexed for snapping; `ids[i]` is the node path `i` came\n * from, or null for a path of the query's own (`also`). */\nexport interface SceneSnapIndex {\n ids: (string | null)[];\n index: PathSnapIndex;\n}\n\n/** Indexes every leaf of `scene` with geometry (`nodeSnapGeometry`), but\n * hidden ones (`nodeGates`) and those on an annotation layer, once per scene\n * version, and again when a query brings geometry of its own. */\nexport function createSceneSnapIndexer(scene: SnapScene): (also?: SnapGeometry) => SceneSnapIndex {\n
|
|
1
|
+
{"version":3,"file":"sceneIndex.js","names":[],"sources":["../../../../src/features/paths/pathSnap/sceneIndex.ts"],"sourcesContent":["import {\n createPathSnapIndex, type Path, type PathSnapIndex, type PathSnapTarget,\n} from '@weasel-js/geom';\nimport type { Scene } from 'core/scene/types';\nimport { isAnnotationLayer } from 'core/scene/annotation';\nimport { nodeGates } from 'core/scene/nodeGates';\nimport type { SnapGeometry } from 'interactions/actions/snapDep';\nimport { nodeSnapGeometry } from './snapGeometry';\n\ntype SnapScene = Pick<Scene<unknown, string, unknown>, 'nodes' | 'layers' | 'getVersion'>;\n\n/** A scene's paths indexed for snapping; `ids[i]` is the node path `i` came\n * from, or null for a path of the query's own (`also`). */\nexport interface SceneSnapIndex {\n ids: (string | null)[];\n index: PathSnapIndex;\n}\n\n/** Indexes every leaf of `scene` with geometry (`nodeSnapGeometry`), but\n * hidden ones (`nodeGates`) and those on an annotation layer, once per scene\n * version, and again when a query brings geometry of its own. The scene\n * alone and the scene with the last `also` are cached apart, so a query\n * without geometry does not evict a gesture's. */\nexport function createSceneSnapIndexer(scene: SnapScene): (also?: SnapGeometry) => SceneSnapIndex {\n type Slot = { version: number; layers: unknown; also: SnapGeometry | undefined; built: SceneSnapIndex };\n const slots: { bare: Slot | null; also: Slot | null } = { bare: null, also: null };\n return (also) => {\n const version = scene.getVersion();\n const layers = scene.layers;\n const key = also ? 'also' : 'bare';\n const cached = slots[key];\n if (cached?.version === version && cached.layers === layers && cached.also === also) return cached.built;\n const notes = new Set(layers.filter(isAnnotationLayer).map((l) => l.id));\n const gates = nodeGates({ layers, get: (id) => scene.nodes.get(id) });\n const ids: (string | null)[] = [];\n const paths: Path[] = [];\n const extra: PathSnapTarget[] = [];\n for (const node of scene.nodes.values()) {\n if (node.kind !== 'leaf' || notes.has(node.layer) || gates.hidden(node.id)) continue;\n const g = nodeSnapGeometry(node);\n if (!g) continue;\n for (const p of g.points) extra.push({ ...p, paths: [paths.length] });\n ids.push(node.id);\n paths.push(g.path);\n }\n for (const path of also?.paths ?? []) { ids.push(null); paths.push(path); }\n if (also?.anchors) {\n ids.push(null);\n for (const p of also.anchors) extra.push({ kind: 'anchor', x: p.x, y: p.y, paths: [paths.length] });\n paths.push({ kind: 'polygon', commands: new Uint8Array(), coords: new Float32Array(), fillRule: 'nonzero' });\n }\n const built = { ids, index: createPathSnapIndex(paths, extra) };\n slots[key] = { version, layers, also, built };\n return built;\n };\n}\n\nconst indexers = new WeakMap<object, ReturnType<typeof createSceneSnapIndexer>>();\n\n/** {@link createSceneSnapIndexer}, one per scene, so every source over a\n * scene shares its index. */\nexport function sceneSnapIndex(scene: SnapScene, also?: SnapGeometry): SceneSnapIndex {\n let indexer = indexers.get(scene);\n if (!indexer) indexers.set(scene, (indexer = createSceneSnapIndexer(scene)));\n return indexer(also);\n}\n"],"mappings":";;;;;;;;;;;AAuBA,SAAgB,uBAAuB,OAA2D;CAEhG,MAAM,QAAkD;EAAE,MAAM;EAAM,MAAM;CAAK;CACjF,QAAQ,SAAS;EACf,MAAM,UAAU,MAAM,WAAW;EACjC,MAAM,SAAS,MAAM;EACrB,MAAM,MAAM,OAAO,SAAS;EAC5B,MAAM,SAAS,MAAM;EACrB,IAAI,QAAQ,YAAY,WAAW,OAAO,WAAW,UAAU,OAAO,SAAS,MAAM,OAAO,OAAO;EACnG,MAAM,QAAQ,IAAI,IAAI,OAAO,OAAO,iBAAiB,CAAC,CAAC,KAAK,MAAM,EAAE,EAAE,CAAC;EACvE,MAAM,QAAQ,UAAU;GAAE;GAAQ,MAAM,OAAO,MAAM,MAAM,IAAI,EAAE;EAAE,CAAC;EACpE,MAAM,MAAyB,CAAC;EAChC,MAAM,QAAgB,CAAC;EACvB,MAAM,QAA0B,CAAC;EACjC,KAAK,MAAM,QAAQ,MAAM,MAAM,OAAO,GAAG;GACvC,IAAI,KAAK,SAAS,UAAU,MAAM,IAAI,KAAK,KAAK,KAAK,MAAM,OAAO,KAAK,EAAE,GAAG;GAC5E,MAAM,IAAI,iBAAiB,IAAI;GAC/B,IAAI,CAAC,GAAG;GACR,KAAK,MAAM,KAAK,EAAE,QAAQ,MAAM,KAAK;IAAE,GAAG;IAAG,OAAO,CAAC,MAAM,MAAM;GAAE,CAAC;GACpE,IAAI,KAAK,KAAK,EAAE;GAChB,MAAM,KAAK,EAAE,IAAI;EACnB;EACA,KAAK,MAAM,QAAQ,MAAM,SAAS,CAAC,GAAG;GAAE,IAAI,KAAK,IAAI;GAAG,MAAM,KAAK,IAAI;EAAG;EAC1E,IAAI,MAAM,SAAS;GACjB,IAAI,KAAK,IAAI;GACb,KAAK,MAAM,KAAK,KAAK,SAAS,MAAM,KAAK;IAAE,MAAM;IAAU,GAAG,EAAE;IAAG,GAAG,EAAE;IAAG,OAAO,CAAC,MAAM,MAAM;GAAE,CAAC;GAClG,MAAM,KAAK;IAAE,MAAM;IAAW,0BAAU,IAAI,WAAW;IAAG,wBAAQ,IAAI,aAAa;IAAG,UAAU;GAAU,CAAC;EAC7G;EACA,MAAM,QAAQ;GAAE;GAAK,OAAO,oBAAoB,OAAO,KAAK;EAAE;EAC9D,MAAM,OAAO;GAAE;GAAS;GAAQ;GAAM;EAAM;EAC5C,OAAO;CACT;AACF;AAEA,IAAM,2BAAW,IAAI,QAA2D;;;AAIhF,SAAgB,eAAe,OAAkB,MAAqC;CACpF,IAAI,UAAU,SAAS,IAAI,KAAK;CAChC,IAAI,CAAC,SAAS,SAAS,IAAI,OAAQ,UAAU,uBAAuB,KAAK,CAAE;CAC3E,OAAO,QAAQ,IAAI;AACrB"}
|
|
@@ -31,7 +31,10 @@ function boxReader(d, scene) {
|
|
|
31
31
|
framed: (_id, pose) => framedBounds(pose, d),
|
|
32
32
|
aabb: (_id, pose) => visualBoundsViaDescriptor(pose, d)
|
|
33
33
|
};
|
|
34
|
-
const leaves = {
|
|
34
|
+
const leaves = {
|
|
35
|
+
get: (id) => scene.get(id),
|
|
36
|
+
...scene.derivedPathOf ? { derivedPathOf: (id) => scene.derivedPathOf(id) } : {}
|
|
37
|
+
};
|
|
35
38
|
const opts = (scale) => ({
|
|
36
39
|
descriptor: d,
|
|
37
40
|
...scale !== void 0 ? { scale } : {}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selectionPose.js","names":[],"sources":["../../../src/features/selection/selectionPose.ts"],"sourcesContent":["/**\n * The pose and box a selection's chrome is drawn around: precedence between\n * the in-flight overlays and the stored pose, a container's union over its\n * leaves, and the drawn box a scene supplies.\n */\nimport type { Scale2 } from '@weasel-js/geom';\nimport { drawnAABBOf, drawnBoundsOf, type DrawnBoundsScene } from 'canvas/drawnBounds';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport { framedBounds, visualBoundsViaDescriptor, type PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport { AUTO_POSE_DESCRIPTOR } from 'core/geometry/autoPoseDescriptor';\nimport type { NodeId } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\n\n/**\n * Transitive leaf ids under `id`. A childless node is a leaf only if it is not\n * itself a container: an empty container contributes no bounds, and its own\n * stored pose is at its most stale when no children are left to have moved it.\n */\nfunction leavesOf(\n id: string,\n getChildren: (id: string) => readonly string[],\n isContainer: (id: string) => boolean,\n): string[] {\n if (!isContainer(id)) return [id];\n const out: string[] = [];\n const visit = (nid: string) => {\n const kids = getChildren(nid);\n if (kids.length === 0) { if (!isContainer(nid)) out.push(nid); return; }\n for (const k of kids) visit(k);\n };\n visit(id);\n return out;\n}\n\n/** How one id's pose becomes a box: the pose box, or with a scene the box the\n * node is drawn with. Each id is read as a leaf — the pose already says where\n * a container is, so its members' stored poses are not consulted again. */\nfunction boxReader<TPose>(\n d: PoseDescriptor<TPose>,\n scene: DrawnBoundsScene | undefined,\n): { framed(id: string, pose: TPose, scale?: number | Scale2): Bounds; aabb(id: string, pose: TPose, scale?: number | Scale2): Bounds } {\n if (!scene) {\n return {\n framed: (_id, pose) => framedBounds(pose, d),\n aabb: (_id, pose) => visualBoundsViaDescriptor(pose, d),\n };\n }\n const leaves: DrawnBoundsScene = {
|
|
1
|
+
{"version":3,"file":"selectionPose.js","names":[],"sources":["../../../src/features/selection/selectionPose.ts"],"sourcesContent":["/**\n * The pose and box a selection's chrome is drawn around: precedence between\n * the in-flight overlays and the stored pose, a container's union over its\n * leaves, and the drawn box a scene supplies.\n */\nimport type { Scale2 } from '@weasel-js/geom';\nimport { drawnAABBOf, drawnBoundsOf, type DrawnBoundsScene } from 'canvas/drawnBounds';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport { framedBounds, visualBoundsViaDescriptor, type PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport { AUTO_POSE_DESCRIPTOR } from 'core/geometry/autoPoseDescriptor';\nimport type { NodeId } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\n\n/**\n * Transitive leaf ids under `id`. A childless node is a leaf only if it is not\n * itself a container: an empty container contributes no bounds, and its own\n * stored pose is at its most stale when no children are left to have moved it.\n */\nfunction leavesOf(\n id: string,\n getChildren: (id: string) => readonly string[],\n isContainer: (id: string) => boolean,\n): string[] {\n if (!isContainer(id)) return [id];\n const out: string[] = [];\n const visit = (nid: string) => {\n const kids = getChildren(nid);\n if (kids.length === 0) { if (!isContainer(nid)) out.push(nid); return; }\n for (const k of kids) visit(k);\n };\n visit(id);\n return out;\n}\n\n/** How one id's pose becomes a box: the pose box, or with a scene the box the\n * node is drawn with. Each id is read as a leaf — the pose already says where\n * a container is, so its members' stored poses are not consulted again. */\nfunction boxReader<TPose>(\n d: PoseDescriptor<TPose>,\n scene: DrawnBoundsScene | undefined,\n): { framed(id: string, pose: TPose, scale?: number | Scale2): Bounds; aabb(id: string, pose: TPose, scale?: number | Scale2): Bounds } {\n if (!scene) {\n return {\n framed: (_id, pose) => framedBounds(pose, d),\n aabb: (_id, pose) => visualBoundsViaDescriptor(pose, d),\n };\n }\n const leaves: DrawnBoundsScene = {\n get: (id) => scene.get(id),\n ...(scene.derivedPathOf ? { derivedPathOf: (id: NodeId) => scene.derivedPathOf!(id) } : {}),\n };\n const opts = (scale: number | Scale2 | undefined) => ({\n descriptor: d as PoseDescriptor<unknown>,\n ...(scale !== undefined ? { scale } : {}),\n });\n return {\n framed: (id, pose, scale) => drawnBoundsOf(leaves, id as NodeId, pose, opts(scale)),\n aabb: (id, pose, scale) => drawnAABBOf(leaves, id as NodeId, pose, opts(scale)),\n };\n}\n\n/** Options for `composeSelectionPose`. */\nexport interface ComposeSelectionPoseOpts<TPose> {\n /** Move overlay; when present its `poses` map wins over everything else. */\n moveOverlay?: { poses: Map<string, TPose> } | null;\n /**\n * Resize overlay; consulted only when move overlay does not own the id.\n * For container resize, `leafPoses` (when present) maps each leaf id under\n * the container to its overlay pose. If absent the container falls back to\n * stored leaf poses.\n */\n resizeOverlay?: {\n id: string;\n currentPose: TPose;\n leafPoses?: Map<string, TPose>;\n } | null;\n /** Fallback pose lookup (typically the stored/committed pose). */\n getStoredPose: (id: string) => TPose;\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Walk a container's direct children (e.g. `scene.childrenOf`). With\n * `isContainer`, a selected container resolves to the union AABB of its\n * transitive leaf poses instead of its own stored pose. */\n getChildren?: (id: string) => readonly string[];\n /** True when `id` is a structural container. */\n isContainer?: (id: string) => boolean;\n /** The nodes behind the ids. With it, a container's union takes each leaf\n * as drawn, stroke included (`drawnBoundsOf`); without, its pose box. */\n scene?: DrawnBoundsScene;\n /** View scale a screen-pixel stroke is resolved at. Default 1. */\n viewScale?: () => number | Scale2;\n}\n\n/**\n * Build a pose resolver for a selection. Precedence per id:\n * move overlay > resize overlay > stored. When `getChildren`/`isContainer`\n * are supplied and the id resolves to a container, the resolver returns the\n * union AABB of all transitive leaf poses (each leaf still subject to the\n * precedence rules). Containers with no leaves resolve to `null`.\n */\nexport function composeSelectionPose<TPose>(\n opts: ComposeSelectionPoseOpts<TPose>,\n): (id: string) => TPose | null {\n const { moveOverlay, resizeOverlay, getStoredPose, getChildren, isContainer } = opts;\n const d = (opts.poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n const boxes = boxReader(d, opts.scene);\n\n const selectionLeaves = (id: string): string[] =>\n getChildren && isContainer ? leavesOf(id, getChildren, isContainer) : [id];\n\n const resolveLeaf = (id: string): TPose => {\n const moved = moveOverlay?.poses.get(id);\n if (moved !== undefined) return moved;\n if (resizeOverlay && resizeOverlay.id === id) return resizeOverlay.currentPose;\n return getStoredPose(id);\n };\n\n return (id: string): TPose | null => {\n if (isContainer?.(id)) {\n const leaves = selectionLeaves(id);\n if (leaves.length === 0) return null;\n const containerResizeLeafPoses =\n resizeOverlay && resizeOverlay.id === id ? resizeOverlay.leafPoses : undefined;\n const scale = opts.viewScale?.();\n const leafBounds: Bounds[] = [];\n for (const leafId of leaves) {\n const pose = moveOverlay?.poses.get(leafId)\n ?? containerResizeLeafPoses?.get(leafId)\n ?? getStoredPose(leafId);\n leafBounds.push(boxes.aabb(leafId, pose, scale));\n }\n const u = unionAABB(leafBounds);\n if (u === null) return null;\n return d.fromBounds(u, getStoredPose(leaves[0]!));\n }\n return resolveLeaf(id);\n };\n}\n\n/**\n * Build a bounds resolver that handles container ids by computing the union\n * AABB of every leaf's bounds. Non-container ids pass through directly. When\n * `getChildren`/`isContainer` are omitted, every id is treated as a leaf.\n * With a scene, each leaf is boxed as drawn at the view's scale.\n */\nexport function containerAwareBoundsResolver<TPose>(\n getPose: (id: string) => TPose | null,\n d: PoseDescriptor<TPose>,\n getChildren: ((id: string) => readonly string[]) | undefined,\n isContainer: ((id: string) => boolean) | undefined,\n scene: DrawnBoundsScene | undefined,\n): (id: string, scale: Scale2) => Bounds | null {\n const boxes = boxReader(d, scene);\n const leaf = (id: string, scale: Scale2): Bounds | null => {\n const p = getPose(id);\n return p === null ? null : boxes.framed(id, p, scale);\n };\n if (getChildren === undefined || isContainer === undefined) return leaf;\n return (id, scale) => {\n if (!isContainer(id)) return leaf(id, scale);\n const leaves = leavesOf(id, getChildren, isContainer);\n if (leaves.length === 0) return null;\n const leafBounds: Bounds[] = [];\n for (const leafId of leaves) {\n const p = getPose(leafId);\n if (p !== null) leafBounds.push(boxes.aabb(leafId, p, scale));\n }\n if (leafBounds.length === 0) return null;\n return unionAABB(leafBounds);\n };\n}\n"],"mappings":";;;;;;;;;;;AAkBA,SAAS,SACP,IACA,aACA,aACU;CACV,IAAI,CAAC,YAAY,EAAE,GAAG,OAAO,CAAC,EAAE;CAChC,MAAM,MAAgB,CAAC;CACvB,MAAM,SAAS,QAAgB;EAC7B,MAAM,OAAO,YAAY,GAAG;EAC5B,IAAI,KAAK,WAAW,GAAG;GAAE,IAAI,CAAC,YAAY,GAAG,GAAG,IAAI,KAAK,GAAG;GAAG;EAAQ;EACvE,KAAK,MAAM,KAAK,MAAM,MAAM,CAAC;CAC/B;CACA,MAAM,EAAE;CACR,OAAO;AACT;;;;AAKA,SAAS,UACP,GACA,OACsI;CACtI,IAAI,CAAC,OACH,OAAO;EACL,SAAS,KAAK,SAAS,aAAa,MAAM,CAAC;EAC3C,OAAO,KAAK,SAAS,0BAA0B,MAAM,CAAC;CACxD;CAEF,MAAM,SAA2B;EAC/B,MAAM,OAAO,MAAM,IAAI,EAAE;EACzB,GAAI,MAAM,gBAAgB,EAAE,gBAAgB,OAAe,MAAM,cAAe,EAAE,EAAE,IAAI,CAAC;CAC3F;CACA,MAAM,QAAQ,WAAwC;EACpD,YAAY;EACZ,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;CACzC;CACA,OAAO;EACL,SAAS,IAAI,MAAM,UAAU,cAAc,QAAQ,IAAc,MAAM,KAAK,KAAK,CAAC;EAClF,OAAO,IAAI,MAAM,UAAU,YAAY,QAAQ,IAAc,MAAM,KAAK,KAAK,CAAC;CAChF;AACF;;;;;;;;AAyCA,SAAgB,qBACd,MAC8B;CAC9B,MAAM,EAAE,aAAa,eAAe,eAAe,aAAa,gBAAgB;CAChF,MAAM,IAAK,KAAK,kBAAkB;CAClC,MAAM,QAAQ,UAAU,GAAG,KAAK,KAAK;CAErC,MAAM,mBAAmB,OACvB,eAAe,cAAc,SAAS,IAAI,aAAa,WAAW,IAAI,CAAC,EAAE;CAE3E,MAAM,eAAe,OAAsB;EACzC,MAAM,QAAQ,aAAa,MAAM,IAAI,EAAE;EACvC,IAAI,UAAU,QAAW,OAAO;EAChC,IAAI,iBAAiB,cAAc,OAAO,IAAI,OAAO,cAAc;EACnE,OAAO,cAAc,EAAE;CACzB;CAEA,QAAQ,OAA6B;EACnC,IAAI,cAAc,EAAE,GAAG;GACrB,MAAM,SAAS,gBAAgB,EAAE;GACjC,IAAI,OAAO,WAAW,GAAG,OAAO;GAChC,MAAM,2BACJ,iBAAiB,cAAc,OAAO,KAAK,cAAc,YAAY;GACvE,MAAM,QAAQ,KAAK,YAAY;GAC/B,MAAM,aAAuB,CAAC;GAC9B,KAAK,MAAM,UAAU,QAAQ;IAC3B,MAAM,OAAO,aAAa,MAAM,IAAI,MAAM,KACrC,0BAA0B,IAAI,MAAM,KACpC,cAAc,MAAM;IACzB,WAAW,KAAK,MAAM,KAAK,QAAQ,MAAM,KAAK,CAAC;GACjD;GACA,MAAM,IAAI,UAAU,UAAU;GAC9B,IAAI,MAAM,MAAM,OAAO;GACvB,OAAO,EAAE,WAAW,GAAG,cAAc,OAAO,EAAG,CAAC;EAClD;EACA,OAAO,YAAY,EAAE;CACvB;AACF;;;;;;;AAQA,SAAgB,6BACd,SACA,GACA,aACA,aACA,OAC8C;CAC9C,MAAM,QAAQ,UAAU,GAAG,KAAK;CAChC,MAAM,QAAQ,IAAY,UAAiC;EACzD,MAAM,IAAI,QAAQ,EAAE;EACpB,OAAO,MAAM,OAAO,OAAO,MAAM,OAAO,IAAI,GAAG,KAAK;CACtD;CACA,IAAI,gBAAgB,UAAa,gBAAgB,QAAW,OAAO;CACnE,QAAQ,IAAI,UAAU;EACpB,IAAI,CAAC,YAAY,EAAE,GAAG,OAAO,KAAK,IAAI,KAAK;EAC3C,MAAM,SAAS,SAAS,IAAI,aAAa,WAAW;EACpD,IAAI,OAAO,WAAW,GAAG,OAAO;EAChC,MAAM,aAAuB,CAAC;EAC9B,KAAK,MAAM,UAAU,QAAQ;GAC3B,MAAM,IAAI,QAAQ,MAAM;GACxB,IAAI,MAAM,MAAM,WAAW,KAAK,MAAM,KAAK,QAAQ,GAAG,KAAK,CAAC;EAC9D;EACA,IAAI,WAAW,WAAW,GAAG,OAAO;EACpC,OAAO,UAAU,UAAU;CAC7B;AACF"}
|
|
@@ -10,6 +10,14 @@ var DEFAULT_GESTURES = [
|
|
|
10
10
|
function snapSourcesFor(sources, gesture) {
|
|
11
11
|
return sources.filter((s) => (s.gestures ?? DEFAULT_GESTURES).includes(gesture));
|
|
12
12
|
}
|
|
13
|
+
/** Throws if two of `sources` share an id: one would silently replace the other. */
|
|
14
|
+
function assertSnapSourceIds(sources) {
|
|
15
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16
|
+
for (const { id } of sources) {
|
|
17
|
+
if (seen.has(id)) throw new Error(`[snap] two snap sources share the id '${id}'. Give one its own id, or drop one.`);
|
|
18
|
+
seen.add(id);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
13
21
|
/** How near `origin` a point target counts as on it, relative to its magnitude. */
|
|
14
22
|
var ORIGIN_EPS = 1e-9;
|
|
15
23
|
/**
|
|
@@ -67,5 +75,5 @@ function marksOf(mark, delta) {
|
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
//#endregion
|
|
70
|
-
export { gatherSnapCandidates, resolvedSnapMarks, snapSourcesFor };
|
|
78
|
+
export { assertSnapSourceIds, gatherSnapCandidates, resolvedSnapMarks, snapSourcesFor };
|
|
71
79
|
//# sourceMappingURL=gather.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gather.js","names":[],"sources":["../../../src/features/snap/gather.ts"],"sourcesContent":["import type { SnapCandidate, Vec } from '@weasel-js/geom/nd';\nimport { distinct } from './marks';\nimport type { SnapCollect, SnapGesture, SnapMark, SnapProbeAt, SnapSource, SourceCandidate } from './types';\n\nconst DEFAULT_GESTURES: readonly SnapGesture[] = ['point', 'move', 'resize'];\n\n/** The sources that answer `gesture`: those naming it, and, for one naming none, point, move and resize. */\nexport function snapSourcesFor<S extends Pick<SnapSource<unknown>, 'gestures'>>(sources: readonly S[], gesture: SnapGesture): S[] {\n return sources.filter((s) => (s.gestures ?? DEFAULT_GESTURES).includes(gesture));\n}\n\n/** What a candidate draws when the result meets it. */\nexport type SnapCandidateMark<P> = NonNullable<SourceCandidate<P>['mark']>;\n\n/** How near `origin` a point target counts as on it, relative to its magnitude. */\nconst ORIGIN_EPS = 1e-9;\n\n/** How `gatherSnapCandidates` reads a host's points. */\nexport interface GatherSnapOptions<P> {\n /** `p` as a resolver tuple. */\n toVec(p: P): Vec;\n /** The reach of a source that sets none, in screen px. */\n reachPx: number;\n /** Where the geometry being drawn starts: no point target on it is offered. */\n origin?: P;\n}\n\n/**\n * One frame's resolver candidates: each source is asked, through `ask`, about\n * the probes whose role it matches and the reach that applies to it (its\n * own `reachPx`, else `opts.reachPx`), and what it answers for a probe it was\n * not offered, or a point on `origin`, is dropped. Sources run in order, and\n * an earlier source, then an earlier yield, wins a full tie. The building\n * block of a host's own snap session over `resolveSnap`.\n */\nexport function gatherSnapCandidates<P>(\n sources: readonly SnapSource<P>[],\n probes: readonly SnapProbeAt<P>[],\n ask: (source: SnapSource<P>, offered: SnapProbeAt<P>[], reachPx: number) => SnapCollect<P>,\n opts: GatherSnapOptions<P>,\n): SnapCandidate<SnapCandidateMark<P>>[] {\n const origin = opts.origin === undefined ? null : opts.toVec(opts.origin);\n const out: SnapCandidate<SnapCandidateMark<P>>[] = [];\n let order = 0;\n for (const source of sources) {\n const offered = probes.filter((q) => source.roles.includes(q.role));\n if (offered.length === 0) continue;\n const ids = new Set(offered.map((q) => q.id));\n const reachPx = source.reachPx ?? opts.reachPx;\n for (const c of source.collect(ask(source, offered, reachPx))) {\n if (!ids.has(c.probe)) continue;\n const at = opts.toVec(c.locus.at);\n if (origin && c.locus.dirs.length === 0 && same(at, origin)) continue;\n out.push({\n probe: c.probe, locus: { at, dirs: c.locus.dirs.map(opts.toVec) },\n ...(c.locus.span ? { span: c.locus.span } : {}),\n source: source.id, order: order++, tier: source.tier ?? 'target', reachPx,\n ...(c.required ? { required: true } : {}),\n ...(c.mark ? { mark: c.mark } : {}),\n });\n }\n }\n return out;\n}\n\nfunction same(a: Vec, b: Vec): boolean {\n const eps = ORIGIN_EPS * Math.max(1, ...b.map(Math.abs));\n return a.every((v, i) => Math.abs(v - b[i]) <= eps);\n}\n\n/** The marks of the candidates a result meets, with `delta` the resolved\n * move, and repeats dropped so a target several probes meet is drawn once. */\nexport function resolvedSnapMarks<P>(\n satisfied: readonly { mark?: SnapCandidateMark<P> }[], delta: P,\n): SnapMark<P>[] {\n return distinct(satisfied.flatMap((c) => marksOf(c.mark, delta)));\n}\n\nfunction marksOf<P>(mark: SnapCandidateMark<P> | undefined, delta: P): readonly SnapMark<P>[] {\n if (!mark) return [];\n const m = typeof mark === 'function' ? mark(delta) : mark;\n return 'kind' in m ? [m as SnapMark<P>] : (m as readonly SnapMark<P>[]);\n}\n"],"mappings":";;;AAIA,IAAM,mBAA2C;CAAC;CAAS;CAAQ;AAAQ;;AAG3E,SAAgB,eAAgE,SAAuB,SAA2B;CAChI,OAAO,QAAQ,QAAQ,OAAO,EAAE,YAAY,iBAAA,CAAkB,SAAS,OAAO,CAAC;AACjF;;AAMA,IAAM,aAAa;;;;;;;;;AAoBnB,SAAgB,qBACd,SACA,QACA,KACA,MACuC;CACvC,MAAM,SAAS,KAAK,WAAW,SAAY,OAAO,KAAK,MAAM,KAAK,MAAM;CACxE,MAAM,MAA6C,CAAC;CACpD,IAAI,QAAQ;CACZ,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,UAAU,OAAO,QAAQ,MAAM,OAAO,MAAM,SAAS,EAAE,IAAI,CAAC;EAClE,IAAI,QAAQ,WAAW,GAAG;EAC1B,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,MAAM,EAAE,EAAE,CAAC;EAC5C,MAAM,UAAU,OAAO,WAAW,KAAK;EACvC,KAAK,MAAM,KAAK,OAAO,QAAQ,IAAI,QAAQ,SAAS,OAAO,CAAC,GAAG;GAC7D,IAAI,CAAC,IAAI,IAAI,EAAE,KAAK,GAAG;GACvB,MAAM,KAAK,KAAK,MAAM,EAAE,MAAM,EAAE;GAChC,IAAI,UAAU,EAAE,MAAM,KAAK,WAAW,KAAK,KAAK,IAAI,MAAM,GAAG;GAC7D,IAAI,KAAK;IACP,OAAO,EAAE;IAAO,OAAO;KAAE;KAAI,MAAM,EAAE,MAAM,KAAK,IAAI,KAAK,KAAK;IAAE;IAChE,GAAI,EAAE,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,OAAO;IAAI,OAAO;IAAS,MAAM,OAAO,QAAQ;IAAU;IAClE,GAAI,EAAE,WAAW,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,GAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;GACnC,CAAC;EACH;CACF;CACA,OAAO;AACT;AAEA,SAAS,KAAK,GAAQ,GAAiB;CACrC,MAAM,MAAM,aAAa,KAAK,IAAI,GAAG,GAAG,EAAE,IAAI,KAAK,GAAG,CAAC;CACvD,OAAO,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI,IAAI,EAAE,EAAE,KAAK,GAAG;AACpD;;;AAIA,SAAgB,kBACd,WAAuD,OACxC;CACf,OAAO,SAAS,UAAU,SAAS,MAAM,QAAQ,EAAE,MAAM,KAAK,CAAC,CAAC;AAClE;AAEA,SAAS,QAAW,MAAwC,OAAkC;CAC5F,IAAI,CAAC,MAAM,OAAO,CAAC;CACnB,MAAM,IAAI,OAAO,SAAS,aAAa,KAAK,KAAK,IAAI;CACrD,OAAO,UAAU,IAAI,CAAC,CAAgB,IAAK;AAC7C"}
|
|
1
|
+
{"version":3,"file":"gather.js","names":[],"sources":["../../../src/features/snap/gather.ts"],"sourcesContent":["import type { SnapCandidate, Vec } from '@weasel-js/geom/nd';\nimport { distinct } from './marks';\nimport type { SnapCollect, SnapGesture, SnapMark, SnapProbeAt, SnapSource, SourceCandidate } from './types';\n\nconst DEFAULT_GESTURES: readonly SnapGesture[] = ['point', 'move', 'resize'];\n\n/** The sources that answer `gesture`: those naming it, and, for one naming none, point, move and resize. */\nexport function snapSourcesFor<S extends Pick<SnapSource<unknown>, 'gestures'>>(sources: readonly S[], gesture: SnapGesture): S[] {\n return sources.filter((s) => (s.gestures ?? DEFAULT_GESTURES).includes(gesture));\n}\n\n/** Throws if two of `sources` share an id: one would silently replace the other. */\nexport function assertSnapSourceIds(sources: readonly Pick<SnapSource<unknown>, 'id'>[]): void {\n const seen = new Set<string>();\n for (const { id } of sources) {\n if (seen.has(id)) {\n throw new Error(`[snap] two snap sources share the id '${id}'. Give one its own id, or drop one.`);\n }\n seen.add(id);\n }\n}\n\n/** What a candidate draws when the result meets it. */\nexport type SnapCandidateMark<P> = NonNullable<SourceCandidate<P>['mark']>;\n\n/** How near `origin` a point target counts as on it, relative to its magnitude. */\nconst ORIGIN_EPS = 1e-9;\n\n/** How `gatherSnapCandidates` reads a host's points. */\nexport interface GatherSnapOptions<P> {\n /** `p` as a resolver tuple. */\n toVec(p: P): Vec;\n /** The reach of a source that sets none, in screen px. */\n reachPx: number;\n /** Where the geometry being drawn starts: no point target on it is offered. */\n origin?: P;\n}\n\n/**\n * One frame's resolver candidates: each source is asked, through `ask`, about\n * the probes whose role it matches and the reach that applies to it (its\n * own `reachPx`, else `opts.reachPx`), and what it answers for a probe it was\n * not offered, or a point on `origin`, is dropped. Sources run in order, and\n * an earlier source, then an earlier yield, wins a full tie. The building\n * block of a host's own snap session over `resolveSnap`.\n */\nexport function gatherSnapCandidates<P>(\n sources: readonly SnapSource<P>[],\n probes: readonly SnapProbeAt<P>[],\n ask: (source: SnapSource<P>, offered: SnapProbeAt<P>[], reachPx: number) => SnapCollect<P>,\n opts: GatherSnapOptions<P>,\n): SnapCandidate<SnapCandidateMark<P>>[] {\n const origin = opts.origin === undefined ? null : opts.toVec(opts.origin);\n const out: SnapCandidate<SnapCandidateMark<P>>[] = [];\n let order = 0;\n for (const source of sources) {\n const offered = probes.filter((q) => source.roles.includes(q.role));\n if (offered.length === 0) continue;\n const ids = new Set(offered.map((q) => q.id));\n const reachPx = source.reachPx ?? opts.reachPx;\n for (const c of source.collect(ask(source, offered, reachPx))) {\n if (!ids.has(c.probe)) continue;\n const at = opts.toVec(c.locus.at);\n if (origin && c.locus.dirs.length === 0 && same(at, origin)) continue;\n out.push({\n probe: c.probe, locus: { at, dirs: c.locus.dirs.map(opts.toVec) },\n ...(c.locus.span ? { span: c.locus.span } : {}),\n source: source.id, order: order++, tier: source.tier ?? 'target', reachPx,\n ...(c.required ? { required: true } : {}),\n ...(c.mark ? { mark: c.mark } : {}),\n });\n }\n }\n return out;\n}\n\nfunction same(a: Vec, b: Vec): boolean {\n const eps = ORIGIN_EPS * Math.max(1, ...b.map(Math.abs));\n return a.every((v, i) => Math.abs(v - b[i]) <= eps);\n}\n\n/** The marks of the candidates a result meets, with `delta` the resolved\n * move, and repeats dropped so a target several probes meet is drawn once. */\nexport function resolvedSnapMarks<P>(\n satisfied: readonly { mark?: SnapCandidateMark<P> }[], delta: P,\n): SnapMark<P>[] {\n return distinct(satisfied.flatMap((c) => marksOf(c.mark, delta)));\n}\n\nfunction marksOf<P>(mark: SnapCandidateMark<P> | undefined, delta: P): readonly SnapMark<P>[] {\n if (!mark) return [];\n const m = typeof mark === 'function' ? mark(delta) : mark;\n return 'kind' in m ? [m as SnapMark<P>] : (m as readonly SnapMark<P>[]);\n}\n"],"mappings":";;;AAIA,IAAM,mBAA2C;CAAC;CAAS;CAAQ;AAAQ;;AAG3E,SAAgB,eAAgE,SAAuB,SAA2B;CAChI,OAAO,QAAQ,QAAQ,OAAO,EAAE,YAAY,iBAAA,CAAkB,SAAS,OAAO,CAAC;AACjF;;AAGA,SAAgB,oBAAoB,SAA2D;CAC7F,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,EAAE,QAAQ,SAAS;EAC5B,IAAI,KAAK,IAAI,EAAE,GACb,MAAM,IAAI,MAAM,yCAAyC,GAAG,qCAAqC;EAEnG,KAAK,IAAI,EAAE;CACb;AACF;;AAMA,IAAM,aAAa;;;;;;;;;AAoBnB,SAAgB,qBACd,SACA,QACA,KACA,MACuC;CACvC,MAAM,SAAS,KAAK,WAAW,SAAY,OAAO,KAAK,MAAM,KAAK,MAAM;CACxE,MAAM,MAA6C,CAAC;CACpD,IAAI,QAAQ;CACZ,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,UAAU,OAAO,QAAQ,MAAM,OAAO,MAAM,SAAS,EAAE,IAAI,CAAC;EAClE,IAAI,QAAQ,WAAW,GAAG;EAC1B,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,MAAM,EAAE,EAAE,CAAC;EAC5C,MAAM,UAAU,OAAO,WAAW,KAAK;EACvC,KAAK,MAAM,KAAK,OAAO,QAAQ,IAAI,QAAQ,SAAS,OAAO,CAAC,GAAG;GAC7D,IAAI,CAAC,IAAI,IAAI,EAAE,KAAK,GAAG;GACvB,MAAM,KAAK,KAAK,MAAM,EAAE,MAAM,EAAE;GAChC,IAAI,UAAU,EAAE,MAAM,KAAK,WAAW,KAAK,KAAK,IAAI,MAAM,GAAG;GAC7D,IAAI,KAAK;IACP,OAAO,EAAE;IAAO,OAAO;KAAE;KAAI,MAAM,EAAE,MAAM,KAAK,IAAI,KAAK,KAAK;IAAE;IAChE,GAAI,EAAE,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,OAAO;IAAI,OAAO;IAAS,MAAM,OAAO,QAAQ;IAAU;IAClE,GAAI,EAAE,WAAW,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,GAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;GACnC,CAAC;EACH;CACF;CACA,OAAO;AACT;AAEA,SAAS,KAAK,GAAQ,GAAiB;CACrC,MAAM,MAAM,aAAa,KAAK,IAAI,GAAG,GAAG,EAAE,IAAI,KAAK,GAAG,CAAC;CACvD,OAAO,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI,IAAI,EAAE,EAAE,KAAK,GAAG;AACpD;;;AAIA,SAAgB,kBACd,WAAuD,OACxC;CACf,OAAO,SAAS,UAAU,SAAS,MAAM,QAAQ,EAAE,MAAM,KAAK,CAAC,CAAC;AAClE;AAEA,SAAS,QAAW,MAAwC,OAAkC;CAC5F,IAAI,CAAC,MAAM,OAAO,CAAC;CACnB,MAAM,IAAI,OAAO,SAAS,aAAa,KAAK,KAAK,IAAI;CACrD,OAAO,UAAU,IAAI,CAAC,CAAgB,IAAK;AAC7C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/features/snap/lazySession.ts
|
|
2
|
+
/** A session of `dep` that begins on its first `at` or `angle`, so a press
|
|
3
|
+
* that never moves reads nothing of the scene. Null without a dep. */
|
|
4
|
+
function lazySnapSession(dep, req) {
|
|
5
|
+
if (!dep) return null;
|
|
6
|
+
let begun = null;
|
|
7
|
+
const session = () => begun ??= dep.begin(req);
|
|
8
|
+
return {
|
|
9
|
+
at: (p, mods) => session().at(p, mods),
|
|
10
|
+
angle: (theta, mods) => session().angle(theta, mods),
|
|
11
|
+
end: () => begun?.end()
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { lazySnapSession };
|
|
17
|
+
//# sourceMappingURL=lazySession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazySession.js","names":[],"sources":["../../../src/features/snap/lazySession.ts"],"sourcesContent":["import type { SnapBegin, SnapDep, SnapSession } from 'interactions/actions/snapDep';\n\n/** A session of `dep` that begins on its first `at` or `angle`, so a press\n * that never moves reads nothing of the scene. Null without a dep. */\nexport function lazySnapSession(dep: SnapDep | undefined, req: SnapBegin): SnapSession | null {\n if (!dep) return null;\n let begun: SnapSession | null = null;\n const session = () => (begun ??= dep.begin(req));\n return {\n at: (p, mods) => session().at(p, mods),\n angle: (theta, mods) => session().angle(theta, mods),\n end: () => begun?.end(),\n };\n}\n"],"mappings":";;;AAIA,SAAgB,gBAAgB,KAA0B,KAAoC;CAC5F,IAAI,CAAC,KAAK,OAAO;CACjB,IAAI,QAA4B;CAChC,MAAM,gBAAiB,UAAU,IAAI,MAAM,GAAG;CAC9C,OAAO;EACL,KAAK,GAAG,SAAS,QAAQ,CAAC,CAAC,GAAG,GAAG,IAAI;EACrC,QAAQ,OAAO,SAAS,QAAQ,CAAC,CAAC,MAAM,OAAO,IAAI;EACnD,WAAW,OAAO,IAAI;CACxB;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marks.js","names":[],"sources":["../../../src/features/snap/marks.ts"],"sourcesContent":["import { fromPlane, type PlaneMap } from 'core/viewport/parallax';\nimport type { SnapMark } from './types';\n\ntype Point = { x: number; y: number };\n\n/** `marks` with repeats dropped, so a target several probes meet is drawn once. */\nexport function distinct<P>(marks: readonly SnapMark<P>[]): SnapMark<P>[] {\n const seen = new Set<string>();\n return marks.filter((m) => {\n const key = JSON.stringify(m);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** `m` carried out of a plane into the camera's world, where the readout draws. */\nexport function markFromPlane(m: SnapMark, plane: PlaneMap): SnapMark {\n const pt = (p: Point) => fromPlane(plane, p);\n return m.kind === 'point' ? { ...m, at: pt(m.at) } : { ...m, from: pt(m.from), to: pt(m.to) };\n}\n"],"mappings":";;;;AAMA,SAAgB,SAAY,OAA8C;
|
|
1
|
+
{"version":3,"file":"marks.js","names":[],"sources":["../../../src/features/snap/marks.ts"],"sourcesContent":["import { fromPlane, type PlaneMap } from 'core/viewport/parallax';\nimport type { SnapMark } from './types';\n\ntype Point = { x: number; y: number };\n\n/** `marks` with repeats dropped, so a target several probes meet is drawn once. */\nexport function distinct<P>(marks: readonly SnapMark<P>[]): SnapMark<P>[] {\n // A string key keeps this linear: comparing every pair field by field more\n // than doubled a crowded row's frame time (culling.test.ts, 2026-10-18).\n const seen = new Set<string>();\n return marks.filter((m) => {\n const key = JSON.stringify(m);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** `m` carried out of a plane into the camera's world, where the readout draws. */\nexport function markFromPlane(m: SnapMark, plane: PlaneMap): SnapMark {\n const pt = (p: Point) => fromPlane(plane, p);\n return m.kind === 'point' ? { ...m, at: pt(m.at) } : { ...m, from: pt(m.from), to: pt(m.to) };\n}\n"],"mappings":";;;;AAMA,SAAgB,SAAY,OAA8C;CAGxE,MAAM,uBAAO,IAAI,IAAY;CAC7B,OAAO,MAAM,QAAQ,MAAM;EACzB,MAAM,MAAM,KAAK,UAAU,CAAC;EAC5B,IAAI,KAAK,IAAI,GAAG,GAAG,OAAO;EAC1B,KAAK,IAAI,GAAG;EACZ,OAAO;CACT,CAAC;AACH;;AAGA,SAAgB,cAAc,GAAa,OAA2B;CACpE,MAAM,MAAM,MAAa,UAAU,OAAO,CAAC;CAC3C,OAAO,EAAE,SAAS,UAAU;EAAE,GAAG;EAAG,IAAI,GAAG,EAAE,EAAE;CAAE,IAAI;EAAE,GAAG;EAAG,MAAM,GAAG,EAAE,IAAI;EAAG,IAAI,GAAG,EAAE,EAAE;CAAE;AAC9F"}
|
|
@@ -11,16 +11,28 @@ function subjectBox(ids, reads) {
|
|
|
11
11
|
}
|
|
12
12
|
return unionBounds(boxes);
|
|
13
13
|
}
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
/** The subject of `req`, null where the gesture has none or nothing is left. */
|
|
15
|
+
function subjectOf(req, reads) {
|
|
16
|
+
if (req.gesture === "move") return {
|
|
17
|
+
box: subjectBox(req.ids ?? [], reads),
|
|
18
|
+
resize: null
|
|
19
|
+
};
|
|
20
|
+
if (req.gesture !== "resize" || !req.handle) return {
|
|
21
|
+
box: null,
|
|
22
|
+
resize: null
|
|
23
|
+
};
|
|
24
|
+
if (req.box) return {
|
|
25
|
+
box: null,
|
|
26
|
+
resize: resizeSubject(req.box, req.handle)
|
|
27
|
+
};
|
|
19
28
|
const bounds = subjectBox(req.ids ?? [], reads);
|
|
20
|
-
return
|
|
29
|
+
return {
|
|
30
|
+
box: null,
|
|
31
|
+
resize: bounds ? resizeSubject({ bounds }, req.handle) : null
|
|
32
|
+
};
|
|
21
33
|
}
|
|
22
34
|
/** The probes a gesture snaps, where they are at press. */
|
|
23
|
-
function buildProbes(req, reads) {
|
|
35
|
+
function buildProbes(req, reads, subject = subjectOf(req, reads)) {
|
|
24
36
|
const ids = req.ids ?? [];
|
|
25
37
|
switch (req.gesture) {
|
|
26
38
|
case "point": return [{
|
|
@@ -28,20 +40,17 @@ function buildProbes(req, reads) {
|
|
|
28
40
|
at: req.press,
|
|
29
41
|
role: "pointer"
|
|
30
42
|
}];
|
|
31
|
-
case "resize": {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}];
|
|
38
|
-
}
|
|
39
|
-
case "move": return moveProbes(req.press, ids, reads);
|
|
43
|
+
case "resize": return subject.resize ? resizeProbes(subject.resize) : [{
|
|
44
|
+
id: "pointer",
|
|
45
|
+
at: req.press,
|
|
46
|
+
role: "pointer"
|
|
47
|
+
}];
|
|
48
|
+
case "move": return moveProbes(req.press, ids, reads, subject.box);
|
|
40
49
|
case "rotate":
|
|
41
50
|
case "handle": return [];
|
|
42
51
|
}
|
|
43
52
|
}
|
|
44
|
-
function moveProbes(press, ids, reads) {
|
|
53
|
+
function moveProbes(press, ids, reads, box) {
|
|
45
54
|
const out = [];
|
|
46
55
|
for (const id of ids) {
|
|
47
56
|
const pose = reads.pose(id);
|
|
@@ -51,7 +60,6 @@ function moveProbes(press, ids, reads) {
|
|
|
51
60
|
role: "origin"
|
|
52
61
|
});
|
|
53
62
|
}
|
|
54
|
-
const box = subjectBox(ids, reads);
|
|
55
63
|
if (box) out.push({
|
|
56
64
|
id: "box.min",
|
|
57
65
|
at: {
|
|
@@ -87,5 +95,5 @@ function moveProbes(press, ids, reads) {
|
|
|
87
95
|
}
|
|
88
96
|
|
|
89
97
|
//#endregion
|
|
90
|
-
export { buildProbes,
|
|
98
|
+
export { buildProbes, subjectBox, subjectOf };
|
|
91
99
|
//# sourceMappingURL=probes2d.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"probes2d.js","names":[],"sources":["../../../src/features/snap/probes2d.ts"],"sourcesContent":["import { unionBounds } from 'core/geometry/unionBounds';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { SnapBegin } from 'interactions/actions/snapDep';\nimport type { SnapProbeAt } from './types';\nimport { resizeProbes, resizeSubject, type ResizeSubject } from './resizeBox';\n\ntype Point = { x: number; y: number };\n\n/** How a 2D session reads its subject at press. */\nexport interface ProbeReads {\n /** `id`'s world pose now, or undefined when it is gone. */\n pose(id: string): unknown;\n /** The axis-aligned box `id` is drawn with at `pose`, stroke included. */\n drawnBox(id: string, pose: unknown): Bounds;\n /** The point of `pose` a grid rounds: its `OriginProjection` origin. */\n origin(pose: unknown): Point;\n /** The point of the subject's own geometry nearest `press`, or null. */\n geometryAt?(press: Point, ids: readonly string[]): Point | null;\n}\n\n/** The union drawn box of the subjects, or null when none is left. */\nexport function subjectBox(ids: readonly string[], reads: ProbeReads): Bounds | null {\n const boxes: Bounds[] = [];\n for (const id of ids) {\n const pose = reads.pose(id);\n if (pose !== undefined) boxes.push(reads.drawnBox(id, pose));\n }\n return unionBounds(boxes);\n}\n\n/** A resize's box and frame: the one it names, else the subjects' drawn
|
|
1
|
+
{"version":3,"file":"probes2d.js","names":[],"sources":["../../../src/features/snap/probes2d.ts"],"sourcesContent":["import { unionBounds } from 'core/geometry/unionBounds';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { SnapBegin } from 'interactions/actions/snapDep';\nimport type { SnapProbeAt } from './types';\nimport { resizeProbes, resizeSubject, type ResizeSubject } from './resizeBox';\n\ntype Point = { x: number; y: number };\n\n/** How a 2D session reads its subject at press. */\nexport interface ProbeReads {\n /** `id`'s world pose now, or undefined when it is gone. */\n pose(id: string): unknown;\n /** The axis-aligned box `id` is drawn with at `pose`, stroke included. */\n drawnBox(id: string, pose: unknown): Bounds;\n /** The point of `pose` a grid rounds: its `OriginProjection` origin. */\n origin(pose: unknown): Point;\n /** The point of the subject's own geometry nearest `press`, or null. */\n geometryAt?(press: Point, ids: readonly string[]): Point | null;\n}\n\n/** The union drawn box of the subjects, or null when none is left. */\nexport function subjectBox(ids: readonly string[], reads: ProbeReads): Bounds | null {\n const boxes: Bounds[] = [];\n for (const id of ids) {\n const pose = reads.pose(id);\n if (pose !== undefined) boxes.push(reads.drawnBox(id, pose));\n }\n return unionBounds(boxes);\n}\n\n/** What a gesture drags, read once at press. */\nexport interface Subject2d {\n /** A move's subjects' union drawn box. */\n box: Bounds | null;\n /** A resize's box and frame: the one it names, else the subjects' drawn\n * box, axis-aligned. */\n resize: ResizeSubject | null;\n}\n\n/** The subject of `req`, null where the gesture has none or nothing is left. */\nexport function subjectOf(req: SnapBegin, reads: ProbeReads): Subject2d {\n if (req.gesture === 'move') return { box: subjectBox(req.ids ?? [], reads), resize: null };\n if (req.gesture !== 'resize' || !req.handle) return { box: null, resize: null };\n if (req.box) return { box: null, resize: resizeSubject(req.box, req.handle) };\n const bounds = subjectBox(req.ids ?? [], reads);\n return { box: null, resize: bounds ? resizeSubject({ bounds }, req.handle) : null };\n}\n\n/** The probes a gesture snaps, where they are at press. */\nexport function buildProbes(req: SnapBegin, reads: ProbeReads, subject = subjectOf(req, reads)): SnapProbeAt[] {\n const ids = req.ids ?? [];\n switch (req.gesture) {\n case 'point':\n return [{ id: 'pointer', at: req.press, role: 'pointer' }];\n case 'resize':\n return subject.resize ? resizeProbes(subject.resize) : [{ id: 'pointer', at: req.press, role: 'pointer' }];\n case 'move':\n return moveProbes(req.press, ids, reads, subject.box);\n case 'rotate':\n case 'handle':\n return [];\n }\n}\n\nfunction moveProbes(press: Point, ids: readonly string[], reads: ProbeReads, box: Bounds | null): SnapProbeAt[] {\n const out: SnapProbeAt[] = [];\n for (const id of ids) {\n const pose = reads.pose(id);\n if (pose !== undefined) out.push({ id: `origin:${id}`, at: reads.origin(pose), role: 'origin' });\n }\n if (box) {\n out.push(\n { id: 'box.min', at: { x: box.x, y: box.y }, role: 'box' },\n { id: 'box.center', at: { x: box.x + box.width / 2, y: box.y + box.height / 2 }, role: 'box' },\n { id: 'box.max', at: { x: box.x + box.width, y: box.y + box.height }, role: 'box' },\n );\n }\n const geometry = reads.geometryAt?.(press, ids) ?? press;\n out.push({ id: 'geometry', at: { x: geometry.x, y: geometry.y }, role: 'geometry' });\n return out;\n}\n"],"mappings":";;;;;AAqBA,SAAgB,WAAW,KAAwB,OAAkC;CACnF,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,OAAO,MAAM,KAAK,EAAE;EAC1B,IAAI,SAAS,QAAW,MAAM,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC;CAC7D;CACA,OAAO,YAAY,KAAK;AAC1B;;AAYA,SAAgB,UAAU,KAAgB,OAA8B;CACtE,IAAI,IAAI,YAAY,QAAQ,OAAO;EAAE,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,KAAK;EAAG,QAAQ;CAAK;CACzF,IAAI,IAAI,YAAY,YAAY,CAAC,IAAI,QAAQ,OAAO;EAAE,KAAK;EAAM,QAAQ;CAAK;CAC9E,IAAI,IAAI,KAAK,OAAO;EAAE,KAAK;EAAM,QAAQ,cAAc,IAAI,KAAK,IAAI,MAAM;CAAE;CAC5E,MAAM,SAAS,WAAW,IAAI,OAAO,CAAC,GAAG,KAAK;CAC9C,OAAO;EAAE,KAAK;EAAM,QAAQ,SAAS,cAAc,EAAE,OAAO,GAAG,IAAI,MAAM,IAAI;CAAK;AACpF;;AAGA,SAAgB,YAAY,KAAgB,OAAmB,UAAU,UAAU,KAAK,KAAK,GAAkB;CAC7G,MAAM,MAAM,IAAI,OAAO,CAAC;CACxB,QAAQ,IAAI,SAAZ;EACE,KAAK,SACH,OAAO,CAAC;GAAE,IAAI;GAAW,IAAI,IAAI;GAAO,MAAM;EAAU,CAAC;EAC3D,KAAK,UACH,OAAO,QAAQ,SAAS,aAAa,QAAQ,MAAM,IAAI,CAAC;GAAE,IAAI;GAAW,IAAI,IAAI;GAAO,MAAM;EAAU,CAAC;EAC3G,KAAK,QACH,OAAO,WAAW,IAAI,OAAO,KAAK,OAAO,QAAQ,GAAG;EACtD,KAAK;EACL,KAAK,UACH,OAAO,CAAC;CACZ;AACF;AAEA,SAAS,WAAW,OAAc,KAAwB,OAAmB,KAAmC;CAC9G,MAAM,MAAqB,CAAC;CAC5B,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,OAAO,MAAM,KAAK,EAAE;EAC1B,IAAI,SAAS,QAAW,IAAI,KAAK;GAAE,IAAI,UAAU;GAAM,IAAI,MAAM,OAAO,IAAI;GAAG,MAAM;EAAS,CAAC;CACjG;CACA,IAAI,KACF,IAAI,KACF;EAAE,IAAI;EAAW,IAAI;GAAE,GAAG,IAAI;GAAG,GAAG,IAAI;EAAE;EAAG,MAAM;CAAM,GACzD;EAAE,IAAI;EAAc,IAAI;GAAE,GAAG,IAAI,IAAI,IAAI,QAAQ;GAAG,GAAG,IAAI,IAAI,IAAI,SAAS;EAAE;EAAG,MAAM;CAAM,GAC7F;EAAE,IAAI;EAAW,IAAI;GAAE,GAAG,IAAI,IAAI,IAAI;GAAO,GAAG,IAAI,IAAI,IAAI;EAAO;EAAG,MAAM;CAAM,CACpF;CAEF,MAAM,WAAW,MAAM,aAAa,OAAO,GAAG,KAAK;CACnD,IAAI,KAAK;EAAE,IAAI;EAAY,IAAI;GAAE,GAAG,SAAS;GAAG,GAAG,SAAS;EAAE;EAAG,MAAM;CAAW,CAAC;CACnF,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readoutLayer.js","names":[],"sources":["../../../src/features/snap/readoutLayer.ts"],"sourcesContent":["/** The one layer that draws what a snap won: every mark in the outcome store. */\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { RenderLayer } from 'core/layers/render';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\nimport type { SnapOutcomeStore } from './outcomeStore';\nimport { glyphCommands, measuredSegmentCommands } from './readoutDraw';\
|
|
1
|
+
{"version":3,"file":"readoutLayer.js","names":[],"sources":["../../../src/features/snap/readoutLayer.ts"],"sourcesContent":["/** The one layer that draws what a snap won: every mark in the outcome store. */\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { RenderLayer } from 'core/layers/render';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\nimport type { SnapOutcomeStore } from './outcomeStore';\nimport { glyphCommands, measuredSegmentCommands } from './readoutDraw';\nimport type { SnapReadoutStyle } from './types';\n\nconst TICK = 6;\n\n/** A screen-space layer drawing the marks in `store`, redrawn when they change. */\nexport function createSnapReadoutLayer(\n store: SnapOutcomeStore,\n style: SnapReadoutStyle = {},\n): RenderLayer<unknown> {\n const color = style.color ?? '#e8742c';\n const gapColor = style.gapColor ?? '#3aa0ff';\n const width = style.lineWidth ?? 1;\n const strokeOf = (c: string) => ({ paint: { kind: 'solid' as const, color: c }, width });\n return {\n id: 'snap-readout',\n label: 'Snap readout',\n space: 'screen',\n alwaysOn: true,\n subscribe: (repaint) => store.subscribe(repaint),\n draw: (_data, view) => {\n const marks = store.get();\n if (marks.length === 0) return [];\n const t = viewToTransform(view);\n const out: DrawCommand[] = [];\n for (const m of marks) {\n const measured = m.kind === 'gap' || m.kind === 'distance';\n const c = m.color ?? (measured ? gapColor : color);\n if (m.kind === 'point') {\n const [x, y] = worldToScreen(m.at.x, m.at.y, t);\n out.push(...glyphCommands(m.glyph, x, y, m.label, c));\n continue;\n }\n const [x0, y0] = worldToScreen(m.from.x, m.from.y, t);\n const [x1, y1] = worldToScreen(m.to.x, m.to.y, t);\n out.push(...measuredSegmentCommands(\n x0, y0, x1, y1, measured ? TICK : 0, strokeOf(c), measured ? String(Math.round(m.value)) : null, c,\n ));\n }\n return out;\n },\n };\n}\n"],"mappings":";;;;;AASA,IAAM,OAAO;;AAGb,SAAgB,uBACd,OACA,QAA0B,CAAC,GACL;CACtB,MAAM,QAAQ,MAAM,SAAS;CAC7B,MAAM,WAAW,MAAM,YAAY;CACnC,MAAM,QAAQ,MAAM,aAAa;CACjC,MAAM,YAAY,OAAe;EAAE,OAAO;GAAE,MAAM;GAAkB,OAAO;EAAE;EAAG;CAAM;CACtF,OAAO;EACL,IAAI;EACJ,OAAO;EACP,OAAO;EACP,UAAU;EACV,YAAY,YAAY,MAAM,UAAU,OAAO;EAC/C,OAAO,OAAO,SAAS;GACrB,MAAM,QAAQ,MAAM,IAAI;GACxB,IAAI,MAAM,WAAW,GAAG,OAAO,CAAC;GAChC,MAAM,IAAI,gBAAgB,IAAI;GAC9B,MAAM,MAAqB,CAAC;GAC5B,KAAK,MAAM,KAAK,OAAO;IACrB,MAAM,WAAW,EAAE,SAAS,SAAS,EAAE,SAAS;IAChD,MAAM,IAAI,EAAE,UAAU,WAAW,WAAW;IAC5C,IAAI,EAAE,SAAS,SAAS;KACtB,MAAM,CAAC,GAAG,KAAK,cAAc,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;KAC9C,IAAI,KAAK,GAAG,cAAc,EAAE,OAAO,GAAG,GAAG,EAAE,OAAO,CAAC,CAAC;KACpD;IACF;IACA,MAAM,CAAC,IAAI,MAAM,cAAc,EAAE,KAAK,GAAG,EAAE,KAAK,GAAG,CAAC;IACpD,MAAM,CAAC,IAAI,MAAM,cAAc,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;IAChD,IAAI,KAAK,GAAG,wBACV,IAAI,IAAI,IAAI,IAAI,WAAW,OAAO,GAAG,SAAS,CAAC,GAAG,WAAW,OAAO,KAAK,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CACnG,CAAC;GACH;GACA,OAAO;EACT;CACF;AACF"}
|
|
@@ -15,7 +15,8 @@ var SNAP_ROLES = {
|
|
|
15
15
|
/** The angle step `snap.constrain` (Shift) holds a direction to: a line, a
|
|
16
16
|
* measurement, a rotate, a symmetry axis. 15 degrees. */
|
|
17
17
|
var SNAP_ANGLE_STEP = Math.PI / 12;
|
|
18
|
-
/** The step an `'axis'` lock holds a move
|
|
18
|
+
/** The step an `'axis'` lock holds a move or an anchor drag to, and Shift a
|
|
19
|
+
* pen handle: the axes and the diagonals. */
|
|
19
20
|
var SNAP_AXIS_STEP = Math.PI / 4;
|
|
20
21
|
var held = roleReader(SNAP_ROLES);
|
|
21
22
|
/** The snap roles `ctx` holds. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roles.js","names":[],"sources":["../../../src/features/snap/roles.ts"],"sourcesContent":["import { roleReader, type ModifierState } from '@weasel-js/routing';\nimport type { SnapMods } from 'interactions/actions/snapDep';\n\n/** The modifier roles a snapping action declares. */\nexport const SNAP_ROLES = {\n 'snap.suspend': { label: 'Suspend snapping', keys: ['ctrl'] },\n 'snap.constrain': { label: 'Constrain', keys: ['shift'] },\n} as const;\n\n/** The angle step `snap.constrain` (Shift) holds a direction to: a line, a\n * measurement, a rotate, a symmetry axis. 15 degrees. */\nexport const SNAP_ANGLE_STEP = Math.PI / 12;\n\n/** The step an `'axis'` lock holds a move to: the axes and the diagonals. */\nexport const SNAP_AXIS_STEP = Math.PI / 4;\n\nconst held = roleReader(SNAP_ROLES);\n\n/** The snap roles `ctx` holds. */\nexport function snapMods(ctx: { roles?: Readonly<Record<string, boolean>>; modifiers: ModifierState }): SnapMods {\n return { suspend: held(ctx, 'snap.suspend'), constrain: held(ctx, 'snap.constrain') };\n}\n"],"mappings":";;;;AAIA,IAAa,aAAa;CACxB,gBAAgB;EAAE,OAAO;EAAoB,MAAM,CAAC,MAAM;CAAE;CAC5D,kBAAkB;EAAE,OAAO;EAAa,MAAM,CAAC,OAAO;CAAE;AAC1D;;;AAIA,IAAa,kBAAkB,KAAK,KAAK
|
|
1
|
+
{"version":3,"file":"roles.js","names":[],"sources":["../../../src/features/snap/roles.ts"],"sourcesContent":["import { roleReader, type ModifierRoles, type ModifierState } from '@weasel-js/routing';\nimport type { SnapMods } from 'interactions/actions/snapDep';\n\n/** The modifier roles a snapping action declares. */\nexport const SNAP_ROLES = {\n 'snap.suspend': { label: 'Suspend snapping', keys: ['ctrl'] },\n 'snap.constrain': { label: 'Constrain', keys: ['shift'] },\n} as const satisfies ModifierRoles;\n\n/** The angle step `snap.constrain` (Shift) holds a direction to: a line, a\n * measurement, a rotate, a symmetry axis. 15 degrees. */\nexport const SNAP_ANGLE_STEP = Math.PI / 12;\n\n/** The step an `'axis'` lock holds a move or an anchor drag to, and Shift a\n * pen handle: the axes and the diagonals. */\nexport const SNAP_AXIS_STEP = Math.PI / 4;\n\nconst held = roleReader(SNAP_ROLES);\n\n/** The snap roles `ctx` holds. */\nexport function snapMods(ctx: { roles?: Readonly<Record<string, boolean>>; modifiers: ModifierState }): SnapMods {\n return { suspend: held(ctx, 'snap.suspend'), constrain: held(ctx, 'snap.constrain') };\n}\n"],"mappings":";;;;AAIA,IAAa,aAAa;CACxB,gBAAgB;EAAE,OAAO;EAAoB,MAAM,CAAC,MAAM;CAAE;CAC5D,kBAAkB;EAAE,OAAO;EAAa,MAAM,CAAC,OAAO;CAAE;AAC1D;;;AAIA,IAAa,kBAAkB,KAAK,KAAK;;;AAIzC,IAAa,iBAAiB,KAAK,KAAK;AAExC,IAAM,OAAO,WAAW,UAAU;;AAGlC,SAAgB,SAAS,KAAwF;CAC/G,OAAO;EAAE,SAAS,KAAK,KAAK,cAAc;EAAG,WAAW,KAAK,KAAK,gBAAgB;CAAE;AACtF"}
|
|
@@ -6,6 +6,30 @@ var QUARTER = Math.PI / 2;
|
|
|
6
6
|
* Every `<SceneCanvas>` asks it, under the id `'rotation'`.
|
|
7
7
|
*/
|
|
8
8
|
function rotationSnapSource() {
|
|
9
|
+
let cached = null;
|
|
10
|
+
const nodeAngles = (q) => {
|
|
11
|
+
const { scene, rotationOf } = q;
|
|
12
|
+
if (!scene || !rotationOf) return [];
|
|
13
|
+
const key = [
|
|
14
|
+
scene,
|
|
15
|
+
scene.getVersion(),
|
|
16
|
+
rotationOf,
|
|
17
|
+
q.exclude
|
|
18
|
+
];
|
|
19
|
+
if (cached && key.every((k, i) => k === cached.key[i])) return cached.angles;
|
|
20
|
+
const exclude = new Set(q.exclude);
|
|
21
|
+
const angles = [];
|
|
22
|
+
for (const id of scene.nodes.keys()) {
|
|
23
|
+
if (exclude.has(id) || scene.isHidden(id)) continue;
|
|
24
|
+
const angle = rotationOf(id);
|
|
25
|
+
if (angle !== void 0 && Number.isFinite(angle)) angles.push(angle);
|
|
26
|
+
}
|
|
27
|
+
cached = {
|
|
28
|
+
key,
|
|
29
|
+
angles
|
|
30
|
+
};
|
|
31
|
+
return angles;
|
|
32
|
+
};
|
|
9
33
|
return {
|
|
10
34
|
id: "rotation",
|
|
11
35
|
roles: [],
|
|
@@ -13,14 +37,7 @@ function rotationSnapSource() {
|
|
|
13
37
|
collect: () => [],
|
|
14
38
|
*angles(q) {
|
|
15
39
|
for (let k = 0; k < 4; k++) yield { angle: k * QUARTER };
|
|
16
|
-
const
|
|
17
|
-
if (!scene || !rotationOf) return;
|
|
18
|
-
const exclude = new Set(q.exclude);
|
|
19
|
-
for (const id of scene.nodes.keys()) {
|
|
20
|
-
if (exclude.has(id) || scene.isHidden(id)) continue;
|
|
21
|
-
const angle = rotationOf(id);
|
|
22
|
-
if (angle !== void 0 && Number.isFinite(angle)) yield { angle };
|
|
23
|
-
}
|
|
40
|
+
for (const angle of nodeAngles(q)) yield { angle };
|
|
24
41
|
}
|
|
25
42
|
};
|
|
26
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rotationSource.js","names":[],"sources":["../../../src/features/snap/rotationSource.ts"],"sourcesContent":["import type { NodeId } from 'core/scene/types';\nimport type { AngleCandidate, SnapSource } from './types';\n\nconst QUARTER = Math.PI / 2;\n\n/**\n * A rotate's angle targets: every quarter turn, and the world rotation of\n * every other visible node that can turn. Shift's step is the rotate's own.\n * Every `<SceneCanvas>` asks it, under the id `'rotation'`.\n */\nexport function rotationSnapSource(): SnapSource {\n
|
|
1
|
+
{"version":3,"file":"rotationSource.js","names":[],"sources":["../../../src/features/snap/rotationSource.ts"],"sourcesContent":["import type { NodeId } from 'core/scene/types';\nimport type { AngleCandidate, AngleCollect, SnapSource } from './types';\n\nconst QUARTER = Math.PI / 2;\n\n/**\n * A rotate's angle targets: every quarter turn, and the world rotation of\n * every other visible node that can turn. Shift's step is the rotate's own.\n * Every `<SceneCanvas>` asks it, under the id `'rotation'`.\n */\nexport function rotationSnapSource(): SnapSource {\n let cached: { key: readonly unknown[]; angles: number[] } | null = null;\n const nodeAngles = (q: AngleCollect): readonly number[] => {\n const { scene, rotationOf } = q;\n if (!scene || !rotationOf) return [];\n const key = [scene, scene.getVersion(), rotationOf, q.exclude];\n if (cached && key.every((k, i) => k === cached!.key[i])) return cached.angles;\n const exclude = new Set(q.exclude);\n const angles: number[] = [];\n for (const id of scene.nodes.keys()) {\n if (exclude.has(id) || scene.isHidden(id as NodeId)) continue;\n const angle = rotationOf(id);\n if (angle !== undefined && Number.isFinite(angle)) angles.push(angle);\n }\n cached = { key, angles };\n return angles;\n };\n return {\n id: 'rotation',\n roles: [],\n gestures: ['rotate'],\n collect: () => [],\n *angles(q): Iterable<AngleCandidate> {\n for (let k = 0; k < 4; k++) yield { angle: k * QUARTER };\n for (const angle of nodeAngles(q)) yield { angle };\n },\n };\n}\n"],"mappings":";AAGA,IAAM,UAAU,KAAK,KAAK;;;;;;AAO1B,SAAgB,qBAAiC;CAC/C,IAAI,SAA+D;CACnE,MAAM,cAAc,MAAuC;EACzD,MAAM,EAAE,OAAO,eAAe;EAC9B,IAAI,CAAC,SAAS,CAAC,YAAY,OAAO,CAAC;EACnC,MAAM,MAAM;GAAC;GAAO,MAAM,WAAW;GAAG;GAAY,EAAE;EAAO;EAC7D,IAAI,UAAU,IAAI,OAAO,GAAG,MAAM,MAAM,OAAQ,IAAI,EAAE,GAAG,OAAO,OAAO;EACvE,MAAM,UAAU,IAAI,IAAI,EAAE,OAAO;EACjC,MAAM,SAAmB,CAAC;EAC1B,KAAK,MAAM,MAAM,MAAM,MAAM,KAAK,GAAG;GACnC,IAAI,QAAQ,IAAI,EAAE,KAAK,MAAM,SAAS,EAAY,GAAG;GACrD,MAAM,QAAQ,WAAW,EAAE;GAC3B,IAAI,UAAU,UAAa,OAAO,SAAS,KAAK,GAAG,OAAO,KAAK,KAAK;EACtE;EACA,SAAS;GAAE;GAAK;EAAO;EACvB,OAAO;CACT;CACA,OAAO;EACL,IAAI;EACJ,OAAO,CAAC;EACR,UAAU,CAAC,QAAQ;EACnB,eAAe,CAAC;EAChB,CAAC,OAAO,GAA6B;GACnC,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,MAAM,EAAE,OAAO,IAAI,QAAQ;GACvD,KAAK,MAAM,SAAS,WAAW,CAAC,GAAG,MAAM,EAAE,MAAM;EACnD;CACF;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { drawnBoxes } from "../../interactions/actions/drawnBoxes.js";
|
|
2
2
|
import { createSnapOutcomeStore } from "./outcomeStore.js";
|
|
3
3
|
import { DEFAULT_SNAP_PX, createSession2d } from "./session2d.js";
|
|
4
|
-
import { buildProbes,
|
|
4
|
+
import { buildProbes, subjectOf } from "./probes2d.js";
|
|
5
5
|
import { sceneProbeReads, sceneRotations, withSubtrees } from "./sceneReads.js";
|
|
6
6
|
|
|
7
7
|
//#region src/features/snap/sceneSession2d.ts
|
|
@@ -13,12 +13,13 @@ function sceneSession2d(i) {
|
|
|
13
13
|
...i.geometryAt ? { geometryAt: i.geometryAt } : {},
|
|
14
14
|
...i.originProjection ? { originProjection: i.originProjection } : {}
|
|
15
15
|
});
|
|
16
|
+
const subject = subjectOf(i.req, reads);
|
|
16
17
|
return createSession2d({
|
|
17
18
|
req: i.req,
|
|
18
19
|
sources: i.sources,
|
|
19
|
-
probes: buildProbes(i.req, reads),
|
|
20
|
-
box:
|
|
21
|
-
resize:
|
|
20
|
+
probes: buildProbes(i.req, reads, subject),
|
|
21
|
+
box: subject.box,
|
|
22
|
+
resize: subject.resize,
|
|
22
23
|
drawnBox: (id) => {
|
|
23
24
|
const pose = reads.pose(id);
|
|
24
25
|
return pose === void 0 ? void 0 : reads.drawnBox(id, pose);
|
|
@@ -45,6 +46,7 @@ function createSnapSession2d(opts) {
|
|
|
45
46
|
gesture: opts.gesture,
|
|
46
47
|
press: opts.press,
|
|
47
48
|
...opts.ids ? { ids: opts.ids } : {},
|
|
49
|
+
...opts.parent !== void 0 ? { parent: opts.parent } : {},
|
|
48
50
|
...opts.origin ? { origin: opts.origin } : {},
|
|
49
51
|
...opts.constrain ? { constrain: opts.constrain } : {},
|
|
50
52
|
...opts.handle ? { handle: opts.handle } : {},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sceneSession2d.js","names":[],"sources":["../../../src/features/snap/sceneSession2d.ts"],"sourcesContent":["import type { ResizeAnchor } from '@weasel-js/routing';\nimport type { View } from '@weasel-js/geom';\nimport type { DebugSink } from '@weasel-js/routing';\nimport type { PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport type { Scene } from 'core/scene/types';\nimport type { PlaneMap } from 'core/viewport/parallax';\nimport type { OriginProjection } from 'interactions/gestures/shared/originProjection';\nimport { drawnBoxes, type DrawnBoxes } from 'interactions/actions/drawnBoxes';\nimport type { SnapBegin, SnapConstrain, SnapGeometry, SnapResizeBox, SnapSession } from 'interactions/actions/snapDep';\nimport { createSnapOutcomeStore, type SnapOutcomeStore } from './outcomeStore';\nimport { buildProbes,
|
|
1
|
+
{"version":3,"file":"sceneSession2d.js","names":[],"sources":["../../../src/features/snap/sceneSession2d.ts"],"sourcesContent":["import type { ResizeAnchor } from '@weasel-js/routing';\nimport type { View } from '@weasel-js/geom';\nimport type { DebugSink } from '@weasel-js/routing';\nimport type { PoseDescriptor } from 'core/geometry/poseDescriptor';\nimport type { Scene } from 'core/scene/types';\nimport type { PlaneMap } from 'core/viewport/parallax';\nimport type { OriginProjection } from 'interactions/gestures/shared/originProjection';\nimport { drawnBoxes, type DrawnBoxes } from 'interactions/actions/drawnBoxes';\nimport type { SnapBegin, SnapConstrain, SnapGeometry, SnapResizeBox, SnapSession } from 'interactions/actions/snapDep';\nimport { createSnapOutcomeStore, type SnapOutcomeStore } from './outcomeStore';\nimport { buildProbes, subjectOf } from './probes2d';\nimport { sceneProbeReads, sceneRotations, withSubtrees } from './sceneReads';\nimport { createSession2d, DEFAULT_SNAP_PX } from './session2d';\nimport type { SnapGesture, SnapSource } from './types';\n\ntype Point = { x: number; y: number };\ntype AnyScene = Scene<unknown, string, unknown>;\n\n/** What a session over a scene runs on: its subject's probes and boxes come\n * from `scene`, measured through `boxes`. */\nexport interface SceneSessionInputs {\n req: SnapBegin;\n scene: AnyScene;\n boxes: DrawnBoxes;\n sources: readonly SnapSource[];\n view(): View | null;\n reachPx: number;\n store: SnapOutcomeStore;\n geometryAt?: (press: Point, ids: readonly string[]) => Point | null;\n /** How a pose's origin is read. Default `AUTO_ORIGIN_PROJECTION`. */\n originProjection?: OriginProjection<unknown>;\n /** How a node's rotation is read. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<unknown>;\n /** Where each frame's candidates are recorded. */\n debug?: DebugSink;\n}\n\n/** A 2D session whose probes are the subject's, read from the scene at press. */\nexport function sceneSession2d(i: SceneSessionInputs): SnapSession {\n const reads = sceneProbeReads({\n scene: i.scene, boxes: i.boxes,\n ...(i.geometryAt ? { geometryAt: i.geometryAt } : {}),\n ...(i.originProjection ? { originProjection: i.originProjection } : {}),\n });\n const subject = subjectOf(i.req, reads);\n return createSession2d({\n req: i.req,\n sources: i.sources,\n probes: buildProbes(i.req, reads, subject),\n box: subject.box,\n resize: subject.resize,\n drawnBox: (id) => {\n const pose = reads.pose(id);\n return pose === undefined ? undefined : reads.drawnBox(id, pose);\n },\n ...(i.req.ids ? { exclude: withSubtrees(i.scene, i.req.ids) } : {}),\n view: i.view,\n reachPx: i.reachPx,\n scene: i.scene,\n rotationOf: sceneRotations(i.scene, i.poseDescriptor),\n store: i.store,\n ...(i.debug ? { debug: i.debug } : {}),\n });\n}\n\n/** Options for {@link createSnapSession2d}. */\nexport interface SnapSession2dOptions {\n scene: AnyScene;\n /** The camera the reach is measured through. */\n view: View;\n sources: readonly SnapSource[];\n gesture: SnapGesture;\n /** World coords. */\n press: Point;\n /** The subject, whose geometry offers no targets. */\n ids?: readonly string[];\n /** The container a subject not yet in the scene lands in. */\n parent?: string;\n /** Point gestures: the previous anchor, a line's start. */\n origin?: Point;\n constrain?: SnapConstrain;\n /** Resize: the sides the drag pins. */\n handle?: ResizeAnchor;\n /** Rotate: the point the angle turns about. */\n pivot?: Point;\n /** Rotate: the subject's angle at press. */\n theta0?: number;\n /** Angle gestures: the reach as an angle, radians. */\n reachRad?: number;\n /** Resize: the box `handle` belongs to. Default: the subjects' drawn box. */\n box?: SnapResizeBox;\n also?: SnapGeometry;\n /** The reach of a source that sets none, in screen px. Default `DEFAULT_SNAP_PX`. */\n reachPx?: number;\n /** Where the session writes its marks. Default: a store of its own. */\n store?: SnapOutcomeStore;\n /** How poses are read. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<unknown>;\n /** Whether drawn boxes include the stroke. Default `true`. */\n boundsIncludeStroke?: boolean;\n /** How a pose's origin, the point a grid or a guide snaps, is read.\n * Default `AUTO_ORIGIN_PROJECTION`: a rect's `{x, y}`, a path's bounds. */\n originProjection?: OriginProjection<unknown>;\n /** How `view`'s world maps into the parallax plane the gesture's points\n * are in. Default: they are in `view`'s own world. */\n plane?: PlaneMap | null;\n}\n\n/**\n * One gesture's snapping over a scene, for a host without `<SceneCanvas>`:\n * the session a canvas's `snap` dep begins, built from the same probes and\n * drawn boxes. Call `at` with each world point the gesture reaches, and\n * `end` when it lets go.\n */\nexport function createSnapSession2d(opts: SnapSession2dOptions): SnapSession {\n const view = opts.view;\n const req: SnapBegin = {\n gesture: opts.gesture,\n press: opts.press,\n ...(opts.ids ? { ids: opts.ids } : {}),\n ...(opts.parent !== undefined ? { parent: opts.parent } : {}),\n ...(opts.origin ? { origin: opts.origin } : {}),\n ...(opts.constrain ? { constrain: opts.constrain } : {}),\n ...(opts.handle ? { handle: opts.handle } : {}),\n ...(opts.pivot ? { pivot: opts.pivot } : {}),\n ...(opts.theta0 !== undefined ? { theta0: opts.theta0 } : {}),\n ...(opts.reachRad !== undefined ? { reachRad: opts.reachRad } : {}),\n ...(opts.box ? { box: opts.box } : {}),\n ...(opts.also ? { also: opts.also } : {}),\n ...(opts.plane ? { plane: () => opts.plane ?? null } : {}),\n };\n return sceneSession2d({\n req,\n scene: opts.scene,\n boxes: drawnBoxes({\n scene: opts.scene,\n view: { get: () => view, set: () => {} },\n ...(opts.poseDescriptor ? { poseDescriptor: opts.poseDescriptor } : {}),\n ...(opts.boundsIncludeStroke !== undefined ? { boundsIncludeStroke: opts.boundsIncludeStroke } : {}),\n }),\n sources: opts.sources,\n view: () => view,\n reachPx: opts.reachPx ?? DEFAULT_SNAP_PX,\n store: opts.store ?? createSnapOutcomeStore(),\n ...(opts.originProjection ? { originProjection: opts.originProjection } : {}),\n ...(opts.poseDescriptor ? { poseDescriptor: opts.poseDescriptor } : {}),\n });\n}\n"],"mappings":";;;;;;;;AAsCA,SAAgB,eAAe,GAAoC;CACjE,MAAM,QAAQ,gBAAgB;EAC5B,OAAO,EAAE;EAAO,OAAO,EAAE;EACzB,GAAI,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,IAAI,CAAC;EACnD,GAAI,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,IAAI,CAAC;CACvE,CAAC;CACD,MAAM,UAAU,UAAU,EAAE,KAAK,KAAK;CACtC,OAAO,gBAAgB;EACrB,KAAK,EAAE;EACP,SAAS,EAAE;EACX,QAAQ,YAAY,EAAE,KAAK,OAAO,OAAO;EACzC,KAAK,QAAQ;EACb,QAAQ,QAAQ;EAChB,WAAW,OAAO;GAChB,MAAM,OAAO,MAAM,KAAK,EAAE;GAC1B,OAAO,SAAS,SAAY,SAAY,MAAM,SAAS,IAAI,IAAI;EACjE;EACA,GAAI,EAAE,IAAI,MAAM,EAAE,SAAS,aAAa,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,CAAC;EACjE,MAAM,EAAE;EACR,SAAS,EAAE;EACX,OAAO,EAAE;EACT,YAAY,eAAe,EAAE,OAAO,EAAE,cAAc;EACpD,OAAO,EAAE;EACT,GAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;CACtC,CAAC;AACH;;;;;;;AAmDA,SAAgB,oBAAoB,MAAyC;CAC3E,MAAM,OAAO,KAAK;CAgBlB,OAAO,eAAe;EACpB;GAfA,SAAS,KAAK;GACd,OAAO,KAAK;GACZ,GAAI,KAAK,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;GACpC,GAAI,KAAK,WAAW,SAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC3D,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC7C,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;GACtD,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC7C,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;GAC1C,GAAI,KAAK,WAAW,SAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC3D,GAAI,KAAK,aAAa,SAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;GACjE,GAAI,KAAK,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;GACpC,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;GACvC,GAAI,KAAK,QAAQ,EAAE,aAAa,KAAK,SAAS,KAAK,IAAI,CAAC;EAGxD;EACA,OAAO,KAAK;EACZ,OAAO,WAAW;GAChB,OAAO,KAAK;GACZ,MAAM;IAAE,WAAW;IAAM,WAAW,CAAC;GAAE;GACvC,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;GACrE,GAAI,KAAK,wBAAwB,SAAY,EAAE,qBAAqB,KAAK,oBAAoB,IAAI,CAAC;EACpG,CAAC;EACD,SAAS,KAAK;EACd,YAAY;EACZ,SAAS,KAAK,WAAW;EACzB,OAAO,KAAK,SAAS,uBAAuB;EAC5C,GAAI,KAAK,mBAAmB,EAAE,kBAAkB,KAAK,iBAAiB,IAAI,CAAC;EAC3E,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;CACvE,CAAC;AACH"}
|