@weasel-js/core 1.10.0 → 1.10.1
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 +168 -0
- package/README.md +33 -0
- package/dist/affordances/composeAffordanceLayer.js +21 -21
- package/dist/affordances/composeAffordanceLayer.js.map +1 -1
- package/dist/affordances/hitAffordanceRegions.js +48 -32
- package/dist/affordances/hitAffordanceRegions.js.map +1 -1
- package/dist/affordances/pathAnchors.js +50 -28
- package/dist/affordances/pathAnchors.js.map +1 -1
- package/dist/affordances/rotateCursor.js +12 -0
- package/dist/affordances/rotateCursor.js.map +1 -0
- package/dist/affordances/rotationHandle.js +40 -43
- package/dist/affordances/rotationHandle.js.map +1 -1
- package/dist/animation/rig/rigNode.js +9 -3
- package/dist/animation/rig/rigNode.js.map +1 -1
- package/dist/animation/rig/rigSeat.js +46 -13
- package/dist/animation/rig/rigSeat.js.map +1 -1
- package/dist/animation/rig/skinBinding.js +22 -14
- package/dist/animation/rig/skinBinding.js.map +1 -1
- package/dist/barrel/canvas.js +29 -28
- package/dist/barrel/interactions.js +33 -32
- package/dist/barrel/paths.js +11 -10
- package/dist/barrel/routing.js +49 -48
- package/dist/barrel/scene.js +10 -10
- package/dist/barrel/viewport.js +24 -21
- package/dist/canvas/Canvas.js +6 -17
- package/dist/canvas/Canvas.js.map +1 -1
- package/dist/canvas/CanvasView.js +34 -37
- package/dist/canvas/CanvasView.js.map +1 -1
- package/dist/canvas/CursorCoordsHud.js +3 -3
- package/dist/canvas/CursorCoordsHud.js.map +1 -1
- package/dist/canvas/DrawCanvas.js +3 -3
- package/dist/canvas/DrawCanvas.js.map +1 -1
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +24 -23
- package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
- package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js +40 -49
- package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js.map +1 -1
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js +297 -259
- package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
- package/dist/canvas/SceneCanvas/features.js +3 -24
- package/dist/canvas/SceneCanvas/features.js.map +1 -1
- package/dist/canvas/SceneCanvas/insertPreviewCommands.js +97 -0
- package/dist/canvas/SceneCanvas/insertPreviewCommands.js.map +1 -0
- package/dist/canvas/SceneCanvas/poseGeometry.js.map +1 -1
- package/dist/canvas/SceneCanvas/props.js.map +1 -1
- package/dist/canvas/SceneCanvas/scenePointQuery.js +50 -0
- package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -0
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +52 -0
- package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -0
- package/dist/canvas/SceneCanvas/useActionTunings.js +17 -0
- package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -0
- package/dist/canvas/SceneCanvas/useCanvasCamera.js +37 -29
- package/dist/canvas/SceneCanvas/useCanvasCamera.js.map +1 -1
- package/dist/canvas/SceneCanvas/useCanvasDispatcher.js +11 -11
- package/dist/canvas/SceneCanvas/useCanvasDispatcher.js.map +1 -1
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +45 -109
- package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +49 -41
- package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +64 -96
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas/worldPointAt.js +3 -4
- package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +77 -80
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/SceneViewCanvas.js +3 -3
- package/dist/canvas/SceneViewCanvas.js.map +1 -1
- package/dist/canvas/SurfaceCanvas.js +40 -0
- package/dist/canvas/SurfaceCanvas.js.map +1 -0
- package/dist/canvas/adapterDerivedPath.js +13 -13
- package/dist/canvas/adapterDerivedPath.js.map +1 -1
- package/dist/canvas/adapterPickSource.js +34 -0
- package/dist/canvas/adapterPickSource.js.map +1 -0
- package/dist/canvas/affordanceAt.js +1 -1
- package/dist/canvas/affordanceAt.js.map +1 -1
- package/dist/canvas/buildSceneLayer.js.map +1 -1
- package/dist/canvas/buildSceneTree.js +56 -34
- package/dist/canvas/buildSceneTree.js.map +1 -1
- package/dist/canvas/copiesAbove.js +27 -0
- package/dist/canvas/copiesAbove.js.map +1 -0
- package/dist/canvas/defaultDrawOne.js +24 -23
- package/dist/canvas/defaultDrawOne.js.map +1 -1
- package/dist/canvas/deps/editAnchors.js +45 -50
- package/dist/canvas/deps/editAnchors.js.map +1 -1
- package/dist/canvas/deps/hitTestArea.js +30 -15
- package/dist/canvas/deps/hitTestArea.js.map +1 -1
- package/dist/canvas/deps/insert.js +134 -100
- package/dist/canvas/deps/insert.js.map +1 -1
- package/dist/canvas/deps/layout.js +9 -15
- package/dist/canvas/deps/layout.js.map +1 -1
- package/dist/canvas/derivedPath.js +53 -29
- package/dist/canvas/derivedPath.js.map +1 -1
- package/dist/canvas/insertPreviewExtent.js +33 -31
- package/dist/canvas/insertPreviewExtent.js.map +1 -1
- package/dist/canvas/overChildren.js +29 -0
- package/dist/canvas/overChildren.js.map +1 -0
- package/dist/canvas/paintedCursorLayer.js.map +1 -1
- package/dist/canvas/pickReach.js +23 -0
- package/dist/canvas/pickReach.js.map +1 -0
- package/dist/canvas/pickWalk.js +51 -80
- package/dist/canvas/pickWalk.js.map +1 -1
- package/dist/canvas/sceneAdapter.js +14 -35
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/sceneSlotWiring.js +11 -10
- package/dist/canvas/sceneSlotWiring.js.map +1 -1
- package/dist/canvas/sceneViewRender.js +38 -44
- package/dist/canvas/sceneViewRender.js.map +1 -1
- package/dist/canvas/useCanvasView.js +42 -44
- package/dist/canvas/useCanvasView.js.map +1 -1
- package/dist/canvas/useSceneAdapter.js +22 -0
- package/dist/canvas/useSceneAdapter.js.map +1 -0
- package/dist/canvas/useSurfaceInput.js +13 -16
- package/dist/canvas/useSurfaceInput.js.map +1 -1
- package/dist/canvas/viewRegistry.js +31 -23
- package/dist/canvas/viewRegistry.js.map +1 -1
- package/dist/canvas/wrapNodeOutput.js +7 -2
- package/dist/canvas/wrapNodeOutput.js.map +1 -1
- package/dist/clipboard.d.ts +1 -1
- package/dist/{clone-2a5hVbBd.d.ts → clone-C0eADtS0.d.ts} +13 -13
- package/dist/clone.d.ts +2 -2
- package/dist/core/geometry/poseDescriptor.js +49 -23
- package/dist/core/geometry/poseDescriptor.js.map +1 -1
- package/dist/core/geometry/regionHit.js +2 -2
- package/dist/core/geometry/regionHit.js.map +1 -1
- package/dist/core/geometry/targetFrame.js.map +1 -1
- package/dist/core/layers/children.js +1 -3
- package/dist/core/layers/children.js.map +1 -1
- package/dist/core/ops/create.js +2 -2
- package/dist/core/ops/create.js.map +1 -1
- package/dist/core/ops/delete.js +19 -23
- package/dist/core/ops/delete.js.map +1 -1
- package/dist/core/ops/reorder/index.js +3 -7
- package/dist/core/ops/reorder/index.js.map +1 -1
- package/dist/core/ops/reorder/setChildOrder.js +2 -4
- package/dist/core/ops/reorder/setChildOrder.js.map +1 -1
- package/dist/core/ops/reparent.js +0 -1
- package/dist/core/ops/reparent.js.map +1 -1
- package/dist/core/ops/slot.js +3 -6
- package/dist/core/ops/slot.js.map +1 -1
- package/dist/core/pages/fitViewToPage.js +15 -0
- package/dist/core/pages/fitViewToPage.js.map +1 -0
- package/dist/core/pages/pages.js +65 -0
- package/dist/core/pages/pages.js.map +1 -0
- package/dist/core/pages/pagesLayer.js +27 -0
- package/dist/core/pages/pagesLayer.js.map +1 -0
- package/dist/core/paint/meshKindLazy.js +2 -2
- package/dist/core/paint/meshKindLazy.js.map +1 -1
- package/dist/core/scene/NodeProperties.js.map +1 -1
- package/dist/core/scene/composeFrame.js.map +1 -1
- package/dist/core/scene/composePose.js +58 -20
- package/dist/core/scene/composePose.js.map +1 -1
- package/dist/core/scene/effectivePose.js +5 -1
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/historyFacade.js +19 -13
- package/dist/core/scene/historyFacade.js.map +1 -1
- package/dist/core/scene/nodeFnFields.js +7 -0
- package/dist/core/scene/nodeFnFields.js.map +1 -1
- package/dist/core/scene/outerOps.js +2 -1
- package/dist/core/scene/outerOps.js.map +1 -1
- package/dist/core/scene/reconcileSpecs.js +1 -1
- package/dist/core/scene/reconcileSpecs.js.map +1 -1
- package/dist/core/scene/sceneRecording.js +2 -1
- package/dist/core/scene/sceneRecording.js.map +1 -1
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/viewport/screenSlop.js.map +1 -1
- package/dist/core/viewport/useDecayLoop.js +28 -30
- package/dist/core/viewport/useDecayLoop.js.map +1 -1
- package/dist/core/viewport/useNodeOverlayFrame.js.map +1 -1
- package/dist/core/viewport/useViewAnimation.js +70 -69
- package/dist/core/viewport/useViewAnimation.js.map +1 -1
- package/dist/core/viewport/view.js +8 -5
- package/dist/core/viewport/view.js.map +1 -1
- package/dist/core/viewport/zoomAt.js +11 -2
- package/dist/core/viewport/zoomAt.js.map +1 -1
- package/dist/{cornerHandles-BEshc4z3.d.ts → cornerHandles-BSKbyuvQ.d.ts} +1 -1
- package/dist/features/paths/editablePath.js +24 -8
- package/dist/features/paths/editablePath.js.map +1 -1
- package/dist/features/paths/index.js +4 -4
- package/dist/features/paths/shapeGenerator.js +89 -0
- package/dist/features/paths/shapeGenerator.js.map +1 -0
- package/dist/features/paths/usePathEdit.js +13 -13
- package/dist/features/poseRun/usePoseRun.js +25 -25
- package/dist/features/poseRun/usePoseRun.js.map +1 -1
- package/dist/features/text/useSceneTextEdit.js +82 -64
- package/dist/features/text/useSceneTextEdit.js.map +1 -1
- package/dist/features/viewports/viewResolver.js +28 -24
- package/dist/features/viewports/viewResolver.js.map +1 -1
- package/dist/icons/SliceIcon.js +24 -0
- package/dist/icons/SliceIcon.js.map +1 -0
- package/dist/index.d.ts +956 -581
- package/dist/index.js +260 -251
- package/dist/interactions/actions/align/align.js +9 -9
- package/dist/interactions/actions/align/align.js.map +1 -1
- package/dist/interactions/actions/booleans/booleans.js +18 -18
- package/dist/interactions/actions/booleans/booleans.js.map +1 -1
- package/dist/interactions/actions/booleans/operands.js.map +1 -1
- package/dist/interactions/actions/clone/action.js +35 -30
- package/dist/interactions/actions/clone/action.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js +56 -59
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorHandles.js +42 -0
- package/dist/interactions/actions/defaults/anchorHandles.js.map +1 -0
- package/dist/interactions/actions/defaults/anchorJoin.js +92 -0
- package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -0
- package/dist/interactions/actions/defaults/bendSegment.js +46 -0
- package/dist/interactions/actions/defaults/bendSegment.js.map +1 -0
- package/dist/interactions/actions/defaults/copySubtree.js +1 -1
- package/dist/interactions/actions/defaults/copySubtree.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js +32 -17
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/enterPathEdit.js +19 -7
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/icons/anchorIcons.js +75 -0
- package/dist/interactions/actions/defaults/icons/anchorIcons.js.map +1 -0
- package/dist/interactions/actions/defaults/icons/editIcons.js +35 -8
- package/dist/interactions/actions/defaults/icons/editIcons.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +16 -31
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
- package/dist/interactions/actions/defaults/nudge.js +28 -23
- package/dist/interactions/actions/defaults/nudge.js.map +1 -1
- package/dist/interactions/actions/defaults/pinchZoom.js +29 -29
- package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
- package/dist/interactions/actions/defaults/segmentUnder.js +22 -0
- package/dist/interactions/actions/defaults/segmentUnder.js.map +1 -0
- package/dist/interactions/actions/defaults/viewportZoom.js +82 -79
- package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
- package/dist/interactions/actions/distribute/distribute.js +8 -8
- package/dist/interactions/actions/distribute/distribute.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/action.js +58 -55
- package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
- package/dist/interactions/actions/edit-anchors/preview.js +26 -0
- package/dist/interactions/actions/edit-anchors/preview.js.map +1 -0
- package/dist/interactions/actions/edit-anchors/symmetry.js +11 -0
- package/dist/interactions/actions/edit-anchors/symmetry.js.map +1 -0
- package/dist/interactions/actions/flip/action.js.map +1 -1
- package/dist/interactions/actions/geometryProjection.js.map +1 -1
- package/dist/interactions/actions/insert/action.js +37 -30
- package/dist/interactions/actions/insert/action.js.map +1 -1
- package/dist/interactions/actions/insert/frame.js +9 -2
- package/dist/interactions/actions/insert/frame.js.map +1 -1
- package/dist/interactions/actions/insert/repositionAction.js +31 -0
- package/dist/interactions/actions/insert/repositionAction.js.map +1 -0
- package/dist/interactions/actions/lasso-select/action.js +32 -32
- package/dist/interactions/actions/move/action.js +29 -25
- package/dist/interactions/actions/move/action.js.map +1 -1
- package/dist/interactions/actions/move/behaviors/snapToContainer.js +12 -6
- package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
- package/dist/interactions/actions/move/capture.js +32 -23
- package/dist/interactions/actions/move/capture.js.map +1 -1
- package/dist/interactions/actions/move/frame.js +2 -14
- package/dist/interactions/actions/move/frame.js.map +1 -1
- package/dist/interactions/actions/move/session.js +1 -1
- package/dist/interactions/actions/move/session.js.map +1 -1
- package/dist/interactions/actions/move/translate.js.map +1 -1
- package/dist/interactions/actions/outlines/createOutlines.js.map +1 -1
- package/dist/interactions/actions/outlines/replaceWithPaths.js +13 -13
- package/dist/interactions/actions/outlines/replaceWithPaths.js.map +1 -1
- package/dist/interactions/actions/outlines/strokeRegion.js.map +1 -1
- package/dist/interactions/actions/pathCommands/cutJoin.js +102 -0
- package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -0
- package/dist/interactions/actions/pathCommands/livePathEdit.js +64 -0
- package/dist/interactions/actions/pathCommands/livePathEdit.js.map +1 -0
- package/dist/interactions/actions/pathCommands/pathNodes.js +99 -0
- package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -0
- package/dist/interactions/actions/pathCommands/simplifyOffset.js +42 -0
- package/dist/interactions/actions/pathCommands/simplifyOffset.js.map +1 -0
- package/dist/interactions/actions/resize/action.js +31 -20
- package/dist/interactions/actions/resize/action.js.map +1 -1
- package/dist/interactions/actions/resize/commit.js.map +1 -1
- package/dist/interactions/actions/resize/frame.js +29 -15
- package/dist/interactions/actions/resize/frame.js.map +1 -1
- package/dist/interactions/actions/resize/replay.js +47 -0
- package/dist/interactions/actions/resize/replay.js.map +1 -0
- package/dist/interactions/actions/resize/session.js +49 -35
- package/dist/interactions/actions/resize/session.js.map +1 -1
- package/dist/interactions/actions/resolveOverlays.js +2 -1
- package/dist/interactions/actions/resolveOverlays.js.map +1 -1
- package/dist/interactions/actions/rotate/action.js +40 -25
- package/dist/interactions/actions/rotate/action.js.map +1 -1
- package/dist/interactions/actions/rotate/frame.js +1 -1
- package/dist/interactions/actions/rotate/frame.js.map +1 -1
- package/dist/interactions/actions/rotate/replay.js +22 -0
- package/dist/interactions/actions/rotate/replay.js.map +1 -0
- package/dist/interactions/actions/rotate/session.js +42 -32
- package/dist/interactions/actions/rotate/session.js.map +1 -1
- package/dist/interactions/actions/transform-again/action.js +63 -0
- package/dist/interactions/actions/transform-again/action.js.map +1 -0
- package/dist/interactions/actions/transform-again/memory.js +35 -0
- package/dist/interactions/actions/transform-again/memory.js.map +1 -0
- package/dist/interactions/actions/useStandardActions.js +101 -83
- package/dist/interactions/actions/useStandardActions.js.map +1 -1
- package/dist/move.d.ts +4 -4
- package/dist/{originProjection-PPT88jZv.d.ts → originProjection-CoNVpITV.d.ts} +1 -1
- package/dist/resize.d.ts +3 -3
- package/dist/style.css +1 -1
- package/dist/tools/builtin/ellipse/useEllipseTool.js +16 -15
- package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
- package/dist/tools/builtin/line/useLineTool.js +16 -15
- package/dist/tools/builtin/line/useLineTool.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +111 -111
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/pickTopMostHit.js +11 -14
- package/dist/tools/builtin/pickTopMostHit.js.map +1 -1
- package/dist/tools/builtin/polygon/usePolygonTool.js +17 -15
- package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
- package/dist/tools/builtin/rect/useRectTool.js +15 -14
- package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
- package/dist/tools/builtin/select/adapterPointQuery.js +22 -18
- package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
- package/dist/tools/builtin/select/selectionContributions.js +1 -1
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js +2 -1
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/slice/useSliceTool.js +42 -40
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/tools/builtin/star/useStarTool.js +18 -16
- package/dist/tools/builtin/star/useStarTool.js.map +1 -1
- package/dist/tools/builtin/text/useTextTool.js +2 -2
- package/dist/tools/builtin/text/useTextTool.js.map +1 -1
- package/dist/{types-CIKDwlsP.d.ts → types-DBbbCy0i.d.ts} +22 -15
- package/dist/version.js +1 -1
- package/package.json +22 -22
- package/dist/canvas/surface.module.js +0 -6
- package/dist/canvas/surface.module.js.map +0 -1
- package/dist/canvas/surfaceBox.js +0 -16
- package/dist/canvas/surfaceBox.js.map +0 -1
- package/dist/layout/arrivals.js +0 -33
- package/dist/layout/arrivals.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insert.js","names":["e","paintKeys","fill","stroke","withFillRule","path","data","rule","paletteInsertPaint","color","cycleFill","seq","kind","strokeOf","solid","useInsertDepSource","sceneRef","useLatest","scene","adapterRef","adapter","factoriesRef","factories","paintRef","paint","insertSeqRef","useRef","liveRef","useDepSource","sc","ad","layer","build","extras","id","asked","painted","as","extent","insertPreviewExtent","pose","factory","built","bounds","createInsertOp","geom","linePath","regularPolygonPath","starPath","samples","schneiderFit","polygonFromPoints","rectPath","ellipsePath"],"sources":["../../../src/canvas/deps/insert.ts"],"sourcesContent":["/**\n * `useInsertDepSource` — wires the `insert` dep consumed by `insertAction`.\n *\n * `line`, `polygon`, `star`, and `pencil` receive the drag AABB from the insertAction invoker,\n * but `extras` may carry richer geometry (endpoints, center+radius+rotation, point trail).\n * `insertPreviewExtent` resolves the two into the node's real extent — the same resolution the\n * live preview and the reported gesture bounds use.\n */\nimport { useRef } from 'react';\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { InsertDep, InsertExtras, InsertLive } from 'interactions/actions/depSchema';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport type { Op } from 'core/ops/types';\nimport { createInsertOp } from 'core/ops/create';\nimport {\n rectPath,\n ellipsePath,\n regularPolygonPath,\n starPath,\n linePath,\n polygonFromPoints,\n schneiderFit,\n type PathFillRule,\n type PolygonPath,\n} from '@weasel-js/geom';\nimport { insertPreviewExtent } from '../insertPreviewExtent';\nimport type { Stroke, Fill } from '@weasel-js/paint';\nimport { cycleFill, solid, strokeOf } from '../../util/paint';\n\ninterface OpsApplier {\n applyOps(ops: Op[], label?: string): void;\n}\n\n/**\n * Consumer-supplied node factory for one insert `kind`. Given the drag AABB\n * and the tool's `extras`, returns the node's `data` (in the consumer's own\n * data shape) plus an optional `pose` override — the dep supplies id, layer,\n * and the undoable insert op. Return `null` to reject the insert.\n *\n * A factory registered for a kit kind (`rect`, `line`, …) fully replaces the\n * kit's default `{ path, fill }` factory for that kind; a factory for a novel\n * kind adds support the kit doesn't ship (e.g. `text`). To change only the\n * paint of a kit shape, pass an {@link InsertPaint}. See\n * `SceneCanvas`'s `insertNodeFactories` prop.\n */\nexport type InsertNodeFactory = (\n bounds: { x: number; y: number; width: number; height: number },\n extras: InsertExtras,\n) => { data: unknown; pose?: unknown } | null;\n\n/**\n * The paint a kit-built shape is inserted with. `kind` is the shape being\n * built and `seq` counts this canvas's inserts from 1. A key left out stays\n * off the node, so its painter's default applies; `null` is \"none\". A pencil\n * trail too short to fit is built as a rect and asks as one. A line and an\n * open pen path are inserted unfilled: a fill given to either is dropped.\n * `fillRule` is the rule a path that carries one is built with, where the\n * kit's own is nonzero; a rect or an ellipse has none to set.\n *\n * It paints only the shapes the kit builds: an `InsertNodeFactory` owns its\n * node's whole `data`. See `SceneCanvas`'s `insertPaint` prop.\n */\nexport type InsertPaint = (kind: string, seq: number) => {\n fill?: Fill | null;\n stroke?: Stroke | null;\n fillRule?: PathFillRule;\n};\n\nfunction paintKeys({ fill, stroke }: ReturnType<InsertPaint>): { fill?: Fill | null; stroke?: Stroke | null } {\n return { ...(fill !== undefined ? { fill } : {}), ...(stroke !== undefined ? { stroke } : {}) };\n}\n\nfunction withFillRule(data: unknown, rule: PathFillRule | undefined): unknown {\n const path = (data as { path?: object } | undefined)?.path;\n if (rule === undefined || path === undefined || !('fillRule' in path)) return data;\n return { ...(data as object), path: { ...path, fillRule: rule } };\n}\n\n/** The default {@link InsertPaint}: the next color of the kit palette, as a\n * fill on a closed shape, a fill and a stroke on a pen path, and a stroke\n * alone on a line or a pencil trail. */\nexport const paletteInsertPaint: InsertPaint = (kind, seq) => {\n const color = cycleFill(seq);\n if (kind === 'line' || kind === 'pencil') return { stroke: strokeOf(color, 2) };\n if (kind === 'path') return { fill: { paint: solid(color) }, stroke: strokeOf(color, 2) };\n return { fill: { paint: solid(color) } };\n};\n\nexport function useInsertDepSource(\n scene: Scene<unknown, string, unknown>,\n adapter: OpsApplier,\n factories?: Record<string, InsertNodeFactory>,\n paint: InsertPaint = paletteInsertPaint,\n): void {\n const sceneRef = useLatest(scene);\n const adapterRef = useLatest(adapter);\n const factoriesRef = useLatest(factories);\n const paintRef = useLatest(paint);\n const insertSeqRef = useRef(0);\n const liveRef = useRef<InsertLive>({ gesture: null });\n useDepSource('insertLive', () => liveRef.current);\n\n useDepSource('insert', (): InsertDep => {\n const sc = sceneRef.current;\n const ad = adapterRef.current;\n\n const layer = (sc.layers[0]?.id ?? 'default') as string;\n const build = (\n bounds: { x: number; y: number; width: number; height: number },\n extras: InsertExtras,\n ): { id: NodeId; ops: Op[] } | null => {\n const kind = extras.kind;\n const seq = ++insertSeqRef.current;\n const id = sc.mintId();\n let asked: ReturnType<InsertPaint> | undefined;\n const painted = (as: string = kind) => paintKeys(asked = paintRef.current(as, seq));\n\n // The nascent node's extent — drag AABB reconciled with whatever\n // richer geometry `extras` carries.\n const extent = insertPreviewExtent({ shape: kind, bounds, extras });\n const pose: unknown = extent.bounds;\n\n // Consumer factory wins over the kit default for this kind. It owns the node's\n // data + optional pose; the dep still supplies id/layer/op.\n const factory = factoriesRef.current?.[kind];\n if (factory) {\n const built = factory(bounds, extras);\n if (built === null) return null;\n return {\n id,\n ops: [createInsertOp({ node: { id, kind: 'leaf', layer, pose: built.pose ?? pose, data: built.data } as unknown as { id: string }, label: `Insert ${kind}` })],\n };\n }\n\n const geom = extent.geometry;\n let data: unknown;\n\n switch (geom.kind) {\n case 'line':\n data = { path: linePath(geom.a, geom.b), ...painted(), fill: null };\n break;\n case 'polygon':\n data = {\n path: regularPolygonPath(geom.center, geom.radius, geom.sides, geom.rotation),\n ...painted(),\n };\n break;\n case 'star':\n data = {\n path: starPath(geom.center, geom.outerRadius, geom.points, geom.innerRadius, geom.rotation),\n ...painted(),\n };\n break;\n case 'pencil': {\n const samples = geom.samples as { x: number; y: number }[];\n if (samples.length >= 4) {\n data = { path: schneiderFit(samples, 2.0), ...painted() };\n } else if (samples.length >= 2) {\n data = { path: polygonFromPoints(samples), ...painted() };\n } else {\n data = { path: rectPath(0, 0, extent.bounds.width, extent.bounds.height), ...painted('rect') };\n }\n break;\n }\n case 'box':\n switch (kind) {\n case 'rect':\n // The rect path lives at the origin and the pose carries position:\n // `pathInPoseFrame` rebases a rect path onto the pose box, so don't\n // double-count the position.\n data = { path: rectPath(0, 0, extent.bounds.width, extent.bounds.height), ...painted() };\n break;\n case 'ellipse':\n data = { path: ellipsePath(extent.bounds), ...painted() };\n break;\n case 'path': {\n const e = extras as { path: PolygonPath; closed: boolean };\n data = { path: e.path, ...painted(), ...(e.closed ? {} : { fill: null }) };\n break;\n }\n case 'text': {\n // The built-in text tool drags an empty text box you then type into, so\n // `extras` carries no content. The kit:text painter matches on\n // `data.text != null` and applies style defaults at render time, so a bare\n // `{ text }` is a complete, editable node.\n const e = extras as Partial<{ text: string }>;\n data = { text: e.text ?? '' };\n break;\n }\n case 'image': {\n // The bitmap is loaded + cached by `imageCache` keyed on `src`;\n // only the (serializable) `src` lives on the node.\n const e = extras as Partial<{ src: string; opacity: number }>;\n data = {\n image: {\n src: e.src ?? '',\n ...(e.opacity !== undefined ? { opacity: e.opacity } : {}),\n },\n };\n break;\n }\n default:\n console.warn(`weasel insertDep: no factory for kind=\"${kind}\". Skipping insert.`);\n return null;\n }\n break;\n }\n\n data = withFillRule(data, asked?.fillRule);\n return {\n id,\n ops: [createInsertOp({ node: { id, kind: 'leaf', layer, pose, data } as unknown as { id: string }, label: `Insert ${kind}` })],\n };\n };\n return {\n layer: () => layer,\n build,\n commit(bounds, extras): NodeId | null {\n const built = build(bounds, extras);\n if (built === null) return null;\n ad.applyOps(built.ops, `Insert ${extras.kind}`);\n return built.id;\n },\n };\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"insert.js","names":["e","paintKeys","fill","stroke","withFillRule","path","data","rule","paletteInsertPaint","color","cycleFill","seq","kind","strokeOf","solid","boxKindData","rectPath","bounds","painted","ellipsePath","extras","insertSite","parent","into","sc","p","composition","composesFrames","frame","composeWorldPose","id","definesFrame","useInsertDepSource","sceneRef","useLatest","scene","adapterRef","adapter","factoriesRef","factories","paintRef","paint","registry","useDepRegistry","insertSeqRef","useRef","liveRef","useDepSource","ad","site","build","asked","as","extent","insertPreviewExtent","pose","factory","built","createInsertOp","local","geom","linePath","regularPolygonPath","starPath","samples","schneiderFit","polygonFromPoints"],"sources":["../../../src/canvas/deps/insert.ts"],"sourcesContent":["/**\n * `useInsertDepSource` — wires the `insert` dep consumed by `insertAction`.\n *\n * `line`, `polygon`, `star`, and `pencil` receive the drag AABB from the insertAction invoker,\n * but `extras` may carry richer geometry (endpoints, center+radius+rotation, point trail).\n * `insertPreviewExtent` resolves the two into the node's real extent — the same resolution the\n * live preview and the reported gesture bounds use.\n */\nimport { useRef } from 'react';\nimport { useDepRegistry, useDepSource } from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { InsertDep, InsertExtras, InsertLive } from 'interactions/actions/depSchema';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport type { Op } from 'core/ops/types';\nimport { createInsertOp } from 'core/ops/create';\nimport {\n rectPath,\n ellipsePath,\n regularPolygonPath,\n starPath,\n linePath,\n polygonFromPoints,\n schneiderFit,\n type PathFillRule,\n type PolygonPath,\n} from '@weasel-js/geom';\nimport { insertPreviewExtent } from '../insertPreviewExtent';\nimport type { ShapeGenerator } from 'features/paths/shapeGenerator';\nimport type { Stroke, Fill } from '@weasel-js/paint';\nimport { cycleFill, solid, strokeOf } from '../../util/paint';\nimport { composesFrames, composeWorldPose } from 'core/scene/composeFrame';\nimport { definesFrame } from 'core/scene/effectivePose';\n\ninterface OpsApplier {\n applyOps(ops: Op[], label?: string): void;\n}\n\n/**\n * Consumer-supplied node factory for one insert `kind`. Given the drag AABB\n * and the tool's `extras`, returns the node's `data` (in the consumer's own\n * data shape) plus an optional `pose` override — the dep supplies id, layer,\n * and the undoable insert op. Return `null` to reject the insert.\n *\n * A factory registered for a kit kind (`rect`, `line`, …) fully replaces the\n * kit's default `{ path, fill }` factory for that kind; a factory for a novel\n * kind adds support the kit doesn't ship (e.g. `text`). To change only the\n * paint of a kit shape, pass an {@link InsertPaint}. See\n * `SceneCanvas`'s `insertNodeFactories` prop.\n */\nexport type InsertNodeFactory = (\n bounds: { x: number; y: number; width: number; height: number },\n extras: InsertExtras,\n) => { data: unknown; pose?: unknown } | null;\n\n/**\n * The paint a kit-built shape is inserted with. `kind` is the shape being\n * built and `seq` counts this canvas's inserts from 1. A key left out stays\n * off the node, so its painter's default applies; `null` is \"none\". A pencil\n * trail too short to fit is built as a rect and asks as one. A line and an\n * open pen path are inserted unfilled: a fill given to either is dropped.\n * `fillRule` is the rule a path that carries one is built with, where the\n * kit's own is nonzero; a rect or an ellipse has none to set.\n *\n * It paints only the shapes the kit builds: an `InsertNodeFactory` owns its\n * node's whole `data`. See `SceneCanvas`'s `insertPaint` prop.\n */\nexport type InsertPaint = (kind: string, seq: number) => {\n fill?: Fill | null;\n stroke?: Stroke | null;\n fillRule?: PathFillRule;\n};\n\nfunction paintKeys({ fill, stroke }: ReturnType<InsertPaint>): { fill?: Fill | null; stroke?: Stroke | null } {\n return { ...(fill !== undefined ? { fill } : {}), ...(stroke !== undefined ? { stroke } : {}) };\n}\n\nfunction withFillRule(data: unknown, rule: PathFillRule | undefined): unknown {\n const path = (data as { path?: object } | undefined)?.path;\n if (rule === undefined || path === undefined || !('fillRule' in path)) return data;\n return { ...(data as object), path: { ...path, fillRule: rule } };\n}\n\n/** The default {@link InsertPaint}: the next color of the kit palette, as a\n * fill on a closed shape, a fill and a stroke on a pen path, and a stroke\n * alone on a line or a pencil trail. */\nexport const paletteInsertPaint: InsertPaint = (kind, seq) => {\n const color = cycleFill(seq);\n if (kind === 'line' || kind === 'pencil') return { stroke: strokeOf(color, 2) };\n if (kind === 'path') return { fill: { paint: solid(color) }, stroke: strokeOf(color, 2) };\n return { fill: { paint: solid(color) } };\n};\n\n/** The kit's default data for a kind drawn as a box, or `null` for a kind it has none for. */\nfunction boxKindData(\n kind: string,\n bounds: { x: number; y: number; width: number; height: number },\n extras: InsertExtras,\n painted: (as?: string) => ReturnType<typeof paintKeys>,\n): unknown {\n switch (kind) {\n case 'rect':\n // The rect path lives at the origin and the pose carries position:\n // `pathInPoseFrame` rebases a rect path onto the pose box, so don't\n // double-count the position.\n return { path: rectPath(0, 0, bounds.width, bounds.height), ...painted() };\n case 'ellipse':\n return { path: ellipsePath(bounds), ...painted() };\n case 'path': {\n const e = extras as { path: PolygonPath; closed: boolean };\n return { path: e.path, ...painted(), ...(e.closed ? {} : { fill: null }) };\n }\n case 'text': {\n // The built-in text tool drags an empty text box you then type into, so\n // `extras` carries no content. The kit:text painter matches on\n // `data.text != null` and applies style defaults at render time, so a bare\n // `{ text }` is a complete, editable node.\n const e = extras as Partial<{ text: string }>;\n return { text: e.text ?? '' };\n }\n case 'image': {\n // The bitmap is loaded + cached by `imageCache` keyed on `src`;\n // only the (serializable) `src` lives on the node.\n const e = extras as Partial<{ src: string; opacity: number }>;\n return { image: { src: e.src ?? '', ...(e.opacity !== undefined ? { opacity: e.opacity } : {}) } };\n }\n default:\n return null;\n }\n}\n\n/**\n * Where an insert lands: the container the `insertInto` dep names, on that container's\n * layer, with the pose made local to it when the scene composes frames —\n * or the top of the tree, on the first layer, when it names no container.\n */\nfunction insertSite(\n sc: Scene<unknown, string, unknown>,\n into: string | null | undefined,\n): { parent: NodeId | null; layer: string; local: (world: unknown) => unknown } {\n const parent = into == null ? undefined : sc.get(into as NodeId);\n if (parent === undefined || parent.kind !== 'container') {\n return { parent: null, layer: (sc.layers[0]?.id ?? 'default') as string, local: (p) => p };\n }\n const composition = sc.composition;\n if (composition === undefined || !composesFrames(composition)) {\n return { parent: parent.id, layer: parent.layer, local: (p) => p };\n }\n const frame = composeWorldPose({\n getPose: (id) => sc.get(id as NodeId)!.pose,\n getParent: (id) => sc.get(id as NodeId)?.parent ?? null,\n definesFrame: (id) => definesFrame(sc.get(id as NodeId) ?? {}),\n }, parent.id, composition.compose);\n return { parent: parent.id, layer: parent.layer, local: (p) => composition.decompose(frame, p) };\n}\n\nexport function useInsertDepSource(\n scene: Scene<unknown, string, unknown>,\n adapter: OpsApplier,\n factories?: Record<string, InsertNodeFactory>,\n paint: InsertPaint = paletteInsertPaint,\n): void {\n const sceneRef = useLatest(scene);\n const adapterRef = useLatest(adapter);\n const factoriesRef = useLatest(factories);\n const paintRef = useLatest(paint);\n const registry = useDepRegistry();\n const insertSeqRef = useRef(0);\n const liveRef = useRef<InsertLive>({ gesture: null });\n useDepSource('insertLive', () => liveRef.current);\n\n useDepSource('insert', (): InsertDep => {\n const sc = sceneRef.current;\n const ad = adapterRef.current;\n\n const site = () => insertSite(sc, registry.get('insertInto')?.get());\n const build = (\n bounds: { x: number; y: number; width: number; height: number },\n extras: InsertExtras,\n ): { id: NodeId; ops: Op[] } | null => {\n const kind = extras.kind;\n const { parent, layer, local } = site();\n const seq = ++insertSeqRef.current;\n const id = sc.mintId();\n let asked: ReturnType<InsertPaint> | undefined;\n const painted = (as: string = kind) => paintKeys(asked = paintRef.current(as, seq));\n\n // The nascent node's extent — drag AABB reconciled with whatever\n // richer geometry `extras` carries.\n const extent = insertPreviewExtent({ shape: kind, bounds, extras });\n const pose: unknown = extent.bounds;\n\n // Consumer factory wins over the kit default for this kind. It owns the node's\n // data + optional pose; the dep still supplies id/layer/op.\n const factory = factoriesRef.current?.[kind];\n if (factory) {\n const built = factory(bounds, extras);\n if (built === null) return null;\n return {\n id,\n ops: [createInsertOp({ node: { id, kind: 'leaf', layer, parent, pose: local(built.pose ?? pose), data: built.data } as unknown as { id: string }, label: `Insert ${kind}` })],\n };\n }\n\n const geom = extent.geometry;\n let data: unknown;\n\n switch (geom.kind) {\n case 'line':\n data = { path: linePath(geom.a, geom.b), ...painted(), fill: null };\n break;\n case 'polygon':\n data = {\n path: regularPolygonPath(geom.center, geom.radius, geom.sides, geom.rotation),\n generator: { kind: 'polygon', sides: geom.sides, rotation: geom.rotation } satisfies ShapeGenerator,\n ...painted(),\n };\n break;\n case 'star':\n data = {\n path: starPath(geom.center, geom.outerRadius, geom.points, geom.innerRadius, geom.rotation),\n generator: {\n kind: 'star',\n points: geom.points,\n innerRadiusRatio: geom.outerRadius === 0 ? 0.5 : geom.innerRadius / geom.outerRadius,\n rotation: geom.rotation,\n } satisfies ShapeGenerator,\n ...painted(),\n };\n break;\n case 'pencil': {\n const samples = geom.samples as { x: number; y: number }[];\n if (samples.length >= 4) {\n data = { path: schneiderFit(samples, 2.0), ...painted() };\n } else if (samples.length >= 2) {\n data = { path: polygonFromPoints(samples), ...painted() };\n } else {\n data = { path: rectPath(0, 0, extent.bounds.width, extent.bounds.height), ...painted('rect') };\n }\n break;\n }\n case 'box':\n data = boxKindData(kind, extent.bounds, extras, painted);\n if (data === null) {\n console.warn(`weasel insertDep: no factory for kind=\"${kind}\". Skipping insert.`);\n return null;\n }\n break;\n }\n\n data = withFillRule(data, asked?.fillRule);\n return {\n id,\n ops: [createInsertOp({ node: { id, kind: 'leaf', layer, parent, pose: local(pose), data } as unknown as { id: string }, label: `Insert ${kind}` })],\n };\n };\n return {\n layer: () => site().layer,\n build,\n commit(bounds, extras): NodeId | null {\n const built = build(bounds, extras);\n if (built === null) return null;\n ad.applyOps(built.ops, `Insert ${extras.kind}`);\n return built.id;\n },\n };\n });\n}\n"],"mappings":"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"}
|
|
@@ -3,30 +3,24 @@ import { useEffect as t } from "react";
|
|
|
3
3
|
import { useLatest as n } from "@weasel-js/react";
|
|
4
4
|
import { useDepSource as r } from "@weasel-js/routing/react";
|
|
5
5
|
//#region src/canvas/deps/layout.ts
|
|
6
|
-
function i(i, a, o
|
|
7
|
-
let
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
reflow: s
|
|
6
|
+
function i(i, a, o) {
|
|
7
|
+
let s = n({
|
|
8
|
+
dropTarget: a,
|
|
9
|
+
reflow: o
|
|
11
10
|
});
|
|
12
11
|
r("layout", () => ({
|
|
13
|
-
getLayout: (t) =>
|
|
14
|
-
|
|
15
|
-
if (n !== null) return n;
|
|
16
|
-
let r = c.current.layouts;
|
|
17
|
-
return r ? typeof r == "function" ? r(t) : r[t] ?? null : null;
|
|
18
|
-
},
|
|
19
|
-
dropTarget: c.current.dropTarget,
|
|
12
|
+
getLayout: (t) => i.layoutOf(e(t)),
|
|
13
|
+
dropTarget: s.current.dropTarget,
|
|
20
14
|
get reflow() {
|
|
21
|
-
return
|
|
15
|
+
return s.current.reflow ?? null;
|
|
22
16
|
}
|
|
23
17
|
})), t(() => i.onReflow((e) => {
|
|
24
|
-
let t =
|
|
18
|
+
let t = s.current.reflow;
|
|
25
19
|
if (t) for (let n of e) {
|
|
26
20
|
let e = n.id;
|
|
27
21
|
t.settle(e, t.poseOf(e) === void 0 ? { from: n.from } : void 0);
|
|
28
22
|
}
|
|
29
|
-
}), [i,
|
|
23
|
+
}), [i, s]);
|
|
30
24
|
}
|
|
31
25
|
//#endregion
|
|
32
26
|
export { i as useLayoutDepSource };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","names":["useLayoutDepSource","ref","useLatest","useDepSource","
|
|
1
|
+
{"version":3,"file":"layout.js","names":["useLayoutDepSource","ref","useLatest","useDepSource","scene","asNodeId","containerId","useEffect","glide","m","moves","id"],"sources":["../../../src/canvas/deps/layout.ts"],"sourcesContent":["/**\n * `useLayoutDepSource` — wires the `layout` dep consumed by `moveAction`'s\n * drag-time reflow pass. A container's layout is the one its scene node\n * declares (`scene.layoutOf`). Carries the `layoutDropTarget` mode, and hands\n * every reflow the scene records to the reflow transition so it glides as a\n * drag's does. Always registers; returns null for a container that declares\n * no layout, so the reflow pass is a no-op without churning dep registration\n * on prop changes.\n */\nimport { useEffect } from 'react';\nimport { useDepSource } from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { LayoutDep } from 'interactions/actions/depSchema';\nimport type { Scene } from 'core/scene/types';\nimport { asNodeId } from 'core/scene/types';\nimport type { LayoutDropTargetMode, ReflowTransition } from '../../layout/types';\n\nexport function useLayoutDepSource(\n scene: Scene<unknown, string, unknown>,\n dropTarget?: LayoutDropTargetMode,\n reflow?: ReflowTransition<unknown> | null,\n): void {\n const ref = useLatest({ dropTarget, reflow });\n\n useDepSource('layout', (): LayoutDep => ({\n getLayout: (containerId) => scene.layoutOf(asNodeId(containerId)),\n dropTarget: ref.current.dropTarget,\n get reflow() { return ref.current.reflow ?? null; },\n }));\n\n useEffect(() => scene.onReflow((moves) => {\n const glide = ref.current.reflow;\n if (!glide) return;\n for (const m of moves) {\n // One already gliding carries on from where it is shown.\n const id = m.id as string;\n glide.settle(id, glide.poseOf(id) === undefined ? { from: m.from } : undefined);\n }\n }), [scene, ref]);\n}\n"],"mappings":";;;;;AAiBA,SAAgBA,EACd,GACA,GACA,GACM;CACN,IAAMC,IAAMC,EAAU;EAAE;EAAY;CAAO,CAAC;CAQ5C,AANAC,EAAa,iBAA4B;EACvC,YAAY,MAAgBC,EAAM,SAASC,EAASC,CAAW,CAAC;EAChE,YAAYL,EAAI,QAAQ;EACxB,IAAI,SAAS;GAAE,OAAOA,EAAI,QAAQ,UAAU;EAAM;CACpD,EAAE,GAEFM,QAAgBH,EAAM,UAAU,MAAU;EACxC,IAAMI,IAAQP,EAAI,QAAQ;EAC1B,IAAKO,GACL,KAAK,IAAMC,KAAKC,GAAO;GAErB,IAAMC,IAAKF,EAAE;GACb,EAAM,OAAOE,GAAIH,EAAM,OAAOG,CAAE,MAAM,KAAA,IAAY,EAAE,MAAMF,EAAE,KAAK,IAAI,KAAA,CAAS;EAChF;CACF,CAAC,GAAG,CAACL,GAAOH,CAAG,CAAC;AAClB"}
|
|
@@ -2,39 +2,63 @@ import { composeWorldPose as e, composesFrames as t } from "../core/scene/compos
|
|
|
2
2
|
import { createNodeMemoScope as n } from "../core/scene/nodeMemo.js";
|
|
3
3
|
import { resolveDerivedPath as r } from "../core/scene/derivedPath.js";
|
|
4
4
|
import { definesFrame as i, derivedDepOf as a, effectivePose as o } from "../core/scene/effectivePose.js";
|
|
5
|
-
import {
|
|
5
|
+
import { isRectPose as s } from "../core/geometry/autoPoseDescriptor.js";
|
|
6
|
+
import { asNodeId as c } from "../core/scene/types.js";
|
|
7
|
+
import { boxToBox as l, transformPath as u } from "@weasel-js/geom";
|
|
6
8
|
//#region src/canvas/derivedPath.ts
|
|
7
|
-
function
|
|
8
|
-
let
|
|
9
|
+
function d(e, t) {
|
|
10
|
+
let n = o(e, t);
|
|
11
|
+
return n === t.pose ? t : {
|
|
12
|
+
...t,
|
|
13
|
+
pose: n
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function f(e, t) {
|
|
17
|
+
return (n) => t(d(e, n));
|
|
18
|
+
}
|
|
19
|
+
function p(e, t, n) {
|
|
20
|
+
return !s(t) || !s(n) || t.x === n.x && t.y === n.y && t.width === n.width && t.height === n.height ? e : u(e, l(t.x, t.y, t.width, t.height, n.x, n.y, n.width, n.height));
|
|
21
|
+
}
|
|
22
|
+
function m(e, t) {
|
|
23
|
+
return t === void 0 ? (t) => e.overrides.read(t.id)?.path : (n) => {
|
|
24
|
+
let r = e.overrides.read(n.id)?.path;
|
|
25
|
+
if (r === void 0) return;
|
|
26
|
+
let i = d(e, n);
|
|
27
|
+
return p(r, i.pose, t(i));
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function h(n, r) {
|
|
31
|
+
let a = r ? f(n, r) : (e) => o(n, e);
|
|
9
32
|
if (!t(n.composition)) return a;
|
|
10
|
-
let
|
|
33
|
+
let s = {
|
|
11
34
|
getPose: (e) => {
|
|
12
|
-
let t = n.get(
|
|
35
|
+
let t = n.get(c(e));
|
|
13
36
|
return t ? a(t) : void 0;
|
|
14
37
|
},
|
|
15
|
-
getParent: (e) => n.get(
|
|
38
|
+
getParent: (e) => n.get(c(e))?.parent ?? null,
|
|
16
39
|
definesFrame: (e) => {
|
|
17
|
-
let t = n.get(
|
|
40
|
+
let t = n.get(c(e));
|
|
18
41
|
return t === void 0 || i(t);
|
|
19
42
|
}
|
|
20
43
|
};
|
|
21
|
-
return (t) => e(
|
|
44
|
+
return (t) => e(s, t.id, n.composition.compose);
|
|
22
45
|
}
|
|
23
|
-
function
|
|
24
|
-
let r =
|
|
46
|
+
function g(e, n) {
|
|
47
|
+
let r = x(n, t(e.composition));
|
|
25
48
|
if (r === void 0) return (t) => a(e, t);
|
|
26
49
|
let i = {
|
|
27
|
-
at:
|
|
50
|
+
at: h(e, n),
|
|
28
51
|
slot: r,
|
|
52
|
+
shown: m(e, n),
|
|
29
53
|
childrenOf: (t) => e.childrenOf(t),
|
|
30
54
|
lookup: (t) => {
|
|
31
55
|
let n = e.get(t);
|
|
32
|
-
return n === void 0 ? void 0 : new
|
|
56
|
+
return n === void 0 ? void 0 : new _(n, i);
|
|
33
57
|
}
|
|
34
58
|
};
|
|
35
59
|
return i.lookup;
|
|
36
60
|
}
|
|
37
|
-
var
|
|
61
|
+
var _ = class {
|
|
38
62
|
ctx;
|
|
39
63
|
node;
|
|
40
64
|
pose;
|
|
@@ -42,31 +66,31 @@ var u = class {
|
|
|
42
66
|
this.ctx = t, this.node = e, this.pose = t.at(e);
|
|
43
67
|
}
|
|
44
68
|
get path() {
|
|
45
|
-
return r(this.node, this.ctx.lookup, this.ctx.childrenOf, this.ctx.slot);
|
|
69
|
+
return this.ctx.shown(this.node) ?? r(this.node, this.ctx.lookup, this.ctx.childrenOf, this.ctx.slot);
|
|
46
70
|
}
|
|
47
71
|
};
|
|
48
|
-
function
|
|
72
|
+
function v(e, t) {
|
|
49
73
|
return t.dependsOn !== void 0 || e.overrides.read(t.id)?.path !== void 0;
|
|
50
74
|
}
|
|
51
|
-
function
|
|
52
|
-
let i =
|
|
53
|
-
return
|
|
75
|
+
function y(e, n) {
|
|
76
|
+
let i = g(e, n), a = x(n, t(e.composition)), o = (t) => e.childrenOf(t), s = (e) => r(e, i, o, a), c = m(e, n);
|
|
77
|
+
return (e) => c(e) ?? s(e);
|
|
54
78
|
}
|
|
55
|
-
var
|
|
56
|
-
function
|
|
79
|
+
var b = /* @__PURE__ */ new WeakMap();
|
|
80
|
+
function x(e, t) {
|
|
57
81
|
let r = t ? "world" : "local";
|
|
58
82
|
if (e === void 0) return r === "world" ? "kit:derivedPath:world" : void 0;
|
|
59
|
-
let i =
|
|
60
|
-
return i === void 0 && (i = {},
|
|
83
|
+
let i = b.get(e);
|
|
84
|
+
return i === void 0 && (i = {}, b.set(e, i)), i[r] ??= n();
|
|
61
85
|
}
|
|
62
|
-
function
|
|
63
|
-
let r =
|
|
64
|
-
return (i, a, o
|
|
65
|
-
...
|
|
66
|
-
derivedPath: r(
|
|
67
|
-
});
|
|
86
|
+
function S(e, t, n) {
|
|
87
|
+
let r = y(e, n);
|
|
88
|
+
return (n, i, a, o) => v(e, n) ? t(n, i, a, {
|
|
89
|
+
...o,
|
|
90
|
+
derivedPath: r(n)
|
|
91
|
+
}) : t(n, i, a, o);
|
|
68
92
|
}
|
|
69
93
|
//#endregion
|
|
70
|
-
export { r as resolveDerivedPath,
|
|
94
|
+
export { r as resolveDerivedPath, g as sceneDepLookup, y as sceneDerivedPathOf, h as scenePaintedPoseOf, f as sceneShownToPose, v as showsComputedPath, S as withDerivedPaths };
|
|
71
95
|
|
|
72
96
|
//# sourceMappingURL=derivedPath.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derivedPath.js","names":["scenePaintedPoseOf","local","toPose","effectivePose","scene","node","composesFrames","chain","n","asNodeId","id","definesFrame","composeWorldPose","sceneDepLookup","slot","memoSlotFor","derivedDepOf","ctx","SlotDep","posed","resolveDerivedPath","showsComputedPath","sceneDerivedPathOf","depOf","childrenOf","derived","toPoseScopes","frame","composes","scopes","createNodeMemoScope","withDerivedPaths","derivedPathOf","drawOne","pose","view"],"sources":["../../src/canvas/derivedPath.ts"],"sourcesContent":["/**\n * The render walk's half of derived paths: resolving one against a scene, and\n * handing it to the painter.\n *\n * The resolver itself lives in `core/scene/derivedPath.ts`, beside\n * `derivedPose` — a *pose* can derive from a dependency's path, so\n * `effectivePose` has to be able to reach it.\n */\nimport type { DerivedDep, Node, NodeId, Scene } from 'core/scene/types';\nimport type { Path } from '@weasel-js/geom';\nimport { asNodeId } from 'core/scene/types';\nimport { definesFrame, derivedDepOf, effectivePose } from 'core/scene/effectivePose';\nimport { composesFrames, composeWorldPose, type PoseAdapter } from 'core/scene/composeFrame';\nimport { resolveDerivedPath } from 'core/scene/derivedPath';\nimport { createNodeMemoScope, type NodeMemoScope } from 'core/scene/nodeMemo';\nimport type { SceneViewDrawOne } from './NodeShape';\n\nexport { resolveDerivedPath } from 'core/scene/derivedPath';\n\n/**\n * `(node) => the pose it is painted at`: the slot's `toPose` if it has one,\n * else the scene's effective pose, folded through the parent chain when\n * the scene's composition makes a stored pose local to its container.\n */\nexport function scenePaintedPoseOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (node: Node<TData, TLayer, TPose>) => TPose {\n const local = toPose ?? ((node: Node<TData, TLayer, TPose>) => effectivePose(scene, node));\n if (!composesFrames(scene.composition)) return local;\n const chain: PoseAdapter<TPose> = {\n getPose: (id) => {\n const n = scene.get(asNodeId(id));\n return n ? local(n) : (undefined as unknown as TPose);\n },\n getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,\n definesFrame: (id) => {\n const n = scene.get(asNodeId(id));\n return n === undefined || definesFrame(n);\n },\n };\n return (node) => composeWorldPose(chain, node.id, scene.composition.compose);\n}\n\n/**\n * `(id) => that node, the pose it is painted at, and the path it derives` —\n * resolved against the scene, so a dependency that is itself derived resolves\n * before it is read.\n *\n * A derived edge is drawn from these coordinates and must meet the nodes it\n * connects, so this reads the pose each one is painted at: see\n * {@link scenePaintedPoseOf}.\n */\nexport function sceneDepLookup<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (id: NodeId) => DerivedDep<TPose> | undefined {\n const slot = memoSlotFor(toPose, composesFrames(scene.composition));\n if (slot === undefined) return (id) => derivedDepOf(scene, id);\n const ctx: SlotLookup<TPose> = {\n at: scenePaintedPoseOf(scene, toPose) as (node: unknown) => TPose,\n slot,\n childrenOf: (id: NodeId) => scene.childrenOf(id),\n lookup: (id: NodeId) => {\n const node = scene.get(id);\n return node === undefined ? undefined : new SlotDep(node, ctx);\n },\n };\n return ctx.lookup;\n}\n\ninterface SlotLookup<TPose> {\n at: (node: unknown) => TPose;\n slot: string | NodeMemoScope;\n childrenOf: (id: NodeId) => readonly NodeId[];\n lookup: (id: NodeId) => DerivedDep<TPose> | undefined;\n}\n\n/** A class, not an object literal with a `get path()` — see `SceneDep` in\n * `core/scene/effectivePose.ts` for why. */\nclass SlotDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n\n constructor(posed: unknown, private readonly ctx: SlotLookup<TPose>) {\n this.node = posed as Node<unknown, string, TPose>;\n this.pose = ctx.at(posed);\n }\n\n get path(): Path | null {\n return resolveDerivedPath(\n this.node as never, this.ctx.lookup, this.ctx.childrenOf, this.ctx.slot,\n );\n }\n}\n\n/** Whether something outside `node`'s data says what path it shows: it derives one, or a\n * pose override carries one. The gate both scene walks check before resolving a path. */\nexport function showsComputedPath<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n node: { id: NodeId; dependsOn?: readonly NodeId[] | 'children' },\n): boolean {\n return node.dependsOn !== undefined || scene.overrides.read(node.id)?.path !== undefined;\n}\n\n/**\n * `(node) => the path it shows in place of its data's`: a pose override's `path`, else the\n * one it derives, read through {@link sceneDepLookup}.\n *\n * An override path is in the scene's own frame, so a reader painting through a `toPose` is\n * answered the derived path alone.\n */\nexport function sceneDerivedPathOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (node: Node<TData, TLayer, TPose>) => Path | null {\n const depOf = sceneDepLookup(scene, toPose);\n const slot = memoSlotFor(toPose, composesFrames(scene.composition));\n const childrenOf = (id: NodeId): readonly NodeId[] => scene.childrenOf(id);\n const derived = (node: Node<TData, TLayer, TPose>): Path | null =>\n resolveDerivedPath(node, depOf, childrenOf, slot);\n if (toPose !== undefined) return derived;\n return (node) => scene.overrides.read(node.id)?.path ?? derived(node);\n}\n\nconst toPoseScopes = new WeakMap<object, { local?: NodeMemoScope; world?: NodeMemoScope }>();\n\n/** Where one way of reading poses memoizes its paths, or `undefined` for the\n * scene's own slot: two readers painting one scene at different poses must\n * not serve each other's paths. Every reader composing stored poses shares a\n * slot; a `toPose` gets a scope that is collected with the function. */\nfunction memoSlotFor(\n toPose: object | undefined,\n composes: boolean,\n): string | NodeMemoScope | undefined {\n const frame = composes ? 'world' : 'local';\n if (toPose === undefined) return frame === 'world' ? 'kit:derivedPath:world' : undefined;\n let scopes = toPoseScopes.get(toPose);\n if (scopes === undefined) {\n scopes = {};\n toPoseScopes.set(toPose, scopes);\n }\n return (scopes[frame] ??= createNodeMemoScope());\n}\n\n/**\n * Wrap a `drawOne` so a node that derives its geometry, or whose pose override\n * carries a path, arrives at the painter with the resolved path. The painter has no scene handle and so cannot read\n * the dependencies' poses itself; both scene walks wrap here instead.\n *\n * A node that derives nothing passes the caller's `ctx` through untouched —\n * this runs per node per frame, and an added `{ derivedPath: null }` would be\n * an allocation per node for a field no painter reads.\n */\nexport function withDerivedPaths<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): SceneViewDrawOne<TData, TLayer, TPose> {\n const derivedPathOf = sceneDerivedPathOf(scene, toPose);\n return (node, pose, view, ctx) => {\n if (toPose !== undefined ? node.dependsOn === undefined : !showsComputedPath(scene, node)) {\n return drawOne(node, pose, view, ctx);\n }\n return drawOne(node, pose, view, { ...ctx, derivedPath: derivedPathOf(node) });\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"derivedPath.js","names":["shownNode","pose","effectivePose","scene","node","sceneShownToPose","toPose","carryPath","isRectPose","from","to","path","transformPath","boxToBox","sceneOverridePathOf","shown","scenePaintedPoseOf","local","composesFrames","chain","n","asNodeId","id","definesFrame","composeWorldPose","sceneDepLookup","slot","memoSlotFor","derivedDepOf","ctx","SlotDep","posed","resolveDerivedPath","showsComputedPath","sceneDerivedPathOf","depOf","childrenOf","derived","overridePathOf","toPoseScopes","frame","composes","scopes","createNodeMemoScope","withDerivedPaths","derivedPathOf","drawOne","view"],"sources":["../../src/canvas/derivedPath.ts"],"sourcesContent":["/**\n * The render walk's half of derived paths: resolving one against a scene, and\n * handing it to the painter.\n *\n * The resolver itself lives in `core/scene/derivedPath.ts`, beside\n * `derivedPose` — a *pose* can derive from a dependency's path, so\n * `effectivePose` has to be able to reach it.\n */\nimport type { DerivedDep, Node, NodeId, Scene } from 'core/scene/types';\nimport { boxToBox, transformPath, type Path } from '@weasel-js/geom';\nimport { asNodeId } from 'core/scene/types';\nimport { isRectPose } from 'core/geometry/autoPoseDescriptor';\nimport { definesFrame, derivedDepOf, effectivePose } from 'core/scene/effectivePose';\nimport { composesFrames, composeWorldPose, type PoseAdapter } from 'core/scene/composeFrame';\nimport { resolveDerivedPath } from 'core/scene/derivedPath';\nimport { createNodeMemoScope, type NodeMemoScope } from 'core/scene/nodeMemo';\nimport type { SceneViewDrawOne } from './NodeShape';\n\nexport { resolveDerivedPath } from 'core/scene/derivedPath';\n\ntype ToPose<TData, TLayer extends string, TPose> = (node: Node<TData, TLayer, TPose>) => TPose;\n\n/** `node` as the scene shows it, its `pose` an override's or a derived one: the stored node\n * itself where the two agree. */\nfunction shownNode<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n node: Node<TData, TLayer, TPose>,\n): Node<TData, TLayer, TPose> {\n const pose = effectivePose(scene, node);\n return pose === node.pose ? node : { ...node, pose };\n}\n\n/** A slot's `toPose`, handed each node as the scene shows it, so a view drawn through one\n * shows a drag in flight and a rig's motion as every other view does. */\nexport function sceneShownToPose<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose: ToPose<TData, TLayer, TPose>,\n): ToPose<TData, TLayer, TPose> {\n return (node) => toPose(shownNode(scene, node));\n}\n\n/** `path`, drawn for a node boxed at `from`, as it is drawn for that node boxed at `to`. A\n * pose that is not a box leaves the path where it is. */\nfunction carryPath(path: Path, from: unknown, to: unknown): Path {\n if (!isRectPose(from) || !isRectPose(to)) return path;\n if (from.x === to.x && from.y === to.y && from.width === to.width && from.height === to.height) return path;\n return transformPath(path, boxToBox(from.x, from.y, from.width, from.height, to.x, to.y, to.width, to.height));\n}\n\n/**\n * `(node) => the path its pose override shows it by`, in the frame the reader paints in: as\n * the override has it, or under a `toPose` carried from the box the scene shows the node at\n * to the box `toPose` answers.\n */\nfunction sceneOverridePathOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: ToPose<TData, TLayer, TPose>,\n): (node: Node<TData, TLayer, TPose>) => Path | undefined {\n if (toPose === undefined) return (node) => scene.overrides.read(node.id)?.path;\n return (node) => {\n const path = scene.overrides.read(node.id)?.path;\n if (path === undefined) return undefined;\n const shown = shownNode(scene, node);\n return carryPath(path, shown.pose, toPose(shown));\n };\n}\n\n/**\n * `(node) => the pose it is painted at`: the slot's `toPose` of the node as the scene shows\n * it if it has one, else the scene's effective pose, folded through the parent chain when\n * the scene's composition makes a stored pose local to its container.\n */\nexport function scenePaintedPoseOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (node: Node<TData, TLayer, TPose>) => TPose {\n const local = toPose\n ? sceneShownToPose(scene, toPose)\n : (node: Node<TData, TLayer, TPose>) => effectivePose(scene, node);\n if (!composesFrames(scene.composition)) return local;\n const chain: PoseAdapter<TPose> = {\n getPose: (id) => {\n const n = scene.get(asNodeId(id));\n return n ? local(n) : (undefined as unknown as TPose);\n },\n getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,\n definesFrame: (id) => {\n const n = scene.get(asNodeId(id));\n return n === undefined || definesFrame(n);\n },\n };\n return (node) => composeWorldPose(chain, node.id, scene.composition.compose);\n}\n\n/**\n * `(id) => that node, the pose it is painted at, and the path it derives` —\n * resolved against the scene, so a dependency that is itself derived resolves\n * before it is read.\n *\n * A derived edge is drawn from these coordinates and must meet the nodes it\n * connects, so this reads the pose each one is painted at: see\n * {@link scenePaintedPoseOf}.\n */\nexport function sceneDepLookup<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (id: NodeId) => DerivedDep<TPose> | undefined {\n const slot = memoSlotFor(toPose, composesFrames(scene.composition));\n if (slot === undefined) return (id) => derivedDepOf(scene, id);\n const ctx: SlotLookup<TPose> = {\n at: scenePaintedPoseOf(scene, toPose) as (node: unknown) => TPose,\n slot,\n shown: sceneOverridePathOf(scene, toPose) as (node: unknown) => Path | undefined,\n childrenOf: (id: NodeId) => scene.childrenOf(id),\n lookup: (id: NodeId) => {\n const node = scene.get(id);\n return node === undefined ? undefined : new SlotDep(node, ctx);\n },\n };\n return ctx.lookup;\n}\n\ninterface SlotLookup<TPose> {\n at: (node: unknown) => TPose;\n slot: string | NodeMemoScope;\n /** The path a pose override shows a node by, where it has one. */\n shown: (node: unknown) => Path | undefined;\n childrenOf: (id: NodeId) => readonly NodeId[];\n lookup: (id: NodeId) => DerivedDep<TPose> | undefined;\n}\n\n/** A class, not an object literal with a `get path()` — see `SceneDep` in\n * `core/scene/effectivePose.ts` for why. */\nclass SlotDep<TPose> implements DerivedDep<TPose> {\n readonly node: Node<unknown, string, TPose>;\n readonly pose: TPose;\n\n constructor(posed: unknown, private readonly ctx: SlotLookup<TPose>) {\n this.node = posed as Node<unknown, string, TPose>;\n this.pose = ctx.at(posed);\n }\n\n get path(): Path | null {\n return this.ctx.shown(this.node) ?? resolveDerivedPath(\n this.node as never, this.ctx.lookup, this.ctx.childrenOf, this.ctx.slot,\n );\n }\n}\n\n/** Whether something outside `node`'s data says what path it shows: it derives one, or a\n * pose override carries one. The gate both scene walks check before resolving a path. */\nexport function showsComputedPath<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n node: { id: NodeId; dependsOn?: readonly NodeId[] | 'children' },\n): boolean {\n return node.dependsOn !== undefined || scene.overrides.read(node.id)?.path !== undefined;\n}\n\n/**\n * `(node) => the path it shows in place of its data's`: a pose override's `path`, else the\n * one it derives, read through {@link sceneDepLookup}. A reader painting through a `toPose`\n * is answered the override's path carried into the box its `toPose` answers.\n */\nexport function sceneDerivedPathOf<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): (node: Node<TData, TLayer, TPose>) => Path | null {\n const depOf = sceneDepLookup(scene, toPose);\n const slot = memoSlotFor(toPose, composesFrames(scene.composition));\n const childrenOf = (id: NodeId): readonly NodeId[] => scene.childrenOf(id);\n const derived = (node: Node<TData, TLayer, TPose>): Path | null =>\n resolveDerivedPath(node, depOf, childrenOf, slot);\n const overridePathOf = sceneOverridePathOf(scene, toPose);\n return (node) => overridePathOf(node) ?? derived(node);\n}\n\nconst toPoseScopes = new WeakMap<object, { local?: NodeMemoScope; world?: NodeMemoScope }>();\n\n/** Where one way of reading poses memoizes its paths, or `undefined` for the\n * scene's own slot: two readers painting one scene at different poses must\n * not serve each other's paths. Every reader composing stored poses shares a\n * slot; a `toPose` gets a scope that is collected with the function. */\nfunction memoSlotFor(\n toPose: object | undefined,\n composes: boolean,\n): string | NodeMemoScope | undefined {\n const frame = composes ? 'world' : 'local';\n if (toPose === undefined) return frame === 'world' ? 'kit:derivedPath:world' : undefined;\n let scopes = toPoseScopes.get(toPose);\n if (scopes === undefined) {\n scopes = {};\n toPoseScopes.set(toPose, scopes);\n }\n return (scopes[frame] ??= createNodeMemoScope());\n}\n\n/**\n * Wrap a `drawOne` so a node that derives its geometry, or whose pose override\n * carries a path, arrives at the painter with the resolved path. The painter has no scene handle and so cannot read\n * the dependencies' poses itself; both scene walks wrap here instead.\n *\n * A node that derives nothing passes the caller's `ctx` through untouched —\n * this runs per node per frame, and an added `{ derivedPath: null }` would be\n * an allocation per node for a field no painter reads.\n */\nexport function withDerivedPaths<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>,\n toPose?: (node: Node<TData, TLayer, TPose>) => TPose,\n): SceneViewDrawOne<TData, TLayer, TPose> {\n const derivedPathOf = sceneDerivedPathOf(scene, toPose);\n return (node, pose, view, ctx) => {\n if (!showsComputedPath(scene, node)) return drawOne(node, pose, view, ctx);\n return drawOne(node, pose, view, { ...ctx, derivedPath: derivedPathOf(node) });\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { boundsOfPath as e, regularPolygonPath as t, starPath as n } from "@weasel-js/geom";
|
|
1
2
|
//#region src/canvas/insertPreviewExtent.ts
|
|
2
|
-
function
|
|
3
|
-
let r = e.bounds,
|
|
3
|
+
function r(e) {
|
|
4
|
+
let r = e.bounds, o = {
|
|
4
5
|
x: r.x,
|
|
5
6
|
y: r.y,
|
|
6
7
|
width: r.width,
|
|
@@ -8,55 +9,55 @@ function e(e) {
|
|
|
8
9
|
};
|
|
9
10
|
switch (e.shape) {
|
|
10
11
|
case "line": {
|
|
11
|
-
let t = e.extras,
|
|
12
|
+
let t = e.extras, n = t.a ?? {
|
|
12
13
|
x: r.x,
|
|
13
14
|
y: r.y
|
|
14
|
-
},
|
|
15
|
+
}, i = t.b ?? {
|
|
15
16
|
x: r.x + r.width,
|
|
16
17
|
y: r.y + r.height
|
|
17
18
|
};
|
|
18
19
|
return {
|
|
19
20
|
shape: e.shape,
|
|
20
|
-
bounds:
|
|
21
|
+
bounds: a([n, i]) ?? o,
|
|
21
22
|
geometry: {
|
|
22
23
|
kind: "line",
|
|
23
|
-
a,
|
|
24
|
-
b:
|
|
24
|
+
a: n,
|
|
25
|
+
b: i
|
|
25
26
|
}
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
case "polygon": {
|
|
29
|
-
let n = e.extras,
|
|
30
|
+
let n = e.extras, a = n.center ?? {
|
|
30
31
|
x: r.x + r.width / 2,
|
|
31
32
|
y: r.y + r.height / 2
|
|
32
|
-
},
|
|
33
|
+
}, o = n.radius ?? Math.min(r.width, r.height) / 2, s = Math.max(3, Math.floor(n.sides ?? 6)), c = n.rotation ?? 0;
|
|
33
34
|
return {
|
|
34
35
|
shape: e.shape,
|
|
35
|
-
bounds: t(
|
|
36
|
+
bounds: i(t(a, o, s, c)),
|
|
36
37
|
geometry: {
|
|
37
38
|
kind: "polygon",
|
|
38
|
-
center:
|
|
39
|
-
radius:
|
|
40
|
-
sides:
|
|
41
|
-
rotation:
|
|
39
|
+
center: a,
|
|
40
|
+
radius: o,
|
|
41
|
+
sides: s,
|
|
42
|
+
rotation: c
|
|
42
43
|
}
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
46
|
case "star": {
|
|
46
|
-
let
|
|
47
|
+
let t = e.extras, a = t.center ?? {
|
|
47
48
|
x: r.x + r.width / 2,
|
|
48
49
|
y: r.y + r.height / 2
|
|
49
|
-
},
|
|
50
|
+
}, o = t.outerRadius ?? Math.min(r.width, r.height) / 2, s = o * (t.innerRadiusRatio ?? .5), c = Math.max(3, Math.floor(t.points ?? 5)), l = t.rotation ?? 0;
|
|
50
51
|
return {
|
|
51
52
|
shape: e.shape,
|
|
52
|
-
bounds:
|
|
53
|
+
bounds: i(n(a, o, c, s, l)),
|
|
53
54
|
geometry: {
|
|
54
55
|
kind: "star",
|
|
55
|
-
center:
|
|
56
|
-
outerRadius:
|
|
57
|
-
innerRadius:
|
|
58
|
-
points:
|
|
59
|
-
rotation:
|
|
56
|
+
center: a,
|
|
57
|
+
outerRadius: o,
|
|
58
|
+
innerRadius: s,
|
|
59
|
+
points: c,
|
|
60
|
+
rotation: l
|
|
60
61
|
}
|
|
61
62
|
};
|
|
62
63
|
}
|
|
@@ -64,7 +65,7 @@ function e(e) {
|
|
|
64
65
|
let t = e.extras.samples ?? [];
|
|
65
66
|
return {
|
|
66
67
|
shape: e.shape,
|
|
67
|
-
bounds:
|
|
68
|
+
bounds: a(t) ?? o,
|
|
68
69
|
geometry: {
|
|
69
70
|
kind: "pencil",
|
|
70
71
|
samples: t
|
|
@@ -73,20 +74,21 @@ function e(e) {
|
|
|
73
74
|
}
|
|
74
75
|
default: return {
|
|
75
76
|
shape: e.shape,
|
|
76
|
-
bounds:
|
|
77
|
+
bounds: o,
|
|
77
78
|
geometry: { kind: "box" }
|
|
78
79
|
};
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
|
-
function
|
|
82
|
+
function i(t) {
|
|
83
|
+
let { x: n, y: r, width: i, height: a } = e(t);
|
|
82
84
|
return {
|
|
83
|
-
x:
|
|
84
|
-
y:
|
|
85
|
-
width:
|
|
86
|
-
height:
|
|
85
|
+
x: n,
|
|
86
|
+
y: r,
|
|
87
|
+
width: i,
|
|
88
|
+
height: a
|
|
87
89
|
};
|
|
88
90
|
}
|
|
89
|
-
function
|
|
91
|
+
function a(e) {
|
|
90
92
|
if (e.length === 0) return null;
|
|
91
93
|
let t = Infinity, n = Infinity, r = -Infinity, i = -Infinity;
|
|
92
94
|
for (let a of e) a.x < t && (t = a.x), a.y < n && (n = a.y), a.x > r && (r = a.x), a.y > i && (i = a.y);
|
|
@@ -98,6 +100,6 @@ function n(e) {
|
|
|
98
100
|
};
|
|
99
101
|
}
|
|
100
102
|
//#endregion
|
|
101
|
-
export {
|
|
103
|
+
export { r as insertPreviewExtent };
|
|
102
104
|
|
|
103
105
|
//# sourceMappingURL=insertPreviewExtent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insertPreviewExtent.js","names":["insertPreviewExtent","b","ov","box","e","b2","aabbOf","center","radius","
|
|
1
|
+
{"version":3,"file":"insertPreviewExtent.js","names":["insertPreviewExtent","b","ov","box","e","a","b2","aabbOf","center","radius","sides","rotation","boxOf","regularPolygonPath","outerRadius","innerRadius","points","starPath","samples","boundsOfPath","path","pts","minX","minY","maxX","maxY","p"],"sources":["../../src/canvas/insertPreviewExtent.ts"],"sourcesContent":["/**\n * The one answer to \"how big is the thing this in-flight insert is making\",\n * shared by the preview paint, the commit, and the gesture's reported bounds.\n *\n * The drag AABB alone is NOT the answer. `insertAction` hands over an\n * `extras` payload that can carry richer geometry than the drag rect, and\n * where it does, that geometry is the shape: a pencil that loops back to its\n * start produces a zero-area drag rect around a trail that swept the page.\n */\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { OngoingOverlay } from '@weasel-js/routing';\nimport { boundsOfPath, regularPolygonPath, starPath, type Path } from '@weasel-js/geom';\n\ntype Point = { x: number; y: number };\n\n/** The fields of an `insertPreview` overlay this needs. `canvas/deps/insert`\n * passes the equivalent from its own `(bounds, extras)` commit arguments. */\nexport interface InsertPreviewLike {\n shape: string;\n bounds: { x: number; y: number; width: number; height: number };\n extras: unknown;\n}\n\n/** Resolved preview geometry, in the terms the path builders take. */\nexport type InsertPreviewGeometry =\n | { kind: 'box' }\n | { kind: 'line'; a: Point; b: Point }\n | { kind: 'polygon'; center: Point; radius: number; sides: number; rotation: number }\n | {\n kind: 'star';\n center: Point;\n outerRadius: number;\n innerRadius: number;\n points: number;\n rotation: number;\n }\n | { kind: 'pencil'; samples: ReadonlyArray<Point> };\n\n/** An in-flight insert's shape, resolved from its drag rect and `extras`. */\nexport interface InsertPreviewExtent {\n /** The insert kind, verbatim from the caller. */\n shape: string;\n /** World-space AABB of `geometry` — the extent. */\n bounds: Bounds;\n geometry: InsertPreviewGeometry;\n}\n\n/** The `insertPreview` member of `OngoingOverlay`, which `insertAction` publishes during a drag-to-insert. */\nexport type InsertPreviewOverlay = Extract<OngoingOverlay, { kind: 'insertPreview' }>;\n\n/** Resolve an in-flight insert's geometry and world AABB. Uses the geometry in\n * `extras` where the shape carries it; an unknown shape falls back to its drag rect. */\nexport function insertPreviewExtent(ov: InsertPreviewLike): InsertPreviewExtent {\n const b = ov.bounds;\n const box = { x: b.x, y: b.y, width: b.width, height: b.height };\n\n switch (ov.shape) {\n case 'line': {\n const e = ov.extras as Partial<{ a: Point; b: Point }>;\n const a = e.a ?? { x: b.x, y: b.y };\n const b2 = e.b ?? { x: b.x + b.width, y: b.y + b.height };\n return { shape: ov.shape, bounds: aabbOf([a, b2]) ?? box, geometry: { kind: 'line', a, b: b2 } };\n }\n case 'polygon': {\n const e = ov.extras as Partial<{\n sides: number; rotation: number; center: Point; radius: number;\n }>;\n const center = e.center ?? { x: b.x + b.width / 2, y: b.y + b.height / 2 };\n const radius = e.radius ?? Math.min(b.width, b.height) / 2;\n const sides = Math.max(3, Math.floor(e.sides ?? 6));\n const rotation = e.rotation ?? 0;\n return {\n shape: ov.shape,\n bounds: boxOf(regularPolygonPath(center, radius, sides, rotation)),\n geometry: { kind: 'polygon', center, radius, sides, rotation },\n };\n }\n case 'star': {\n const e = ov.extras as Partial<{\n points: number; innerRadiusRatio: number; rotation: number;\n center: Point; outerRadius: number;\n }>;\n const center = e.center ?? { x: b.x + b.width / 2, y: b.y + b.height / 2 };\n const outerRadius = e.outerRadius ?? Math.min(b.width, b.height) / 2;\n const innerRadius = outerRadius * (e.innerRadiusRatio ?? 0.5);\n const points = Math.max(3, Math.floor(e.points ?? 5));\n const rotation = e.rotation ?? 0;\n return {\n shape: ov.shape,\n bounds: boxOf(starPath(center, outerRadius, points, innerRadius, rotation)),\n geometry: { kind: 'star', center, outerRadius, innerRadius, points, rotation },\n };\n }\n case 'pencil': {\n const e = ov.extras as Partial<{ samples: ReadonlyArray<Point> }>;\n const samples = e.samples ?? [];\n return {\n shape: ov.shape,\n bounds: aabbOf(samples) ?? box,\n geometry: { kind: 'pencil', samples },\n };\n }\n default:\n return { shape: ov.shape, bounds: box, geometry: { kind: 'box' } };\n }\n}\n\n/** A radial shape's extent is the box of the shape it makes, as the commit stores it. */\nfunction boxOf(path: Path): Bounds {\n const { x, y, width, height } = boundsOfPath(path);\n return { x, y, width, height };\n}\n\nfunction aabbOf(pts: ReadonlyArray<Point>): Bounds | null {\n if (pts.length === 0) return null;\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n"],"mappings":";;AAoDA,SAAgBA,EAAoB,GAA4C;CAC9E,IAAMC,IAAIC,EAAG,QACPC,IAAM;EAAE,GAAGF,EAAE;EAAG,GAAGA,EAAE;EAAG,OAAOA,EAAE;EAAO,QAAQA,EAAE;CAAO;CAE/D,QAAQC,EAAG,OAAX;EACE,KAAK,QAAQ;GACX,IAAME,IAAIF,EAAG,QACPG,IAAID,EAAE,KAAK;IAAE,GAAGH,EAAE;IAAG,GAAGA,EAAE;GAAE,GAC5BK,IAAKF,EAAE,KAAK;IAAE,GAAGH,EAAE,IAAIA,EAAE;IAAO,GAAGA,EAAE,IAAIA,EAAE;GAAO;GACxD,OAAO;IAAE,OAAOC,EAAG;IAAO,QAAQK,EAAO,CAACF,GAAGC,CAAE,CAAC,KAAKH;IAAK,UAAU;KAAE,MAAM;KAAQ;KAAG,GAAGG;IAAG;GAAE;EACjG;EACA,KAAK,WAAW;GACd,IAAMF,IAAIF,EAAG,QAGPM,IAASJ,EAAE,UAAU;IAAE,GAAGH,EAAE,IAAIA,EAAE,QAAQ;IAAG,GAAGA,EAAE,IAAIA,EAAE,SAAS;GAAE,GACnEQ,IAASL,EAAE,UAAU,KAAK,IAAIH,EAAE,OAAOA,EAAE,MAAM,IAAI,GACnDS,IAAQ,KAAK,IAAI,GAAG,KAAK,MAAMN,EAAE,SAAS,CAAC,CAAC,GAC5CO,IAAWP,EAAE,YAAY;GAC/B,OAAO;IACL,OAAOF,EAAG;IACV,QAAQU,EAAMC,EAAmBL,GAAQC,GAAQC,GAAOC,CAAQ,CAAC;IACjE,UAAU;KAAE,MAAM;KAAW;KAAQ;KAAQ;KAAO;IAAS;GAC/D;EACF;EACA,KAAK,QAAQ;GACX,IAAMP,IAAIF,EAAG,QAIPM,IAASJ,EAAE,UAAU;IAAE,GAAGH,EAAE,IAAIA,EAAE,QAAQ;IAAG,GAAGA,EAAE,IAAIA,EAAE,SAAS;GAAE,GACnEa,IAAcV,EAAE,eAAe,KAAK,IAAIH,EAAE,OAAOA,EAAE,MAAM,IAAI,GAC7Dc,IAAcD,KAAeV,EAAE,oBAAoB,KACnDY,IAAS,KAAK,IAAI,GAAG,KAAK,MAAMZ,EAAE,UAAU,CAAC,CAAC,GAC9CO,IAAWP,EAAE,YAAY;GAC/B,OAAO;IACL,OAAOF,EAAG;IACV,QAAQU,EAAMK,EAAST,GAAQM,GAAaE,GAAQD,GAAaJ,CAAQ,CAAC;IAC1E,UAAU;KAAE,MAAM;KAAQ;KAAQ;KAAa;KAAa;KAAQ;IAAS;GAC/E;EACF;EACA,KAAK,UAAU;GAEb,IAAMO,IADIhB,EAAG,OACK,WAAW,CAAC;GAC9B,OAAO;IACL,OAAOA,EAAG;IACV,QAAQK,EAAOW,CAAO,KAAKf;IAC3B,UAAU;KAAE,MAAM;KAAU;IAAQ;GACtC;EACF;EACA,SACE,OAAO;GAAE,OAAOD,EAAG;GAAO,QAAQC;GAAK,UAAU,EAAE,MAAM,MAAM;EAAE;CACrE;AACF;AAGA,SAASS,EAAM,GAAoB;CACjC,IAAM,EAAE,MAAG,MAAG,UAAO,cAAWO,EAAaC,CAAI;CACjD,OAAO;EAAE;EAAG;EAAG;EAAO;CAAO;AAC/B;AAEA,SAASb,EAAO,GAA0C;CACxD,IAAIc,EAAI,WAAW,GAAG,OAAO;CAC7B,IAAIC,IAAO,UAAUC,IAAO,UAAUC,IAAO,WAAWC,IAAO;CAC/D,KAAK,IAAMC,KAAKL,GAId,AAHIK,EAAE,IAAIJ,MAAM,IAAOI,EAAE,IACrBA,EAAE,IAAIH,MAAM,IAAOG,EAAE,IACrBA,EAAE,IAAIF,MAAM,IAAOE,EAAE,IACrBA,EAAE,IAAID,MAAM,IAAOC,EAAE;CAE3B,OAAO;EAAE,GAAGJ;EAAM,GAAGC;EAAM,OAAOC,IAAOF;EAAM,QAAQG,IAAOF;CAAK;AACrE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/canvas/overChildren.ts
|
|
2
|
+
var e = /* @__PURE__ */ new WeakSet();
|
|
3
|
+
function t(t) {
|
|
4
|
+
let n = {
|
|
5
|
+
kind: "group",
|
|
6
|
+
children: t
|
|
7
|
+
};
|
|
8
|
+
return e.add(n), n;
|
|
9
|
+
}
|
|
10
|
+
function n(t) {
|
|
11
|
+
return e.has(t);
|
|
12
|
+
}
|
|
13
|
+
var r = [];
|
|
14
|
+
function i(e) {
|
|
15
|
+
if (!e.some(n)) return {
|
|
16
|
+
under: e,
|
|
17
|
+
over: r
|
|
18
|
+
};
|
|
19
|
+
let t = [], i = [];
|
|
20
|
+
for (let r of e) n(r) ? i.push(...r.children) : t.push(r);
|
|
21
|
+
return {
|
|
22
|
+
under: t,
|
|
23
|
+
over: i
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { n as isOverChildren, t as overChildren, i as splitOverChildren };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=overChildren.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overChildren.js","names":["OVER","overChildren","group","cmds","isOverChildren","cmd","NOTHING","splitOverChildren","under","over"],"sources":["../../src/canvas/overChildren.ts"],"sourcesContent":["/**\n * How a painter asks for part of a node's paint to land on top of the node's\n * children: a container's label, a frame's title, a badge. A scene walk draws\n * a node before its children, so anything else a container paints is covered\n * by them.\n */\nimport type { DrawCommand, GroupDrawCommand } from '@weasel-js/renderer';\n\nconst OVER = new WeakSet<object>();\n\n/**\n * `cmds` as one command a scene walk paints after the node's children. Return\n * it among a `drawOne`'s other commands. Outside a scene walk it is an\n * ordinary group, painted where it sits in the list.\n */\nexport function overChildren(cmds: DrawCommand[]): DrawCommand {\n const group: GroupDrawCommand = { kind: 'group', children: cmds };\n OVER.add(group);\n return group;\n}\n\n/** Whether `cmd` came from {@link overChildren}. */\nexport function isOverChildren(cmd: DrawCommand): boolean {\n return OVER.has(cmd);\n}\n\nconst NOTHING: DrawCommand[] = [];\n\n/** `cmds` as what paints under the node's children and what paints over them.\n * A list asking for nothing over comes back as `under` itself. */\nexport function splitOverChildren(cmds: DrawCommand[]): { under: DrawCommand[]; over: DrawCommand[] } {\n if (!cmds.some(isOverChildren)) return { under: cmds, over: NOTHING };\n const under: DrawCommand[] = [];\n const over: DrawCommand[] = [];\n for (const cmd of cmds) {\n if (isOverChildren(cmd)) over.push(...(cmd as GroupDrawCommand).children);\n else under.push(cmd);\n }\n return { under, over };\n}\n"],"mappings":";AAQA,IAAMA,oBAAO,IAAI,QAAgB;AAOjC,SAAgBC,EAAa,GAAkC;CAC7D,IAAMC,IAA0B;EAAE,MAAM;EAAS,UAAUC;CAAK;CAEhE,OADAH,EAAK,IAAIE,CAAK,GACPA;AACT;AAGA,SAAgBE,EAAe,GAA2B;CACxD,OAAOJ,EAAK,IAAIK,CAAG;AACrB;AAEA,IAAMC,IAAyB,CAAC;AAIhC,SAAgBC,EAAkB,GAAoE;CACpG,IAAI,CAACJ,EAAK,KAAKC,CAAc,GAAG,OAAO;EAAE,OAAOD;EAAM,MAAMG;CAAQ;CACpE,IAAME,IAAuB,CAAC,GACxBC,IAAsB,CAAC;CAC7B,KAAK,IAAMJ,KAAOF,GAChB,AAAIC,EAAeC,CAAG,IAAGI,EAAK,KAAK,GAAIJ,EAAyB,QAAQ,IACnEG,EAAM,KAAKH,CAAG;CAErB,OAAO;EAAE;EAAO;CAAK;AACvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paintedCursorLayer.js","names":["PAINTED_CURSOR_LAYER_ID","pathCache","pathFor","p","d","pathFromD","commandFor","op","createPaintedCursorLayer","frame","state","glyph","GLYPHS","cursor","scale","view","worldSized","size","cursorWorldSize","ops","cursorPaintOps","chromeLineWidthScale","a","b","c","e","f","cursorPaintMatrix"],"sources":["../../src/canvas/paintedCursorLayer.ts"],"sourcesContent":["/**\n * The painted tier: draws a cursor glyph into the scene when it is too big,\n * or too tied to the view, to be a CSS `url()` cursor.\n *\n * Screen-space: the glyph is chrome at the pointer, so it must not pan or zoom\n * with the camera. What *does* track the camera is a world-sized glyph's size,\n * and `view.scale` is read for that.\n */\n\nimport { GLYPHS } from '@weasel-js/cursor';\nimport {\n chromeLineWidthScale,\n cursorPaintMatrix,\n cursorPaintOps,\n cursorWorldSize,\n} from '@weasel-js/cursor';\nimport type { CursorPaintOp } from '@weasel-js/cursor';\nimport type { DrawCommand, PathDrawCommand } from '@weasel-js/renderer';\nimport type { RenderLayer } from 'core/layers/render';\nimport { pathFromD, type Path } from '@weasel-js/geom';\nimport type { PaintedCursorState } from '@weasel-js/cursor';\n\n/** Layer id, so a consumer can order or hide it like any other. */\nexport const PAINTED_CURSOR_LAYER_ID = 'painted-cursor';\n\n/** Handing the renderer the same `Path` object every frame lets its mesh cache hit. */\nconst pathCache = new Map<string, Path>();\nfunction pathFor(d: string): Path {\n let p = pathCache.get(d);\n if (p === undefined) {\n p = pathFromD(d);\n pathCache.set(d, p);\n }\n return p;\n}\n\nfunction commandFor(op: CursorPaintOp): PathDrawCommand {\n return {\n kind: 'path',\n path: pathFor(op.d),\n ...(op.fill !== undefined ? { fill: { paint: { color: op.fill } } } : {}),\n ...(op.stroke !== undefined\n ? {\n stroke: {\n paint: { color: op.stroke.color },\n width: op.stroke.width,\n cap: 'round' as const,\n join: 'round' as const,\n },\n }\n : {}),\n };\n}\n\n/**\n * A screen-space layer that draws the glyph `state` currently holds at the pointer,\n * or nothing when it holds none. `<Canvas>` mounts one over its own state already.\n */\nexport function createPaintedCursorLayer(state: PaintedCursorState): RenderLayer<unknown> {\n return {\n id: PAINTED_CURSOR_LAYER_ID,\n label: 'Painted cursor',\n space: 'screen',\n draw: (_data, view) => {\n const frame = state.current();\n if (!frame) return [];\n const { cursor, at } = frame;\n const glyph = GLYPHS[cursor.glyph];\n if (!glyph) return [];\n\n // A world-sized glyph holds its line weight in CSS px while its geometry\n // grows — a ring at a 400px radius drawn with scaled weight is a filled\n // blob. A single radius needs one scale factor, so average the axes.\n const scale = (view.scale.x + view.scale.y) / 2;\n const worldSized = cursor.worldRadius !== undefined;\n const size = worldSized\n ? cursorWorldSize(glyph, cursor.worldRadius as number, scale)\n : (cursor.size ?? 24);\n if (!(size > 0) || !Number.isFinite(size)) return [];\n\n const ops = cursorPaintOps(\n glyph,\n worldSized ? { lineWidthScale: chromeLineWidthScale(glyph, size) } : {},\n );\n const [a, b, c, d, e, f] = cursorPaintMatrix(glyph, {\n size,\n angle: cursor.angle,\n at,\n });\n // Column-major, the layout `
|
|
1
|
+
{"version":3,"file":"paintedCursorLayer.js","names":["PAINTED_CURSOR_LAYER_ID","pathCache","pathFor","p","d","pathFromD","commandFor","op","createPaintedCursorLayer","frame","state","glyph","GLYPHS","cursor","scale","view","worldSized","size","cursorWorldSize","ops","cursorPaintOps","chromeLineWidthScale","a","b","c","e","f","cursorPaintMatrix"],"sources":["../../src/canvas/paintedCursorLayer.ts"],"sourcesContent":["/**\n * The painted tier: draws a cursor glyph into the scene when it is too big,\n * or too tied to the view, to be a CSS `url()` cursor.\n *\n * Screen-space: the glyph is chrome at the pointer, so it must not pan or zoom\n * with the camera. What *does* track the camera is a world-sized glyph's size,\n * and `view.scale` is read for that.\n */\n\nimport { GLYPHS } from '@weasel-js/cursor';\nimport {\n chromeLineWidthScale,\n cursorPaintMatrix,\n cursorPaintOps,\n cursorWorldSize,\n} from '@weasel-js/cursor';\nimport type { CursorPaintOp } from '@weasel-js/cursor';\nimport type { DrawCommand, PathDrawCommand } from '@weasel-js/renderer';\nimport type { RenderLayer } from 'core/layers/render';\nimport { pathFromD, type Path } from '@weasel-js/geom';\nimport type { PaintedCursorState } from '@weasel-js/cursor';\n\n/** Layer id, so a consumer can order or hide it like any other. */\nexport const PAINTED_CURSOR_LAYER_ID = 'painted-cursor';\n\n/** Handing the renderer the same `Path` object every frame lets its mesh cache hit. */\nconst pathCache = new Map<string, Path>();\nfunction pathFor(d: string): Path {\n let p = pathCache.get(d);\n if (p === undefined) {\n p = pathFromD(d);\n pathCache.set(d, p);\n }\n return p;\n}\n\nfunction commandFor(op: CursorPaintOp): PathDrawCommand {\n return {\n kind: 'path',\n path: pathFor(op.d),\n ...(op.fill !== undefined ? { fill: { paint: { color: op.fill } } } : {}),\n ...(op.stroke !== undefined\n ? {\n stroke: {\n paint: { color: op.stroke.color },\n width: op.stroke.width,\n cap: 'round' as const,\n join: 'round' as const,\n },\n }\n : {}),\n };\n}\n\n/**\n * A screen-space layer that draws the glyph `state` currently holds at the pointer,\n * or nothing when it holds none. `<Canvas>` mounts one over its own state already.\n */\nexport function createPaintedCursorLayer(state: PaintedCursorState): RenderLayer<unknown> {\n return {\n id: PAINTED_CURSOR_LAYER_ID,\n label: 'Painted cursor',\n space: 'screen',\n draw: (_data, view) => {\n const frame = state.current();\n if (!frame) return [];\n const { cursor, at } = frame;\n const glyph = GLYPHS[cursor.glyph];\n if (!glyph) return [];\n\n // A world-sized glyph holds its line weight in CSS px while its geometry\n // grows — a ring at a 400px radius drawn with scaled weight is a filled\n // blob. A single radius needs one scale factor, so average the axes.\n const scale = (view.scale.x + view.scale.y) / 2;\n const worldSized = cursor.worldRadius !== undefined;\n const size = worldSized\n ? cursorWorldSize(glyph, cursor.worldRadius as number, scale)\n : (cursor.size ?? 24);\n if (!(size > 0) || !Number.isFinite(size)) return [];\n\n const ops = cursorPaintOps(\n glyph,\n worldSized ? { lineWidthScale: chromeLineWidthScale(glyph, size) } : {},\n );\n const [a, b, c, d, e, f] = cursorPaintMatrix(glyph, {\n size,\n angle: cursor.angle,\n at,\n });\n // Column-major, the layout `GlMat3` documents.\n const transform = new Float32Array([a, b, 0, c, d, 0, e, f, 1]);\n const children: DrawCommand[] = ops.map(commandFor);\n return [{ kind: 'group', transform, children }];\n },\n };\n}\n"],"mappings":";;;AAuBA,IAAaA,IAA0B,kBAGjCC,oBAAY,IAAI,IAAkB;AACxC,SAASC,EAAQ,GAAiB;CAChC,IAAIC,IAAIF,EAAU,IAAIG,CAAC;CAKvB,OAJID,MAAM,KAAA,MACR,IAAIE,EAAUD,CAAC,GACfH,EAAU,IAAIG,GAAGD,CAAC,IAEbA;AACT;AAEA,SAASG,EAAW,GAAoC;CACtD,OAAO;EACL,MAAM;EACN,MAAMJ,EAAQK,EAAG,CAAC;EAClB,GAAIA,EAAG,SAAS,KAAA,IAAsD,CAAC,IAA3C,EAAE,MAAM,EAAE,OAAO,EAAE,OAAOA,EAAG,KAAK,EAAE,EAAE;EAClE,GAAIA,EAAG,WAAW,KAAA,IASd,CAAC,IARD,EACE,QAAQ;GACN,OAAO,EAAE,OAAOA,EAAG,OAAO,MAAM;GAChC,OAAOA,EAAG,OAAO;GACjB,KAAK;GACL,MAAM;EACR,EACF;CAEN;AACF;AAMA,SAAgBC,EAAyB,GAAiD;CACxF,OAAO;EACL,IAAIR;EACJ,OAAO;EACP,OAAO;EACP,OAAO,GAAO,MAAS;GACrB,IAAMS,IAAQC,EAAM,QAAQ;GAC5B,IAAI,CAACD,GAAO,OAAO,CAAC;GACpB,IAAM,EAAE,WAAQ,UAAOA,GACjBE,IAAQC,EAAOC,EAAO;GAC5B,IAAI,CAACF,GAAO,OAAO,CAAC;GAKpB,IAAMG,KAASC,EAAK,MAAM,IAAIA,EAAK,MAAM,KAAK,GACxCC,IAAaH,EAAO,gBAAgB,KAAA,GACpCI,IAAOD,IACTE,EAAgBP,GAAOE,EAAO,aAAuBC,CAAK,IACzDD,EAAO,QAAQ;GACpB,IAAI,EAAEI,IAAO,MAAM,CAAC,OAAO,SAASA,CAAI,GAAG,OAAO,CAAC;GAEnD,IAAME,IAAMC,EACVT,GACAK,IAAa,EAAE,gBAAgBK,EAAqBV,GAAOM,CAAI,EAAE,IAAI,CAAC,CACxE,GACM,CAACK,GAAGC,GAAGC,GAAGpB,GAAGqB,GAAGC,KAAKC,EAAkBhB,GAAO;IAClD;IACA,OAAOE,EAAO;IACd;GACF,CAAC;GAID,OAAO,CAAC;IAAE,MAAM;IAAS,WAAA,IAFH,aAAa;KAACS;KAAGC;KAAG;KAAGC;KAAGpB;KAAG;KAAGqB;KAAGC;KAAG;IAAC,CAEpC;IAAW,UADJP,EAAI,IAAIb,CACJ;GAAS,CAAC;EAChD;CACF;AACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/canvas/pickReach.ts
|
|
2
|
+
function e(e, t, n, r, i, a, o) {
|
|
3
|
+
let s = (r, i) => {
|
|
4
|
+
let a = o.clipOf(i);
|
|
5
|
+
return a === null || r.clipAdmits(o.carry(a, i.layer, e.layer), e, t, n);
|
|
6
|
+
}, c = a && r.inCopy !== void 0 ? i() : null;
|
|
7
|
+
if (c === null || !c.some((e) => o.copiesOf(e).length > 0)) return r.hits(e, t, n) ? (c ?? i()).every((e) => s(r, e)) : !1;
|
|
8
|
+
let l = [...c].reverse(), u = (r, i) => {
|
|
9
|
+
if (r === l.length) return i.hits(e, t, n);
|
|
10
|
+
let a = l[r];
|
|
11
|
+
if (s(i, a) && u(r + 1, i)) return !0;
|
|
12
|
+
for (let e of o.copiesOf(a)) {
|
|
13
|
+
let t = i.inCopy?.(e);
|
|
14
|
+
if (t !== void 0 && s(t, a) && u(r + 1, t)) return !0;
|
|
15
|
+
}
|
|
16
|
+
return !1;
|
|
17
|
+
};
|
|
18
|
+
return u(0, r);
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { e as reaches };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=pickReach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pickReach.js","names":["reaches","admits","clip","look","ancestor","query","node","pose","derived","parents","copying","q","parentsOf","a","outermostFirst","from","i","m","inCopy"],"sources":["../../src/canvas/pickReach.ts"],"sourcesContent":["import type { Affine, Path } from '@weasel-js/geom';\nimport type { PickCandidate, PickQuery } from './pickWalk';\n\n/** What {@link reaches} needs from the walk, each memoized per walk there. */\nexport interface ReachLookups<TPose> {\n /** An ancestor's own clip, or null. */\n clipOf(ancestor: PickCandidate<TPose>): Path | null;\n /** The maps from world into the source frame of each copy `ancestor` draws:\n * the inverses of its `copiesFromPose`. Empty when it draws none. */\n copiesOf(ancestor: PickCandidate<TPose>): readonly Affine[];\n /** A clip carried from its container's plane into the node's. */\n carry(clip: Path, fromLayer: string | undefined, toLayer: string | undefined): Path;\n}\n\n/**\n * Whether `q` lands on `node` anywhere it is painted: as authored, or in any\n * copy an ancestor draws of it. `parents` is innermost first.\n *\n * A copy is the clipped content transformed, so the query is carried into the\n * copy's source frame before the copying container's own clip is asked, and\n * every clip below it is asked in that frame too.\n *\n * `parents` is called only when the answer needs it — always when\n * `copying` says some container in the walk draws copies, otherwise only\n * after the node hits as authored.\n */\nexport function reaches<TPose>(\n node: PickCandidate<TPose>,\n pose: TPose,\n derived: Path | null | undefined,\n q: PickQuery<TPose>,\n parentsOf: () => readonly PickCandidate<TPose>[],\n copying: boolean,\n look: ReachLookups<TPose>,\n): boolean {\n const admits = (query: PickQuery<TPose>, ancestor: PickCandidate<TPose>): boolean => {\n const clip = look.clipOf(ancestor);\n return clip === null\n || query.clipAdmits(look.carry(clip, ancestor.layer, node.layer), node, pose, derived);\n };\n\n const parents = copying && q.inCopy !== undefined ? parentsOf() : null;\n if (parents === null || !parents.some((a) => look.copiesOf(a).length > 0)) {\n if (!q.hits(node, pose, derived)) return false;\n return (parents ?? parentsOf()).every((a) => admits(q, a));\n }\n\n const outermostFirst = [...parents].reverse();\n const from = (i: number, query: PickQuery<TPose>): boolean => {\n if (i === outermostFirst.length) return query.hits(node, pose, derived);\n const ancestor = outermostFirst[i];\n if (admits(query, ancestor) && from(i + 1, query)) return true;\n for (const m of look.copiesOf(ancestor)) {\n const inCopy = query.inCopy?.(m);\n if (inCopy !== undefined && admits(inCopy, ancestor) && from(i + 1, inCopy)) return true;\n }\n return false;\n };\n return from(0, q);\n}\n"],"mappings":";AA0BA,SAAgBA,EACd,GACA,GACA,GACA,GACA,GACA,GACA,GACS;CACT,IAAMC,KAAU,GAAyB,MAA4C;EACnF,IAAMC,IAAOC,EAAK,OAAOC,CAAQ;EACjC,OAAOF,MAAS,QACXG,EAAM,WAAWF,EAAK,MAAMD,GAAME,EAAS,OAAOE,EAAK,KAAK,GAAGA,GAAMC,GAAMC,CAAO;CACzF,GAEMC,IAAUC,KAAWC,EAAE,WAAW,KAAA,IAAYC,EAAU,IAAI;CAClE,IAAIH,MAAY,QAAQ,CAACA,EAAQ,MAAM,MAAMN,EAAK,SAASU,CAAC,CAAC,CAAC,SAAS,CAAC,GAEtE,OADKF,EAAE,KAAKL,GAAMC,GAAMC,CAAO,KACvBC,KAAWG,EAAU,EAAA,CAAG,OAAO,MAAMX,EAAOU,GAAGE,CAAC,CAAC,IADhB;CAI3C,IAAMC,IAAiB,CAAC,GAAGL,CAAO,CAAC,CAAC,QAAQ,GACtCM,KAAQ,GAAW,MAAqC;EAC5D,IAAIC,MAAMF,EAAe,QAAQ,OAAOT,EAAM,KAAKC,GAAMC,GAAMC,CAAO;EACtE,IAAMJ,IAAWU,EAAeE;EAChC,IAAIf,EAAOI,GAAOD,CAAQ,KAAKW,EAAKC,IAAI,GAAGX,CAAK,GAAG,OAAO;EAC1D,KAAK,IAAMY,KAAKd,EAAK,SAASC,CAAQ,GAAG;GACvC,IAAMc,IAASb,EAAM,SAASY,CAAC;GAC/B,IAAIC,MAAW,KAAA,KAAajB,EAAOiB,GAAQd,CAAQ,KAAKW,EAAKC,IAAI,GAAGE,CAAM,GAAG,OAAO;EACtF;EACA,OAAO;CACT;CACA,OAAOH,EAAK,GAAGJ,CAAC;AAClB"}
|