@editframe/elements 0.30.1-beta.0 → 0.31.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EF_FRAMEGEN.d.ts +5 -0
- package/dist/EF_FRAMEGEN.js +20 -4
- package/dist/EF_FRAMEGEN.js.map +1 -1
- package/dist/EF_INTERACTIVE.js.map +1 -1
- package/dist/_virtual/rolldown_runtime.js +27 -0
- package/dist/canvas/EFCanvas.d.ts +311 -0
- package/dist/canvas/EFCanvas.js +1089 -0
- package/dist/canvas/EFCanvas.js.map +1 -0
- package/dist/canvas/EFCanvasItem.d.ts +55 -0
- package/dist/canvas/EFCanvasItem.js +72 -0
- package/dist/canvas/EFCanvasItem.js.map +1 -0
- package/dist/canvas/api/CanvasAPI.d.ts +115 -0
- package/dist/canvas/api/CanvasAPI.js +182 -0
- package/dist/canvas/api/CanvasAPI.js.map +1 -0
- package/dist/canvas/api/types.d.ts +42 -0
- package/dist/canvas/coordinateTransform.js +90 -0
- package/dist/canvas/coordinateTransform.js.map +1 -0
- package/dist/canvas/getElementBounds.js +40 -0
- package/dist/canvas/getElementBounds.js.map +1 -0
- package/dist/canvas/overlays/SelectionOverlay.js +265 -0
- package/dist/canvas/overlays/SelectionOverlay.js.map +1 -0
- package/dist/canvas/overlays/overlayState.js +153 -0
- package/dist/canvas/overlays/overlayState.js.map +1 -0
- package/dist/canvas/selection/SelectionController.js +105 -0
- package/dist/canvas/selection/SelectionController.js.map +1 -0
- package/dist/canvas/selection/SelectionModel.d.ts +98 -0
- package/dist/canvas/selection/SelectionModel.js +229 -0
- package/dist/canvas/selection/SelectionModel.js.map +1 -0
- package/dist/canvas/selection/selectionContext.d.ts +31 -0
- package/dist/canvas/selection/selectionContext.js +12 -0
- package/dist/canvas/selection/selectionContext.js.map +1 -0
- package/dist/elements/ContainerInfo.d.ts +29 -0
- package/dist/elements/ContainerInfo.js +30 -0
- package/dist/elements/ContainerInfo.js.map +1 -0
- package/dist/elements/EFAudio.d.ts +13 -3
- package/dist/elements/EFAudio.js +64 -10
- package/dist/elements/EFAudio.js.map +1 -1
- package/dist/elements/EFCaptions.d.ts +18 -16
- package/dist/elements/EFCaptions.js +110 -19
- package/dist/elements/EFCaptions.js.map +1 -1
- package/dist/elements/EFImage.d.ts +16 -6
- package/dist/elements/EFImage.js +79 -9
- package/dist/elements/EFImage.js.map +1 -1
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +51 -4
- package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/AssetMediaEngine.js +125 -52
- package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BaseMediaEngine.js +24 -6
- package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/JitMediaEngine.js +12 -8
- package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +46 -7
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +98 -73
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +28 -5
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +18 -6
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +8 -2
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +31 -6
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +28 -5
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +97 -72
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js.map +1 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
- package/dist/elements/EFMedia/shared/BufferUtils.js +1 -1
- package/dist/elements/EFMedia/shared/BufferUtils.js.map +1 -1
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +25 -14
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js.map +1 -1
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +47 -16
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +37 -19
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +65 -21
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +8 -3
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js +32 -9
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +33 -10
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +23 -8
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js +34 -10
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +31 -8
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +31 -114
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +44 -8
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js.map +1 -1
- package/dist/elements/EFMedia.d.ts +18 -7
- package/dist/elements/EFMedia.js +23 -3
- package/dist/elements/EFMedia.js.map +1 -1
- package/dist/elements/EFPanZoom.d.ts +96 -0
- package/dist/elements/EFPanZoom.js +290 -0
- package/dist/elements/EFPanZoom.js.map +1 -0
- package/dist/elements/EFSourceMixin.js +7 -6
- package/dist/elements/EFSourceMixin.js.map +1 -1
- package/dist/elements/EFSurface.d.ts +6 -6
- package/dist/elements/EFSurface.js +7 -2
- package/dist/elements/EFSurface.js.map +1 -1
- package/dist/elements/EFTemporal.d.ts +2 -1
- package/dist/elements/EFTemporal.js +192 -71
- package/dist/elements/EFTemporal.js.map +1 -1
- package/dist/elements/EFText.d.ts +5 -4
- package/dist/elements/EFText.js +102 -13
- package/dist/elements/EFText.js.map +1 -1
- package/dist/elements/EFTextSegment.d.ts +32 -6
- package/dist/elements/EFTextSegment.js +53 -15
- package/dist/elements/EFTextSegment.js.map +1 -1
- package/dist/elements/EFThumbnailStrip.d.ts +118 -56
- package/dist/elements/EFThumbnailStrip.js +522 -358
- package/dist/elements/EFThumbnailStrip.js.map +1 -1
- package/dist/elements/EFTimegroup.d.ts +223 -27
- package/dist/elements/EFTimegroup.js +851 -148
- package/dist/elements/EFTimegroup.js.map +1 -1
- package/dist/elements/EFVideo.d.ts +42 -5
- package/dist/elements/EFVideo.js +165 -11
- package/dist/elements/EFVideo.js.map +1 -1
- package/dist/elements/EFWaveform.d.ts +6 -6
- package/dist/elements/EFWaveform.js +2 -1
- package/dist/elements/EFWaveform.js.map +1 -1
- package/dist/elements/ElementPositionInfo.d.ts +35 -0
- package/dist/elements/ElementPositionInfo.js +49 -0
- package/dist/elements/ElementPositionInfo.js.map +1 -0
- package/dist/elements/FetchMixin.js +16 -1
- package/dist/elements/FetchMixin.js.map +1 -1
- package/dist/elements/SessionThumbnailCache.js +152 -0
- package/dist/elements/SessionThumbnailCache.js.map +1 -0
- package/dist/elements/TargetController.js +3 -1
- package/dist/elements/TargetController.js.map +1 -1
- package/dist/elements/TimegroupController.js +9 -3
- package/dist/elements/TimegroupController.js.map +1 -1
- package/dist/elements/findRootTemporal.js +30 -0
- package/dist/elements/findRootTemporal.js.map +1 -0
- package/dist/elements/renderTemporalAudio.js +18 -5
- package/dist/elements/renderTemporalAudio.js.map +1 -1
- package/dist/elements/updateAnimations.js +492 -109
- package/dist/elements/updateAnimations.js.map +1 -1
- package/dist/getRenderInfo.d.ts +2 -2
- package/dist/gui/ContextMixin.js +4 -2
- package/dist/gui/ContextMixin.js.map +1 -1
- package/dist/gui/Controllable.js +74 -1
- package/dist/gui/Controllable.js.map +1 -1
- package/dist/gui/EFActiveRootTemporal.d.ts +50 -0
- package/dist/gui/EFActiveRootTemporal.js +94 -0
- package/dist/gui/EFActiveRootTemporal.js.map +1 -0
- package/dist/gui/EFConfiguration.d.ts +11 -5
- package/dist/gui/EFConfiguration.js.map +1 -1
- package/dist/gui/EFControls.d.ts +2 -2
- package/dist/gui/EFControls.js +109 -13
- package/dist/gui/EFControls.js.map +1 -1
- package/dist/gui/EFDial.d.ts +4 -4
- package/dist/gui/EFFilmstrip.d.ts +11 -214
- package/dist/gui/EFFilmstrip.js +53 -1152
- package/dist/gui/EFFilmstrip.js.map +1 -1
- package/dist/gui/EFFitScale.d.ts +3 -3
- package/dist/gui/EFFitScale.js +39 -12
- package/dist/gui/EFFitScale.js.map +1 -1
- package/dist/gui/EFFocusOverlay.d.ts +4 -4
- package/dist/gui/EFOverlayItem.d.ts +48 -0
- package/dist/gui/EFOverlayItem.js +97 -0
- package/dist/gui/EFOverlayItem.js.map +1 -0
- package/dist/gui/EFOverlayLayer.d.ts +70 -0
- package/dist/gui/EFOverlayLayer.js +104 -0
- package/dist/gui/EFOverlayLayer.js.map +1 -0
- package/dist/gui/EFPause.d.ts +4 -4
- package/dist/gui/EFPlay.d.ts +4 -4
- package/dist/gui/EFPreview.d.ts +4 -4
- package/dist/gui/EFResizableBox.d.ts +12 -16
- package/dist/gui/EFResizableBox.js +109 -451
- package/dist/gui/EFResizableBox.js.map +1 -1
- package/dist/gui/EFScrubber.d.ts +30 -5
- package/dist/gui/EFScrubber.js +224 -31
- package/dist/gui/EFScrubber.js.map +1 -1
- package/dist/gui/EFTimeDisplay.d.ts +4 -4
- package/dist/gui/EFTimeDisplay.js +4 -1
- package/dist/gui/EFTimeDisplay.js.map +1 -1
- package/dist/gui/EFTimelineRuler.d.ts +71 -0
- package/dist/gui/EFTimelineRuler.js +320 -0
- package/dist/gui/EFTimelineRuler.js.map +1 -0
- package/dist/gui/EFToggleLoop.d.ts +4 -4
- package/dist/gui/EFTogglePlay.d.ts +4 -4
- package/dist/gui/EFTransformHandles.d.ts +91 -0
- package/dist/gui/EFTransformHandles.js +393 -0
- package/dist/gui/EFTransformHandles.js.map +1 -0
- package/dist/gui/EFWorkbench.d.ts +182 -4
- package/dist/gui/EFWorkbench.js +2067 -22
- package/dist/gui/EFWorkbench.js.map +1 -1
- package/dist/gui/FitScaleHelpers.d.ts +31 -0
- package/dist/gui/FitScaleHelpers.js +41 -0
- package/dist/gui/FitScaleHelpers.js.map +1 -0
- package/dist/gui/PlaybackController.d.ts +2 -1
- package/dist/gui/PlaybackController.js +46 -15
- package/dist/gui/PlaybackController.js.map +1 -1
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin.js.map +1 -1
- package/dist/gui/hierarchy/EFHierarchy.d.ts +65 -0
- package/dist/gui/hierarchy/EFHierarchy.js +338 -0
- package/dist/gui/hierarchy/EFHierarchy.js.map +1 -0
- package/dist/gui/hierarchy/EFHierarchyItem.d.ts +118 -0
- package/dist/gui/hierarchy/EFHierarchyItem.js +551 -0
- package/dist/gui/hierarchy/EFHierarchyItem.js.map +1 -0
- package/dist/gui/hierarchy/hierarchyContext.d.ts +38 -0
- package/dist/gui/hierarchy/hierarchyContext.js +8 -0
- package/dist/gui/hierarchy/hierarchyContext.js.map +1 -0
- package/dist/gui/icons.js +34 -0
- package/dist/gui/icons.js.map +1 -0
- package/dist/gui/panZoomTransformContext.js +12 -0
- package/dist/gui/panZoomTransformContext.js.map +1 -0
- package/dist/gui/previewSettingsContext.js +12 -0
- package/dist/gui/previewSettingsContext.js.map +1 -0
- package/dist/gui/timeline/EFTimeline.d.ts +270 -0
- package/dist/gui/timeline/EFTimeline.js +1369 -0
- package/dist/gui/timeline/EFTimeline.js.map +1 -0
- package/dist/gui/timeline/EFTimelineRow.js +374 -0
- package/dist/gui/timeline/EFTimelineRow.js.map +1 -0
- package/dist/gui/timeline/TrimHandles.d.ts +36 -0
- package/dist/gui/timeline/TrimHandles.js +204 -0
- package/dist/gui/timeline/TrimHandles.js.map +1 -0
- package/dist/gui/timeline/flattenHierarchy.js +31 -0
- package/dist/gui/timeline/flattenHierarchy.js.map +1 -0
- package/dist/gui/timeline/timelineStateContext.d.ts +26 -0
- package/dist/gui/timeline/timelineStateContext.js +42 -0
- package/dist/gui/timeline/timelineStateContext.js.map +1 -0
- package/dist/gui/timeline/tracks/AudioTrack.js +264 -0
- package/dist/gui/timeline/tracks/AudioTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/CaptionsTrack.js +595 -0
- package/dist/gui/timeline/tracks/CaptionsTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/HTMLTrack.js +19 -0
- package/dist/gui/timeline/tracks/HTMLTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/ImageTrack.js +53 -0
- package/dist/gui/timeline/tracks/ImageTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/TextTrack.js +250 -0
- package/dist/gui/timeline/tracks/TextTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/TimegroupTrack.js +143 -0
- package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/TrackItem.js +269 -0
- package/dist/gui/timeline/tracks/TrackItem.js.map +1 -0
- package/dist/gui/timeline/tracks/VideoTrack.js +265 -0
- package/dist/gui/timeline/tracks/VideoTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/WaveformTrack.js +19 -0
- package/dist/gui/timeline/tracks/WaveformTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/ensureTrackItemInit.js +1 -0
- package/dist/gui/timeline/tracks/preloadTracks.js +9 -0
- package/dist/gui/timeline/tracks/renderTrackChildren.js +119 -0
- package/dist/gui/timeline/tracks/renderTrackChildren.js.map +1 -0
- package/dist/gui/timeline/tracks/waveformUtils.js +80 -0
- package/dist/gui/timeline/tracks/waveformUtils.js.map +1 -0
- package/dist/gui/transformCalculations.js +217 -0
- package/dist/gui/transformCalculations.js.map +1 -0
- package/dist/gui/transformUtils.d.ts +37 -0
- package/dist/gui/transformUtils.js +77 -0
- package/dist/gui/transformUtils.js.map +1 -0
- package/dist/gui/tree/EFTree.d.ts +59 -0
- package/dist/gui/tree/EFTree.js +174 -0
- package/dist/gui/tree/EFTree.js.map +1 -0
- package/dist/gui/tree/EFTreeItem.d.ts +38 -0
- package/dist/gui/tree/EFTreeItem.js +146 -0
- package/dist/gui/tree/EFTreeItem.js.map +1 -0
- package/dist/gui/tree/treeContext.d.ts +60 -0
- package/dist/gui/tree/treeContext.js +23 -0
- package/dist/gui/tree/treeContext.js.map +1 -0
- package/dist/index.d.ts +32 -8
- package/dist/index.js +30 -6
- package/dist/index.js.map +1 -1
- package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +688 -0
- package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +1 -0
- package/dist/node_modules/react/cjs/react.development.js +1521 -0
- package/dist/node_modules/react/cjs/react.development.js.map +1 -0
- package/dist/node_modules/react/index.js +13 -0
- package/dist/node_modules/react/index.js.map +1 -0
- package/dist/node_modules/react/jsx-runtime.js +13 -0
- package/dist/node_modules/react/jsx-runtime.js.map +1 -0
- package/dist/preview/AdaptiveResolutionTracker.js +228 -0
- package/dist/preview/AdaptiveResolutionTracker.js.map +1 -0
- package/dist/preview/RenderProfiler.js +135 -0
- package/dist/preview/RenderProfiler.js.map +1 -0
- package/dist/preview/previewSettings.js +131 -0
- package/dist/preview/previewSettings.js.map +1 -0
- package/dist/preview/previewTypes.js +64 -0
- package/dist/preview/previewTypes.js.map +1 -0
- package/dist/preview/renderTimegroupPreview.js +656 -0
- package/dist/preview/renderTimegroupPreview.js.map +1 -0
- package/dist/preview/renderTimegroupToCanvas.d.ts +37 -0
- package/dist/preview/renderTimegroupToCanvas.js +840 -0
- package/dist/preview/renderTimegroupToCanvas.js.map +1 -0
- package/dist/preview/renderTimegroupToVideo.d.ts +39 -0
- package/dist/preview/renderTimegroupToVideo.js +274 -0
- package/dist/preview/renderTimegroupToVideo.js.map +1 -0
- package/dist/preview/renderers.js +16 -0
- package/dist/preview/renderers.js.map +1 -0
- package/dist/preview/statsTrackingStrategy.js +201 -0
- package/dist/preview/statsTrackingStrategy.js.map +1 -0
- package/dist/preview/thumbnailCacheSettings.js +52 -0
- package/dist/preview/thumbnailCacheSettings.js.map +1 -0
- package/dist/preview/workers/WorkerPool.js +178 -0
- package/dist/preview/workers/WorkerPool.js.map +1 -0
- package/dist/sandbox/PlaybackControls.js +10 -0
- package/dist/sandbox/PlaybackControls.js.map +1 -0
- package/dist/sandbox/ScenarioRunner.js +1 -0
- package/dist/sandbox/index.js +2 -0
- package/dist/style.css +66 -69
- package/dist/transcoding/types/index.d.ts +2 -1
- package/dist/transcoding/utils/UrlGenerator.d.ts +6 -1
- package/dist/transcoding/utils/UrlGenerator.js +12 -3
- package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
- package/dist/utils/LRUCache.js +1 -375
- package/dist/utils/LRUCache.js.map +1 -1
- package/dist/utils/frameTime.js +14 -0
- package/dist/utils/frameTime.js.map +1 -0
- package/package.json +3 -3
- package/test/profilingPlugin.ts +223 -0
- package/test/recordReplayProxyPlugin.js +22 -27
- package/test/thumbnail-performance-test.html +116 -0
- package/test/visualRegressionUtils.ts +286 -0
- package/types.json +1 -1
- package/dist/elements/TimegroupController.d.ts +0 -18
- package/dist/msToTimeCode.js +0 -17
- package/dist/msToTimeCode.js.map +0 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
//#region src/canvas/api/CanvasAPI.ts
|
|
2
|
+
/**
|
|
3
|
+
* Programmatic API/SDK for canvas operations.
|
|
4
|
+
*/
|
|
5
|
+
var CanvasAPI = class {
|
|
6
|
+
constructor(canvas) {
|
|
7
|
+
this.canvas = canvas;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Register an existing element for canvas management.
|
|
11
|
+
* @param element - The HTML element to register
|
|
12
|
+
* @param id - Optional custom ID, otherwise auto-generated
|
|
13
|
+
* @returns The element ID
|
|
14
|
+
*/
|
|
15
|
+
registerElement(element, id) {
|
|
16
|
+
return this.canvas.registerElement(element, id);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Unregister an element from canvas management.
|
|
20
|
+
* @param id - Element ID or element itself
|
|
21
|
+
*/
|
|
22
|
+
unregisterElement(id) {
|
|
23
|
+
this.canvas.unregisterElement(id);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Update element position/transform in canvas coordinates.
|
|
27
|
+
* @param id - Element ID
|
|
28
|
+
* @param updates - Partial element data to update
|
|
29
|
+
*/
|
|
30
|
+
updateElement(id, updates) {
|
|
31
|
+
const current = this.getElement(id);
|
|
32
|
+
if (!current) throw new Error(`Element ${id} not found`);
|
|
33
|
+
if (updates.x !== void 0 || updates.y !== void 0) {
|
|
34
|
+
const x = updates.x !== void 0 ? updates.x : current.x;
|
|
35
|
+
const y = updates.y !== void 0 ? updates.y : current.y;
|
|
36
|
+
this.canvas.updateElementPosition(id, x, y);
|
|
37
|
+
}
|
|
38
|
+
if (updates.width !== void 0 || updates.height !== void 0) {
|
|
39
|
+
const element = current.element;
|
|
40
|
+
const width = updates.width !== void 0 ? updates.width : current.width;
|
|
41
|
+
const height = updates.height !== void 0 ? updates.height : current.height;
|
|
42
|
+
element.style.width = `${width}px`;
|
|
43
|
+
element.style.height = `${height}px`;
|
|
44
|
+
}
|
|
45
|
+
if (updates.rotation !== void 0) {
|
|
46
|
+
const element = current.element;
|
|
47
|
+
element.style.transform = `rotate(${updates.rotation}deg)`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get element data by ID.
|
|
52
|
+
* @param id - Element ID
|
|
53
|
+
* @returns Element data or null if not found
|
|
54
|
+
*/
|
|
55
|
+
getElement(id) {
|
|
56
|
+
return this.canvas.getElementData(id);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get all registered elements.
|
|
60
|
+
* @returns Array of all element data
|
|
61
|
+
*/
|
|
62
|
+
getAllElements() {
|
|
63
|
+
return this.canvas.getAllElementsData();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get the number of registered elements.
|
|
67
|
+
* @returns The count of registered elements
|
|
68
|
+
*/
|
|
69
|
+
get elementCount() {
|
|
70
|
+
return this.getAllElements().length;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get all registered elements (getter alias for getAllElements).
|
|
74
|
+
* @returns Array of all element data
|
|
75
|
+
*/
|
|
76
|
+
get elements() {
|
|
77
|
+
return this.getAllElements();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Convert screen coordinates to canvas coordinates.
|
|
81
|
+
* @param screenX - X coordinate in screen space
|
|
82
|
+
* @param screenY - Y coordinate in screen space
|
|
83
|
+
* @returns Canvas coordinates
|
|
84
|
+
*/
|
|
85
|
+
screenToCanvas(screenX, screenY) {
|
|
86
|
+
return this.canvas.screenToCanvasCoords(screenX, screenY);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Convert canvas coordinates to screen coordinates.
|
|
90
|
+
* @param canvasX - X coordinate in canvas space
|
|
91
|
+
* @param canvasY - Y coordinate in canvas space
|
|
92
|
+
* @returns Screen coordinates
|
|
93
|
+
*/
|
|
94
|
+
canvasToScreen(canvasX, canvasY) {
|
|
95
|
+
return this.canvas.canvasToScreenCoords(canvasX, canvasY);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Select an element.
|
|
99
|
+
* @param id - Element ID
|
|
100
|
+
*/
|
|
101
|
+
select(id) {
|
|
102
|
+
this.canvas.selectionController.getModel().select(id);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Select multiple elements.
|
|
106
|
+
* @param ids - Array of element IDs
|
|
107
|
+
*/
|
|
108
|
+
selectMultiple(ids) {
|
|
109
|
+
this.canvas.selectionController.getModel().selectMultiple(ids);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Deselect an element.
|
|
113
|
+
* @param id - Element ID
|
|
114
|
+
*/
|
|
115
|
+
deselect(id) {
|
|
116
|
+
this.canvas.selectionController.getModel().deselect(id);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get currently selected element IDs.
|
|
120
|
+
* @returns Set of selected IDs
|
|
121
|
+
*/
|
|
122
|
+
getSelectedIds() {
|
|
123
|
+
const controller = this.canvas.selectionController;
|
|
124
|
+
return Array.from(controller.getModel().selectedIds);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Create a group from element IDs.
|
|
128
|
+
* @param ids - Array of element IDs to group
|
|
129
|
+
* @returns Group ID
|
|
130
|
+
*/
|
|
131
|
+
group(ids) {
|
|
132
|
+
return this.canvas.selectionController.getModel().createGroup(ids);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Ungroup a group.
|
|
136
|
+
* @param groupId - Group ID
|
|
137
|
+
*/
|
|
138
|
+
ungroup(groupId) {
|
|
139
|
+
this.canvas.selectionController.getModel().ungroup(groupId);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Export canvas data.
|
|
143
|
+
* @returns Canvas data structure
|
|
144
|
+
*/
|
|
145
|
+
export() {
|
|
146
|
+
const model = this.canvas.selectionController.getModel();
|
|
147
|
+
const groups = [];
|
|
148
|
+
const processedGroups = /* @__PURE__ */ new Set();
|
|
149
|
+
for (const elementId of this.getAllElements().map((e) => e.id)) {
|
|
150
|
+
const groupId = model.getGroupId(elementId);
|
|
151
|
+
if (groupId && !processedGroups.has(groupId)) {
|
|
152
|
+
processedGroups.add(groupId);
|
|
153
|
+
groups.push({
|
|
154
|
+
id: groupId,
|
|
155
|
+
elementIds: model.getGroupElements(groupId)
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
elements: this.getAllElements(),
|
|
161
|
+
groups
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Import canvas data.
|
|
166
|
+
* @param data - Canvas data structure
|
|
167
|
+
*/
|
|
168
|
+
import(data) {
|
|
169
|
+
for (const element of this.getAllElements()) this.unregisterElement(element.id);
|
|
170
|
+
for (const elementData of data.elements) {
|
|
171
|
+
const element = elementData.element;
|
|
172
|
+
this.registerElement(element, elementData.id);
|
|
173
|
+
this.updateElement(elementData.id, elementData);
|
|
174
|
+
}
|
|
175
|
+
const controller = this.canvas.selectionController;
|
|
176
|
+
for (const group of data.groups) controller.getModel().createGroup(group.elementIds);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
//#endregion
|
|
181
|
+
export { CanvasAPI };
|
|
182
|
+
//# sourceMappingURL=CanvasAPI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CanvasAPI.js","names":["canvas: EFCanvas","groups: Array<{ id: string; elementIds: string[] }>"],"sources":["../../../src/canvas/api/CanvasAPI.ts"],"sourcesContent":["import type { EFCanvas } from \"../EFCanvas.js\";\nimport type { CanvasElementData, CanvasData } from \"./types.js\";\nimport { SelectionModel } from \"../selection/SelectionModel.js\";\n\n/**\n * Programmatic API/SDK for canvas operations.\n */\nexport class CanvasAPI {\n constructor(private canvas: EFCanvas) {}\n\n /**\n * Register an existing element for canvas management.\n * @param element - The HTML element to register\n * @param id - Optional custom ID, otherwise auto-generated\n * @returns The element ID\n */\n registerElement(element: HTMLElement, id?: string): string {\n return (this.canvas as any).registerElement(element, id);\n }\n\n /**\n * Unregister an element from canvas management.\n * @param id - Element ID or element itself\n */\n unregisterElement(id: string | HTMLElement): void {\n (this.canvas as any).unregisterElement(id);\n }\n\n /**\n * Update element position/transform in canvas coordinates.\n * @param id - Element ID\n * @param updates - Partial element data to update\n */\n updateElement(id: string, updates: Partial<CanvasElementData>): void {\n const current = this.getElement(id);\n if (!current) {\n throw new Error(`Element ${id} not found`);\n }\n\n if (updates.x !== undefined || updates.y !== undefined) {\n const x = updates.x !== undefined ? updates.x : current.x;\n const y = updates.y !== undefined ? updates.y : current.y;\n (this.canvas as any).updateElementPosition(id, x, y);\n }\n\n if (updates.width !== undefined || updates.height !== undefined) {\n const element = current.element;\n const width = updates.width !== undefined ? updates.width : current.width;\n const height =\n updates.height !== undefined ? updates.height : current.height;\n // Set size in canvas coordinates (parent transform handles scaling)\n element.style.width = `${width}px`;\n element.style.height = `${height}px`;\n }\n\n if (updates.rotation !== undefined) {\n const element = current.element;\n element.style.transform = `rotate(${updates.rotation}deg)`;\n }\n }\n\n /**\n * Get element data by ID.\n * @param id - Element ID\n * @returns Element data or null if not found\n */\n getElement(id: string): CanvasElementData | null {\n return (this.canvas as any).getElementData(id);\n }\n\n /**\n * Get all registered elements.\n * @returns Array of all element data\n */\n getAllElements(): CanvasElementData[] {\n return (this.canvas as any).getAllElementsData();\n }\n\n /**\n * Get the number of registered elements.\n * @returns The count of registered elements\n */\n get elementCount(): number {\n return this.getAllElements().length;\n }\n\n /**\n * Get all registered elements (getter alias for getAllElements).\n * @returns Array of all element data\n */\n get elements(): CanvasElementData[] {\n return this.getAllElements();\n }\n\n /**\n * Convert screen coordinates to canvas coordinates.\n * @param screenX - X coordinate in screen space\n * @param screenY - Y coordinate in screen space\n * @returns Canvas coordinates\n */\n screenToCanvas(screenX: number, screenY: number): { x: number; y: number } {\n return (this.canvas as any).screenToCanvasCoords(screenX, screenY);\n }\n\n /**\n * Convert canvas coordinates to screen coordinates.\n * @param canvasX - X coordinate in canvas space\n * @param canvasY - Y coordinate in canvas space\n * @returns Screen coordinates\n */\n canvasToScreen(canvasX: number, canvasY: number): { x: number; y: number } {\n return (this.canvas as any).canvasToScreenCoords(canvasX, canvasY);\n }\n\n /**\n * Select an element.\n * @param id - Element ID\n */\n select(id: string): void {\n const controller = (this.canvas as any).selectionController as {\n getModel(): SelectionModel;\n };\n controller.getModel().select(id);\n // Update is deferred via selectionchange event listener\n }\n\n /**\n * Select multiple elements.\n * @param ids - Array of element IDs\n */\n selectMultiple(ids: string[]): void {\n const controller = (this.canvas as any).selectionController as {\n getModel(): SelectionModel;\n };\n controller.getModel().selectMultiple(ids);\n // Update is deferred via selectionchange event listener\n }\n\n /**\n * Deselect an element.\n * @param id - Element ID\n */\n deselect(id: string): void {\n const controller = (this.canvas as any).selectionController as {\n getModel(): SelectionModel;\n };\n controller.getModel().deselect(id);\n // Update is deferred via selectionchange event listener\n }\n\n /**\n * Get currently selected element IDs.\n * @returns Set of selected IDs\n */\n getSelectedIds(): string[] {\n const controller = (this.canvas as any).selectionController as {\n getModel(): SelectionModel;\n };\n return Array.from(controller.getModel().selectedIds);\n }\n\n /**\n * Create a group from element IDs.\n * @param ids - Array of element IDs to group\n * @returns Group ID\n */\n group(ids: string[]): string {\n const controller = (this.canvas as any).selectionController as {\n getModel(): SelectionModel;\n };\n const groupId = controller.getModel().createGroup(ids);\n // Update is deferred via selectionchange event listener\n return groupId;\n }\n\n /**\n * Ungroup a group.\n * @param groupId - Group ID\n */\n ungroup(groupId: string): void {\n const controller = (this.canvas as any).selectionController as {\n getModel(): SelectionModel;\n };\n controller.getModel().ungroup(groupId);\n // Update is deferred via selectionchange event listener\n }\n\n /**\n * Export canvas data.\n * @returns Canvas data structure\n */\n export(): CanvasData {\n const controller = (this.canvas as any).selectionController as {\n getModel(): SelectionModel;\n };\n const model = controller.getModel();\n const groups: Array<{ id: string; elementIds: string[] }> = [];\n\n // Collect all groups\n const processedGroups = new Set<string>();\n for (const elementId of this.getAllElements().map((e) => e.id)) {\n const groupId = model.getGroupId(elementId);\n if (groupId && !processedGroups.has(groupId)) {\n processedGroups.add(groupId);\n groups.push({\n id: groupId,\n elementIds: model.getGroupElements(groupId),\n });\n }\n }\n\n return {\n elements: this.getAllElements(),\n groups,\n };\n }\n\n /**\n * Import canvas data.\n * @param data - Canvas data structure\n */\n import(data: CanvasData): void {\n // Clear existing\n for (const element of this.getAllElements()) {\n this.unregisterElement(element.id);\n }\n\n // Import elements\n for (const elementData of data.elements) {\n const element = elementData.element;\n this.registerElement(element, elementData.id);\n this.updateElement(elementData.id, elementData);\n }\n\n // Import groups\n const controller = (this.canvas as any).selectionController as {\n getModel(): SelectionModel;\n };\n for (const group of data.groups) {\n controller.getModel().createGroup(group.elementIds);\n }\n }\n}\n"],"mappings":";;;;AAOA,IAAa,YAAb,MAAuB;CACrB,YAAY,AAAQA,QAAkB;EAAlB;;;;;;;;CAQpB,gBAAgB,SAAsB,IAAqB;AACzD,SAAQ,KAAK,OAAe,gBAAgB,SAAS,GAAG;;;;;;CAO1D,kBAAkB,IAAgC;AAChD,EAAC,KAAK,OAAe,kBAAkB,GAAG;;;;;;;CAQ5C,cAAc,IAAY,SAA2C;EACnE,MAAM,UAAU,KAAK,WAAW,GAAG;AACnC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,WAAW,GAAG,YAAY;AAG5C,MAAI,QAAQ,MAAM,UAAa,QAAQ,MAAM,QAAW;GACtD,MAAM,IAAI,QAAQ,MAAM,SAAY,QAAQ,IAAI,QAAQ;GACxD,MAAM,IAAI,QAAQ,MAAM,SAAY,QAAQ,IAAI,QAAQ;AACxD,GAAC,KAAK,OAAe,sBAAsB,IAAI,GAAG,EAAE;;AAGtD,MAAI,QAAQ,UAAU,UAAa,QAAQ,WAAW,QAAW;GAC/D,MAAM,UAAU,QAAQ;GACxB,MAAM,QAAQ,QAAQ,UAAU,SAAY,QAAQ,QAAQ,QAAQ;GACpE,MAAM,SACJ,QAAQ,WAAW,SAAY,QAAQ,SAAS,QAAQ;AAE1D,WAAQ,MAAM,QAAQ,GAAG,MAAM;AAC/B,WAAQ,MAAM,SAAS,GAAG,OAAO;;AAGnC,MAAI,QAAQ,aAAa,QAAW;GAClC,MAAM,UAAU,QAAQ;AACxB,WAAQ,MAAM,YAAY,UAAU,QAAQ,SAAS;;;;;;;;CASzD,WAAW,IAAsC;AAC/C,SAAQ,KAAK,OAAe,eAAe,GAAG;;;;;;CAOhD,iBAAsC;AACpC,SAAQ,KAAK,OAAe,oBAAoB;;;;;;CAOlD,IAAI,eAAuB;AACzB,SAAO,KAAK,gBAAgB,CAAC;;;;;;CAO/B,IAAI,WAAgC;AAClC,SAAO,KAAK,gBAAgB;;;;;;;;CAS9B,eAAe,SAAiB,SAA2C;AACzE,SAAQ,KAAK,OAAe,qBAAqB,SAAS,QAAQ;;;;;;;;CASpE,eAAe,SAAiB,SAA2C;AACzE,SAAQ,KAAK,OAAe,qBAAqB,SAAS,QAAQ;;;;;;CAOpE,OAAO,IAAkB;AAIvB,EAHoB,KAAK,OAAe,oBAG7B,UAAU,CAAC,OAAO,GAAG;;;;;;CAQlC,eAAe,KAAqB;AAIlC,EAHoB,KAAK,OAAe,oBAG7B,UAAU,CAAC,eAAe,IAAI;;;;;;CAQ3C,SAAS,IAAkB;AAIzB,EAHoB,KAAK,OAAe,oBAG7B,UAAU,CAAC,SAAS,GAAG;;;;;;CAQpC,iBAA2B;EACzB,MAAM,aAAc,KAAK,OAAe;AAGxC,SAAO,MAAM,KAAK,WAAW,UAAU,CAAC,YAAY;;;;;;;CAQtD,MAAM,KAAuB;AAM3B,SALoB,KAAK,OAAe,oBAGb,UAAU,CAAC,YAAY,IAAI;;;;;;CASxD,QAAQ,SAAuB;AAI7B,EAHoB,KAAK,OAAe,oBAG7B,UAAU,CAAC,QAAQ,QAAQ;;;;;;CAQxC,SAAqB;EAInB,MAAM,QAHc,KAAK,OAAe,oBAGf,UAAU;EACnC,MAAMC,SAAsD,EAAE;EAG9D,MAAM,kCAAkB,IAAI,KAAa;AACzC,OAAK,MAAM,aAAa,KAAK,gBAAgB,CAAC,KAAK,MAAM,EAAE,GAAG,EAAE;GAC9D,MAAM,UAAU,MAAM,WAAW,UAAU;AAC3C,OAAI,WAAW,CAAC,gBAAgB,IAAI,QAAQ,EAAE;AAC5C,oBAAgB,IAAI,QAAQ;AAC5B,WAAO,KAAK;KACV,IAAI;KACJ,YAAY,MAAM,iBAAiB,QAAQ;KAC5C,CAAC;;;AAIN,SAAO;GACL,UAAU,KAAK,gBAAgB;GAC/B;GACD;;;;;;CAOH,OAAO,MAAwB;AAE7B,OAAK,MAAM,WAAW,KAAK,gBAAgB,CACzC,MAAK,kBAAkB,QAAQ,GAAG;AAIpC,OAAK,MAAM,eAAe,KAAK,UAAU;GACvC,MAAM,UAAU,YAAY;AAC5B,QAAK,gBAAgB,SAAS,YAAY,GAAG;AAC7C,QAAK,cAAc,YAAY,IAAI,YAAY;;EAIjD,MAAM,aAAc,KAAK,OAAe;AAGxC,OAAK,MAAM,SAAS,KAAK,OACvB,YAAW,UAAU,CAAC,YAAY,MAAM,WAAW"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/canvas/api/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Core types for the canvas system.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Selection state enumeration.
|
|
7
|
+
*/
|
|
8
|
+
type SelectionState = "none" | "single" | "multiple" | "box-selecting";
|
|
9
|
+
/**
|
|
10
|
+
* Element bounds interface - elements can implement this to override default bounding rect.
|
|
11
|
+
* This allows elements to provide custom hit testing areas or account for visual bounds
|
|
12
|
+
* that differ from DOM bounds.
|
|
13
|
+
*/
|
|
14
|
+
interface CanvasElementBounds {
|
|
15
|
+
getCanvasBounds(): DOMRect;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Canvas element metadata for API/manipulation.
|
|
19
|
+
* Positions and dimensions are in canvas coordinate space.
|
|
20
|
+
*/
|
|
21
|
+
interface CanvasElementData {
|
|
22
|
+
id: string;
|
|
23
|
+
element: HTMLElement;
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
rotation?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Canvas data structure for export/import.
|
|
32
|
+
*/
|
|
33
|
+
interface CanvasData {
|
|
34
|
+
elements: CanvasElementData[];
|
|
35
|
+
groups: Array<{
|
|
36
|
+
id: string;
|
|
37
|
+
elementIds: string[];
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { CanvasData, CanvasElementBounds, CanvasElementData, SelectionState };
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
//#region src/canvas/coordinateTransform.ts
|
|
2
|
+
/**
|
|
3
|
+
* =============================================================================
|
|
4
|
+
* COORDINATE SPACES
|
|
5
|
+
* =============================================================================
|
|
6
|
+
*
|
|
7
|
+
* This module provides utilities for converting between two coordinate spaces:
|
|
8
|
+
*
|
|
9
|
+
* 1. SCREEN SPACE (viewport coordinates)
|
|
10
|
+
* - Origin: Top-left of browser viewport
|
|
11
|
+
* - Units: Physical screen pixels
|
|
12
|
+
* - Used by: getBoundingClientRect(), mouse events (clientX/clientY)
|
|
13
|
+
* - AFFECTED by: zoom/scale transforms
|
|
14
|
+
*
|
|
15
|
+
* 2. CANVAS SPACE (logical coordinates)
|
|
16
|
+
* - Origin: Top-left of the canvas content area
|
|
17
|
+
* - Units: CSS pixels at 1:1 scale (unaffected by zoom)
|
|
18
|
+
* - Used by: Element positioning (style.left/top), metadata storage
|
|
19
|
+
* - NOT AFFECTED by: zoom/scale transforms
|
|
20
|
+
*
|
|
21
|
+
* KEY RELATIONSHIP:
|
|
22
|
+
* screenPosition = canvasRect.origin + (canvasPosition * scale)
|
|
23
|
+
* canvasPosition = (screenPosition - canvasRect.origin) / scale
|
|
24
|
+
*
|
|
25
|
+
* IMPORTANT: These functions convert POSITIONS, not DIMENSIONS.
|
|
26
|
+
*
|
|
27
|
+
* For positions (like element center or mouse coordinates):
|
|
28
|
+
* - Use screenToCanvas() / canvasToScreen() for conversion
|
|
29
|
+
*
|
|
30
|
+
* For dimensions (like element width/height):
|
|
31
|
+
* - Screen dimensions = canvas dimensions * scale
|
|
32
|
+
* - Canvas dimensions = screen dimensions / scale
|
|
33
|
+
* - OR better: use offsetWidth/offsetHeight which are already in canvas space
|
|
34
|
+
*
|
|
35
|
+
* =============================================================================
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* Convert screen coordinates to canvas coordinates.
|
|
39
|
+
*
|
|
40
|
+
* Use this for converting POSITIONS from screen space (getBoundingClientRect,
|
|
41
|
+
* mouse events) to canvas space (element positioning, metadata).
|
|
42
|
+
*
|
|
43
|
+
* Example: Converting a click position to canvas coordinates for hit testing.
|
|
44
|
+
* Example: Converting element center from screen to canvas for metadata.
|
|
45
|
+
*
|
|
46
|
+
* @param screenX - X coordinate in screen space (e.g., event.clientX, rect.left)
|
|
47
|
+
* @param screenY - Y coordinate in screen space (e.g., event.clientY, rect.top)
|
|
48
|
+
* @param canvasRect - Canvas content element's bounding rect (.canvas-content, not <ef-canvas>)
|
|
49
|
+
* @param panZoomTransform - Optional PanZoom transform from context
|
|
50
|
+
* @returns Object with x, y in canvas coordinate space
|
|
51
|
+
*/
|
|
52
|
+
function screenToCanvas(screenX, screenY, canvasRect, panZoomTransform) {
|
|
53
|
+
if (!panZoomTransform) return {
|
|
54
|
+
x: screenX - canvasRect.left,
|
|
55
|
+
y: screenY - canvasRect.top
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
x: (screenX - canvasRect.left) / panZoomTransform.scale,
|
|
59
|
+
y: (screenY - canvasRect.top) / panZoomTransform.scale
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Convert canvas coordinates to screen coordinates.
|
|
64
|
+
*
|
|
65
|
+
* Use this for converting POSITIONS from canvas space (element positioning,
|
|
66
|
+
* metadata) to screen space (overlay positioning, visual display).
|
|
67
|
+
*
|
|
68
|
+
* Example: Converting element top-left from metadata to screen position for overlays.
|
|
69
|
+
* Example: Converting a canvas point to screen coordinates for rendering guides.
|
|
70
|
+
*
|
|
71
|
+
* @param canvasX - X coordinate in canvas space (from metadata or style.left)
|
|
72
|
+
* @param canvasY - Y coordinate in canvas space (from metadata or style.top)
|
|
73
|
+
* @param canvasRect - Canvas content element's bounding rect (.canvas-content, not <ef-canvas>)
|
|
74
|
+
* @param panZoomTransform - Optional PanZoom transform from context
|
|
75
|
+
* @returns Object with x, y in screen coordinate space
|
|
76
|
+
*/
|
|
77
|
+
function canvasToScreen(canvasX, canvasY, canvasRect, panZoomTransform) {
|
|
78
|
+
if (!panZoomTransform) return {
|
|
79
|
+
x: canvasRect.left + canvasX,
|
|
80
|
+
y: canvasRect.top + canvasY
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
x: canvasRect.left + canvasX * panZoomTransform.scale,
|
|
84
|
+
y: canvasRect.top + canvasY * panZoomTransform.scale
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
export { canvasToScreen, screenToCanvas };
|
|
90
|
+
//# sourceMappingURL=coordinateTransform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordinateTransform.js","names":[],"sources":["../../src/canvas/coordinateTransform.ts"],"sourcesContent":["import type { PanZoomTransform } from \"../elements/EFPanZoom.js\";\n\n/**\n * =============================================================================\n * COORDINATE SPACES\n * =============================================================================\n *\n * This module provides utilities for converting between two coordinate spaces:\n *\n * 1. SCREEN SPACE (viewport coordinates)\n * - Origin: Top-left of browser viewport\n * - Units: Physical screen pixels\n * - Used by: getBoundingClientRect(), mouse events (clientX/clientY)\n * - AFFECTED by: zoom/scale transforms\n *\n * 2. CANVAS SPACE (logical coordinates)\n * - Origin: Top-left of the canvas content area\n * - Units: CSS pixels at 1:1 scale (unaffected by zoom)\n * - Used by: Element positioning (style.left/top), metadata storage\n * - NOT AFFECTED by: zoom/scale transforms\n *\n * KEY RELATIONSHIP:\n * screenPosition = canvasRect.origin + (canvasPosition * scale)\n * canvasPosition = (screenPosition - canvasRect.origin) / scale\n *\n * IMPORTANT: These functions convert POSITIONS, not DIMENSIONS.\n *\n * For positions (like element center or mouse coordinates):\n * - Use screenToCanvas() / canvasToScreen() for conversion\n *\n * For dimensions (like element width/height):\n * - Screen dimensions = canvas dimensions * scale\n * - Canvas dimensions = screen dimensions / scale\n * - OR better: use offsetWidth/offsetHeight which are already in canvas space\n *\n * =============================================================================\n */\n\n/**\n * Convert screen coordinates to canvas coordinates.\n *\n * Use this for converting POSITIONS from screen space (getBoundingClientRect,\n * mouse events) to canvas space (element positioning, metadata).\n *\n * Example: Converting a click position to canvas coordinates for hit testing.\n * Example: Converting element center from screen to canvas for metadata.\n *\n * @param screenX - X coordinate in screen space (e.g., event.clientX, rect.left)\n * @param screenY - Y coordinate in screen space (e.g., event.clientY, rect.top)\n * @param canvasRect - Canvas content element's bounding rect (.canvas-content, not <ef-canvas>)\n * @param panZoomTransform - Optional PanZoom transform from context\n * @returns Object with x, y in canvas coordinate space\n */\nexport function screenToCanvas(\n screenX: number,\n screenY: number,\n canvasRect: DOMRect,\n panZoomTransform?: PanZoomTransform,\n): { x: number; y: number } {\n if (!panZoomTransform) {\n return {\n x: screenX - canvasRect.left,\n y: screenY - canvasRect.top,\n };\n }\n // canvasRect already includes the panzoom transform (since canvas is inside .content-wrapper)\n // So we only need to:\n // 1. Get position relative to canvas in screen space: screenX - canvasRect.left\n // 2. Divide by scale to get canvas coordinates\n // We don't need to subtract panZoomTransform.x/y because it's already accounted for in canvasRect\n return {\n x: (screenX - canvasRect.left) / panZoomTransform.scale,\n y: (screenY - canvasRect.top) / panZoomTransform.scale,\n };\n}\n\n/**\n * Convert canvas coordinates to screen coordinates.\n *\n * Use this for converting POSITIONS from canvas space (element positioning,\n * metadata) to screen space (overlay positioning, visual display).\n *\n * Example: Converting element top-left from metadata to screen position for overlays.\n * Example: Converting a canvas point to screen coordinates for rendering guides.\n *\n * @param canvasX - X coordinate in canvas space (from metadata or style.left)\n * @param canvasY - Y coordinate in canvas space (from metadata or style.top)\n * @param canvasRect - Canvas content element's bounding rect (.canvas-content, not <ef-canvas>)\n * @param panZoomTransform - Optional PanZoom transform from context\n * @returns Object with x, y in screen coordinate space\n */\nexport function canvasToScreen(\n canvasX: number,\n canvasY: number,\n canvasRect: DOMRect,\n panZoomTransform?: PanZoomTransform,\n): { x: number; y: number } {\n if (!panZoomTransform) {\n return {\n x: canvasRect.left + canvasX,\n y: canvasRect.top + canvasY,\n };\n }\n // canvasRect already includes the panzoom transform (since canvas is inside .content-wrapper)\n // So we only need to:\n // 1. Multiply canvas coordinates by scale to get screen-space offset\n // 2. Add to canvasRect.left/top (which already includes pan)\n // We don't need to add panZoomTransform.x/y because it's already accounted for in canvasRect\n return {\n x: canvasRect.left + canvasX * panZoomTransform.scale,\n y: canvasRect.top + canvasY * panZoomTransform.scale,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,SAAgB,eACd,SACA,SACA,YACA,kBAC0B;AAC1B,KAAI,CAAC,iBACH,QAAO;EACL,GAAG,UAAU,WAAW;EACxB,GAAG,UAAU,WAAW;EACzB;AAOH,QAAO;EACL,IAAI,UAAU,WAAW,QAAQ,iBAAiB;EAClD,IAAI,UAAU,WAAW,OAAO,iBAAiB;EAClD;;;;;;;;;;;;;;;;;AAkBH,SAAgB,eACd,SACA,SACA,YACA,kBAC0B;AAC1B,KAAI,CAAC,iBACH,QAAO;EACL,GAAG,WAAW,OAAO;EACrB,GAAG,WAAW,MAAM;EACrB;AAOH,QAAO;EACL,GAAG,WAAW,OAAO,UAAU,iBAAiB;EAChD,GAAG,WAAW,MAAM,UAAU,iBAAiB;EAChD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/canvas/getElementBounds.ts
|
|
2
|
+
/**
|
|
3
|
+
* Get element bounds using the CanvasElementBounds protocol if available,
|
|
4
|
+
* otherwise fall back to getBoundingClientRect().
|
|
5
|
+
*
|
|
6
|
+
* This allows elements to provide custom hit testing areas or account for
|
|
7
|
+
* visual bounds that differ from DOM bounds.
|
|
8
|
+
*
|
|
9
|
+
* IMPORTANT: This returns a DOMRect in SCREEN SPACE (like getBoundingClientRect).
|
|
10
|
+
*
|
|
11
|
+
* For ROTATED elements, the returned rect is the AXIS-ALIGNED BOUNDING BOX:
|
|
12
|
+
* - rect.width/height are the bounding box dimensions, NOT the element's actual dimensions
|
|
13
|
+
* - rect.left/top are the bounding box corner, NOT the element's visual top-left
|
|
14
|
+
*
|
|
15
|
+
* CORRECT USAGE:
|
|
16
|
+
*
|
|
17
|
+
* ✅ Getting element CENTER (rotation-invariant):
|
|
18
|
+
* const rect = getElementBounds(element);
|
|
19
|
+
* const centerX = rect.left + rect.width / 2;
|
|
20
|
+
* const centerY = rect.top + rect.height / 2;
|
|
21
|
+
*
|
|
22
|
+
* ✅ Hit testing (checking if a point is inside the bounding box):
|
|
23
|
+
* const rect = getElementBounds(element);
|
|
24
|
+
* if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { ... }
|
|
25
|
+
*
|
|
26
|
+
* ❌ Getting element DIMENSIONS (wrong for rotated elements):
|
|
27
|
+
* const rect = getElementBounds(element);
|
|
28
|
+
* const width = rect.width; // WRONG! This is bounding box width, not element width
|
|
29
|
+
*
|
|
30
|
+
* For actual dimensions, use element.offsetWidth / element.offsetHeight instead.
|
|
31
|
+
* These return layout dimensions unaffected by CSS transforms.
|
|
32
|
+
*/
|
|
33
|
+
function getElementBounds(element) {
|
|
34
|
+
if ("getCanvasBounds" in element && typeof element.getCanvasBounds === "function") return element.getCanvasBounds();
|
|
35
|
+
return element.getBoundingClientRect();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
export { getElementBounds };
|
|
40
|
+
//# sourceMappingURL=getElementBounds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getElementBounds.js","names":[],"sources":["../../src/canvas/getElementBounds.ts"],"sourcesContent":["import type { CanvasElementBounds } from \"./api/types.js\";\n\n/**\n * Get element bounds using the CanvasElementBounds protocol if available,\n * otherwise fall back to getBoundingClientRect().\n *\n * This allows elements to provide custom hit testing areas or account for\n * visual bounds that differ from DOM bounds.\n *\n * IMPORTANT: This returns a DOMRect in SCREEN SPACE (like getBoundingClientRect).\n *\n * For ROTATED elements, the returned rect is the AXIS-ALIGNED BOUNDING BOX:\n * - rect.width/height are the bounding box dimensions, NOT the element's actual dimensions\n * - rect.left/top are the bounding box corner, NOT the element's visual top-left\n *\n * CORRECT USAGE:\n *\n * ✅ Getting element CENTER (rotation-invariant):\n * const rect = getElementBounds(element);\n * const centerX = rect.left + rect.width / 2;\n * const centerY = rect.top + rect.height / 2;\n *\n * ✅ Hit testing (checking if a point is inside the bounding box):\n * const rect = getElementBounds(element);\n * if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { ... }\n *\n * ❌ Getting element DIMENSIONS (wrong for rotated elements):\n * const rect = getElementBounds(element);\n * const width = rect.width; // WRONG! This is bounding box width, not element width\n *\n * For actual dimensions, use element.offsetWidth / element.offsetHeight instead.\n * These return layout dimensions unaffected by CSS transforms.\n */\nexport function getElementBounds(element: HTMLElement): DOMRect {\n if (\n \"getCanvasBounds\" in element &&\n typeof (element as any).getCanvasBounds === \"function\"\n ) {\n return (element as CanvasElementBounds).getCanvasBounds();\n }\n return element.getBoundingClientRect();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,SAAgB,iBAAiB,SAA+B;AAC9D,KACE,qBAAqB,WACrB,OAAQ,QAAgB,oBAAoB,WAE5C,QAAQ,QAAgC,iBAAiB;AAE3D,QAAO,QAAQ,uBAAuB"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
|
|
2
|
+
import { panZoomTransformContext } from "../../gui/panZoomTransformContext.js";
|
|
3
|
+
import { selectionContext } from "../selection/selectionContext.js";
|
|
4
|
+
import { calculateOverlayState, getOverlayTargets } from "./overlayState.js";
|
|
5
|
+
import { consume } from "@lit/context";
|
|
6
|
+
import { LitElement, css, html } from "lit";
|
|
7
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
8
|
+
|
|
9
|
+
//#region src/canvas/overlays/SelectionOverlay.ts
|
|
10
|
+
let SelectionOverlay = class SelectionOverlay$1 extends LitElement {
|
|
11
|
+
constructor(..._args) {
|
|
12
|
+
super(..._args);
|
|
13
|
+
this.canvasElement = null;
|
|
14
|
+
this.overlayState = {
|
|
15
|
+
selection: null,
|
|
16
|
+
boxSelect: null,
|
|
17
|
+
highlight: null
|
|
18
|
+
};
|
|
19
|
+
this.lastSelectionMode = null;
|
|
20
|
+
this.rafLoopActive = false;
|
|
21
|
+
this.rafLoop = () => {
|
|
22
|
+
if (!this.rafLoopActive) return;
|
|
23
|
+
this.updateOverlayData();
|
|
24
|
+
this.animationFrame = requestAnimationFrame(this.rafLoop);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
static {
|
|
28
|
+
this.styles = [css`
|
|
29
|
+
:host {
|
|
30
|
+
position: fixed;
|
|
31
|
+
top: 0;
|
|
32
|
+
left: 0;
|
|
33
|
+
width: 100vw;
|
|
34
|
+
height: 100vh;
|
|
35
|
+
pointer-events: none;
|
|
36
|
+
z-index: 1000;
|
|
37
|
+
}
|
|
38
|
+
.box-select {
|
|
39
|
+
position: absolute;
|
|
40
|
+
border: 2px dashed rgb(59, 130, 246);
|
|
41
|
+
background: rgba(59, 130, 246, 0.05);
|
|
42
|
+
pointer-events: none;
|
|
43
|
+
}
|
|
44
|
+
.highlight-box {
|
|
45
|
+
position: absolute;
|
|
46
|
+
border: 2px solid rgb(148, 163, 184);
|
|
47
|
+
background: rgba(148, 163, 184, 0.1);
|
|
48
|
+
pointer-events: none;
|
|
49
|
+
box-shadow: 0 0 0 2px rgba(148, 163, 184, 0.3);
|
|
50
|
+
}
|
|
51
|
+
`];
|
|
52
|
+
}
|
|
53
|
+
createRenderRoot() {
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
firstUpdated(changedProperties) {
|
|
57
|
+
super.firstUpdated?.(changedProperties);
|
|
58
|
+
const styleElement = this.querySelector("style");
|
|
59
|
+
if (!styleElement) {
|
|
60
|
+
if (!(this.closest("[data-test-container]") !== null || this.closest("#sandbox-container") !== null || window.location.pathname.includes("scenario-runner"))) console.warn("[SelectionOverlay] No style element found - styles may not be applied");
|
|
61
|
+
} else console.log("[SelectionOverlay] Style element found, content length:", styleElement.textContent?.length || 0);
|
|
62
|
+
}
|
|
63
|
+
connectedCallback() {
|
|
64
|
+
super.connectedCallback();
|
|
65
|
+
this.style.position = "fixed";
|
|
66
|
+
this.style.top = "0";
|
|
67
|
+
this.style.left = "0";
|
|
68
|
+
this.style.width = "100vw";
|
|
69
|
+
this.style.height = "100vh";
|
|
70
|
+
this.style.pointerEvents = "none";
|
|
71
|
+
this.style.zIndex = "1000";
|
|
72
|
+
this.setAttribute("data-selection-overlay", "true");
|
|
73
|
+
requestAnimationFrame(() => {
|
|
74
|
+
if (this.canvas) this.canvasElement = this.canvas;
|
|
75
|
+
else this.findCanvasElement();
|
|
76
|
+
if (this.canvasElement) this.startRafLoop();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
disconnectedCallback() {
|
|
80
|
+
super.disconnectedCallback();
|
|
81
|
+
this.stopRafLoop();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* React to selection context changes to ensure box selection visual updates.
|
|
85
|
+
* This is called whenever Lit detects a property change, including context updates.
|
|
86
|
+
* Note: We don't call requestUpdate() here to avoid the Lit warning about scheduling
|
|
87
|
+
* updates after an update completes. The RAF loop handles all updates.
|
|
88
|
+
*/
|
|
89
|
+
updated(changedProperties) {
|
|
90
|
+
super.updated?.(changedProperties);
|
|
91
|
+
const currentMode = this.effectiveSelection?.selectionMode ?? null;
|
|
92
|
+
if (currentMode !== this.lastSelectionMode) this.lastSelectionMode = currentMode;
|
|
93
|
+
if (currentMode === "box-selecting" && !this.rafLoopActive) this.startRafLoop();
|
|
94
|
+
if (changedProperties.has("canvas") && this.canvas) {
|
|
95
|
+
this.canvasElement = this.canvas;
|
|
96
|
+
if (!this.rafLoopActive) this.startRafLoop();
|
|
97
|
+
}
|
|
98
|
+
if (this.canvasElement && !this.rafLoopActive) this.startRafLoop();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Find the EFCanvas element.
|
|
102
|
+
* Handles both cases:
|
|
103
|
+
* 1. Overlay is inside EFCanvas's shadow DOM (old case)
|
|
104
|
+
* 2. Overlay is a sibling of ef-pan-zoom (new case - outside transform)
|
|
105
|
+
*/
|
|
106
|
+
findCanvasElement() {
|
|
107
|
+
const parent = this.parentElement;
|
|
108
|
+
if (parent) {
|
|
109
|
+
const panZoom$1 = parent.querySelector("ef-pan-zoom");
|
|
110
|
+
if (panZoom$1) {
|
|
111
|
+
const canvas = panZoom$1.querySelector("ef-canvas");
|
|
112
|
+
if (canvas) {
|
|
113
|
+
this.canvasElement = canvas;
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const panZoom = this.closest("ef-pan-zoom");
|
|
119
|
+
if (panZoom) {
|
|
120
|
+
const canvas = panZoom.querySelector("ef-canvas");
|
|
121
|
+
if (canvas) {
|
|
122
|
+
this.canvasElement = canvas;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
let current = this;
|
|
127
|
+
while (current) if (current instanceof ShadowRoot) current = current.host;
|
|
128
|
+
else if (current instanceof HTMLElement) {
|
|
129
|
+
if (current.tagName === "EF-CANVAS" || current.tagName.toLowerCase() === "ef-canvas") {
|
|
130
|
+
this.canvasElement = current;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const rootNode = current.getRootNode();
|
|
134
|
+
if (rootNode instanceof ShadowRoot) current = rootNode.host;
|
|
135
|
+
else current = current.parentElement;
|
|
136
|
+
} else {
|
|
137
|
+
const rootNode = current.getRootNode();
|
|
138
|
+
if (rootNode instanceof ShadowRoot) current = rootNode.host;
|
|
139
|
+
else current = current.parentElement;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Start continuous RAF loop for smooth overlay updates.
|
|
144
|
+
*/
|
|
145
|
+
startRafLoop() {
|
|
146
|
+
if (this.rafLoopActive) return;
|
|
147
|
+
this.rafLoopActive = true;
|
|
148
|
+
this.rafLoop();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Stop RAF loop.
|
|
152
|
+
*/
|
|
153
|
+
stopRafLoop() {
|
|
154
|
+
this.rafLoopActive = false;
|
|
155
|
+
if (this.animationFrame) {
|
|
156
|
+
cancelAnimationFrame(this.animationFrame);
|
|
157
|
+
this.animationFrame = void 0;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get the effective selection context (from context or property).
|
|
162
|
+
*/
|
|
163
|
+
get effectiveSelection() {
|
|
164
|
+
return this.selectionFromContext ?? this.selection;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get the effective pan-zoom transform (from context or property).
|
|
168
|
+
*/
|
|
169
|
+
get effectivePanZoomTransform() {
|
|
170
|
+
return this.panZoomTransformFromContext ?? this.panZoomTransform;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Update overlay data state using the abstraction layer.
|
|
174
|
+
*
|
|
175
|
+
* This method now uses the clean separation of:
|
|
176
|
+
* - SEMANTICS: getOverlayTargets() determines WHAT should be shown
|
|
177
|
+
* - MECHANISM: calculateOverlayState() determines HOW to show it
|
|
178
|
+
*/
|
|
179
|
+
updateOverlayData() {
|
|
180
|
+
if (this.canvas && this.canvas !== this.canvasElement) this.canvasElement = this.canvas;
|
|
181
|
+
const effectiveCanvas = this.canvasElement || this.canvas;
|
|
182
|
+
if (!effectiveCanvas) {
|
|
183
|
+
this.overlayState = {
|
|
184
|
+
selection: null,
|
|
185
|
+
boxSelect: null,
|
|
186
|
+
highlight: null
|
|
187
|
+
};
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
let canvasRect = effectiveCanvas.getBoundingClientRect();
|
|
191
|
+
if (effectiveCanvas.shadowRoot) {
|
|
192
|
+
const canvasContent = effectiveCanvas.shadowRoot.querySelector(".canvas-content");
|
|
193
|
+
if (canvasContent) canvasRect = canvasContent.getBoundingClientRect();
|
|
194
|
+
}
|
|
195
|
+
const panZoomElement = effectiveCanvas.closest("ef-pan-zoom");
|
|
196
|
+
const canvas = effectiveCanvas;
|
|
197
|
+
const highlightedElement = canvas?.highlightedElement;
|
|
198
|
+
const targets = getOverlayTargets(this.effectiveSelection, highlightedElement);
|
|
199
|
+
const canvasWithMetadata = {
|
|
200
|
+
getElementData: (id) => canvas?.getElementData?.(id),
|
|
201
|
+
getElement: (id) => canvas?.elementRegistry?.get(id),
|
|
202
|
+
querySelector: (selector) => effectiveCanvas.querySelector(selector),
|
|
203
|
+
shadowRoot: effectiveCanvas.shadowRoot
|
|
204
|
+
};
|
|
205
|
+
const currentTransform = this.readCurrentTransform(panZoomElement);
|
|
206
|
+
this.overlayState = calculateOverlayState(targets, canvasWithMetadata, canvasRect, panZoomElement, currentTransform);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Read current transform directly from panzoom element.
|
|
210
|
+
* This ensures we always have fresh values instead of stale property/context.
|
|
211
|
+
*/
|
|
212
|
+
readCurrentTransform(panZoomElement) {
|
|
213
|
+
if (panZoomElement) {
|
|
214
|
+
const pz = panZoomElement;
|
|
215
|
+
if (typeof pz.x === "number" && typeof pz.y === "number" && typeof pz.scale === "number") return {
|
|
216
|
+
x: pz.x,
|
|
217
|
+
y: pz.y,
|
|
218
|
+
scale: pz.scale
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return this.effectivePanZoomTransform;
|
|
222
|
+
}
|
|
223
|
+
render() {
|
|
224
|
+
if (!(this.canvasElement || this.canvas)) return html``;
|
|
225
|
+
const { boxSelect, highlight } = this.overlayState;
|
|
226
|
+
const selectionMode = this.effectiveSelection?.selectionMode;
|
|
227
|
+
return html`
|
|
228
|
+
${boxSelect ? html`
|
|
229
|
+
<div
|
|
230
|
+
class="box-select"
|
|
231
|
+
style="left: ${boxSelect.x}px; top: ${boxSelect.y}px; width: ${boxSelect.width}px; height: ${boxSelect.height}px; position: absolute; border: 2px dashed rgb(59, 130, 246); background: rgba(59, 130, 246, 0.05); pointer-events: none;"
|
|
232
|
+
></div>
|
|
233
|
+
` : html``}
|
|
234
|
+
${highlight ? html`
|
|
235
|
+
<div
|
|
236
|
+
class="highlight-box"
|
|
237
|
+
style="left: ${highlight.x}px; top: ${highlight.y}px; width: ${highlight.width}px; height: ${highlight.height}px; position: absolute; border: 2px solid rgb(148, 163, 184); background: rgba(148, 163, 184, 0.1); pointer-events: none; box-shadow: 0 0 0 2px rgba(148, 163, 184, 0.3);"
|
|
238
|
+
></div>
|
|
239
|
+
` : html``}
|
|
240
|
+
${selectionMode === "box-selecting" && !boxSelect ? html`
|
|
241
|
+
<div style="position: fixed; top: 50px; right: 10px; background: orange; color: white; padding: 4px; z-index: 10000; font-size: 12px;">
|
|
242
|
+
Box selecting but no bounds! mode=${selectionMode} bounds=${this.effectiveSelection?.boxSelectBounds ? "exists" : "null"}
|
|
243
|
+
</div>
|
|
244
|
+
` : html``}
|
|
245
|
+
`;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
__decorate([consume({
|
|
249
|
+
context: selectionContext,
|
|
250
|
+
subscribe: true
|
|
251
|
+
})], SelectionOverlay.prototype, "selectionFromContext", void 0);
|
|
252
|
+
__decorate([consume({
|
|
253
|
+
context: panZoomTransformContext,
|
|
254
|
+
subscribe: true
|
|
255
|
+
})], SelectionOverlay.prototype, "panZoomTransformFromContext", void 0);
|
|
256
|
+
__decorate([property({ type: Object })], SelectionOverlay.prototype, "selection", void 0);
|
|
257
|
+
__decorate([property({ type: Object })], SelectionOverlay.prototype, "panZoomTransform", void 0);
|
|
258
|
+
__decorate([state()], SelectionOverlay.prototype, "canvasElement", void 0);
|
|
259
|
+
__decorate([property({ type: Object })], SelectionOverlay.prototype, "canvas", void 0);
|
|
260
|
+
__decorate([state()], SelectionOverlay.prototype, "overlayState", void 0);
|
|
261
|
+
__decorate([state()], SelectionOverlay.prototype, "lastSelectionMode", void 0);
|
|
262
|
+
SelectionOverlay = __decorate([customElement("ef-canvas-selection-overlay")], SelectionOverlay);
|
|
263
|
+
|
|
264
|
+
//#endregion
|
|
265
|
+
//# sourceMappingURL=SelectionOverlay.js.map
|